Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gnulib-local / lib / libxml / xpath.c
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16
17 #define IN_LIBXML
18 #include "libxml.h"
19
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61
62 #define TODO                                                            \
63     xmlGenericError(xmlGenericErrorContext,                             \
64             "Unimplemented block at %s:%d\n",                           \
65             __FILE__, __LINE__);
66
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */ 
83 #define XP_OPTIMIZED_FILTER_FIRST
84
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91
92 /*
93  * TODO:
94  * There are a few spots where some tests are done which depend upon ascii
95  * data.  These should be enhanced for full UTF8 support (see particularly
96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97  */
98
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101 /************************************************************************
102  *                                                                      *
103  *                      Floating point stuff                            *
104  *                                                                      *
105  ************************************************************************/
106
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111
112 /*
113  * The lack of portability of this section of the libc is annoying !
114  */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120
121 /**
122  * xmlXPathInit:
123  *
124  * Initialize the XPath environment
125  */
126 void
127 xmlXPathInit(void) {
128     if (xmlXPathInitialized) return;
129
130     xmlXPathPINF = trio_pinf();
131     xmlXPathNINF = trio_ninf();
132     xmlXPathNAN = trio_nan();
133     xmlXPathNZERO = trio_nzero();
134
135     xmlXPathInitialized = 1;
136 }
137
138 /**
139  * xmlXPathIsNaN:
140  * @val:  a double value
141  *
142  * Provides a portable isnan() function to detect whether a double
143  * is a NotaNumber. Based on trio code
144  * http://sourceforge.net/projects/ctrio/
145  * 
146  * Returns 1 if the value is a NaN, 0 otherwise
147  */
148 int
149 xmlXPathIsNaN(double val) {
150     return(trio_isnan(val));
151 }
152
153 /**
154  * xmlXPathIsInf:
155  * @val:  a double value
156  *
157  * Provides a portable isinf() function to detect whether a double
158  * is a +Infinite or -Infinite. Based on trio code
159  * http://sourceforge.net/projects/ctrio/
160  * 
161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162  */
163 int
164 xmlXPathIsInf(double val) {
165     return(trio_isinf(val));
166 }
167
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171  * xmlXPathGetSign:
172  * @val:  a double value
173  *
174  * Provides a portable function to detect the sign of a double
175  * Modified from trio code
176  * http://sourceforge.net/projects/ctrio/
177  * 
178  * Returns 1 if the value is Negative, 0 if positive
179  */
180 static int
181 xmlXPathGetSign(double val) {
182     return(trio_signbit(val));
183 }
184
185
186 /*
187  * TODO: when compatibility allows remove all "fake node libxslt" strings
188  *       the test should just be name[0] = ' '
189  */
190 /* #define DEBUG */
191 /* #define DEBUG_STEP */
192 /* #define DEBUG_STEP_NTH */
193 /* #define DEBUG_EXPR */
194 /* #define DEBUG_EVAL_COUNTS */
195
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197     NULL,
198     XML_NAMESPACE_DECL,
199     XML_XML_NAMESPACE,
200     BAD_CAST "xml",
201     NULL
202 };
203 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204 #ifndef LIBXML_THREAD_ENABLED
205 /* 
206  * Optimizer is disabled only when threaded apps are detected while
207  * the library ain't compiled for thread safety.
208  */
209 static int xmlXPathDisableOptimizer = 0;
210 #endif
211
212 /************************************************************************
213  *                                                                      *
214  *                      Error handling routines                         *
215  *                                                                      *
216  ************************************************************************/
217
218 /**
219  * XP_ERRORNULL:
220  * @X:  the error code
221  *
222  * Macro to raise an XPath error and return NULL.
223  */
224 #define XP_ERRORNULL(X)                                                 \
225     { xmlXPathErr(ctxt, X); return(NULL); }
226
227 /*
228  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
229  */
230 static const char *xmlXPathErrorMessages[] = {
231     "Ok\n",
232     "Number encoding\n",
233     "Unfinished literal\n",
234     "Start of literal\n",
235     "Expected $ for variable reference\n",
236     "Undefined variable\n",
237     "Invalid predicate\n",
238     "Invalid expression\n",
239     "Missing closing curly brace\n",
240     "Unregistered function\n",
241     "Invalid operand\n",
242     "Invalid type\n",
243     "Invalid number of arguments\n",
244     "Invalid context size\n",
245     "Invalid context position\n",
246     "Memory allocation error\n",
247     "Syntax error\n",
248     "Resource error\n",
249     "Sub resource error\n",
250     "Undefined namespace prefix\n",
251     "Encoding error\n",
252     "Char out of XML range\n",
253     "Invalid or incomplete context\n",
254     "?? Unknown error ??\n"     /* Must be last in the list! */
255 };
256 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
257                    sizeof(xmlXPathErrorMessages[0])) - 1)
258 /**
259  * xmlXPathErrMemory:
260  * @ctxt:  an XPath context
261  * @extra:  extra informations
262  *
263  * Handle a redefinition of attribute error
264  */
265 static void
266 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
267 {
268     if (ctxt != NULL) {
269         if (extra) {
270             xmlChar buf[200];
271
272             xmlStrPrintf(buf, 200,
273                          BAD_CAST "Memory allocation failed : %s\n",
274                          extra);
275             ctxt->lastError.message = (char *) xmlStrdup(buf);
276         } else {
277             ctxt->lastError.message = (char *)
278                xmlStrdup(BAD_CAST "Memory allocation failed\n");
279         }
280         ctxt->lastError.domain = XML_FROM_XPATH;
281         ctxt->lastError.code = XML_ERR_NO_MEMORY;
282         if (ctxt->error != NULL)
283             ctxt->error(ctxt->userData, &ctxt->lastError);
284     } else {
285         if (extra)
286             __xmlRaiseError(NULL, NULL, NULL,
287                             NULL, NULL, XML_FROM_XPATH,
288                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289                             extra, NULL, NULL, 0, 0,
290                             "Memory allocation failed : %s\n", extra);
291         else
292             __xmlRaiseError(NULL, NULL, NULL,
293                             NULL, NULL, XML_FROM_XPATH,
294                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295                             NULL, NULL, NULL, 0, 0,
296                             "Memory allocation failed\n");
297     }
298 }
299
300 /**
301  * xmlXPathPErrMemory:
302  * @ctxt:  an XPath parser context
303  * @extra:  extra informations
304  *
305  * Handle a redefinition of attribute error
306  */
307 static void
308 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
309 {
310     if (ctxt == NULL)
311         xmlXPathErrMemory(NULL, extra);
312     else {
313         ctxt->error = XPATH_MEMORY_ERROR;
314         xmlXPathErrMemory(ctxt->context, extra);
315     }
316 }
317
318 /**
319  * xmlXPathErr:
320  * @ctxt:  a XPath parser context
321  * @error:  the error code
322  *
323  * Handle an XPath error
324  */
325 void
326 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
327 {
328     if ((error < 0) || (error > MAXERRNO))
329         error = MAXERRNO;
330     if (ctxt == NULL) {
331         __xmlRaiseError(NULL, NULL, NULL,
332                         NULL, NULL, XML_FROM_XPATH,
333                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334                         XML_ERR_ERROR, NULL, 0,
335                         NULL, NULL, NULL, 0, 0,
336                         xmlXPathErrorMessages[error]);
337         return;
338     }
339     ctxt->error = error;
340     if (ctxt->context == NULL) {
341         __xmlRaiseError(NULL, NULL, NULL,
342                         NULL, NULL, XML_FROM_XPATH,
343                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344                         XML_ERR_ERROR, NULL, 0,
345                         (const char *) ctxt->base, NULL, NULL,
346                         ctxt->cur - ctxt->base, 0,
347                         xmlXPathErrorMessages[error]);
348         return;
349     }
350
351     /* cleanup current last error */
352     xmlResetError(&ctxt->context->lastError); 
353
354     ctxt->context->lastError.domain = XML_FROM_XPATH;
355     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356                            XPATH_EXPRESSION_OK;
357     ctxt->context->lastError.level = XML_ERR_ERROR;
358     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360     ctxt->context->lastError.node = ctxt->context->debugNode;
361     if (ctxt->context->error != NULL) {
362         ctxt->context->error(ctxt->context->userData,
363                              &ctxt->context->lastError);
364     } else {
365         __xmlRaiseError(NULL, NULL, NULL,
366                         NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367                         error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368                         XML_ERR_ERROR, NULL, 0,
369                         (const char *) ctxt->base, NULL, NULL,
370                         ctxt->cur - ctxt->base, 0,
371                         xmlXPathErrorMessages[error]);
372     }
373
374 }
375
376 /**
377  * xmlXPatherror:
378  * @ctxt:  the XPath Parser context
379  * @file:  the file name
380  * @line:  the line number
381  * @no:  the error number
382  *
383  * Formats an error message.
384  */
385 void
386 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387               int line ATTRIBUTE_UNUSED, int no) {
388     xmlXPathErr(ctxt, no);
389 }
390
391 /************************************************************************
392  *                                                                      *
393  *                      Utilities                                       *
394  *                                                                      *
395  ************************************************************************/
396
397 /**
398  * xsltPointerList:
399  *
400  * Pointer-list for various purposes.
401  */
402 typedef struct _xmlPointerList xmlPointerList;
403 typedef xmlPointerList *xmlPointerListPtr;
404 struct _xmlPointerList {
405     void **items;
406     int number;
407     int size;
408 };
409 /*
410 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411 * and here, we should make the functions public.
412 */
413 static int
414 xmlPointerListAddSize(xmlPointerListPtr list,                  
415                        void *item,
416                        int initialSize)
417 {
418     if (list->items == NULL) {
419         if (initialSize <= 0)
420             initialSize = 1;
421         list->items = (void **) xmlMalloc(
422             initialSize * sizeof(void *));
423         if (list->items == NULL) {
424             xmlXPathErrMemory(NULL,
425                 "xmlPointerListCreate: allocating item\n");
426             return(-1);
427         }
428         list->number = 0;
429         list->size = initialSize;
430     } else if (list->size <= list->number) {
431         list->size *= 2;
432         list->items = (void **) xmlRealloc(list->items,
433             list->size * sizeof(void *));
434         if (list->items == NULL) {
435             xmlXPathErrMemory(NULL,
436                 "xmlPointerListCreate: re-allocating item\n");
437             list->size = 0;
438             return(-1);
439         }
440     }
441     list->items[list->number++] = item;
442     return(0);
443 }
444
445 /**
446  * xsltPointerListCreate:
447  *
448  * Creates an xsltPointerList structure.
449  *
450  * Returns a xsltPointerList structure or NULL in case of an error.
451  */
452 static xmlPointerListPtr
453 xmlPointerListCreate(int initialSize)
454 {
455     xmlPointerListPtr ret;
456
457     ret = xmlMalloc(sizeof(xmlPointerList));
458     if (ret == NULL) {
459         xmlXPathErrMemory(NULL,
460             "xmlPointerListCreate: allocating item\n");
461         return (NULL);
462     }
463     memset(ret, 0, sizeof(xmlPointerList));
464     if (initialSize > 0) {
465         xmlPointerListAddSize(ret, NULL, initialSize);
466         ret->number = 0;
467     }
468     return (ret);
469 }
470
471 /**
472  * xsltPointerListFree:
473  *
474  * Frees the xsltPointerList structure. This does not free
475  * the content of the list.
476  */
477 static void
478 xmlPointerListFree(xmlPointerListPtr list)
479 {
480     if (list == NULL)
481         return;
482     if (list->items != NULL)
483         xmlFree(list->items);
484     xmlFree(list);
485 }
486
487 /************************************************************************
488  *                                                                      *
489  *                      Parser Types                                    *
490  *                                                                      *
491  ************************************************************************/
492
493 /*
494  * Types are private:
495  */
496
497 typedef enum {
498     XPATH_OP_END=0,
499     XPATH_OP_AND,
500     XPATH_OP_OR,
501     XPATH_OP_EQUAL,
502     XPATH_OP_CMP,
503     XPATH_OP_PLUS,
504     XPATH_OP_MULT,
505     XPATH_OP_UNION,
506     XPATH_OP_ROOT,
507     XPATH_OP_NODE,
508     XPATH_OP_RESET, /* 10 */
509     XPATH_OP_COLLECT,
510     XPATH_OP_VALUE, /* 12 */
511     XPATH_OP_VARIABLE,
512     XPATH_OP_FUNCTION,
513     XPATH_OP_ARG,
514     XPATH_OP_PREDICATE,
515     XPATH_OP_FILTER, /* 17 */
516     XPATH_OP_SORT /* 18 */
517 #ifdef LIBXML_XPTR_ENABLED
518     ,XPATH_OP_RANGETO
519 #endif
520 } xmlXPathOp;
521
522 typedef enum {
523     AXIS_ANCESTOR = 1,
524     AXIS_ANCESTOR_OR_SELF,
525     AXIS_ATTRIBUTE,
526     AXIS_CHILD,
527     AXIS_DESCENDANT,
528     AXIS_DESCENDANT_OR_SELF,
529     AXIS_FOLLOWING,
530     AXIS_FOLLOWING_SIBLING,
531     AXIS_NAMESPACE,
532     AXIS_PARENT,
533     AXIS_PRECEDING,
534     AXIS_PRECEDING_SIBLING,
535     AXIS_SELF    
536 } xmlXPathAxisVal;
537
538 typedef enum {
539     NODE_TEST_NONE = 0,
540     NODE_TEST_TYPE = 1,
541     NODE_TEST_PI = 2,
542     NODE_TEST_ALL = 3,
543     NODE_TEST_NS = 4,
544     NODE_TEST_NAME = 5
545 } xmlXPathTestVal;
546
547 typedef enum {
548     NODE_TYPE_NODE = 0,
549     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550     NODE_TYPE_TEXT = XML_TEXT_NODE,
551     NODE_TYPE_PI = XML_PI_NODE   
552 } xmlXPathTypeVal;
553
554 #define XP_REWRITE_DOS_CHILD_ELEM 1
555
556 typedef struct _xmlXPathStepOp xmlXPathStepOp;
557 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558 struct _xmlXPathStepOp {
559     xmlXPathOp op;              /* The identifier of the operation */
560     int ch1;                    /* First child */
561     int ch2;                    /* Second child */
562     int value;
563     int value2;
564     int value3;
565     void *value4;
566     void *value5;
567     void *cache;
568     void *cacheURI;
569     int rewriteType;
570 };
571
572 struct _xmlXPathCompExpr {
573     int nbStep;                 /* Number of steps in this expression */
574     int maxStep;                /* Maximum number of steps allocated */
575     xmlXPathStepOp *steps;      /* ops for computation of this expression */
576     int last;                   /* index of last step in expression */
577     xmlChar *expr;              /* the expression being computed */
578     xmlDictPtr dict;            /* the dictionnary to use if any */
579 #ifdef DEBUG_EVAL_COUNTS
580     int nb;
581     xmlChar *string;
582 #endif
583 #ifdef XPATH_STREAMING
584     xmlPatternPtr stream;
585 #endif
586 };
587
588 /************************************************************************
589  *                                                                      *
590  *                      Forward declarations                            *
591  *                                                                      *
592  ************************************************************************/
593 static void
594 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
595 static void
596 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
597 static int
598 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599                         xmlXPathStepOpPtr op, xmlNodePtr *first);
600 static int
601 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
602                             xmlXPathStepOpPtr op,
603                             int isPredicate);
604
605 /************************************************************************
606  *                                                                      *
607  *                      Parser Type functions                           *
608  *                                                                      *
609  ************************************************************************/
610
611 /**
612  * xmlXPathNewCompExpr:
613  *
614  * Create a new Xpath component
615  *
616  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617  */
618 static xmlXPathCompExprPtr
619 xmlXPathNewCompExpr(void) {
620     xmlXPathCompExprPtr cur;
621
622     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623     if (cur == NULL) {
624         xmlXPathErrMemory(NULL, "allocating component\n");
625         return(NULL);
626     }
627     memset(cur, 0, sizeof(xmlXPathCompExpr));
628     cur->maxStep = 10;
629     cur->nbStep = 0;
630     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631                                            sizeof(xmlXPathStepOp));
632     if (cur->steps == NULL) {
633         xmlXPathErrMemory(NULL, "allocating steps\n");
634         xmlFree(cur);
635         return(NULL);
636     }
637     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638     cur->last = -1;
639 #ifdef DEBUG_EVAL_COUNTS
640     cur->nb = 0;
641 #endif
642     return(cur);
643 }
644
645 /**
646  * xmlXPathFreeCompExpr:
647  * @comp:  an XPATH comp
648  *
649  * Free up the memory allocated by @comp
650  */
651 void
652 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653 {
654     xmlXPathStepOpPtr op;
655     int i;
656
657     if (comp == NULL)
658         return;
659     if (comp->dict == NULL) {
660         for (i = 0; i < comp->nbStep; i++) {
661             op = &comp->steps[i];
662             if (op->value4 != NULL) {
663                 if (op->op == XPATH_OP_VALUE)
664                     xmlXPathFreeObject(op->value4);
665                 else
666                     xmlFree(op->value4);
667             }
668             if (op->value5 != NULL)
669                 xmlFree(op->value5);
670         }
671     } else {
672         for (i = 0; i < comp->nbStep; i++) {
673             op = &comp->steps[i];
674             if (op->value4 != NULL) {
675                 if (op->op == XPATH_OP_VALUE)
676                     xmlXPathFreeObject(op->value4);
677             }
678         }
679         xmlDictFree(comp->dict);
680     }
681     if (comp->steps != NULL) {
682         xmlFree(comp->steps);
683     }
684 #ifdef DEBUG_EVAL_COUNTS
685     if (comp->string != NULL) {
686         xmlFree(comp->string);
687     }
688 #endif
689 #ifdef XPATH_STREAMING
690     if (comp->stream != NULL) {
691         xmlFreePatternList(comp->stream);
692     }
693 #endif
694     if (comp->expr != NULL) {
695         xmlFree(comp->expr);
696     }
697
698     xmlFree(comp);
699 }
700
701 /**
702  * xmlXPathCompExprAdd:
703  * @comp:  the compiled expression
704  * @ch1: first child index
705  * @ch2: second child index
706  * @op:  an op
707  * @value:  the first int value
708  * @value2:  the second int value
709  * @value3:  the third int value
710  * @value4:  the first string value
711  * @value5:  the second string value
712  *
713  * Add a step to an XPath Compiled Expression
714  *
715  * Returns -1 in case of failure, the index otherwise
716  */
717 static int
718 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719    xmlXPathOp op, int value,
720    int value2, int value3, void *value4, void *value5) {
721     if (comp->nbStep >= comp->maxStep) {
722         xmlXPathStepOp *real;
723
724         comp->maxStep *= 2;
725         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726                                       comp->maxStep * sizeof(xmlXPathStepOp));
727         if (real == NULL) {
728             comp->maxStep /= 2;
729             xmlXPathErrMemory(NULL, "adding step\n");
730             return(-1);
731         }
732         comp->steps = real;
733     }
734     comp->last = comp->nbStep;
735     comp->steps[comp->nbStep].rewriteType = 0;
736     comp->steps[comp->nbStep].ch1 = ch1;
737     comp->steps[comp->nbStep].ch2 = ch2;
738     comp->steps[comp->nbStep].op = op;
739     comp->steps[comp->nbStep].value = value;
740     comp->steps[comp->nbStep].value2 = value2;
741     comp->steps[comp->nbStep].value3 = value3;
742     if ((comp->dict != NULL) &&
743         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744          (op == XPATH_OP_COLLECT))) {
745         if (value4 != NULL) {
746             comp->steps[comp->nbStep].value4 = (xmlChar *)
747                 (void *)xmlDictLookup(comp->dict, value4, -1);
748             xmlFree(value4);
749         } else
750             comp->steps[comp->nbStep].value4 = NULL;
751         if (value5 != NULL) {
752             comp->steps[comp->nbStep].value5 = (xmlChar *)
753                 (void *)xmlDictLookup(comp->dict, value5, -1);
754             xmlFree(value5);
755         } else
756             comp->steps[comp->nbStep].value5 = NULL;
757     } else {
758         comp->steps[comp->nbStep].value4 = value4;
759         comp->steps[comp->nbStep].value5 = value5;
760     }
761     comp->steps[comp->nbStep].cache = NULL;
762     return(comp->nbStep++);
763 }
764
765 /**
766  * xmlXPathCompSwap:
767  * @comp:  the compiled expression
768  * @op: operation index
769  *
770  * Swaps 2 operations in the compiled expression
771  */
772 static void
773 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
774     int tmp;
775
776 #ifndef LIBXML_THREAD_ENABLED
777     /*
778      * Since this manipulates possibly shared variables, this is
779      * disabled if one detects that the library is used in a multithreaded
780      * application
781      */
782     if (xmlXPathDisableOptimizer)
783         return;
784 #endif
785
786     tmp = op->ch1;
787     op->ch1 = op->ch2;
788     op->ch2 = tmp;
789 }
790
791 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
792     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
793                         (op), (val), (val2), (val3), (val4), (val5))
794 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
795     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
796                         (op), (val), (val2), (val3), (val4), (val5))
797
798 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
799 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
802 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
805 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
806                         (val), (val2), 0 ,NULL ,NULL)
807
808 /************************************************************************
809  *                                                                      *
810  *              XPath object cache structures                           *
811  *                                                                      *
812  ************************************************************************/
813
814 /* #define XP_DEFAULT_CACHE_ON */
815
816 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
817
818 typedef struct _xmlXPathContextCache xmlXPathContextCache;
819 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820 struct _xmlXPathContextCache {
821     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
822     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
823     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
824     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
825     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
826     int maxNodeset;
827     int maxString;
828     int maxBoolean;
829     int maxNumber;
830     int maxMisc;
831 #ifdef XP_DEBUG_OBJ_USAGE
832     int dbgCachedAll;
833     int dbgCachedNodeset;
834     int dbgCachedString;
835     int dbgCachedBool;
836     int dbgCachedNumber;
837     int dbgCachedPoint;
838     int dbgCachedRange;
839     int dbgCachedLocset;
840     int dbgCachedUsers;
841     int dbgCachedXSLTTree;
842     int dbgCachedUndefined; 
843     
844
845     int dbgReusedAll;
846     int dbgReusedNodeset;
847     int dbgReusedString;
848     int dbgReusedBool;
849     int dbgReusedNumber;
850     int dbgReusedPoint;
851     int dbgReusedRange;
852     int dbgReusedLocset;
853     int dbgReusedUsers;
854     int dbgReusedXSLTTree;
855     int dbgReusedUndefined;
856
857 #endif
858 };
859
860 /************************************************************************
861  *                                                                      *
862  *              Debugging related functions                             *
863  *                                                                      *
864  ************************************************************************/
865
866 #define STRANGE                                                         \
867     xmlGenericError(xmlGenericErrorContext,                             \
868             "Internal error at %s:%d\n",                                \
869             __FILE__, __LINE__);
870
871 #ifdef LIBXML_DEBUG_ENABLED
872 static void
873 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
874     int i;
875     char shift[100];
876
877     for (i = 0;((i < depth) && (i < 25));i++)
878         shift[2 * i] = shift[2 * i + 1] = ' ';
879     shift[2 * i] = shift[2 * i + 1] = 0;
880     if (cur == NULL) {
881         fprintf(output, shift);
882         fprintf(output, "Node is NULL !\n");
883         return;
884         
885     }
886
887     if ((cur->type == XML_DOCUMENT_NODE) ||
888              (cur->type == XML_HTML_DOCUMENT_NODE)) {
889         fprintf(output, shift);
890         fprintf(output, " /\n");
891     } else if (cur->type == XML_ATTRIBUTE_NODE)
892         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
893     else
894         xmlDebugDumpOneNode(output, cur, depth);
895 }
896 static void
897 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
898     xmlNodePtr tmp;
899     int i;
900     char shift[100];
901
902     for (i = 0;((i < depth) && (i < 25));i++)
903         shift[2 * i] = shift[2 * i + 1] = ' ';
904     shift[2 * i] = shift[2 * i + 1] = 0;
905     if (cur == NULL) {
906         fprintf(output, shift);
907         fprintf(output, "Node is NULL !\n");
908         return;
909         
910     }
911
912     while (cur != NULL) {
913         tmp = cur;
914         cur = cur->next;
915         xmlDebugDumpOneNode(output, tmp, depth);
916     }
917 }
918
919 static void
920 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
921     int i;
922     char shift[100];
923
924     for (i = 0;((i < depth) && (i < 25));i++)
925         shift[2 * i] = shift[2 * i + 1] = ' ';
926     shift[2 * i] = shift[2 * i + 1] = 0;
927
928     if (cur == NULL) {
929         fprintf(output, shift);
930         fprintf(output, "NodeSet is NULL !\n");
931         return;
932         
933     }
934
935     if (cur != NULL) {
936         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937         for (i = 0;i < cur->nodeNr;i++) {
938             fprintf(output, shift);
939             fprintf(output, "%d", i + 1);
940             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
941         }
942     }
943 }
944
945 static void
946 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
947     int i;
948     char shift[100];
949
950     for (i = 0;((i < depth) && (i < 25));i++)
951         shift[2 * i] = shift[2 * i + 1] = ' ';
952     shift[2 * i] = shift[2 * i + 1] = 0;
953
954     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955         fprintf(output, shift);
956         fprintf(output, "Value Tree is NULL !\n");
957         return;
958         
959     }
960
961     fprintf(output, shift);
962     fprintf(output, "%d", i + 1);
963     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
964 }
965 #if defined(LIBXML_XPTR_ENABLED)
966 static void
967 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
968     int i;
969     char shift[100];
970
971     for (i = 0;((i < depth) && (i < 25));i++)
972         shift[2 * i] = shift[2 * i + 1] = ' ';
973     shift[2 * i] = shift[2 * i + 1] = 0;
974
975     if (cur == NULL) {
976         fprintf(output, shift);
977         fprintf(output, "LocationSet is NULL !\n");
978         return;
979         
980     }
981
982     for (i = 0;i < cur->locNr;i++) {
983         fprintf(output, shift);
984         fprintf(output, "%d : ", i + 1);
985         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
986     }
987 }
988 #endif /* LIBXML_XPTR_ENABLED */
989
990 /**
991  * xmlXPathDebugDumpObject:
992  * @output:  the FILE * to dump the output
993  * @cur:  the object to inspect
994  * @depth:  indentation level
995  *
996  * Dump the content of the object for debugging purposes
997  */
998 void
999 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1000     int i;
1001     char shift[100];
1002
1003     if (output == NULL) return;
1004
1005     for (i = 0;((i < depth) && (i < 25));i++)
1006         shift[2 * i] = shift[2 * i + 1] = ' ';
1007     shift[2 * i] = shift[2 * i + 1] = 0;
1008
1009
1010     fprintf(output, shift);    
1011
1012     if (cur == NULL) {
1013         fprintf(output, "Object is empty (NULL)\n");
1014         return;
1015     }
1016     switch(cur->type) {
1017         case XPATH_UNDEFINED:
1018             fprintf(output, "Object is uninitialized\n");
1019             break;
1020         case XPATH_NODESET:
1021             fprintf(output, "Object is a Node Set :\n");
1022             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1023             break;
1024         case XPATH_XSLT_TREE:
1025             fprintf(output, "Object is an XSLT value tree :\n");
1026             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1027             break;
1028         case XPATH_BOOLEAN:
1029             fprintf(output, "Object is a Boolean : ");
1030             if (cur->boolval) fprintf(output, "true\n");
1031             else fprintf(output, "false\n");
1032             break;
1033         case XPATH_NUMBER:
1034             switch (xmlXPathIsInf(cur->floatval)) {
1035             case 1:
1036                 fprintf(output, "Object is a number : Infinity\n");
1037                 break;
1038             case -1:
1039                 fprintf(output, "Object is a number : -Infinity\n");
1040                 break;
1041             default:
1042                 if (xmlXPathIsNaN(cur->floatval)) {
1043                     fprintf(output, "Object is a number : NaN\n");
1044                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045                     fprintf(output, "Object is a number : 0\n");
1046                 } else {
1047                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
1048                 }
1049             }
1050             break;
1051         case XPATH_STRING:
1052             fprintf(output, "Object is a string : ");
1053             xmlDebugDumpString(output, cur->stringval);
1054             fprintf(output, "\n");
1055             break;
1056         case XPATH_POINT:
1057             fprintf(output, "Object is a point : index %d in node", cur->index);
1058             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059             fprintf(output, "\n");
1060             break;
1061         case XPATH_RANGE:
1062             if ((cur->user2 == NULL) ||
1063                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064                 fprintf(output, "Object is a collapsed range :\n");
1065                 fprintf(output, shift);
1066                 if (cur->index >= 0)
1067                     fprintf(output, "index %d in ", cur->index);
1068                 fprintf(output, "node\n");
1069                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1070                                       depth + 1);
1071             } else  {
1072                 fprintf(output, "Object is a range :\n");
1073                 fprintf(output, shift);
1074                 fprintf(output, "From ");
1075                 if (cur->index >= 0)
1076                     fprintf(output, "index %d in ", cur->index);
1077                 fprintf(output, "node\n");
1078                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1079                                       depth + 1);
1080                 fprintf(output, shift);
1081                 fprintf(output, "To ");
1082                 if (cur->index2 >= 0)
1083                     fprintf(output, "index %d in ", cur->index2);
1084                 fprintf(output, "node\n");
1085                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1086                                       depth + 1);
1087                 fprintf(output, "\n");
1088             }
1089             break;
1090         case XPATH_LOCATIONSET:
1091 #if defined(LIBXML_XPTR_ENABLED)
1092             fprintf(output, "Object is a Location Set:\n");
1093             xmlXPathDebugDumpLocationSet(output,
1094                     (xmlLocationSetPtr) cur->user, depth);
1095 #endif
1096             break;
1097         case XPATH_USERS:
1098             fprintf(output, "Object is user defined\n");
1099             break;
1100     }
1101 }
1102
1103 static void
1104 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1105                              xmlXPathStepOpPtr op, int depth) {
1106     int i;
1107     char shift[100];
1108
1109     for (i = 0;((i < depth) && (i < 25));i++)
1110         shift[2 * i] = shift[2 * i + 1] = ' ';
1111     shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113     fprintf(output, shift);
1114     if (op == NULL) {
1115         fprintf(output, "Step is NULL\n");
1116         return;
1117     }
1118     switch (op->op) {
1119         case XPATH_OP_END:
1120             fprintf(output, "END"); break;
1121         case XPATH_OP_AND:
1122             fprintf(output, "AND"); break;
1123         case XPATH_OP_OR:
1124             fprintf(output, "OR"); break;
1125         case XPATH_OP_EQUAL:
1126              if (op->value)
1127                  fprintf(output, "EQUAL =");
1128              else
1129                  fprintf(output, "EQUAL !=");
1130              break;
1131         case XPATH_OP_CMP:
1132              if (op->value)
1133                  fprintf(output, "CMP <");
1134              else
1135                  fprintf(output, "CMP >");
1136              if (!op->value2)
1137                  fprintf(output, "=");
1138              break;
1139         case XPATH_OP_PLUS:
1140              if (op->value == 0)
1141                  fprintf(output, "PLUS -");
1142              else if (op->value == 1)
1143                  fprintf(output, "PLUS +");
1144              else if (op->value == 2)
1145                  fprintf(output, "PLUS unary -");
1146              else if (op->value == 3)
1147                  fprintf(output, "PLUS unary - -");
1148              break;
1149         case XPATH_OP_MULT:
1150              if (op->value == 0)
1151                  fprintf(output, "MULT *");
1152              else if (op->value == 1)
1153                  fprintf(output, "MULT div");
1154              else
1155                  fprintf(output, "MULT mod");
1156              break;
1157         case XPATH_OP_UNION:
1158              fprintf(output, "UNION"); break;
1159         case XPATH_OP_ROOT:
1160              fprintf(output, "ROOT"); break;
1161         case XPATH_OP_NODE:
1162              fprintf(output, "NODE"); break;
1163         case XPATH_OP_RESET:
1164              fprintf(output, "RESET"); break;
1165         case XPATH_OP_SORT:
1166              fprintf(output, "SORT"); break;
1167         case XPATH_OP_COLLECT: {
1168             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1171             const xmlChar *prefix = op->value4;
1172             const xmlChar *name = op->value5;
1173
1174             fprintf(output, "COLLECT ");
1175             switch (axis) {
1176                 case AXIS_ANCESTOR:
1177                     fprintf(output, " 'ancestors' "); break;
1178                 case AXIS_ANCESTOR_OR_SELF:
1179                     fprintf(output, " 'ancestors-or-self' "); break;
1180                 case AXIS_ATTRIBUTE:
1181                     fprintf(output, " 'attributes' "); break;
1182                 case AXIS_CHILD:
1183                     fprintf(output, " 'child' "); break;
1184                 case AXIS_DESCENDANT:
1185                     fprintf(output, " 'descendant' "); break;
1186                 case AXIS_DESCENDANT_OR_SELF:
1187                     fprintf(output, " 'descendant-or-self' "); break;
1188                 case AXIS_FOLLOWING:
1189                     fprintf(output, " 'following' "); break;
1190                 case AXIS_FOLLOWING_SIBLING:
1191                     fprintf(output, " 'following-siblings' "); break;
1192                 case AXIS_NAMESPACE:
1193                     fprintf(output, " 'namespace' "); break;
1194                 case AXIS_PARENT:
1195                     fprintf(output, " 'parent' "); break;
1196                 case AXIS_PRECEDING:
1197                     fprintf(output, " 'preceding' "); break;
1198                 case AXIS_PRECEDING_SIBLING:
1199                     fprintf(output, " 'preceding-sibling' "); break;
1200                 case AXIS_SELF:
1201                     fprintf(output, " 'self' "); break;
1202             }
1203             switch (test) {
1204                 case NODE_TEST_NONE:
1205                     fprintf(output, "'none' "); break;
1206                 case NODE_TEST_TYPE:
1207                     fprintf(output, "'type' "); break;
1208                 case NODE_TEST_PI:
1209                     fprintf(output, "'PI' "); break;
1210                 case NODE_TEST_ALL:
1211                     fprintf(output, "'all' "); break;
1212                 case NODE_TEST_NS:
1213                     fprintf(output, "'namespace' "); break;
1214                 case NODE_TEST_NAME:
1215                     fprintf(output, "'name' "); break;
1216             }
1217             switch (type) {
1218                 case NODE_TYPE_NODE:
1219                     fprintf(output, "'node' "); break;
1220                 case NODE_TYPE_COMMENT:
1221                     fprintf(output, "'comment' "); break;
1222                 case NODE_TYPE_TEXT:
1223                     fprintf(output, "'text' "); break;
1224                 case NODE_TYPE_PI:
1225                     fprintf(output, "'PI' "); break;
1226             }
1227             if (prefix != NULL)
1228                 fprintf(output, "%s:", prefix);
1229             if (name != NULL)
1230                 fprintf(output, "%s", (const char *) name);
1231             break;
1232
1233         }
1234         case XPATH_OP_VALUE: {
1235             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1236
1237             fprintf(output, "ELEM ");
1238             xmlXPathDebugDumpObject(output, object, 0);
1239             goto finish;
1240         }
1241         case XPATH_OP_VARIABLE: {
1242             const xmlChar *prefix = op->value5;
1243             const xmlChar *name = op->value4;
1244
1245             if (prefix != NULL)
1246                 fprintf(output, "VARIABLE %s:%s", prefix, name);
1247             else
1248                 fprintf(output, "VARIABLE %s", name);
1249             break;
1250         }
1251         case XPATH_OP_FUNCTION: {
1252             int nbargs = op->value;
1253             const xmlChar *prefix = op->value5;
1254             const xmlChar *name = op->value4;
1255
1256             if (prefix != NULL)
1257                 fprintf(output, "FUNCTION %s:%s(%d args)",
1258                         prefix, name, nbargs);
1259             else
1260                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1261             break;
1262         }
1263         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1265         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1266 #ifdef LIBXML_XPTR_ENABLED
1267         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1268 #endif
1269         default:
1270         fprintf(output, "UNKNOWN %d\n", op->op); return;
1271     }
1272     fprintf(output, "\n");
1273 finish:
1274     if (op->ch1 >= 0)
1275         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1276     if (op->ch2 >= 0)
1277         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1278 }
1279
1280 /**
1281  * xmlXPathDebugDumpCompExpr:
1282  * @output:  the FILE * for the output
1283  * @comp:  the precompiled XPath expression
1284  * @depth:  the indentation level.
1285  *
1286  * Dumps the tree of the compiled XPath expression.
1287  */
1288 void
1289 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1290                           int depth) {
1291     int i;
1292     char shift[100];
1293
1294     if ((output == NULL) || (comp == NULL)) return;
1295
1296     for (i = 0;((i < depth) && (i < 25));i++)
1297         shift[2 * i] = shift[2 * i + 1] = ' ';
1298     shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300     fprintf(output, shift);
1301
1302     fprintf(output, "Compiled Expression : %d elements\n",
1303             comp->nbStep);
1304     i = comp->last;
1305     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1306 }
1307
1308 #ifdef XP_DEBUG_OBJ_USAGE
1309
1310 /*
1311 * XPath object usage related debugging variables.
1312 */
1313 static int xmlXPathDebugObjCounterUndefined = 0;
1314 static int xmlXPathDebugObjCounterNodeset = 0;
1315 static int xmlXPathDebugObjCounterBool = 0;
1316 static int xmlXPathDebugObjCounterNumber = 0;
1317 static int xmlXPathDebugObjCounterString = 0;
1318 static int xmlXPathDebugObjCounterPoint = 0;
1319 static int xmlXPathDebugObjCounterRange = 0;
1320 static int xmlXPathDebugObjCounterLocset = 0;
1321 static int xmlXPathDebugObjCounterUsers = 0;
1322 static int xmlXPathDebugObjCounterXSLTTree = 0;
1323 static int xmlXPathDebugObjCounterAll = 0;
1324
1325 static int xmlXPathDebugObjTotalUndefined = 0;
1326 static int xmlXPathDebugObjTotalNodeset = 0;
1327 static int xmlXPathDebugObjTotalBool = 0;
1328 static int xmlXPathDebugObjTotalNumber = 0;
1329 static int xmlXPathDebugObjTotalString = 0;
1330 static int xmlXPathDebugObjTotalPoint = 0;
1331 static int xmlXPathDebugObjTotalRange = 0;
1332 static int xmlXPathDebugObjTotalLocset = 0;
1333 static int xmlXPathDebugObjTotalUsers = 0;
1334 static int xmlXPathDebugObjTotalXSLTTree = 0;
1335 static int xmlXPathDebugObjTotalAll = 0; 
1336
1337 static int xmlXPathDebugObjMaxUndefined = 0;
1338 static int xmlXPathDebugObjMaxNodeset = 0;
1339 static int xmlXPathDebugObjMaxBool = 0;
1340 static int xmlXPathDebugObjMaxNumber = 0;
1341 static int xmlXPathDebugObjMaxString = 0;
1342 static int xmlXPathDebugObjMaxPoint = 0;
1343 static int xmlXPathDebugObjMaxRange = 0;
1344 static int xmlXPathDebugObjMaxLocset = 0;
1345 static int xmlXPathDebugObjMaxUsers = 0;
1346 static int xmlXPathDebugObjMaxXSLTTree = 0;
1347 static int xmlXPathDebugObjMaxAll = 0;
1348
1349 /* REVISIT TODO: Make this static when committing */
1350 static void
1351 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1352 {
1353     if (ctxt != NULL) {
1354         if (ctxt->cache != NULL) {
1355             xmlXPathContextCachePtr cache =
1356                 (xmlXPathContextCachePtr) ctxt->cache;
1357
1358             cache->dbgCachedAll = 0;
1359             cache->dbgCachedNodeset = 0;
1360             cache->dbgCachedString = 0;
1361             cache->dbgCachedBool = 0;
1362             cache->dbgCachedNumber = 0;
1363             cache->dbgCachedPoint = 0;
1364             cache->dbgCachedRange = 0;
1365             cache->dbgCachedLocset = 0;
1366             cache->dbgCachedUsers = 0;
1367             cache->dbgCachedXSLTTree = 0;
1368             cache->dbgCachedUndefined = 0; 
1369
1370             cache->dbgReusedAll = 0;
1371             cache->dbgReusedNodeset = 0;
1372             cache->dbgReusedString = 0;
1373             cache->dbgReusedBool = 0;
1374             cache->dbgReusedNumber = 0;
1375             cache->dbgReusedPoint = 0;
1376             cache->dbgReusedRange = 0;
1377             cache->dbgReusedLocset = 0;
1378             cache->dbgReusedUsers = 0;
1379             cache->dbgReusedXSLTTree = 0;
1380             cache->dbgReusedUndefined = 0;
1381         }
1382     }    
1383
1384     xmlXPathDebugObjCounterUndefined = 0;
1385     xmlXPathDebugObjCounterNodeset = 0;
1386     xmlXPathDebugObjCounterBool = 0;
1387     xmlXPathDebugObjCounterNumber = 0;
1388     xmlXPathDebugObjCounterString = 0;
1389     xmlXPathDebugObjCounterPoint = 0;
1390     xmlXPathDebugObjCounterRange = 0;
1391     xmlXPathDebugObjCounterLocset = 0;
1392     xmlXPathDebugObjCounterUsers = 0;
1393     xmlXPathDebugObjCounterXSLTTree = 0;
1394     xmlXPathDebugObjCounterAll = 0;
1395     
1396     xmlXPathDebugObjTotalUndefined = 0;
1397     xmlXPathDebugObjTotalNodeset = 0;
1398     xmlXPathDebugObjTotalBool = 0;
1399     xmlXPathDebugObjTotalNumber = 0;
1400     xmlXPathDebugObjTotalString = 0;
1401     xmlXPathDebugObjTotalPoint = 0;
1402     xmlXPathDebugObjTotalRange = 0;
1403     xmlXPathDebugObjTotalLocset = 0;
1404     xmlXPathDebugObjTotalUsers = 0;
1405     xmlXPathDebugObjTotalXSLTTree = 0;
1406     xmlXPathDebugObjTotalAll = 0; 
1407
1408     xmlXPathDebugObjMaxUndefined = 0;
1409     xmlXPathDebugObjMaxNodeset = 0;
1410     xmlXPathDebugObjMaxBool = 0;
1411     xmlXPathDebugObjMaxNumber = 0;
1412     xmlXPathDebugObjMaxString = 0;
1413     xmlXPathDebugObjMaxPoint = 0;
1414     xmlXPathDebugObjMaxRange = 0;
1415     xmlXPathDebugObjMaxLocset = 0;
1416     xmlXPathDebugObjMaxUsers = 0;
1417     xmlXPathDebugObjMaxXSLTTree = 0;
1418     xmlXPathDebugObjMaxAll = 0;
1419
1420 }
1421
1422 static void
1423 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424                               xmlXPathObjectType objType)
1425 {
1426     int isCached = 0;
1427
1428     if (ctxt != NULL) {
1429         if (ctxt->cache != NULL) {
1430             xmlXPathContextCachePtr cache =
1431                 (xmlXPathContextCachePtr) ctxt->cache;
1432             
1433             isCached = 1;
1434             
1435             cache->dbgReusedAll++;          
1436             switch (objType) {
1437                 case XPATH_UNDEFINED:
1438                     cache->dbgReusedUndefined++;
1439                     break;
1440                 case XPATH_NODESET:
1441                     cache->dbgReusedNodeset++;
1442                     break;
1443                 case XPATH_BOOLEAN:
1444                     cache->dbgReusedBool++;
1445                     break;
1446                 case XPATH_NUMBER:
1447                     cache->dbgReusedNumber++;
1448                     break;
1449                 case XPATH_STRING:
1450                     cache->dbgReusedString++;
1451                     break;
1452                 case XPATH_POINT:
1453                     cache->dbgReusedPoint++;
1454                     break;
1455                 case XPATH_RANGE:
1456                     cache->dbgReusedRange++;
1457                     break;
1458                 case XPATH_LOCATIONSET:
1459                     cache->dbgReusedLocset++;
1460                     break;
1461                 case XPATH_USERS:
1462                     cache->dbgReusedUsers++;
1463                     break;
1464                 case XPATH_XSLT_TREE:
1465                     cache->dbgReusedXSLTTree++;
1466                     break;
1467                 default:
1468                     break;
1469             }   
1470         }
1471     }
1472
1473     switch (objType) {
1474         case XPATH_UNDEFINED:
1475             if (! isCached)
1476                 xmlXPathDebugObjTotalUndefined++;
1477             xmlXPathDebugObjCounterUndefined++;     
1478             if (xmlXPathDebugObjCounterUndefined >
1479                 xmlXPathDebugObjMaxUndefined)
1480                 xmlXPathDebugObjMaxUndefined =
1481                     xmlXPathDebugObjCounterUndefined;
1482             break;
1483         case XPATH_NODESET:
1484             if (! isCached)
1485                 xmlXPathDebugObjTotalNodeset++;
1486             xmlXPathDebugObjCounterNodeset++;       
1487             if (xmlXPathDebugObjCounterNodeset >
1488                 xmlXPathDebugObjMaxNodeset)
1489                 xmlXPathDebugObjMaxNodeset =
1490                     xmlXPathDebugObjCounterNodeset;
1491             break;
1492         case XPATH_BOOLEAN:
1493             if (! isCached)
1494                 xmlXPathDebugObjTotalBool++;
1495             xmlXPathDebugObjCounterBool++;          
1496             if (xmlXPathDebugObjCounterBool >
1497                 xmlXPathDebugObjMaxBool)
1498                 xmlXPathDebugObjMaxBool =
1499                     xmlXPathDebugObjCounterBool;
1500             break;
1501         case XPATH_NUMBER:
1502             if (! isCached)
1503                 xmlXPathDebugObjTotalNumber++;
1504             xmlXPathDebugObjCounterNumber++;        
1505             if (xmlXPathDebugObjCounterNumber >
1506                 xmlXPathDebugObjMaxNumber)
1507                 xmlXPathDebugObjMaxNumber =
1508                     xmlXPathDebugObjCounterNumber;
1509             break;
1510         case XPATH_STRING:
1511             if (! isCached)
1512                 xmlXPathDebugObjTotalString++;
1513             xmlXPathDebugObjCounterString++;        
1514             if (xmlXPathDebugObjCounterString >
1515                 xmlXPathDebugObjMaxString)
1516                 xmlXPathDebugObjMaxString =
1517                     xmlXPathDebugObjCounterString;
1518             break;
1519         case XPATH_POINT:
1520             if (! isCached)
1521                 xmlXPathDebugObjTotalPoint++;
1522             xmlXPathDebugObjCounterPoint++;         
1523             if (xmlXPathDebugObjCounterPoint >
1524                 xmlXPathDebugObjMaxPoint)
1525                 xmlXPathDebugObjMaxPoint =
1526                     xmlXPathDebugObjCounterPoint;
1527             break;
1528         case XPATH_RANGE:
1529             if (! isCached)
1530                 xmlXPathDebugObjTotalRange++;
1531             xmlXPathDebugObjCounterRange++;
1532             if (xmlXPathDebugObjCounterRange >
1533                 xmlXPathDebugObjMaxRange)
1534                 xmlXPathDebugObjMaxRange =
1535                     xmlXPathDebugObjCounterRange;
1536             break;
1537         case XPATH_LOCATIONSET:
1538             if (! isCached)
1539                 xmlXPathDebugObjTotalLocset++;
1540             xmlXPathDebugObjCounterLocset++;
1541             if (xmlXPathDebugObjCounterLocset >
1542                 xmlXPathDebugObjMaxLocset)
1543                 xmlXPathDebugObjMaxLocset =
1544                     xmlXPathDebugObjCounterLocset;
1545             break;
1546         case XPATH_USERS:
1547             if (! isCached)
1548                 xmlXPathDebugObjTotalUsers++;
1549             xmlXPathDebugObjCounterUsers++;         
1550             if (xmlXPathDebugObjCounterUsers >
1551                 xmlXPathDebugObjMaxUsers)
1552                 xmlXPathDebugObjMaxUsers =
1553                     xmlXPathDebugObjCounterUsers;
1554             break;
1555         case XPATH_XSLT_TREE:
1556             if (! isCached)
1557                 xmlXPathDebugObjTotalXSLTTree++;
1558             xmlXPathDebugObjCounterXSLTTree++;      
1559             if (xmlXPathDebugObjCounterXSLTTree >
1560                 xmlXPathDebugObjMaxXSLTTree)
1561                 xmlXPathDebugObjMaxXSLTTree =
1562                     xmlXPathDebugObjCounterXSLTTree;
1563             break;
1564         default:
1565             break;
1566     }
1567     if (! isCached)
1568         xmlXPathDebugObjTotalAll++;
1569     xmlXPathDebugObjCounterAll++;
1570     if (xmlXPathDebugObjCounterAll >
1571         xmlXPathDebugObjMaxAll)
1572         xmlXPathDebugObjMaxAll =
1573             xmlXPathDebugObjCounterAll;
1574 }
1575
1576 static void
1577 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578                               xmlXPathObjectType objType)
1579 {
1580     int isCached = 0;
1581
1582     if (ctxt != NULL) {
1583         if (ctxt->cache != NULL) {
1584             xmlXPathContextCachePtr cache =
1585                 (xmlXPathContextCachePtr) ctxt->cache;
1586
1587             isCached = 1;           
1588             
1589             cache->dbgCachedAll++;
1590             switch (objType) {
1591                 case XPATH_UNDEFINED:
1592                     cache->dbgCachedUndefined++;
1593                     break;
1594                 case XPATH_NODESET:
1595                     cache->dbgCachedNodeset++;
1596                     break;
1597                 case XPATH_BOOLEAN:
1598                     cache->dbgCachedBool++;
1599                     break;
1600                 case XPATH_NUMBER:
1601                     cache->dbgCachedNumber++;
1602                     break;
1603                 case XPATH_STRING:
1604                     cache->dbgCachedString++;
1605                     break;
1606                 case XPATH_POINT:
1607                     cache->dbgCachedPoint++;
1608                     break;
1609                 case XPATH_RANGE:
1610                     cache->dbgCachedRange++;
1611                     break;
1612                 case XPATH_LOCATIONSET:
1613                     cache->dbgCachedLocset++;
1614                     break;
1615                 case XPATH_USERS:
1616                     cache->dbgCachedUsers++;
1617                     break;
1618                 case XPATH_XSLT_TREE:
1619                     cache->dbgCachedXSLTTree++;
1620                     break;
1621                 default:
1622                     break;
1623             }
1624             
1625         }
1626     }
1627     switch (objType) {
1628         case XPATH_UNDEFINED:
1629             xmlXPathDebugObjCounterUndefined--;
1630             break;
1631         case XPATH_NODESET:
1632             xmlXPathDebugObjCounterNodeset--;
1633             break;
1634         case XPATH_BOOLEAN:
1635             xmlXPathDebugObjCounterBool--;
1636             break;
1637         case XPATH_NUMBER:
1638             xmlXPathDebugObjCounterNumber--;
1639             break;
1640         case XPATH_STRING:
1641             xmlXPathDebugObjCounterString--;
1642             break;
1643         case XPATH_POINT:
1644             xmlXPathDebugObjCounterPoint--;
1645             break;
1646         case XPATH_RANGE:
1647             xmlXPathDebugObjCounterRange--;
1648             break;
1649         case XPATH_LOCATIONSET:
1650             xmlXPathDebugObjCounterLocset--;
1651             break;
1652         case XPATH_USERS:
1653             xmlXPathDebugObjCounterUsers--;
1654             break;
1655         case XPATH_XSLT_TREE:
1656             xmlXPathDebugObjCounterXSLTTree--;
1657             break;
1658         default:
1659             break;
1660     }   
1661     xmlXPathDebugObjCounterAll--;
1662 }
1663
1664 /* REVISIT TODO: Make this static when committing */
1665 static void
1666 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1667 {
1668     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669         reqXSLTTree, reqUndefined;
1670     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671         caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673         reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674     int leftObjs = xmlXPathDebugObjCounterAll;
1675
1676     reqAll = xmlXPathDebugObjTotalAll;
1677     reqNodeset = xmlXPathDebugObjTotalNodeset;
1678     reqString = xmlXPathDebugObjTotalString;
1679     reqBool = xmlXPathDebugObjTotalBool;
1680     reqNumber = xmlXPathDebugObjTotalNumber;
1681     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682     reqUndefined = xmlXPathDebugObjTotalUndefined;
1683     
1684     printf("# XPath object usage:\n");
1685
1686     if (ctxt != NULL) {
1687         if (ctxt->cache != NULL) {
1688             xmlXPathContextCachePtr cache =
1689                 (xmlXPathContextCachePtr) ctxt->cache;
1690
1691             reAll = cache->dbgReusedAll;
1692             reqAll += reAll;
1693             reNodeset = cache->dbgReusedNodeset;
1694             reqNodeset += reNodeset;
1695             reString = cache->dbgReusedString;
1696             reqString += reString;
1697             reBool = cache->dbgReusedBool;
1698             reqBool += reBool;
1699             reNumber = cache->dbgReusedNumber;
1700             reqNumber += reNumber;
1701             reXSLTTree = cache->dbgReusedXSLTTree;
1702             reqXSLTTree += reXSLTTree;
1703             reUndefined = cache->dbgReusedUndefined;
1704             reqUndefined += reUndefined;
1705             
1706             caAll = cache->dbgCachedAll;
1707             caBool = cache->dbgCachedBool;
1708             caNodeset = cache->dbgCachedNodeset;
1709             caString = cache->dbgCachedString;
1710             caNumber = cache->dbgCachedNumber;
1711             caXSLTTree = cache->dbgCachedXSLTTree;
1712             caUndefined = cache->dbgCachedUndefined;
1713             
1714             if (cache->nodesetObjs)
1715                 leftObjs -= cache->nodesetObjs->number;
1716             if (cache->stringObjs)
1717                 leftObjs -= cache->stringObjs->number;
1718             if (cache->booleanObjs)
1719                 leftObjs -= cache->booleanObjs->number;
1720             if (cache->numberObjs)
1721                 leftObjs -= cache->numberObjs->number;
1722             if (cache->miscObjs)
1723                 leftObjs -= cache->miscObjs->number;
1724         }
1725     }
1726        
1727     printf("# all\n");       
1728     printf("#   total  : %d\n", reqAll);
1729     printf("#   left  : %d\n", leftObjs);
1730     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1731     printf("#   reused : %d\n", reAll);
1732     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1733
1734     printf("# node-sets\n");
1735     printf("#   total  : %d\n", reqNodeset);
1736     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1737     printf("#   reused : %d\n", reNodeset);
1738     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1739
1740     printf("# strings\n");
1741     printf("#   total  : %d\n", reqString);
1742     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1743     printf("#   reused : %d\n", reString);
1744     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1745
1746     printf("# booleans\n");
1747     printf("#   total  : %d\n", reqBool);
1748     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1749     printf("#   reused : %d\n", reBool);
1750     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1751
1752     printf("# numbers\n");
1753     printf("#   total  : %d\n", reqNumber);
1754     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1755     printf("#   reused : %d\n", reNumber);
1756     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1757
1758     printf("# XSLT result tree fragments\n");
1759     printf("#   total  : %d\n", reqXSLTTree);
1760     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761     printf("#   reused : %d\n", reXSLTTree);
1762     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1763
1764     printf("# undefined\n");
1765     printf("#   total  : %d\n", reqUndefined);
1766     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1767     printf("#   reused : %d\n", reUndefined);
1768     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1769
1770 }
1771
1772 #endif /* XP_DEBUG_OBJ_USAGE */
1773
1774 #endif /* LIBXML_DEBUG_ENABLED */
1775
1776 /************************************************************************
1777  *                                                                      *
1778  *                      XPath object caching                            *
1779  *                                                                      *
1780  ************************************************************************/
1781
1782 /**
1783  * xmlXPathNewCache:
1784  *
1785  * Create a new object cache
1786  *
1787  * Returns the xmlXPathCache just allocated.
1788  */
1789 static xmlXPathContextCachePtr
1790 xmlXPathNewCache(void)
1791 {
1792     xmlXPathContextCachePtr ret;
1793
1794     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1795     if (ret == NULL) {
1796         xmlXPathErrMemory(NULL, "creating object cache\n");
1797         return(NULL);
1798     }
1799     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1800     ret->maxNodeset = 100;
1801     ret->maxString = 100;
1802     ret->maxBoolean = 100;
1803     ret->maxNumber = 100;
1804     ret->maxMisc = 100;
1805     return(ret);
1806 }
1807
1808 static void
1809 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1810 {
1811     int i;
1812     xmlXPathObjectPtr obj;
1813
1814     if (list == NULL)
1815         return;
1816
1817     for (i = 0; i < list->number; i++) {
1818         obj = list->items[i];
1819         /*
1820         * Note that it is already assured that we don't need to
1821         * look out for namespace nodes in the node-set.
1822         */
1823         if (obj->nodesetval != NULL) {
1824             if (obj->nodesetval->nodeTab != NULL)
1825                 xmlFree(obj->nodesetval->nodeTab);
1826             xmlFree(obj->nodesetval);
1827         }
1828         xmlFree(obj);
1829 #ifdef XP_DEBUG_OBJ_USAGE
1830         xmlXPathDebugObjCounterAll--;
1831 #endif
1832     }
1833     xmlPointerListFree(list);
1834 }
1835
1836 static void
1837 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1838 {
1839     if (cache == NULL)
1840         return;
1841     if (cache->nodesetObjs)
1842         xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1843     if (cache->stringObjs)
1844         xmlXPathCacheFreeObjectList(cache->stringObjs);
1845     if (cache->booleanObjs)
1846         xmlXPathCacheFreeObjectList(cache->booleanObjs);
1847     if (cache->numberObjs)
1848         xmlXPathCacheFreeObjectList(cache->numberObjs);
1849     if (cache->miscObjs)
1850         xmlXPathCacheFreeObjectList(cache->miscObjs);    
1851     xmlFree(cache);
1852 }
1853
1854 /**
1855  * xmlXPathContextSetCache:
1856  *
1857  * @ctxt:  the XPath context
1858  * @active: enables/disables (creates/frees) the cache
1859  * @value: a value with semantics dependant on @options 
1860  * @options: options (currently only the value 0 is used)
1861  *
1862  * Creates/frees an object cache on the XPath context.
1863  * If activates XPath objects (xmlXPathObject) will be cached internally
1864  * to be reused.
1865  * @options:
1866  *   0: This will set the XPath object caching:
1867  *      @value:
1868  *        This will set the maximum number of XPath objects
1869  *        to be cached per slot
1870  *        There are 5 slots for: node-set, string, number, boolean, and
1871  *        misc objects. Use <0 for the default number (100).
1872  *   Other values for @options have currently no effect.
1873  *
1874  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1875  */
1876 int
1877 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1878                         int active,
1879                         int value,
1880                         int options)
1881 {
1882     if (ctxt == NULL)
1883         return(-1);
1884     if (active) {
1885         xmlXPathContextCachePtr cache;
1886         
1887         if (ctxt->cache == NULL) {
1888             ctxt->cache = xmlXPathNewCache();
1889             if (ctxt->cache == NULL)
1890                 return(-1);
1891         }
1892         cache = (xmlXPathContextCachePtr) ctxt->cache;
1893         if (options == 0) {
1894             if (value < 0)
1895                 value = 100;
1896             cache->maxNodeset = value;
1897             cache->maxString = value;
1898             cache->maxNumber = value;
1899             cache->maxBoolean = value;
1900             cache->maxMisc = value;
1901         }
1902     } else if (ctxt->cache != NULL) {
1903         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1904         ctxt->cache = NULL;
1905     }
1906     return(0);
1907 }
1908
1909 /**
1910  * xmlXPathCacheWrapNodeSet:
1911  * @ctxt: the XPath context
1912  * @val:  the NodePtr value
1913  *
1914  * This is the cached version of xmlXPathWrapNodeSet().
1915  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1916  *
1917  * Returns the created or reused object.
1918  */
1919 static xmlXPathObjectPtr
1920 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1921 {    
1922     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923         xmlXPathContextCachePtr cache =
1924             (xmlXPathContextCachePtr) ctxt->cache;
1925
1926         if ((cache->miscObjs != NULL) &&
1927             (cache->miscObjs->number != 0))
1928         {
1929             xmlXPathObjectPtr ret;
1930             
1931             ret = (xmlXPathObjectPtr)
1932                 cache->miscObjs->items[--cache->miscObjs->number];
1933             ret->type = XPATH_NODESET;
1934             ret->nodesetval = val;
1935 #ifdef XP_DEBUG_OBJ_USAGE
1936             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1937 #endif
1938             return(ret);            
1939         }
1940     }
1941             
1942     return(xmlXPathWrapNodeSet(val));
1943     
1944 }
1945
1946 /**
1947  * xmlXPathCacheWrapString:
1948  * @ctxt: the XPath context
1949  * @val:  the xmlChar * value
1950  *
1951  * This is the cached version of xmlXPathWrapString().
1952  * Wraps the @val string into an XPath object.
1953  *
1954  * Returns the created or reused object.
1955  */
1956 static xmlXPathObjectPtr
1957 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1958 {    
1959     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1961
1962         if ((cache->stringObjs != NULL) &&
1963             (cache->stringObjs->number != 0))
1964         {
1965         
1966             xmlXPathObjectPtr ret;
1967             
1968             ret = (xmlXPathObjectPtr)
1969                 cache->stringObjs->items[--cache->stringObjs->number];
1970             ret->type = XPATH_STRING;
1971             ret->stringval = val;
1972 #ifdef XP_DEBUG_OBJ_USAGE
1973             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1974 #endif
1975             return(ret);
1976         } else if ((cache->miscObjs != NULL) &&
1977             (cache->miscObjs->number != 0))
1978         {
1979             xmlXPathObjectPtr ret;
1980             /*
1981             * Fallback to misc-cache.
1982             */
1983             ret = (xmlXPathObjectPtr)
1984                 cache->miscObjs->items[--cache->miscObjs->number];
1985
1986             ret->type = XPATH_STRING;
1987             ret->stringval = val;
1988 #ifdef XP_DEBUG_OBJ_USAGE
1989             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1990 #endif
1991             return(ret);
1992         }
1993     }
1994     return(xmlXPathWrapString(val));
1995 }
1996
1997 /**
1998  * xmlXPathCacheNewNodeSet:
1999  * @ctxt: the XPath context
2000  * @val:  the NodePtr value
2001  *
2002  * This is the cached version of xmlXPathNewNodeSet().
2003  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004  * it with the single Node @val
2005  *
2006  * Returns the created or reused object.
2007  */
2008 static xmlXPathObjectPtr
2009 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2010 {
2011     if ((ctxt != NULL) && (ctxt->cache)) {
2012         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2013
2014         if ((cache->nodesetObjs != NULL) &&
2015             (cache->nodesetObjs->number != 0))
2016         {       
2017             xmlXPathObjectPtr ret;
2018             /*
2019             * Use the nodset-cache.
2020             */      
2021             ret = (xmlXPathObjectPtr)
2022                 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023             ret->type = XPATH_NODESET;
2024             ret->boolval = 0;
2025             if (val) {          
2026                 if ((ret->nodesetval->nodeMax == 0) ||
2027                     (val->type == XML_NAMESPACE_DECL))
2028                 {
2029                     xmlXPathNodeSetAddUnique(ret->nodesetval, val);             
2030                 } else {
2031                     ret->nodesetval->nodeTab[0] = val;
2032                     ret->nodesetval->nodeNr = 1;
2033                 }
2034             }
2035 #ifdef XP_DEBUG_OBJ_USAGE
2036             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2037 #endif
2038             return(ret);
2039         } else if ((cache->miscObjs != NULL) &&
2040             (cache->miscObjs->number != 0))
2041         {
2042             xmlXPathObjectPtr ret;
2043             /*
2044             * Fallback to misc-cache.
2045             */
2046
2047             ret = (xmlXPathObjectPtr)
2048                 cache->miscObjs->items[--cache->miscObjs->number];
2049
2050             ret->type = XPATH_NODESET;
2051             ret->boolval = 0;
2052             ret->nodesetval = xmlXPathNodeSetCreate(val);
2053 #ifdef XP_DEBUG_OBJ_USAGE
2054             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2055 #endif
2056             return(ret);
2057         }
2058     }
2059     return(xmlXPathNewNodeSet(val));
2060 }
2061
2062 /**
2063  * xmlXPathCacheNewCString:
2064  * @ctxt: the XPath context
2065  * @val:  the char * value
2066  *
2067  * This is the cached version of xmlXPathNewCString().
2068  * Acquire an xmlXPathObjectPtr of type string and of value @val
2069  *
2070  * Returns the created or reused object.
2071  */
2072 static xmlXPathObjectPtr
2073 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2074 {    
2075     if ((ctxt != NULL) && (ctxt->cache)) {
2076         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2077
2078         if ((cache->stringObjs != NULL) &&
2079             (cache->stringObjs->number != 0))
2080         {       
2081             xmlXPathObjectPtr ret;
2082             
2083             ret = (xmlXPathObjectPtr)
2084                 cache->stringObjs->items[--cache->stringObjs->number];
2085
2086             ret->type = XPATH_STRING;
2087             ret->stringval = xmlStrdup(BAD_CAST val);
2088 #ifdef XP_DEBUG_OBJ_USAGE
2089             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2090 #endif
2091             return(ret);
2092         } else if ((cache->miscObjs != NULL) &&
2093             (cache->miscObjs->number != 0))
2094         {
2095             xmlXPathObjectPtr ret;
2096
2097             ret = (xmlXPathObjectPtr)
2098                 cache->miscObjs->items[--cache->miscObjs->number];
2099
2100             ret->type = XPATH_STRING;
2101             ret->stringval = xmlStrdup(BAD_CAST val);
2102 #ifdef XP_DEBUG_OBJ_USAGE
2103             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2104 #endif
2105             return(ret);
2106         }
2107     }
2108     return(xmlXPathNewCString(val));
2109 }
2110
2111 /**
2112  * xmlXPathCacheNewString:
2113  * @ctxt: the XPath context
2114  * @val:  the xmlChar * value
2115  *
2116  * This is the cached version of xmlXPathNewString().
2117  * Acquire an xmlXPathObjectPtr of type string and of value @val
2118  *
2119  * Returns the created or reused object.
2120  */
2121 static xmlXPathObjectPtr
2122 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2123 {    
2124     if ((ctxt != NULL) && (ctxt->cache)) {
2125         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2126
2127         if ((cache->stringObjs != NULL) &&
2128             (cache->stringObjs->number != 0))
2129         {       
2130             xmlXPathObjectPtr ret;
2131             
2132             ret = (xmlXPathObjectPtr)
2133                 cache->stringObjs->items[--cache->stringObjs->number];
2134             ret->type = XPATH_STRING;
2135             if (val != NULL)
2136                 ret->stringval = xmlStrdup(val);
2137             else
2138                 ret->stringval = xmlStrdup((const xmlChar *)"");
2139 #ifdef XP_DEBUG_OBJ_USAGE
2140             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2141 #endif
2142             return(ret);
2143         } else if ((cache->miscObjs != NULL) &&
2144             (cache->miscObjs->number != 0))
2145         {
2146             xmlXPathObjectPtr ret;
2147
2148             ret = (xmlXPathObjectPtr)
2149                 cache->miscObjs->items[--cache->miscObjs->number];
2150
2151             ret->type = XPATH_STRING;
2152             if (val != NULL)
2153                 ret->stringval = xmlStrdup(val);
2154             else
2155                 ret->stringval = xmlStrdup((const xmlChar *)"");
2156 #ifdef XP_DEBUG_OBJ_USAGE
2157             xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2158 #endif
2159             return(ret);
2160         }
2161     }
2162     return(xmlXPathNewString(val));
2163 }
2164
2165 /**
2166  * xmlXPathCacheNewBoolean:
2167  * @ctxt: the XPath context
2168  * @val:  the boolean value
2169  *
2170  * This is the cached version of xmlXPathNewBoolean().
2171  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2172  *
2173  * Returns the created or reused object.
2174  */
2175 static xmlXPathObjectPtr
2176 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2177 {    
2178     if ((ctxt != NULL) && (ctxt->cache)) {
2179         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2180
2181         if ((cache->booleanObjs != NULL) &&
2182             (cache->booleanObjs->number != 0))
2183         {       
2184             xmlXPathObjectPtr ret;
2185             
2186             ret = (xmlXPathObjectPtr)
2187                 cache->booleanObjs->items[--cache->booleanObjs->number];
2188             ret->type = XPATH_BOOLEAN;
2189             ret->boolval = (val != 0);
2190 #ifdef XP_DEBUG_OBJ_USAGE
2191             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2192 #endif
2193             return(ret);
2194         } else if ((cache->miscObjs != NULL) &&
2195             (cache->miscObjs->number != 0))
2196         {
2197             xmlXPathObjectPtr ret;
2198
2199             ret = (xmlXPathObjectPtr)
2200                 cache->miscObjs->items[--cache->miscObjs->number];
2201
2202             ret->type = XPATH_BOOLEAN;
2203             ret->boolval = (val != 0);
2204 #ifdef XP_DEBUG_OBJ_USAGE
2205             xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2206 #endif
2207             return(ret);
2208         }
2209     }
2210     return(xmlXPathNewBoolean(val));
2211 }
2212
2213 /**
2214  * xmlXPathCacheNewFloat:
2215  * @ctxt: the XPath context
2216  * @val:  the double value
2217  *
2218  * This is the cached version of xmlXPathNewFloat().
2219  * Acquires an xmlXPathObjectPtr of type double and of value @val
2220  *
2221  * Returns the created or reused object.
2222  */
2223 static xmlXPathObjectPtr
2224 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2225 {
2226      if ((ctxt != NULL) && (ctxt->cache)) {
2227         xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2228
2229         if ((cache->numberObjs != NULL) &&
2230             (cache->numberObjs->number != 0))
2231         {       
2232             xmlXPathObjectPtr ret;
2233             
2234             ret = (xmlXPathObjectPtr)
2235                 cache->numberObjs->items[--cache->numberObjs->number];
2236             ret->type = XPATH_NUMBER;
2237             ret->floatval = val;
2238 #ifdef XP_DEBUG_OBJ_USAGE
2239             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2240 #endif
2241             return(ret);
2242         } else if ((cache->miscObjs != NULL) &&
2243             (cache->miscObjs->number != 0))
2244         {
2245             xmlXPathObjectPtr ret;
2246
2247             ret = (xmlXPathObjectPtr)
2248                 cache->miscObjs->items[--cache->miscObjs->number];
2249
2250             ret->type = XPATH_NUMBER;
2251             ret->floatval = val;
2252 #ifdef XP_DEBUG_OBJ_USAGE
2253             xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2254 #endif
2255             return(ret);
2256         }
2257     }
2258     return(xmlXPathNewFloat(val));
2259 }
2260
2261 /**
2262  * xmlXPathCacheConvertString:
2263  * @ctxt: the XPath context
2264  * @val:  an XPath object
2265  *
2266  * This is the cached version of xmlXPathConvertString().
2267  * Converts an existing object to its string() equivalent
2268  *
2269  * Returns a created or reused object, the old one is freed (cached)
2270  *         (or the operation is done directly on @val)
2271  */
2272
2273 static xmlXPathObjectPtr
2274 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275     xmlChar *res = NULL;    
2276
2277     if (val == NULL)
2278         return(xmlXPathCacheNewCString(ctxt, ""));
2279
2280     switch (val->type) {
2281     case XPATH_UNDEFINED:
2282 #ifdef DEBUG_EXPR
2283         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2284 #endif
2285         break;
2286     case XPATH_NODESET:
2287     case XPATH_XSLT_TREE:
2288         res = xmlXPathCastNodeSetToString(val->nodesetval);
2289         break;
2290     case XPATH_STRING:
2291         return(val);
2292     case XPATH_BOOLEAN:
2293         res = xmlXPathCastBooleanToString(val->boolval);
2294         break;
2295     case XPATH_NUMBER:
2296         res = xmlXPathCastNumberToString(val->floatval);
2297         break;
2298     case XPATH_USERS:
2299     case XPATH_POINT:
2300     case XPATH_RANGE:
2301     case XPATH_LOCATIONSET:
2302         TODO;
2303         break;
2304     }
2305     xmlXPathReleaseObject(ctxt, val);
2306     if (res == NULL)
2307         return(xmlXPathCacheNewCString(ctxt, ""));
2308     return(xmlXPathCacheWrapString(ctxt, res));
2309 }
2310
2311 /**
2312  * xmlXPathCacheObjectCopy:
2313  * @ctxt: the XPath context
2314  * @val:  the original object
2315  *
2316  * This is the cached version of xmlXPathObjectCopy().
2317  * Acquire a copy of a given object
2318  *
2319  * Returns a created or reused created object.
2320  */
2321 static xmlXPathObjectPtr
2322 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2323 {
2324     if (val == NULL)
2325         return(NULL);
2326
2327     if (XP_HAS_CACHE(ctxt)) {
2328         switch (val->type) {
2329             case XPATH_NODESET:
2330                 return(xmlXPathCacheWrapNodeSet(ctxt,
2331                     xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2332             case XPATH_STRING:
2333                 return(xmlXPathCacheNewString(ctxt, val->stringval));
2334             case XPATH_BOOLEAN:
2335                 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2336             case XPATH_NUMBER:
2337                 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2338             default:
2339                 break;
2340         }
2341     }
2342     return(xmlXPathObjectCopy(val));
2343 }
2344
2345 /**
2346  * xmlXPathCacheConvertBoolean:
2347  * @ctxt: the XPath context
2348  * @val:  an XPath object
2349  *
2350  * This is the cached version of xmlXPathConvertBoolean().
2351  * Converts an existing object to its boolean() equivalent
2352  *
2353  * Returns a created or reused object, the old one is freed (or the operation
2354  *         is done directly on @val)
2355  */
2356 static xmlXPathObjectPtr
2357 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358     xmlXPathObjectPtr ret;
2359     
2360     if (val == NULL)
2361         return(xmlXPathCacheNewBoolean(ctxt, 0));
2362     if (val->type == XPATH_BOOLEAN)
2363         return(val);
2364     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365     xmlXPathReleaseObject(ctxt, val);
2366     return(ret);
2367 }
2368
2369 /**
2370  * xmlXPathCacheConvertNumber:
2371  * @ctxt: the XPath context
2372  * @val:  an XPath object
2373  *
2374  * This is the cached version of xmlXPathConvertNumber().
2375  * Converts an existing object to its number() equivalent
2376  *
2377  * Returns a created or reused object, the old one is freed (or the operation
2378  *         is done directly on @val)
2379  */
2380 static xmlXPathObjectPtr
2381 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382     xmlXPathObjectPtr ret;
2383     
2384     if (val == NULL)
2385         return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386     if (val->type == XPATH_NUMBER)
2387         return(val);
2388     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389     xmlXPathReleaseObject(ctxt, val);
2390     return(ret);
2391 }
2392
2393 /************************************************************************
2394  *                                                                      *
2395  *              Parser stacks related functions and macros              *
2396  *                                                                      *
2397  ************************************************************************/
2398
2399 /**
2400  * valuePop:
2401  * @ctxt: an XPath evaluation context
2402  *
2403  * Pops the top XPath object from the value stack
2404  *
2405  * Returns the XPath object just removed
2406  */
2407 xmlXPathObjectPtr
2408 valuePop(xmlXPathParserContextPtr ctxt)
2409 {
2410     xmlXPathObjectPtr ret;
2411
2412     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2413         return (NULL);
2414     ctxt->valueNr--;
2415     if (ctxt->valueNr > 0)
2416         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2417     else
2418         ctxt->value = NULL;
2419     ret = ctxt->valueTab[ctxt->valueNr];
2420     ctxt->valueTab[ctxt->valueNr] = NULL;
2421     return (ret);
2422 }
2423 /**
2424  * valuePush:
2425  * @ctxt:  an XPath evaluation context
2426  * @value:  the XPath object
2427  *
2428  * Pushes a new XPath object on top of the value stack
2429  *
2430  * returns the number of items on the value stack
2431  */
2432 int
2433 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2434 {
2435     if ((ctxt == NULL) || (value == NULL)) return(-1);
2436     if (ctxt->valueNr >= ctxt->valueMax) {
2437         xmlXPathObjectPtr *tmp;
2438
2439         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440                                              2 * ctxt->valueMax *
2441                                              sizeof(ctxt->valueTab[0]));
2442         if (tmp == NULL) {
2443             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2444             return (0);
2445         }
2446         ctxt->valueMax *= 2;
2447         ctxt->valueTab = tmp;
2448     }
2449     ctxt->valueTab[ctxt->valueNr] = value;
2450     ctxt->value = value;
2451     return (ctxt->valueNr++);
2452 }
2453
2454 /**
2455  * xmlXPathPopBoolean:
2456  * @ctxt:  an XPath parser context
2457  *
2458  * Pops a boolean from the stack, handling conversion if needed.
2459  * Check error with #xmlXPathCheckError.
2460  *
2461  * Returns the boolean
2462  */
2463 int
2464 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465     xmlXPathObjectPtr obj;
2466     int ret;
2467
2468     obj = valuePop(ctxt);
2469     if (obj == NULL) {
2470         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2471         return(0);
2472     }
2473     if (obj->type != XPATH_BOOLEAN)
2474         ret = xmlXPathCastToBoolean(obj);
2475     else
2476         ret = obj->boolval;
2477     xmlXPathReleaseObject(ctxt->context, obj);
2478     return(ret);
2479 }
2480
2481 /**
2482  * xmlXPathPopNumber:
2483  * @ctxt:  an XPath parser context
2484  *
2485  * Pops a number from the stack, handling conversion if needed.
2486  * Check error with #xmlXPathCheckError.
2487  *
2488  * Returns the number
2489  */
2490 double
2491 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492     xmlXPathObjectPtr obj;
2493     double ret;
2494
2495     obj = valuePop(ctxt);
2496     if (obj == NULL) {
2497         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2498         return(0);
2499     }
2500     if (obj->type != XPATH_NUMBER)
2501         ret = xmlXPathCastToNumber(obj);
2502     else
2503         ret = obj->floatval;
2504     xmlXPathReleaseObject(ctxt->context, obj);
2505     return(ret);
2506 }
2507
2508 /**
2509  * xmlXPathPopString:
2510  * @ctxt:  an XPath parser context
2511  *
2512  * Pops a string from the stack, handling conversion if needed.
2513  * Check error with #xmlXPathCheckError.
2514  *
2515  * Returns the string
2516  */
2517 xmlChar *
2518 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519     xmlXPathObjectPtr obj;
2520     xmlChar * ret;
2521
2522     obj = valuePop(ctxt);
2523     if (obj == NULL) {
2524         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2525         return(NULL);
2526     }
2527     ret = xmlXPathCastToString(obj);    /* this does required strdup */
2528     /* TODO: needs refactoring somewhere else */
2529     if (obj->stringval == ret)
2530         obj->stringval = NULL;
2531     xmlXPathReleaseObject(ctxt->context, obj);
2532     return(ret);
2533 }
2534
2535 /**
2536  * xmlXPathPopNodeSet:
2537  * @ctxt:  an XPath parser context
2538  *
2539  * Pops a node-set from the stack, handling conversion if needed.
2540  * Check error with #xmlXPathCheckError.
2541  *
2542  * Returns the node-set
2543  */
2544 xmlNodeSetPtr
2545 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546     xmlXPathObjectPtr obj;
2547     xmlNodeSetPtr ret;
2548
2549     if (ctxt == NULL) return(NULL);
2550     if (ctxt->value == NULL) {
2551         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2552         return(NULL);
2553     }
2554     if (!xmlXPathStackIsNodeSet(ctxt)) {
2555         xmlXPathSetTypeError(ctxt);
2556         return(NULL);
2557     }
2558     obj = valuePop(ctxt);
2559     ret = obj->nodesetval;
2560 #if 0
2561     /* to fix memory leak of not clearing obj->user */
2562     if (obj->boolval && obj->user != NULL)
2563         xmlFreeNodeList((xmlNodePtr) obj->user);
2564 #endif
2565     obj->nodesetval = NULL;
2566     xmlXPathReleaseObject(ctxt->context, obj);
2567     return(ret);
2568 }
2569
2570 /**
2571  * xmlXPathPopExternal:
2572  * @ctxt:  an XPath parser context
2573  *
2574  * Pops an external object from the stack, handling conversion if needed.
2575  * Check error with #xmlXPathCheckError.
2576  *
2577  * Returns the object
2578  */
2579 void *
2580 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581     xmlXPathObjectPtr obj;
2582     void * ret;
2583
2584     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2585         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586         return(NULL);
2587     }
2588     if (ctxt->value->type != XPATH_USERS) {
2589         xmlXPathSetTypeError(ctxt);
2590         return(NULL);
2591     }
2592     obj = valuePop(ctxt);
2593     ret = obj->user;
2594     obj->user = NULL;
2595     xmlXPathReleaseObject(ctxt->context, obj);
2596     return(ret);
2597 }
2598
2599 /*
2600  * Macros for accessing the content. Those should be used only by the parser,
2601  * and not exported.
2602  *
2603  * Dirty macros, i.e. one need to make assumption on the context to use them
2604  *
2605  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2606  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2607  *           in ISO-Latin or UTF-8.
2608  *           This should be used internally by the parser
2609  *           only to compare to ASCII values otherwise it would break when
2610  *           running with UTF-8 encoding.
2611  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2612  *           to compare on ASCII based substring.
2613  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614  *           strings within the parser.
2615  *   CURRENT Returns the current char value, with the full decoding of
2616  *           UTF-8 if we are using this mode. It returns an int.
2617  *   NEXT    Skip to the next character, this does the proper decoding
2618  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619  *           It returns the pointer to the current xmlChar.
2620  */
2621
2622 #define CUR (*ctxt->cur)
2623 #define SKIP(val) ctxt->cur += (val)
2624 #define NXT(val) ctxt->cur[(val)]
2625 #define CUR_PTR ctxt->cur
2626 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2627
2628 #define COPY_BUF(l,b,i,v)                                              \
2629     if (l == 1) b[i++] = (xmlChar) v;                                  \
2630     else i += xmlCopyChar(l,&b[i],v)
2631
2632 #define NEXTL(l)  ctxt->cur += l
2633
2634 #define SKIP_BLANKS                                                     \
2635     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2636
2637 #define CURRENT (*ctxt->cur)
2638 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2639
2640
2641 #ifndef DBL_DIG
2642 #define DBL_DIG 16
2643 #endif
2644 #ifndef DBL_EPSILON
2645 #define DBL_EPSILON 1E-9
2646 #endif
2647
2648 #define UPPER_DOUBLE 1E9
2649 #define LOWER_DOUBLE 1E-5
2650
2651 #define INTEGER_DIGITS DBL_DIG
2652 #define FRACTION_DIGITS (DBL_DIG + 1)
2653 #define EXPONENT_DIGITS (3 + 2)
2654
2655 /**
2656  * xmlXPathFormatNumber:
2657  * @number:     number to format
2658  * @buffer:     output buffer
2659  * @buffersize: size of output buffer
2660  *
2661  * Convert the number into a string representation.
2662  */
2663 static void
2664 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2665 {
2666     switch (xmlXPathIsInf(number)) {
2667     case 1:
2668         if (buffersize > (int)sizeof("Infinity"))
2669             snprintf(buffer, buffersize, "Infinity");
2670         break;
2671     case -1:
2672         if (buffersize > (int)sizeof("-Infinity"))
2673             snprintf(buffer, buffersize, "-Infinity");
2674         break;
2675     default:
2676         if (xmlXPathIsNaN(number)) {
2677             if (buffersize > (int)sizeof("NaN"))
2678                 snprintf(buffer, buffersize, "NaN");
2679         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2680             snprintf(buffer, buffersize, "0");
2681         } else if (number == ((int) number)) {
2682             char work[30];
2683             char *ptr, *cur;
2684             int value = (int) number;
2685
2686             ptr = &buffer[0];
2687             if (value == 0) {
2688                 *ptr++ = '0';
2689             } else {
2690                 snprintf(work, 29, "%d", value);
2691                 cur = &work[0];
2692                 while ((*cur) && (ptr - buffer < buffersize)) {
2693                     *ptr++ = *cur++;
2694                 }
2695             }
2696             if (ptr - buffer < buffersize) {
2697                 *ptr = 0;
2698             } else if (buffersize > 0) {
2699                 ptr--;
2700                 *ptr = 0;
2701             }
2702         } else {
2703             /* 3 is sign, decimal point, and terminating zero */
2704             char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705             int integer_place, fraction_place;
2706             char *ptr;
2707             char *after_fraction;
2708             double absolute_value;
2709             int size;
2710
2711             absolute_value = fabs(number);
2712
2713             /*
2714              * First choose format - scientific or regular floating point.
2715              * In either case, result is in work, and after_fraction points
2716              * just past the fractional part.
2717             */
2718             if ( ((absolute_value > UPPER_DOUBLE) ||
2719                   (absolute_value < LOWER_DOUBLE)) &&
2720                  (absolute_value != 0.0) ) {
2721                 /* Use scientific notation */
2722                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723                 fraction_place = DBL_DIG - 1;
2724                 size = snprintf(work, sizeof(work),"%*.*e",
2725                          integer_place, fraction_place, number);
2726                 while ((size > 0) && (work[size] != 'e')) size--;
2727                 after_fraction = work + size;
2728
2729             }
2730             else {
2731                 /* Use regular notation */
2732                 if (absolute_value > 0.0)
2733                     integer_place = 1 + (int)log10(absolute_value);
2734                 else
2735                     integer_place = 0;
2736                 fraction_place = (integer_place > 0)
2737                     ? DBL_DIG - integer_place
2738                     : DBL_DIG;
2739                 size = snprintf(work, sizeof(work), "%0.*f",
2740                                 fraction_place, number);
2741                 after_fraction = work + size;
2742             }
2743
2744             /* Remove fractional trailing zeroes */
2745             ptr = after_fraction;
2746             while (*(--ptr) == '0')
2747                 ;
2748             if (*ptr != '.')
2749                 ptr++;
2750             while ((*ptr++ = *after_fraction++) != 0);
2751
2752             /* Finally copy result back to caller */
2753             size = strlen(work) + 1;
2754             if (size > buffersize) {
2755                 work[buffersize - 1] = 0;
2756                 size = buffersize;
2757             }
2758             memmove(buffer, work, size);
2759         }
2760         break;
2761     }
2762 }
2763
2764
2765 /************************************************************************
2766  *                                                                      *
2767  *                      Routines to handle NodeSets                     *
2768  *                                                                      *
2769  ************************************************************************/
2770
2771 /**
2772  * xmlXPathOrderDocElems:
2773  * @doc:  an input document
2774  *
2775  * Call this routine to speed up XPath computation on static documents.
2776  * This stamps all the element nodes with the document order
2777  * Like for line information, the order is kept in the element->content
2778  * field, the value stored is actually - the node number (starting at -1)
2779  * to be able to differentiate from line numbers.
2780  *
2781  * Returns the number of elements found in the document or -1 in case
2782  *    of error.
2783  */
2784 long
2785 xmlXPathOrderDocElems(xmlDocPtr doc) {
2786     long count = 0;
2787     xmlNodePtr cur;
2788
2789     if (doc == NULL)
2790         return(-1);
2791     cur = doc->children;
2792     while (cur != NULL) {
2793         if (cur->type == XML_ELEMENT_NODE) {
2794             cur->content = (void *) (-(++count));
2795             if (cur->children != NULL) {
2796                 cur = cur->children;
2797                 continue;
2798             }
2799         }
2800         if (cur->next != NULL) {
2801             cur = cur->next;
2802             continue;
2803         }
2804         do {
2805             cur = cur->parent;
2806             if (cur == NULL)
2807                 break;
2808             if (cur == (xmlNodePtr) doc) {
2809                 cur = NULL;
2810                 break;
2811             }
2812             if (cur->next != NULL) {
2813                 cur = cur->next;
2814                 break;
2815             }
2816         } while (cur != NULL);
2817     }
2818     return(count);
2819 }
2820
2821 /**
2822  * xmlXPathCmpNodes:
2823  * @node1:  the first node
2824  * @node2:  the second node
2825  *
2826  * Compare two nodes w.r.t document order
2827  *
2828  * Returns -2 in case of error 1 if first point < second point, 0 if
2829  *         it's the same node, -1 otherwise
2830  */
2831 int
2832 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2833     int depth1, depth2;
2834     int attr1 = 0, attr2 = 0;
2835     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2836     xmlNodePtr cur, root;
2837
2838     if ((node1 == NULL) || (node2 == NULL))
2839         return(-2);
2840     /*
2841      * a couple of optimizations which will avoid computations in most cases
2842      */
2843     if (node1->type == XML_ATTRIBUTE_NODE) {
2844         attr1 = 1;
2845         attrNode1 = node1;
2846         node1 = node1->parent;
2847     }
2848     if (node2->type == XML_ATTRIBUTE_NODE) {
2849         attr2 = 1;
2850         attrNode2 = node2;
2851         node2 = node2->parent;
2852     }
2853     if (node1 == node2) {
2854         if (attr1 == attr2) {
2855             /* not required, but we keep attributes in order */
2856             if (attr1 != 0) {
2857                 cur = attrNode2->prev;
2858                 while (cur != NULL) {
2859                     if (cur == attrNode1)
2860                         return (1);
2861                     cur = cur->prev;
2862                 }
2863                 return (-1);
2864             }
2865             return(0);
2866         }
2867         if (attr2 == 1)
2868             return(1);
2869         return(-1);
2870     }
2871     if ((node1->type == XML_NAMESPACE_DECL) ||
2872         (node2->type == XML_NAMESPACE_DECL))
2873         return(1);
2874     if (node1 == node2->prev)
2875         return(1);
2876     if (node1 == node2->next)
2877         return(-1);
2878
2879     /*
2880      * Speedup using document order if availble.
2881      */
2882     if ((node1->type == XML_ELEMENT_NODE) &&
2883         (node2->type == XML_ELEMENT_NODE) &&
2884         (0 > (long) node1->content) &&
2885         (0 > (long) node2->content) &&
2886         (node1->doc == node2->doc)) {
2887         long l1, l2;
2888
2889         l1 = -((long) node1->content);
2890         l2 = -((long) node2->content);
2891         if (l1 < l2)
2892             return(1);
2893         if (l1 > l2)
2894             return(-1);
2895     }
2896
2897     /*
2898      * compute depth to root
2899      */
2900     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2901         if (cur == node1)
2902             return(1);
2903         depth2++;
2904     }
2905     root = cur;
2906     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2907         if (cur == node2)
2908             return(-1);
2909         depth1++;
2910     }
2911     /*
2912      * Distinct document (or distinct entities :-( ) case.
2913      */
2914     if (root != cur) {
2915         return(-2);
2916     }
2917     /*
2918      * get the nearest common ancestor.
2919      */
2920     while (depth1 > depth2) {
2921         depth1--;
2922         node1 = node1->parent;
2923     }
2924     while (depth2 > depth1) {
2925         depth2--;
2926         node2 = node2->parent;
2927     }
2928     while (node1->parent != node2->parent) {
2929         node1 = node1->parent;
2930         node2 = node2->parent;
2931         /* should not happen but just in case ... */
2932         if ((node1 == NULL) || (node2 == NULL))
2933             return(-2);
2934     }
2935     /*
2936      * Find who's first.
2937      */
2938     if (node1 == node2->prev)
2939         return(1);
2940     if (node1 == node2->next)
2941         return(-1);
2942     /*
2943      * Speedup using document order if availble.
2944      */
2945     if ((node1->type == XML_ELEMENT_NODE) &&
2946         (node2->type == XML_ELEMENT_NODE) &&
2947         (0 > (long) node1->content) &&
2948         (0 > (long) node2->content) &&
2949         (node1->doc == node2->doc)) {
2950         long l1, l2;
2951
2952         l1 = -((long) node1->content);
2953         l2 = -((long) node2->content);
2954         if (l1 < l2)
2955             return(1);
2956         if (l1 > l2)
2957             return(-1);
2958     }
2959
2960     for (cur = node1->next;cur != NULL;cur = cur->next)
2961         if (cur == node2)
2962             return(1);
2963     return(-1); /* assume there is no sibling list corruption */
2964 }
2965
2966 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2967 /**
2968  * xmlXPathCmpNodesExt:
2969  * @node1:  the first node
2970  * @node2:  the second node
2971  *
2972  * Compare two nodes w.r.t document order.
2973  * This one is optimized for handling of non-element nodes.
2974  *
2975  * Returns -2 in case of error 1 if first point < second point, 0 if
2976  *         it's the same node, -1 otherwise
2977  */
2978 static int
2979 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2980     int depth1, depth2;
2981     int misc = 0, precedence1 = 0, precedence2 = 0;
2982     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983     xmlNodePtr cur, root;
2984     long l1, l2;
2985
2986     if ((node1 == NULL) || (node2 == NULL))
2987         return(-2);
2988
2989     if (node1 == node2)
2990         return(0);
2991    
2992     /*
2993      * a couple of optimizations which will avoid computations in most cases
2994      */    
2995     switch (node1->type) {
2996         case XML_ELEMENT_NODE:
2997             if (node2->type == XML_ELEMENT_NODE) {
2998                 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999                     (0 > (long) node2->content) &&
3000                     (node1->doc == node2->doc))
3001                 {               
3002                     l1 = -((long) node1->content);
3003                     l2 = -((long) node2->content);
3004                     if (l1 < l2)
3005                         return(1);
3006                     if (l1 > l2)
3007                         return(-1);
3008                 } else
3009                     goto turtle_comparison;                 
3010             }
3011             break;
3012         case XML_ATTRIBUTE_NODE:
3013             precedence1 = 1; /* element is owner */
3014             miscNode1 = node1;
3015             node1 = node1->parent;
3016             misc = 1;
3017             break;
3018         case XML_TEXT_NODE:
3019         case XML_CDATA_SECTION_NODE:
3020         case XML_COMMENT_NODE:
3021         case XML_PI_NODE: {
3022             miscNode1 = node1;
3023             /*
3024             * Find nearest element node.
3025             */      
3026             if (node1->prev != NULL) {
3027                 do {
3028                     node1 = node1->prev;
3029                     if (node1->type == XML_ELEMENT_NODE) {
3030                         precedence1 = 3; /* element in prev-sibl axis */
3031                         break;
3032                     }
3033                     if (node1->prev == NULL) {
3034                         precedence1 = 2; /* element is parent */
3035                         /*
3036                         * URGENT TODO: Are there any cases, where the
3037                         * parent of such a node is not an element node?
3038                         */
3039                         node1 = node1->parent;
3040                         break;
3041                     }
3042                 } while (1);
3043             } else {
3044                 precedence1 = 2; /* element is parent */
3045                 node1 = node1->parent;
3046             }
3047             if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3048                 /*
3049                 * Fallback for whatever case.
3050                 */
3051                 node1 = miscNode1;
3052                 precedence1 = 0;
3053             } else
3054                 misc = 1;
3055         }
3056             break;
3057         case XML_NAMESPACE_DECL:
3058             /*
3059             * TODO: why do we return 1 for namespace nodes?
3060             */
3061             return(1);
3062         default:
3063             break;
3064     }    
3065     switch (node2->type) {
3066         case XML_ELEMENT_NODE:      
3067             break;
3068         case XML_ATTRIBUTE_NODE:
3069             precedence2 = 1; /* element is owner */
3070             miscNode2 = node2;
3071             node2 = node2->parent;
3072             misc = 1;
3073             break;
3074         case XML_TEXT_NODE:
3075         case XML_CDATA_SECTION_NODE:
3076         case XML_COMMENT_NODE:
3077         case XML_PI_NODE: {
3078             miscNode2 = node2;
3079             if (node2->prev != NULL) {
3080                 do {
3081                     node2 = node2->prev;
3082                     if (node2->type == XML_ELEMENT_NODE) {
3083                         precedence2 = 3; /* element in prev-sibl axis */
3084                         break;
3085                     }
3086                     if (node2->prev == NULL) {
3087                         precedence2 = 2; /* element is parent */
3088                         node2 = node2->parent;
3089                         break;
3090                     }
3091                 } while (1);
3092             } else {
3093                 precedence2 = 2; /* element is parent */
3094                 node2 = node2->parent;
3095             }       
3096             if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097                 (0 <= (long) node1->content))
3098             {
3099                 node2 = miscNode2;
3100                 precedence2 = 0;
3101             } else
3102                 misc = 1;
3103         }
3104             break;
3105         case XML_NAMESPACE_DECL:
3106             return(1);
3107         default:
3108             break;
3109     }
3110     if (misc) {
3111         if (node1 == node2) {
3112             if (precedence1 == precedence2) {
3113                 /*
3114                 * The ugly case; but normally there aren't many
3115                 * adjacent non-element nodes around.
3116                 */
3117                 cur = miscNode2->prev;
3118                 while (cur != NULL) {
3119                     if (cur == miscNode1)
3120                         return(1);
3121                     if (cur->type == XML_ELEMENT_NODE)
3122                         return(-1);
3123                     cur = cur->prev;
3124                 }
3125                 return (-1);
3126             } else {
3127                 /*
3128                 * Evaluate based on higher precedence wrt to the element.
3129                 * TODO: This assumes attributes are sorted before content.
3130                 *   Is this 100% correct?
3131                 */
3132                 if (precedence1 < precedence2)
3133                     return(1); 
3134                 else
3135                     return(-1);     
3136             }
3137         }    
3138         /*
3139         * Special case: One of the helper-elements is contained by the other.
3140         * <foo>
3141         *   <node2>
3142         *     <node1>Text-1(precedence1 == 2)</node1>
3143         *   </node2>
3144         *   Text-6(precedence2 == 3)
3145         * </foo>
3146         */      
3147         if ((precedence2 == 3) && (precedence1 > 1)) {
3148             cur = node1->parent;
3149             while (cur) {
3150                 if (cur == node2)
3151                     return(1);
3152                 cur = cur->parent;
3153             }
3154         }
3155         if ((precedence1 == 3) && (precedence2 > 1)) {  
3156             cur = node2->parent;
3157             while (cur) {
3158                 if (cur == node1)
3159                     return(-1);
3160                 cur = cur->parent;
3161             }
3162         }
3163     }        
3164
3165     /*
3166      * Speedup using document order if availble.
3167      */
3168     if ((node1->type == XML_ELEMENT_NODE) &&    
3169         (node2->type == XML_ELEMENT_NODE) &&
3170         (0 > (long) node1->content) &&
3171         (0 > (long) node2->content) &&
3172         (node1->doc == node2->doc)) {   
3173
3174         l1 = -((long) node1->content);
3175         l2 = -((long) node2->content);
3176         if (l1 < l2)
3177             return(1);
3178         if (l1 > l2)
3179             return(-1);
3180     }
3181
3182 turtle_comparison:
3183
3184     if (node1 == node2->prev)
3185         return(1);
3186     if (node1 == node2->next)
3187         return(-1);
3188     /*
3189      * compute depth to root
3190      */
3191     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3192         if (cur == node1)
3193             return(1);
3194         depth2++;
3195     }
3196     root = cur;
3197     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3198         if (cur == node2)
3199             return(-1);
3200         depth1++;
3201     }
3202     /*
3203      * Distinct document (or distinct entities :-( ) case.
3204      */
3205     if (root != cur) {
3206         return(-2);
3207     }
3208     /*
3209      * get the nearest common ancestor.
3210      */
3211     while (depth1 > depth2) {
3212         depth1--;
3213         node1 = node1->parent;
3214     }
3215     while (depth2 > depth1) {
3216         depth2--;
3217         node2 = node2->parent;
3218     }
3219     while (node1->parent != node2->parent) {
3220         node1 = node1->parent;
3221         node2 = node2->parent;
3222         /* should not happen but just in case ... */
3223         if ((node1 == NULL) || (node2 == NULL))
3224             return(-2);
3225     }
3226     /*
3227      * Find who's first.
3228      */
3229     if (node1 == node2->prev)
3230         return(1);
3231     if (node1 == node2->next)
3232         return(-1);
3233     /*
3234      * Speedup using document order if availble.
3235      */
3236     if ((node1->type == XML_ELEMENT_NODE) &&
3237         (node2->type == XML_ELEMENT_NODE) &&
3238         (0 > (long) node1->content) &&
3239         (0 > (long) node2->content) &&
3240         (node1->doc == node2->doc)) {   
3241
3242         l1 = -((long) node1->content);
3243         l2 = -((long) node2->content);
3244         if (l1 < l2)
3245             return(1);
3246         if (l1 > l2)
3247             return(-1);
3248     }
3249
3250     for (cur = node1->next;cur != NULL;cur = cur->next)
3251         if (cur == node2)
3252             return(1);
3253     return(-1); /* assume there is no sibling list corruption */
3254 }
3255 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3256
3257 /**
3258  * xmlXPathNodeSetSort:
3259  * @set:  the node set
3260  *
3261  * Sort the node set in document order
3262  */
3263 void
3264 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3265     int i, j, incr, len;
3266     xmlNodePtr tmp;
3267
3268     if (set == NULL)
3269         return;
3270
3271     /* Use Shell's sort to sort the node-set */
3272     len = set->nodeNr;
3273     for (incr = len / 2; incr > 0; incr /= 2) {
3274         for (i = incr; i < len; i++) {
3275             j = i - incr;
3276             while (j >= 0) {
3277 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3278                 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279                         set->nodeTab[j + incr]) == -1)
3280 #else
3281                 if (xmlXPathCmpNodes(set->nodeTab[j],
3282                         set->nodeTab[j + incr]) == -1)
3283 #endif
3284                 {
3285                     tmp = set->nodeTab[j];
3286                     set->nodeTab[j] = set->nodeTab[j + incr];
3287                     set->nodeTab[j + incr] = tmp;
3288                     j -= incr;
3289                 } else
3290                     break;
3291             }
3292         }
3293     }
3294 }
3295
3296 #define XML_NODESET_DEFAULT     10
3297 /**
3298  * xmlXPathNodeSetDupNs:
3299  * @node:  the parent node of the namespace XPath node
3300  * @ns:  the libxml namespace declaration node.
3301  *
3302  * Namespace node in libxml don't match the XPath semantic. In a node set
3303  * the namespace nodes are duplicated and the next pointer is set to the
3304  * parent node in the XPath semantic.
3305  *
3306  * Returns the newly created object.
3307  */
3308 static xmlNodePtr
3309 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3310     xmlNsPtr cur;
3311
3312     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3313         return(NULL);
3314     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315         return((xmlNodePtr) ns);
3316
3317     /*
3318      * Allocate a new Namespace and fill the fields.
3319      */
3320     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3321     if (cur == NULL) {
3322         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3323         return(NULL);
3324     }
3325     memset(cur, 0, sizeof(xmlNs));
3326     cur->type = XML_NAMESPACE_DECL;
3327     if (ns->href != NULL)
3328         cur->href = xmlStrdup(ns->href); 
3329     if (ns->prefix != NULL)
3330         cur->prefix = xmlStrdup(ns->prefix); 
3331     cur->next = (xmlNsPtr) node;
3332     return((xmlNodePtr) cur);
3333 }
3334
3335 /**
3336  * xmlXPathNodeSetFreeNs:
3337  * @ns:  the XPath namespace node found in a nodeset.
3338  *
3339  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3340  * the namespace nodes are duplicated and the next pointer is set to the
3341  * parent node in the XPath semantic. Check if such a node needs to be freed
3342  */
3343 void
3344 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3346         return;
3347
3348     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349         if (ns->href != NULL)
3350             xmlFree((xmlChar *)ns->href);
3351         if (ns->prefix != NULL)
3352             xmlFree((xmlChar *)ns->prefix);
3353         xmlFree(ns);
3354     }
3355 }
3356
3357 /**
3358  * xmlXPathNodeSetCreate:
3359  * @val:  an initial xmlNodePtr, or NULL
3360  *
3361  * Create a new xmlNodeSetPtr of type double and of value @val
3362  *
3363  * Returns the newly created object.
3364  */
3365 xmlNodeSetPtr
3366 xmlXPathNodeSetCreate(xmlNodePtr val) {
3367     xmlNodeSetPtr ret;
3368
3369     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3370     if (ret == NULL) {
3371         xmlXPathErrMemory(NULL, "creating nodeset\n");
3372         return(NULL);
3373     }
3374     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3375     if (val != NULL) {
3376         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377                                              sizeof(xmlNodePtr));
3378         if (ret->nodeTab == NULL) {
3379             xmlXPathErrMemory(NULL, "creating nodeset\n");
3380             xmlFree(ret);
3381             return(NULL);
3382         }
3383         memset(ret->nodeTab, 0 ,
3384                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385         ret->nodeMax = XML_NODESET_DEFAULT;
3386         if (val->type == XML_NAMESPACE_DECL) {
3387             xmlNsPtr ns = (xmlNsPtr) val;
3388
3389             ret->nodeTab[ret->nodeNr++] =
3390                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3391         } else
3392             ret->nodeTab[ret->nodeNr++] = val;
3393     }
3394     return(ret);
3395 }
3396
3397 /**
3398  * xmlXPathNodeSetCreateSize:
3399  * @size:  the initial size of the set
3400  *
3401  * Create a new xmlNodeSetPtr of type double and of value @val
3402  *
3403  * Returns the newly created object.
3404  */
3405 static xmlNodeSetPtr
3406 xmlXPathNodeSetCreateSize(int size) {
3407     xmlNodeSetPtr ret;
3408
3409     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3410     if (ret == NULL) {
3411         xmlXPathErrMemory(NULL, "creating nodeset\n");
3412         return(NULL);
3413     }
3414     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415     if (size < XML_NODESET_DEFAULT)
3416         size = XML_NODESET_DEFAULT;
3417     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418     if (ret->nodeTab == NULL) {
3419         xmlXPathErrMemory(NULL, "creating nodeset\n");
3420         xmlFree(ret);
3421         return(NULL);
3422     }
3423     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424     ret->nodeMax = size;  
3425     return(ret);
3426 }
3427
3428 /**
3429  * xmlXPathNodeSetContains:
3430  * @cur:  the node-set
3431  * @val:  the node
3432  *
3433  * checks whether @cur contains @val
3434  *
3435  * Returns true (1) if @cur contains @val, false (0) otherwise
3436  */
3437 int
3438 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439     int i;
3440
3441     if ((cur == NULL) || (val == NULL)) return(0);
3442     if (val->type == XML_NAMESPACE_DECL) {
3443         for (i = 0; i < cur->nodeNr; i++) {
3444             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445                 xmlNsPtr ns1, ns2;
3446
3447                 ns1 = (xmlNsPtr) val;
3448                 ns2 = (xmlNsPtr) cur->nodeTab[i];
3449                 if (ns1 == ns2)
3450                     return(1);
3451                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453                     return(1);
3454             }
3455         }
3456     } else {
3457         for (i = 0; i < cur->nodeNr; i++) {
3458             if (cur->nodeTab[i] == val)
3459                 return(1);
3460         }
3461     }
3462     return(0);
3463 }
3464
3465 /**
3466  * xmlXPathNodeSetAddNs:
3467  * @cur:  the initial node set
3468  * @node:  the hosting node
3469  * @ns:  a the namespace node
3470  *
3471  * add a new namespace node to an existing NodeSet
3472  */
3473 void
3474 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475     int i;
3476
3477     
3478     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479         (ns->type != XML_NAMESPACE_DECL) ||
3480         (node->type != XML_ELEMENT_NODE))
3481         return;
3482
3483     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3484     /*
3485      * prevent duplicates
3486      */
3487     for (i = 0;i < cur->nodeNr;i++) {
3488         if ((cur->nodeTab[i] != NULL) &&
3489             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3490             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3491             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492             return;
3493     }
3494
3495     /*
3496      * grow the nodeTab if needed
3497      */
3498     if (cur->nodeMax == 0) {
3499         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500                                              sizeof(xmlNodePtr));
3501         if (cur->nodeTab == NULL) {
3502             xmlXPathErrMemory(NULL, "growing nodeset\n");
3503             return;
3504         }
3505         memset(cur->nodeTab, 0 ,
3506                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507         cur->nodeMax = XML_NODESET_DEFAULT;
3508     } else if (cur->nodeNr == cur->nodeMax) {
3509         xmlNodePtr *temp;
3510
3511         cur->nodeMax *= 2;
3512         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513                                       sizeof(xmlNodePtr));
3514         if (temp == NULL) {
3515             xmlXPathErrMemory(NULL, "growing nodeset\n");
3516             return;
3517         }
3518         cur->nodeTab = temp;
3519     }
3520     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521 }
3522
3523 /**
3524  * xmlXPathNodeSetAdd:
3525  * @cur:  the initial node set
3526  * @val:  a new xmlNodePtr
3527  *
3528  * add a new xmlNodePtr to an existing NodeSet
3529  */
3530 void
3531 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532     int i;
3533
3534     if ((cur == NULL) || (val == NULL)) return;
3535
3536 #if 0
3537     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538         return; /* an XSLT fake node */
3539 #endif
3540
3541     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542     /*
3543      * prevent duplcates
3544      */
3545     for (i = 0;i < cur->nodeNr;i++)
3546         if (cur->nodeTab[i] == val) return;
3547
3548     /*
3549      * grow the nodeTab if needed
3550      */
3551     if (cur->nodeMax == 0) {
3552         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553                                              sizeof(xmlNodePtr));
3554         if (cur->nodeTab == NULL) {
3555             xmlXPathErrMemory(NULL, "growing nodeset\n");
3556             return;
3557         }
3558         memset(cur->nodeTab, 0 ,
3559                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560         cur->nodeMax = XML_NODESET_DEFAULT;
3561     } else if (cur->nodeNr == cur->nodeMax) {
3562         xmlNodePtr *temp;
3563
3564         cur->nodeMax *= 2;
3565         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566                                       sizeof(xmlNodePtr));
3567         if (temp == NULL) {
3568             xmlXPathErrMemory(NULL, "growing nodeset\n");
3569             return;
3570         }
3571         cur->nodeTab = temp;
3572     }
3573     if (val->type == XML_NAMESPACE_DECL) {
3574         xmlNsPtr ns = (xmlNsPtr) val;
3575
3576         cur->nodeTab[cur->nodeNr++] = 
3577             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578     } else
3579         cur->nodeTab[cur->nodeNr++] = val;
3580 }
3581
3582 /**
3583  * xmlXPathNodeSetAddUnique:
3584  * @cur:  the initial node set
3585  * @val:  a new xmlNodePtr
3586  *
3587  * add a new xmlNodePtr to an existing NodeSet, optimized version
3588  * when we are sure the node is not already in the set.
3589  */
3590 void
3591 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3592     if ((cur == NULL) || (val == NULL)) return;
3593
3594 #if 0
3595     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596         return; /* an XSLT fake node */
3597 #endif
3598
3599     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600     /*
3601      * grow the nodeTab if needed
3602      */
3603     if (cur->nodeMax == 0) {
3604         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605                                              sizeof(xmlNodePtr));
3606         if (cur->nodeTab == NULL) {
3607             xmlXPathErrMemory(NULL, "growing nodeset\n");
3608             return;
3609         }
3610         memset(cur->nodeTab, 0 ,
3611                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612         cur->nodeMax = XML_NODESET_DEFAULT;
3613     } else if (cur->nodeNr == cur->nodeMax) {
3614         xmlNodePtr *temp;
3615
3616         cur->nodeMax *= 2;
3617         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618                                       sizeof(xmlNodePtr));
3619         if (temp == NULL) {
3620             xmlXPathErrMemory(NULL, "growing nodeset\n");
3621             return;
3622         }
3623         cur->nodeTab = temp;
3624     }
3625     if (val->type == XML_NAMESPACE_DECL) {
3626         xmlNsPtr ns = (xmlNsPtr) val;
3627
3628         cur->nodeTab[cur->nodeNr++] = 
3629             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630     } else
3631         cur->nodeTab[cur->nodeNr++] = val;
3632 }
3633
3634 /**
3635  * xmlXPathNodeSetMerge:
3636  * @val1:  the first NodeSet or NULL
3637  * @val2:  the second NodeSet
3638  *
3639  * Merges two nodesets, all nodes from @val2 are added to @val1
3640  * if @val1 is NULL, a new set is created and copied from @val2
3641  *
3642  * Returns @val1 once extended or NULL in case of error.
3643  */
3644 xmlNodeSetPtr
3645 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3646     int i, j, initNr, skip;
3647     xmlNodePtr n1, n2;
3648
3649     if (val2 == NULL) return(val1);
3650     if (val1 == NULL) {
3651         val1 = xmlXPathNodeSetCreate(NULL);
3652 #if 0
3653         /*
3654         * TODO: The optimization won't work in every case, since
3655         *  those nasty namespace nodes need to be added with
3656         *  xmlXPathNodeSetDupNs() to the set; thus a pure
3657         *  memcpy is not possible.
3658         *  If there was a flag on the nodesetval, indicating that
3659         *  some temporary nodes are in, that would be helpfull.
3660         */
3661         /*      
3662         * Optimization: Create an equally sized node-set
3663         * and memcpy the content.
3664         */
3665         val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3666         if (val1 == NULL)
3667             return(NULL);
3668         if (val2->nodeNr != 0) {
3669             if (val2->nodeNr == 1)
3670                 *(val1->nodeTab) = *(val2->nodeTab);
3671             else {
3672                 memcpy(val1->nodeTab, val2->nodeTab,
3673                     val2->nodeNr * sizeof(xmlNodePtr));
3674             }
3675             val1->nodeNr = val2->nodeNr;
3676         }
3677         return(val1);
3678 #endif
3679     }
3680
3681     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3682     initNr = val1->nodeNr;
3683
3684     for (i = 0;i < val2->nodeNr;i++) {
3685         n2 = val2->nodeTab[i]; 
3686         /*
3687          * check against duplicates
3688          */
3689         skip = 0;
3690         for (j = 0; j < initNr; j++) {
3691             n1 = val1->nodeTab[j];
3692             if (n1 == n2) {
3693                 skip = 1;
3694                 break;
3695             } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696                        (n2->type == XML_NAMESPACE_DECL)) {              
3697                 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698                     (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699                         ((xmlNsPtr) n2)->prefix)))
3700                 {
3701                     skip = 1;
3702                     break;
3703                 }
3704             }
3705         }
3706         if (skip)
3707             continue;
3708
3709         /*
3710          * grow the nodeTab if needed
3711          */
3712         if (val1->nodeMax == 0) {
3713             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714                                                     sizeof(xmlNodePtr));
3715             if (val1->nodeTab == NULL) {
3716                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3717                 return(NULL);
3718             }
3719             memset(val1->nodeTab, 0 ,
3720                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721             val1->nodeMax = XML_NODESET_DEFAULT;
3722         } else if (val1->nodeNr == val1->nodeMax) {
3723             xmlNodePtr *temp;
3724
3725             val1->nodeMax *= 2;
3726             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727                                              sizeof(xmlNodePtr));
3728             if (temp == NULL) {
3729                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3730                 return(NULL);
3731             }
3732             val1->nodeTab = temp;
3733         }
3734         if (n2->type == XML_NAMESPACE_DECL) {
3735             xmlNsPtr ns = (xmlNsPtr) n2;
3736
3737             val1->nodeTab[val1->nodeNr++] =
3738                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3739         } else
3740             val1->nodeTab[val1->nodeNr++] = n2;
3741     }
3742
3743     return(val1);
3744 }
3745
3746 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3747 /**
3748  * xmlXPathNodeSetMergeUnique:
3749  * @val1:  the first NodeSet or NULL
3750  * @val2:  the second NodeSet
3751  *
3752  * Merges two nodesets, all nodes from @val2 are added to @val1
3753  * if @val1 is NULL, a new set is created and copied from @val2
3754  *
3755  * Returns @val1 once extended or NULL in case of error.
3756  */
3757 static xmlNodeSetPtr
3758 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3759     int i;
3760
3761     if (val2 == NULL) return(val1);
3762     if (val1 == NULL) {
3763         val1 = xmlXPathNodeSetCreate(NULL);
3764     }
3765
3766     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3767
3768     for (i = 0;i < val2->nodeNr;i++) {
3769         /*
3770          * grow the nodeTab if needed
3771          */
3772         if (val1->nodeMax == 0) {
3773             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774                                                     sizeof(xmlNodePtr));
3775             if (val1->nodeTab == NULL) {
3776                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3777                 return(NULL);
3778             }
3779             memset(val1->nodeTab, 0 ,
3780                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781             val1->nodeMax = XML_NODESET_DEFAULT;
3782         } else if (val1->nodeNr == val1->nodeMax) {
3783             xmlNodePtr *temp;
3784
3785             val1->nodeMax *= 2;
3786             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787                                              sizeof(xmlNodePtr));
3788             if (temp == NULL) {
3789                 xmlXPathErrMemory(NULL, "merging nodeset\n");
3790                 return(NULL);
3791             }
3792             val1->nodeTab = temp;
3793         }
3794         if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795             xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3796
3797             val1->nodeTab[val1->nodeNr++] =
3798                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799         } else
3800             val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3801     }
3802
3803     return(val1);
3804 }
3805 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3806
3807 /**
3808  * xmlXPathNodeSetMergeAndClear:
3809  * @set1:  the first NodeSet or NULL
3810  * @set2:  the second NodeSet
3811  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3812  *
3813  * Merges two nodesets, all nodes from @set2 are added to @set1
3814  * if @set1 is NULL, a new set is created and copied from @set2.
3815  * Checks for duplicate nodes. Clears set2.
3816  *
3817  * Returns @set1 once extended or NULL in case of error.
3818  */
3819 static xmlNodeSetPtr
3820 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3821                              int hasNullEntries)
3822 {
3823     if ((set1 == NULL) && (hasNullEntries == 0)) {
3824         /*
3825         * Note that doing a memcpy of the list, namespace nodes are
3826         * just assigned to set1, since set2 is cleared anyway.
3827         */
3828         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3829         if (set1 == NULL)
3830             return(NULL);
3831         if (set2->nodeNr != 0) {
3832             memcpy(set1->nodeTab, set2->nodeTab,
3833                 set2->nodeNr * sizeof(xmlNodePtr));
3834             set1->nodeNr = set2->nodeNr;
3835         }
3836     } else {
3837         int i, j, initNbSet1;
3838         xmlNodePtr n1, n2;
3839
3840         if (set1 == NULL)
3841                 set1 = xmlXPathNodeSetCreate(NULL);
3842
3843         initNbSet1 = set1->nodeNr;        
3844         for (i = 0;i < set2->nodeNr;i++) {
3845             n2 = set2->nodeTab[i];
3846             /*
3847             * Skip NULLed entries.
3848             */
3849             if (n2 == NULL)
3850                 continue;
3851             /*
3852             * Skip duplicates.
3853             */
3854             for (j = 0; j < initNbSet1; j++) {
3855                 n1 = set1->nodeTab[j];
3856                 if (n1 == n2) {             
3857                     goto skip_node;
3858                 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3859                     (n2->type == XML_NAMESPACE_DECL))
3860                 {               
3861                     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862                         (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863                         ((xmlNsPtr) n2)->prefix)))
3864                     {
3865                         /*
3866                         * Free the namespace node.
3867                         */
3868                         set2->nodeTab[i] = NULL;
3869                         xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3870                         goto skip_node;
3871                     }
3872                 }
3873             }
3874             /*
3875             * grow the nodeTab if needed
3876             */
3877             if (set1->nodeMax == 0) {
3878                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880                 if (set1->nodeTab == NULL) {
3881                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3882                     return(NULL);
3883                 }
3884                 memset(set1->nodeTab, 0,
3885                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886                 set1->nodeMax = XML_NODESET_DEFAULT;
3887             } else if (set1->nodeNr >= set1->nodeMax) {
3888                 xmlNodePtr *temp;
3889                 
3890                 set1->nodeMax *= 2;
3891                 temp = (xmlNodePtr *) xmlRealloc(
3892                     set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3893                 if (temp == NULL) {
3894                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3895                     return(NULL);
3896                 }
3897                 set1->nodeTab = temp;
3898             }
3899             if (n2->type == XML_NAMESPACE_DECL) {
3900                 xmlNsPtr ns = (xmlNsPtr) n2;
3901                 
3902                 set1->nodeTab[set1->nodeNr++] =
3903                     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3904             } else
3905                 set1->nodeTab[set1->nodeNr++] = n2;
3906 skip_node:
3907             {}
3908         }
3909     }
3910     set2->nodeNr = 0;
3911     return(set1);
3912 }
3913
3914 /**
3915  * xmlXPathNodeSetMergeAndClearNoDupls:
3916  * @set1:  the first NodeSet or NULL
3917  * @set2:  the second NodeSet
3918  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3919  *
3920  * Merges two nodesets, all nodes from @set2 are added to @set1
3921  * if @set1 is NULL, a new set is created and copied from @set2.
3922  * Doesn't chack for duplicate nodes. Clears set2.
3923  *
3924  * Returns @set1 once extended or NULL in case of error.
3925  */
3926 static xmlNodeSetPtr
3927 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3928                                     int hasNullEntries)
3929 {    
3930     if (set2 == NULL)
3931         return(set1);
3932     if ((set1 == NULL) && (hasNullEntries == 0)) {
3933         /*
3934         * Note that doing a memcpy of the list, namespace nodes are
3935         * just assigned to set1, since set2 is cleared anyway.
3936         */
3937         set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3938         if (set1 == NULL)
3939             return(NULL);
3940         if (set2->nodeNr != 0) {
3941             memcpy(set1->nodeTab, set2->nodeTab,
3942                 set2->nodeNr * sizeof(xmlNodePtr));
3943             set1->nodeNr = set2->nodeNr;
3944         }
3945     } else {
3946         int i;
3947         xmlNodePtr n2;
3948
3949         if (set1 == NULL)
3950             set1 = xmlXPathNodeSetCreate(NULL);
3951    
3952         for (i = 0;i < set2->nodeNr;i++) {
3953             n2 = set2->nodeTab[i];
3954             /*
3955             * Skip NULLed entries.
3956             */
3957             if (n2 == NULL)
3958                 continue;       
3959             if (set1->nodeMax == 0) {
3960                 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961                     XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962                 if (set1->nodeTab == NULL) {
3963                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3964                     return(NULL);
3965                 }
3966                 memset(set1->nodeTab, 0,
3967                     XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968                 set1->nodeMax = XML_NODESET_DEFAULT;
3969             } else if (set1->nodeNr >= set1->nodeMax) {
3970                 xmlNodePtr *temp;
3971                 
3972                 set1->nodeMax *= 2;
3973                 temp = (xmlNodePtr *) xmlRealloc(
3974                     set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3975                 if (temp == NULL) {
3976                     xmlXPathErrMemory(NULL, "merging nodeset\n");
3977                     return(NULL);
3978                 }
3979                 set1->nodeTab = temp;
3980             }
3981             set1->nodeTab[set1->nodeNr++] = n2;
3982         }
3983     }
3984     set2->nodeNr = 0;
3985     return(set1);
3986 }
3987
3988 /**
3989  * xmlXPathNodeSetDel:
3990  * @cur:  the initial node set
3991  * @val:  an xmlNodePtr
3992  *
3993  * Removes an xmlNodePtr from an existing NodeSet
3994  */
3995 void
3996 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3997     int i;
3998
3999     if (cur == NULL) return;
4000     if (val == NULL) return;
4001
4002     /*
4003      * find node in nodeTab
4004      */
4005     for (i = 0;i < cur->nodeNr;i++)
4006         if (cur->nodeTab[i] == val) break;
4007
4008     if (i >= cur->nodeNr) {     /* not found */
4009 #ifdef DEBUG
4010         xmlGenericError(xmlGenericErrorContext, 
4011                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4012                 val->name);
4013 #endif
4014         return;
4015     }
4016     if ((cur->nodeTab[i] != NULL) &&
4017         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4019     cur->nodeNr--;
4020     for (;i < cur->nodeNr;i++)
4021         cur->nodeTab[i] = cur->nodeTab[i + 1];
4022     cur->nodeTab[cur->nodeNr] = NULL;
4023 }
4024
4025 /**
4026  * xmlXPathNodeSetRemove:
4027  * @cur:  the initial node set
4028  * @val:  the index to remove
4029  *
4030  * Removes an entry from an existing NodeSet list.
4031  */
4032 void
4033 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034     if (cur == NULL) return;
4035     if (val >= cur->nodeNr) return;
4036     if ((cur->nodeTab[val] != NULL) &&
4037         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4039     cur->nodeNr--;
4040     for (;val < cur->nodeNr;val++)
4041         cur->nodeTab[val] = cur->nodeTab[val + 1];
4042     cur->nodeTab[cur->nodeNr] = NULL;
4043 }
4044
4045 /**
4046  * xmlXPathFreeNodeSet:
4047  * @obj:  the xmlNodeSetPtr to free
4048  *
4049  * Free the NodeSet compound (not the actual nodes !).
4050  */
4051 void
4052 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053     if (obj == NULL) return;
4054     if (obj->nodeTab != NULL) {
4055         int i;
4056
4057         /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4058         for (i = 0;i < obj->nodeNr;i++)
4059             if ((obj->nodeTab[i] != NULL) &&
4060                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4062         xmlFree(obj->nodeTab);
4063     }
4064     xmlFree(obj);
4065 }
4066
4067 /**
4068  * xmlXPathNodeSetClear:
4069  * @set:  the node set to clear
4070  * 
4071  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072  * are feed), but does *not* free the list itself. Sets the length of the
4073  * list to 0.
4074  */
4075 static void
4076 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4077 {
4078     if ((set == NULL) || (set->nodeNr <= 0))
4079         return;
4080     else if (hasNsNodes) {
4081         int i;
4082         xmlNodePtr node;
4083         
4084         for (i = 0; i < set->nodeNr; i++) {
4085             node = set->nodeTab[i];
4086             if ((node != NULL) &&
4087                 (node->type == XML_NAMESPACE_DECL))
4088                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4089         }       
4090     }
4091     set->nodeNr = 0;
4092 }
4093
4094 /**
4095  * xmlXPathNodeSetClearFromPos:
4096  * @set: the node set to be cleared
4097  * @pos: the start position to clear from
4098  * 
4099  * Clears the list from temporary XPath objects (e.g. namespace nodes
4100  * are feed) starting with the entry at @pos, but does *not* free the list
4101  * itself. Sets the length of the list to @pos.
4102  */
4103 static void
4104 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4105 {
4106     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4107         return;
4108     else if ((hasNsNodes)) {
4109         int i;
4110         xmlNodePtr node;
4111         
4112         for (i = pos; i < set->nodeNr; i++) {
4113             node = set->nodeTab[i];
4114             if ((node != NULL) &&
4115                 (node->type == XML_NAMESPACE_DECL))
4116                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117         }       
4118     }
4119     set->nodeNr = pos;
4120 }
4121
4122 /**
4123  * xmlXPathFreeValueTree:
4124  * @obj:  the xmlNodeSetPtr to free
4125  *
4126  * Free the NodeSet compound and the actual tree, this is different
4127  * from xmlXPathFreeNodeSet()
4128  */
4129 static void
4130 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4131     int i;
4132
4133     if (obj == NULL) return;
4134
4135     if (obj->nodeTab != NULL) {
4136         for (i = 0;i < obj->nodeNr;i++) {
4137             if (obj->nodeTab[i] != NULL) {
4138                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4140                 } else {
4141                     xmlFreeNodeList(obj->nodeTab[i]);
4142                 }
4143             }
4144         }
4145         xmlFree(obj->nodeTab);
4146     }
4147     xmlFree(obj);
4148 }
4149
4150 #if defined(DEBUG) || defined(DEBUG_STEP)
4151 /**
4152  * xmlGenericErrorContextNodeSet:
4153  * @output:  a FILE * for the output
4154  * @obj:  the xmlNodeSetPtr to display
4155  *
4156  * Quick display of a NodeSet
4157  */
4158 void
4159 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4160     int i;
4161
4162     if (output == NULL) output = xmlGenericErrorContext;
4163     if (obj == NULL)  {
4164         fprintf(output, "NodeSet == NULL !\n");
4165         return;
4166     }
4167     if (obj->nodeNr == 0) {
4168         fprintf(output, "NodeSet is empty\n");
4169         return;
4170     }
4171     if (obj->nodeTab == NULL) {
4172         fprintf(output, " nodeTab == NULL !\n");
4173         return;
4174     }
4175     for (i = 0; i < obj->nodeNr; i++) {
4176         if (obj->nodeTab[i] == NULL) {
4177             fprintf(output, " NULL !\n");
4178             return;
4179         }
4180         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182             fprintf(output, " /");
4183         else if (obj->nodeTab[i]->name == NULL)
4184             fprintf(output, " noname!");
4185         else fprintf(output, " %s", obj->nodeTab[i]->name);
4186     }
4187     fprintf(output, "\n");
4188 }
4189 #endif
4190
4191 /**
4192  * xmlXPathNewNodeSet:
4193  * @val:  the NodePtr value
4194  *
4195  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196  * it with the single Node @val
4197  *
4198  * Returns the newly created object.
4199  */
4200 xmlXPathObjectPtr
4201 xmlXPathNewNodeSet(xmlNodePtr val) {
4202     xmlXPathObjectPtr ret;
4203
4204     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4205     if (ret == NULL) {
4206         xmlXPathErrMemory(NULL, "creating nodeset\n");
4207         return(NULL);
4208     }
4209     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210     ret->type = XPATH_NODESET;
4211     ret->boolval = 0;
4212     ret->nodesetval = xmlXPathNodeSetCreate(val);
4213     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4214 #ifdef XP_DEBUG_OBJ_USAGE
4215     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4216 #endif
4217     return(ret);
4218 }
4219
4220 /**
4221  * xmlXPathNewValueTree:
4222  * @val:  the NodePtr value
4223  *
4224  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225  * it with the tree root @val
4226  *
4227  * Returns the newly created object.
4228  */
4229 xmlXPathObjectPtr
4230 xmlXPathNewValueTree(xmlNodePtr val) {
4231     xmlXPathObjectPtr ret;
4232
4233     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234     if (ret == NULL) {
4235         xmlXPathErrMemory(NULL, "creating result value tree\n");
4236         return(NULL);
4237     }
4238     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239     ret->type = XPATH_XSLT_TREE;
4240     ret->boolval = 1;
4241     ret->user = (void *) val;
4242     ret->nodesetval = xmlXPathNodeSetCreate(val);
4243 #ifdef XP_DEBUG_OBJ_USAGE
4244     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4245 #endif
4246     return(ret);
4247 }
4248
4249 /**
4250  * xmlXPathNewNodeSetList:
4251  * @val:  an existing NodeSet
4252  *
4253  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254  * it with the Nodeset @val
4255  *
4256  * Returns the newly created object.
4257  */
4258 xmlXPathObjectPtr
4259 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4260 {
4261     xmlXPathObjectPtr ret;
4262     int i;
4263
4264     if (val == NULL)
4265         ret = NULL;
4266     else if (val->nodeTab == NULL)
4267         ret = xmlXPathNewNodeSet(NULL);
4268     else {
4269         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270         for (i = 1; i < val->nodeNr; ++i)
4271             xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4272     }
4273
4274     return (ret);
4275 }
4276
4277 /**
4278  * xmlXPathWrapNodeSet:
4279  * @val:  the NodePtr value
4280  *
4281  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4282  *
4283  * Returns the newly created object.
4284  */
4285 xmlXPathObjectPtr
4286 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287     xmlXPathObjectPtr ret;
4288
4289     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4290     if (ret == NULL) {
4291         xmlXPathErrMemory(NULL, "creating node set object\n");
4292         return(NULL);
4293     }
4294     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295     ret->type = XPATH_NODESET;
4296     ret->nodesetval = val;
4297 #ifdef XP_DEBUG_OBJ_USAGE
4298     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4299 #endif
4300     return(ret);
4301 }
4302
4303 /**
4304  * xmlXPathFreeNodeSetList:
4305  * @obj:  an existing NodeSetList object
4306  *
4307  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308  * the list contrary to xmlXPathFreeObject().
4309  */
4310 void
4311 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312     if (obj == NULL) return;
4313 #ifdef XP_DEBUG_OBJ_USAGE
4314     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4315 #endif
4316     xmlFree(obj);
4317 }
4318
4319 /**
4320  * xmlXPathDifference:
4321  * @nodes1:  a node-set
4322  * @nodes2:  a node-set
4323  *
4324  * Implements the EXSLT - Sets difference() function:
4325  *    node-set set:difference (node-set, node-set)
4326  *
4327  * Returns the difference between the two node sets, or nodes1 if
4328  *         nodes2 is empty
4329  */
4330 xmlNodeSetPtr
4331 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4332     xmlNodeSetPtr ret;
4333     int i, l1;
4334     xmlNodePtr cur;
4335
4336     if (xmlXPathNodeSetIsEmpty(nodes2))
4337         return(nodes1);
4338
4339     ret = xmlXPathNodeSetCreate(NULL);
4340     if (xmlXPathNodeSetIsEmpty(nodes1))
4341         return(ret);
4342
4343     l1 = xmlXPathNodeSetGetLength(nodes1);
4344
4345     for (i = 0; i < l1; i++) {
4346         cur = xmlXPathNodeSetItem(nodes1, i);
4347         if (!xmlXPathNodeSetContains(nodes2, cur))
4348             xmlXPathNodeSetAddUnique(ret, cur);
4349     }
4350     return(ret);
4351 }
4352
4353 /**
4354  * xmlXPathIntersection:
4355  * @nodes1:  a node-set
4356  * @nodes2:  a node-set
4357  *
4358  * Implements the EXSLT - Sets intersection() function:
4359  *    node-set set:intersection (node-set, node-set)
4360  *
4361  * Returns a node set comprising the nodes that are within both the
4362  *         node sets passed as arguments
4363  */
4364 xmlNodeSetPtr
4365 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4367     int i, l1;
4368     xmlNodePtr cur;
4369
4370     if (xmlXPathNodeSetIsEmpty(nodes1))
4371         return(ret);
4372     if (xmlXPathNodeSetIsEmpty(nodes2))
4373         return(ret);
4374
4375     l1 = xmlXPathNodeSetGetLength(nodes1);
4376
4377     for (i = 0; i < l1; i++) {
4378         cur = xmlXPathNodeSetItem(nodes1, i);
4379         if (xmlXPathNodeSetContains(nodes2, cur))
4380             xmlXPathNodeSetAddUnique(ret, cur);
4381     }
4382     return(ret);
4383 }
4384
4385 /**
4386  * xmlXPathDistinctSorted:
4387  * @nodes:  a node-set, sorted by document order
4388  *
4389  * Implements the EXSLT - Sets distinct() function:
4390  *    node-set set:distinct (node-set)
4391  * 
4392  * Returns a subset of the nodes contained in @nodes, or @nodes if
4393  *         it is empty
4394  */
4395 xmlNodeSetPtr
4396 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4397     xmlNodeSetPtr ret;
4398     xmlHashTablePtr hash;
4399     int i, l;
4400     xmlChar * strval;
4401     xmlNodePtr cur;
4402
4403     if (xmlXPathNodeSetIsEmpty(nodes))
4404         return(nodes);
4405
4406     ret = xmlXPathNodeSetCreate(NULL);
4407     l = xmlXPathNodeSetGetLength(nodes);
4408     hash = xmlHashCreate (l);
4409     for (i = 0; i < l; i++) {
4410         cur = xmlXPathNodeSetItem(nodes, i);
4411         strval = xmlXPathCastNodeToString(cur);
4412         if (xmlHashLookup(hash, strval) == NULL) {
4413             xmlHashAddEntry(hash, strval, strval);
4414             xmlXPathNodeSetAddUnique(ret, cur);
4415         } else {
4416             xmlFree(strval);
4417         }
4418     }
4419     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4420     return(ret);
4421 }
4422
4423 /**
4424  * xmlXPathDistinct:
4425  * @nodes:  a node-set
4426  *
4427  * Implements the EXSLT - Sets distinct() function:
4428  *    node-set set:distinct (node-set)
4429  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430  * is called with the sorted node-set
4431  *
4432  * Returns a subset of the nodes contained in @nodes, or @nodes if
4433  *         it is empty
4434  */
4435 xmlNodeSetPtr
4436 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437     if (xmlXPathNodeSetIsEmpty(nodes))
4438         return(nodes);
4439
4440     xmlXPathNodeSetSort(nodes);
4441     return(xmlXPathDistinctSorted(nodes));
4442 }
4443
4444 /**
4445  * xmlXPathHasSameNodes:
4446  * @nodes1:  a node-set
4447  * @nodes2:  a node-set
4448  *
4449  * Implements the EXSLT - Sets has-same-nodes function:
4450  *    boolean set:has-same-node(node-set, node-set)
4451  *
4452  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4453  *         otherwise
4454  */
4455 int
4456 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4457     int i, l;
4458     xmlNodePtr cur;
4459
4460     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461         xmlXPathNodeSetIsEmpty(nodes2))
4462         return(0);
4463
4464     l = xmlXPathNodeSetGetLength(nodes1);
4465     for (i = 0; i < l; i++) {
4466         cur = xmlXPathNodeSetItem(nodes1, i);
4467         if (xmlXPathNodeSetContains(nodes2, cur))
4468             return(1);
4469     }
4470     return(0);
4471 }
4472
4473 /**
4474  * xmlXPathNodeLeadingSorted:
4475  * @nodes: a node-set, sorted by document order
4476  * @node: a node
4477  *
4478  * Implements the EXSLT - Sets leading() function:
4479  *    node-set set:leading (node-set, node-set)
4480  *
4481  * Returns the nodes in @nodes that precede @node in document order,
4482  *         @nodes if @node is NULL or an empty node-set if @nodes
4483  *         doesn't contain @node
4484  */
4485 xmlNodeSetPtr
4486 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4487     int i, l;
4488     xmlNodePtr cur;
4489     xmlNodeSetPtr ret;
4490
4491     if (node == NULL)
4492         return(nodes);
4493
4494     ret = xmlXPathNodeSetCreate(NULL);
4495     if (xmlXPathNodeSetIsEmpty(nodes) ||
4496         (!xmlXPathNodeSetContains(nodes, node)))
4497         return(ret);
4498
4499     l = xmlXPathNodeSetGetLength(nodes);
4500     for (i = 0; i < l; i++) {
4501         cur = xmlXPathNodeSetItem(nodes, i);
4502         if (cur == node)
4503             break;
4504         xmlXPathNodeSetAddUnique(ret, cur);
4505     }
4506     return(ret);
4507 }
4508
4509 /**
4510  * xmlXPathNodeLeading:
4511  * @nodes:  a node-set
4512  * @node:  a node
4513  *
4514  * Implements the EXSLT - Sets leading() function:
4515  *    node-set set:leading (node-set, node-set)
4516  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4517  * is called.
4518  *
4519  * Returns the nodes in @nodes that precede @node in document order,
4520  *         @nodes if @node is NULL or an empty node-set if @nodes
4521  *         doesn't contain @node
4522  */
4523 xmlNodeSetPtr
4524 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525     xmlXPathNodeSetSort(nodes);
4526     return(xmlXPathNodeLeadingSorted(nodes, node));
4527 }
4528
4529 /**
4530  * xmlXPathLeadingSorted:
4531  * @nodes1:  a node-set, sorted by document order
4532  * @nodes2:  a node-set, sorted by document order
4533  *
4534  * Implements the EXSLT - Sets leading() function:
4535  *    node-set set:leading (node-set, node-set)
4536  *
4537  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4539  *         an empty node-set if @nodes1 doesn't contain @nodes2
4540  */
4541 xmlNodeSetPtr
4542 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543     if (xmlXPathNodeSetIsEmpty(nodes2))
4544         return(nodes1);
4545     return(xmlXPathNodeLeadingSorted(nodes1,
4546                                      xmlXPathNodeSetItem(nodes2, 1)));
4547 }
4548
4549 /**
4550  * xmlXPathLeading:
4551  * @nodes1:  a node-set
4552  * @nodes2:  a node-set
4553  *
4554  * Implements the EXSLT - Sets leading() function:
4555  *    node-set set:leading (node-set, node-set)
4556  * @nodes1 and @nodes2 are sorted by document order, then
4557  * #exslSetsLeadingSorted is called.
4558  *
4559  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4561  *         an empty node-set if @nodes1 doesn't contain @nodes2
4562  */
4563 xmlNodeSetPtr
4564 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565     if (xmlXPathNodeSetIsEmpty(nodes2))
4566         return(nodes1);
4567     if (xmlXPathNodeSetIsEmpty(nodes1))
4568         return(xmlXPathNodeSetCreate(NULL));
4569     xmlXPathNodeSetSort(nodes1);
4570     xmlXPathNodeSetSort(nodes2);
4571     return(xmlXPathNodeLeadingSorted(nodes1,
4572                                      xmlXPathNodeSetItem(nodes2, 1)));
4573 }
4574
4575 /**
4576  * xmlXPathNodeTrailingSorted:
4577  * @nodes: a node-set, sorted by document order
4578  * @node: a node
4579  *
4580  * Implements the EXSLT - Sets trailing() function:
4581  *    node-set set:trailing (node-set, node-set)
4582  *
4583  * Returns the nodes in @nodes that follow @node in document order,
4584  *         @nodes if @node is NULL or an empty node-set if @nodes
4585  *         doesn't contain @node
4586  */
4587 xmlNodeSetPtr
4588 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589     int i, l;
4590     xmlNodePtr cur;
4591     xmlNodeSetPtr ret;
4592
4593     if (node == NULL)
4594         return(nodes);
4595
4596     ret = xmlXPathNodeSetCreate(NULL);
4597     if (xmlXPathNodeSetIsEmpty(nodes) ||
4598         (!xmlXPathNodeSetContains(nodes, node)))
4599         return(ret);
4600
4601     l = xmlXPathNodeSetGetLength(nodes);
4602     for (i = l; i > 0; i--) {
4603         cur = xmlXPathNodeSetItem(nodes, i);
4604         if (cur == node)
4605             break;
4606         xmlXPathNodeSetAddUnique(ret, cur);
4607     }
4608     return(ret);
4609 }
4610
4611 /**
4612  * xmlXPathNodeTrailing:
4613  * @nodes:  a node-set
4614  * @node:  a node
4615  *
4616  * Implements the EXSLT - Sets trailing() function:
4617  *    node-set set:trailing (node-set, node-set)
4618  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4619  * is called.
4620  *
4621  * Returns the nodes in @nodes that follow @node in document order,
4622  *         @nodes if @node is NULL or an empty node-set if @nodes
4623  *         doesn't contain @node
4624  */
4625 xmlNodeSetPtr
4626 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627     xmlXPathNodeSetSort(nodes);
4628     return(xmlXPathNodeTrailingSorted(nodes, node));
4629 }
4630
4631 /**
4632  * xmlXPathTrailingSorted:
4633  * @nodes1:  a node-set, sorted by document order
4634  * @nodes2:  a node-set, sorted by document order
4635  *
4636  * Implements the EXSLT - Sets trailing() function:
4637  *    node-set set:trailing (node-set, node-set)
4638  *
4639  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641  *         an empty node-set if @nodes1 doesn't contain @nodes2
4642  */
4643 xmlNodeSetPtr
4644 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645     if (xmlXPathNodeSetIsEmpty(nodes2))
4646         return(nodes1);
4647     return(xmlXPathNodeTrailingSorted(nodes1,
4648                                       xmlXPathNodeSetItem(nodes2, 0)));
4649 }
4650
4651 /**
4652  * xmlXPathTrailing:
4653  * @nodes1:  a node-set
4654  * @nodes2:  a node-set
4655  *
4656  * Implements the EXSLT - Sets trailing() function:
4657  *    node-set set:trailing (node-set, node-set)
4658  * @nodes1 and @nodes2 are sorted by document order, then
4659  * #xmlXPathTrailingSorted is called.
4660  *
4661  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663  *         an empty node-set if @nodes1 doesn't contain @nodes2
4664  */
4665 xmlNodeSetPtr
4666 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667     if (xmlXPathNodeSetIsEmpty(nodes2))
4668         return(nodes1);
4669     if (xmlXPathNodeSetIsEmpty(nodes1))
4670         return(xmlXPathNodeSetCreate(NULL));
4671     xmlXPathNodeSetSort(nodes1);
4672     xmlXPathNodeSetSort(nodes2);
4673     return(xmlXPathNodeTrailingSorted(nodes1,
4674                                       xmlXPathNodeSetItem(nodes2, 0)));
4675 }
4676
4677 /************************************************************************
4678  *                                                                      *
4679  *              Routines to handle extra functions                      *
4680  *                                                                      *
4681  ************************************************************************/
4682
4683 /**
4684  * xmlXPathRegisterFunc:
4685  * @ctxt:  the XPath context
4686  * @name:  the function name
4687  * @f:  the function implementation or NULL
4688  *
4689  * Register a new function. If @f is NULL it unregisters the function
4690  *
4691  * Returns 0 in case of success, -1 in case of error
4692  */
4693 int               
4694 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695                      xmlXPathFunction f) {
4696     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4697 }
4698
4699 /**
4700  * xmlXPathRegisterFuncNS:
4701  * @ctxt:  the XPath context
4702  * @name:  the function name
4703  * @ns_uri:  the function namespace URI
4704  * @f:  the function implementation or NULL
4705  *
4706  * Register a new function. If @f is NULL it unregisters the function
4707  *
4708  * Returns 0 in case of success, -1 in case of error
4709  */
4710 int
4711 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712                        const xmlChar *ns_uri, xmlXPathFunction f) {
4713     if (ctxt == NULL)
4714         return(-1);
4715     if (name == NULL)
4716         return(-1);
4717
4718     if (ctxt->funcHash == NULL)
4719         ctxt->funcHash = xmlHashCreate(0);
4720     if (ctxt->funcHash == NULL)
4721         return(-1);
4722     if (f == NULL)
4723         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4724     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4725 }
4726
4727 /**
4728  * xmlXPathRegisterFuncLookup:
4729  * @ctxt:  the XPath context
4730  * @f:  the lookup function
4731  * @funcCtxt:  the lookup data
4732  *
4733  * Registers an external mechanism to do function lookup.
4734  */
4735 void
4736 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737                             xmlXPathFuncLookupFunc f,
4738                             void *funcCtxt) {
4739     if (ctxt == NULL)
4740         return;
4741     ctxt->funcLookupFunc = f;
4742     ctxt->funcLookupData = funcCtxt;
4743 }
4744
4745 /**
4746  * xmlXPathFunctionLookup:
4747  * @ctxt:  the XPath context
4748  * @name:  the function name
4749  *
4750  * Search in the Function array of the context for the given
4751  * function.
4752  *
4753  * Returns the xmlXPathFunction or NULL if not found
4754  */
4755 xmlXPathFunction
4756 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4757     if (ctxt == NULL)
4758         return (NULL);
4759
4760     if (ctxt->funcLookupFunc != NULL) {
4761         xmlXPathFunction ret;
4762         xmlXPathFuncLookupFunc f;
4763
4764         f = ctxt->funcLookupFunc;
4765         ret = f(ctxt->funcLookupData, name, NULL);
4766         if (ret != NULL)
4767             return(ret);
4768     }
4769     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4770 }
4771
4772 /**
4773  * xmlXPathFunctionLookupNS:
4774  * @ctxt:  the XPath context
4775  * @name:  the function name
4776  * @ns_uri:  the function namespace URI
4777  *
4778  * Search in the Function array of the context for the given
4779  * function.
4780  *
4781  * Returns the xmlXPathFunction or NULL if not found
4782  */
4783 xmlXPathFunction
4784 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785                          const xmlChar *ns_uri) {
4786     xmlXPathFunction ret;
4787     
4788     if (ctxt == NULL)
4789         return(NULL);
4790     if (name == NULL)
4791         return(NULL);
4792
4793     if (ctxt->funcLookupFunc != NULL) {
4794         xmlXPathFuncLookupFunc f;
4795
4796         f = ctxt->funcLookupFunc;
4797         ret = f(ctxt->funcLookupData, name, ns_uri);
4798         if (ret != NULL)
4799             return(ret);
4800     }
4801
4802     if (ctxt->funcHash == NULL)
4803         return(NULL);
4804
4805     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4806     return(ret);
4807 }
4808
4809 /**
4810  * xmlXPathRegisteredFuncsCleanup:
4811  * @ctxt:  the XPath context
4812  *
4813  * Cleanup the XPath context data associated to registered functions
4814  */
4815 void
4816 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4817     if (ctxt == NULL)
4818         return;
4819
4820     xmlHashFree(ctxt->funcHash, NULL);
4821     ctxt->funcHash = NULL;
4822 }
4823
4824 /************************************************************************
4825  *                                                                      *
4826  *                      Routines to handle Variables                    *
4827  *                                                                      *
4828  ************************************************************************/
4829
4830 /**
4831  * xmlXPathRegisterVariable:
4832  * @ctxt:  the XPath context
4833  * @name:  the variable name
4834  * @value:  the variable value or NULL
4835  *
4836  * Register a new variable value. If @value is NULL it unregisters
4837  * the variable
4838  *
4839  * Returns 0 in case of success, -1 in case of error
4840  */
4841 int               
4842 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843                          xmlXPathObjectPtr value) {
4844     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4845 }
4846
4847 /**
4848  * xmlXPathRegisterVariableNS:
4849  * @ctxt:  the XPath context
4850  * @name:  the variable name
4851  * @ns_uri:  the variable namespace URI
4852  * @value:  the variable value or NULL
4853  *
4854  * Register a new variable value. If @value is NULL it unregisters
4855  * the variable
4856  *
4857  * Returns 0 in case of success, -1 in case of error
4858  */
4859 int
4860 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861                            const xmlChar *ns_uri,
4862                            xmlXPathObjectPtr value) {
4863     if (ctxt == NULL)
4864         return(-1);
4865     if (name == NULL)
4866         return(-1);
4867
4868     if (ctxt->varHash == NULL)
4869         ctxt->varHash = xmlHashCreate(0);
4870     if (ctxt->varHash == NULL)
4871         return(-1);
4872     if (value == NULL)
4873         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 
4874                                    (xmlHashDeallocator)xmlXPathFreeObject));
4875     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4876                                (void *) value,
4877                                (xmlHashDeallocator)xmlXPathFreeObject));
4878 }
4879
4880 /**
4881  * xmlXPathRegisterVariableLookup:
4882  * @ctxt:  the XPath context
4883  * @f:  the lookup function
4884  * @data:  the lookup data
4885  *
4886  * register an external mechanism to do variable lookup
4887  */
4888 void
4889 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890          xmlXPathVariableLookupFunc f, void *data) {
4891     if (ctxt == NULL)
4892         return;
4893     ctxt->varLookupFunc = f;
4894     ctxt->varLookupData = data;
4895 }
4896
4897 /**
4898  * xmlXPathVariableLookup:
4899  * @ctxt:  the XPath context
4900  * @name:  the variable name
4901  *
4902  * Search in the Variable array of the context for the given
4903  * variable value.
4904  *
4905  * Returns a copy of the value or NULL if not found
4906  */
4907 xmlXPathObjectPtr
4908 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4909     if (ctxt == NULL)
4910         return(NULL);
4911
4912     if (ctxt->varLookupFunc != NULL) {
4913         xmlXPathObjectPtr ret;
4914
4915         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916                 (ctxt->varLookupData, name, NULL);
4917         return(ret);
4918     }
4919     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4920 }
4921
4922 /**
4923  * xmlXPathVariableLookupNS:
4924  * @ctxt:  the XPath context
4925  * @name:  the variable name
4926  * @ns_uri:  the variable namespace URI
4927  *
4928  * Search in the Variable array of the context for the given
4929  * variable value. 
4930  *
4931  * Returns the a copy of the value or NULL if not found
4932  */
4933 xmlXPathObjectPtr
4934 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935                          const xmlChar *ns_uri) {
4936     if (ctxt == NULL)
4937         return(NULL);
4938
4939     if (ctxt->varLookupFunc != NULL) {
4940         xmlXPathObjectPtr ret;
4941
4942         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943                 (ctxt->varLookupData, name, ns_uri);
4944         if (ret != NULL) return(ret);
4945     }
4946
4947     if (ctxt->varHash == NULL)
4948         return(NULL);
4949     if (name == NULL)
4950         return(NULL);
4951
4952     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4953                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4954 }
4955
4956 /**
4957  * xmlXPathRegisteredVariablesCleanup:
4958  * @ctxt:  the XPath context
4959  *
4960  * Cleanup the XPath context data associated to registered variables
4961  */
4962 void
4963 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4964     if (ctxt == NULL)
4965         return;
4966
4967     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4968     ctxt->varHash = NULL;
4969 }
4970
4971 /**
4972  * xmlXPathRegisterNs:
4973  * @ctxt:  the XPath context
4974  * @prefix:  the namespace prefix
4975  * @ns_uri:  the namespace name
4976  *
4977  * Register a new namespace. If @ns_uri is NULL it unregisters
4978  * the namespace
4979  *
4980  * Returns 0 in case of success, -1 in case of error
4981  */
4982 int
4983 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984                            const xmlChar *ns_uri) {
4985     if (ctxt == NULL)
4986         return(-1);
4987     if (prefix == NULL)
4988         return(-1);
4989
4990     if (ctxt->nsHash == NULL)
4991         ctxt->nsHash = xmlHashCreate(10);
4992     if (ctxt->nsHash == NULL)
4993         return(-1);
4994     if (ns_uri == NULL)
4995         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4996                                   (xmlHashDeallocator)xmlFree));
4997     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
4998                               (xmlHashDeallocator)xmlFree));
4999 }
5000
5001 /**
5002  * xmlXPathNsLookup:
5003  * @ctxt:  the XPath context
5004  * @prefix:  the namespace prefix value
5005  *
5006  * Search in the namespace declaration array of the context for the given
5007  * namespace name associated to the given prefix
5008  *
5009  * Returns the value or NULL if not found
5010  */
5011 const xmlChar *
5012 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5013     if (ctxt == NULL)
5014         return(NULL);
5015     if (prefix == NULL)
5016         return(NULL);
5017
5018 #ifdef XML_XML_NAMESPACE
5019     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020         return(XML_XML_NAMESPACE);
5021 #endif
5022
5023     if (ctxt->namespaces != NULL) {
5024         int i;
5025
5026         for (i = 0;i < ctxt->nsNr;i++) {
5027             if ((ctxt->namespaces[i] != NULL) &&
5028                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029                 return(ctxt->namespaces[i]->href);
5030         }
5031     }
5032
5033     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5034 }
5035
5036 /**
5037  * xmlXPathRegisteredNsCleanup:
5038  * @ctxt:  the XPath context
5039  *
5040  * Cleanup the XPath context data associated to registered variables
5041  */
5042 void
5043 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5044     if (ctxt == NULL)
5045         return;
5046
5047     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5048     ctxt->nsHash = NULL;
5049 }
5050
5051 /************************************************************************
5052  *                                                                      *
5053  *                      Routines to handle Values                       *
5054  *                                                                      *
5055  ************************************************************************/
5056
5057 /* Allocations are terrible, one needs to optimize all this !!! */
5058
5059 /**
5060  * xmlXPathNewFloat:
5061  * @val:  the double value
5062  *
5063  * Create a new xmlXPathObjectPtr of type double and of value @val
5064  *
5065  * Returns the newly created object.
5066  */
5067 xmlXPathObjectPtr
5068 xmlXPathNewFloat(double val) {
5069     xmlXPathObjectPtr ret;
5070
5071     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5072     if (ret == NULL) {
5073         xmlXPathErrMemory(NULL, "creating float object\n");
5074         return(NULL);
5075     }
5076     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077     ret->type = XPATH_NUMBER;
5078     ret->floatval = val;
5079 #ifdef XP_DEBUG_OBJ_USAGE
5080     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5081 #endif
5082     return(ret);
5083 }
5084
5085 /**
5086  * xmlXPathNewBoolean:
5087  * @val:  the boolean value
5088  *
5089  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5090  *
5091  * Returns the newly created object.
5092  */
5093 xmlXPathObjectPtr
5094 xmlXPathNewBoolean(int val) {
5095     xmlXPathObjectPtr ret;
5096
5097     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5098     if (ret == NULL) {
5099         xmlXPathErrMemory(NULL, "creating boolean object\n");
5100         return(NULL);
5101     }
5102     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103     ret->type = XPATH_BOOLEAN;
5104     ret->boolval = (val != 0);
5105 #ifdef XP_DEBUG_OBJ_USAGE
5106     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5107 #endif
5108     return(ret);
5109 }
5110
5111 /**
5112  * xmlXPathNewString:
5113  * @val:  the xmlChar * value
5114  *
5115  * Create a new xmlXPathObjectPtr of type string and of value @val
5116  *
5117  * Returns the newly created object.
5118  */
5119 xmlXPathObjectPtr
5120 xmlXPathNewString(const xmlChar *val) {
5121     xmlXPathObjectPtr ret;
5122
5123     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5124     if (ret == NULL) {
5125         xmlXPathErrMemory(NULL, "creating string object\n");
5126         return(NULL);
5127     }
5128     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129     ret->type = XPATH_STRING;
5130     if (val != NULL)
5131         ret->stringval = xmlStrdup(val);
5132     else
5133         ret->stringval = xmlStrdup((const xmlChar *)"");
5134 #ifdef XP_DEBUG_OBJ_USAGE
5135     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5136 #endif
5137     return(ret);
5138 }
5139
5140 /**
5141  * xmlXPathWrapString:
5142  * @val:  the xmlChar * value
5143  *
5144  * Wraps the @val string into an XPath object.
5145  *
5146  * Returns the newly created object.
5147  */
5148 xmlXPathObjectPtr
5149 xmlXPathWrapString (xmlChar *val) {
5150     xmlXPathObjectPtr ret;
5151
5152     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5153     if (ret == NULL) {
5154         xmlXPathErrMemory(NULL, "creating string object\n");
5155         return(NULL);
5156     }
5157     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158     ret->type = XPATH_STRING;
5159     ret->stringval = val;
5160 #ifdef XP_DEBUG_OBJ_USAGE
5161     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5162 #endif
5163     return(ret);
5164 }
5165
5166 /**
5167  * xmlXPathNewCString:
5168  * @val:  the char * value
5169  *
5170  * Create a new xmlXPathObjectPtr of type string and of value @val
5171  *
5172  * Returns the newly created object.
5173  */
5174 xmlXPathObjectPtr
5175 xmlXPathNewCString(const char *val) {
5176     xmlXPathObjectPtr ret;
5177
5178     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5179     if (ret == NULL) {
5180         xmlXPathErrMemory(NULL, "creating string object\n");
5181         return(NULL);
5182     }
5183     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184     ret->type = XPATH_STRING;
5185     ret->stringval = xmlStrdup(BAD_CAST val);
5186 #ifdef XP_DEBUG_OBJ_USAGE
5187     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5188 #endif
5189     return(ret);
5190 }
5191
5192 /**
5193  * xmlXPathWrapCString:
5194  * @val:  the char * value
5195  *
5196  * Wraps a string into an XPath object.
5197  *
5198  * Returns the newly created object.
5199  */
5200 xmlXPathObjectPtr
5201 xmlXPathWrapCString (char * val) {
5202     return(xmlXPathWrapString((xmlChar *)(val)));
5203 }
5204
5205 /**
5206  * xmlXPathWrapExternal:
5207  * @val:  the user data
5208  *
5209  * Wraps the @val data into an XPath object.
5210  *
5211  * Returns the newly created object.
5212  */
5213 xmlXPathObjectPtr
5214 xmlXPathWrapExternal (void *val) {
5215     xmlXPathObjectPtr ret;
5216
5217     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5218     if (ret == NULL) {
5219         xmlXPathErrMemory(NULL, "creating user object\n");
5220         return(NULL);
5221     }
5222     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223     ret->type = XPATH_USERS;
5224     ret->user = val;
5225 #ifdef XP_DEBUG_OBJ_USAGE
5226     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5227 #endif
5228     return(ret);
5229 }
5230
5231 /**
5232  * xmlXPathObjectCopy:
5233  * @val:  the original object
5234  *
5235  * allocate a new copy of a given object
5236  *
5237  * Returns the newly created object.
5238  */
5239 xmlXPathObjectPtr
5240 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241     xmlXPathObjectPtr ret;
5242
5243     if (val == NULL)
5244         return(NULL);
5245
5246     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247     if (ret == NULL) {
5248         xmlXPathErrMemory(NULL, "copying object\n");
5249         return(NULL);
5250     }
5251     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5252 #ifdef XP_DEBUG_OBJ_USAGE
5253     xmlXPathDebugObjUsageRequested(NULL, val->type);
5254 #endif
5255     switch (val->type) {
5256         case XPATH_BOOLEAN:
5257         case XPATH_NUMBER:
5258         case XPATH_POINT:
5259         case XPATH_RANGE:
5260             break;
5261         case XPATH_STRING:
5262             ret->stringval = xmlStrdup(val->stringval);
5263             break;
5264         case XPATH_XSLT_TREE:
5265 #if 0
5266 /*
5267   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268   this previous handling is no longer correct, and can cause some serious
5269   problems (ref. bug 145547)
5270 */
5271             if ((val->nodesetval != NULL) &&
5272                 (val->nodesetval->nodeTab != NULL)) {
5273                 xmlNodePtr cur, tmp;
5274                 xmlDocPtr top;
5275
5276                 ret->boolval = 1;
5277                 top =  xmlNewDoc(NULL);
5278                 top->name = (char *)
5279                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
5280                 ret->user = top;
5281                 if (top != NULL) {
5282                     top->doc = top;
5283                     cur = val->nodesetval->nodeTab[0]->children;
5284                     while (cur != NULL) {
5285                         tmp = xmlDocCopyNode(cur, top, 1);
5286                         xmlAddChild((xmlNodePtr) top, tmp);
5287                         cur = cur->next;
5288                     }
5289                 }
5290
5291                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5292             } else
5293                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5294             /* Deallocate the copied tree value */
5295             break;
5296 #endif
5297         case XPATH_NODESET:
5298             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5299             /* Do not deallocate the copied tree value */
5300             ret->boolval = 0;
5301             break;
5302         case XPATH_LOCATIONSET:
5303 #ifdef LIBXML_XPTR_ENABLED
5304         {
5305             xmlLocationSetPtr loc = val->user;
5306             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5307             break;
5308         }
5309 #endif
5310         case XPATH_USERS:
5311             ret->user = val->user;
5312             break; 
5313         case XPATH_UNDEFINED:
5314             xmlGenericError(xmlGenericErrorContext,
5315                     "xmlXPathObjectCopy: unsupported type %d\n",
5316                     val->type);
5317             break;
5318     }
5319     return(ret);
5320 }
5321
5322 /**
5323  * xmlXPathFreeObject:
5324  * @obj:  the object to free
5325  *
5326  * Free up an xmlXPathObjectPtr object.
5327  */
5328 void
5329 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330     if (obj == NULL) return;
5331     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5332         if (obj->boolval) {
5333 #if 0
5334             if (obj->user != NULL) {
5335                 xmlXPathFreeNodeSet(obj->nodesetval);
5336                 xmlFreeNodeList((xmlNodePtr) obj->user);
5337             } else
5338 #endif
5339             obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5340             if (obj->nodesetval != NULL)
5341                 xmlXPathFreeValueTree(obj->nodesetval); 
5342         } else {
5343             if (obj->nodesetval != NULL)
5344                 xmlXPathFreeNodeSet(obj->nodesetval);
5345         }
5346 #ifdef LIBXML_XPTR_ENABLED
5347     } else if (obj->type == XPATH_LOCATIONSET) {
5348         if (obj->user != NULL)
5349             xmlXPtrFreeLocationSet(obj->user);
5350 #endif
5351     } else if (obj->type == XPATH_STRING) {
5352         if (obj->stringval != NULL)
5353             xmlFree(obj->stringval);
5354     }
5355 #ifdef XP_DEBUG_OBJ_USAGE
5356     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5357 #endif
5358     xmlFree(obj);        
5359 }
5360
5361 /**
5362  * xmlXPathReleaseObject:
5363  * @obj:  the xmlXPathObjectPtr to free or to cache
5364  *
5365  * Depending on the state of the cache this frees the given
5366  * XPath object or stores it in the cache.
5367  */
5368 static void
5369 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5370 {
5371 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372         sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5374
5375 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5376
5377     if (obj == NULL)
5378         return;
5379     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5380          xmlXPathFreeObject(obj);
5381     } else {       
5382         xmlXPathContextCachePtr cache =
5383             (xmlXPathContextCachePtr) ctxt->cache;
5384
5385         switch (obj->type) {
5386             case XPATH_NODESET:
5387             case XPATH_XSLT_TREE:
5388                 if (obj->nodesetval != NULL) {
5389                     if (obj->boolval) {
5390                         /*
5391                         * It looks like the @boolval is used for
5392                         * evaluation if this an XSLT Result Tree Fragment.
5393                         * TODO: Check if this assumption is correct.
5394                         */
5395                         obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396                         xmlXPathFreeValueTree(obj->nodesetval);
5397                         obj->nodesetval = NULL;
5398                     } else if ((obj->nodesetval->nodeMax <= 40) &&
5399                         (XP_CACHE_WANTS(cache->nodesetObjs,
5400                                         cache->maxNodeset)))
5401                     {
5402                         XP_CACHE_ADD(cache->nodesetObjs, obj);
5403                         goto obj_cached;
5404                     } else {
5405                         xmlXPathFreeNodeSet(obj->nodesetval);
5406                         obj->nodesetval = NULL;
5407                     }
5408                 }
5409                 break;
5410             case XPATH_STRING:
5411                 if (obj->stringval != NULL)
5412                     xmlFree(obj->stringval);
5413
5414                 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415                     XP_CACHE_ADD(cache->stringObjs, obj);
5416                     goto obj_cached;
5417                 }
5418                 break;
5419             case XPATH_BOOLEAN:
5420                 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421                     XP_CACHE_ADD(cache->booleanObjs, obj);
5422                     goto obj_cached;
5423                 }
5424                 break;
5425             case XPATH_NUMBER:
5426                 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427                     XP_CACHE_ADD(cache->numberObjs, obj);
5428                     goto obj_cached;
5429                 }
5430                 break;
5431 #ifdef LIBXML_XPTR_ENABLED
5432             case XPATH_LOCATIONSET:
5433                 if (obj->user != NULL) {
5434                     xmlXPtrFreeLocationSet(obj->user);
5435                 }
5436                 goto free_obj;
5437 #endif      
5438             default:
5439                 goto free_obj;
5440         }
5441
5442         /*
5443         * Fallback to adding to the misc-objects slot.
5444         */
5445         if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446             XP_CACHE_ADD(cache->miscObjs, obj);
5447         } else
5448             goto free_obj;
5449
5450 obj_cached:
5451
5452 #ifdef XP_DEBUG_OBJ_USAGE
5453         xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5454 #endif
5455
5456         if (obj->nodesetval != NULL) {
5457             xmlNodeSetPtr tmpset = obj->nodesetval;
5458             
5459             /*
5460             * TODO: Due to those nasty ns-nodes, we need to traverse
5461             *  the list and free the ns-nodes.
5462             * URGENT TODO: Check if it's actually slowing things down.
5463             *  Maybe we shouldn't try to preserve the list.
5464             */
5465             if (tmpset->nodeNr > 1) {
5466                 int i;
5467                 xmlNodePtr node;
5468
5469                 for (i = 0; i < tmpset->nodeNr; i++) {
5470                     node = tmpset->nodeTab[i];
5471                     if ((node != NULL) &&
5472                         (node->type == XML_NAMESPACE_DECL))
5473                     {
5474                         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5475                     }
5476                 }
5477             } else if (tmpset->nodeNr == 1) {
5478                 if ((tmpset->nodeTab[0] != NULL) &&
5479                     (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480                     xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5481             }           
5482             tmpset->nodeNr = 0;
5483             memset(obj, 0, sizeof(xmlXPathObject));
5484             obj->nodesetval = tmpset;
5485         } else
5486             memset(obj, 0, sizeof(xmlXPathObject));
5487
5488         return;
5489
5490 free_obj:
5491         /*
5492         * Cache is full; free the object.
5493         */    
5494         if (obj->nodesetval != NULL)
5495             xmlXPathFreeNodeSet(obj->nodesetval);
5496 #ifdef XP_DEBUG_OBJ_USAGE
5497         xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498 #endif
5499         xmlFree(obj);
5500     }
5501     return;
5502 }
5503
5504
5505 /************************************************************************
5506  *                                                                      *
5507  *                      Type Casting Routines                           *
5508  *                                                                      *
5509  ************************************************************************/
5510
5511 /**
5512  * xmlXPathCastBooleanToString:
5513  * @val:  a boolean
5514  *
5515  * Converts a boolean to its string value.
5516  *
5517  * Returns a newly allocated string.
5518  */
5519 xmlChar *
5520 xmlXPathCastBooleanToString (int val) {
5521     xmlChar *ret;
5522     if (val)
5523         ret = xmlStrdup((const xmlChar *) "true");
5524     else
5525         ret = xmlStrdup((const xmlChar *) "false");
5526     return(ret);
5527 }
5528
5529 /**
5530  * xmlXPathCastNumberToString:
5531  * @val:  a number
5532  *
5533  * Converts a number to its string value.
5534  *
5535  * Returns a newly allocated string.
5536  */
5537 xmlChar *
5538 xmlXPathCastNumberToString (double val) {
5539     xmlChar *ret;
5540     switch (xmlXPathIsInf(val)) {
5541     case 1:
5542         ret = xmlStrdup((const xmlChar *) "Infinity");
5543         break;
5544     case -1:
5545         ret = xmlStrdup((const xmlChar *) "-Infinity");
5546         break;
5547     default:
5548         if (xmlXPathIsNaN(val)) {
5549             ret = xmlStrdup((const xmlChar *) "NaN");
5550         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551             ret = xmlStrdup((const xmlChar *) "0");
5552         } else {
5553             /* could be improved */
5554             char buf[100];
5555             xmlXPathFormatNumber(val, buf, 99);
5556             buf[99] = 0;
5557             ret = xmlStrdup((const xmlChar *) buf);
5558         }
5559     }
5560     return(ret);
5561 }
5562
5563 /**
5564  * xmlXPathCastNodeToString:
5565  * @node:  a node
5566  *
5567  * Converts a node to its string value.
5568  *
5569  * Returns a newly allocated string.
5570  */
5571 xmlChar *
5572 xmlXPathCastNodeToString (xmlNodePtr node) {
5573     return(xmlNodeGetContent(node));
5574 }
5575
5576 /**
5577  * xmlXPathCastNodeSetToString:
5578  * @ns:  a node-set
5579  *
5580  * Converts a node-set to its string value.
5581  *
5582  * Returns a newly allocated string.
5583  */
5584 xmlChar *
5585 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587         return(xmlStrdup((const xmlChar *) ""));
5588
5589     if (ns->nodeNr > 1)
5590         xmlXPathNodeSetSort(ns);
5591     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5592 }
5593
5594 /**
5595  * xmlXPathCastToString:
5596  * @val:  an XPath object
5597  *
5598  * Converts an existing object to its string() equivalent
5599  *
5600  * Returns the allocated string value of the object, NULL in case of error.
5601  *         It's up to the caller to free the string memory with xmlFree(). 
5602  */
5603 xmlChar *
5604 xmlXPathCastToString(xmlXPathObjectPtr val) {
5605     xmlChar *ret = NULL;
5606
5607     if (val == NULL)
5608         return(xmlStrdup((const xmlChar *) ""));
5609     switch (val->type) {
5610         case XPATH_UNDEFINED:
5611 #ifdef DEBUG_EXPR
5612             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5613 #endif
5614             ret = xmlStrdup((const xmlChar *) "");
5615             break;
5616         case XPATH_NODESET:
5617         case XPATH_XSLT_TREE:
5618             ret = xmlXPathCastNodeSetToString(val->nodesetval);
5619             break;
5620         case XPATH_STRING:
5621             return(xmlStrdup(val->stringval));
5622         case XPATH_BOOLEAN:
5623             ret = xmlXPathCastBooleanToString(val->boolval);
5624             break;
5625         case XPATH_NUMBER: {
5626             ret = xmlXPathCastNumberToString(val->floatval);
5627             break;
5628         }
5629         case XPATH_USERS:
5630         case XPATH_POINT:
5631         case XPATH_RANGE:
5632         case XPATH_LOCATIONSET:
5633             TODO
5634             ret = xmlStrdup((const xmlChar *) "");
5635             break;
5636     }
5637     return(ret);
5638 }
5639
5640 /**
5641  * xmlXPathConvertString:
5642  * @val:  an XPath object
5643  *
5644  * Converts an existing object to its string() equivalent
5645  *
5646  * Returns the new object, the old one is freed (or the operation
5647  *         is done directly on @val)
5648  */
5649 xmlXPathObjectPtr
5650 xmlXPathConvertString(xmlXPathObjectPtr val) {
5651     xmlChar *res = NULL;
5652
5653     if (val == NULL)
5654         return(xmlXPathNewCString(""));
5655
5656     switch (val->type) {
5657     case XPATH_UNDEFINED:
5658 #ifdef DEBUG_EXPR
5659         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5660 #endif
5661         break;
5662     case XPATH_NODESET:
5663     case XPATH_XSLT_TREE:
5664         res = xmlXPathCastNodeSetToString(val->nodesetval);
5665         break;
5666     case XPATH_STRING:
5667         return(val);
5668     case XPATH_BOOLEAN:
5669         res = xmlXPathCastBooleanToString(val->boolval);
5670         break;
5671     case XPATH_NUMBER:
5672         res = xmlXPathCastNumberToString(val->floatval);
5673         break;
5674     case XPATH_USERS:
5675     case XPATH_POINT:
5676     case XPATH_RANGE:
5677     case XPATH_LOCATIONSET:
5678         TODO;
5679         break;
5680     }
5681     xmlXPathFreeObject(val);
5682     if (res == NULL)
5683         return(xmlXPathNewCString(""));
5684     return(xmlXPathWrapString(res));
5685 }
5686
5687 /**
5688  * xmlXPathCastBooleanToNumber:
5689  * @val:  a boolean
5690  *
5691  * Converts a boolean to its number value
5692  *
5693  * Returns the number value
5694  */
5695 double
5696 xmlXPathCastBooleanToNumber(int val) {
5697     if (val)
5698         return(1.0);
5699     return(0.0);
5700 }
5701
5702 /**
5703  * xmlXPathCastStringToNumber:
5704  * @val:  a string
5705  *
5706  * Converts a string to its number value
5707  *
5708  * Returns the number value
5709  */
5710 double
5711 xmlXPathCastStringToNumber(const xmlChar * val) {
5712     return(xmlXPathStringEvalNumber(val));
5713 }
5714
5715 /**
5716  * xmlXPathCastNodeToNumber:
5717  * @node:  a node
5718  *
5719  * Converts a node to its number value
5720  *
5721  * Returns the number value
5722  */
5723 double
5724 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5725     xmlChar *strval;
5726     double ret;
5727
5728     if (node == NULL)
5729         return(xmlXPathNAN);
5730     strval = xmlXPathCastNodeToString(node);
5731     if (strval == NULL)
5732         return(xmlXPathNAN);
5733     ret = xmlXPathCastStringToNumber(strval);
5734     xmlFree(strval);
5735
5736     return(ret);
5737 }
5738
5739 /**
5740  * xmlXPathCastNodeSetToNumber:
5741  * @ns:  a node-set
5742  *
5743  * Converts a node-set to its number value
5744  *
5745  * Returns the number value
5746  */
5747 double
5748 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5749     xmlChar *str;
5750     double ret;
5751
5752     if (ns == NULL)
5753         return(xmlXPathNAN);
5754     str = xmlXPathCastNodeSetToString(ns);
5755     ret = xmlXPathCastStringToNumber(str);
5756     xmlFree(str);
5757     return(ret);
5758 }
5759
5760 /**
5761  * xmlXPathCastToNumber:
5762  * @val:  an XPath object
5763  *
5764  * Converts an XPath object to its number value
5765  *
5766  * Returns the number value
5767  */
5768 double
5769 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5770     double ret = 0.0;
5771
5772     if (val == NULL)
5773         return(xmlXPathNAN);
5774     switch (val->type) {
5775     case XPATH_UNDEFINED:
5776 #ifdef DEGUB_EXPR
5777         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5778 #endif
5779         ret = xmlXPathNAN;
5780         break;
5781     case XPATH_NODESET:
5782     case XPATH_XSLT_TREE:
5783         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5784         break;
5785     case XPATH_STRING:
5786         ret = xmlXPathCastStringToNumber(val->stringval);
5787         break;
5788     case XPATH_NUMBER:
5789         ret = val->floatval;
5790         break;
5791     case XPATH_BOOLEAN:
5792         ret = xmlXPathCastBooleanToNumber(val->boolval);
5793         break;
5794     case XPATH_USERS:
5795     case XPATH_POINT:
5796     case XPATH_RANGE:
5797     case XPATH_LOCATIONSET:
5798         TODO;
5799         ret = xmlXPathNAN;
5800         break;
5801     }
5802     return(ret);
5803 }
5804
5805 /**
5806  * xmlXPathConvertNumber:
5807  * @val:  an XPath object
5808  *
5809  * Converts an existing object to its number() equivalent
5810  *
5811  * Returns the new object, the old one is freed (or the operation
5812  *         is done directly on @val)
5813  */
5814 xmlXPathObjectPtr
5815 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5816     xmlXPathObjectPtr ret;
5817
5818     if (val == NULL)
5819         return(xmlXPathNewFloat(0.0));
5820     if (val->type == XPATH_NUMBER)
5821         return(val);
5822     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5823     xmlXPathFreeObject(val);
5824     return(ret);
5825 }
5826
5827 /**
5828  * xmlXPathCastNumberToBoolean:
5829  * @val:  a number
5830  *
5831  * Converts a number to its boolean value
5832  *
5833  * Returns the boolean value
5834  */
5835 int
5836 xmlXPathCastNumberToBoolean (double val) {
5837      if (xmlXPathIsNaN(val) || (val == 0.0))
5838          return(0);
5839      return(1);
5840 }
5841
5842 /**
5843  * xmlXPathCastStringToBoolean:
5844  * @val:  a string
5845  *
5846  * Converts a string to its boolean value
5847  *
5848  * Returns the boolean value
5849  */
5850 int
5851 xmlXPathCastStringToBoolean (const xmlChar *val) {
5852     if ((val == NULL) || (xmlStrlen(val) == 0))
5853         return(0);
5854     return(1);
5855 }
5856
5857 /**
5858  * xmlXPathCastNodeSetToBoolean:
5859  * @ns:  a node-set
5860  *
5861  * Converts a node-set to its boolean value
5862  *
5863  * Returns the boolean value
5864  */
5865 int
5866 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5867     if ((ns == NULL) || (ns->nodeNr == 0))
5868         return(0);
5869     return(1);
5870 }
5871
5872 /**
5873  * xmlXPathCastToBoolean:
5874  * @val:  an XPath object
5875  *
5876  * Converts an XPath object to its boolean value
5877  *
5878  * Returns the boolean value
5879  */
5880 int
5881 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5882     int ret = 0;
5883
5884     if (val == NULL)
5885         return(0);
5886     switch (val->type) {
5887     case XPATH_UNDEFINED:
5888 #ifdef DEBUG_EXPR
5889         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5890 #endif
5891         ret = 0;
5892         break;
5893     case XPATH_NODESET:
5894     case XPATH_XSLT_TREE:
5895         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5896         break;
5897     case XPATH_STRING:
5898         ret = xmlXPathCastStringToBoolean(val->stringval);
5899         break;
5900     case XPATH_NUMBER:
5901         ret = xmlXPathCastNumberToBoolean(val->floatval);
5902         break;
5903     case XPATH_BOOLEAN:
5904         ret = val->boolval;
5905         break;
5906     case XPATH_USERS:
5907     case XPATH_POINT:
5908     case XPATH_RANGE:
5909     case XPATH_LOCATIONSET:
5910         TODO;
5911         ret = 0;
5912         break;
5913     }
5914     return(ret);
5915 }
5916
5917
5918 /**
5919  * xmlXPathConvertBoolean:
5920  * @val:  an XPath object
5921  *
5922  * Converts an existing object to its boolean() equivalent
5923  *
5924  * Returns the new object, the old one is freed (or the operation
5925  *         is done directly on @val)
5926  */
5927 xmlXPathObjectPtr
5928 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5929     xmlXPathObjectPtr ret;
5930
5931     if (val == NULL)
5932         return(xmlXPathNewBoolean(0));
5933     if (val->type == XPATH_BOOLEAN)
5934         return(val);
5935     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5936     xmlXPathFreeObject(val);
5937     return(ret);
5938 }
5939
5940 /************************************************************************
5941  *                                                                      *
5942  *              Routines to handle XPath contexts                       *
5943  *                                                                      *
5944  ************************************************************************/
5945
5946 /**
5947  * xmlXPathNewContext:
5948  * @doc:  the XML document
5949  *
5950  * Create a new xmlXPathContext
5951  *
5952  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5953  */
5954 xmlXPathContextPtr
5955 xmlXPathNewContext(xmlDocPtr doc) {
5956     xmlXPathContextPtr ret;
5957
5958     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5959     if (ret == NULL) {
5960         xmlXPathErrMemory(NULL, "creating context\n");
5961         return(NULL);
5962     }
5963     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5964     ret->doc = doc;
5965     ret->node = NULL;
5966
5967     ret->varHash = NULL;
5968
5969     ret->nb_types = 0;
5970     ret->max_types = 0;
5971     ret->types = NULL;
5972
5973     ret->funcHash = xmlHashCreate(0);
5974
5975     ret->nb_axis = 0;
5976     ret->max_axis = 0;
5977     ret->axis = NULL;
5978
5979     ret->nsHash = NULL;
5980     ret->user = NULL;
5981
5982     ret->contextSize = -1;
5983     ret->proximityPosition = -1;
5984
5985 #ifdef XP_DEFAULT_CACHE_ON
5986     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5987         xmlXPathFreeContext(ret);
5988         return(NULL);
5989     }
5990 #endif
5991
5992     xmlXPathRegisterAllFunctions(ret);   
5993
5994     return(ret);
5995 }
5996
5997 /**
5998  * xmlXPathFreeContext:
5999  * @ctxt:  the context to free
6000  *
6001  * Free up an xmlXPathContext
6002  */
6003 void
6004 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6005     if (ctxt == NULL) return;
6006
6007     if (ctxt->cache != NULL)
6008         xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6009     xmlXPathRegisteredNsCleanup(ctxt);
6010     xmlXPathRegisteredFuncsCleanup(ctxt);
6011     xmlXPathRegisteredVariablesCleanup(ctxt);
6012     xmlResetError(&ctxt->lastError);
6013     xmlFree(ctxt);
6014 }
6015
6016 /************************************************************************
6017  *                                                                      *
6018  *              Routines to handle XPath parser contexts                *
6019  *                                                                      *
6020  ************************************************************************/
6021
6022 #define CHECK_CTXT(ctxt)                                                \
6023     if (ctxt == NULL) {                                                 \
6024         __xmlRaiseError(NULL, NULL, NULL,                               \
6025                 NULL, NULL, XML_FROM_XPATH,                             \
6026                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6027                 __FILE__, __LINE__,                                     \
6028                 NULL, NULL, NULL, 0, 0,                                 \
6029                 "NULL context pointer\n");                              \
6030         return(NULL);                                                   \
6031     }                                                                   \
6032
6033 #define CHECK_CTXT_NEG(ctxt)                                            \
6034     if (ctxt == NULL) {                                                 \
6035         __xmlRaiseError(NULL, NULL, NULL,                               \
6036                 NULL, NULL, XML_FROM_XPATH,                             \
6037                 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6038                 __FILE__, __LINE__,                                     \
6039                 NULL, NULL, NULL, 0, 0,                                 \
6040                 "NULL context pointer\n");                              \
6041         return(-1);                                                     \
6042     }                                                                   \
6043
6044
6045 #define CHECK_CONTEXT(ctxt)                                             \
6046     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6047         (ctxt->doc->children == NULL)) {                                \
6048         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6049         return(NULL);                                                   \
6050     }
6051
6052
6053 /**
6054  * xmlXPathNewParserContext:
6055  * @str:  the XPath expression
6056  * @ctxt:  the XPath context
6057  *
6058  * Create a new xmlXPathParserContext
6059  *
6060  * Returns the xmlXPathParserContext just allocated.
6061  */
6062 xmlXPathParserContextPtr
6063 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6064     xmlXPathParserContextPtr ret;
6065
6066     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6067     if (ret == NULL) {
6068         xmlXPathErrMemory(ctxt, "creating parser context\n");
6069         return(NULL);
6070     }
6071     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6072     ret->cur = ret->base = str;
6073     ret->context = ctxt;
6074
6075     ret->comp = xmlXPathNewCompExpr();
6076     if (ret->comp == NULL) {
6077         xmlFree(ret->valueTab);
6078         xmlFree(ret);
6079         return(NULL);
6080     }
6081     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6082         ret->comp->dict = ctxt->dict;
6083         xmlDictReference(ret->comp->dict);
6084     }
6085
6086     return(ret);
6087 }
6088
6089 /**
6090  * xmlXPathCompParserContext:
6091  * @comp:  the XPath compiled expression
6092  * @ctxt:  the XPath context
6093  *
6094  * Create a new xmlXPathParserContext when processing a compiled expression
6095  *
6096  * Returns the xmlXPathParserContext just allocated.
6097  */
6098 static xmlXPathParserContextPtr
6099 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6100     xmlXPathParserContextPtr ret;
6101
6102     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6103     if (ret == NULL) {
6104         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6105         return(NULL);
6106     }
6107     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6108
6109     /* Allocate the value stack */
6110     ret->valueTab = (xmlXPathObjectPtr *) 
6111                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6112     if (ret->valueTab == NULL) {
6113         xmlFree(ret);
6114         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6115         return(NULL);
6116     }
6117     ret->valueNr = 0;
6118     ret->valueMax = 10;
6119     ret->value = NULL;
6120
6121     ret->context = ctxt;
6122     ret->comp = comp;
6123
6124     return(ret);
6125 }
6126
6127 /**
6128  * xmlXPathFreeParserContext:
6129  * @ctxt:  the context to free
6130  *
6131  * Free up an xmlXPathParserContext
6132  */
6133 void
6134 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6135     if (ctxt->valueTab != NULL) {
6136         xmlFree(ctxt->valueTab);
6137     }
6138     if (ctxt->comp != NULL) {
6139 #ifdef XPATH_STREAMING
6140         if (ctxt->comp->stream != NULL) {
6141             xmlFreePatternList(ctxt->comp->stream);
6142             ctxt->comp->stream = NULL;
6143         }
6144 #endif
6145         xmlXPathFreeCompExpr(ctxt->comp);
6146     }
6147     xmlFree(ctxt);
6148 }
6149
6150 /************************************************************************
6151  *                                                                      *
6152  *              The implicit core function library                      *
6153  *                                                                      *
6154  ************************************************************************/
6155
6156 /**
6157  * xmlXPathNodeValHash:
6158  * @node:  a node pointer
6159  *
6160  * Function computing the beginning of the string value of the node,
6161  * used to speed up comparisons
6162  *
6163  * Returns an int usable as a hash
6164  */
6165 static unsigned int
6166 xmlXPathNodeValHash(xmlNodePtr node) {
6167     int len = 2;
6168     const xmlChar * string = NULL;
6169     xmlNodePtr tmp = NULL;
6170     unsigned int ret = 0;
6171
6172     if (node == NULL)
6173         return(0);
6174
6175     if (node->type == XML_DOCUMENT_NODE) {
6176         tmp = xmlDocGetRootElement((xmlDocPtr) node);
6177         if (tmp == NULL)
6178             node = node->children;
6179         else
6180             node = tmp;
6181
6182         if (node == NULL)
6183             return(0);
6184     }
6185
6186     switch (node->type) {
6187         case XML_COMMENT_NODE:
6188         case XML_PI_NODE:
6189         case XML_CDATA_SECTION_NODE:
6190         case XML_TEXT_NODE:
6191             string = node->content;
6192             if (string == NULL)
6193                 return(0);
6194             if (string[0] == 0)
6195                 return(0);
6196             return(((unsigned int) string[0]) +
6197                    (((unsigned int) string[1]) << 8));
6198         case XML_NAMESPACE_DECL:
6199             string = ((xmlNsPtr)node)->href;
6200             if (string == NULL)
6201                 return(0);
6202             if (string[0] == 0)
6203                 return(0);
6204             return(((unsigned int) string[0]) +
6205                    (((unsigned int) string[1]) << 8));
6206         case XML_ATTRIBUTE_NODE:
6207             tmp = ((xmlAttrPtr) node)->children;
6208             break;
6209         case XML_ELEMENT_NODE:
6210             tmp = node->children;
6211             break;
6212         default:
6213             return(0);
6214     }
6215     while (tmp != NULL) {
6216         switch (tmp->type) {
6217             case XML_COMMENT_NODE:
6218             case XML_PI_NODE:
6219             case XML_CDATA_SECTION_NODE:
6220             case XML_TEXT_NODE:
6221                 string = tmp->content;
6222                 break;
6223             case XML_NAMESPACE_DECL:
6224                 string = ((xmlNsPtr)tmp)->href;
6225                 break;
6226             default:
6227                 break;
6228         }
6229         if ((string != NULL) && (string[0] != 0)) {
6230             if (len == 1) {
6231                 return(ret + (((unsigned int) string[0]) << 8));
6232             }
6233             if (string[1] == 0) {
6234                 len = 1;
6235                 ret = (unsigned int) string[0];
6236             } else {
6237                 return(((unsigned int) string[0]) +
6238                        (((unsigned int) string[1]) << 8));
6239             }
6240         }
6241         /*
6242          * Skip to next node
6243          */
6244         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6245             if (tmp->children->type != XML_ENTITY_DECL) {
6246                 tmp = tmp->children;
6247                 continue;
6248             }
6249         }
6250         if (tmp == node)
6251             break;
6252
6253         if (tmp->next != NULL) {
6254             tmp = tmp->next;
6255             continue;
6256         }
6257         
6258         do {
6259             tmp = tmp->parent;
6260             if (tmp == NULL)
6261                 break;
6262             if (tmp == node) {
6263                 tmp = NULL;
6264                 break;
6265             }
6266             if (tmp->next != NULL) {
6267                 tmp = tmp->next;
6268                 break;
6269             }
6270         } while (tmp != NULL);
6271     }
6272     return(ret);
6273 }
6274
6275 /**
6276  * xmlXPathStringHash:
6277  * @string:  a string
6278  *
6279  * Function computing the beginning of the string value of the node,
6280  * used to speed up comparisons
6281  *
6282  * Returns an int usable as a hash
6283  */
6284 static unsigned int
6285 xmlXPathStringHash(const xmlChar * string) {
6286     if (string == NULL)
6287         return((unsigned int) 0);
6288     if (string[0] == 0)
6289         return(0);
6290     return(((unsigned int) string[0]) +
6291            (((unsigned int) string[1]) << 8));
6292 }
6293
6294 /**
6295  * xmlXPathCompareNodeSetFloat:
6296  * @ctxt:  the XPath Parser context
6297  * @inf:  less than (1) or greater than (0)
6298  * @strict:  is the comparison strict
6299  * @arg:  the node set
6300  * @f:  the value
6301  *
6302  * Implement the compare operation between a nodeset and a number
6303  *     @ns < @val    (1, 1, ...
6304  *     @ns <= @val   (1, 0, ...
6305  *     @ns > @val    (0, 1, ...
6306  *     @ns >= @val   (0, 0, ...
6307  *
6308  * If one object to be compared is a node-set and the other is a number,
6309  * then the comparison will be true if and only if there is a node in the
6310  * node-set such that the result of performing the comparison on the number
6311  * to be compared and on the result of converting the string-value of that
6312  * node to a number using the number function is true.
6313  *
6314  * Returns 0 or 1 depending on the results of the test.
6315  */
6316 static int
6317 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6318                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6319     int i, ret = 0;
6320     xmlNodeSetPtr ns;
6321     xmlChar *str2;
6322
6323     if ((f == NULL) || (arg == NULL) ||
6324         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6325         xmlXPathReleaseObject(ctxt->context, arg);
6326         xmlXPathReleaseObject(ctxt->context, f);
6327         return(0);
6328     }
6329     ns = arg->nodesetval;
6330     if (ns != NULL) {
6331         for (i = 0;i < ns->nodeNr;i++) {
6332              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6333              if (str2 != NULL) {
6334                  valuePush(ctxt,
6335                            xmlXPathCacheNewString(ctxt->context, str2));
6336                  xmlFree(str2);
6337                  xmlXPathNumberFunction(ctxt, 1);
6338                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6339                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6340                  if (ret)
6341                      break;
6342              }
6343         }
6344     }
6345     xmlXPathReleaseObject(ctxt->context, arg);
6346     xmlXPathReleaseObject(ctxt->context, f);
6347     return(ret);
6348 }
6349
6350 /**
6351  * xmlXPathCompareNodeSetString:
6352  * @ctxt:  the XPath Parser context
6353  * @inf:  less than (1) or greater than (0)
6354  * @strict:  is the comparison strict
6355  * @arg:  the node set
6356  * @s:  the value
6357  *
6358  * Implement the compare operation between a nodeset and a string
6359  *     @ns < @val    (1, 1, ...
6360  *     @ns <= @val   (1, 0, ...
6361  *     @ns > @val    (0, 1, ...
6362  *     @ns >= @val   (0, 0, ...
6363  *
6364  * If one object to be compared is a node-set and the other is a string,
6365  * then the comparison will be true if and only if there is a node in
6366  * the node-set such that the result of performing the comparison on the
6367  * string-value of the node and the other string is true.
6368  *
6369  * Returns 0 or 1 depending on the results of the test.
6370  */
6371 static int
6372 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6373                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6374     int i, ret = 0;
6375     xmlNodeSetPtr ns;
6376     xmlChar *str2;
6377
6378     if ((s == NULL) || (arg == NULL) ||
6379         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6380         xmlXPathReleaseObject(ctxt->context, arg);
6381         xmlXPathReleaseObject(ctxt->context, s);
6382         return(0);
6383     }
6384     ns = arg->nodesetval;
6385     if (ns != NULL) {
6386         for (i = 0;i < ns->nodeNr;i++) {
6387              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6388              if (str2 != NULL) {
6389                  valuePush(ctxt,
6390                            xmlXPathCacheNewString(ctxt->context, str2));
6391                  xmlFree(str2);
6392                  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6393                  ret = xmlXPathCompareValues(ctxt, inf, strict);
6394                  if (ret)
6395                      break;
6396              }
6397         }
6398     }
6399     xmlXPathReleaseObject(ctxt->context, arg);
6400     xmlXPathReleaseObject(ctxt->context, s);
6401     return(ret);
6402 }
6403
6404 /**
6405  * xmlXPathCompareNodeSets:
6406  * @inf:  less than (1) or greater than (0)
6407  * @strict:  is the comparison strict
6408  * @arg1:  the first node set object
6409  * @arg2:  the second node set object
6410  *
6411  * Implement the compare operation on nodesets:
6412  *
6413  * If both objects to be compared are node-sets, then the comparison
6414  * will be true if and only if there is a node in the first node-set
6415  * and a node in the second node-set such that the result of performing
6416  * the comparison on the string-values of the two nodes is true. 
6417  * ....
6418  * When neither object to be compared is a node-set and the operator
6419  * is <=, <, >= or >, then the objects are compared by converting both
6420  * objects to numbers and comparing the numbers according to IEEE 754.
6421  * ....
6422  * The number function converts its argument to a number as follows:
6423  *  - a string that consists of optional whitespace followed by an
6424  *    optional minus sign followed by a Number followed by whitespace
6425  *    is converted to the IEEE 754 number that is nearest (according
6426  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6427  *    represented by the string; any other string is converted to NaN
6428  *
6429  * Conclusion all nodes need to be converted first to their string value
6430  * and then the comparison must be done when possible 
6431  */
6432 static int
6433 xmlXPathCompareNodeSets(int inf, int strict,
6434                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6435     int i, j, init = 0;
6436     double val1;
6437     double *values2;
6438     int ret = 0;
6439     xmlNodeSetPtr ns1;
6440     xmlNodeSetPtr ns2;
6441
6442     if ((arg1 == NULL) ||
6443         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6444         xmlXPathFreeObject(arg2);
6445         return(0);
6446     }
6447     if ((arg2 == NULL) ||
6448         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6449         xmlXPathFreeObject(arg1);
6450         xmlXPathFreeObject(arg2);
6451         return(0);
6452     }
6453
6454     ns1 = arg1->nodesetval;
6455     ns2 = arg2->nodesetval;
6456
6457     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6458         xmlXPathFreeObject(arg1);
6459         xmlXPathFreeObject(arg2);
6460         return(0);
6461     }
6462     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6463         xmlXPathFreeObject(arg1);
6464         xmlXPathFreeObject(arg2);
6465         return(0);
6466     }
6467
6468     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6469     if (values2 == NULL) {
6470         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6471         xmlXPathFreeObject(arg1);
6472         xmlXPathFreeObject(arg2);
6473         return(0);
6474     }
6475     for (i = 0;i < ns1->nodeNr;i++) {
6476         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6477         if (xmlXPathIsNaN(val1))
6478             continue;
6479         for (j = 0;j < ns2->nodeNr;j++) {
6480             if (init == 0) {
6481                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6482             }
6483             if (xmlXPathIsNaN(values2[j]))
6484                 continue;
6485             if (inf && strict) 
6486                 ret = (val1 < values2[j]);
6487             else if (inf && !strict)
6488                 ret = (val1 <= values2[j]);
6489             else if (!inf && strict)
6490                 ret = (val1 > values2[j]);
6491             else if (!inf && !strict)
6492                 ret = (val1 >= values2[j]);
6493             if (ret)
6494                 break;
6495         }
6496         if (ret)
6497             break;
6498         init = 1;
6499     }
6500     xmlFree(values2);
6501     xmlXPathFreeObject(arg1);
6502     xmlXPathFreeObject(arg2);
6503     return(ret);
6504 }
6505
6506 /**
6507  * xmlXPathCompareNodeSetValue:
6508  * @ctxt:  the XPath Parser context
6509  * @inf:  less than (1) or greater than (0)
6510  * @strict:  is the comparison strict
6511  * @arg:  the node set
6512  * @val:  the value
6513  *
6514  * Implement the compare operation between a nodeset and a value
6515  *     @ns < @val    (1, 1, ...
6516  *     @ns <= @val   (1, 0, ...
6517  *     @ns > @val    (0, 1, ...
6518  *     @ns >= @val   (0, 0, ...
6519  *
6520  * If one object to be compared is a node-set and the other is a boolean,
6521  * then the comparison will be true if and only if the result of performing
6522  * the comparison on the boolean and on the result of converting
6523  * the node-set to a boolean using the boolean function is true.
6524  *
6525  * Returns 0 or 1 depending on the results of the test.
6526  */
6527 static int
6528 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6529                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6530     if ((val == NULL) || (arg == NULL) ||
6531         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6532         return(0);
6533
6534     switch(val->type) {
6535         case XPATH_NUMBER:
6536             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6537         case XPATH_NODESET:
6538         case XPATH_XSLT_TREE:
6539             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6540         case XPATH_STRING:
6541             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6542         case XPATH_BOOLEAN:
6543             valuePush(ctxt, arg);
6544             xmlXPathBooleanFunction(ctxt, 1);
6545             valuePush(ctxt, val);
6546             return(xmlXPathCompareValues(ctxt, inf, strict));
6547         default:
6548             TODO
6549     }
6550     return(0);
6551 }
6552
6553 /**
6554  * xmlXPathEqualNodeSetString:
6555  * @arg:  the nodeset object argument
6556  * @str:  the string to compare to.
6557  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6558  *
6559  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6560  * If one object to be compared is a node-set and the other is a string,
6561  * then the comparison will be true if and only if there is a node in
6562  * the node-set such that the result of performing the comparison on the
6563  * string-value of the node and the other string is true.
6564  *
6565  * Returns 0 or 1 depending on the results of the test.
6566  */
6567 static int
6568 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6569 {
6570     int i;
6571     xmlNodeSetPtr ns;
6572     xmlChar *str2;
6573     unsigned int hash;
6574
6575     if ((str == NULL) || (arg == NULL) ||
6576         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6577         return (0);
6578     ns = arg->nodesetval;
6579     /*
6580      * A NULL nodeset compared with a string is always false
6581      * (since there is no node equal, and no node not equal)
6582      */
6583     if ((ns == NULL) || (ns->nodeNr <= 0) )
6584         return (0);
6585     hash = xmlXPathStringHash(str);
6586     for (i = 0; i < ns->nodeNr; i++) {
6587         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6588             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6589             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6590                 xmlFree(str2);
6591                 if (neq)
6592                     continue;
6593                 return (1);
6594             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6595                 if (neq)
6596                     continue;
6597                 return (1);
6598             } else if (neq) {
6599                 if (str2 != NULL)
6600                     xmlFree(str2);
6601                 return (1);
6602             }
6603             if (str2 != NULL)
6604                 xmlFree(str2);
6605         } else if (neq)
6606             return (1);
6607     }
6608     return (0);
6609 }
6610
6611 /**
6612  * xmlXPathEqualNodeSetFloat:
6613  * @arg:  the nodeset object argument
6614  * @f:  the float to compare to
6615  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6616  *
6617  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6618  * If one object to be compared is a node-set and the other is a number,
6619  * then the comparison will be true if and only if there is a node in
6620  * the node-set such that the result of performing the comparison on the
6621  * number to be compared and on the result of converting the string-value
6622  * of that node to a number using the number function is true.
6623  *
6624  * Returns 0 or 1 depending on the results of the test.
6625  */
6626 static int
6627 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6628     xmlXPathObjectPtr arg, double f, int neq) {
6629   int i, ret=0;
6630   xmlNodeSetPtr ns;
6631   xmlChar *str2;
6632   xmlXPathObjectPtr val;
6633   double v;
6634
6635     if ((arg == NULL) ||
6636         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6637         return(0);
6638
6639     ns = arg->nodesetval;
6640     if (ns != NULL) {
6641         for (i=0;i<ns->nodeNr;i++) {
6642             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6643             if (str2 != NULL) {
6644                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6645                 xmlFree(str2);
6646                 xmlXPathNumberFunction(ctxt, 1);
6647                 val = valuePop(ctxt);
6648                 v = val->floatval;
6649                 xmlXPathReleaseObject(ctxt->context, val);
6650                 if (!xmlXPathIsNaN(v)) {
6651                     if ((!neq) && (v==f)) {
6652                         ret = 1;
6653                         break;
6654                     } else if ((neq) && (v!=f)) {
6655                         ret = 1;
6656                         break;
6657                     }
6658                 } else {        /* NaN is unequal to any value */
6659                     if (neq)
6660                         ret = 1;
6661                 }
6662             }
6663         }
6664     }
6665
6666     return(ret);
6667 }
6668
6669
6670 /**
6671  * xmlXPathEqualNodeSets:
6672  * @arg1:  first nodeset object argument
6673  * @arg2:  second nodeset object argument
6674  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6675  *
6676  * Implement the equal / not equal operation on XPath nodesets:
6677  * @arg1 == @arg2  or  @arg1 != @arg2
6678  * If both objects to be compared are node-sets, then the comparison
6679  * will be true if and only if there is a node in the first node-set and
6680  * a node in the second node-set such that the result of performing the
6681  * comparison on the string-values of the two nodes is true.
6682  *
6683  * (needless to say, this is a costly operation)
6684  *
6685  * Returns 0 or 1 depending on the results of the test.
6686  */
6687 static int
6688 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6689     int i, j;
6690     unsigned int *hashs1;
6691     unsigned int *hashs2;
6692     xmlChar **values1;
6693     xmlChar **values2;
6694     int ret = 0;
6695     xmlNodeSetPtr ns1;
6696     xmlNodeSetPtr ns2;
6697
6698     if ((arg1 == NULL) ||
6699         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6700         return(0);
6701     if ((arg2 == NULL) ||
6702         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6703         return(0);
6704
6705     ns1 = arg1->nodesetval;
6706     ns2 = arg2->nodesetval;
6707
6708     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6709         return(0);
6710     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6711         return(0);
6712
6713     /*
6714      * for equal, check if there is a node pertaining to both sets
6715      */
6716     if (neq == 0)
6717         for (i = 0;i < ns1->nodeNr;i++)
6718             for (j = 0;j < ns2->nodeNr;j++)
6719                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6720                     return(1);
6721
6722     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6723     if (values1 == NULL) {
6724         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6725         return(0);
6726     }
6727     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6728     if (hashs1 == NULL) {
6729         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6730         xmlFree(values1);
6731         return(0);
6732     }
6733     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6734     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6735     if (values2 == NULL) {
6736         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6737         xmlFree(hashs1);
6738         xmlFree(values1);
6739         return(0);
6740     }
6741     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6742     if (hashs2 == NULL) {
6743         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6744         xmlFree(hashs1);
6745         xmlFree(values1);
6746         xmlFree(values2);
6747         return(0);
6748     }
6749     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6750     for (i = 0;i < ns1->nodeNr;i++) {
6751         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6752         for (j = 0;j < ns2->nodeNr;j++) {
6753             if (i == 0)
6754                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6755             if (hashs1[i] != hashs2[j]) {
6756                 if (neq) {
6757                     ret = 1;
6758                     break;
6759                 }
6760             }
6761             else {
6762                 if (values1[i] == NULL)
6763                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6764                 if (values2[j] == NULL)
6765                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6766                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6767                 if (ret)
6768                     break;
6769             }
6770         }
6771         if (ret)
6772             break;
6773     }
6774     for (i = 0;i < ns1->nodeNr;i++)
6775         if (values1[i] != NULL)
6776             xmlFree(values1[i]);
6777     for (j = 0;j < ns2->nodeNr;j++)
6778         if (values2[j] != NULL)
6779             xmlFree(values2[j]);
6780     xmlFree(values1);
6781     xmlFree(values2);
6782     xmlFree(hashs1);
6783     xmlFree(hashs2);
6784     return(ret);
6785 }
6786
6787 static int
6788 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6789   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6790     int ret = 0;
6791     /*
6792      *At this point we are assured neither arg1 nor arg2
6793      *is a nodeset, so we can just pick the appropriate routine.
6794      */
6795     switch (arg1->type) {
6796         case XPATH_UNDEFINED:
6797 #ifdef DEBUG_EXPR
6798             xmlGenericError(xmlGenericErrorContext,
6799                     "Equal: undefined\n");
6800 #endif
6801             break;
6802         case XPATH_BOOLEAN:
6803             switch (arg2->type) {
6804                 case XPATH_UNDEFINED:
6805 #ifdef DEBUG_EXPR
6806                     xmlGenericError(xmlGenericErrorContext,
6807                             "Equal: undefined\n");
6808 #endif
6809                     break;
6810                 case XPATH_BOOLEAN:
6811 #ifdef DEBUG_EXPR
6812                     xmlGenericError(xmlGenericErrorContext,
6813                             "Equal: %d boolean %d \n",
6814                             arg1->boolval, arg2->boolval);
6815 #endif
6816                     ret = (arg1->boolval == arg2->boolval);
6817                     break;
6818                 case XPATH_NUMBER:
6819                     ret = (arg1->boolval ==
6820                            xmlXPathCastNumberToBoolean(arg2->floatval));
6821                     break;
6822                 case XPATH_STRING:
6823                     if ((arg2->stringval == NULL) ||
6824                         (arg2->stringval[0] == 0)) ret = 0;
6825                     else 
6826                         ret = 1;
6827                     ret = (arg1->boolval == ret);
6828                     break;
6829                 case XPATH_USERS:
6830                 case XPATH_POINT:
6831                 case XPATH_RANGE:
6832                 case XPATH_LOCATIONSET:
6833                     TODO
6834                     break;
6835                 case XPATH_NODESET:
6836                 case XPATH_XSLT_TREE:
6837                     break;
6838             }
6839             break;
6840         case XPATH_NUMBER:
6841             switch (arg2->type) {
6842                 case XPATH_UNDEFINED:
6843 #ifdef DEBUG_EXPR
6844                     xmlGenericError(xmlGenericErrorContext,
6845                             "Equal: undefined\n");
6846 #endif
6847                     break;
6848                 case XPATH_BOOLEAN:
6849                     ret = (arg2->boolval==
6850                            xmlXPathCastNumberToBoolean(arg1->floatval));
6851                     break;
6852                 case XPATH_STRING:
6853                     valuePush(ctxt, arg2);
6854                     xmlXPathNumberFunction(ctxt, 1);
6855                     arg2 = valuePop(ctxt);
6856                     /* no break on purpose */
6857                 case XPATH_NUMBER:
6858                     /* Hand check NaN and Infinity equalities */
6859                     if (xmlXPathIsNaN(arg1->floatval) ||
6860                             xmlXPathIsNaN(arg2->floatval)) {
6861                         ret = 0;
6862                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6863                         if (xmlXPathIsInf(arg2->floatval) == 1)
6864                             ret = 1;
6865                         else
6866                             ret = 0;
6867                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6868                         if (xmlXPathIsInf(arg2->floatval) == -1)
6869                             ret = 1;
6870                         else
6871                             ret = 0;
6872                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6873                         if (xmlXPathIsInf(arg1->floatval) == 1)
6874                             ret = 1;
6875                         else
6876                             ret = 0;
6877                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6878                         if (xmlXPathIsInf(arg1->floatval) == -1)
6879                             ret = 1;
6880                         else
6881                             ret = 0;
6882                     } else {
6883                         ret = (arg1->floatval == arg2->floatval);
6884                     }
6885                     break;
6886                 case XPATH_USERS:
6887                 case XPATH_POINT:
6888                 case XPATH_RANGE:
6889                 case XPATH_LOCATIONSET:
6890                     TODO
6891                     break;
6892                 case XPATH_NODESET:
6893                 case XPATH_XSLT_TREE:
6894                     break;
6895             }
6896             break;
6897         case XPATH_STRING:
6898             switch (arg2->type) {
6899                 case XPATH_UNDEFINED:
6900 #ifdef DEBUG_EXPR
6901                     xmlGenericError(xmlGenericErrorContext,
6902                             "Equal: undefined\n");
6903 #endif
6904                     break;
6905                 case XPATH_BOOLEAN:
6906                     if ((arg1->stringval == NULL) ||
6907                         (arg1->stringval[0] == 0)) ret = 0;
6908                     else 
6909                         ret = 1;
6910                     ret = (arg2->boolval == ret);
6911                     break;
6912                 case XPATH_STRING:
6913                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6914                     break;
6915                 case XPATH_NUMBER:
6916                     valuePush(ctxt, arg1);
6917                     xmlXPathNumberFunction(ctxt, 1);
6918                     arg1 = valuePop(ctxt);
6919                     /* Hand check NaN and Infinity equalities */
6920                     if (xmlXPathIsNaN(arg1->floatval) ||
6921                             xmlXPathIsNaN(arg2->floatval)) {
6922                         ret = 0;
6923                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6924                         if (xmlXPathIsInf(arg2->floatval) == 1)
6925                             ret = 1;
6926                         else
6927                             ret = 0;
6928                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6929                         if (xmlXPathIsInf(arg2->floatval) == -1)
6930                             ret = 1;
6931                         else
6932                             ret = 0;
6933                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6934                         if (xmlXPathIsInf(arg1->floatval) == 1)
6935                             ret = 1;
6936                         else
6937                             ret = 0;
6938                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6939                         if (xmlXPathIsInf(arg1->floatval) == -1)
6940                             ret = 1;
6941                         else
6942                             ret = 0;
6943                     } else {
6944                         ret = (arg1->floatval == arg2->floatval);
6945                     }
6946                     break;
6947                 case XPATH_USERS:
6948                 case XPATH_POINT:
6949                 case XPATH_RANGE:
6950                 case XPATH_LOCATIONSET:
6951                     TODO
6952                     break;
6953                 case XPATH_NODESET:
6954                 case XPATH_XSLT_TREE:
6955                     break;
6956             }
6957             break;
6958         case XPATH_USERS:
6959         case XPATH_POINT:
6960         case XPATH_RANGE:
6961         case XPATH_LOCATIONSET:
6962             TODO
6963             break;
6964         case XPATH_NODESET:
6965         case XPATH_XSLT_TREE:
6966             break;
6967     }
6968     xmlXPathReleaseObject(ctxt->context, arg1);
6969     xmlXPathReleaseObject(ctxt->context, arg2);
6970     return(ret);
6971 }
6972
6973 /**
6974  * xmlXPathEqualValues:
6975  * @ctxt:  the XPath Parser context
6976  *
6977  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6978  *
6979  * Returns 0 or 1 depending on the results of the test.
6980  */
6981 int
6982 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6983     xmlXPathObjectPtr arg1, arg2, argtmp;
6984     int ret = 0;
6985
6986     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6987     arg2 = valuePop(ctxt); 
6988     arg1 = valuePop(ctxt);
6989     if ((arg1 == NULL) || (arg2 == NULL)) {
6990         if (arg1 != NULL)
6991             xmlXPathReleaseObject(ctxt->context, arg1);
6992         else
6993             xmlXPathReleaseObject(ctxt->context, arg2);
6994         XP_ERROR0(XPATH_INVALID_OPERAND);
6995     }
6996
6997     if (arg1 == arg2) {
6998 #ifdef DEBUG_EXPR
6999         xmlGenericError(xmlGenericErrorContext,
7000                 "Equal: by pointer\n");
7001 #endif
7002         xmlXPathFreeObject(arg1);
7003         return(1);
7004     }
7005
7006     /*
7007      *If either argument is a nodeset, it's a 'special case'
7008      */
7009     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7010       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7011         /*
7012          *Hack it to assure arg1 is the nodeset
7013          */
7014         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7015                 argtmp = arg2;
7016                 arg2 = arg1;
7017                 arg1 = argtmp;
7018         }
7019         switch (arg2->type) {
7020             case XPATH_UNDEFINED:
7021 #ifdef DEBUG_EXPR
7022                 xmlGenericError(xmlGenericErrorContext,
7023                         "Equal: undefined\n");
7024 #endif
7025                 break;
7026             case XPATH_NODESET:
7027             case XPATH_XSLT_TREE:
7028                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7029                 break;
7030             case XPATH_BOOLEAN:
7031                 if ((arg1->nodesetval == NULL) ||
7032                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7033                 else 
7034                     ret = 1;
7035                 ret = (ret == arg2->boolval);
7036                 break;
7037             case XPATH_NUMBER:
7038                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7039                 break;
7040             case XPATH_STRING:
7041                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7042                 break;
7043             case XPATH_USERS:
7044             case XPATH_POINT:
7045             case XPATH_RANGE:
7046             case XPATH_LOCATIONSET:
7047                 TODO
7048                 break;
7049         }
7050         xmlXPathReleaseObject(ctxt->context, arg1);
7051         xmlXPathReleaseObject(ctxt->context, arg2);
7052         return(ret);
7053     }
7054
7055     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7056 }
7057
7058 /**
7059  * xmlXPathNotEqualValues:
7060  * @ctxt:  the XPath Parser context
7061  *
7062  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7063  *
7064  * Returns 0 or 1 depending on the results of the test.
7065  */
7066 int
7067 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7068     xmlXPathObjectPtr arg1, arg2, argtmp;
7069     int ret = 0;
7070
7071     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7072     arg2 = valuePop(ctxt); 
7073     arg1 = valuePop(ctxt);
7074     if ((arg1 == NULL) || (arg2 == NULL)) {
7075         if (arg1 != NULL)
7076             xmlXPathReleaseObject(ctxt->context, arg1);
7077         else
7078             xmlXPathReleaseObject(ctxt->context, arg2);
7079         XP_ERROR0(XPATH_INVALID_OPERAND);
7080     }
7081
7082     if (arg1 == arg2) {
7083 #ifdef DEBUG_EXPR
7084         xmlGenericError(xmlGenericErrorContext,
7085                 "NotEqual: by pointer\n");
7086 #endif
7087         xmlXPathReleaseObject(ctxt->context, arg1);
7088         return(0);
7089     }
7090
7091     /*
7092      *If either argument is a nodeset, it's a 'special case'
7093      */
7094     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7095       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7096         /*
7097          *Hack it to assure arg1 is the nodeset
7098          */
7099         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7100                 argtmp = arg2;
7101                 arg2 = arg1;
7102                 arg1 = argtmp;
7103         }
7104         switch (arg2->type) {
7105             case XPATH_UNDEFINED:
7106 #ifdef DEBUG_EXPR
7107                 xmlGenericError(xmlGenericErrorContext,
7108                         "NotEqual: undefined\n");
7109 #endif
7110                 break;
7111             case XPATH_NODESET:
7112             case XPATH_XSLT_TREE:
7113                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7114                 break;
7115             case XPATH_BOOLEAN:
7116                 if ((arg1->nodesetval == NULL) ||
7117                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
7118                 else 
7119                     ret = 1;
7120                 ret = (ret != arg2->boolval);
7121                 break;
7122             case XPATH_NUMBER:
7123                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7124                 break;
7125             case XPATH_STRING:
7126                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7127                 break;
7128             case XPATH_USERS:
7129             case XPATH_POINT:
7130             case XPATH_RANGE:
7131             case XPATH_LOCATIONSET:
7132                 TODO
7133                 break;
7134         }
7135         xmlXPathReleaseObject(ctxt->context, arg1);
7136         xmlXPathReleaseObject(ctxt->context, arg2);
7137         return(ret);
7138     }
7139
7140     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7141 }
7142
7143 /**
7144  * xmlXPathCompareValues:
7145  * @ctxt:  the XPath Parser context
7146  * @inf:  less than (1) or greater than (0)
7147  * @strict:  is the comparison strict
7148  *
7149  * Implement the compare operation on XPath objects: 
7150  *     @arg1 < @arg2    (1, 1, ...
7151  *     @arg1 <= @arg2   (1, 0, ...
7152  *     @arg1 > @arg2    (0, 1, ...
7153  *     @arg1 >= @arg2   (0, 0, ...
7154  *
7155  * When neither object to be compared is a node-set and the operator is
7156  * <=, <, >=, >, then the objects are compared by converted both objects
7157  * to numbers and comparing the numbers according to IEEE 754. The <
7158  * comparison will be true if and only if the first number is less than the
7159  * second number. The <= comparison will be true if and only if the first
7160  * number is less than or equal to the second number. The > comparison
7161  * will be true if and only if the first number is greater than the second
7162  * number. The >= comparison will be true if and only if the first number
7163  * is greater than or equal to the second number.
7164  *
7165  * Returns 1 if the comparison succeeded, 0 if it failed
7166  */
7167 int
7168 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7169     int ret = 0, arg1i = 0, arg2i = 0;
7170     xmlXPathObjectPtr arg1, arg2;
7171
7172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7173     arg2 = valuePop(ctxt); 
7174     arg1 = valuePop(ctxt);
7175     if ((arg1 == NULL) || (arg2 == NULL)) {
7176         if (arg1 != NULL)
7177             xmlXPathReleaseObject(ctxt->context, arg1);
7178         else
7179             xmlXPathReleaseObject(ctxt->context, arg2);
7180         XP_ERROR0(XPATH_INVALID_OPERAND);
7181     }
7182
7183     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7184       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7185         /*
7186          * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7187          * are not freed from within this routine; they will be freed from the
7188          * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7189          */
7190         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7191           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7192             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7193         } else {
7194             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7195                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7196                                                   arg1, arg2);
7197             } else {
7198                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7199                                                   arg2, arg1);
7200             }
7201         }
7202         return(ret);
7203     }
7204
7205     if (arg1->type != XPATH_NUMBER) {
7206         valuePush(ctxt, arg1);
7207         xmlXPathNumberFunction(ctxt, 1);
7208         arg1 = valuePop(ctxt);
7209     }
7210     if (arg1->type != XPATH_NUMBER) {
7211         xmlXPathFreeObject(arg1);
7212         xmlXPathFreeObject(arg2);
7213         XP_ERROR0(XPATH_INVALID_OPERAND);
7214     }
7215     if (arg2->type != XPATH_NUMBER) {
7216         valuePush(ctxt, arg2);
7217         xmlXPathNumberFunction(ctxt, 1);
7218         arg2 = valuePop(ctxt);
7219     }
7220     if (arg2->type != XPATH_NUMBER) {
7221         xmlXPathReleaseObject(ctxt->context, arg1);
7222         xmlXPathReleaseObject(ctxt->context, arg2);
7223         XP_ERROR0(XPATH_INVALID_OPERAND);
7224     }
7225     /*
7226      * Add tests for infinity and nan
7227      * => feedback on 3.4 for Inf and NaN
7228      */
7229     /* Hand check NaN and Infinity comparisons */
7230     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7231         ret=0;
7232     } else {
7233         arg1i=xmlXPathIsInf(arg1->floatval);
7234         arg2i=xmlXPathIsInf(arg2->floatval);
7235         if (inf && strict) {
7236             if ((arg1i == -1 && arg2i != -1) ||
7237                 (arg2i == 1 && arg1i != 1)) {
7238                 ret = 1;
7239             } else if (arg1i == 0 && arg2i == 0) {
7240                 ret = (arg1->floatval < arg2->floatval);
7241             } else {
7242                 ret = 0;
7243             }
7244         }
7245         else if (inf && !strict) {
7246             if (arg1i == -1 || arg2i == 1) {
7247                 ret = 1;
7248             } else if (arg1i == 0 && arg2i == 0) {
7249                 ret = (arg1->floatval <= arg2->floatval);
7250             } else {
7251                 ret = 0;
7252             }
7253         }
7254         else if (!inf && strict) {
7255             if ((arg1i == 1 && arg2i != 1) ||
7256                 (arg2i == -1 && arg1i != -1)) {
7257                 ret = 1;
7258             } else if (arg1i == 0 && arg2i == 0) {
7259                 ret = (arg1->floatval > arg2->floatval);
7260             } else {
7261                 ret = 0;
7262             }
7263         }
7264         else if (!inf && !strict) {
7265             if (arg1i == 1 || arg2i == -1) {
7266                 ret = 1;
7267             } else if (arg1i == 0 && arg2i == 0) {
7268                 ret = (arg1->floatval >= arg2->floatval);
7269             } else {
7270                 ret = 0;
7271             }
7272         }
7273     }
7274     xmlXPathReleaseObject(ctxt->context, arg1);
7275     xmlXPathReleaseObject(ctxt->context, arg2);
7276     return(ret);
7277 }
7278
7279 /**
7280  * xmlXPathValueFlipSign:
7281  * @ctxt:  the XPath Parser context
7282  *
7283  * Implement the unary - operation on an XPath object
7284  * The numeric operators convert their operands to numbers as if
7285  * by calling the number function.
7286  */
7287 void
7288 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7289     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7290     CAST_TO_NUMBER;
7291     CHECK_TYPE(XPATH_NUMBER);
7292     if (xmlXPathIsNaN(ctxt->value->floatval))
7293         ctxt->value->floatval=xmlXPathNAN;
7294     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7295         ctxt->value->floatval=xmlXPathNINF;
7296     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7297         ctxt->value->floatval=xmlXPathPINF;
7298     else if (ctxt->value->floatval == 0) {
7299         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7300             ctxt->value->floatval = xmlXPathNZERO;
7301         else
7302             ctxt->value->floatval = 0;
7303     }
7304     else
7305         ctxt->value->floatval = - ctxt->value->floatval;
7306 }
7307
7308 /**
7309  * xmlXPathAddValues:
7310  * @ctxt:  the XPath Parser context
7311  *
7312  * Implement the add operation on XPath objects:
7313  * The numeric operators convert their operands to numbers as if
7314  * by calling the number function.
7315  */
7316 void
7317 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7318     xmlXPathObjectPtr arg;
7319     double val;
7320
7321     arg = valuePop(ctxt);
7322     if (arg == NULL)
7323         XP_ERROR(XPATH_INVALID_OPERAND);
7324     val = xmlXPathCastToNumber(arg);
7325     xmlXPathReleaseObject(ctxt->context, arg);
7326     CAST_TO_NUMBER;
7327     CHECK_TYPE(XPATH_NUMBER);
7328     ctxt->value->floatval += val;
7329 }
7330
7331 /**
7332  * xmlXPathSubValues:
7333  * @ctxt:  the XPath Parser context
7334  *
7335  * Implement the subtraction operation on XPath objects:
7336  * The numeric operators convert their operands to numbers as if
7337  * by calling the number function.
7338  */
7339 void
7340 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7341     xmlXPathObjectPtr arg;
7342     double val;
7343
7344     arg = valuePop(ctxt);
7345     if (arg == NULL)
7346         XP_ERROR(XPATH_INVALID_OPERAND);
7347     val = xmlXPathCastToNumber(arg);
7348     xmlXPathReleaseObject(ctxt->context, arg);
7349     CAST_TO_NUMBER;
7350     CHECK_TYPE(XPATH_NUMBER);
7351     ctxt->value->floatval -= val;
7352 }
7353
7354 /**
7355  * xmlXPathMultValues:
7356  * @ctxt:  the XPath Parser context
7357  *
7358  * Implement the multiply operation on XPath objects:
7359  * The numeric operators convert their operands to numbers as if
7360  * by calling the number function.
7361  */
7362 void
7363 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7364     xmlXPathObjectPtr arg;
7365     double val;
7366
7367     arg = valuePop(ctxt);
7368     if (arg == NULL)
7369         XP_ERROR(XPATH_INVALID_OPERAND);
7370     val = xmlXPathCastToNumber(arg);
7371     xmlXPathReleaseObject(ctxt->context, arg);
7372     CAST_TO_NUMBER;
7373     CHECK_TYPE(XPATH_NUMBER);
7374     ctxt->value->floatval *= val;
7375 }
7376
7377 /**
7378  * xmlXPathDivValues:
7379  * @ctxt:  the XPath Parser context
7380  *
7381  * Implement the div operation on XPath objects @arg1 / @arg2:
7382  * The numeric operators convert their operands to numbers as if
7383  * by calling the number function.
7384  */
7385 void
7386 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7387     xmlXPathObjectPtr arg;
7388     double val;
7389
7390     arg = valuePop(ctxt);
7391     if (arg == NULL)
7392         XP_ERROR(XPATH_INVALID_OPERAND);
7393     val = xmlXPathCastToNumber(arg);
7394     xmlXPathReleaseObject(ctxt->context, arg);
7395     CAST_TO_NUMBER;
7396     CHECK_TYPE(XPATH_NUMBER);
7397     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7398         ctxt->value->floatval = xmlXPathNAN;
7399     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7400         if (ctxt->value->floatval == 0)
7401             ctxt->value->floatval = xmlXPathNAN;
7402         else if (ctxt->value->floatval > 0)
7403             ctxt->value->floatval = xmlXPathNINF;
7404         else if (ctxt->value->floatval < 0)
7405             ctxt->value->floatval = xmlXPathPINF;
7406     }
7407     else if (val == 0) {
7408         if (ctxt->value->floatval == 0)
7409             ctxt->value->floatval = xmlXPathNAN;
7410         else if (ctxt->value->floatval > 0)
7411             ctxt->value->floatval = xmlXPathPINF;
7412         else if (ctxt->value->floatval < 0)
7413             ctxt->value->floatval = xmlXPathNINF;
7414     } else 
7415         ctxt->value->floatval /= val;
7416 }
7417
7418 /**
7419  * xmlXPathModValues:
7420  * @ctxt:  the XPath Parser context
7421  *
7422  * Implement the mod operation on XPath objects: @arg1 / @arg2
7423  * The numeric operators convert their operands to numbers as if
7424  * by calling the number function.
7425  */
7426 void
7427 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7428     xmlXPathObjectPtr arg;
7429     double arg1, arg2;
7430
7431     arg = valuePop(ctxt);
7432     if (arg == NULL)
7433         XP_ERROR(XPATH_INVALID_OPERAND);
7434     arg2 = xmlXPathCastToNumber(arg);
7435     xmlXPathReleaseObject(ctxt->context, arg);
7436     CAST_TO_NUMBER;
7437     CHECK_TYPE(XPATH_NUMBER);
7438     arg1 = ctxt->value->floatval;
7439     if (arg2 == 0)
7440         ctxt->value->floatval = xmlXPathNAN;
7441     else {
7442         ctxt->value->floatval = fmod(arg1, arg2);
7443     }
7444 }
7445
7446 /************************************************************************
7447  *                                                                      *
7448  *              The traversal functions                                 *
7449  *                                                                      *
7450  ************************************************************************/
7451
7452 /*
7453  * A traversal function enumerates nodes along an axis.
7454  * Initially it must be called with NULL, and it indicates
7455  * termination on the axis by returning NULL.
7456  */
7457 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7458                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7459
7460 /*
7461  * xmlXPathTraversalFunctionExt:
7462  * A traversal function enumerates nodes along an axis.
7463  * Initially it must be called with NULL, and it indicates
7464  * termination on the axis by returning NULL.
7465  * The context node of the traversal is specified via @contextNode.
7466  */
7467 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7468                     (xmlNodePtr cur, xmlNodePtr contextNode);
7469
7470 /*
7471  * xmlXPathNodeSetMergeFunction:
7472  * Used for merging node sets in xmlXPathCollectAndTest().
7473  */
7474 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7475                     (xmlNodeSetPtr, xmlNodeSetPtr, int);
7476
7477
7478 /**
7479  * xmlXPathNextSelf:
7480  * @ctxt:  the XPath Parser context
7481  * @cur:  the current node in the traversal
7482  *
7483  * Traversal function for the "self" direction
7484  * The self axis contains just the context node itself
7485  *
7486  * Returns the next element following that axis
7487  */
7488 xmlNodePtr
7489 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7491     if (cur == NULL)
7492         return(ctxt->context->node);
7493     return(NULL);
7494 }
7495
7496 /**
7497  * xmlXPathNextChild:
7498  * @ctxt:  the XPath Parser context
7499  * @cur:  the current node in the traversal
7500  *
7501  * Traversal function for the "child" direction
7502  * The child axis contains the children of the context node in document order.
7503  *
7504  * Returns the next element following that axis
7505  */
7506 xmlNodePtr
7507 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7508     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7509     if (cur == NULL) {
7510         if (ctxt->context->node == NULL) return(NULL);
7511         switch (ctxt->context->node->type) {
7512             case XML_ELEMENT_NODE:
7513             case XML_TEXT_NODE:
7514             case XML_CDATA_SECTION_NODE:
7515             case XML_ENTITY_REF_NODE:
7516             case XML_ENTITY_NODE:
7517             case XML_PI_NODE:
7518             case XML_COMMENT_NODE:
7519             case XML_NOTATION_NODE:
7520             case XML_DTD_NODE:
7521                 return(ctxt->context->node->children);
7522             case XML_DOCUMENT_NODE:
7523             case XML_DOCUMENT_TYPE_NODE:
7524             case XML_DOCUMENT_FRAG_NODE:
7525             case XML_HTML_DOCUMENT_NODE:
7526 #ifdef LIBXML_DOCB_ENABLED
7527             case XML_DOCB_DOCUMENT_NODE:
7528 #endif
7529                 return(((xmlDocPtr) ctxt->context->node)->children);
7530             case XML_ELEMENT_DECL:
7531             case XML_ATTRIBUTE_DECL:
7532             case XML_ENTITY_DECL:
7533             case XML_ATTRIBUTE_NODE:
7534             case XML_NAMESPACE_DECL:
7535             case XML_XINCLUDE_START:
7536             case XML_XINCLUDE_END:
7537                 return(NULL);
7538         }
7539         return(NULL);
7540     }
7541     if ((cur->type == XML_DOCUMENT_NODE) ||
7542         (cur->type == XML_HTML_DOCUMENT_NODE))
7543         return(NULL);
7544     return(cur->next);
7545 }
7546
7547 /**
7548  * xmlXPathNextChildElement:
7549  * @ctxt:  the XPath Parser context
7550  * @cur:  the current node in the traversal
7551  *
7552  * Traversal function for the "child" direction and nodes of type element.
7553  * The child axis contains the children of the context node in document order.
7554  *
7555  * Returns the next element following that axis
7556  */
7557 static xmlNodePtr
7558 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7559     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7560     if (cur == NULL) {
7561         cur = ctxt->context->node;
7562         if (cur == NULL) return(NULL);
7563         /*
7564         * Get the first element child.
7565         */
7566         switch (cur->type) {
7567             case XML_ELEMENT_NODE:
7568             case XML_DOCUMENT_FRAG_NODE:
7569             case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7570             case XML_ENTITY_NODE:
7571                 cur = cur->children;
7572                 if (cur != NULL) {
7573                     if (cur->type == XML_ELEMENT_NODE)
7574                         return(cur);
7575                     do {
7576                         cur = cur->next;
7577                     } while ((cur != NULL) &&
7578                         (cur->type != XML_ELEMENT_NODE));
7579                     return(cur);
7580                 }
7581                 return(NULL);
7582             case XML_DOCUMENT_NODE:
7583             case XML_HTML_DOCUMENT_NODE:
7584 #ifdef LIBXML_DOCB_ENABLED
7585             case XML_DOCB_DOCUMENT_NODE:
7586 #endif
7587                 return(xmlDocGetRootElement((xmlDocPtr) cur));
7588             default:
7589                 return(NULL);
7590         }
7591         return(NULL);
7592     }
7593     /*
7594     * Get the next sibling element node.
7595     */
7596     switch (cur->type) {
7597         case XML_ELEMENT_NODE:
7598         case XML_TEXT_NODE:
7599         case XML_ENTITY_REF_NODE:
7600         case XML_ENTITY_NODE:
7601         case XML_CDATA_SECTION_NODE:
7602         case XML_PI_NODE:
7603         case XML_COMMENT_NODE:
7604         case XML_XINCLUDE_END:
7605             break;
7606         /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7607         default:
7608             return(NULL);
7609     }
7610     if (cur->next != NULL) {
7611         if (cur->next->type == XML_ELEMENT_NODE)
7612             return(cur->next);
7613         cur = cur->next;
7614         do {
7615             cur = cur->next;
7616         } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7617         return(cur);
7618     }
7619     return(NULL);
7620 }
7621
7622 /**
7623  * xmlXPathNextDescendantOrSelfElemParent:
7624  * @ctxt:  the XPath Parser context
7625  * @cur:  the current node in the traversal
7626  *
7627  * Traversal function for the "descendant-or-self" axis.
7628  * Additionally it returns only nodes which can be parents of
7629  * element nodes.
7630  *
7631  *
7632  * Returns the next element following that axis
7633  */
7634 static xmlNodePtr
7635 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7636                                        xmlNodePtr contextNode)
7637 {
7638     if (cur == NULL) {
7639         if (contextNode == NULL)
7640             return(NULL);
7641         switch (contextNode->type) {
7642             case XML_ELEMENT_NODE:
7643             case XML_XINCLUDE_START:
7644             case XML_DOCUMENT_FRAG_NODE:
7645             case XML_DOCUMENT_NODE:
7646 #ifdef LIBXML_DOCB_ENABLED
7647             case XML_DOCB_DOCUMENT_NODE:
7648 #endif
7649             case XML_HTML_DOCUMENT_NODE:                
7650                 return(contextNode);
7651             default:
7652                 return(NULL);       
7653         }
7654         return(NULL);
7655     } else {
7656         xmlNodePtr start = cur;
7657
7658         while (cur != NULL) {
7659             switch (cur->type) {
7660                 case XML_ELEMENT_NODE:
7661                 /* TODO: OK to have XInclude here? */
7662                 case XML_XINCLUDE_START:
7663                 case XML_DOCUMENT_FRAG_NODE:            
7664                     if (cur != start)
7665                         return(cur);
7666                     if (cur->children != NULL) {
7667                         cur = cur->children;
7668                         continue;
7669                     }
7670                     break;
7671 #ifdef LIBXML_DOCB_ENABLED
7672                 /* Not sure if we need those here. */
7673                 case XML_DOCUMENT_NODE:
7674                 case XML_DOCB_DOCUMENT_NODE:
7675 #endif
7676                 case XML_HTML_DOCUMENT_NODE:
7677                     if (cur != start)
7678                         return(cur);
7679                     return(xmlDocGetRootElement((xmlDocPtr) cur));
7680                 default:
7681                     break;
7682             }       
7683             
7684 next_sibling:
7685             if ((cur == NULL) || (cur == contextNode))
7686                 return(NULL);   
7687             if (cur->next != NULL) {
7688                 cur = cur->next;                
7689             } else {
7690                 cur = cur->parent;
7691                 goto next_sibling;
7692             }
7693         }
7694     }
7695     return(NULL);
7696 }            
7697
7698 /**
7699  * xmlXPathNextDescendant:
7700  * @ctxt:  the XPath Parser context
7701  * @cur:  the current node in the traversal
7702  *
7703  * Traversal function for the "descendant" direction
7704  * the descendant axis contains the descendants of the context node in document
7705  * order; a descendant is a child or a child of a child and so on.
7706  *
7707  * Returns the next element following that axis
7708  */
7709 xmlNodePtr
7710 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712     if (cur == NULL) {
7713         if (ctxt->context->node == NULL)
7714             return(NULL);
7715         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7716             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7717             return(NULL);
7718
7719         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7720             return(ctxt->context->doc->children);
7721         return(ctxt->context->node->children);
7722     }
7723
7724     if (cur->children != NULL) {
7725         /*
7726          * Do not descend on entities declarations
7727          */
7728         if (cur->children->type != XML_ENTITY_DECL) {
7729             cur = cur->children;
7730             /*
7731              * Skip DTDs
7732              */
7733             if (cur->type != XML_DTD_NODE)
7734                 return(cur);
7735         }
7736     }
7737
7738     if (cur == ctxt->context->node) return(NULL);
7739
7740     while (cur->next != NULL) {
7741         cur = cur->next;
7742         if ((cur->type != XML_ENTITY_DECL) &&
7743             (cur->type != XML_DTD_NODE))
7744             return(cur);
7745     }
7746     
7747     do {
7748         cur = cur->parent;
7749         if (cur == NULL) break;
7750         if (cur == ctxt->context->node) return(NULL);
7751         if (cur->next != NULL) {
7752             cur = cur->next;
7753             return(cur);
7754         }
7755     } while (cur != NULL);
7756     return(cur);
7757 }
7758
7759 /**
7760  * xmlXPathNextDescendantOrSelf:
7761  * @ctxt:  the XPath Parser context
7762  * @cur:  the current node in the traversal
7763  *
7764  * Traversal function for the "descendant-or-self" direction
7765  * the descendant-or-self axis contains the context node and the descendants
7766  * of the context node in document order; thus the context node is the first
7767  * node on the axis, and the first child of the context node is the second node
7768  * on the axis
7769  *
7770  * Returns the next element following that axis
7771  */
7772 xmlNodePtr
7773 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7774     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7775     if (cur == NULL) {
7776         if (ctxt->context->node == NULL)
7777             return(NULL);
7778         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7779             (ctxt->context->node->type == XML_NAMESPACE_DECL))
7780             return(NULL);
7781         return(ctxt->context->node);
7782     }
7783
7784     return(xmlXPathNextDescendant(ctxt, cur));
7785 }
7786
7787 /**
7788  * xmlXPathNextParent:
7789  * @ctxt:  the XPath Parser context
7790  * @cur:  the current node in the traversal
7791  *
7792  * Traversal function for the "parent" direction
7793  * The parent axis contains the parent of the context node, if there is one.
7794  *
7795  * Returns the next element following that axis
7796  */
7797 xmlNodePtr
7798 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7799     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7800     /*
7801      * the parent of an attribute or namespace node is the element
7802      * to which the attribute or namespace node is attached
7803      * Namespace handling !!!
7804      */
7805     if (cur == NULL) {
7806         if (ctxt->context->node == NULL) return(NULL);
7807         switch (ctxt->context->node->type) {
7808             case XML_ELEMENT_NODE:
7809             case XML_TEXT_NODE:
7810             case XML_CDATA_SECTION_NODE:
7811             case XML_ENTITY_REF_NODE:
7812             case XML_ENTITY_NODE:
7813             case XML_PI_NODE:
7814             case XML_COMMENT_NODE:
7815             case XML_NOTATION_NODE:
7816             case XML_DTD_NODE:
7817             case XML_ELEMENT_DECL:
7818             case XML_ATTRIBUTE_DECL:
7819             case XML_XINCLUDE_START:
7820             case XML_XINCLUDE_END:
7821             case XML_ENTITY_DECL:
7822                 if (ctxt->context->node->parent == NULL)
7823                     return((xmlNodePtr) ctxt->context->doc);
7824                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7825                     ((ctxt->context->node->parent->name[0] == ' ') ||
7826                      (xmlStrEqual(ctxt->context->node->parent->name,
7827                                  BAD_CAST "fake node libxslt"))))
7828                     return(NULL);
7829                 return(ctxt->context->node->parent);
7830             case XML_ATTRIBUTE_NODE: {
7831                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7832
7833                 return(att->parent);
7834             }
7835             case XML_DOCUMENT_NODE:
7836             case XML_DOCUMENT_TYPE_NODE:
7837             case XML_DOCUMENT_FRAG_NODE:
7838             case XML_HTML_DOCUMENT_NODE:
7839 #ifdef LIBXML_DOCB_ENABLED
7840             case XML_DOCB_DOCUMENT_NODE:
7841 #endif
7842                 return(NULL);
7843             case XML_NAMESPACE_DECL: {
7844                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7845                 
7846                 if ((ns->next != NULL) &&
7847                     (ns->next->type != XML_NAMESPACE_DECL))
7848                     return((xmlNodePtr) ns->next);
7849                 return(NULL);
7850             }
7851         }
7852     }
7853     return(NULL);
7854 }
7855
7856 /**
7857  * xmlXPathNextAncestor:
7858  * @ctxt:  the XPath Parser context
7859  * @cur:  the current node in the traversal
7860  *
7861  * Traversal function for the "ancestor" direction
7862  * the ancestor axis contains the ancestors of the context node; the ancestors
7863  * of the context node consist of the parent of context node and the parent's
7864  * parent and so on; the nodes are ordered in reverse document order; thus the
7865  * parent is the first node on the axis, and the parent's parent is the second
7866  * node on the axis
7867  *
7868  * Returns the next element following that axis
7869  */
7870 xmlNodePtr
7871 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7872     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7873     /*
7874      * the parent of an attribute or namespace node is the element
7875      * to which the attribute or namespace node is attached
7876      * !!!!!!!!!!!!!
7877      */
7878     if (cur == NULL) {
7879         if (ctxt->context->node == NULL) return(NULL);
7880         switch (ctxt->context->node->type) {
7881             case XML_ELEMENT_NODE:
7882             case XML_TEXT_NODE:
7883             case XML_CDATA_SECTION_NODE:
7884             case XML_ENTITY_REF_NODE:
7885             case XML_ENTITY_NODE:
7886             case XML_PI_NODE:
7887             case XML_COMMENT_NODE:
7888             case XML_DTD_NODE:
7889             case XML_ELEMENT_DECL:
7890             case XML_ATTRIBUTE_DECL:
7891             case XML_ENTITY_DECL:
7892             case XML_NOTATION_NODE:
7893             case XML_XINCLUDE_START:
7894             case XML_XINCLUDE_END:
7895                 if (ctxt->context->node->parent == NULL)
7896                     return((xmlNodePtr) ctxt->context->doc);
7897                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7898                     ((ctxt->context->node->parent->name[0] == ' ') ||
7899                      (xmlStrEqual(ctxt->context->node->parent->name,
7900                                  BAD_CAST "fake node libxslt"))))
7901                     return(NULL);
7902                 return(ctxt->context->node->parent);
7903             case XML_ATTRIBUTE_NODE: {
7904                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7905
7906                 return(tmp->parent);
7907             }
7908             case XML_DOCUMENT_NODE:
7909             case XML_DOCUMENT_TYPE_NODE:
7910             case XML_DOCUMENT_FRAG_NODE:
7911             case XML_HTML_DOCUMENT_NODE:
7912 #ifdef LIBXML_DOCB_ENABLED
7913             case XML_DOCB_DOCUMENT_NODE:
7914 #endif
7915                 return(NULL);
7916             case XML_NAMESPACE_DECL: {
7917                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7918                 
7919                 if ((ns->next != NULL) &&
7920                     (ns->next->type != XML_NAMESPACE_DECL))
7921                     return((xmlNodePtr) ns->next);
7922                 /* Bad, how did that namespace end up here ? */
7923                 return(NULL);
7924             }
7925         }
7926         return(NULL);
7927     }
7928     if (cur == ctxt->context->doc->children)
7929         return((xmlNodePtr) ctxt->context->doc);
7930     if (cur == (xmlNodePtr) ctxt->context->doc)
7931         return(NULL);
7932     switch (cur->type) {
7933         case XML_ELEMENT_NODE:
7934         case XML_TEXT_NODE:
7935         case XML_CDATA_SECTION_NODE:
7936         case XML_ENTITY_REF_NODE:
7937         case XML_ENTITY_NODE:
7938         case XML_PI_NODE:
7939         case XML_COMMENT_NODE:
7940         case XML_NOTATION_NODE:
7941         case XML_DTD_NODE:
7942         case XML_ELEMENT_DECL:
7943         case XML_ATTRIBUTE_DECL:
7944         case XML_ENTITY_DECL:
7945         case XML_XINCLUDE_START:
7946         case XML_XINCLUDE_END:
7947             if (cur->parent == NULL)
7948                 return(NULL);
7949             if ((cur->parent->type == XML_ELEMENT_NODE) &&
7950                 ((cur->parent->name[0] == ' ') ||
7951                  (xmlStrEqual(cur->parent->name,
7952                               BAD_CAST "fake node libxslt"))))
7953                 return(NULL);
7954             return(cur->parent);
7955         case XML_ATTRIBUTE_NODE: {
7956             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7957
7958             return(att->parent);
7959         }
7960         case XML_NAMESPACE_DECL: {
7961             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7962                 
7963             if ((ns->next != NULL) &&
7964                 (ns->next->type != XML_NAMESPACE_DECL))
7965                 return((xmlNodePtr) ns->next);
7966             /* Bad, how did that namespace end up here ? */
7967             return(NULL);
7968         }
7969         case XML_DOCUMENT_NODE:
7970         case XML_DOCUMENT_TYPE_NODE:
7971         case XML_DOCUMENT_FRAG_NODE:
7972         case XML_HTML_DOCUMENT_NODE:
7973 #ifdef LIBXML_DOCB_ENABLED
7974         case XML_DOCB_DOCUMENT_NODE:
7975 #endif
7976             return(NULL);
7977     }
7978     return(NULL);
7979 }
7980
7981 /**
7982  * xmlXPathNextAncestorOrSelf:
7983  * @ctxt:  the XPath Parser context
7984  * @cur:  the current node in the traversal
7985  *
7986  * Traversal function for the "ancestor-or-self" direction
7987  * he ancestor-or-self axis contains the context node and ancestors of
7988  * the context node in reverse document order; thus the context node is
7989  * the first node on the axis, and the context node's parent the second;
7990  * parent here is defined the same as with the parent axis.
7991  *
7992  * Returns the next element following that axis
7993  */
7994 xmlNodePtr
7995 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7996     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7997     if (cur == NULL)
7998         return(ctxt->context->node);
7999     return(xmlXPathNextAncestor(ctxt, cur));
8000 }
8001
8002 /**
8003  * xmlXPathNextFollowingSibling:
8004  * @ctxt:  the XPath Parser context
8005  * @cur:  the current node in the traversal
8006  *
8007  * Traversal function for the "following-sibling" direction
8008  * The following-sibling axis contains the following siblings of the context
8009  * node in document order.
8010  *
8011  * Returns the next element following that axis
8012  */
8013 xmlNodePtr
8014 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8015     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8016     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8017         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8018         return(NULL);
8019     if (cur == (xmlNodePtr) ctxt->context->doc)
8020         return(NULL);
8021     if (cur == NULL)
8022         return(ctxt->context->node->next);
8023     return(cur->next);
8024 }
8025
8026 /**
8027  * xmlXPathNextPrecedingSibling:
8028  * @ctxt:  the XPath Parser context
8029  * @cur:  the current node in the traversal
8030  *
8031  * Traversal function for the "preceding-sibling" direction
8032  * The preceding-sibling axis contains the preceding siblings of the context
8033  * node in reverse document order; the first preceding sibling is first on the
8034  * axis; the sibling preceding that node is the second on the axis and so on.
8035  *
8036  * Returns the next element following that axis
8037  */
8038 xmlNodePtr
8039 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8040     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8041     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8042         (ctxt->context->node->type == XML_NAMESPACE_DECL))
8043         return(NULL);
8044     if (cur == (xmlNodePtr) ctxt->context->doc)
8045         return(NULL);
8046     if (cur == NULL)
8047         return(ctxt->context->node->prev);
8048     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8049         cur = cur->prev;
8050         if (cur == NULL)
8051             return(ctxt->context->node->prev);
8052     }
8053     return(cur->prev);
8054 }
8055
8056 /**
8057  * xmlXPathNextFollowing:
8058  * @ctxt:  the XPath Parser context
8059  * @cur:  the current node in the traversal
8060  *
8061  * Traversal function for the "following" direction
8062  * The following axis contains all nodes in the same document as the context
8063  * node that are after the context node in document order, excluding any
8064  * descendants and excluding attribute nodes and namespace nodes; the nodes
8065  * are ordered in document order
8066  *
8067  * Returns the next element following that axis
8068  */
8069 xmlNodePtr
8070 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8071     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8072     if (cur != NULL && cur->children != NULL)
8073         return cur->children ;
8074     if (cur == NULL) cur = ctxt->context->node;
8075     if (cur == NULL) return(NULL) ; /* ERROR */
8076     if (cur->next != NULL) return(cur->next) ;
8077     do {
8078         cur = cur->parent;
8079         if (cur == NULL) break;
8080         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8081         if (cur->next != NULL) return(cur->next);
8082     } while (cur != NULL);
8083     return(cur);
8084 }
8085
8086 /*
8087  * xmlXPathIsAncestor:
8088  * @ancestor:  the ancestor node
8089  * @node:  the current node
8090  *
8091  * Check that @ancestor is a @node's ancestor
8092  *
8093  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8094  */
8095 static int
8096 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8097     if ((ancestor == NULL) || (node == NULL)) return(0);
8098     /* nodes need to be in the same document */
8099     if (ancestor->doc != node->doc) return(0);
8100     /* avoid searching if ancestor or node is the root node */
8101     if (ancestor == (xmlNodePtr) node->doc) return(1);
8102     if (node == (xmlNodePtr) ancestor->doc) return(0);
8103     while (node->parent != NULL) {
8104         if (node->parent == ancestor)
8105             return(1);
8106         node = node->parent;
8107     }
8108     return(0);
8109 }
8110
8111 /**
8112  * xmlXPathNextPreceding:
8113  * @ctxt:  the XPath Parser context
8114  * @cur:  the current node in the traversal
8115  *
8116  * Traversal function for the "preceding" direction
8117  * the preceding axis contains all nodes in the same document as the context
8118  * node that are before the context node in document order, excluding any
8119  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8120  * ordered in reverse document order
8121  *
8122  * Returns the next element following that axis
8123  */
8124 xmlNodePtr
8125 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8126 {
8127     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8128     if (cur == NULL)
8129         cur = ctxt->context->node;
8130     if (cur == NULL)
8131         return (NULL);
8132     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8133         cur = cur->prev;
8134     do {
8135         if (cur->prev != NULL) {
8136             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8137             return (cur);
8138         }
8139
8140         cur = cur->parent;
8141         if (cur == NULL)
8142             return (NULL);
8143         if (cur == ctxt->context->doc->children)
8144             return (NULL);
8145     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8146     return (cur);
8147 }
8148
8149 /**
8150  * xmlXPathNextPrecedingInternal:
8151  * @ctxt:  the XPath Parser context
8152  * @cur:  the current node in the traversal
8153  *
8154  * Traversal function for the "preceding" direction
8155  * the preceding axis contains all nodes in the same document as the context
8156  * node that are before the context node in document order, excluding any
8157  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8158  * ordered in reverse document order
8159  * This is a faster implementation but internal only since it requires a 
8160  * state kept in the parser context: ctxt->ancestor.
8161  *
8162  * Returns the next element following that axis
8163  */
8164 static xmlNodePtr
8165 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8166                               xmlNodePtr cur)
8167 {
8168     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8169     if (cur == NULL) {
8170         cur = ctxt->context->node;
8171         if (cur == NULL)
8172             return (NULL);
8173         if (cur->type == XML_NAMESPACE_DECL)
8174             cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8175         ctxt->ancestor = cur->parent;
8176     }
8177     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8178         cur = cur->prev;
8179     while (cur->prev == NULL) {
8180         cur = cur->parent;
8181         if (cur == NULL)
8182             return (NULL);
8183         if (cur == ctxt->context->doc->children)
8184             return (NULL);
8185         if (cur != ctxt->ancestor)
8186             return (cur);
8187         ctxt->ancestor = cur->parent;
8188     }
8189     cur = cur->prev;
8190     while (cur->last != NULL)
8191         cur = cur->last;
8192     return (cur);
8193 }
8194
8195 /**
8196  * xmlXPathNextNamespace:
8197  * @ctxt:  the XPath Parser context
8198  * @cur:  the current attribute in the traversal
8199  *
8200  * Traversal function for the "namespace" direction
8201  * the namespace axis contains the namespace nodes of the context node;
8202  * the order of nodes on this axis is implementation-defined; the axis will
8203  * be empty unless the context node is an element
8204  *
8205  * We keep the XML namespace node at the end of the list.
8206  *
8207  * Returns the next element following that axis
8208  */
8209 xmlNodePtr
8210 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8211     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8212     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8213     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8214         if (ctxt->context->tmpNsList != NULL)
8215             xmlFree(ctxt->context->tmpNsList);
8216         ctxt->context->tmpNsList = 
8217             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8218         ctxt->context->tmpNsNr = 0;
8219         if (ctxt->context->tmpNsList != NULL) {
8220             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8221                 ctxt->context->tmpNsNr++;
8222             }
8223         }
8224         return((xmlNodePtr) xmlXPathXMLNamespace);
8225     }
8226     if (ctxt->context->tmpNsNr > 0) {
8227         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8228     } else {
8229         if (ctxt->context->tmpNsList != NULL)
8230             xmlFree(ctxt->context->tmpNsList);
8231         ctxt->context->tmpNsList = NULL;
8232         return(NULL);
8233     }
8234 }
8235
8236 /**
8237  * xmlXPathNextAttribute:
8238  * @ctxt:  the XPath Parser context
8239  * @cur:  the current attribute in the traversal
8240  *
8241  * Traversal function for the "attribute" direction
8242  * TODO: support DTD inherited default attributes
8243  *
8244  * Returns the next element following that axis
8245  */
8246 xmlNodePtr
8247 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8248     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8249     if (ctxt->context->node == NULL)
8250         return(NULL);
8251     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8252         return(NULL);
8253     if (cur == NULL) {
8254         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8255             return(NULL);
8256         return((xmlNodePtr)ctxt->context->node->properties);
8257     }
8258     return((xmlNodePtr)cur->next);
8259 }
8260
8261 /************************************************************************
8262  *                                                                      *
8263  *              NodeTest Functions                                      *
8264  *                                                                      *
8265  ************************************************************************/
8266
8267 #define IS_FUNCTION                     200
8268
8269
8270 /************************************************************************
8271  *                                                                      *
8272  *              Implicit tree core function library                     *
8273  *                                                                      *
8274  ************************************************************************/
8275
8276 /**
8277  * xmlXPathRoot:
8278  * @ctxt:  the XPath Parser context
8279  *
8280  * Initialize the context to the root of the document
8281  */
8282 void
8283 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8284     if ((ctxt == NULL) || (ctxt->context == NULL))
8285         return;
8286     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8287     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8288         ctxt->context->node));
8289 }
8290
8291 /************************************************************************
8292  *                                                                      *
8293  *              The explicit core function library                      *
8294  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8295  *                                                                      *
8296  ************************************************************************/
8297
8298
8299 /**
8300  * xmlXPathLastFunction:
8301  * @ctxt:  the XPath Parser context
8302  * @nargs:  the number of arguments
8303  *
8304  * Implement the last() XPath function
8305  *    number last()
8306  * The last function returns the number of nodes in the context node list.
8307  */
8308 void
8309 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8310     CHECK_ARITY(0);
8311     if (ctxt->context->contextSize >= 0) {
8312         valuePush(ctxt,
8313             xmlXPathCacheNewFloat(ctxt->context,
8314                 (double) ctxt->context->contextSize));
8315 #ifdef DEBUG_EXPR
8316         xmlGenericError(xmlGenericErrorContext,
8317                 "last() : %d\n", ctxt->context->contextSize);
8318 #endif
8319     } else {
8320         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8321     }
8322 }
8323
8324 /**
8325  * xmlXPathPositionFunction:
8326  * @ctxt:  the XPath Parser context
8327  * @nargs:  the number of arguments
8328  *
8329  * Implement the position() XPath function
8330  *    number position()
8331  * The position function returns the position of the context node in the
8332  * context node list. The first position is 1, and so the last position
8333  * will be equal to last().
8334  */
8335 void
8336 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8337     CHECK_ARITY(0);
8338     if (ctxt->context->proximityPosition >= 0) {
8339         valuePush(ctxt,
8340               xmlXPathCacheNewFloat(ctxt->context,
8341                 (double) ctxt->context->proximityPosition));
8342 #ifdef DEBUG_EXPR
8343         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8344                 ctxt->context->proximityPosition);
8345 #endif
8346     } else {
8347         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8348     }
8349 }
8350
8351 /**
8352  * xmlXPathCountFunction:
8353  * @ctxt:  the XPath Parser context
8354  * @nargs:  the number of arguments
8355  *
8356  * Implement the count() XPath function
8357  *    number count(node-set)
8358  */
8359 void
8360 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8361     xmlXPathObjectPtr cur;
8362
8363     CHECK_ARITY(1);
8364     if ((ctxt->value == NULL) || 
8365         ((ctxt->value->type != XPATH_NODESET) &&
8366          (ctxt->value->type != XPATH_XSLT_TREE)))
8367         XP_ERROR(XPATH_INVALID_TYPE);
8368     cur = valuePop(ctxt);
8369
8370     if ((cur == NULL) || (cur->nodesetval == NULL))
8371         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8372     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8373         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8374             (double) cur->nodesetval->nodeNr));
8375     } else {
8376         if ((cur->nodesetval->nodeNr != 1) ||
8377             (cur->nodesetval->nodeTab == NULL)) {
8378             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8379         } else {
8380             xmlNodePtr tmp;
8381             int i = 0;
8382
8383             tmp = cur->nodesetval->nodeTab[0];
8384             if (tmp != NULL) {
8385                 tmp = tmp->children;
8386                 while (tmp != NULL) {
8387                     tmp = tmp->next;
8388                     i++;
8389                 }
8390             }
8391             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8392         }
8393     }
8394     xmlXPathReleaseObject(ctxt->context, cur);
8395 }
8396
8397 /**
8398  * xmlXPathGetElementsByIds:
8399  * @doc:  the document
8400  * @ids:  a whitespace separated list of IDs
8401  *
8402  * Selects elements by their unique ID.
8403  *
8404  * Returns a node-set of selected elements.
8405  */
8406 static xmlNodeSetPtr
8407 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8408     xmlNodeSetPtr ret;
8409     const xmlChar *cur = ids;
8410     xmlChar *ID;
8411     xmlAttrPtr attr;
8412     xmlNodePtr elem = NULL;
8413
8414     if (ids == NULL) return(NULL);
8415
8416     ret = xmlXPathNodeSetCreate(NULL);
8417
8418     while (IS_BLANK_CH(*cur)) cur++;
8419     while (*cur != 0) {
8420         while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8421             cur++;
8422
8423         ID = xmlStrndup(ids, cur - ids);
8424         if (ID != NULL) {
8425             /*
8426              * We used to check the fact that the value passed
8427              * was an NCName, but this generated much troubles for
8428              * me and Aleksey Sanin, people blatantly violated that
8429              * constaint, like Visa3D spec.
8430              * if (xmlValidateNCName(ID, 1) == 0)
8431              */
8432             attr = xmlGetID(doc, ID);
8433             if (attr != NULL) {
8434                 if (attr->type == XML_ATTRIBUTE_NODE)
8435                     elem = attr->parent;
8436                 else if (attr->type == XML_ELEMENT_NODE)
8437                     elem = (xmlNodePtr) attr;
8438                 else
8439                     elem = NULL;
8440                 if (elem != NULL)
8441                     xmlXPathNodeSetAdd(ret, elem);
8442             }
8443             xmlFree(ID);
8444         }
8445
8446         while (IS_BLANK_CH(*cur)) cur++;
8447         ids = cur;
8448     }
8449     return(ret);
8450 }
8451
8452 /**
8453  * xmlXPathIdFunction:
8454  * @ctxt:  the XPath Parser context
8455  * @nargs:  the number of arguments
8456  *
8457  * Implement the id() XPath function
8458  *    node-set id(object)
8459  * The id function selects elements by their unique ID
8460  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8461  * then the result is the union of the result of applying id to the
8462  * string value of each of the nodes in the argument node-set. When the
8463  * argument to id is of any other type, the argument is converted to a
8464  * string as if by a call to the string function; the string is split
8465  * into a whitespace-separated list of tokens (whitespace is any sequence
8466  * of characters matching the production S); the result is a node-set
8467  * containing the elements in the same document as the context node that
8468  * have a unique ID equal to any of the tokens in the list.
8469  */
8470 void
8471 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8472     xmlChar *tokens;
8473     xmlNodeSetPtr ret;
8474     xmlXPathObjectPtr obj;
8475
8476     CHECK_ARITY(1);
8477     obj = valuePop(ctxt);
8478     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8479     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8480         xmlNodeSetPtr ns;
8481         int i;
8482
8483         ret = xmlXPathNodeSetCreate(NULL);
8484
8485         if (obj->nodesetval != NULL) {
8486             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8487                 tokens =
8488                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8489                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8490                 ret = xmlXPathNodeSetMerge(ret, ns);
8491                 xmlXPathFreeNodeSet(ns);
8492                 if (tokens != NULL)
8493                     xmlFree(tokens);
8494             }
8495         }
8496         xmlXPathReleaseObject(ctxt->context, obj);
8497         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8498         return;
8499     }
8500     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8501     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8502     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));    
8503     xmlXPathReleaseObject(ctxt->context, obj);
8504     return;
8505 }
8506
8507 /**
8508  * xmlXPathLocalNameFunction:
8509  * @ctxt:  the XPath Parser context
8510  * @nargs:  the number of arguments
8511  *
8512  * Implement the local-name() XPath function
8513  *    string local-name(node-set?)
8514  * The local-name function returns a string containing the local part
8515  * of the name of the node in the argument node-set that is first in
8516  * document order. If the node-set is empty or the first node has no
8517  * name, an empty string is returned. If the argument is omitted it
8518  * defaults to the context node.
8519  */
8520 void
8521 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522     xmlXPathObjectPtr cur;
8523
8524     if (ctxt == NULL) return;
8525
8526     if (nargs == 0) {
8527         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8528             ctxt->context->node));
8529         nargs = 1;
8530     }
8531
8532     CHECK_ARITY(1);
8533     if ((ctxt->value == NULL) || 
8534         ((ctxt->value->type != XPATH_NODESET) &&
8535          (ctxt->value->type != XPATH_XSLT_TREE)))
8536         XP_ERROR(XPATH_INVALID_TYPE);
8537     cur = valuePop(ctxt);
8538
8539     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8540         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8541     } else {
8542         int i = 0; /* Should be first in document order !!!!! */
8543         switch (cur->nodesetval->nodeTab[i]->type) {
8544         case XML_ELEMENT_NODE:
8545         case XML_ATTRIBUTE_NODE:
8546         case XML_PI_NODE:
8547             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8548                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8549             else
8550                 valuePush(ctxt,
8551                       xmlXPathCacheNewString(ctxt->context,
8552                         cur->nodesetval->nodeTab[i]->name));
8553             break;
8554         case XML_NAMESPACE_DECL:
8555             valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8556                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8557             break;
8558         default:
8559             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8560         }
8561     }
8562     xmlXPathReleaseObject(ctxt->context, cur);
8563 }
8564
8565 /**
8566  * xmlXPathNamespaceURIFunction:
8567  * @ctxt:  the XPath Parser context
8568  * @nargs:  the number of arguments
8569  *
8570  * Implement the namespace-uri() XPath function
8571  *    string namespace-uri(node-set?)
8572  * The namespace-uri function returns a string containing the
8573  * namespace URI of the expanded name of the node in the argument
8574  * node-set that is first in document order. If the node-set is empty,
8575  * the first node has no name, or the expanded name has no namespace
8576  * URI, an empty string is returned. If the argument is omitted it
8577  * defaults to the context node.
8578  */
8579 void
8580 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8581     xmlXPathObjectPtr cur;
8582
8583     if (ctxt == NULL) return;
8584
8585     if (nargs == 0) {
8586         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8587             ctxt->context->node));
8588         nargs = 1;
8589     }
8590     CHECK_ARITY(1);
8591     if ((ctxt->value == NULL) || 
8592         ((ctxt->value->type != XPATH_NODESET) &&
8593          (ctxt->value->type != XPATH_XSLT_TREE)))
8594         XP_ERROR(XPATH_INVALID_TYPE);
8595     cur = valuePop(ctxt);
8596
8597     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8598         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8599     } else {
8600         int i = 0; /* Should be first in document order !!!!! */
8601         switch (cur->nodesetval->nodeTab[i]->type) {
8602         case XML_ELEMENT_NODE:
8603         case XML_ATTRIBUTE_NODE:
8604             if (cur->nodesetval->nodeTab[i]->ns == NULL)
8605                 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8606             else
8607                 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8608                           cur->nodesetval->nodeTab[i]->ns->href));
8609             break;
8610         default:
8611             valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8612         }
8613     }
8614     xmlXPathReleaseObject(ctxt->context, cur);
8615 }
8616
8617 /**
8618  * xmlXPathNameFunction:
8619  * @ctxt:  the XPath Parser context
8620  * @nargs:  the number of arguments
8621  *
8622  * Implement the name() XPath function
8623  *    string name(node-set?)
8624  * The name function returns a string containing a QName representing
8625  * the name of the node in the argument node-set that is first in document
8626  * order. The QName must represent the name with respect to the namespace
8627  * declarations in effect on the node whose name is being represented.
8628  * Typically, this will be the form in which the name occurred in the XML
8629  * source. This need not be the case if there are namespace declarations
8630  * in effect on the node that associate multiple prefixes with the same
8631  * namespace. However, an implementation may include information about
8632  * the original prefix in its representation of nodes; in this case, an
8633  * implementation can ensure that the returned string is always the same
8634  * as the QName used in the XML source. If the argument it omitted it
8635  * defaults to the context node.
8636  * Libxml keep the original prefix so the "real qualified name" used is
8637  * returned.
8638  */
8639 static void
8640 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8641 {
8642     xmlXPathObjectPtr cur;
8643
8644     if (nargs == 0) {
8645         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8646             ctxt->context->node));
8647         nargs = 1;
8648     }
8649
8650     CHECK_ARITY(1);
8651     if ((ctxt->value == NULL) ||
8652         ((ctxt->value->type != XPATH_NODESET) &&
8653          (ctxt->value->type != XPATH_XSLT_TREE)))
8654         XP_ERROR(XPATH_INVALID_TYPE);
8655     cur = valuePop(ctxt);
8656
8657     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8658         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8659     } else {
8660         int i = 0;              /* Should be first in document order !!!!! */
8661
8662         switch (cur->nodesetval->nodeTab[i]->type) {
8663             case XML_ELEMENT_NODE:
8664             case XML_ATTRIBUTE_NODE:
8665                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8666                     valuePush(ctxt,
8667                         xmlXPathCacheNewCString(ctxt->context, ""));
8668                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8669                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8670                     valuePush(ctxt,
8671                         xmlXPathCacheNewString(ctxt->context,
8672                             cur->nodesetval->nodeTab[i]->name));
8673                 } else {
8674                     xmlChar *fullname;
8675                     
8676                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8677                                      cur->nodesetval->nodeTab[i]->ns->prefix,
8678                                      NULL, 0);
8679                     if (fullname == cur->nodesetval->nodeTab[i]->name)
8680                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8681                     if (fullname == NULL) {
8682                         XP_ERROR(XPATH_MEMORY_ERROR);
8683                     }
8684                     valuePush(ctxt, xmlXPathCacheWrapString(
8685                         ctxt->context, fullname));
8686                 }
8687                 break;
8688             default:
8689                 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690                     cur->nodesetval->nodeTab[i]));
8691                 xmlXPathLocalNameFunction(ctxt, 1);
8692         }
8693     }
8694     xmlXPathReleaseObject(ctxt->context, cur);
8695 }
8696
8697
8698 /**
8699  * xmlXPathStringFunction:
8700  * @ctxt:  the XPath Parser context
8701  * @nargs:  the number of arguments
8702  *
8703  * Implement the string() XPath function
8704  *    string string(object?)
8705  * The string function converts an object to a string as follows:
8706  *    - A node-set is converted to a string by returning the value of
8707  *      the node in the node-set that is first in document order.
8708  *      If the node-set is empty, an empty string is returned.
8709  *    - A number is converted to a string as follows
8710  *      + NaN is converted to the string NaN 
8711  *      + positive zero is converted to the string 0 
8712  *      + negative zero is converted to the string 0 
8713  *      + positive infinity is converted to the string Infinity 
8714  *      + negative infinity is converted to the string -Infinity 
8715  *      + if the number is an integer, the number is represented in
8716  *        decimal form as a Number with no decimal point and no leading
8717  *        zeros, preceded by a minus sign (-) if the number is negative
8718  *      + otherwise, the number is represented in decimal form as a
8719  *        Number including a decimal point with at least one digit
8720  *        before the decimal point and at least one digit after the
8721  *        decimal point, preceded by a minus sign (-) if the number
8722  *        is negative; there must be no leading zeros before the decimal
8723  *        point apart possibly from the one required digit immediately
8724  *        before the decimal point; beyond the one required digit
8725  *        after the decimal point there must be as many, but only as
8726  *        many, more digits as are needed to uniquely distinguish the
8727  *        number from all other IEEE 754 numeric values.
8728  *    - The boolean false value is converted to the string false.
8729  *      The boolean true value is converted to the string true.
8730  *
8731  * If the argument is omitted, it defaults to a node-set with the
8732  * context node as its only member.
8733  */
8734 void
8735 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736     xmlXPathObjectPtr cur;
8737
8738     if (ctxt == NULL) return;
8739     if (nargs == 0) {
8740     valuePush(ctxt,
8741         xmlXPathCacheWrapString(ctxt->context,
8742             xmlXPathCastNodeToString(ctxt->context->node)));
8743         return;
8744     }
8745
8746     CHECK_ARITY(1);
8747     cur = valuePop(ctxt);
8748     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8749     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8750 }
8751
8752 /**
8753  * xmlXPathStringLengthFunction:
8754  * @ctxt:  the XPath Parser context
8755  * @nargs:  the number of arguments
8756  *
8757  * Implement the string-length() XPath function
8758  *    number string-length(string?)
8759  * The string-length returns the number of characters in the string
8760  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8761  * the context node converted to a string, in other words the value
8762  * of the context node.
8763  */
8764 void
8765 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8766     xmlXPathObjectPtr cur;
8767
8768     if (nargs == 0) {
8769         if ((ctxt == NULL) || (ctxt->context == NULL))
8770             return;
8771         if (ctxt->context->node == NULL) {
8772             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8773         } else {
8774             xmlChar *content;
8775
8776             content = xmlXPathCastNodeToString(ctxt->context->node);
8777             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8778                 xmlUTF8Strlen(content)));
8779             xmlFree(content);
8780         }
8781         return;
8782     }
8783     CHECK_ARITY(1);
8784     CAST_TO_STRING;
8785     CHECK_TYPE(XPATH_STRING);
8786     cur = valuePop(ctxt);
8787     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8788         xmlUTF8Strlen(cur->stringval)));    
8789     xmlXPathReleaseObject(ctxt->context, cur);
8790 }
8791
8792 /**
8793  * xmlXPathConcatFunction:
8794  * @ctxt:  the XPath Parser context
8795  * @nargs:  the number of arguments
8796  *
8797  * Implement the concat() XPath function
8798  *    string concat(string, string, string*)
8799  * The concat function returns the concatenation of its arguments.
8800  */
8801 void
8802 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8803     xmlXPathObjectPtr cur, newobj;
8804     xmlChar *tmp;
8805
8806     if (ctxt == NULL) return;
8807     if (nargs < 2) {
8808         CHECK_ARITY(2);
8809     }
8810
8811     CAST_TO_STRING;
8812     cur = valuePop(ctxt);
8813     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8814         xmlXPathReleaseObject(ctxt->context, cur);
8815         return;
8816     }
8817     nargs--;
8818
8819     while (nargs > 0) {
8820         CAST_TO_STRING;
8821         newobj = valuePop(ctxt);
8822         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8823             xmlXPathReleaseObject(ctxt->context, newobj);
8824             xmlXPathReleaseObject(ctxt->context, cur);
8825             XP_ERROR(XPATH_INVALID_TYPE);
8826         }
8827         tmp = xmlStrcat(newobj->stringval, cur->stringval);
8828         newobj->stringval = cur->stringval;
8829         cur->stringval = tmp;
8830         xmlXPathReleaseObject(ctxt->context, newobj);
8831         nargs--;
8832     }
8833     valuePush(ctxt, cur);
8834 }
8835
8836 /**
8837  * xmlXPathContainsFunction:
8838  * @ctxt:  the XPath Parser context
8839  * @nargs:  the number of arguments
8840  *
8841  * Implement the contains() XPath function
8842  *    boolean contains(string, string)
8843  * The contains function returns true if the first argument string
8844  * contains the second argument string, and otherwise returns false.
8845  */
8846 void
8847 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8848     xmlXPathObjectPtr hay, needle;
8849
8850     CHECK_ARITY(2);
8851     CAST_TO_STRING;
8852     CHECK_TYPE(XPATH_STRING);
8853     needle = valuePop(ctxt);
8854     CAST_TO_STRING;
8855     hay = valuePop(ctxt);
8856
8857     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8858         xmlXPathReleaseObject(ctxt->context, hay);
8859         xmlXPathReleaseObject(ctxt->context, needle);
8860         XP_ERROR(XPATH_INVALID_TYPE);
8861     }
8862     if (xmlStrstr(hay->stringval, needle->stringval))
8863         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8864     else
8865         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8866     xmlXPathReleaseObject(ctxt->context, hay);
8867     xmlXPathReleaseObject(ctxt->context, needle);
8868 }
8869
8870 /**
8871  * xmlXPathStartsWithFunction:
8872  * @ctxt:  the XPath Parser context
8873  * @nargs:  the number of arguments
8874  *
8875  * Implement the starts-with() XPath function
8876  *    boolean starts-with(string, string)
8877  * The starts-with function returns true if the first argument string
8878  * starts with the second argument string, and otherwise returns false.
8879  */
8880 void
8881 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8882     xmlXPathObjectPtr hay, needle;
8883     int n;
8884
8885     CHECK_ARITY(2);
8886     CAST_TO_STRING;
8887     CHECK_TYPE(XPATH_STRING);
8888     needle = valuePop(ctxt);
8889     CAST_TO_STRING;
8890     hay = valuePop(ctxt);
8891
8892     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8893         xmlXPathReleaseObject(ctxt->context, hay);
8894         xmlXPathReleaseObject(ctxt->context, needle);
8895         XP_ERROR(XPATH_INVALID_TYPE);
8896     }
8897     n = xmlStrlen(needle->stringval);
8898     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8899         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8900     else
8901         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8902     xmlXPathReleaseObject(ctxt->context, hay);
8903     xmlXPathReleaseObject(ctxt->context, needle);
8904 }
8905
8906 /**
8907  * xmlXPathSubstringFunction:
8908  * @ctxt:  the XPath Parser context
8909  * @nargs:  the number of arguments
8910  *
8911  * Implement the substring() XPath function
8912  *    string substring(string, number, number?)
8913  * The substring function returns the substring of the first argument
8914  * starting at the position specified in the second argument with
8915  * length specified in the third argument. For example,
8916  * substring("12345",2,3) returns "234". If the third argument is not
8917  * specified, it returns the substring starting at the position specified
8918  * in the second argument and continuing to the end of the string. For
8919  * example, substring("12345",2) returns "2345".  More precisely, each
8920  * character in the string (see [3.6 Strings]) is considered to have a
8921  * numeric position: the position of the first character is 1, the position
8922  * of the second character is 2 and so on. The returned substring contains
8923  * those characters for which the position of the character is greater than
8924  * or equal to the second argument and, if the third argument is specified,
8925  * less than the sum of the second and third arguments; the comparisons
8926  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8927  *  - substring("12345", 1.5, 2.6) returns "234" 
8928  *  - substring("12345", 0, 3) returns "12" 
8929  *  - substring("12345", 0 div 0, 3) returns "" 
8930  *  - substring("12345", 1, 0 div 0) returns "" 
8931  *  - substring("12345", -42, 1 div 0) returns "12345" 
8932  *  - substring("12345", -1 div 0, 1 div 0) returns "" 
8933  */
8934 void
8935 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936     xmlXPathObjectPtr str, start, len;
8937     double le=0, in;
8938     int i, l, m;
8939     xmlChar *ret;
8940
8941     if (nargs < 2) {
8942         CHECK_ARITY(2);
8943     }
8944     if (nargs > 3) {
8945         CHECK_ARITY(3);
8946     }
8947     /*
8948      * take care of possible last (position) argument
8949     */
8950     if (nargs == 3) {
8951         CAST_TO_NUMBER;
8952         CHECK_TYPE(XPATH_NUMBER);
8953         len = valuePop(ctxt);
8954         le = len->floatval;
8955         xmlXPathReleaseObject(ctxt->context, len);
8956     }
8957
8958     CAST_TO_NUMBER;
8959     CHECK_TYPE(XPATH_NUMBER);
8960     start = valuePop(ctxt);
8961     in = start->floatval;
8962     xmlXPathReleaseObject(ctxt->context, start);
8963     CAST_TO_STRING;
8964     CHECK_TYPE(XPATH_STRING);
8965     str = valuePop(ctxt);
8966     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8967
8968     /*
8969      * If last pos not present, calculate last position
8970     */
8971     if (nargs != 3) {
8972         le = (double)m;
8973         if (in < 1.0) 
8974             in = 1.0;
8975     }
8976
8977     /* Need to check for the special cases where either 
8978      * the index is NaN, the length is NaN, or both
8979      * arguments are infinity (relying on Inf + -Inf = NaN)
8980      */
8981     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
8982         /*
8983          * To meet the requirements of the spec, the arguments
8984          * must be converted to integer format before 
8985          * initial index calculations are done
8986          *
8987          * First we go to integer form, rounding up
8988          * and checking for special cases
8989          */
8990         i = (int) in;
8991         if (((double)i)+0.5 <= in) i++;
8992
8993         if (xmlXPathIsInf(le) == 1) {
8994             l = m;
8995             if (i < 1)
8996                 i = 1;
8997         }
8998         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8999             l = 0;
9000         else {
9001             l = (int) le;
9002             if (((double)l)+0.5 <= le) l++;
9003         }
9004
9005         /* Now we normalize inidices */
9006         i -= 1;
9007         l += i;
9008         if (i < 0)
9009             i = 0;
9010         if (l > m)
9011             l = m;
9012
9013         /* number of chars to copy */
9014         l -= i;
9015
9016         ret = xmlUTF8Strsub(str->stringval, i, l);
9017     }
9018     else {
9019         ret = NULL;
9020     }
9021     if (ret == NULL)
9022         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9023     else {
9024         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9025         xmlFree(ret);
9026     }
9027     xmlXPathReleaseObject(ctxt->context, str);
9028 }
9029
9030 /**
9031  * xmlXPathSubstringBeforeFunction:
9032  * @ctxt:  the XPath Parser context
9033  * @nargs:  the number of arguments
9034  *
9035  * Implement the substring-before() XPath function
9036  *    string substring-before(string, string)
9037  * The substring-before function returns the substring of the first
9038  * argument string that precedes the first occurrence of the second
9039  * argument string in the first argument string, or the empty string
9040  * if the first argument string does not contain the second argument
9041  * string. For example, substring-before("1999/04/01","/") returns 1999.
9042  */
9043 void
9044 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045   xmlXPathObjectPtr str;
9046   xmlXPathObjectPtr find;
9047   xmlBufferPtr target;
9048   const xmlChar *point;
9049   int offset;
9050   
9051   CHECK_ARITY(2);
9052   CAST_TO_STRING;
9053   find = valuePop(ctxt);
9054   CAST_TO_STRING;
9055   str = valuePop(ctxt);
9056   
9057   target = xmlBufferCreate();
9058   if (target) {
9059     point = xmlStrstr(str->stringval, find->stringval);
9060     if (point) {
9061       offset = (int)(point - str->stringval);
9062       xmlBufferAdd(target, str->stringval, offset);
9063     }
9064     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9065         xmlBufferContent(target)));
9066     xmlBufferFree(target);
9067   }
9068   xmlXPathReleaseObject(ctxt->context, str);
9069   xmlXPathReleaseObject(ctxt->context, find);
9070 }
9071
9072 /**
9073  * xmlXPathSubstringAfterFunction:
9074  * @ctxt:  the XPath Parser context
9075  * @nargs:  the number of arguments
9076  *
9077  * Implement the substring-after() XPath function
9078  *    string substring-after(string, string)
9079  * The substring-after function returns the substring of the first
9080  * argument string that follows the first occurrence of the second
9081  * argument string in the first argument string, or the empty stringi
9082  * if the first argument string does not contain the second argument
9083  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9084  * and substring-after("1999/04/01","19") returns 99/04/01.
9085  */
9086 void
9087 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9088   xmlXPathObjectPtr str;
9089   xmlXPathObjectPtr find;
9090   xmlBufferPtr target;
9091   const xmlChar *point;
9092   int offset;
9093   
9094   CHECK_ARITY(2);
9095   CAST_TO_STRING;
9096   find = valuePop(ctxt);
9097   CAST_TO_STRING;
9098   str = valuePop(ctxt);
9099   
9100   target = xmlBufferCreate();
9101   if (target) {
9102     point = xmlStrstr(str->stringval, find->stringval);
9103     if (point) {
9104       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9105       xmlBufferAdd(target, &str->stringval[offset],
9106                    xmlStrlen(str->stringval) - offset);
9107     }
9108     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109         xmlBufferContent(target)));    
9110     xmlBufferFree(target);
9111   }
9112   xmlXPathReleaseObject(ctxt->context, str);
9113   xmlXPathReleaseObject(ctxt->context, find);
9114 }
9115
9116 /**
9117  * xmlXPathNormalizeFunction:
9118  * @ctxt:  the XPath Parser context
9119  * @nargs:  the number of arguments
9120  *
9121  * Implement the normalize-space() XPath function
9122  *    string normalize-space(string?)
9123  * The normalize-space function returns the argument string with white
9124  * space normalized by stripping leading and trailing whitespace
9125  * and replacing sequences of whitespace characters by a single
9126  * space. Whitespace characters are the same allowed by the S production
9127  * in XML. If the argument is omitted, it defaults to the context
9128  * node converted to a string, in other words the value of the context node.
9129  */
9130 void
9131 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132   xmlXPathObjectPtr obj = NULL;
9133   xmlChar *source = NULL;
9134   xmlBufferPtr target;
9135   xmlChar blank;
9136   
9137   if (ctxt == NULL) return;
9138   if (nargs == 0) {
9139     /* Use current context node */
9140       valuePush(ctxt,
9141           xmlXPathCacheWrapString(ctxt->context,
9142             xmlXPathCastNodeToString(ctxt->context->node)));
9143     nargs = 1;
9144   }
9145
9146   CHECK_ARITY(1);
9147   CAST_TO_STRING;
9148   CHECK_TYPE(XPATH_STRING);
9149   obj = valuePop(ctxt);
9150   source = obj->stringval;
9151
9152   target = xmlBufferCreate();
9153   if (target && source) {
9154     
9155     /* Skip leading whitespaces */
9156     while (IS_BLANK_CH(*source))
9157       source++;
9158   
9159     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9160     blank = 0;
9161     while (*source) {
9162       if (IS_BLANK_CH(*source)) {
9163         blank = 0x20;
9164       } else {
9165         if (blank) {
9166           xmlBufferAdd(target, &blank, 1);
9167           blank = 0;
9168         }
9169         xmlBufferAdd(target, source, 1);
9170       }
9171       source++;
9172     }
9173     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9174         xmlBufferContent(target)));
9175     xmlBufferFree(target);
9176   }
9177   xmlXPathReleaseObject(ctxt->context, obj);
9178 }
9179
9180 /**
9181  * xmlXPathTranslateFunction:
9182  * @ctxt:  the XPath Parser context
9183  * @nargs:  the number of arguments
9184  *
9185  * Implement the translate() XPath function
9186  *    string translate(string, string, string)
9187  * The translate function returns the first argument string with
9188  * occurrences of characters in the second argument string replaced
9189  * by the character at the corresponding position in the third argument
9190  * string. For example, translate("bar","abc","ABC") returns the string
9191  * BAr. If there is a character in the second argument string with no
9192  * character at a corresponding position in the third argument string
9193  * (because the second argument string is longer than the third argument
9194  * string), then occurrences of that character in the first argument
9195  * string are removed. For example, translate("--aaa--","abc-","ABC")
9196  * returns "AAA". If a character occurs more than once in second
9197  * argument string, then the first occurrence determines the replacement
9198  * character. If the third argument string is longer than the second
9199  * argument string, then excess characters are ignored.
9200  */
9201 void
9202 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9203     xmlXPathObjectPtr str;
9204     xmlXPathObjectPtr from;
9205     xmlXPathObjectPtr to;
9206     xmlBufferPtr target;
9207     int offset, max;
9208     xmlChar ch;
9209     const xmlChar *point;
9210     xmlChar *cptr;
9211
9212     CHECK_ARITY(3);
9213
9214     CAST_TO_STRING;
9215     to = valuePop(ctxt);
9216     CAST_TO_STRING;
9217     from = valuePop(ctxt);
9218     CAST_TO_STRING;
9219     str = valuePop(ctxt);
9220
9221     target = xmlBufferCreate();
9222     if (target) {
9223         max = xmlUTF8Strlen(to->stringval);
9224         for (cptr = str->stringval; (ch=*cptr); ) {
9225             offset = xmlUTF8Strloc(from->stringval, cptr);
9226             if (offset >= 0) {
9227                 if (offset < max) {
9228                     point = xmlUTF8Strpos(to->stringval, offset);
9229                     if (point)
9230                         xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9231                 }
9232             } else
9233                 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9234
9235             /* Step to next character in input */
9236             cptr++;
9237             if ( ch & 0x80 ) {
9238                 /* if not simple ascii, verify proper format */
9239                 if ( (ch & 0xc0) != 0xc0 ) {
9240                     xmlGenericError(xmlGenericErrorContext,
9241                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9242                     break;
9243                 }
9244                 /* then skip over remaining bytes for this char */
9245                 while ( (ch <<= 1) & 0x80 )
9246                     if ( (*cptr++ & 0xc0) != 0x80 ) {
9247                         xmlGenericError(xmlGenericErrorContext,
9248                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9249                         break;
9250                     }
9251                 if (ch & 0x80) /* must have had error encountered */
9252                     break;
9253             }
9254         }
9255     }
9256     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9257         xmlBufferContent(target)));
9258     xmlBufferFree(target);
9259     xmlXPathReleaseObject(ctxt->context, str);
9260     xmlXPathReleaseObject(ctxt->context, from);
9261     xmlXPathReleaseObject(ctxt->context, to);
9262 }
9263
9264 /**
9265  * xmlXPathBooleanFunction:
9266  * @ctxt:  the XPath Parser context
9267  * @nargs:  the number of arguments
9268  *
9269  * Implement the boolean() XPath function
9270  *    boolean boolean(object)
9271  * The boolean function converts its argument to a boolean as follows:
9272  *    - a number is true if and only if it is neither positive or
9273  *      negative zero nor NaN
9274  *    - a node-set is true if and only if it is non-empty
9275  *    - a string is true if and only if its length is non-zero
9276  */
9277 void
9278 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279     xmlXPathObjectPtr cur;
9280
9281     CHECK_ARITY(1);
9282     cur = valuePop(ctxt);
9283     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9284     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9285     valuePush(ctxt, cur);
9286 }
9287
9288 /**
9289  * xmlXPathNotFunction:
9290  * @ctxt:  the XPath Parser context
9291  * @nargs:  the number of arguments
9292  *
9293  * Implement the not() XPath function
9294  *    boolean not(boolean)
9295  * The not function returns true if its argument is false,
9296  * and false otherwise.
9297  */
9298 void
9299 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9300     CHECK_ARITY(1);
9301     CAST_TO_BOOLEAN;
9302     CHECK_TYPE(XPATH_BOOLEAN);
9303     ctxt->value->boolval = ! ctxt->value->boolval;
9304 }
9305
9306 /**
9307  * xmlXPathTrueFunction:
9308  * @ctxt:  the XPath Parser context
9309  * @nargs:  the number of arguments
9310  *
9311  * Implement the true() XPath function
9312  *    boolean true()
9313  */
9314 void
9315 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316     CHECK_ARITY(0);
9317     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9318 }
9319
9320 /**
9321  * xmlXPathFalseFunction:
9322  * @ctxt:  the XPath Parser context
9323  * @nargs:  the number of arguments
9324  *
9325  * Implement the false() XPath function
9326  *    boolean false()
9327  */
9328 void
9329 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330     CHECK_ARITY(0);
9331     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9332 }
9333
9334 /**
9335  * xmlXPathLangFunction:
9336  * @ctxt:  the XPath Parser context
9337  * @nargs:  the number of arguments
9338  *
9339  * Implement the lang() XPath function
9340  *    boolean lang(string)
9341  * The lang function returns true or false depending on whether the
9342  * language of the context node as specified by xml:lang attributes
9343  * is the same as or is a sublanguage of the language specified by
9344  * the argument string. The language of the context node is determined
9345  * by the value of the xml:lang attribute on the context node, or, if
9346  * the context node has no xml:lang attribute, by the value of the
9347  * xml:lang attribute on the nearest ancestor of the context node that
9348  * has an xml:lang attribute. If there is no such attribute, then lang
9349  * returns false. If there is such an attribute, then lang returns
9350  * true if the attribute value is equal to the argument ignoring case,
9351  * or if there is some suffix starting with - such that the attribute
9352  * value is equal to the argument ignoring that suffix of the attribute
9353  * value and ignoring case.
9354  */
9355 void
9356 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357     xmlXPathObjectPtr val = NULL;
9358     const xmlChar *theLang = NULL;
9359     const xmlChar *lang;
9360     int ret = 0;
9361     int i;
9362
9363     CHECK_ARITY(1);
9364     CAST_TO_STRING;
9365     CHECK_TYPE(XPATH_STRING);
9366     val = valuePop(ctxt);
9367     lang = val->stringval;
9368     theLang = xmlNodeGetLang(ctxt->context->node);
9369     if ((theLang != NULL) && (lang != NULL)) {
9370         for (i = 0;lang[i] != 0;i++)
9371             if (toupper(lang[i]) != toupper(theLang[i]))
9372                 goto not_equal;
9373         if ((theLang[i] == 0) || (theLang[i] == '-'))
9374             ret = 1;
9375     }
9376 not_equal:
9377     if (theLang != NULL)
9378         xmlFree((void *)theLang);
9379
9380     xmlXPathReleaseObject(ctxt->context, val);
9381     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9382 }
9383
9384 /**
9385  * xmlXPathNumberFunction:
9386  * @ctxt:  the XPath Parser context
9387  * @nargs:  the number of arguments
9388  *
9389  * Implement the number() XPath function
9390  *    number number(object?)
9391  */
9392 void
9393 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9394     xmlXPathObjectPtr cur;
9395     double res;
9396
9397     if (ctxt == NULL) return;
9398     if (nargs == 0) {
9399         if (ctxt->context->node == NULL) {
9400             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9401         } else {
9402             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9403
9404             res = xmlXPathStringEvalNumber(content);
9405             valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9406             xmlFree(content);
9407         }
9408         return;
9409     }
9410
9411     CHECK_ARITY(1);
9412     cur = valuePop(ctxt);
9413     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9414 }
9415
9416 /**
9417  * xmlXPathSumFunction:
9418  * @ctxt:  the XPath Parser context
9419  * @nargs:  the number of arguments
9420  *
9421  * Implement the sum() XPath function
9422  *    number sum(node-set)
9423  * The sum function returns the sum of the values of the nodes in
9424  * the argument node-set.
9425  */
9426 void
9427 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9428     xmlXPathObjectPtr cur;
9429     int i;
9430     double res = 0.0;
9431
9432     CHECK_ARITY(1);
9433     if ((ctxt->value == NULL) || 
9434         ((ctxt->value->type != XPATH_NODESET) &&
9435          (ctxt->value->type != XPATH_XSLT_TREE)))
9436         XP_ERROR(XPATH_INVALID_TYPE);
9437     cur = valuePop(ctxt);
9438
9439     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9440         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9441             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9442         }
9443     }
9444     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9445     xmlXPathReleaseObject(ctxt->context, cur);
9446 }
9447
9448 /*
9449  * To assure working code on multiple platforms, we want to only depend
9450  * upon the characteristic truncation of converting a floating point value
9451  * to an integer.  Unfortunately, because of the different storage sizes
9452  * of our internal floating point value (double) and integer (int), we
9453  * can't directly convert (see bug 301162).  This macro is a messy
9454  * 'workaround'
9455  */
9456 #define XTRUNC(f, v)            \
9457     f = fmod((v), INT_MAX);     \
9458     f = (v) - (f) + (double)((int)(f));
9459
9460 /**
9461  * xmlXPathFloorFunction:
9462  * @ctxt:  the XPath Parser context
9463  * @nargs:  the number of arguments
9464  *
9465  * Implement the floor() XPath function
9466  *    number floor(number)
9467  * The floor function returns the largest (closest to positive infinity)
9468  * number that is not greater than the argument and that is an integer.
9469  */
9470 void
9471 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472     double f;
9473
9474     CHECK_ARITY(1);
9475     CAST_TO_NUMBER;
9476     CHECK_TYPE(XPATH_NUMBER);
9477
9478     XTRUNC(f, ctxt->value->floatval);
9479     if (f != ctxt->value->floatval) {
9480         if (ctxt->value->floatval > 0)
9481             ctxt->value->floatval = f;
9482         else
9483             ctxt->value->floatval = f - 1;
9484     }
9485 }
9486
9487 /**
9488  * xmlXPathCeilingFunction:
9489  * @ctxt:  the XPath Parser context
9490  * @nargs:  the number of arguments
9491  *
9492  * Implement the ceiling() XPath function
9493  *    number ceiling(number)
9494  * The ceiling function returns the smallest (closest to negative infinity)
9495  * number that is not less than the argument and that is an integer.
9496  */
9497 void
9498 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9499     double f;
9500
9501     CHECK_ARITY(1);
9502     CAST_TO_NUMBER;
9503     CHECK_TYPE(XPATH_NUMBER);
9504
9505 #if 0
9506     ctxt->value->floatval = ceil(ctxt->value->floatval);
9507 #else
9508     XTRUNC(f, ctxt->value->floatval);
9509     if (f != ctxt->value->floatval) {
9510         if (ctxt->value->floatval > 0)
9511             ctxt->value->floatval = f + 1;
9512         else {
9513             if (ctxt->value->floatval < 0 && f == 0)
9514                 ctxt->value->floatval = xmlXPathNZERO;
9515             else
9516                 ctxt->value->floatval = f;
9517         }
9518
9519     }
9520 #endif
9521 }
9522
9523 /**
9524  * xmlXPathRoundFunction:
9525  * @ctxt:  the XPath Parser context
9526  * @nargs:  the number of arguments
9527  *
9528  * Implement the round() XPath function
9529  *    number round(number)
9530  * The round function returns the number that is closest to the
9531  * argument and that is an integer. If there are two such numbers,
9532  * then the one that is even is returned.
9533  */
9534 void
9535 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536     double f;
9537
9538     CHECK_ARITY(1);
9539     CAST_TO_NUMBER;
9540     CHECK_TYPE(XPATH_NUMBER);
9541
9542     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9543         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9544         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9545         (ctxt->value->floatval == 0.0))
9546         return;
9547
9548     XTRUNC(f, ctxt->value->floatval);
9549     if (ctxt->value->floatval < 0) {
9550         if (ctxt->value->floatval < f - 0.5)
9551             ctxt->value->floatval = f - 1;
9552         else 
9553             ctxt->value->floatval = f;
9554         if (ctxt->value->floatval == 0)
9555             ctxt->value->floatval = xmlXPathNZERO;
9556     } else {
9557         if (ctxt->value->floatval < f + 0.5)
9558             ctxt->value->floatval = f;
9559         else 
9560             ctxt->value->floatval = f + 1;
9561     }
9562 }
9563
9564 /************************************************************************
9565  *                                                                      *
9566  *                      The Parser                                      *
9567  *                                                                      *
9568  ************************************************************************/
9569
9570 /*
9571  * a few forward declarations since we use a recursive call based
9572  * implementation.
9573  */
9574 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9575 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9576 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9577 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9578 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9579                                           int qualified);
9580
9581 /**
9582  * xmlXPathCurrentChar:
9583  * @ctxt:  the XPath parser context
9584  * @cur:  pointer to the beginning of the char
9585  * @len:  pointer to the length of the char read
9586  *
9587  * The current char value, if using UTF-8 this may actually span multiple
9588  * bytes in the input buffer.
9589  *
9590  * Returns the current char value and its length
9591  */
9592
9593 static int
9594 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9595     unsigned char c;
9596     unsigned int val;
9597     const xmlChar *cur;
9598
9599     if (ctxt == NULL)
9600         return(0);
9601     cur = ctxt->cur;
9602
9603     /*
9604      * We are supposed to handle UTF8, check it's valid
9605      * From rfc2044: encoding of the Unicode values on UTF-8:
9606      *
9607      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9608      * 0000 0000-0000 007F   0xxxxxxx
9609      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9610      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
9611      *
9612      * Check for the 0x110000 limit too
9613      */
9614     c = *cur;
9615     if (c & 0x80) {
9616         if ((cur[1] & 0xc0) != 0x80)
9617             goto encoding_error;
9618         if ((c & 0xe0) == 0xe0) {
9619
9620             if ((cur[2] & 0xc0) != 0x80)
9621                 goto encoding_error;
9622             if ((c & 0xf0) == 0xf0) {
9623                 if (((c & 0xf8) != 0xf0) ||
9624                     ((cur[3] & 0xc0) != 0x80))
9625                     goto encoding_error;
9626                 /* 4-byte code */
9627                 *len = 4;
9628                 val = (cur[0] & 0x7) << 18;
9629                 val |= (cur[1] & 0x3f) << 12;
9630                 val |= (cur[2] & 0x3f) << 6;
9631                 val |= cur[3] & 0x3f;
9632             } else {
9633               /* 3-byte code */
9634                 *len = 3;
9635                 val = (cur[0] & 0xf) << 12;
9636                 val |= (cur[1] & 0x3f) << 6;
9637                 val |= cur[2] & 0x3f;
9638             }
9639         } else {
9640           /* 2-byte code */
9641             *len = 2;
9642             val = (cur[0] & 0x1f) << 6;
9643             val |= cur[1] & 0x3f;
9644         }
9645         if (!IS_CHAR(val)) {
9646             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9647         }    
9648         return(val);
9649     } else {
9650         /* 1-byte code */
9651         *len = 1;
9652         return((int) *cur);
9653     }
9654 encoding_error:
9655     /*
9656      * If we detect an UTF8 error that probably means that the
9657      * input encoding didn't get properly advertised in the
9658      * declaration header. Report the error and switch the encoding
9659      * to ISO-Latin-1 (if you don't like this policy, just declare the
9660      * encoding !)
9661      */
9662     *len = 0;
9663     XP_ERROR0(XPATH_ENCODING_ERROR);
9664 }
9665
9666 /**
9667  * xmlXPathParseNCName:
9668  * @ctxt:  the XPath Parser context
9669  *
9670  * parse an XML namespace non qualified name.
9671  *
9672  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9673  *
9674  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9675  *                       CombiningChar | Extender
9676  *
9677  * Returns the namespace name or NULL
9678  */
9679
9680 xmlChar *
9681 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9682     const xmlChar *in;
9683     xmlChar *ret;
9684     int count = 0;
9685
9686     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9687     /*
9688      * Accelerator for simple ASCII names
9689      */
9690     in = ctxt->cur;
9691     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9692         ((*in >= 0x41) && (*in <= 0x5A)) ||
9693         (*in == '_')) {
9694         in++;
9695         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9696                ((*in >= 0x41) && (*in <= 0x5A)) ||
9697                ((*in >= 0x30) && (*in <= 0x39)) ||
9698                (*in == '_') || (*in == '.') ||
9699                (*in == '-'))
9700             in++;
9701         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9702             (*in == '[') || (*in == ']') || (*in == ':') ||
9703             (*in == '@') || (*in == '*')) {
9704             count = in - ctxt->cur;
9705             if (count == 0)
9706                 return(NULL);
9707             ret = xmlStrndup(ctxt->cur, count);
9708             ctxt->cur = in;
9709             return(ret);
9710         }
9711     }
9712     return(xmlXPathParseNameComplex(ctxt, 0));
9713 }
9714
9715
9716 /**
9717  * xmlXPathParseQName:
9718  * @ctxt:  the XPath Parser context
9719  * @prefix:  a xmlChar ** 
9720  *
9721  * parse an XML qualified name
9722  *
9723  * [NS 5] QName ::= (Prefix ':')? LocalPart
9724  *
9725  * [NS 6] Prefix ::= NCName
9726  *
9727  * [NS 7] LocalPart ::= NCName
9728  *
9729  * Returns the function returns the local part, and prefix is updated
9730  *   to get the Prefix if any.
9731  */
9732
9733 static xmlChar *
9734 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9735     xmlChar *ret = NULL;
9736
9737     *prefix = NULL;
9738     ret = xmlXPathParseNCName(ctxt);
9739     if (CUR == ':') {
9740         *prefix = ret;
9741         NEXT;
9742         ret = xmlXPathParseNCName(ctxt);
9743     }
9744     return(ret);
9745 }
9746
9747 /**
9748  * xmlXPathParseName:
9749  * @ctxt:  the XPath Parser context
9750  *
9751  * parse an XML name
9752  *
9753  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9754  *                  CombiningChar | Extender
9755  *
9756  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9757  *
9758  * Returns the namespace name or NULL
9759  */
9760
9761 xmlChar *
9762 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9763     const xmlChar *in;
9764     xmlChar *ret;
9765     int count = 0;
9766
9767     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9768     /*
9769      * Accelerator for simple ASCII names
9770      */
9771     in = ctxt->cur;
9772     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9773         ((*in >= 0x41) && (*in <= 0x5A)) ||
9774         (*in == '_') || (*in == ':')) {
9775         in++;
9776         while (((*in >= 0x61) && (*in <= 0x7A)) ||
9777                ((*in >= 0x41) && (*in <= 0x5A)) ||
9778                ((*in >= 0x30) && (*in <= 0x39)) ||
9779                (*in == '_') || (*in == '-') ||
9780                (*in == ':') || (*in == '.'))
9781             in++;
9782         if ((*in > 0) && (*in < 0x80)) {
9783             count = in - ctxt->cur;
9784             ret = xmlStrndup(ctxt->cur, count);
9785             ctxt->cur = in;
9786             return(ret);
9787         }
9788     }
9789     return(xmlXPathParseNameComplex(ctxt, 1));
9790 }
9791
9792 static xmlChar *
9793 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9794     xmlChar buf[XML_MAX_NAMELEN + 5];
9795     int len = 0, l;
9796     int c;
9797
9798     /*
9799      * Handler for more complex cases
9800      */
9801     c = CUR_CHAR(l);
9802     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9803         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9804         (c == '*') || /* accelerators */
9805         (!IS_LETTER(c) && (c != '_') &&
9806          ((qualified) && (c != ':')))) {
9807         return(NULL);
9808     }
9809
9810     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9811            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9812             (c == '.') || (c == '-') ||
9813             (c == '_') || ((qualified) && (c == ':')) || 
9814             (IS_COMBINING(c)) ||
9815             (IS_EXTENDER(c)))) {
9816         COPY_BUF(l,buf,len,c);
9817         NEXTL(l);
9818         c = CUR_CHAR(l);
9819         if (len >= XML_MAX_NAMELEN) {
9820             /*
9821              * Okay someone managed to make a huge name, so he's ready to pay
9822              * for the processing speed.
9823              */
9824             xmlChar *buffer;
9825             int max = len * 2;
9826             
9827             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9828             if (buffer == NULL) {
9829                 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9830             }
9831             memcpy(buffer, buf, len);
9832             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9833                    (c == '.') || (c == '-') ||
9834                    (c == '_') || ((qualified) && (c == ':')) || 
9835                    (IS_COMBINING(c)) ||
9836                    (IS_EXTENDER(c))) {
9837                 if (len + 10 > max) {
9838                     max *= 2;
9839                     buffer = (xmlChar *) xmlRealloc(buffer,
9840                                                     max * sizeof(xmlChar));
9841                     if (buffer == NULL) {
9842                         XP_ERRORNULL(XPATH_MEMORY_ERROR);
9843                     }
9844                 }
9845                 COPY_BUF(l,buffer,len,c);
9846                 NEXTL(l);
9847                 c = CUR_CHAR(l);
9848             }
9849             buffer[len] = 0;
9850             return(buffer);
9851         }
9852     }
9853     if (len == 0)
9854         return(NULL);
9855     return(xmlStrndup(buf, len));
9856 }
9857
9858 #define MAX_FRAC 20
9859
9860 /*
9861  * These are used as divisors for the fractional part of a number.
9862  * Since the table includes 1.0 (representing '0' fractional digits),
9863  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9864  */
9865 static double my_pow10[MAX_FRAC+1] = {
9866     1.0, 10.0, 100.0, 1000.0, 10000.0,
9867     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9868     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9869     100000000000000.0,
9870     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9871     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9872 };
9873
9874 /**
9875  * xmlXPathStringEvalNumber:
9876  * @str:  A string to scan
9877  *
9878  *  [30a]  Float  ::= Number ('e' Digits?)?
9879  *
9880  *  [30]   Number ::=   Digits ('.' Digits?)?
9881  *                    | '.' Digits 
9882  *  [31]   Digits ::=   [0-9]+
9883  *
9884  * Compile a Number in the string
9885  * In complement of the Number expression, this function also handles
9886  * negative values : '-' Number.
9887  *
9888  * Returns the double value.
9889  */
9890 double
9891 xmlXPathStringEvalNumber(const xmlChar *str) {
9892     const xmlChar *cur = str;
9893     double ret;
9894     int ok = 0;
9895     int isneg = 0;
9896     int exponent = 0;
9897     int is_exponent_negative = 0;
9898 #ifdef __GNUC__
9899     unsigned long tmp = 0;
9900     double temp;
9901 #endif
9902     if (cur == NULL) return(0);
9903     while (IS_BLANK_CH(*cur)) cur++;
9904     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9905         return(xmlXPathNAN);
9906     }
9907     if (*cur == '-') {
9908         isneg = 1;
9909         cur++;
9910     }
9911
9912 #ifdef __GNUC__
9913     /*
9914      * tmp/temp is a workaround against a gcc compiler bug
9915      * http://veillard.com/gcc.bug
9916      */
9917     ret = 0;
9918     while ((*cur >= '0') && (*cur <= '9')) {
9919         ret = ret * 10;
9920         tmp = (*cur - '0');
9921         ok = 1;
9922         cur++;
9923         temp = (double) tmp;
9924         ret = ret + temp;
9925     }
9926 #else
9927     ret = 0;
9928     while ((*cur >= '0') && (*cur <= '9')) {
9929         ret = ret * 10 + (*cur - '0');
9930         ok = 1;
9931         cur++;
9932     }
9933 #endif
9934
9935     if (*cur == '.') {
9936         int v, frac = 0;
9937         double fraction = 0;
9938
9939         cur++;
9940         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9941             return(xmlXPathNAN);
9942         }
9943         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9944             v = (*cur - '0');
9945             fraction = fraction * 10 + v;
9946             frac = frac + 1;
9947             cur++;
9948         }
9949         fraction /= my_pow10[frac];
9950         ret = ret + fraction;
9951         while ((*cur >= '0') && (*cur <= '9'))
9952             cur++;
9953     }
9954     if ((*cur == 'e') || (*cur == 'E')) {
9955       cur++;
9956       if (*cur == '-') {
9957         is_exponent_negative = 1;
9958         cur++;
9959       } else if (*cur == '+') {
9960         cur++;
9961       }
9962       while ((*cur >= '0') && (*cur <= '9')) {
9963         exponent = exponent * 10 + (*cur - '0');
9964         cur++;
9965       }
9966     }
9967     while (IS_BLANK_CH(*cur)) cur++;
9968     if (*cur != 0) return(xmlXPathNAN);
9969     if (isneg) ret = -ret;
9970     if (is_exponent_negative) exponent = -exponent;
9971     ret *= pow(10.0, (double)exponent);
9972     return(ret);
9973 }
9974
9975 /**
9976  * xmlXPathCompNumber:
9977  * @ctxt:  the XPath Parser context
9978  *
9979  *  [30]   Number ::=   Digits ('.' Digits?)?
9980  *                    | '.' Digits 
9981  *  [31]   Digits ::=   [0-9]+
9982  *
9983  * Compile a Number, then push it on the stack
9984  *
9985  */
9986 static void
9987 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9988 {
9989     double ret = 0.0;
9990     double mult = 1;
9991     int ok = 0;
9992     int exponent = 0;
9993     int is_exponent_negative = 0;
9994 #ifdef __GNUC__
9995     unsigned long tmp = 0;
9996     double temp;
9997 #endif
9998
9999     CHECK_ERROR;
10000     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10001         XP_ERROR(XPATH_NUMBER_ERROR);
10002     }
10003 #ifdef __GNUC__
10004     /*
10005      * tmp/temp is a workaround against a gcc compiler bug
10006      * http://veillard.com/gcc.bug
10007      */
10008     ret = 0;
10009     while ((CUR >= '0') && (CUR <= '9')) {
10010         ret = ret * 10;
10011         tmp = (CUR - '0');
10012         ok = 1;
10013         NEXT;
10014         temp = (double) tmp;
10015         ret = ret + temp;
10016     }
10017 #else
10018     ret = 0;
10019     while ((CUR >= '0') && (CUR <= '9')) {
10020         ret = ret * 10 + (CUR - '0');
10021         ok = 1;
10022         NEXT;
10023     }
10024 #endif
10025     if (CUR == '.') {
10026         NEXT;
10027         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10028             XP_ERROR(XPATH_NUMBER_ERROR);
10029         }
10030         while ((CUR >= '0') && (CUR <= '9')) {
10031             mult /= 10;
10032             ret = ret + (CUR - '0') * mult;
10033             NEXT;
10034         }
10035     }
10036     if ((CUR == 'e') || (CUR == 'E')) {
10037         NEXT;
10038         if (CUR == '-') {
10039             is_exponent_negative = 1;
10040             NEXT;
10041         } else if (CUR == '+') {
10042             NEXT;
10043         }
10044         while ((CUR >= '0') && (CUR <= '9')) {
10045             exponent = exponent * 10 + (CUR - '0');
10046             NEXT;
10047         }
10048         if (is_exponent_negative)
10049             exponent = -exponent;
10050         ret *= pow(10.0, (double) exponent);
10051     }
10052     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10053                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10054 }
10055
10056 /**
10057  * xmlXPathParseLiteral:
10058  * @ctxt:  the XPath Parser context
10059  *
10060  * Parse a Literal
10061  *
10062  *  [29]   Literal ::=   '"' [^"]* '"'
10063  *                    | "'" [^']* "'"
10064  *
10065  * Returns the value found or NULL in case of error
10066  */
10067 static xmlChar *
10068 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10069     const xmlChar *q;
10070     xmlChar *ret = NULL;
10071
10072     if (CUR == '"') {
10073         NEXT;
10074         q = CUR_PTR;
10075         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10076             NEXT;
10077         if (!IS_CHAR_CH(CUR)) {
10078             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10079         } else {
10080             ret = xmlStrndup(q, CUR_PTR - q);
10081             NEXT;
10082         }
10083     } else if (CUR == '\'') {
10084         NEXT;
10085         q = CUR_PTR;
10086         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10087             NEXT;
10088         if (!IS_CHAR_CH(CUR)) {
10089             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10090         } else {
10091             ret = xmlStrndup(q, CUR_PTR - q);
10092             NEXT;
10093         }
10094     } else {
10095         XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10096     }
10097     return(ret);
10098 }
10099
10100 /**
10101  * xmlXPathCompLiteral:
10102  * @ctxt:  the XPath Parser context
10103  *
10104  * Parse a Literal and push it on the stack.
10105  *
10106  *  [29]   Literal ::=   '"' [^"]* '"'
10107  *                    | "'" [^']* "'"
10108  *
10109  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10110  */
10111 static void
10112 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10113     const xmlChar *q;
10114     xmlChar *ret = NULL;
10115
10116     if (CUR == '"') {
10117         NEXT;
10118         q = CUR_PTR;
10119         while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10120             NEXT;
10121         if (!IS_CHAR_CH(CUR)) {
10122             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10123         } else {
10124             ret = xmlStrndup(q, CUR_PTR - q);
10125             NEXT;
10126         }
10127     } else if (CUR == '\'') {
10128         NEXT;
10129         q = CUR_PTR;
10130         while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10131             NEXT;
10132         if (!IS_CHAR_CH(CUR)) {
10133             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10134         } else {
10135             ret = xmlStrndup(q, CUR_PTR - q);
10136             NEXT;
10137         }
10138     } else {
10139         XP_ERROR(XPATH_START_LITERAL_ERROR);
10140     }
10141     if (ret == NULL) return;
10142     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10143                    xmlXPathCacheNewString(ctxt->context, ret), NULL);
10144     xmlFree(ret);
10145 }
10146
10147 /**
10148  * xmlXPathCompVariableReference:
10149  * @ctxt:  the XPath Parser context
10150  *
10151  * Parse a VariableReference, evaluate it and push it on the stack.
10152  *
10153  * The variable bindings consist of a mapping from variable names
10154  * to variable values. The value of a variable is an object, which can be
10155  * of any of the types that are possible for the value of an expression,
10156  * and may also be of additional types not specified here.
10157  *
10158  * Early evaluation is possible since:
10159  * The variable bindings [...] used to evaluate a subexpression are
10160  * always the same as those used to evaluate the containing expression. 
10161  *
10162  *  [36]   VariableReference ::=   '$' QName 
10163  */
10164 static void
10165 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10166     xmlChar *name;
10167     xmlChar *prefix;
10168
10169     SKIP_BLANKS;
10170     if (CUR != '$') {
10171         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10172     }
10173     NEXT;
10174     name = xmlXPathParseQName(ctxt, &prefix);
10175     if (name == NULL) {
10176         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10177     }
10178     ctxt->comp->last = -1;
10179     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10180                    name, prefix);
10181     SKIP_BLANKS;
10182     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10183         XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10184     }
10185 }
10186
10187 /**
10188  * xmlXPathIsNodeType:
10189  * @name:  a name string
10190  *
10191  * Is the name given a NodeType one.
10192  *
10193  *  [38]   NodeType ::=   'comment'
10194  *                    | 'text'
10195  *                    | 'processing-instruction'
10196  *                    | 'node'
10197  *
10198  * Returns 1 if true 0 otherwise
10199  */
10200 int
10201 xmlXPathIsNodeType(const xmlChar *name) {
10202     if (name == NULL)
10203         return(0);
10204
10205     if (xmlStrEqual(name, BAD_CAST "node"))
10206         return(1);
10207     if (xmlStrEqual(name, BAD_CAST "text"))
10208         return(1);
10209     if (xmlStrEqual(name, BAD_CAST "comment"))
10210         return(1);
10211     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10212         return(1);
10213     return(0);
10214 }
10215
10216 /**
10217  * xmlXPathCompFunctionCall:
10218  * @ctxt:  the XPath Parser context
10219  *
10220  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10221  *  [17]   Argument ::=   Expr 
10222  *
10223  * Compile a function call, the evaluation of all arguments are
10224  * pushed on the stack
10225  */
10226 static void
10227 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10228     xmlChar *name;
10229     xmlChar *prefix;
10230     int nbargs = 0;
10231     int sort = 1;
10232
10233     name = xmlXPathParseQName(ctxt, &prefix);
10234     if (name == NULL) {
10235         XP_ERROR(XPATH_EXPR_ERROR);
10236     }
10237     SKIP_BLANKS;
10238 #ifdef DEBUG_EXPR
10239     if (prefix == NULL)
10240         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10241                         name);
10242     else
10243         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10244                         prefix, name);
10245 #endif
10246
10247     if (CUR != '(') {
10248         XP_ERROR(XPATH_EXPR_ERROR);
10249     }
10250     NEXT;
10251     SKIP_BLANKS;
10252
10253     /*
10254     * Optimization for count(): we don't need the node-set to be sorted.
10255     */
10256     if ((prefix == NULL) && (name[0] == 'c') &&
10257         xmlStrEqual(name, BAD_CAST "count"))
10258     {
10259         sort = 0;
10260     }
10261     ctxt->comp->last = -1;
10262     if (CUR != ')') {
10263         while (CUR != 0) {
10264             int op1 = ctxt->comp->last;
10265             ctxt->comp->last = -1;
10266             xmlXPathCompileExpr(ctxt, sort);
10267             CHECK_ERROR;
10268             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10269             nbargs++;
10270             if (CUR == ')') break;
10271             if (CUR != ',') {
10272                 XP_ERROR(XPATH_EXPR_ERROR);
10273             }
10274             NEXT;
10275             SKIP_BLANKS;
10276         }
10277     }
10278     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10279                    name, prefix);
10280     NEXT;
10281     SKIP_BLANKS;
10282 }
10283
10284 /**
10285  * xmlXPathCompPrimaryExpr:
10286  * @ctxt:  the XPath Parser context
10287  *
10288  *  [15]   PrimaryExpr ::=   VariableReference 
10289  *                | '(' Expr ')'
10290  *                | Literal 
10291  *                | Number 
10292  *                | FunctionCall 
10293  *
10294  * Compile a primary expression.
10295  */
10296 static void
10297 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10298     SKIP_BLANKS;
10299     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10300     else if (CUR == '(') {
10301         NEXT;
10302         SKIP_BLANKS;
10303         xmlXPathCompileExpr(ctxt, 1);
10304         CHECK_ERROR;
10305         if (CUR != ')') {
10306             XP_ERROR(XPATH_EXPR_ERROR);
10307         }
10308         NEXT;
10309         SKIP_BLANKS;
10310     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10311         xmlXPathCompNumber(ctxt);
10312     } else if ((CUR == '\'') || (CUR == '"')) {
10313         xmlXPathCompLiteral(ctxt);
10314     } else {
10315         xmlXPathCompFunctionCall(ctxt);
10316     }
10317     SKIP_BLANKS;
10318 }
10319
10320 /**
10321  * xmlXPathCompFilterExpr:
10322  * @ctxt:  the XPath Parser context
10323  *
10324  *  [20]   FilterExpr ::=   PrimaryExpr 
10325  *               | FilterExpr Predicate 
10326  *
10327  * Compile a filter expression.
10328  * Square brackets are used to filter expressions in the same way that
10329  * they are used in location paths. It is an error if the expression to
10330  * be filtered does not evaluate to a node-set. The context node list
10331  * used for evaluating the expression in square brackets is the node-set
10332  * to be filtered listed in document order.
10333  */
10334
10335 static void
10336 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10337     xmlXPathCompPrimaryExpr(ctxt);
10338     CHECK_ERROR;
10339     SKIP_BLANKS;
10340     
10341     while (CUR == '[') {
10342         xmlXPathCompPredicate(ctxt, 1);
10343         SKIP_BLANKS;
10344     }
10345
10346     
10347 }
10348
10349 /**
10350  * xmlXPathScanName:
10351  * @ctxt:  the XPath Parser context
10352  *
10353  * Trickery: parse an XML name but without consuming the input flow
10354  * Needed to avoid insanity in the parser state.
10355  *
10356  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10357  *                  CombiningChar | Extender
10358  *
10359  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10360  *
10361  * [6] Names ::= Name (S Name)*
10362  *
10363  * Returns the Name parsed or NULL
10364  */
10365
10366 static xmlChar *
10367 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10368     int len = 0, l;
10369     int c;
10370     const xmlChar *cur;
10371     xmlChar *ret;
10372
10373     cur = ctxt->cur;
10374
10375     c = CUR_CHAR(l);
10376     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10377         (!IS_LETTER(c) && (c != '_') &&
10378          (c != ':'))) {
10379         return(NULL);
10380     }
10381
10382     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10383            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10384             (c == '.') || (c == '-') ||
10385             (c == '_') || (c == ':') || 
10386             (IS_COMBINING(c)) ||
10387             (IS_EXTENDER(c)))) {
10388         len += l;
10389         NEXTL(l);
10390         c = CUR_CHAR(l);
10391     }
10392     ret = xmlStrndup(cur, ctxt->cur - cur);
10393     ctxt->cur = cur;
10394     return(ret);
10395 }
10396
10397 /**
10398  * xmlXPathCompPathExpr:
10399  * @ctxt:  the XPath Parser context
10400  *
10401  *  [19]   PathExpr ::=   LocationPath 
10402  *               | FilterExpr 
10403  *               | FilterExpr '/' RelativeLocationPath 
10404  *               | FilterExpr '//' RelativeLocationPath 
10405  *
10406  * Compile a path expression.
10407  * The / operator and // operators combine an arbitrary expression
10408  * and a relative location path. It is an error if the expression
10409  * does not evaluate to a node-set.
10410  * The / operator does composition in the same way as when / is
10411  * used in a location path. As in location paths, // is short for
10412  * /descendant-or-self::node()/.
10413  */
10414
10415 static void
10416 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10417     int lc = 1;           /* Should we branch to LocationPath ?         */
10418     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10419
10420     SKIP_BLANKS;
10421     if ((CUR == '$') || (CUR == '(') || 
10422         (IS_ASCII_DIGIT(CUR)) ||
10423         (CUR == '\'') || (CUR == '"') ||
10424         (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425         lc = 0;
10426     } else if (CUR == '*') {
10427         /* relative or absolute location path */
10428         lc = 1;
10429     } else if (CUR == '/') {
10430         /* relative or absolute location path */
10431         lc = 1;
10432     } else if (CUR == '@') {
10433         /* relative abbreviated attribute location path */
10434         lc = 1;
10435     } else if (CUR == '.') {
10436         /* relative abbreviated attribute location path */
10437         lc = 1;
10438     } else {
10439         /*
10440          * Problem is finding if we have a name here whether it's:
10441          *   - a nodetype
10442          *   - a function call in which case it's followed by '('
10443          *   - an axis in which case it's followed by ':'
10444          *   - a element name
10445          * We do an a priori analysis here rather than having to
10446          * maintain parsed token content through the recursive function
10447          * calls. This looks uglier but makes the code easier to
10448          * read/write/debug.
10449          */
10450         SKIP_BLANKS;
10451         name = xmlXPathScanName(ctxt);
10452         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10453 #ifdef DEBUG_STEP
10454             xmlGenericError(xmlGenericErrorContext,
10455                     "PathExpr: Axis\n");
10456 #endif
10457             lc = 1;
10458             xmlFree(name);
10459         } else if (name != NULL) {
10460             int len =xmlStrlen(name);
10461
10462             
10463             while (NXT(len) != 0) {
10464                 if (NXT(len) == '/') {
10465                     /* element name */
10466 #ifdef DEBUG_STEP
10467                     xmlGenericError(xmlGenericErrorContext,
10468                             "PathExpr: AbbrRelLocation\n");
10469 #endif
10470                     lc = 1;
10471                     break;
10472                 } else if (IS_BLANK_CH(NXT(len))) {
10473                     /* ignore blanks */
10474                     ;
10475                 } else if (NXT(len) == ':') {
10476 #ifdef DEBUG_STEP
10477                     xmlGenericError(xmlGenericErrorContext,
10478                             "PathExpr: AbbrRelLocation\n");
10479 #endif
10480                     lc = 1;
10481                     break;
10482                 } else if ((NXT(len) == '(')) {
10483                     /* Note Type or Function */
10484                     if (xmlXPathIsNodeType(name)) {
10485 #ifdef DEBUG_STEP
10486                         xmlGenericError(xmlGenericErrorContext,
10487                                 "PathExpr: Type search\n");
10488 #endif
10489                         lc = 1;
10490                     } else {
10491 #ifdef DEBUG_STEP
10492                         xmlGenericError(xmlGenericErrorContext,
10493                                 "PathExpr: function call\n");
10494 #endif
10495                         lc = 0;
10496                     }
10497                     break;
10498                 } else if ((NXT(len) == '[')) {
10499                     /* element name */
10500 #ifdef DEBUG_STEP
10501                     xmlGenericError(xmlGenericErrorContext,
10502                             "PathExpr: AbbrRelLocation\n");
10503 #endif
10504                     lc = 1;
10505                     break;
10506                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10507                            (NXT(len) == '=')) {
10508                     lc = 1;
10509                     break;
10510                 } else {
10511                     lc = 1;
10512                     break;
10513                 }
10514                 len++;
10515             }
10516             if (NXT(len) == 0) {
10517 #ifdef DEBUG_STEP
10518                 xmlGenericError(xmlGenericErrorContext,
10519                         "PathExpr: AbbrRelLocation\n");
10520 #endif
10521                 /* element name */
10522                 lc = 1;
10523             }
10524             xmlFree(name);
10525         } else {
10526             /* make sure all cases are covered explicitly */
10527             XP_ERROR(XPATH_EXPR_ERROR);
10528         }
10529     } 
10530
10531     if (lc) {
10532         if (CUR == '/') {
10533             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10534         } else {
10535             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10536         }
10537         xmlXPathCompLocationPath(ctxt);
10538     } else {
10539         xmlXPathCompFilterExpr(ctxt);
10540         CHECK_ERROR;
10541         if ((CUR == '/') && (NXT(1) == '/')) {
10542             SKIP(2);
10543             SKIP_BLANKS;
10544
10545             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10546                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10547             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10548
10549             xmlXPathCompRelativeLocationPath(ctxt);
10550         } else if (CUR == '/') {
10551             xmlXPathCompRelativeLocationPath(ctxt);
10552         }
10553     }
10554     SKIP_BLANKS;
10555 }
10556
10557 /**
10558  * xmlXPathCompUnionExpr:
10559  * @ctxt:  the XPath Parser context
10560  *
10561  *  [18]   UnionExpr ::=   PathExpr 
10562  *               | UnionExpr '|' PathExpr 
10563  *
10564  * Compile an union expression.
10565  */
10566
10567 static void
10568 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10569     xmlXPathCompPathExpr(ctxt);
10570     CHECK_ERROR;
10571     SKIP_BLANKS;
10572     while (CUR == '|') {
10573         int op1 = ctxt->comp->last;
10574         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10575
10576         NEXT;
10577         SKIP_BLANKS;
10578         xmlXPathCompPathExpr(ctxt);
10579
10580         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10581
10582         SKIP_BLANKS;
10583     }
10584 }
10585
10586 /**
10587  * xmlXPathCompUnaryExpr:
10588  * @ctxt:  the XPath Parser context
10589  *
10590  *  [27]   UnaryExpr ::=   UnionExpr 
10591  *                   | '-' UnaryExpr 
10592  *
10593  * Compile an unary expression.
10594  */
10595
10596 static void
10597 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10598     int minus = 0;
10599     int found = 0;
10600
10601     SKIP_BLANKS;
10602     while (CUR == '-') {
10603         minus = 1 - minus;
10604         found = 1;
10605         NEXT;
10606         SKIP_BLANKS;
10607     }
10608
10609     xmlXPathCompUnionExpr(ctxt);
10610     CHECK_ERROR;
10611     if (found) {
10612         if (minus)
10613             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10614         else
10615             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10616     }
10617 }
10618
10619 /**
10620  * xmlXPathCompMultiplicativeExpr:
10621  * @ctxt:  the XPath Parser context
10622  *
10623  *  [26]   MultiplicativeExpr ::=   UnaryExpr 
10624  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr 
10625  *                   | MultiplicativeExpr 'div' UnaryExpr 
10626  *                   | MultiplicativeExpr 'mod' UnaryExpr 
10627  *  [34]   MultiplyOperator ::=   '*'
10628  *
10629  * Compile an Additive expression.
10630  */
10631
10632 static void
10633 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10634     xmlXPathCompUnaryExpr(ctxt);
10635     CHECK_ERROR;
10636     SKIP_BLANKS;
10637     while ((CUR == '*') || 
10638            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10639            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10640         int op = -1;
10641         int op1 = ctxt->comp->last;
10642
10643         if (CUR == '*') {
10644             op = 0;
10645             NEXT;
10646         } else if (CUR == 'd') {
10647             op = 1;
10648             SKIP(3);
10649         } else if (CUR == 'm') {
10650             op = 2;
10651             SKIP(3);
10652         }
10653         SKIP_BLANKS;
10654         xmlXPathCompUnaryExpr(ctxt);
10655         CHECK_ERROR;
10656         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10657         SKIP_BLANKS;
10658     }
10659 }
10660
10661 /**
10662  * xmlXPathCompAdditiveExpr:
10663  * @ctxt:  the XPath Parser context
10664  *
10665  *  [25]   AdditiveExpr ::=   MultiplicativeExpr 
10666  *                   | AdditiveExpr '+' MultiplicativeExpr 
10667  *                   | AdditiveExpr '-' MultiplicativeExpr 
10668  *
10669  * Compile an Additive expression.
10670  */
10671
10672 static void
10673 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10674
10675     xmlXPathCompMultiplicativeExpr(ctxt);
10676     CHECK_ERROR;
10677     SKIP_BLANKS;
10678     while ((CUR == '+') || (CUR == '-')) {
10679         int plus;
10680         int op1 = ctxt->comp->last;
10681
10682         if (CUR == '+') plus = 1;
10683         else plus = 0;
10684         NEXT;
10685         SKIP_BLANKS;
10686         xmlXPathCompMultiplicativeExpr(ctxt);
10687         CHECK_ERROR;
10688         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10689         SKIP_BLANKS;
10690     }
10691 }
10692
10693 /**
10694  * xmlXPathCompRelationalExpr:
10695  * @ctxt:  the XPath Parser context
10696  *
10697  *  [24]   RelationalExpr ::=   AdditiveExpr 
10698  *                 | RelationalExpr '<' AdditiveExpr 
10699  *                 | RelationalExpr '>' AdditiveExpr 
10700  *                 | RelationalExpr '<=' AdditiveExpr 
10701  *                 | RelationalExpr '>=' AdditiveExpr 
10702  *
10703  *  A <= B > C is allowed ? Answer from James, yes with
10704  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10705  *  which is basically what got implemented.
10706  *
10707  * Compile a Relational expression, then push the result
10708  * on the stack
10709  */
10710
10711 static void
10712 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10713     xmlXPathCompAdditiveExpr(ctxt);
10714     CHECK_ERROR;
10715     SKIP_BLANKS;
10716     while ((CUR == '<') ||
10717            (CUR == '>') ||
10718            ((CUR == '<') && (NXT(1) == '=')) ||
10719            ((CUR == '>') && (NXT(1) == '='))) {
10720         int inf, strict;
10721         int op1 = ctxt->comp->last;
10722
10723         if (CUR == '<') inf = 1;
10724         else inf = 0;
10725         if (NXT(1) == '=') strict = 0;
10726         else strict = 1;
10727         NEXT;
10728         if (!strict) NEXT;
10729         SKIP_BLANKS;
10730         xmlXPathCompAdditiveExpr(ctxt);
10731         CHECK_ERROR;
10732         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10733         SKIP_BLANKS;
10734     }
10735 }
10736
10737 /**
10738  * xmlXPathCompEqualityExpr:
10739  * @ctxt:  the XPath Parser context
10740  *
10741  *  [23]   EqualityExpr ::=   RelationalExpr 
10742  *                 | EqualityExpr '=' RelationalExpr 
10743  *                 | EqualityExpr '!=' RelationalExpr 
10744  *
10745  *  A != B != C is allowed ? Answer from James, yes with
10746  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10747  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10748  *  which is basically what got implemented.
10749  *
10750  * Compile an Equality expression.
10751  *
10752  */
10753 static void
10754 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10755     xmlXPathCompRelationalExpr(ctxt);
10756     CHECK_ERROR;
10757     SKIP_BLANKS;
10758     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10759         int eq;
10760         int op1 = ctxt->comp->last;
10761
10762         if (CUR == '=') eq = 1;
10763         else eq = 0;
10764         NEXT;
10765         if (!eq) NEXT;
10766         SKIP_BLANKS;
10767         xmlXPathCompRelationalExpr(ctxt);
10768         CHECK_ERROR;
10769         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10770         SKIP_BLANKS;
10771     }
10772 }
10773
10774 /**
10775  * xmlXPathCompAndExpr:
10776  * @ctxt:  the XPath Parser context
10777  *
10778  *  [22]   AndExpr ::=   EqualityExpr 
10779  *                 | AndExpr 'and' EqualityExpr 
10780  *
10781  * Compile an AND expression.
10782  *
10783  */
10784 static void
10785 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10786     xmlXPathCompEqualityExpr(ctxt);
10787     CHECK_ERROR;
10788     SKIP_BLANKS;
10789     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10790         int op1 = ctxt->comp->last;
10791         SKIP(3);
10792         SKIP_BLANKS;
10793         xmlXPathCompEqualityExpr(ctxt);
10794         CHECK_ERROR;
10795         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10796         SKIP_BLANKS;
10797     }
10798 }
10799
10800 /**
10801  * xmlXPathCompileExpr:
10802  * @ctxt:  the XPath Parser context
10803  *
10804  *  [14]   Expr ::=   OrExpr 
10805  *  [21]   OrExpr ::=   AndExpr 
10806  *                 | OrExpr 'or' AndExpr 
10807  *
10808  * Parse and compile an expression
10809  */
10810 static void
10811 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10812     xmlXPathCompAndExpr(ctxt);
10813     CHECK_ERROR;
10814     SKIP_BLANKS;
10815     while ((CUR == 'o') && (NXT(1) == 'r')) {
10816         int op1 = ctxt->comp->last;
10817         SKIP(2);
10818         SKIP_BLANKS;
10819         xmlXPathCompAndExpr(ctxt);
10820         CHECK_ERROR;
10821         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10822         op1 = ctxt->comp->nbStep;
10823         SKIP_BLANKS;
10824     }
10825     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10826         /* more ops could be optimized too */
10827         /*
10828         * This is the main place to eliminate sorting for
10829         * operations which don't require a sorted node-set.
10830         * E.g. count().
10831         */
10832         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10833     }
10834 }
10835
10836 /**
10837  * xmlXPathCompPredicate:
10838  * @ctxt:  the XPath Parser context
10839  * @filter:  act as a filter
10840  *
10841  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10842  *  [9]   PredicateExpr ::=   Expr 
10843  *
10844  * Compile a predicate expression
10845  */
10846 static void
10847 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10848     int op1 = ctxt->comp->last;
10849
10850     SKIP_BLANKS;
10851     if (CUR != '[') {
10852         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10853     }
10854     NEXT;
10855     SKIP_BLANKS;
10856
10857     ctxt->comp->last = -1;
10858     /*
10859     * This call to xmlXPathCompileExpr() will deactivate sorting
10860     * of the predicate result.
10861     * TODO: Sorting is still activated for filters, since I'm not
10862     *  sure if needed. Normally sorting should not be needed, since
10863     *  a filter can only diminish the number of items in a sequence,
10864     *  but won't change its order; so if the initial sequence is sorted,
10865     *  subsequent sorting is not needed.
10866     */
10867     if (! filter)
10868         xmlXPathCompileExpr(ctxt, 0);
10869     else
10870         xmlXPathCompileExpr(ctxt, 1);
10871     CHECK_ERROR;
10872
10873     if (CUR != ']') {
10874         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10875     }
10876
10877     if (filter)
10878         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10879     else
10880         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10881
10882     NEXT;
10883     SKIP_BLANKS;
10884 }
10885
10886 /**
10887  * xmlXPathCompNodeTest:
10888  * @ctxt:  the XPath Parser context
10889  * @test:  pointer to a xmlXPathTestVal
10890  * @type:  pointer to a xmlXPathTypeVal
10891  * @prefix:  placeholder for a possible name prefix
10892  *
10893  * [7] NodeTest ::=   NameTest
10894  *                  | NodeType '(' ')'
10895  *                  | 'processing-instruction' '(' Literal ')'
10896  *
10897  * [37] NameTest ::=  '*'
10898  *                  | NCName ':' '*'
10899  *                  | QName
10900  * [38] NodeType ::= 'comment'
10901  *                 | 'text'
10902  *                 | 'processing-instruction'
10903  *                 | 'node'
10904  *
10905  * Returns the name found and updates @test, @type and @prefix appropriately
10906  */
10907 static xmlChar *
10908 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10909                      xmlXPathTypeVal *type, const xmlChar **prefix,
10910                      xmlChar *name) {
10911     int blanks;
10912
10913     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10914         STRANGE;
10915         return(NULL);
10916     }
10917     *type = (xmlXPathTypeVal) 0;
10918     *test = (xmlXPathTestVal) 0;
10919     *prefix = NULL;
10920     SKIP_BLANKS;
10921
10922     if ((name == NULL) && (CUR == '*')) {
10923         /*
10924          * All elements
10925          */
10926         NEXT;
10927         *test = NODE_TEST_ALL;
10928         return(NULL);
10929     }
10930
10931     if (name == NULL)
10932         name = xmlXPathParseNCName(ctxt);
10933     if (name == NULL) {
10934         XP_ERRORNULL(XPATH_EXPR_ERROR);
10935     }
10936
10937     blanks = IS_BLANK_CH(CUR);
10938     SKIP_BLANKS;
10939     if (CUR == '(') {
10940         NEXT;
10941         /*
10942          * NodeType or PI search
10943          */
10944         if (xmlStrEqual(name, BAD_CAST "comment"))
10945             *type = NODE_TYPE_COMMENT;
10946         else if (xmlStrEqual(name, BAD_CAST "node"))
10947             *type = NODE_TYPE_NODE;
10948         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10949             *type = NODE_TYPE_PI;
10950         else if (xmlStrEqual(name, BAD_CAST "text"))
10951             *type = NODE_TYPE_TEXT;
10952         else {
10953             if (name != NULL)
10954                 xmlFree(name);
10955             XP_ERRORNULL(XPATH_EXPR_ERROR);
10956         }
10957
10958         *test = NODE_TEST_TYPE;
10959         
10960         SKIP_BLANKS;
10961         if (*type == NODE_TYPE_PI) {
10962             /*
10963              * Specific case: search a PI by name.
10964              */
10965             if (name != NULL)
10966                 xmlFree(name);
10967             name = NULL;
10968             if (CUR != ')') {
10969                 name = xmlXPathParseLiteral(ctxt);
10970                 CHECK_ERROR NULL;
10971                 *test = NODE_TEST_PI;
10972                 SKIP_BLANKS;
10973             }
10974         }
10975         if (CUR != ')') {
10976             if (name != NULL)
10977                 xmlFree(name);
10978             XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10979         }
10980         NEXT;
10981         return(name);
10982     }
10983     *test = NODE_TEST_NAME;
10984     if ((!blanks) && (CUR == ':')) {
10985         NEXT;
10986
10987         /*
10988          * Since currently the parser context don't have a
10989          * namespace list associated:
10990          * The namespace name for this prefix can be computed
10991          * only at evaluation time. The compilation is done
10992          * outside of any context.
10993          */
10994 #if 0
10995         *prefix = xmlXPathNsLookup(ctxt->context, name);
10996         if (name != NULL)
10997             xmlFree(name);
10998         if (*prefix == NULL) {
10999             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11000         }
11001 #else
11002         *prefix = name;
11003 #endif
11004
11005         if (CUR == '*') {
11006             /*
11007              * All elements
11008              */
11009             NEXT;
11010             *test = NODE_TEST_ALL;
11011             return(NULL);
11012         }
11013
11014         name = xmlXPathParseNCName(ctxt);
11015         if (name == NULL) {
11016             XP_ERRORNULL(XPATH_EXPR_ERROR);
11017         }
11018     }
11019     return(name);
11020 }
11021
11022 /**
11023  * xmlXPathIsAxisName:
11024  * @name:  a preparsed name token
11025  *
11026  * [6] AxisName ::=   'ancestor'
11027  *                  | 'ancestor-or-self'
11028  *                  | 'attribute'
11029  *                  | 'child'
11030  *                  | 'descendant'
11031  *                  | 'descendant-or-self'
11032  *                  | 'following'
11033  *                  | 'following-sibling'
11034  *                  | 'namespace'
11035  *                  | 'parent'
11036  *                  | 'preceding'
11037  *                  | 'preceding-sibling'
11038  *                  | 'self'
11039  *
11040  * Returns the axis or 0
11041  */
11042 static xmlXPathAxisVal
11043 xmlXPathIsAxisName(const xmlChar *name) {
11044     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11045     switch (name[0]) {
11046         case 'a':
11047             if (xmlStrEqual(name, BAD_CAST "ancestor"))
11048                 ret = AXIS_ANCESTOR;
11049             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11050                 ret = AXIS_ANCESTOR_OR_SELF;
11051             if (xmlStrEqual(name, BAD_CAST "attribute"))
11052                 ret = AXIS_ATTRIBUTE;
11053             break;
11054         case 'c':
11055             if (xmlStrEqual(name, BAD_CAST "child"))
11056                 ret = AXIS_CHILD;
11057             break;
11058         case 'd':
11059             if (xmlStrEqual(name, BAD_CAST "descendant"))
11060                 ret = AXIS_DESCENDANT;
11061             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11062                 ret = AXIS_DESCENDANT_OR_SELF;
11063             break;
11064         case 'f':
11065             if (xmlStrEqual(name, BAD_CAST "following"))
11066                 ret = AXIS_FOLLOWING;
11067             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11068                 ret = AXIS_FOLLOWING_SIBLING;
11069             break;
11070         case 'n':
11071             if (xmlStrEqual(name, BAD_CAST "namespace"))
11072                 ret = AXIS_NAMESPACE;
11073             break;
11074         case 'p':
11075             if (xmlStrEqual(name, BAD_CAST "parent"))
11076                 ret = AXIS_PARENT;
11077             if (xmlStrEqual(name, BAD_CAST "preceding"))
11078                 ret = AXIS_PRECEDING;
11079             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11080                 ret = AXIS_PRECEDING_SIBLING;
11081             break;
11082         case 's':
11083             if (xmlStrEqual(name, BAD_CAST "self"))
11084                 ret = AXIS_SELF;
11085             break;
11086     }
11087     return(ret);
11088 }
11089
11090 /**
11091  * xmlXPathCompStep:
11092  * @ctxt:  the XPath Parser context
11093  *
11094  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11095  *                  | AbbreviatedStep 
11096  *
11097  * [12] AbbreviatedStep ::=   '.' | '..'
11098  *
11099  * [5] AxisSpecifier ::= AxisName '::'
11100  *                  | AbbreviatedAxisSpecifier
11101  *
11102  * [13] AbbreviatedAxisSpecifier ::= '@'?
11103  *
11104  * Modified for XPtr range support as:
11105  *
11106  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11107  *                     | AbbreviatedStep
11108  *                     | 'range-to' '(' Expr ')' Predicate*
11109  *
11110  * Compile one step in a Location Path
11111  * A location step of . is short for self::node(). This is
11112  * particularly useful in conjunction with //. For example, the
11113  * location path .//para is short for
11114  * self::node()/descendant-or-self::node()/child::para
11115  * and so will select all para descendant elements of the context
11116  * node.
11117  * Similarly, a location step of .. is short for parent::node().
11118  * For example, ../title is short for parent::node()/child::title
11119  * and so will select the title children of the parent of the context
11120  * node.
11121  */
11122 static void
11123 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11124 #ifdef LIBXML_XPTR_ENABLED
11125     int rangeto = 0;
11126     int op2 = -1;
11127 #endif
11128
11129     SKIP_BLANKS;
11130     if ((CUR == '.') && (NXT(1) == '.')) {
11131         SKIP(2);
11132         SKIP_BLANKS;
11133         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11134                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11135     } else if (CUR == '.') {
11136         NEXT;
11137         SKIP_BLANKS;
11138     } else {
11139         xmlChar *name = NULL;
11140         const xmlChar *prefix = NULL;
11141         xmlXPathTestVal test = (xmlXPathTestVal) 0;
11142         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11143         xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11144         int op1;
11145
11146         /*
11147          * The modification needed for XPointer change to the production
11148          */
11149 #ifdef LIBXML_XPTR_ENABLED
11150         if (ctxt->xptr) {
11151             name = xmlXPathParseNCName(ctxt);
11152             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11153                 op2 = ctxt->comp->last;
11154                 xmlFree(name);
11155                 SKIP_BLANKS;
11156                 if (CUR != '(') {
11157                     XP_ERROR(XPATH_EXPR_ERROR);
11158                 }
11159                 NEXT;
11160                 SKIP_BLANKS;
11161
11162                 xmlXPathCompileExpr(ctxt, 1);
11163                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11164                 CHECK_ERROR;
11165
11166                 SKIP_BLANKS;
11167                 if (CUR != ')') {
11168                     XP_ERROR(XPATH_EXPR_ERROR);
11169                 }
11170                 NEXT;
11171                 rangeto = 1;
11172                 goto eval_predicates;
11173             }
11174         }
11175 #endif
11176         if (CUR == '*') {
11177             axis = AXIS_CHILD;
11178         } else {
11179             if (name == NULL)
11180                 name = xmlXPathParseNCName(ctxt);
11181             if (name != NULL) {
11182                 axis = xmlXPathIsAxisName(name);
11183                 if (axis != 0) {
11184                     SKIP_BLANKS;
11185                     if ((CUR == ':') && (NXT(1) == ':')) {
11186                         SKIP(2);
11187                         xmlFree(name);
11188                         name = NULL;
11189                     } else {
11190                         /* an element name can conflict with an axis one :-\ */
11191                         axis = AXIS_CHILD;
11192                     }
11193                 } else {
11194                     axis = AXIS_CHILD;
11195                 }
11196             } else if (CUR == '@') {
11197                 NEXT;
11198                 axis = AXIS_ATTRIBUTE;
11199             } else {
11200                 axis = AXIS_CHILD;
11201             }
11202         }
11203
11204         CHECK_ERROR;
11205
11206         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11207         if (test == 0)
11208             return;
11209
11210         if ((prefix != NULL) && (ctxt->context != NULL) &&
11211             (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11212             if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11213                 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11214             }
11215         }
11216 #ifdef DEBUG_STEP
11217         xmlGenericError(xmlGenericErrorContext,
11218                 "Basis : computing new set\n");
11219 #endif
11220
11221 #ifdef DEBUG_STEP
11222         xmlGenericError(xmlGenericErrorContext, "Basis : ");
11223         if (ctxt->value == NULL)
11224             xmlGenericError(xmlGenericErrorContext, "no value\n");
11225         else if (ctxt->value->nodesetval == NULL)
11226             xmlGenericError(xmlGenericErrorContext, "Empty\n");
11227         else
11228             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11229 #endif
11230
11231 #ifdef LIBXML_XPTR_ENABLED
11232 eval_predicates:
11233 #endif
11234         op1 = ctxt->comp->last;
11235         ctxt->comp->last = -1;
11236
11237         SKIP_BLANKS;
11238         while (CUR == '[') {
11239             xmlXPathCompPredicate(ctxt, 0);
11240         }
11241
11242 #ifdef LIBXML_XPTR_ENABLED
11243         if (rangeto) {
11244             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11245         } else
11246 #endif
11247             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11248                            test, type, (void *)prefix, (void *)name);
11249
11250     }
11251 #ifdef DEBUG_STEP
11252     xmlGenericError(xmlGenericErrorContext, "Step : ");
11253     if (ctxt->value == NULL)
11254         xmlGenericError(xmlGenericErrorContext, "no value\n");
11255     else if (ctxt->value->nodesetval == NULL)
11256         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11257     else
11258         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11259                 ctxt->value->nodesetval);
11260 #endif
11261 }
11262
11263 /**
11264  * xmlXPathCompRelativeLocationPath:
11265  * @ctxt:  the XPath Parser context
11266  *
11267  *  [3]   RelativeLocationPath ::=   Step 
11268  *                     | RelativeLocationPath '/' Step 
11269  *                     | AbbreviatedRelativeLocationPath 
11270  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step 
11271  *
11272  * Compile a relative location path.
11273  */
11274 static void
11275 xmlXPathCompRelativeLocationPath
11276 (xmlXPathParserContextPtr ctxt) {
11277     SKIP_BLANKS;
11278     if ((CUR == '/') && (NXT(1) == '/')) {
11279         SKIP(2);
11280         SKIP_BLANKS;
11281         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11282                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11283     } else if (CUR == '/') {
11284             NEXT;
11285         SKIP_BLANKS;
11286     }
11287     xmlXPathCompStep(ctxt);
11288     SKIP_BLANKS;
11289     while (CUR == '/') {
11290         if ((CUR == '/') && (NXT(1) == '/')) {
11291             SKIP(2);
11292             SKIP_BLANKS;
11293             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11294                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11295             xmlXPathCompStep(ctxt);
11296         } else if (CUR == '/') {
11297             NEXT;
11298             SKIP_BLANKS;
11299             xmlXPathCompStep(ctxt);
11300         }
11301         SKIP_BLANKS;
11302     }
11303 }
11304
11305 /**
11306  * xmlXPathCompLocationPath:
11307  * @ctxt:  the XPath Parser context
11308  *
11309  *  [1]   LocationPath ::=   RelativeLocationPath 
11310  *                     | AbsoluteLocationPath 
11311  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11312  *                     | AbbreviatedAbsoluteLocationPath 
11313  *  [10]   AbbreviatedAbsoluteLocationPath ::=   
11314  *                           '//' RelativeLocationPath 
11315  *
11316  * Compile a location path
11317  *
11318  * // is short for /descendant-or-self::node()/. For example,
11319  * //para is short for /descendant-or-self::node()/child::para and
11320  * so will select any para element in the document (even a para element
11321  * that is a document element will be selected by //para since the
11322  * document element node is a child of the root node); div//para is
11323  * short for div/descendant-or-self::node()/child::para and so will
11324  * select all para descendants of div children.
11325  */
11326 static void
11327 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11328     SKIP_BLANKS;
11329     if (CUR != '/') {
11330         xmlXPathCompRelativeLocationPath(ctxt);
11331     } else {
11332         while (CUR == '/') {
11333             if ((CUR == '/') && (NXT(1) == '/')) {
11334                 SKIP(2);
11335                 SKIP_BLANKS;
11336                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11337                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11338                 xmlXPathCompRelativeLocationPath(ctxt);
11339             } else if (CUR == '/') {
11340                 NEXT;
11341                 SKIP_BLANKS;
11342                 if ((CUR != 0 ) &&
11343                     ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11344                      (CUR == '@') || (CUR == '*')))
11345                     xmlXPathCompRelativeLocationPath(ctxt);
11346             }
11347         }
11348     }
11349 }
11350
11351 /************************************************************************
11352  *                                                                      *
11353  *              XPath precompiled expression evaluation                 *
11354  *                                                                      *
11355  ************************************************************************/
11356
11357 static int
11358 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11359
11360 #ifdef DEBUG_STEP
11361 static void
11362 xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11363                           xmlXPathTestVal test,
11364                           int nbNodes)
11365 {
11366     xmlGenericError(xmlGenericErrorContext, "new step : ");
11367     switch (axis) {
11368         case AXIS_ANCESTOR:
11369             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11370             break;
11371         case AXIS_ANCESTOR_OR_SELF:
11372             xmlGenericError(xmlGenericErrorContext,
11373                             "axis 'ancestors-or-self' ");
11374             break;
11375         case AXIS_ATTRIBUTE:
11376             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11377             break;
11378         case AXIS_CHILD:
11379             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11380             break;
11381         case AXIS_DESCENDANT:
11382             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11383             break;
11384         case AXIS_DESCENDANT_OR_SELF:
11385             xmlGenericError(xmlGenericErrorContext,
11386                             "axis 'descendant-or-self' ");
11387             break;
11388         case AXIS_FOLLOWING:
11389             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11390             break;
11391         case AXIS_FOLLOWING_SIBLING:
11392             xmlGenericError(xmlGenericErrorContext,
11393                             "axis 'following-siblings' ");
11394             break;
11395         case AXIS_NAMESPACE:
11396             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11397             break;
11398         case AXIS_PARENT:
11399             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11400             break;
11401         case AXIS_PRECEDING:
11402             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11403             break;
11404         case AXIS_PRECEDING_SIBLING:
11405             xmlGenericError(xmlGenericErrorContext,
11406                             "axis 'preceding-sibling' ");
11407             break;
11408         case AXIS_SELF:
11409             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11410             break;
11411     }
11412     xmlGenericError(xmlGenericErrorContext,
11413         " context contains %d nodes\n", nbNodes);
11414     switch (test) {
11415         case NODE_TEST_NONE:
11416             xmlGenericError(xmlGenericErrorContext,
11417                             "           searching for none !!!\n");
11418             break;
11419         case NODE_TEST_TYPE:
11420             xmlGenericError(xmlGenericErrorContext,
11421                             "           searching for type %d\n", type);
11422             break;
11423         case NODE_TEST_PI:
11424             xmlGenericError(xmlGenericErrorContext,
11425                             "           searching for PI !!!\n");
11426             break;
11427         case NODE_TEST_ALL:
11428             xmlGenericError(xmlGenericErrorContext,
11429                             "           searching for *\n");
11430             break;
11431         case NODE_TEST_NS:
11432             xmlGenericError(xmlGenericErrorContext,
11433                             "           searching for namespace %s\n",
11434                             prefix);
11435             break;
11436         case NODE_TEST_NAME:
11437             xmlGenericError(xmlGenericErrorContext,
11438                             "           searching for name %s\n", name);
11439             if (prefix != NULL)
11440                 xmlGenericError(xmlGenericErrorContext,
11441                                 "           with namespace %s\n", prefix);
11442             break;
11443     }
11444     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11445 }
11446 #endif /* DEBUG_STEP */
11447
11448 static int
11449 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11450                             xmlXPathStepOpPtr op,
11451                             xmlNodeSetPtr set,
11452                             int contextSize,
11453                             int hasNsNodes)
11454 {
11455     if (op->ch1 != -1) {
11456         xmlXPathCompExprPtr comp = ctxt->comp;
11457         /*
11458         * Process inner predicates first.
11459         */
11460         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11461             /*
11462             * TODO: raise an internal error.
11463             */
11464         }
11465         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11466             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11467         CHECK_ERROR0;
11468         if (contextSize <= 0)
11469             return(0);
11470     }    
11471     if (op->ch2 != -1) {
11472         xmlXPathContextPtr xpctxt = ctxt->context;
11473         xmlNodePtr contextNode, oldContextNode;
11474         xmlDocPtr oldContextDoc;
11475         int i, res, contextPos = 0, newContextSize;
11476         xmlXPathStepOpPtr exprOp;
11477         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11478
11479 #ifdef LIBXML_XPTR_ENABLED
11480         /*
11481         * URGENT TODO: Check the following:
11482         *  We don't expect location sets if evaluating prediates, right?
11483         *  Only filters should expect location sets, right?
11484         */
11485 #endif
11486         /*
11487         * SPEC XPath 1.0:
11488         *  "For each node in the node-set to be filtered, the
11489         *  PredicateExpr is evaluated with that node as the
11490         *  context node, with the number of nodes in the
11491         *  node-set as the context size, and with the proximity
11492         *  position of the node in the node-set with respect to
11493         *  the axis as the context position;"
11494         * @oldset is the node-set" to be filtered.
11495         *
11496         * SPEC XPath 1.0:
11497         *  "only predicates change the context position and
11498         *  context size (see [2.4 Predicates])."
11499         * Example:
11500         *   node-set  context pos
11501         *    nA         1
11502         *    nB         2
11503         *    nC         3
11504         *   After applying predicate [position() > 1] :
11505         *   node-set  context pos
11506         *    nB         1
11507         *    nC         2
11508         */
11509         oldContextNode = xpctxt->node;
11510         oldContextDoc = xpctxt->doc;
11511         /*
11512         * Get the expression of this predicate.
11513         */
11514         exprOp = &ctxt->comp->steps[op->ch2];   
11515         newContextSize = 0;
11516         for (i = 0; i < set->nodeNr; i++) {
11517             if (set->nodeTab[i] == NULL)
11518                 continue;
11519
11520             contextNode = set->nodeTab[i];
11521             xpctxt->node = contextNode;
11522             xpctxt->contextSize = contextSize;
11523             xpctxt->proximityPosition = ++contextPos;
11524             
11525             /*     
11526             * Also set the xpath document in case things like
11527             * key() are evaluated in the predicate.
11528             */
11529             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11530                 (contextNode->doc != NULL))
11531                 xpctxt->doc = contextNode->doc;
11532             /*
11533             * Evaluate the predicate expression with 1 context node
11534             * at a time; this node is packaged into a node set; this
11535             * node set is handed over to the evaluation mechanism.
11536             */
11537             if (contextObj == NULL)
11538                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11539             else
11540                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11541                     contextNode);
11542
11543             valuePush(ctxt, contextObj);
11544
11545             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11546
11547             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11548                 goto evaluation_error;
11549
11550             if (res != 0) {
11551                 newContextSize++;
11552             } else {
11553                 /*
11554                 * Remove the entry from the initial node set.
11555                 */
11556                 set->nodeTab[i] = NULL;
11557                 if (contextNode->type == XML_NAMESPACE_DECL)
11558                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11559             }
11560             if (ctxt->value == contextObj) {
11561                 /*
11562                 * Don't free the temporary XPath object holding the
11563                 * context node, in order to avoid massive recreation
11564                 * inside this loop.
11565                 */
11566                 valuePop(ctxt);
11567                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11568             } else {
11569                 /*
11570                 * TODO: The object was lost in the evaluation machinery.
11571                 *  Can this happen? Maybe in internal-error cases.
11572                 */
11573                 contextObj = NULL;
11574             }
11575         }
11576         goto evaluation_exit;
11577
11578 evaluation_error:       
11579         xmlXPathNodeSetClear(set, hasNsNodes);
11580         newContextSize = 0;
11581
11582 evaluation_exit:
11583         if (contextObj != NULL) {
11584             if (ctxt->value == contextObj)
11585                 valuePop(ctxt);
11586             xmlXPathReleaseObject(xpctxt, contextObj);
11587         }       
11588         if (exprRes != NULL)
11589             xmlXPathReleaseObject(ctxt->context, exprRes);
11590         /*
11591         * Reset/invalidate the context.
11592         */
11593         xpctxt->node = oldContextNode;
11594         xpctxt->doc = oldContextDoc;
11595         xpctxt->contextSize = -1;
11596         xpctxt->proximityPosition = -1;
11597         return(newContextSize);
11598     }
11599     return(contextSize);
11600 }
11601
11602 static int
11603 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11604                                       xmlXPathStepOpPtr op,
11605                                       xmlNodeSetPtr set,
11606                                       int contextSize,
11607                                       int minPos,
11608                                       int maxPos,
11609                                       int hasNsNodes)
11610 {
11611     if (op->ch1 != -1) {
11612         xmlXPathCompExprPtr comp = ctxt->comp;
11613         if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11614             /*
11615             * TODO: raise an internal error.
11616             */
11617         }
11618         contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11619             &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11620         CHECK_ERROR0;
11621         if (contextSize <= 0)
11622             return(0);
11623     }
11624     /*
11625     * Check if the node set contains a sufficient number of nodes for
11626     * the requested range.
11627     */
11628     if (contextSize < minPos) {
11629         xmlXPathNodeSetClear(set, hasNsNodes);
11630         return(0);
11631     }
11632     if (op->ch2 == -1) {
11633         /*
11634         * TODO: Can this ever happen?
11635         */
11636         return (contextSize);
11637     } else {
11638         xmlDocPtr oldContextDoc;
11639         int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11640         xmlXPathStepOpPtr exprOp;
11641         xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11642         xmlNodePtr oldContextNode, contextNode = NULL;
11643         xmlXPathContextPtr xpctxt = ctxt->context;
11644
11645 #ifdef LIBXML_XPTR_ENABLED
11646             /*
11647             * URGENT TODO: Check the following:
11648             *  We don't expect location sets if evaluating prediates, right?
11649             *  Only filters should expect location sets, right?
11650         */
11651 #endif /* LIBXML_XPTR_ENABLED */
11652
11653         /*
11654         * Save old context.
11655         */
11656         oldContextNode = xpctxt->node;
11657         oldContextDoc = xpctxt->doc;
11658         /*
11659         * Get the expression of this predicate.
11660         */
11661         exprOp = &ctxt->comp->steps[op->ch2];
11662         for (i = 0; i < set->nodeNr; i++) {
11663             if (set->nodeTab[i] == NULL)
11664                 continue;
11665
11666             contextNode = set->nodeTab[i];
11667             xpctxt->node = contextNode;
11668             xpctxt->contextSize = contextSize;
11669             xpctxt->proximityPosition = ++contextPos;
11670             
11671             /*
11672             * Initialize the new set.
11673             * Also set the xpath document in case things like
11674             * key() evaluation are attempted on the predicate
11675             */
11676             if ((contextNode->type != XML_NAMESPACE_DECL) &&
11677                 (contextNode->doc != NULL))
11678                 xpctxt->doc = contextNode->doc;
11679             /*
11680             * Evaluate the predicate expression with 1 context node
11681             * at a time; this node is packaged into a node set; this
11682             * node set is handed over to the evaluation mechanism.
11683             */
11684             if (contextObj == NULL)
11685                 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11686             else
11687                 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11688                     contextNode);
11689
11690             valuePush(ctxt, contextObj);
11691             res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11692             
11693             if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11694                 goto evaluation_error;
11695
11696             if (res)
11697                 pos++;
11698
11699             if (res && (pos >= minPos) && (pos <= maxPos)) {
11700                 /*
11701                 * Fits in the requested range.
11702                 */
11703                 newContextSize++;
11704                 if (minPos == maxPos) {
11705                     /*
11706                     * Only 1 node was requested.
11707                     */
11708                     if (contextNode->type == XML_NAMESPACE_DECL) {
11709                         /*
11710                         * As always: take care of those nasty
11711                         * namespace nodes.
11712                         */
11713                         set->nodeTab[i] = NULL;
11714                     }
11715                     xmlXPathNodeSetClear(set, hasNsNodes);
11716                     set->nodeNr = 1;
11717                     set->nodeTab[0] = contextNode;                 
11718                     goto evaluation_exit;
11719                 }               
11720                 if (pos == maxPos) {
11721                     /*
11722                     * We are done.
11723                     */
11724                     xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11725                     goto evaluation_exit;
11726                 }
11727             } else {
11728                 /*
11729                 * Remove the entry from the initial node set.
11730                 */
11731                 set->nodeTab[i] = NULL;
11732                 if (contextNode->type == XML_NAMESPACE_DECL)
11733                     xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11734             }
11735             if (exprRes != NULL) {
11736                 xmlXPathReleaseObject(ctxt->context, exprRes);
11737                 exprRes = NULL;
11738             }
11739             if (ctxt->value == contextObj) {
11740                 /*
11741                 * Don't free the temporary XPath object holding the
11742                 * context node, in order to avoid massive recreation
11743                 * inside this loop.
11744                 */
11745                 valuePop(ctxt);
11746                 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11747             } else {
11748                 /*
11749                 * The object was lost in the evaluation machinery.
11750                 * Can this happen? Maybe in case of internal-errors.
11751                 */
11752                 contextObj = NULL;
11753             }
11754         }
11755         goto evaluation_exit;
11756
11757 evaluation_error:
11758         xmlXPathNodeSetClear(set, hasNsNodes);
11759         newContextSize = 0;
11760
11761 evaluation_exit:
11762         if (contextObj != NULL) {
11763             if (ctxt->value == contextObj)
11764                 valuePop(ctxt);
11765             xmlXPathReleaseObject(xpctxt, contextObj);
11766         }
11767         if (exprRes != NULL)
11768             xmlXPathReleaseObject(ctxt->context, exprRes);
11769         /*
11770         * Reset/invalidate the context.
11771         */
11772         xpctxt->node = oldContextNode;
11773         xpctxt->doc = oldContextDoc;
11774         xpctxt->contextSize = -1;
11775         xpctxt->proximityPosition = -1;
11776         return(newContextSize);
11777     }
11778     return(contextSize);
11779 }
11780
11781 static int
11782 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783                             xmlXPathStepOpPtr op,                           
11784                             int *maxPos)
11785 {
11786
11787     xmlXPathStepOpPtr exprOp;
11788
11789     /*
11790     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11791     */
11792     
11793     /*
11794     * If not -1, then ch1 will point to:
11795     * 1) For predicates (XPATH_OP_PREDICATE):
11796     *    - an inner predicate operator
11797     * 2) For filters (XPATH_OP_FILTER):
11798     *    - an inner filter operater OR
11799     *    - an expression selecting the node set.
11800     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11801     */    
11802     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11803         return(0);
11804
11805     if (op->ch2 != -1) {
11806         exprOp = &ctxt->comp->steps[op->ch2];
11807     } else      
11808         return(0);
11809
11810     if ((exprOp != NULL) &&
11811         (exprOp->op == XPATH_OP_VALUE) &&
11812         (exprOp->value4 != NULL) &&
11813         (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11814     {
11815         /*
11816         * We have a "[n]" predicate here.
11817         * TODO: Unfortunately this simplistic test here is not
11818         * able to detect a position() predicate in compound
11819         * expressions like "[@attr = 'a" and position() = 1],
11820         * and even not the usage of position() in
11821         * "[position() = 1]"; thus - obviously - a position-range,
11822         * like it "[position() < 5]", is also not detected.
11823         * Maybe we could rewrite the AST to ease the optimization.
11824         */
11825         *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11826         
11827         if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11828             (float) *maxPos)
11829         {           
11830             return(1);
11831         }
11832     }
11833     return(0);
11834 }
11835
11836 static int
11837 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11838                            xmlXPathStepOpPtr op,
11839                            xmlNodePtr * first, xmlNodePtr * last,
11840                            int toBool)
11841 {
11842
11843 #define XP_TEST_HIT \
11844     if (hasAxisRange != 0) { \
11845         if (++pos == maxPos) { \
11846             addNode(seq, cur); \
11847         goto axis_range_end; } \
11848     } else { \
11849         addNode(seq, cur); \
11850         if (breakOnFirstHit) goto first_hit; }
11851
11852 #define XP_TEST_HIT_NS \
11853     if (hasAxisRange != 0) { \
11854         if (++pos == maxPos) { \
11855             hasNsNodes = 1; \
11856             xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11857         goto axis_range_end; } \
11858     } else { \
11859         hasNsNodes = 1; \
11860         xmlXPathNodeSetAddNs(seq, \
11861         xpctxt->node, (xmlNsPtr) cur); \
11862         if (breakOnFirstHit) goto first_hit; }
11863
11864     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11865     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11866     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11867     const xmlChar *prefix = op->value4;
11868     const xmlChar *name = op->value5;
11869     const xmlChar *URI = NULL;
11870
11871 #ifdef DEBUG_STEP
11872     int nbMatches = 0, prevMatches = 0;
11873 #endif
11874     int total = 0, hasNsNodes = 0;
11875     /* The popped object holding the context nodes */
11876     xmlXPathObjectPtr obj;
11877     /* The set of context nodes for the node tests */
11878     xmlNodeSetPtr contextSeq;
11879     int contextIdx;
11880     xmlNodePtr contextNode;
11881     /* The context node for a compound traversal */
11882     xmlNodePtr outerContextNode;
11883     /* The final resulting node set wrt to all context nodes */
11884     xmlNodeSetPtr outSeq;
11885     /*
11886     * The temporary resulting node set wrt 1 context node.
11887     * Used to feed predicate evaluation.
11888     */
11889     xmlNodeSetPtr seq;
11890     xmlNodePtr cur;    
11891     /* First predicate operator */
11892     xmlXPathStepOpPtr predOp;
11893     int maxPos; /* The requested position() (when a "[n]" predicate) */
11894     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11895     int breakOnFirstHit;
11896
11897     xmlXPathTraversalFunction next = NULL;
11898     /* compound axis traversal */
11899     xmlXPathTraversalFunctionExt outerNext = NULL;
11900     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11901     xmlXPathNodeSetMergeFunction mergeAndClear;
11902     xmlNodePtr oldContextNode;    
11903     xmlXPathContextPtr xpctxt = ctxt->context;
11904
11905
11906     CHECK_TYPE0(XPATH_NODESET);
11907     obj = valuePop(ctxt);
11908     /*
11909     * Setup namespaces.
11910     */
11911     if (prefix != NULL) {
11912         URI = xmlXPathNsLookup(xpctxt, prefix);
11913         if (URI == NULL) {
11914             xmlXPathReleaseObject(xpctxt, obj);
11915             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11916         }
11917     }    
11918     /*
11919     * Setup axis.
11920     *
11921     * MAYBE FUTURE TODO: merging optimizations:
11922     * - If the nodes to be traversed wrt to the initial nodes and
11923     *   the current axis cannot overlap, then we could avoid searching
11924     *   for duplicates during the merge.
11925     *   But the question is how/when to evaluate if they cannot overlap.
11926     *   Example: if we know that for two initial nodes, the one is
11927     *   not in the ancestor-or-self axis of the other, then we could safely
11928     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11929     *   the descendant-or-self axis.
11930     */
11931     addNode = xmlXPathNodeSetAdd;
11932     mergeAndClear = xmlXPathNodeSetMergeAndClear;
11933     switch (axis) {
11934         case AXIS_ANCESTOR:
11935             first = NULL;
11936             next = xmlXPathNextAncestor;
11937             break;
11938         case AXIS_ANCESTOR_OR_SELF:
11939             first = NULL;
11940             next = xmlXPathNextAncestorOrSelf;
11941             break;
11942         case AXIS_ATTRIBUTE:
11943             first = NULL;
11944             last = NULL;
11945             next = xmlXPathNextAttribute;
11946             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11947             break;
11948         case AXIS_CHILD:
11949             last = NULL;
11950             if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11951                 /*
11952                 * This iterator will give us only nodes which can
11953                 * hold element nodes.
11954                 */
11955                 outerNext = xmlXPathNextDescendantOrSelfElemParent;             
11956             }       
11957             if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11958                 (type == NODE_TYPE_NODE))
11959             {
11960                 /*
11961                 * Optimization if an element node type is 'element'.
11962                 */
11963                 next = xmlXPathNextChildElement;
11964             } else
11965                 next = xmlXPathNextChild;
11966             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11967             break;
11968         case AXIS_DESCENDANT:
11969             last = NULL;
11970             next = xmlXPathNextDescendant;
11971             break;
11972         case AXIS_DESCENDANT_OR_SELF:
11973             last = NULL;
11974             next = xmlXPathNextDescendantOrSelf;
11975             break;
11976         case AXIS_FOLLOWING:
11977             last = NULL;
11978             next = xmlXPathNextFollowing;
11979             break;
11980         case AXIS_FOLLOWING_SIBLING:
11981             last = NULL;
11982             next = xmlXPathNextFollowingSibling;
11983             break;
11984         case AXIS_NAMESPACE:
11985             first = NULL;
11986             last = NULL;
11987             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11988             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11989             break;
11990         case AXIS_PARENT:
11991             first = NULL;
11992             next = xmlXPathNextParent;
11993             break;
11994         case AXIS_PRECEDING:
11995             first = NULL;
11996             next = xmlXPathNextPrecedingInternal;
11997             break;
11998         case AXIS_PRECEDING_SIBLING:
11999             first = NULL;
12000             next = xmlXPathNextPrecedingSibling;
12001             break;
12002         case AXIS_SELF:
12003             first = NULL;
12004             last = NULL;
12005             next = xmlXPathNextSelf;
12006             mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12007             break;
12008     }
12009
12010 #ifdef DEBUG_STEP
12011     xmlXPathDebugDumpStepAxis(axis, test,
12012         (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12013 #endif
12014
12015     if (next == NULL) {
12016         xmlXPathReleaseObject(xpctxt, obj); 
12017         return(0);
12018     }    
12019     contextSeq = obj->nodesetval;
12020     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12021         xmlXPathReleaseObject(xpctxt, obj);
12022         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12023         return(0);
12024     }   
12025     /*
12026     * Predicate optimization ---------------------------------------------
12027     * If this step has a last predicate, which contains a position(),
12028     * then we'll optimize (although not exactly "position()", but only
12029     * the  short-hand form, i.e., "[n]".
12030     *
12031     * Example - expression "/foo[parent::bar][1]":
12032     *  
12033     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12034     *   ROOT                               -- op->ch1
12035     *   PREDICATE                          -- op->ch2 (predOp)
12036     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12037     *       SORT
12038     *         COLLECT  'parent' 'name' 'node' bar
12039     *           NODE
12040     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12041     *
12042     */
12043     maxPos = 0;
12044     predOp = NULL;
12045     hasPredicateRange = 0;
12046     hasAxisRange = 0;
12047     if (op->ch2 != -1) {
12048         /*
12049         * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12050         */
12051         predOp = &ctxt->comp->steps[op->ch2];
12052         if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12053             if (predOp->ch1 != -1) {
12054                 /*
12055                 * Use the next inner predicate operator.
12056                 */
12057                 predOp = &ctxt->comp->steps[predOp->ch1];
12058                 hasPredicateRange = 1;
12059             } else {
12060                 /*
12061                 * There's no other predicate than the [n] predicate.
12062                 */
12063                 predOp = NULL;
12064                 hasAxisRange = 1;
12065             }       
12066         }
12067     }
12068     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12069     /*
12070     * Axis traversal -----------------------------------------------------
12071     */
12072     /*
12073      * 2.3 Node Tests
12074      *  - For the attribute axis, the principal node type is attribute. 
12075      *  - For the namespace axis, the principal node type is namespace.
12076      *  - For other axes, the principal node type is element.
12077      *
12078      * A node test * is true for any node of the
12079      * principal node type. For example, child::* will
12080      * select all element children of the context node
12081      */
12082     oldContextNode = xpctxt->node;
12083     addNode = xmlXPathNodeSetAddUnique;
12084     outSeq = NULL;
12085     seq = NULL;
12086     outerContextNode = NULL;
12087     contextNode = NULL;
12088     contextIdx = 0;
12089
12090
12091     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12092         if (outerNext != NULL) {
12093             /*
12094             * This is a compound traversal.
12095             */
12096             if (contextNode == NULL) {
12097                 /*
12098                 * Set the context for the outer traversal.
12099                 */
12100                 outerContextNode = contextSeq->nodeTab[contextIdx++];
12101                 contextNode = outerNext(NULL, outerContextNode);
12102             } else
12103                 contextNode = outerNext(contextNode, outerContextNode);
12104             if (contextNode == NULL)
12105                 continue;
12106             /*
12107             * Set the context for the main traversal.
12108             */
12109             xpctxt->node = contextNode;
12110         } else
12111             xpctxt->node = contextSeq->nodeTab[contextIdx++];   
12112         
12113         if (seq == NULL) {
12114             seq = xmlXPathNodeSetCreate(NULL);
12115             if (seq == NULL) {
12116                 total = 0;
12117                 goto error;
12118             }
12119         }
12120         /*
12121         * Traverse the axis and test the nodes.
12122         */
12123         pos = 0;
12124         cur = NULL;
12125         hasNsNodes = 0;
12126         do {
12127             cur = next(ctxt, cur);
12128             if (cur == NULL)
12129                 break;
12130
12131             /*
12132             * QUESTION TODO: What does the "first" and "last" stuff do?
12133             */
12134             if ((first != NULL) && (*first != NULL)) {
12135                 if (*first == cur)
12136                     break;
12137                 if (((total % 256) == 0) &&
12138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12139                     (xmlXPathCmpNodesExt(*first, cur) >= 0))
12140 #else
12141                     (xmlXPathCmpNodes(*first, cur) >= 0))
12142 #endif
12143                 {
12144                     break;
12145                 }
12146             }
12147             if ((last != NULL) && (*last != NULL)) {
12148                 if (*last == cur)
12149                     break;
12150                 if (((total % 256) == 0) &&
12151 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12152                     (xmlXPathCmpNodesExt(cur, *last) >= 0))
12153 #else
12154                     (xmlXPathCmpNodes(cur, *last) >= 0))
12155 #endif
12156                 {
12157                     break;
12158                 }
12159             }
12160
12161             total++;
12162
12163 #ifdef DEBUG_STEP
12164             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12165 #endif
12166             switch (test) {
12167                 case NODE_TEST_NONE:
12168                     total = 0;
12169                     STRANGE
12170                     goto error;
12171                 case NODE_TEST_TYPE:
12172                     /*
12173                     * TODO: Don't we need to use
12174                     *  xmlXPathNodeSetAddNs() for namespace nodes here?
12175                     *  Surprisingly, some c14n tests fail, if we do this.
12176                     */
12177                     if (type == NODE_TYPE_NODE) {
12178                         switch (cur->type) {
12179                             case XML_DOCUMENT_NODE:
12180                             case XML_HTML_DOCUMENT_NODE:
12181 #ifdef LIBXML_DOCB_ENABLED
12182                             case XML_DOCB_DOCUMENT_NODE:
12183 #endif
12184                             case XML_ELEMENT_NODE:                          
12185                             case XML_ATTRIBUTE_NODE:
12186                             case XML_PI_NODE:
12187                             case XML_COMMENT_NODE:
12188                             case XML_CDATA_SECTION_NODE:
12189                             case XML_TEXT_NODE:
12190                             case XML_NAMESPACE_DECL:
12191                                 XP_TEST_HIT
12192                                 break;
12193                             default:
12194                                 break;
12195                         }
12196                     } else if (cur->type == type) {
12197                         if (type == XML_NAMESPACE_DECL)
12198                             XP_TEST_HIT_NS
12199                         else
12200                             XP_TEST_HIT
12201                     } else if ((type == NODE_TYPE_TEXT) &&
12202                          (cur->type == XML_CDATA_SECTION_NODE))
12203                     {
12204                         XP_TEST_HIT
12205                     }
12206                     break;
12207                 case NODE_TEST_PI:
12208                     if ((cur->type == XML_PI_NODE) &&
12209                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12210                     {
12211                         XP_TEST_HIT
12212                     }
12213                     break;
12214                 case NODE_TEST_ALL:
12215                     if (axis == AXIS_ATTRIBUTE) {
12216                         if (cur->type == XML_ATTRIBUTE_NODE)
12217                         {
12218                             XP_TEST_HIT
12219                         }
12220                     } else if (axis == AXIS_NAMESPACE) {
12221                         if (cur->type == XML_NAMESPACE_DECL)
12222                         {
12223                             XP_TEST_HIT_NS
12224                         }
12225                     } else {
12226                         if (cur->type == XML_ELEMENT_NODE) {
12227                             if (prefix == NULL)
12228                             {
12229                                 XP_TEST_HIT
12230
12231                             } else if ((cur->ns != NULL) &&
12232                                 (xmlStrEqual(URI, cur->ns->href)))
12233                             {
12234                                 XP_TEST_HIT
12235                             }
12236                         }
12237                     }
12238                     break;
12239                 case NODE_TEST_NS:{
12240                         TODO;
12241                         break;
12242                     }
12243                 case NODE_TEST_NAME:
12244                     switch (cur->type) {
12245                         case XML_ELEMENT_NODE:
12246                             if (xmlStrEqual(name, cur->name)) {
12247                                 if (prefix == NULL) {
12248                                     if (cur->ns == NULL)
12249                                     {
12250                                         XP_TEST_HIT
12251                                     }
12252                                 } else {
12253                                     if ((cur->ns != NULL) &&
12254                                         (xmlStrEqual(URI, cur->ns->href)))
12255                                     {
12256                                         XP_TEST_HIT
12257                                     }
12258                                 }
12259                             }
12260                             break;
12261                         case XML_ATTRIBUTE_NODE:{
12262                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12263
12264                                 if (xmlStrEqual(name, attr->name)) {
12265                                     if (prefix == NULL) {
12266                                         if ((attr->ns == NULL) ||
12267                                             (attr->ns->prefix == NULL))
12268                                         {
12269                                             XP_TEST_HIT
12270                                         }
12271                                     } else {
12272                                         if ((attr->ns != NULL) &&
12273                                             (xmlStrEqual(URI,
12274                                               attr->ns->href)))
12275                                         {
12276                                             XP_TEST_HIT
12277                                         }
12278                                     }
12279                                 }
12280                                 break;
12281                             }
12282                         case XML_NAMESPACE_DECL:
12283                             if (cur->type == XML_NAMESPACE_DECL) {
12284                                 xmlNsPtr ns = (xmlNsPtr) cur;
12285
12286                                 if ((ns->prefix != NULL) && (name != NULL)
12287                                     && (xmlStrEqual(ns->prefix, name)))
12288                                 {
12289                                     XP_TEST_HIT_NS
12290                                 }
12291                             }
12292                             break;
12293                         default:
12294                             break;
12295                     }
12296                     break;
12297             } /* switch(test) */
12298         } while (cur != NULL);
12299
12300         goto apply_predicates;
12301
12302 axis_range_end: /* ----------------------------------------------------- */     
12303         /*
12304         * We have a "/foo[n]", and position() = n was reached.
12305         * Note that we can have as well "/foo/::parent::foo[1]", so
12306         * a duplicate-aware merge is still needed.
12307         * Merge with the result.
12308         */
12309         if (outSeq == NULL) {
12310             outSeq = seq;
12311             seq = NULL;
12312         } else
12313             outSeq = mergeAndClear(outSeq, seq, 0);
12314         /*
12315         * Break if only a true/false result was requested.
12316         */
12317         if (toBool)
12318             break;
12319         continue;
12320
12321 first_hit: /* ---------------------------------------------------------- */
12322         /*
12323         * Break if only a true/false result was requested and
12324         * no predicates existed and a node test succeeded.
12325         */
12326         if (outSeq == NULL) {
12327             outSeq = seq;
12328             seq = NULL;
12329         } else
12330             outSeq = mergeAndClear(outSeq, seq, 0);
12331         break;
12332
12333 #ifdef DEBUG_STEP
12334         if (seq != NULL)
12335             nbMatches += seq->nodeNr;
12336 #endif
12337
12338 apply_predicates: /* --------------------------------------------------- */
12339         /*
12340         * Apply predicates.
12341         */      
12342         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12343             /*
12344             * E.g. when we have a "/foo[some expression][n]".
12345             */              
12346             /*
12347             * QUESTION TODO: The old predicate evaluation took into
12348             *  account location-sets.
12349             *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12350             *  Do we expect such a set here?
12351             *  All what I learned now from the evaluation semantics
12352             *  does not indicate that a location-set will be processed
12353             *  here, so this looks OK.
12354             */              
12355             /*
12356             * Iterate over all predicates, starting with the outermost
12357             * predicate.
12358             * TODO: Problem: we cannot execute the inner predicates first
12359             *  since we cannot go back *up* the operator tree!
12360             *  Options we have:
12361             *  1) Use of recursive functions (like is it currently done
12362             *     via xmlXPathCompOpEval())
12363             *  2) Add a predicate evaluation information stack to the
12364             *     context struct
12365             *  3) Change the way the operators are linked; we need a
12366             *     "parent" field on xmlXPathStepOp
12367             *
12368             * For the moment, I'll try to solve this with a recursive
12369             * function: xmlXPathCompOpEvalPredicate().
12370             */      
12371             size = seq->nodeNr;
12372             if (hasPredicateRange != 0)
12373                 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12374                     predOp, seq, size, maxPos, maxPos, hasNsNodes);
12375             else
12376                 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12377                     predOp, seq, size, hasNsNodes);
12378
12379             if (ctxt->error != XPATH_EXPRESSION_OK) {
12380                 total = 0;
12381                 goto error;
12382             }
12383             /*
12384             * Add the filtered set of nodes to the result node set.
12385             */
12386             if (newSize == 0) {
12387                 /*
12388                 * The predicates filtered all nodes out.
12389                 */
12390                 xmlXPathNodeSetClear(seq, hasNsNodes);
12391             } else if (seq->nodeNr > 0) {
12392                 /*
12393                 * Add to result set.
12394                 */
12395                 if (outSeq == NULL) {
12396                     if (size != newSize) {
12397                         /*
12398                         * We need to merge and clear here, since
12399                         * the sequence will contained NULLed entries.
12400                         */
12401                         outSeq = mergeAndClear(NULL, seq, 1);
12402                     } else {
12403                         outSeq = seq;
12404                         seq = NULL;
12405                     }
12406                 } else
12407                     outSeq = mergeAndClear(outSeq, seq,
12408                         (size != newSize) ? 1: 0);
12409                 /*
12410                 * Break if only a true/false result was requested.
12411                 */
12412                 if (toBool)
12413                     break;
12414             }
12415         } else if (seq->nodeNr > 0) {
12416             /*
12417             * Add to result set.
12418             */
12419             if (outSeq == NULL) {
12420                 outSeq = seq;
12421                 seq = NULL;
12422             } else {
12423                 outSeq = mergeAndClear(outSeq, seq, 0);
12424             }
12425         }       
12426     }
12427
12428 error:
12429     if ((obj->boolval) && (obj->user != NULL)) {
12430         /*
12431         * QUESTION TODO: What does this do and why?
12432         * TODO: Do we have to do this also for the "error"
12433         * cleanup further down?
12434         */
12435         ctxt->value->boolval = 1;
12436         ctxt->value->user = obj->user;
12437         obj->user = NULL;
12438         obj->boolval = 0;
12439     }
12440     xmlXPathReleaseObject(xpctxt, obj);
12441
12442     /*
12443     * Ensure we return at least an emtpy set.
12444     */
12445     if (outSeq == NULL) {
12446         if ((seq != NULL) && (seq->nodeNr == 0))
12447             outSeq = seq;
12448         else
12449             outSeq = xmlXPathNodeSetCreate(NULL);
12450     }
12451     if ((seq != NULL) && (seq != outSeq)) {
12452          xmlXPathFreeNodeSet(seq);
12453     }    
12454     /*
12455     * Hand over the result. Better to push the set also in
12456     * case of errors.
12457     */
12458     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12459     /*
12460     * Reset the context node.
12461     */
12462     xpctxt->node = oldContextNode;
12463
12464 #ifdef DEBUG_STEP
12465     xmlGenericError(xmlGenericErrorContext,
12466         "\nExamined %d nodes, found %d nodes at that step\n",
12467         total, nbMatches);
12468 #endif
12469
12470     return(total);
12471 }
12472
12473 static int
12474 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12475                               xmlXPathStepOpPtr op, xmlNodePtr * first);
12476
12477 /**
12478  * xmlXPathCompOpEvalFirst:
12479  * @ctxt:  the XPath parser context with the compiled expression
12480  * @op:  an XPath compiled operation
12481  * @first:  the first elem found so far
12482  *
12483  * Evaluate the Precompiled XPath operation searching only the first
12484  * element in document order
12485  *
12486  * Returns the number of examined objects.
12487  */
12488 static int
12489 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12490                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12491 {
12492     int total = 0, cur;
12493     xmlXPathCompExprPtr comp;
12494     xmlXPathObjectPtr arg1, arg2;
12495
12496     CHECK_ERROR0;
12497     comp = ctxt->comp;
12498     switch (op->op) {
12499         case XPATH_OP_END:
12500             return (0);
12501         case XPATH_OP_UNION:
12502             total =
12503                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12504                                         first);
12505             CHECK_ERROR0;
12506             if ((ctxt->value != NULL)
12507                 && (ctxt->value->type == XPATH_NODESET)
12508                 && (ctxt->value->nodesetval != NULL)
12509                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12510                 /*
12511                  * limit tree traversing to first node in the result
12512                  */
12513                 /*
12514                 * OPTIMIZE TODO: This implicitely sorts
12515                 *  the result, even if not needed. E.g. if the argument
12516                 *  of the count() function, no sorting is needed.
12517                 * OPTIMIZE TODO: How do we know if the node-list wasn't
12518                 *  aready sorted?
12519                 */
12520                 if (ctxt->value->nodesetval->nodeNr > 1)
12521                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12522                 *first = ctxt->value->nodesetval->nodeTab[0];
12523             }
12524             cur =
12525                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12526                                         first);
12527             CHECK_ERROR0;
12528             CHECK_TYPE0(XPATH_NODESET);
12529             arg2 = valuePop(ctxt);
12530
12531             CHECK_TYPE0(XPATH_NODESET);
12532             arg1 = valuePop(ctxt);
12533
12534             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12535                                                     arg2->nodesetval);
12536             valuePush(ctxt, arg1);
12537             xmlXPathReleaseObject(ctxt->context, arg2);
12538             /* optimizer */
12539             if (total > cur)
12540                 xmlXPathCompSwap(op);
12541             return (total + cur);
12542         case XPATH_OP_ROOT:
12543             xmlXPathRoot(ctxt);
12544             return (0);
12545         case XPATH_OP_NODE:
12546             if (op->ch1 != -1)
12547                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12548             CHECK_ERROR0;
12549             if (op->ch2 != -1)
12550                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12551             CHECK_ERROR0;
12552             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12553                 ctxt->context->node));
12554             return (total);
12555         case XPATH_OP_RESET:
12556             if (op->ch1 != -1)
12557                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12558             CHECK_ERROR0;
12559             if (op->ch2 != -1)
12560                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12561             CHECK_ERROR0;
12562             ctxt->context->node = NULL;
12563             return (total);
12564         case XPATH_OP_COLLECT:{
12565                 if (op->ch1 == -1)
12566                     return (total);
12567
12568                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12569                 CHECK_ERROR0;
12570
12571                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12572                 return (total);
12573             }
12574         case XPATH_OP_VALUE:
12575             valuePush(ctxt,
12576                       xmlXPathCacheObjectCopy(ctxt->context,
12577                         (xmlXPathObjectPtr) op->value4));
12578             return (0);
12579         case XPATH_OP_SORT:
12580             if (op->ch1 != -1)
12581                 total +=
12582                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12583                                             first);
12584             CHECK_ERROR0;
12585             if ((ctxt->value != NULL)
12586                 && (ctxt->value->type == XPATH_NODESET)
12587                 && (ctxt->value->nodesetval != NULL)
12588                 && (ctxt->value->nodesetval->nodeNr > 1))
12589                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12590             return (total);
12591 #ifdef XP_OPTIMIZED_FILTER_FIRST
12592         case XPATH_OP_FILTER:
12593                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12594             return (total);
12595 #endif
12596         default:
12597             return (xmlXPathCompOpEval(ctxt, op));
12598     }
12599 }
12600
12601 /**
12602  * xmlXPathCompOpEvalLast:
12603  * @ctxt:  the XPath parser context with the compiled expression
12604  * @op:  an XPath compiled operation
12605  * @last:  the last elem found so far
12606  *
12607  * Evaluate the Precompiled XPath operation searching only the last
12608  * element in document order
12609  *
12610  * Returns the number of nodes traversed
12611  */
12612 static int
12613 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12614                        xmlNodePtr * last)
12615 {
12616     int total = 0, cur;
12617     xmlXPathCompExprPtr comp;
12618     xmlXPathObjectPtr arg1, arg2;
12619     xmlNodePtr bak;
12620     xmlDocPtr bakd;
12621     int pp;
12622     int cs;
12623
12624     CHECK_ERROR0;
12625     comp = ctxt->comp;
12626     switch (op->op) {
12627         case XPATH_OP_END:
12628             return (0);
12629         case XPATH_OP_UNION:
12630             bakd = ctxt->context->doc;
12631             bak = ctxt->context->node;
12632             pp = ctxt->context->proximityPosition;
12633             cs = ctxt->context->contextSize;
12634             total =
12635                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12636             CHECK_ERROR0;
12637             if ((ctxt->value != NULL)
12638                 && (ctxt->value->type == XPATH_NODESET)
12639                 && (ctxt->value->nodesetval != NULL)
12640                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12641                 /*
12642                  * limit tree traversing to first node in the result
12643                  */
12644                 if (ctxt->value->nodesetval->nodeNr > 1)
12645                     xmlXPathNodeSetSort(ctxt->value->nodesetval);
12646                 *last =
12647                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12648                                                      nodesetval->nodeNr -
12649                                                      1];
12650             }
12651             ctxt->context->doc = bakd;
12652             ctxt->context->node = bak;
12653             ctxt->context->proximityPosition = pp;
12654             ctxt->context->contextSize = cs;
12655             cur =
12656                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12657             CHECK_ERROR0;
12658             if ((ctxt->value != NULL)
12659                 && (ctxt->value->type == XPATH_NODESET)
12660                 && (ctxt->value->nodesetval != NULL)
12661                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12662             }
12663             CHECK_TYPE0(XPATH_NODESET);
12664             arg2 = valuePop(ctxt);
12665
12666             CHECK_TYPE0(XPATH_NODESET);
12667             arg1 = valuePop(ctxt);
12668
12669             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12670                                                     arg2->nodesetval);
12671             valuePush(ctxt, arg1);
12672             xmlXPathReleaseObject(ctxt->context, arg2);
12673             /* optimizer */
12674             if (total > cur)
12675                 xmlXPathCompSwap(op);
12676             return (total + cur);
12677         case XPATH_OP_ROOT:
12678             xmlXPathRoot(ctxt);
12679             return (0);
12680         case XPATH_OP_NODE:
12681             if (op->ch1 != -1)
12682                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12683             CHECK_ERROR0;
12684             if (op->ch2 != -1)
12685                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12686             CHECK_ERROR0;
12687             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12688                 ctxt->context->node));
12689             return (total);
12690         case XPATH_OP_RESET:
12691             if (op->ch1 != -1)
12692                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693             CHECK_ERROR0;
12694             if (op->ch2 != -1)
12695                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696             CHECK_ERROR0;
12697             ctxt->context->node = NULL;
12698             return (total);
12699         case XPATH_OP_COLLECT:{
12700                 if (op->ch1 == -1)
12701                     return (0);
12702
12703                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12704                 CHECK_ERROR0;
12705
12706                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12707                 return (total);
12708             }
12709         case XPATH_OP_VALUE:
12710             valuePush(ctxt,
12711                       xmlXPathCacheObjectCopy(ctxt->context,
12712                         (xmlXPathObjectPtr) op->value4));
12713             return (0);
12714         case XPATH_OP_SORT:
12715             if (op->ch1 != -1)
12716                 total +=
12717                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12718                                            last);
12719             CHECK_ERROR0;
12720             if ((ctxt->value != NULL)
12721                 && (ctxt->value->type == XPATH_NODESET)
12722                 && (ctxt->value->nodesetval != NULL)
12723                 && (ctxt->value->nodesetval->nodeNr > 1))
12724                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12725             return (total);
12726         default:
12727             return (xmlXPathCompOpEval(ctxt, op));
12728     }
12729 }
12730
12731 #ifdef XP_OPTIMIZED_FILTER_FIRST
12732 static int
12733 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12734                               xmlXPathStepOpPtr op, xmlNodePtr * first)
12735 {
12736     int total = 0;
12737     xmlXPathCompExprPtr comp;    
12738     xmlXPathObjectPtr res;
12739     xmlXPathObjectPtr obj;    
12740     xmlNodeSetPtr oldset;
12741     xmlNodePtr oldnode;
12742     xmlDocPtr oldDoc;
12743     int i;
12744
12745     CHECK_ERROR0;
12746     comp = ctxt->comp;
12747     /*
12748     * Optimization for ()[last()] selection i.e. the last elem
12749     */
12750     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12751         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12752         (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12753         int f = comp->steps[op->ch2].ch1;
12754         
12755         if ((f != -1) &&
12756             (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12757             (comp->steps[f].value5 == NULL) &&
12758             (comp->steps[f].value == 0) &&
12759             (comp->steps[f].value4 != NULL) &&
12760             (xmlStrEqual
12761             (comp->steps[f].value4, BAD_CAST "last"))) {
12762             xmlNodePtr last = NULL;
12763             
12764             total +=
12765                 xmlXPathCompOpEvalLast(ctxt,
12766                     &comp->steps[op->ch1],
12767                     &last);
12768             CHECK_ERROR0;
12769             /*
12770             * The nodeset should be in document order,
12771             * Keep only the last value
12772             */
12773             if ((ctxt->value != NULL) &&
12774                 (ctxt->value->type == XPATH_NODESET) &&
12775                 (ctxt->value->nodesetval != NULL) &&
12776                 (ctxt->value->nodesetval->nodeTab != NULL) &&
12777                 (ctxt->value->nodesetval->nodeNr > 1)) {
12778                 ctxt->value->nodesetval->nodeTab[0] =
12779                     ctxt->value->nodesetval->nodeTab[ctxt->
12780                     value->
12781                     nodesetval->
12782                     nodeNr -
12783                     1];
12784                 ctxt->value->nodesetval->nodeNr = 1;
12785                 *first = *(ctxt->value->nodesetval->nodeTab);
12786             }
12787             return (total);
12788         }
12789     }
12790     
12791     if (op->ch1 != -1)
12792         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793     CHECK_ERROR0;
12794     if (op->ch2 == -1)
12795         return (total);
12796     if (ctxt->value == NULL)
12797         return (total);
12798     
12799 #ifdef LIBXML_XPTR_ENABLED
12800     oldnode = ctxt->context->node;
12801     /*
12802     * Hum are we filtering the result of an XPointer expression
12803     */
12804     if (ctxt->value->type == XPATH_LOCATIONSET) {
12805         xmlXPathObjectPtr tmp = NULL;
12806         xmlLocationSetPtr newlocset = NULL;
12807         xmlLocationSetPtr oldlocset;
12808         
12809         /*
12810         * Extract the old locset, and then evaluate the result of the
12811         * expression for all the element in the locset. use it to grow
12812         * up a new locset.
12813         */
12814         CHECK_TYPE0(XPATH_LOCATIONSET);
12815         obj = valuePop(ctxt);
12816         oldlocset = obj->user;
12817         ctxt->context->node = NULL;
12818         
12819         if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12820             ctxt->context->contextSize = 0;
12821             ctxt->context->proximityPosition = 0;
12822             if (op->ch2 != -1)
12823                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824             res = valuePop(ctxt);
12825             if (res != NULL) {
12826                 xmlXPathReleaseObject(ctxt->context, res);
12827             }
12828             valuePush(ctxt, obj);
12829             CHECK_ERROR0;
12830             return (total);
12831         }
12832         newlocset = xmlXPtrLocationSetCreate(NULL);
12833         
12834         for (i = 0; i < oldlocset->locNr; i++) {
12835             /*
12836             * Run the evaluation with a node list made of a
12837             * single item in the nodelocset.
12838             */
12839             ctxt->context->node = oldlocset->locTab[i]->user;
12840             ctxt->context->contextSize = oldlocset->locNr;
12841             ctxt->context->proximityPosition = i + 1;
12842             if (tmp == NULL) {
12843                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12844                     ctxt->context->node);
12845             } else {
12846                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12847                     ctxt->context->node);
12848             }       
12849             valuePush(ctxt, tmp);
12850             if (op->ch2 != -1)
12851                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12852             if (ctxt->error != XPATH_EXPRESSION_OK) {
12853                 xmlXPathFreeObject(obj);
12854                 return(0);
12855             }
12856             /*
12857             * The result of the evaluation need to be tested to
12858             * decided whether the filter succeeded or not
12859             */
12860             res = valuePop(ctxt);
12861             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12862                 xmlXPtrLocationSetAdd(newlocset,
12863                     xmlXPathCacheObjectCopy(ctxt->context,
12864                         oldlocset->locTab[i]));
12865             }
12866             /*
12867             * Cleanup
12868             */
12869             if (res != NULL) {
12870                 xmlXPathReleaseObject(ctxt->context, res);
12871             }
12872             if (ctxt->value == tmp) {
12873                 valuePop(ctxt);
12874                 xmlXPathNodeSetClear(tmp->nodesetval, 1);               
12875                 /*
12876                 * REVISIT TODO: Don't create a temporary nodeset
12877                 * for everly iteration.
12878                 */
12879                 /* OLD: xmlXPathFreeObject(res); */
12880             } else
12881                 tmp = NULL;         
12882             ctxt->context->node = NULL;
12883             /*
12884             * Only put the first node in the result, then leave.
12885             */
12886             if (newlocset->locNr > 0) {
12887                 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12888                 break;
12889             }
12890         }
12891         if (tmp != NULL) {
12892             xmlXPathReleaseObject(ctxt->context, tmp);
12893         }
12894         /*
12895         * The result is used as the new evaluation locset.
12896         */
12897         xmlXPathReleaseObject(ctxt->context, obj);
12898         ctxt->context->node = NULL;
12899         ctxt->context->contextSize = -1;
12900         ctxt->context->proximityPosition = -1;
12901         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12902         ctxt->context->node = oldnode;
12903         return (total);
12904     }
12905 #endif /* LIBXML_XPTR_ENABLED */
12906     
12907     /*
12908     * Extract the old set, and then evaluate the result of the
12909     * expression for all the element in the set. use it to grow
12910     * up a new set.
12911     */
12912     CHECK_TYPE0(XPATH_NODESET);
12913     obj = valuePop(ctxt);
12914     oldset = obj->nodesetval;
12915     
12916     oldnode = ctxt->context->node;
12917     oldDoc = ctxt->context->doc;
12918     ctxt->context->node = NULL;
12919     
12920     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12921         ctxt->context->contextSize = 0;
12922         ctxt->context->proximityPosition = 0;
12923         /* QUESTION TODO: Why was this code commented out?
12924             if (op->ch2 != -1)
12925                 total +=
12926                     xmlXPathCompOpEval(ctxt,
12927                         &comp->steps[op->ch2]);
12928             CHECK_ERROR0;
12929             res = valuePop(ctxt);
12930             if (res != NULL)
12931                 xmlXPathFreeObject(res);
12932         */
12933         valuePush(ctxt, obj);
12934         ctxt->context->node = oldnode;
12935         CHECK_ERROR0;
12936     } else {
12937         xmlNodeSetPtr newset;
12938         xmlXPathObjectPtr tmp = NULL;
12939         /*
12940         * Initialize the new set.
12941         * Also set the xpath document in case things like
12942         * key() evaluation are attempted on the predicate
12943         */      
12944         newset = xmlXPathNodeSetCreate(NULL);
12945         
12946         for (i = 0; i < oldset->nodeNr; i++) {
12947             /*
12948             * Run the evaluation with a node list made of
12949             * a single item in the nodeset.
12950             */
12951             ctxt->context->node = oldset->nodeTab[i];
12952             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12953                 (oldset->nodeTab[i]->doc != NULL))
12954                 ctxt->context->doc = oldset->nodeTab[i]->doc;
12955             if (tmp == NULL) {
12956                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12957                     ctxt->context->node);
12958             } else {
12959                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12960                     ctxt->context->node);
12961             }
12962             valuePush(ctxt, tmp);
12963             ctxt->context->contextSize = oldset->nodeNr;
12964             ctxt->context->proximityPosition = i + 1;
12965             if (op->ch2 != -1)
12966                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12967             if (ctxt->error != XPATH_EXPRESSION_OK) {
12968                 xmlXPathFreeNodeSet(newset);
12969                 xmlXPathFreeObject(obj);
12970                 return(0);
12971             }       
12972             /*
12973             * The result of the evaluation needs to be tested to
12974             * decide whether the filter succeeded or not
12975             */
12976             res = valuePop(ctxt);
12977             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12978                 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12979             }       
12980             /*
12981             * Cleanup
12982             */
12983             if (res != NULL) {
12984                 xmlXPathReleaseObject(ctxt->context, res);
12985             }
12986             if (ctxt->value == tmp) {
12987                 valuePop(ctxt);
12988                 /*
12989                 * Don't free the temporary nodeset
12990                 * in order to avoid massive recreation inside this
12991                 * loop.
12992                 */
12993                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12994             } else
12995                 tmp = NULL;
12996             ctxt->context->node = NULL;
12997             /*
12998             * Only put the first node in the result, then leave.
12999             */
13000             if (newset->nodeNr > 0) {
13001                 *first = *(newset->nodeTab);
13002                 break;
13003             }
13004         }
13005         if (tmp != NULL) {
13006             xmlXPathReleaseObject(ctxt->context, tmp);
13007         }
13008         /*
13009         * The result is used as the new evaluation set.
13010         */
13011         xmlXPathReleaseObject(ctxt->context, obj);
13012         ctxt->context->node = NULL;
13013         ctxt->context->contextSize = -1;
13014         ctxt->context->proximityPosition = -1;
13015         /* may want to move this past the '}' later */
13016         ctxt->context->doc = oldDoc;
13017         valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13018     }
13019     ctxt->context->node = oldnode;
13020     return(total);
13021 }
13022 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13023
13024 /**
13025  * xmlXPathCompOpEval:
13026  * @ctxt:  the XPath parser context with the compiled expression
13027  * @op:  an XPath compiled operation
13028  *
13029  * Evaluate the Precompiled XPath operation
13030  * Returns the number of nodes traversed
13031  */
13032 static int
13033 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13034 {
13035     int total = 0;
13036     int equal, ret;
13037     xmlXPathCompExprPtr comp;
13038     xmlXPathObjectPtr arg1, arg2;
13039     xmlNodePtr bak;
13040     xmlDocPtr bakd;
13041     int pp;
13042     int cs;
13043
13044     CHECK_ERROR0;
13045     comp = ctxt->comp;
13046     switch (op->op) {
13047         case XPATH_OP_END:
13048             return (0);
13049         case XPATH_OP_AND:
13050             bakd = ctxt->context->doc;
13051             bak = ctxt->context->node;
13052             pp = ctxt->context->proximityPosition;
13053             cs = ctxt->context->contextSize;
13054             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055             CHECK_ERROR0;
13056             xmlXPathBooleanFunction(ctxt, 1);
13057             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13058                 return (total);
13059             arg2 = valuePop(ctxt);
13060             ctxt->context->doc = bakd;
13061             ctxt->context->node = bak;
13062             ctxt->context->proximityPosition = pp;
13063             ctxt->context->contextSize = cs;
13064             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13065             if (ctxt->error) {
13066                 xmlXPathFreeObject(arg2);
13067                 return(0);
13068             }
13069             xmlXPathBooleanFunction(ctxt, 1);
13070             arg1 = valuePop(ctxt);
13071             arg1->boolval &= arg2->boolval;
13072             valuePush(ctxt, arg1);
13073             xmlXPathReleaseObject(ctxt->context, arg2);
13074             return (total);
13075         case XPATH_OP_OR:
13076             bakd = ctxt->context->doc;
13077             bak = ctxt->context->node;
13078             pp = ctxt->context->proximityPosition;
13079             cs = ctxt->context->contextSize;
13080             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081             CHECK_ERROR0;
13082             xmlXPathBooleanFunction(ctxt, 1);
13083             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13084                 return (total);
13085             arg2 = valuePop(ctxt);
13086             ctxt->context->doc = bakd;
13087             ctxt->context->node = bak;
13088             ctxt->context->proximityPosition = pp;
13089             ctxt->context->contextSize = cs;
13090             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13091             if (ctxt->error) {
13092                 xmlXPathFreeObject(arg2);
13093                 return(0);
13094             }
13095             xmlXPathBooleanFunction(ctxt, 1);
13096             arg1 = valuePop(ctxt);
13097             arg1->boolval |= arg2->boolval;
13098             valuePush(ctxt, arg1);
13099             xmlXPathReleaseObject(ctxt->context, arg2);
13100             return (total);
13101         case XPATH_OP_EQUAL:
13102             bakd = ctxt->context->doc;
13103             bak = ctxt->context->node;
13104             pp = ctxt->context->proximityPosition;
13105             cs = ctxt->context->contextSize;
13106             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13107             CHECK_ERROR0;
13108             ctxt->context->doc = bakd;
13109             ctxt->context->node = bak;
13110             ctxt->context->proximityPosition = pp;
13111             ctxt->context->contextSize = cs;
13112             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113             CHECK_ERROR0;
13114             if (op->value)
13115                 equal = xmlXPathEqualValues(ctxt);
13116             else
13117                 equal = xmlXPathNotEqualValues(ctxt);
13118             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13119             return (total);
13120         case XPATH_OP_CMP:
13121             bakd = ctxt->context->doc;
13122             bak = ctxt->context->node;
13123             pp = ctxt->context->proximityPosition;
13124             cs = ctxt->context->contextSize;
13125             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13126             CHECK_ERROR0;
13127             ctxt->context->doc = bakd;
13128             ctxt->context->node = bak;
13129             ctxt->context->proximityPosition = pp;
13130             ctxt->context->contextSize = cs;
13131             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13132             CHECK_ERROR0;
13133             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13134             valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13135             return (total);
13136         case XPATH_OP_PLUS:
13137             bakd = ctxt->context->doc;
13138             bak = ctxt->context->node;
13139             pp = ctxt->context->proximityPosition;
13140             cs = ctxt->context->contextSize;
13141             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13142             CHECK_ERROR0;
13143             if (op->ch2 != -1) {
13144                 ctxt->context->doc = bakd;
13145                 ctxt->context->node = bak;
13146                 ctxt->context->proximityPosition = pp;
13147                 ctxt->context->contextSize = cs;
13148                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13149             }
13150             CHECK_ERROR0;
13151             if (op->value == 0)
13152                 xmlXPathSubValues(ctxt);
13153             else if (op->value == 1)
13154                 xmlXPathAddValues(ctxt);
13155             else if (op->value == 2)
13156                 xmlXPathValueFlipSign(ctxt);
13157             else if (op->value == 3) {
13158                 CAST_TO_NUMBER;
13159                 CHECK_TYPE0(XPATH_NUMBER);
13160             }
13161             return (total);
13162         case XPATH_OP_MULT:
13163             bakd = ctxt->context->doc;
13164             bak = ctxt->context->node;
13165             pp = ctxt->context->proximityPosition;
13166             cs = ctxt->context->contextSize;
13167             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13168             CHECK_ERROR0;
13169             ctxt->context->doc = bakd;
13170             ctxt->context->node = bak;
13171             ctxt->context->proximityPosition = pp;
13172             ctxt->context->contextSize = cs;
13173             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13174             CHECK_ERROR0;
13175             if (op->value == 0)
13176                 xmlXPathMultValues(ctxt);
13177             else if (op->value == 1)
13178                 xmlXPathDivValues(ctxt);
13179             else if (op->value == 2)
13180                 xmlXPathModValues(ctxt);
13181             return (total);
13182         case XPATH_OP_UNION:
13183             bakd = ctxt->context->doc;
13184             bak = ctxt->context->node;
13185             pp = ctxt->context->proximityPosition;
13186             cs = ctxt->context->contextSize;
13187             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13188             CHECK_ERROR0;
13189             ctxt->context->doc = bakd;
13190             ctxt->context->node = bak;
13191             ctxt->context->proximityPosition = pp;
13192             ctxt->context->contextSize = cs;
13193             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13194             CHECK_ERROR0;
13195             CHECK_TYPE0(XPATH_NODESET);
13196             arg2 = valuePop(ctxt);
13197
13198             CHECK_TYPE0(XPATH_NODESET);
13199             arg1 = valuePop(ctxt);
13200
13201             if ((arg1->nodesetval == NULL) ||
13202                 ((arg2->nodesetval != NULL) &&
13203                  (arg2->nodesetval->nodeNr != 0)))
13204             {
13205                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13206                                                         arg2->nodesetval);
13207             }
13208
13209             valuePush(ctxt, arg1);
13210             xmlXPathReleaseObject(ctxt->context, arg2);
13211             return (total);
13212         case XPATH_OP_ROOT:
13213             xmlXPathRoot(ctxt);
13214             return (total);
13215         case XPATH_OP_NODE:
13216             if (op->ch1 != -1)
13217                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13218             CHECK_ERROR0;
13219             if (op->ch2 != -1)
13220                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13221             CHECK_ERROR0;
13222             valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13223                 ctxt->context->node));
13224             return (total);
13225         case XPATH_OP_RESET:
13226             if (op->ch1 != -1)
13227                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13228             CHECK_ERROR0;
13229             if (op->ch2 != -1)
13230                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231             CHECK_ERROR0;
13232             ctxt->context->node = NULL;
13233             return (total);
13234         case XPATH_OP_COLLECT:{
13235                 if (op->ch1 == -1)
13236                     return (total);
13237
13238                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13239                 CHECK_ERROR0;
13240
13241                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13242                 return (total);
13243             }
13244         case XPATH_OP_VALUE:
13245             valuePush(ctxt,
13246                       xmlXPathCacheObjectCopy(ctxt->context,
13247                         (xmlXPathObjectPtr) op->value4));
13248             return (total);
13249         case XPATH_OP_VARIABLE:{
13250                 xmlXPathObjectPtr val;
13251
13252                 if (op->ch1 != -1)
13253                     total +=
13254                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13255                 if (op->value5 == NULL) {
13256                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
13257                     if (val == NULL) {
13258                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13259                         return(0);
13260                     }
13261                     valuePush(ctxt, val);
13262                 } else {
13263                     const xmlChar *URI;
13264
13265                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13266                     if (URI == NULL) {
13267                         xmlGenericError(xmlGenericErrorContext,
13268                                         "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13269                                         op->value4, op->value5);
13270                         return (total);
13271                     }
13272                     val = xmlXPathVariableLookupNS(ctxt->context,
13273                                                        op->value4, URI);
13274                     if (val == NULL) {
13275                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13276                         return(0);
13277                     }
13278                     valuePush(ctxt, val);
13279                 }
13280                 return (total);
13281             }
13282         case XPATH_OP_FUNCTION:{
13283                 xmlXPathFunction func;
13284                 const xmlChar *oldFunc, *oldFuncURI;
13285                 int i;
13286
13287                 if (op->ch1 != -1)
13288                     total +=
13289                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13290                 if (ctxt->valueNr < op->value) {
13291                     xmlGenericError(xmlGenericErrorContext,
13292                             "xmlXPathCompOpEval: parameter error\n");
13293                     ctxt->error = XPATH_INVALID_OPERAND;
13294                     return (total);
13295                 }
13296                 for (i = 0; i < op->value; i++)
13297                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13298                         xmlGenericError(xmlGenericErrorContext,
13299                                 "xmlXPathCompOpEval: parameter error\n");
13300                         ctxt->error = XPATH_INVALID_OPERAND;
13301                         return (total);
13302                     }
13303                 if (op->cache != NULL)
13304                     XML_CAST_FPTR(func) = op->cache;
13305                 else {
13306                     const xmlChar *URI = NULL;
13307
13308                     if (op->value5 == NULL)
13309                         func =
13310                             xmlXPathFunctionLookup(ctxt->context,
13311                                                    op->value4);
13312                     else {
13313                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13314                         if (URI == NULL) {
13315                             xmlGenericError(xmlGenericErrorContext,
13316                                             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13317                                             op->value4, op->value5);
13318                             return (total);
13319                         }
13320                         func = xmlXPathFunctionLookupNS(ctxt->context,
13321                                                         op->value4, URI);
13322                     }
13323                     if (func == NULL) {
13324                         xmlGenericError(xmlGenericErrorContext,
13325                                         "xmlXPathCompOpEval: function %s not found\n",
13326                                         op->value4);
13327                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13328                     }
13329                     op->cache = XML_CAST_FPTR(func);
13330                     op->cacheURI = (void *) URI;
13331                 }
13332                 oldFunc = ctxt->context->function;
13333                 oldFuncURI = ctxt->context->functionURI;
13334                 ctxt->context->function = op->value4;
13335                 ctxt->context->functionURI = op->cacheURI;
13336                 func(ctxt, op->value);
13337                 ctxt->context->function = oldFunc;
13338                 ctxt->context->functionURI = oldFuncURI;
13339                 return (total);
13340             }
13341         case XPATH_OP_ARG:
13342             bakd = ctxt->context->doc;
13343             bak = ctxt->context->node;
13344             pp = ctxt->context->proximityPosition;
13345             cs = ctxt->context->contextSize;
13346             if (op->ch1 != -1)
13347                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348             ctxt->context->contextSize = cs;
13349             ctxt->context->proximityPosition = pp;
13350             ctxt->context->node = bak;
13351             ctxt->context->doc = bakd;
13352             CHECK_ERROR0;
13353             if (op->ch2 != -1) {
13354                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13355                 ctxt->context->doc = bakd;
13356                 ctxt->context->node = bak;
13357                 CHECK_ERROR0;
13358             }
13359             return (total);
13360         case XPATH_OP_PREDICATE:
13361         case XPATH_OP_FILTER:{
13362                 xmlXPathObjectPtr res;
13363                 xmlXPathObjectPtr obj, tmp;
13364                 xmlNodeSetPtr newset = NULL;
13365                 xmlNodeSetPtr oldset;
13366                 xmlNodePtr oldnode;
13367                 xmlDocPtr oldDoc;
13368                 int i;
13369
13370                 /*
13371                  * Optimization for ()[1] selection i.e. the first elem
13372                  */
13373                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13374 #ifdef XP_OPTIMIZED_FILTER_FIRST
13375                     /*
13376                     * FILTER TODO: Can we assume that the inner processing
13377                     *  will result in an ordered list if we have an
13378                     *  XPATH_OP_FILTER?
13379                     *  What about an additional field or flag on
13380                     *  xmlXPathObject like @sorted ? This way we wouln'd need
13381                     *  to assume anything, so it would be more robust and
13382                     *  easier to optimize.
13383                     */
13384                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13385                      (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13386 #else
13387                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13388 #endif
13389                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13390                     xmlXPathObjectPtr val;
13391
13392                     val = comp->steps[op->ch2].value4;
13393                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13394                         (val->floatval == 1.0)) {
13395                         xmlNodePtr first = NULL;
13396
13397                         total +=
13398                             xmlXPathCompOpEvalFirst(ctxt,
13399                                                     &comp->steps[op->ch1],
13400                                                     &first);
13401                         CHECK_ERROR0;
13402                         /*
13403                          * The nodeset should be in document order,
13404                          * Keep only the first value
13405                          */
13406                         if ((ctxt->value != NULL) &&
13407                             (ctxt->value->type == XPATH_NODESET) &&
13408                             (ctxt->value->nodesetval != NULL) &&
13409                             (ctxt->value->nodesetval->nodeNr > 1))
13410                             ctxt->value->nodesetval->nodeNr = 1;
13411                         return (total);
13412                     }
13413                 }
13414                 /*
13415                  * Optimization for ()[last()] selection i.e. the last elem
13416                  */
13417                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13418                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13419                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13420                     int f = comp->steps[op->ch2].ch1;
13421
13422                     if ((f != -1) &&
13423                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13424                         (comp->steps[f].value5 == NULL) &&
13425                         (comp->steps[f].value == 0) &&
13426                         (comp->steps[f].value4 != NULL) &&
13427                         (xmlStrEqual
13428                          (comp->steps[f].value4, BAD_CAST "last"))) {
13429                         xmlNodePtr last = NULL;
13430
13431                         total +=
13432                             xmlXPathCompOpEvalLast(ctxt,
13433                                                    &comp->steps[op->ch1],
13434                                                    &last);
13435                         CHECK_ERROR0;
13436                         /*
13437                          * The nodeset should be in document order,
13438                          * Keep only the last value
13439                          */
13440                         if ((ctxt->value != NULL) &&
13441                             (ctxt->value->type == XPATH_NODESET) &&
13442                             (ctxt->value->nodesetval != NULL) &&
13443                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13444                             (ctxt->value->nodesetval->nodeNr > 1)) {
13445                             ctxt->value->nodesetval->nodeTab[0] =
13446                                 ctxt->value->nodesetval->nodeTab[ctxt->
13447                                                                  value->
13448                                                                  nodesetval->
13449                                                                  nodeNr -
13450                                                                  1];
13451                             ctxt->value->nodesetval->nodeNr = 1;
13452                         }
13453                         return (total);
13454                     }
13455                 }
13456                 /*
13457                 * Process inner predicates first.
13458                 * Example "index[parent::book][1]":
13459                 * ...
13460                 *   PREDICATE   <-- we are here "[1]"
13461                 *     PREDICATE <-- process "[parent::book]" first
13462                 *       SORT
13463                 *         COLLECT  'parent' 'name' 'node' book
13464                 *           NODE
13465                 *     ELEM Object is a number : 1
13466                 */
13467                 if (op->ch1 != -1)
13468                     total +=
13469                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13470                 CHECK_ERROR0;
13471                 if (op->ch2 == -1)
13472                     return (total);
13473                 if (ctxt->value == NULL)
13474                     return (total);
13475
13476                 oldnode = ctxt->context->node;
13477
13478 #ifdef LIBXML_XPTR_ENABLED
13479                 /*
13480                  * Hum are we filtering the result of an XPointer expression
13481                  */
13482                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13483                     xmlLocationSetPtr newlocset = NULL;
13484                     xmlLocationSetPtr oldlocset;
13485
13486                     /*
13487                      * Extract the old locset, and then evaluate the result of the
13488                      * expression for all the element in the locset. use it to grow
13489                      * up a new locset.
13490                      */
13491                     CHECK_TYPE0(XPATH_LOCATIONSET);
13492                     obj = valuePop(ctxt);
13493                     oldlocset = obj->user;
13494                     ctxt->context->node = NULL;
13495
13496                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13497                         ctxt->context->contextSize = 0;
13498                         ctxt->context->proximityPosition = 0;
13499                         if (op->ch2 != -1)
13500                             total +=
13501                                 xmlXPathCompOpEval(ctxt,
13502                                                    &comp->steps[op->ch2]);
13503                         res = valuePop(ctxt);
13504                         if (res != NULL) {
13505                             xmlXPathReleaseObject(ctxt->context, res);
13506                         }
13507                         valuePush(ctxt, obj);
13508                         CHECK_ERROR0;
13509                         return (total);
13510                     }
13511                     newlocset = xmlXPtrLocationSetCreate(NULL);
13512
13513                     for (i = 0; i < oldlocset->locNr; i++) {
13514                         /*
13515                          * Run the evaluation with a node list made of a
13516                          * single item in the nodelocset.
13517                          */
13518                         ctxt->context->node = oldlocset->locTab[i]->user;
13519                         ctxt->context->contextSize = oldlocset->locNr;
13520                         ctxt->context->proximityPosition = i + 1;
13521                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13522                             ctxt->context->node);
13523                         valuePush(ctxt, tmp);
13524                         
13525                         if (op->ch2 != -1)
13526                             total +=
13527                                 xmlXPathCompOpEval(ctxt,
13528                                                    &comp->steps[op->ch2]);
13529                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13530                             xmlXPathFreeObject(obj);
13531                             return(0);
13532                         }
13533
13534                         /*
13535                          * The result of the evaluation need to be tested to
13536                          * decided whether the filter succeeded or not
13537                          */
13538                         res = valuePop(ctxt);
13539                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13540                             xmlXPtrLocationSetAdd(newlocset,
13541                                                   xmlXPathObjectCopy
13542                                                   (oldlocset->locTab[i]));
13543                         }
13544
13545                         /*
13546                          * Cleanup
13547                          */
13548                         if (res != NULL) {
13549                             xmlXPathReleaseObject(ctxt->context, res);
13550                         }
13551                         if (ctxt->value == tmp) {
13552                             res = valuePop(ctxt);
13553                             xmlXPathReleaseObject(ctxt->context, res);
13554                         }
13555
13556                         ctxt->context->node = NULL;
13557                     }
13558
13559                     /*
13560                      * The result is used as the new evaluation locset.
13561                      */
13562                     xmlXPathReleaseObject(ctxt->context, obj);
13563                     ctxt->context->node = NULL;
13564                     ctxt->context->contextSize = -1;
13565                     ctxt->context->proximityPosition = -1;
13566                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13567                     ctxt->context->node = oldnode;
13568                     return (total);
13569                 }
13570 #endif /* LIBXML_XPTR_ENABLED */
13571
13572                 /*
13573                  * Extract the old set, and then evaluate the result of the
13574                  * expression for all the element in the set. use it to grow
13575                  * up a new set.
13576                  */
13577                 CHECK_TYPE0(XPATH_NODESET);
13578                 obj = valuePop(ctxt);
13579                 oldset = obj->nodesetval;
13580
13581                 oldnode = ctxt->context->node;
13582                 oldDoc = ctxt->context->doc;
13583                 ctxt->context->node = NULL;
13584
13585                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13586                     ctxt->context->contextSize = 0;
13587                     ctxt->context->proximityPosition = 0;
13588 /*
13589                     if (op->ch2 != -1)
13590                         total +=
13591                             xmlXPathCompOpEval(ctxt,
13592                                                &comp->steps[op->ch2]);
13593                     CHECK_ERROR0;
13594                     res = valuePop(ctxt);
13595                     if (res != NULL)
13596                         xmlXPathFreeObject(res);
13597 */
13598                     valuePush(ctxt, obj);
13599                     ctxt->context->node = oldnode;
13600                     CHECK_ERROR0;
13601                 } else {
13602                     tmp = NULL;
13603                     /*
13604                      * Initialize the new set.
13605                      * Also set the xpath document in case things like
13606                      * key() evaluation are attempted on the predicate
13607                      */
13608                     newset = xmlXPathNodeSetCreate(NULL);
13609                     /*
13610                     * SPEC XPath 1.0:
13611                     *  "For each node in the node-set to be filtered, the
13612                     *  PredicateExpr is evaluated with that node as the
13613                     *  context node, with the number of nodes in the
13614                     *  node-set as the context size, and with the proximity
13615                     *  position of the node in the node-set with respect to
13616                     *  the axis as the context position;"
13617                     * @oldset is the node-set" to be filtered.
13618                     *
13619                     * SPEC XPath 1.0:
13620                     *  "only predicates change the context position and
13621                     *  context size (see [2.4 Predicates])."
13622                     * Example:
13623                     *   node-set  context pos
13624                     *    nA         1
13625                     *    nB         2
13626                     *    nC         3
13627                     *   After applying predicate [position() > 1] :
13628                     *   node-set  context pos
13629                     *    nB         1
13630                     *    nC         2
13631                     *
13632                     * removed the first node in the node-set, then
13633                     * the context position of the 
13634                     */
13635                     for (i = 0; i < oldset->nodeNr; i++) {
13636                         /*
13637                          * Run the evaluation with a node list made of
13638                          * a single item in the nodeset.
13639                          */
13640                         ctxt->context->node = oldset->nodeTab[i];
13641                         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13642                             (oldset->nodeTab[i]->doc != NULL))
13643                             ctxt->context->doc = oldset->nodeTab[i]->doc;
13644                         if (tmp == NULL) {
13645                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13646                                 ctxt->context->node);
13647                         } else {
13648                             xmlXPathNodeSetAddUnique(tmp->nodesetval,
13649                                 ctxt->context->node);
13650                         }
13651                         valuePush(ctxt, tmp);
13652                         ctxt->context->contextSize = oldset->nodeNr;
13653                         ctxt->context->proximityPosition = i + 1;
13654                         /*
13655                         * Evaluate the predicate against the context node.
13656                         * Can/should we optimize position() predicates
13657                         * here (e.g. "[1]")?
13658                         */
13659                         if (op->ch2 != -1)
13660                             total +=
13661                                 xmlXPathCompOpEval(ctxt,
13662                                                    &comp->steps[op->ch2]);
13663                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13664                             xmlXPathFreeNodeSet(newset);
13665                             xmlXPathFreeObject(obj);
13666                             return(0);
13667                         }
13668
13669                         /*
13670                          * The result of the evaluation needs to be tested to
13671                          * decide whether the filter succeeded or not
13672                          */
13673                         /*
13674                         * OPTIMIZE TODO: Can we use
13675                         * xmlXPathNodeSetAdd*Unique()* instead?
13676                         */
13677                         res = valuePop(ctxt);
13678                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13679                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13680                         }
13681
13682                         /*
13683                          * Cleanup
13684                          */
13685                         if (res != NULL) {
13686                             xmlXPathReleaseObject(ctxt->context, res);
13687                         }
13688                         if (ctxt->value == tmp) {
13689                             valuePop(ctxt);
13690                             xmlXPathNodeSetClear(tmp->nodesetval, 1);                       
13691                             /*
13692                             * Don't free the temporary nodeset
13693                             * in order to avoid massive recreation inside this
13694                             * loop.
13695                             */
13696                         } else
13697                             tmp = NULL;
13698                         ctxt->context->node = NULL;
13699                     }
13700                     if (tmp != NULL)
13701                         xmlXPathReleaseObject(ctxt->context, tmp);
13702                     /*
13703                      * The result is used as the new evaluation set.
13704                      */
13705                     xmlXPathReleaseObject(ctxt->context, obj);
13706                     ctxt->context->node = NULL;
13707                     ctxt->context->contextSize = -1;
13708                     ctxt->context->proximityPosition = -1;
13709                     /* may want to move this past the '}' later */
13710                     ctxt->context->doc = oldDoc;
13711                     valuePush(ctxt,
13712                         xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13713                 }
13714                 ctxt->context->node = oldnode;
13715                 return (total);
13716             }
13717         case XPATH_OP_SORT:
13718             if (op->ch1 != -1)
13719                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13720             CHECK_ERROR0;
13721             if ((ctxt->value != NULL) &&
13722                 (ctxt->value->type == XPATH_NODESET) &&
13723                 (ctxt->value->nodesetval != NULL) &&
13724                 (ctxt->value->nodesetval->nodeNr > 1))
13725             {
13726                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13727             }
13728             return (total);
13729 #ifdef LIBXML_XPTR_ENABLED
13730         case XPATH_OP_RANGETO:{
13731                 xmlXPathObjectPtr range;
13732                 xmlXPathObjectPtr res, obj;
13733                 xmlXPathObjectPtr tmp;
13734                 xmlLocationSetPtr newlocset = NULL;
13735                     xmlLocationSetPtr oldlocset;
13736                 xmlNodeSetPtr oldset;
13737                 int i, j;
13738
13739                 if (op->ch1 != -1)
13740                     total +=
13741                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13742                 if (op->ch2 == -1)
13743                     return (total);
13744
13745                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13746                     /*
13747                      * Extract the old locset, and then evaluate the result of the
13748                      * expression for all the element in the locset. use it to grow
13749                      * up a new locset.
13750                      */
13751                     CHECK_TYPE0(XPATH_LOCATIONSET);
13752                     obj = valuePop(ctxt);
13753                     oldlocset = obj->user;
13754
13755                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13756                         ctxt->context->node = NULL;
13757                         ctxt->context->contextSize = 0;
13758                         ctxt->context->proximityPosition = 0;
13759                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13760                         res = valuePop(ctxt);
13761                         if (res != NULL) {
13762                             xmlXPathReleaseObject(ctxt->context, res);
13763                         }
13764                         valuePush(ctxt, obj);
13765                         CHECK_ERROR0;
13766                         return (total);
13767                     }
13768                     newlocset = xmlXPtrLocationSetCreate(NULL);
13769
13770                     for (i = 0; i < oldlocset->locNr; i++) {
13771                         /*
13772                          * Run the evaluation with a node list made of a
13773                          * single item in the nodelocset.
13774                          */
13775                         ctxt->context->node = oldlocset->locTab[i]->user;
13776                         ctxt->context->contextSize = oldlocset->locNr;
13777                         ctxt->context->proximityPosition = i + 1;
13778                         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13779                             ctxt->context->node);
13780                         valuePush(ctxt, tmp);
13781
13782                         if (op->ch2 != -1)
13783                             total +=
13784                                 xmlXPathCompOpEval(ctxt,
13785                                                    &comp->steps[op->ch2]);
13786                         if (ctxt->error != XPATH_EXPRESSION_OK) {
13787                             xmlXPathFreeObject(obj);
13788                             return(0);
13789                         }
13790
13791                         res = valuePop(ctxt);
13792                         if (res->type == XPATH_LOCATIONSET) {
13793                             xmlLocationSetPtr rloc = 
13794                                 (xmlLocationSetPtr)res->user;
13795                             for (j=0; j<rloc->locNr; j++) {
13796                                 range = xmlXPtrNewRange(
13797                                   oldlocset->locTab[i]->user,
13798                                   oldlocset->locTab[i]->index,
13799                                   rloc->locTab[j]->user2,
13800                                   rloc->locTab[j]->index2);
13801                                 if (range != NULL) {
13802                                     xmlXPtrLocationSetAdd(newlocset, range);
13803                                 }
13804                             }
13805                         } else {
13806                             range = xmlXPtrNewRangeNodeObject(
13807                                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13808                             if (range != NULL) {
13809                                 xmlXPtrLocationSetAdd(newlocset,range);
13810                             }
13811                         }
13812
13813                         /*
13814                          * Cleanup
13815                          */
13816                         if (res != NULL) {
13817                             xmlXPathReleaseObject(ctxt->context, res);
13818                         }
13819                         if (ctxt->value == tmp) {
13820                             res = valuePop(ctxt);
13821                             xmlXPathReleaseObject(ctxt->context, res);
13822                         }
13823
13824                         ctxt->context->node = NULL;
13825                     }
13826                 } else {        /* Not a location set */
13827                     CHECK_TYPE0(XPATH_NODESET);
13828                     obj = valuePop(ctxt);
13829                     oldset = obj->nodesetval;
13830                     ctxt->context->node = NULL;
13831
13832                     newlocset = xmlXPtrLocationSetCreate(NULL);
13833
13834                     if (oldset != NULL) {
13835                         for (i = 0; i < oldset->nodeNr; i++) {
13836                             /*
13837                              * Run the evaluation with a node list made of a single item
13838                              * in the nodeset.
13839                              */
13840                             ctxt->context->node = oldset->nodeTab[i];
13841                             /*
13842                             * OPTIMIZE TODO: Avoid recreation for every iteration.
13843                             */
13844                             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13845                                 ctxt->context->node);
13846                             valuePush(ctxt, tmp);
13847
13848                             if (op->ch2 != -1)
13849                                 total +=
13850                                     xmlXPathCompOpEval(ctxt,
13851                                                    &comp->steps[op->ch2]);
13852                             if (ctxt->error != XPATH_EXPRESSION_OK) {
13853                                 xmlXPathFreeObject(obj);
13854                                 return(0);
13855                             }
13856
13857                             res = valuePop(ctxt);
13858                             range =
13859                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13860                                                       res);
13861                             if (range != NULL) {
13862                                 xmlXPtrLocationSetAdd(newlocset, range);
13863                             }
13864
13865                             /*
13866                              * Cleanup
13867                              */
13868                             if (res != NULL) {
13869                                 xmlXPathReleaseObject(ctxt->context, res);
13870                             }
13871                             if (ctxt->value == tmp) {
13872                                 res = valuePop(ctxt);
13873                                 xmlXPathReleaseObject(ctxt->context, res);
13874                             }
13875
13876                             ctxt->context->node = NULL;
13877                         }
13878                     }
13879                 }
13880
13881                 /*
13882                  * The result is used as the new evaluation set.
13883                  */
13884                 xmlXPathReleaseObject(ctxt->context, obj);
13885                 ctxt->context->node = NULL;
13886                 ctxt->context->contextSize = -1;
13887                 ctxt->context->proximityPosition = -1;
13888                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13889                 return (total);
13890             }
13891 #endif /* LIBXML_XPTR_ENABLED */
13892     }
13893     xmlGenericError(xmlGenericErrorContext,
13894                     "XPath: unknown precompiled operation %d\n", op->op);
13895     return (total);
13896 }
13897
13898 /**
13899  * xmlXPathCompOpEvalToBoolean:
13900  * @ctxt:  the XPath parser context
13901  *
13902  * Evaluates if the expression evaluates to true.
13903  *
13904  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13905  */
13906 static int
13907 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13908                             xmlXPathStepOpPtr op,
13909                             int isPredicate)
13910 {
13911     xmlXPathObjectPtr resObj = NULL;
13912
13913 start:
13914     /* comp = ctxt->comp; */
13915     switch (op->op) {
13916         case XPATH_OP_END:
13917             return (0);
13918         case XPATH_OP_VALUE:
13919             resObj = (xmlXPathObjectPtr) op->value4;
13920             if (isPredicate)
13921                 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13922             return(xmlXPathCastToBoolean(resObj));
13923         case XPATH_OP_SORT:
13924             /*
13925             * We don't need sorting for boolean results. Skip this one.
13926             */
13927             if (op->ch1 != -1) {
13928                 op = &ctxt->comp->steps[op->ch1];
13929                 goto start;
13930             }
13931             return(0);
13932         case XPATH_OP_COLLECT:
13933             if (op->ch1 == -1)
13934                 return(0);
13935
13936             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13937             if (ctxt->error != XPATH_EXPRESSION_OK)
13938                 return(-1);
13939
13940             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13941             if (ctxt->error != XPATH_EXPRESSION_OK)
13942                 return(-1);
13943
13944             resObj = valuePop(ctxt);
13945             if (resObj == NULL)
13946                 return(-1);
13947             break;
13948         default:
13949             /*
13950             * Fallback to call xmlXPathCompOpEval().
13951             */
13952             xmlXPathCompOpEval(ctxt, op);
13953             if (ctxt->error != XPATH_EXPRESSION_OK)
13954                 return(-1);
13955             
13956             resObj = valuePop(ctxt);
13957             if (resObj == NULL)
13958                 return(-1);
13959             break;
13960     }
13961
13962     if (resObj) {
13963         int res;
13964
13965         if (resObj->type == XPATH_BOOLEAN) {
13966             res = resObj->boolval;
13967         } else if (isPredicate) {
13968             /*
13969             * For predicates a result of type "number" is handled
13970             * differently:
13971             * SPEC XPath 1.0:
13972             * "If the result is a number, the result will be converted
13973             *  to true if the number is equal to the context position
13974             *  and will be converted to false otherwise;"
13975             */
13976             res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 
13977         } else {
13978             res = xmlXPathCastToBoolean(resObj);
13979         }
13980         xmlXPathReleaseObject(ctxt->context, resObj);
13981         return(res);
13982     }
13983
13984     return(0);
13985 }
13986
13987 #ifdef XPATH_STREAMING
13988 /**
13989  * xmlXPathRunStreamEval:
13990  * @ctxt:  the XPath parser context with the compiled expression
13991  *
13992  * Evaluate the Precompiled Streamable XPath expression in the given context.
13993  */
13994 static int
13995 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13996                       xmlXPathObjectPtr *resultSeq, int toBool)
13997 {
13998     int max_depth, min_depth;
13999     int from_root;    
14000     int ret, depth;
14001     int eval_all_nodes;
14002     xmlNodePtr cur = NULL, limit = NULL;
14003     xmlStreamCtxtPtr patstream = NULL;
14004     
14005     int nb_nodes = 0;    
14006
14007     if ((ctxt == NULL) || (comp == NULL))
14008         return(-1);
14009     max_depth = xmlPatternMaxDepth(comp);
14010     if (max_depth == -1)
14011         return(-1);
14012     if (max_depth == -2)
14013         max_depth = 10000;
14014     min_depth = xmlPatternMinDepth(comp);
14015     if (min_depth == -1)
14016         return(-1);
14017     from_root = xmlPatternFromRoot(comp);
14018     if (from_root < 0)
14019         return(-1);
14020 #if 0
14021     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14022 #endif
14023
14024     if (! toBool) {
14025         if (resultSeq == NULL)
14026             return(-1);
14027         *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14028         if (*resultSeq == NULL)
14029             return(-1);
14030     }
14031     
14032     /*
14033      * handle the special cases of "/" amd "." being matched
14034      */
14035     if (min_depth == 0) {
14036         if (from_root) {
14037             /* Select "/" */
14038             if (toBool)
14039                 return(1);
14040             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14041                 (xmlNodePtr) ctxt->doc);
14042         } else {
14043             /* Select "self::node()" */
14044             if (toBool)
14045                 return(1);
14046             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14047         }
14048     }
14049     if (max_depth == 0) {
14050         return(0);
14051     }
14052
14053     if (from_root) {
14054         cur = (xmlNodePtr)ctxt->doc;
14055     } else if (ctxt->node != NULL) {
14056         switch (ctxt->node->type) {
14057             case XML_ELEMENT_NODE:
14058             case XML_DOCUMENT_NODE:
14059             case XML_DOCUMENT_FRAG_NODE:
14060             case XML_HTML_DOCUMENT_NODE:
14061 #ifdef LIBXML_DOCB_ENABLED
14062             case XML_DOCB_DOCUMENT_NODE:
14063 #endif
14064                 cur = ctxt->node;
14065                 break;
14066             case XML_ATTRIBUTE_NODE:
14067             case XML_TEXT_NODE:
14068             case XML_CDATA_SECTION_NODE:
14069             case XML_ENTITY_REF_NODE:
14070             case XML_ENTITY_NODE:
14071             case XML_PI_NODE:
14072             case XML_COMMENT_NODE:
14073             case XML_NOTATION_NODE:
14074             case XML_DTD_NODE:
14075             case XML_DOCUMENT_TYPE_NODE:
14076             case XML_ELEMENT_DECL:
14077             case XML_ATTRIBUTE_DECL:
14078             case XML_ENTITY_DECL:
14079             case XML_NAMESPACE_DECL:
14080             case XML_XINCLUDE_START:
14081             case XML_XINCLUDE_END:
14082                 break;
14083         }
14084         limit = cur;
14085     }
14086     if (cur == NULL) {
14087         return(0);
14088     }
14089
14090     patstream = xmlPatternGetStreamCtxt(comp);
14091     if (patstream == NULL) {
14092         /*
14093         * QUESTION TODO: Is this an error?
14094         */
14095         return(0);
14096     }
14097
14098     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14099
14100     if (from_root) {
14101         ret = xmlStreamPush(patstream, NULL, NULL);
14102         if (ret < 0) {
14103         } else if (ret == 1) {
14104             if (toBool)
14105                 goto return_1;
14106             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14107         }
14108     }
14109     depth = 0;
14110     goto scan_children;
14111 next_node:
14112     do {
14113         nb_nodes++;
14114
14115         switch (cur->type) {
14116             case XML_ELEMENT_NODE:
14117             case XML_TEXT_NODE:
14118             case XML_CDATA_SECTION_NODE:
14119             case XML_COMMENT_NODE:
14120             case XML_PI_NODE:
14121                 if (cur->type == XML_ELEMENT_NODE) {
14122                     ret = xmlStreamPush(patstream, cur->name,
14123                                 (cur->ns ? cur->ns->href : NULL));
14124                 } else if (eval_all_nodes)
14125                     ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14126                 else
14127                     break;
14128                 
14129                 if (ret < 0) {
14130                     /* NOP. */
14131                 } else if (ret == 1) {
14132                     if (toBool)
14133                         goto return_1;
14134                     xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14135                 }
14136                 if ((cur->children == NULL) || (depth >= max_depth)) {
14137                     ret = xmlStreamPop(patstream);
14138                     while (cur->next != NULL) {
14139                         cur = cur->next;
14140                         if ((cur->type != XML_ENTITY_DECL) &&
14141                             (cur->type != XML_DTD_NODE))
14142                             goto next_node;
14143                     }
14144                 }
14145             default:
14146                 break;
14147         }
14148
14149 scan_children:
14150         if ((cur->children != NULL) && (depth < max_depth)) {
14151             /*
14152              * Do not descend on entities declarations       
14153              */
14154             if (cur->children->type != XML_ENTITY_DECL) {
14155                 cur = cur->children;
14156                 depth++;
14157                 /*
14158                  * Skip DTDs
14159                  */
14160                 if (cur->type != XML_DTD_NODE)
14161                     continue;
14162             }
14163         }
14164
14165         if (cur == limit)
14166             break;
14167
14168         while (cur->next != NULL) {
14169             cur = cur->next;
14170             if ((cur->type != XML_ENTITY_DECL) &&
14171                 (cur->type != XML_DTD_NODE))
14172                 goto next_node;
14173         }
14174         
14175         do {
14176             cur = cur->parent;
14177             depth--;
14178             if ((cur == NULL) || (cur == limit))
14179                 goto done;
14180             if (cur->type == XML_ELEMENT_NODE) {
14181                 ret = xmlStreamPop(patstream);
14182             } else if ((eval_all_nodes) &&
14183                 ((cur->type == XML_TEXT_NODE) ||
14184                  (cur->type == XML_CDATA_SECTION_NODE) ||
14185                  (cur->type == XML_COMMENT_NODE) ||
14186                  (cur->type == XML_PI_NODE)))
14187             {
14188                 ret = xmlStreamPop(patstream);
14189             }
14190             if (cur->next != NULL) {
14191                 cur = cur->next;
14192                 break;
14193             }
14194         } while (cur != NULL);
14195
14196     } while ((cur != NULL) && (depth >= 0));
14197
14198 done:
14199
14200 #if 0
14201     printf("stream eval: checked %d nodes selected %d\n",
14202            nb_nodes, retObj->nodesetval->nodeNr);
14203 #endif
14204
14205     if (patstream)
14206         xmlFreeStreamCtxt(patstream);
14207     return(0);
14208
14209 return_1:
14210     if (patstream)
14211         xmlFreeStreamCtxt(patstream);
14212     return(1);
14213 }
14214 #endif /* XPATH_STREAMING */
14215
14216 /**
14217  * xmlXPathRunEval:
14218  * @ctxt:  the XPath parser context with the compiled expression
14219  * @toBool:  evaluate to a boolean result
14220  *
14221  * Evaluate the Precompiled XPath expression in the given context.
14222  */
14223 static int
14224 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14225 {
14226     xmlXPathCompExprPtr comp;
14227
14228     if ((ctxt == NULL) || (ctxt->comp == NULL))
14229         return(-1);
14230
14231     if (ctxt->valueTab == NULL) {
14232         /* Allocate the value stack */
14233         ctxt->valueTab = (xmlXPathObjectPtr *) 
14234                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14235         if (ctxt->valueTab == NULL) {
14236             xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14237             xmlFree(ctxt);
14238         }
14239         ctxt->valueNr = 0;
14240         ctxt->valueMax = 10;
14241         ctxt->value = NULL;
14242     }
14243 #ifdef XPATH_STREAMING
14244     if (ctxt->comp->stream) {
14245         int res;
14246
14247         if (toBool) {
14248             /*
14249             * Evaluation to boolean result.
14250             */
14251             res = xmlXPathRunStreamEval(ctxt->context,
14252                 ctxt->comp->stream, NULL, 1);
14253             if (res != -1)
14254                 return(res);
14255         } else {
14256             xmlXPathObjectPtr resObj = NULL;    
14257
14258             /*
14259             * Evaluation to a sequence.
14260             */
14261             res = xmlXPathRunStreamEval(ctxt->context,
14262                 ctxt->comp->stream, &resObj, 0);
14263
14264             if ((res != -1) && (resObj != NULL)) {
14265                 valuePush(ctxt, resObj);
14266                 return(0);
14267             }
14268             if (resObj != NULL)
14269                 xmlXPathReleaseObject(ctxt->context, resObj);   
14270         }
14271         /*
14272         * QUESTION TODO: This falls back to normal XPath evaluation
14273         * if res == -1. Is this intended?
14274         */
14275     }
14276 #endif
14277     comp = ctxt->comp;
14278     if (comp->last < 0) {
14279         xmlGenericError(xmlGenericErrorContext,
14280             "xmlXPathRunEval: last is less than zero\n");
14281         return(-1);
14282     }
14283     if (toBool)
14284         return(xmlXPathCompOpEvalToBoolean(ctxt,
14285             &comp->steps[comp->last], 0));
14286     else
14287         xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14288
14289     return(0);
14290 }
14291
14292 /************************************************************************
14293  *                                                                      *
14294  *                      Public interfaces                               *
14295  *                                                                      *
14296  ************************************************************************/
14297
14298 /**
14299  * xmlXPathEvalPredicate:
14300  * @ctxt:  the XPath context
14301  * @res:  the Predicate Expression evaluation result
14302  *
14303  * Evaluate a predicate result for the current node.
14304  * A PredicateExpr is evaluated by evaluating the Expr and converting
14305  * the result to a boolean. If the result is a number, the result will
14306  * be converted to true if the number is equal to the position of the
14307  * context node in the context node list (as returned by the position
14308  * function) and will be converted to false otherwise; if the result
14309  * is not a number, then the result will be converted as if by a call
14310  * to the boolean function. 
14311  *
14312  * Returns 1 if predicate is true, 0 otherwise
14313  */
14314 int
14315 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14316     if ((ctxt == NULL) || (res == NULL)) return(0);
14317     switch (res->type) {
14318         case XPATH_BOOLEAN:
14319             return(res->boolval);
14320         case XPATH_NUMBER:
14321             return(res->floatval == ctxt->proximityPosition);
14322         case XPATH_NODESET:
14323         case XPATH_XSLT_TREE:
14324             if (res->nodesetval == NULL)
14325                 return(0);
14326             return(res->nodesetval->nodeNr != 0);
14327         case XPATH_STRING:
14328             return((res->stringval != NULL) &&
14329                    (xmlStrlen(res->stringval) != 0));
14330         default:
14331             STRANGE
14332     }
14333     return(0);
14334 }
14335
14336 /**
14337  * xmlXPathEvaluatePredicateResult:
14338  * @ctxt:  the XPath Parser context
14339  * @res:  the Predicate Expression evaluation result
14340  *
14341  * Evaluate a predicate result for the current node.
14342  * A PredicateExpr is evaluated by evaluating the Expr and converting
14343  * the result to a boolean. If the result is a number, the result will
14344  * be converted to true if the number is equal to the position of the
14345  * context node in the context node list (as returned by the position
14346  * function) and will be converted to false otherwise; if the result
14347  * is not a number, then the result will be converted as if by a call
14348  * to the boolean function. 
14349  *
14350  * Returns 1 if predicate is true, 0 otherwise
14351  */
14352 int
14353 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
14354                                 xmlXPathObjectPtr res) {
14355     if ((ctxt == NULL) || (res == NULL)) return(0);
14356     switch (res->type) {
14357         case XPATH_BOOLEAN:
14358             return(res->boolval);
14359         case XPATH_NUMBER:
14360 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14361             return((res->floatval == ctxt->context->proximityPosition) &&
14362                    (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14363 #else
14364             return(res->floatval == ctxt->context->proximityPosition);
14365 #endif
14366         case XPATH_NODESET:
14367         case XPATH_XSLT_TREE:
14368             if (res->nodesetval == NULL)
14369                 return(0);
14370             return(res->nodesetval->nodeNr != 0);
14371         case XPATH_STRING:
14372             return((res->stringval != NULL) && (res->stringval[0] != 0));
14373 #ifdef LIBXML_XPTR_ENABLED
14374         case XPATH_LOCATIONSET:{
14375             xmlLocationSetPtr ptr = res->user;
14376             if (ptr == NULL)
14377                 return(0);
14378             return (ptr->locNr != 0);
14379             }
14380 #endif
14381         default:
14382             STRANGE
14383     }
14384     return(0);
14385 }
14386
14387 #ifdef XPATH_STREAMING
14388 /**
14389  * xmlXPathTryStreamCompile:
14390  * @ctxt: an XPath context
14391  * @str:  the XPath expression
14392  *
14393  * Try to compile the XPath expression as a streamable subset.
14394  *
14395  * Returns the compiled expression or NULL if failed to compile.
14396  */
14397 static xmlXPathCompExprPtr
14398 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14399     /*
14400      * Optimization: use streaming patterns when the XPath expression can
14401      * be compiled to a stream lookup
14402      */
14403     xmlPatternPtr stream;
14404     xmlXPathCompExprPtr comp;
14405     xmlDictPtr dict = NULL;
14406     const xmlChar **namespaces = NULL;
14407     xmlNsPtr ns;
14408     int i, j;
14409
14410     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14411         (!xmlStrchr(str, '@'))) {
14412         const xmlChar *tmp;
14413
14414         /*
14415          * We don't try to handle expressions using the verbose axis
14416          * specifiers ("::"), just the simplied form at this point.
14417          * Additionally, if there is no list of namespaces available and
14418          *  there's a ":" in the expression, indicating a prefixed QName,
14419          *  then we won't try to compile either. xmlPatterncompile() needs
14420          *  to have a list of namespaces at compilation time in order to
14421          *  compile prefixed name tests.
14422          */
14423         tmp = xmlStrchr(str, ':');
14424         if ((tmp != NULL) &&
14425             ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14426             return(NULL);           
14427
14428         if (ctxt != NULL) {
14429             dict = ctxt->dict;
14430             if (ctxt->nsNr > 0) {
14431                 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14432                 if (namespaces == NULL) {
14433                     xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14434                     return(NULL);
14435                 }
14436                 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14437                     ns = ctxt->namespaces[j];
14438                     namespaces[i++] = ns->href;
14439                     namespaces[i++] = ns->prefix;
14440                 }
14441                 namespaces[i++] = NULL;
14442                 namespaces[i++] = NULL;
14443             }
14444         }
14445
14446         stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14447                         &namespaces[0]);
14448         if (namespaces != NULL) {
14449             xmlFree((xmlChar **)namespaces);
14450         }
14451         if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14452             comp = xmlXPathNewCompExpr();
14453             if (comp == NULL) {
14454                 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14455                 return(NULL);
14456             }
14457             comp->stream = stream;
14458             comp->dict = dict;
14459             if (comp->dict)
14460                 xmlDictReference(comp->dict);
14461             return(comp);
14462         }
14463         xmlFreePattern(stream);
14464     }
14465     return(NULL);
14466 }
14467 #endif /* XPATH_STREAMING */
14468
14469 static int
14470 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14471 {
14472     if (expr == NULL)
14473         return(0);
14474     do {
14475         if ((*expr == '/') && (*(++expr) == '/'))
14476             return(1);
14477     } while (*expr++);
14478     return(0);
14479 }
14480 static void
14481 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14482 {
14483     /*
14484     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14485     * internal representation.
14486     */
14487     if (op->ch1 != -1) {
14488         if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14489             ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&          
14490             ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14491             ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14492         {
14493             /*
14494             * This is a "child::foo"
14495             */
14496             xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];       
14497
14498             if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14499                 (prevop->ch1 != -1) &&      
14500                 ((xmlXPathAxisVal) prevop->value ==
14501                     AXIS_DESCENDANT_OR_SELF) &&
14502                 (prevop->ch2 == -1) &&
14503                 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14504                 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14505                 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14506             {           
14507                 /*
14508                 * This is a "/descendant-or-self::node()" without predicates.
14509                 * Eliminate it.
14510                 */
14511                 op->ch1 = prevop->ch1;
14512                 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;            
14513             }
14514         }
14515         if (op->ch1 != -1)
14516             xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14517     }
14518     if (op->ch2 != -1)
14519         xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14520 }
14521
14522 /**
14523  * xmlXPathCtxtCompile:
14524  * @ctxt: an XPath context
14525  * @str:  the XPath expression
14526  *
14527  * Compile an XPath expression
14528  *
14529  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14530  *         the caller has to free the object.
14531  */
14532 xmlXPathCompExprPtr
14533 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14534     xmlXPathParserContextPtr pctxt;
14535     xmlXPathCompExprPtr comp;
14536
14537 #ifdef XPATH_STREAMING
14538     comp = xmlXPathTryStreamCompile(ctxt, str);
14539     if (comp != NULL)
14540         return(comp);
14541 #endif
14542
14543     xmlXPathInit();
14544
14545     pctxt = xmlXPathNewParserContext(str, ctxt);
14546     xmlXPathCompileExpr(pctxt, 1);
14547
14548     if( pctxt->error != XPATH_EXPRESSION_OK )
14549     {
14550         xmlXPathFreeParserContext(pctxt);
14551         return(NULL);
14552     }
14553
14554     if (*pctxt->cur != 0) {
14555         /* 
14556          * aleksey: in some cases this line prints *second* error message
14557          * (see bug #78858) and probably this should be fixed.
14558          * However, we are not sure that all error messages are printed
14559          * out in other places. It's not critical so we leave it as-is for now
14560          */
14561         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14562         comp = NULL;
14563     } else {
14564         comp = pctxt->comp;
14565         pctxt->comp = NULL;
14566     }
14567     xmlXPathFreeParserContext(pctxt);
14568
14569     if (comp != NULL) {
14570         comp->expr = xmlStrdup(str);
14571 #ifdef DEBUG_EVAL_COUNTS
14572         comp->string = xmlStrdup(str);
14573         comp->nb = 0;
14574 #endif  
14575         if ((comp->expr != NULL) &&
14576             (comp->nbStep > 2) &&
14577             (comp->last >= 0) &&
14578             (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14579         {
14580             xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14581         }
14582     }
14583     return(comp);
14584 }
14585
14586 /**
14587  * xmlXPathCompile:
14588  * @str:  the XPath expression
14589  *
14590  * Compile an XPath expression
14591  *
14592  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14593  *         the caller has to free the object.
14594  */
14595 xmlXPathCompExprPtr
14596 xmlXPathCompile(const xmlChar *str) {
14597     return(xmlXPathCtxtCompile(NULL, str));
14598 }
14599
14600 /**
14601  * xmlXPathCompiledEvalInternal:
14602  * @comp:  the compiled XPath expression
14603  * @ctxt:  the XPath context
14604  * @resObj: the resulting XPath object or NULL
14605  * @toBool: 1 if only a boolean result is requested
14606  *
14607  * Evaluate the Precompiled XPath expression in the given context.
14608  * The caller has to free @resObj.
14609  *
14610  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14611  *         the caller has to free the object.
14612  */
14613 static int
14614 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14615                              xmlXPathContextPtr ctxt,
14616                              xmlXPathObjectPtr *resObj,
14617                              int toBool)
14618 {
14619     xmlXPathParserContextPtr pctxt;    
14620 #ifndef LIBXML_THREAD_ENABLED
14621     static int reentance = 0;
14622 #endif
14623     int res;
14624
14625     CHECK_CTXT_NEG(ctxt)
14626
14627     if (comp == NULL)
14628         return(-1);
14629     xmlXPathInit();
14630
14631 #ifndef LIBXML_THREAD_ENABLED
14632     reentance++;
14633     if (reentance > 1)
14634         xmlXPathDisableOptimizer = 1;
14635 #endif
14636
14637 #ifdef DEBUG_EVAL_COUNTS
14638     comp->nb++;
14639     if ((comp->string != NULL) && (comp->nb > 100)) {
14640         fprintf(stderr, "100 x %s\n", comp->string);
14641         comp->nb = 0;
14642     }
14643 #endif
14644     pctxt = xmlXPathCompParserContext(comp, ctxt);
14645     res = xmlXPathRunEval(pctxt, toBool);
14646
14647     if (resObj) {
14648         if (pctxt->value == NULL) {         
14649             xmlGenericError(xmlGenericErrorContext,
14650                 "xmlXPathCompiledEval: evaluation failed\n");
14651             *resObj = NULL;         
14652         } else {
14653             *resObj = valuePop(pctxt);
14654         }
14655     }
14656     
14657     /*
14658     * Pop all remaining objects from the stack.
14659     */
14660     if (pctxt->valueNr > 0) {
14661         xmlXPathObjectPtr tmp;
14662         int stack = 0;
14663
14664         do {
14665             tmp = valuePop(pctxt);
14666             if (tmp != NULL) {
14667                 if (tmp != NULL)
14668                     stack++; 
14669                 xmlXPathReleaseObject(ctxt, tmp);
14670             }
14671         } while (tmp != NULL);
14672         if ((stack != 0) &&
14673             ((toBool) || ((resObj) && (*resObj))))
14674         {
14675             xmlGenericError(xmlGenericErrorContext,
14676                 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14677                 stack);
14678         }
14679     }
14680     
14681     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14682         xmlXPathFreeObject(*resObj);
14683         *resObj = NULL;
14684     }        
14685     pctxt->comp = NULL;
14686     xmlXPathFreeParserContext(pctxt);
14687 #ifndef LIBXML_THREAD_ENABLED
14688     reentance--;
14689 #endif
14690
14691     return(res);
14692 }
14693
14694 /**
14695  * xmlXPathCompiledEval:
14696  * @comp:  the compiled XPath expression
14697  * @ctx:  the XPath context
14698  *
14699  * Evaluate the Precompiled XPath expression in the given context.
14700  *
14701  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14702  *         the caller has to free the object.
14703  */
14704 xmlXPathObjectPtr
14705 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14706 {
14707     xmlXPathObjectPtr res = NULL;
14708
14709     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14710     return(res);
14711 }
14712
14713 /**
14714  * xmlXPathCompiledEvalToBoolean:
14715  * @comp:  the compiled XPath expression
14716  * @ctxt:  the XPath context
14717  *
14718  * Applies the XPath boolean() function on the result of the given
14719  * compiled expression.
14720  *
14721  * Returns 1 if the expression evaluated to true, 0 if to false and
14722  *         -1 in API and internal errors.
14723  */
14724 int
14725 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14726                               xmlXPathContextPtr ctxt)
14727 {
14728     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14729 }
14730
14731 /**
14732  * xmlXPathEvalExpr:
14733  * @ctxt:  the XPath Parser context
14734  *
14735  * Parse and evaluate an XPath expression in the given context,
14736  * then push the result on the context stack
14737  */
14738 void
14739 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14740 #ifdef XPATH_STREAMING
14741     xmlXPathCompExprPtr comp;
14742 #endif
14743
14744     if (ctxt == NULL) return;
14745     
14746 #ifdef XPATH_STREAMING
14747     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14748     if (comp != NULL) {
14749         if (ctxt->comp != NULL)
14750             xmlXPathFreeCompExpr(ctxt->comp);
14751         ctxt->comp = comp;
14752         if (ctxt->cur != NULL)
14753             while (*ctxt->cur != 0) ctxt->cur++;
14754     } else
14755 #endif
14756     {
14757         xmlXPathCompileExpr(ctxt, 1);
14758         /*
14759         * In this scenario the expression string will sit in ctxt->base.
14760         */
14761         if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14762             (ctxt->comp != NULL) &&
14763             (ctxt->base != NULL) &&
14764             (ctxt->comp->nbStep > 2) &&
14765             (ctxt->comp->last >= 0) &&
14766             (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14767         {
14768             xmlXPathRewriteDOSExpression(ctxt->comp,
14769                 &ctxt->comp->steps[ctxt->comp->last]);
14770         }
14771     }
14772     CHECK_ERROR;
14773     xmlXPathRunEval(ctxt, 0);    
14774 }
14775
14776 /**
14777  * xmlXPathEval:
14778  * @str:  the XPath expression
14779  * @ctx:  the XPath context
14780  *
14781  * Evaluate the XPath Location Path in the given context.
14782  *
14783  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14784  *         the caller has to free the object.
14785  */
14786 xmlXPathObjectPtr
14787 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14788     xmlXPathParserContextPtr ctxt;
14789     xmlXPathObjectPtr res, tmp, init = NULL;
14790     int stack = 0;
14791
14792     CHECK_CTXT(ctx)
14793
14794     xmlXPathInit();
14795
14796     ctxt = xmlXPathNewParserContext(str, ctx);
14797     xmlXPathEvalExpr(ctxt);
14798
14799     if (ctxt->value == NULL) {
14800         xmlGenericError(xmlGenericErrorContext,
14801                 "xmlXPathEval: evaluation failed\n");
14802         res = NULL;
14803     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 
14804 #ifdef XPATH_STREAMING
14805             && (ctxt->comp->stream == NULL)
14806 #endif
14807               ) {
14808         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14809         res = NULL;
14810     } else {
14811         res = valuePop(ctxt);
14812     }
14813
14814     do {
14815         tmp = valuePop(ctxt);
14816         if (tmp != NULL) {
14817             if (tmp != init)
14818                 stack++;
14819             xmlXPathReleaseObject(ctx, tmp);
14820         }
14821     } while (tmp != NULL);
14822     if ((stack != 0) && (res != NULL)) {
14823         xmlGenericError(xmlGenericErrorContext,
14824                 "xmlXPathEval: %d object left on the stack\n",
14825                 stack);
14826     }
14827     if (ctxt->error != XPATH_EXPRESSION_OK) {
14828         xmlXPathFreeObject(res);
14829         res = NULL;
14830     }
14831
14832     xmlXPathFreeParserContext(ctxt);
14833     return(res);
14834 }
14835
14836 /**
14837  * xmlXPathEvalExpression:
14838  * @str:  the XPath expression
14839  * @ctxt:  the XPath context
14840  *
14841  * Evaluate the XPath expression in the given context.
14842  *
14843  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14844  *         the caller has to free the object.
14845  */
14846 xmlXPathObjectPtr
14847 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14848     xmlXPathParserContextPtr pctxt;
14849     xmlXPathObjectPtr res, tmp;
14850     int stack = 0;
14851
14852     CHECK_CTXT(ctxt)
14853
14854     xmlXPathInit();
14855
14856     pctxt = xmlXPathNewParserContext(str, ctxt);
14857     xmlXPathEvalExpr(pctxt);
14858
14859     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14860         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14861         res = NULL;
14862     } else {
14863         res = valuePop(pctxt);
14864     }
14865     do {
14866         tmp = valuePop(pctxt);
14867         if (tmp != NULL) {
14868             xmlXPathReleaseObject(ctxt, tmp);
14869             stack++;
14870         }
14871     } while (tmp != NULL);
14872     if ((stack != 0) && (res != NULL)) {
14873         xmlGenericError(xmlGenericErrorContext,
14874                 "xmlXPathEvalExpression: %d object left on the stack\n",
14875                 stack);
14876     }
14877     xmlXPathFreeParserContext(pctxt);
14878     return(res);
14879 }
14880
14881 /************************************************************************
14882  *                                                                      *
14883  *      Extra functions not pertaining to the XPath spec                *
14884  *                                                                      *
14885  ************************************************************************/
14886 /**
14887  * xmlXPathEscapeUriFunction:
14888  * @ctxt:  the XPath Parser context
14889  * @nargs:  the number of arguments
14890  *
14891  * Implement the escape-uri() XPath function
14892  *    string escape-uri(string $str, bool $escape-reserved)
14893  *
14894  * This function applies the URI escaping rules defined in section 2 of [RFC
14895  * 2396] to the string supplied as $uri-part, which typically represents all
14896  * or part of a URI. The effect of the function is to replace any special
14897  * character in the string by an escape sequence of the form %xx%yy...,
14898  * where xxyy... is the hexadecimal representation of the octets used to
14899  * represent the character in UTF-8.
14900  *
14901  * The set of characters that are escaped depends on the setting of the
14902  * boolean argument $escape-reserved.
14903  *
14904  * If $escape-reserved is true, all characters are escaped other than lower
14905  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14906  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14907  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14908  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14909  * A-F).
14910  *
14911  * If $escape-reserved is false, the behavior differs in that characters
14912  * referred to in [RFC 2396] as reserved characters are not escaped. These
14913  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14914  * 
14915  * [RFC 2396] does not define whether escaped URIs should use lower case or
14916  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14917  * compared using string comparison functions, this function must always use
14918  * the upper-case letters A-F.
14919  * 
14920  * Generally, $escape-reserved should be set to true when escaping a string
14921  * that is to form a single part of a URI, and to false when escaping an
14922  * entire URI or URI reference.
14923  * 
14924  * In the case of non-ascii characters, the string is encoded according to 
14925  * utf-8 and then converted according to RFC 2396.
14926  *
14927  * Examples
14928  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 
14929  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14930  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14931  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14932  *
14933  */
14934 static void
14935 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14936     xmlXPathObjectPtr str;
14937     int escape_reserved;
14938     xmlBufferPtr target;
14939     xmlChar *cptr;
14940     xmlChar escape[4];
14941     
14942     CHECK_ARITY(2);
14943     
14944     escape_reserved = xmlXPathPopBoolean(ctxt);
14945     
14946     CAST_TO_STRING;
14947     str = valuePop(ctxt);
14948     
14949     target = xmlBufferCreate();
14950     
14951     escape[0] = '%';
14952     escape[3] = 0;
14953     
14954     if (target) {
14955         for (cptr = str->stringval; *cptr; cptr++) {
14956             if ((*cptr >= 'A' && *cptr <= 'Z') ||
14957                 (*cptr >= 'a' && *cptr <= 'z') ||
14958                 (*cptr >= '0' && *cptr <= '9') ||
14959                 *cptr == '-' || *cptr == '_' || *cptr == '.' || 
14960                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14961                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14962                 (*cptr == '%' && 
14963                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14964                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14965                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
14966                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14967                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14968                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14969                 (!escape_reserved &&
14970                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14971                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14972                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14973                   *cptr == ','))) {
14974                 xmlBufferAdd(target, cptr, 1);
14975             } else {
14976                 if ((*cptr >> 4) < 10)
14977                     escape[1] = '0' + (*cptr >> 4);
14978                 else
14979                     escape[1] = 'A' - 10 + (*cptr >> 4);
14980                 if ((*cptr & 0xF) < 10)
14981                     escape[2] = '0' + (*cptr & 0xF);
14982                 else
14983                     escape[2] = 'A' - 10 + (*cptr & 0xF);
14984                 
14985                 xmlBufferAdd(target, &escape[0], 3);
14986             }
14987         }
14988     }
14989     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14990         xmlBufferContent(target)));
14991     xmlBufferFree(target);
14992     xmlXPathReleaseObject(ctxt->context, str);
14993 }
14994
14995 /**
14996  * xmlXPathRegisterAllFunctions:
14997  * @ctxt:  the XPath context
14998  *
14999  * Registers all default XPath functions in this context
15000  */
15001 void
15002 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15003 {
15004     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15005                          xmlXPathBooleanFunction);
15006     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15007                          xmlXPathCeilingFunction);
15008     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15009                          xmlXPathCountFunction);
15010     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15011                          xmlXPathConcatFunction);
15012     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15013                          xmlXPathContainsFunction);
15014     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15015                          xmlXPathIdFunction);
15016     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15017                          xmlXPathFalseFunction);
15018     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15019                          xmlXPathFloorFunction);
15020     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15021                          xmlXPathLastFunction);
15022     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15023                          xmlXPathLangFunction);
15024     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15025                          xmlXPathLocalNameFunction);
15026     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15027                          xmlXPathNotFunction);
15028     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15029                          xmlXPathNameFunction);
15030     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15031                          xmlXPathNamespaceURIFunction);
15032     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15033                          xmlXPathNormalizeFunction);
15034     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15035                          xmlXPathNumberFunction);
15036     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15037                          xmlXPathPositionFunction);
15038     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15039                          xmlXPathRoundFunction);
15040     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15041                          xmlXPathStringFunction);
15042     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15043                          xmlXPathStringLengthFunction);
15044     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15045                          xmlXPathStartsWithFunction);
15046     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15047                          xmlXPathSubstringFunction);
15048     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15049                          xmlXPathSubstringBeforeFunction);
15050     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15051                          xmlXPathSubstringAfterFunction);
15052     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15053                          xmlXPathSumFunction);
15054     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15055                          xmlXPathTrueFunction);
15056     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15057                          xmlXPathTranslateFunction);
15058
15059     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15060          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15061                          xmlXPathEscapeUriFunction);
15062 }
15063
15064 #endif /* LIBXML_XPATH_ENABLED */
15065 #define bottom_xpath
15066 #include "elfgcchack.h"