BRANCH release for 2.5.x critical patches
[baserock-morphs:libxml2.git] / xpath.c
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
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
55 /************************************************************************
56  *                                                                      *
57  *                      Floating point stuff                            *
58  *                                                                      *
59  ************************************************************************/
60
61 #ifndef TRIO_REPLACE_STDIO
62 #define TRIO_PUBLIC static
63 #endif
64 #include "trionan.c"
65
66 /*
67  * The lack of portability of this section of the libc is annoying !
68  */
69 double xmlXPathNAN = 0;
70 double xmlXPathPINF = 1;
71 double xmlXPathNINF = -1;
72 double xmlXPathNZERO = 0;
73 static int xmlXPathInitialized = 0;
74
75 /**
76  * xmlXPathInit:
77  *
78  * Initialize the XPath environment
79  */
80 void
81 xmlXPathInit(void) {
82     if (xmlXPathInitialized) return;
83
84     xmlXPathPINF = trio_pinf();
85     xmlXPathNINF = trio_ninf();
86     xmlXPathNAN = trio_nan();
87     xmlXPathNZERO = trio_nzero();
88
89     xmlXPathInitialized = 1;
90 }
91
92 /**
93  * xmlXPathIsNaN:
94  * @val:  a double value
95  *
96  * Provides a portable isnan() function to detect whether a double
97  * is a NotaNumber. Based on trio code
98  * http://sourceforge.net/projects/ctrio/
99  * 
100  * Returns 1 if the value is a NaN, 0 otherwise
101  */
102 int
103 xmlXPathIsNaN(double val) {
104     return(trio_isnan(val));
105 }
106
107 /**
108  * xmlXPathIsInf:
109  * @val:  a double value
110  *
111  * Provides a portable isinf() function to detect whether a double
112  * is a +Infinite or -Infinite. Based on trio code
113  * http://sourceforge.net/projects/ctrio/
114  * 
115  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
116  */
117 int
118 xmlXPathIsInf(double val) {
119     return(trio_isinf(val));
120 }
121
122 /**
123  * xmlXPathGetSign:
124  * @val:  a double value
125  *
126  * Provides a portable function to detect the sign of a double
127  * Modified from trio code
128  * http://sourceforge.net/projects/ctrio/
129  * 
130  * Returns 1 if the value is Negative, 0 if positive
131  */
132 static int
133 xmlXPathGetSign(double val) {
134     return(trio_signbit(val));
135 }
136
137
138 #ifdef LIBXML_XPATH_ENABLED
139 /*
140  * TODO: when compatibility allows remove all "fake node libxslt" strings
141  *       the test should just be name[0] = ' '
142  */
143 /* #define DEBUG */
144 /* #define DEBUG_STEP */
145 /* #define DEBUG_STEP_NTH */
146 /* #define DEBUG_EXPR */
147 /* #define DEBUG_EVAL_COUNTS */
148
149 static xmlNs xmlXPathXMLNamespaceStruct = {
150     NULL,
151     XML_NAMESPACE_DECL,
152     XML_XML_NAMESPACE,
153     BAD_CAST "xml",
154     NULL
155 };
156 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
157 #ifndef LIBXML_THREAD_ENABLED
158 /* 
159  * Optimizer is disabled only when threaded apps are detected while
160  * the library ain't compiled for thread safety.
161  */
162 static int xmlXPathDisableOptimizer = 0;
163 #endif
164
165 /************************************************************************
166  *                                                                      *
167  *                      Parser Types                                    *
168  *                                                                      *
169  ************************************************************************/
170
171 /*
172  * Types are private:
173  */
174
175 typedef enum {
176     XPATH_OP_END=0,
177     XPATH_OP_AND,
178     XPATH_OP_OR,
179     XPATH_OP_EQUAL,
180     XPATH_OP_CMP,
181     XPATH_OP_PLUS,
182     XPATH_OP_MULT,
183     XPATH_OP_UNION,
184     XPATH_OP_ROOT,
185     XPATH_OP_NODE,
186     XPATH_OP_RESET,
187     XPATH_OP_COLLECT,
188     XPATH_OP_VALUE,
189     XPATH_OP_VARIABLE,
190     XPATH_OP_FUNCTION,
191     XPATH_OP_ARG,
192     XPATH_OP_PREDICATE,
193     XPATH_OP_FILTER,
194     XPATH_OP_SORT
195 #ifdef LIBXML_XPTR_ENABLED
196     ,XPATH_OP_RANGETO
197 #endif
198 } xmlXPathOp;
199
200 typedef enum {
201     AXIS_ANCESTOR = 1,
202     AXIS_ANCESTOR_OR_SELF,
203     AXIS_ATTRIBUTE,
204     AXIS_CHILD,
205     AXIS_DESCENDANT,
206     AXIS_DESCENDANT_OR_SELF,
207     AXIS_FOLLOWING,
208     AXIS_FOLLOWING_SIBLING,
209     AXIS_NAMESPACE,
210     AXIS_PARENT,
211     AXIS_PRECEDING,
212     AXIS_PRECEDING_SIBLING,
213     AXIS_SELF
214 } xmlXPathAxisVal;
215
216 typedef enum {
217     NODE_TEST_NONE = 0,
218     NODE_TEST_TYPE = 1,
219     NODE_TEST_PI = 2,
220     NODE_TEST_ALL = 3,
221     NODE_TEST_NS = 4,
222     NODE_TEST_NAME = 5
223 } xmlXPathTestVal;
224
225 typedef enum {
226     NODE_TYPE_NODE = 0,
227     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228     NODE_TYPE_TEXT = XML_TEXT_NODE,
229     NODE_TYPE_PI = XML_PI_NODE
230 } xmlXPathTypeVal;
231
232
233 typedef struct _xmlXPathStepOp xmlXPathStepOp;
234 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235 struct _xmlXPathStepOp {
236     xmlXPathOp op;
237     int ch1;
238     int ch2;
239     int value;
240     int value2;
241     int value3;
242     void *value4;
243     void *value5;
244     void *cache;
245     void *cacheURI;
246 };
247
248 struct _xmlXPathCompExpr {
249     int nbStep;
250     int maxStep;
251     xmlXPathStepOp *steps;        /* ops for computation */
252     int last;
253     xmlChar *expr;
254 #ifdef DEBUG_EVAL_COUNTS
255     int nb;
256     xmlChar *string;
257 #endif
258 };
259
260 /************************************************************************
261  *                                                                      *
262  *                      Parser Type functions                           *
263  *                                                                      *
264  ************************************************************************/
265
266 /**
267  * xmlXPathNewCompExpr:
268  *
269  * Create a new Xpath component
270  *
271  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272  */
273 static xmlXPathCompExprPtr
274 xmlXPathNewCompExpr(void) {
275     xmlXPathCompExprPtr cur;
276
277     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278     if (cur == NULL) {
279         xmlGenericError(xmlGenericErrorContext,
280                 "xmlXPathNewCompExpr : malloc failed\n");
281         return(NULL);
282     }
283     memset(cur, 0, sizeof(xmlXPathCompExpr));
284     cur->maxStep = 10;
285     cur->nbStep = 0;
286     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287                                            sizeof(xmlXPathStepOp));
288     if (cur->steps == NULL) {
289         xmlGenericError(xmlGenericErrorContext,
290                 "xmlXPathNewCompExpr : malloc failed\n");
291         xmlFree(cur);
292         return(NULL);
293     }
294     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295     cur->last = -1;
296 #ifdef DEBUG_EVAL_COUNTS
297     cur->nb = 0;
298 #endif
299     return(cur);
300 }
301
302 /**
303  * xmlXPathFreeCompExpr:
304  * @comp:  an XPATH comp
305  *
306  * Free up the memory allocated by @comp
307  */
308 void
309 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310 {
311     xmlXPathStepOpPtr op;
312     int i;
313
314     if (comp == NULL)
315         return;
316     for (i = 0; i < comp->nbStep; i++) {
317         op = &comp->steps[i];
318         if (op->value4 != NULL) {
319             if (op->op == XPATH_OP_VALUE)
320                 xmlXPathFreeObject(op->value4);
321             else
322                 xmlFree(op->value4);
323         }
324         if (op->value5 != NULL)
325             xmlFree(op->value5);
326     }
327     if (comp->steps != NULL) {
328         xmlFree(comp->steps);
329     }
330 #ifdef DEBUG_EVAL_COUNTS
331     if (comp->string != NULL) {
332         xmlFree(comp->string);
333     }
334 #endif
335     if (comp->expr != NULL) {
336         xmlFree(comp->expr);
337     }
338
339     xmlFree(comp);
340 }
341
342 /**
343  * xmlXPathCompExprAdd:
344  * @comp:  the compiled expression
345  * @ch1: first child index
346  * @ch2: second child index
347  * @op:  an op
348  * @value:  the first int value
349  * @value2:  the second int value
350  * @value3:  the third int value
351  * @value4:  the first string value
352  * @value5:  the second string value
353  *
354  * Add an step to an XPath Compiled Expression
355  *
356  * Returns -1 in case of failure, the index otherwise
357  */
358 static int
359 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360    xmlXPathOp op, int value,
361    int value2, int value3, void *value4, void *value5) {
362     if (comp->nbStep >= comp->maxStep) {
363         xmlXPathStepOp *real;
364
365         comp->maxStep *= 2;
366         real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367                                       comp->maxStep * sizeof(xmlXPathStepOp));
368         if (real == NULL) {
369             comp->maxStep /= 2;
370             xmlGenericError(xmlGenericErrorContext,
371                     "xmlXPathCompExprAdd : realloc failed\n");
372             return(-1);
373         }
374         comp->steps = real;
375     }
376     comp->last = comp->nbStep;
377     comp->steps[comp->nbStep].ch1 = ch1;
378     comp->steps[comp->nbStep].ch2 = ch2;
379     comp->steps[comp->nbStep].op = op;
380     comp->steps[comp->nbStep].value = value;
381     comp->steps[comp->nbStep].value2 = value2;
382     comp->steps[comp->nbStep].value3 = value3;
383     comp->steps[comp->nbStep].value4 = value4;
384     comp->steps[comp->nbStep].value5 = value5;
385     comp->steps[comp->nbStep].cache = NULL;
386     return(comp->nbStep++);
387 }
388
389 /**
390  * xmlXPathCompSwap:
391  * @comp:  the compiled expression
392  * @op: operation index
393  *
394  * Swaps 2 operations in the compiled expression
395  */
396 static void
397 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398     int tmp;
399
400 #ifndef LIBXML_THREAD_ENABLED
401     /*
402      * Since this manipulates possibly shared variables, this is
403      * disable if one detects that the library is used in a multithreaded
404      * application
405      */
406     if (xmlXPathDisableOptimizer)
407         return;
408 #endif
409
410     tmp = op->ch1;
411     op->ch1 = op->ch2;
412     op->ch2 = tmp;
413 }
414
415 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
416     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
417                         (op), (val), (val2), (val3), (val4), (val5))
418 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
419     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
420                         (op), (val), (val2), (val3), (val4), (val5))
421
422 #define PUSH_LEAVE_EXPR(op, val, val2)                                  \
423 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425 #define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
426 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
429 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431 /************************************************************************
432  *                                                                      *
433  *              Debugging related functions                             *
434  *                                                                      *
435  ************************************************************************/
436
437 #define TODO                                                            \
438     xmlGenericError(xmlGenericErrorContext,                             \
439             "Unimplemented block at %s:%d\n",                           \
440             __FILE__, __LINE__);
441
442 #define STRANGE                                                         \
443     xmlGenericError(xmlGenericErrorContext,                             \
444             "Internal error at %s:%d\n",                                \
445             __FILE__, __LINE__);
446
447 #ifdef LIBXML_DEBUG_ENABLED
448 static void
449 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
450     int i;
451     char shift[100];
452
453     for (i = 0;((i < depth) && (i < 25));i++)
454         shift[2 * i] = shift[2 * i + 1] = ' ';
455     shift[2 * i] = shift[2 * i + 1] = 0;
456     if (cur == NULL) {
457         fprintf(output, shift);
458         fprintf(output, "Node is NULL !\n");
459         return;
460         
461     }
462
463     if ((cur->type == XML_DOCUMENT_NODE) ||
464              (cur->type == XML_HTML_DOCUMENT_NODE)) {
465         fprintf(output, shift);
466         fprintf(output, " /\n");
467     } else if (cur->type == XML_ATTRIBUTE_NODE)
468         xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469     else
470         xmlDebugDumpOneNode(output, cur, depth);
471 }
472 static void
473 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
474     xmlNodePtr tmp;
475     int i;
476     char shift[100];
477
478     for (i = 0;((i < depth) && (i < 25));i++)
479         shift[2 * i] = shift[2 * i + 1] = ' ';
480     shift[2 * i] = shift[2 * i + 1] = 0;
481     if (cur == NULL) {
482         fprintf(output, shift);
483         fprintf(output, "Node is NULL !\n");
484         return;
485         
486     }
487
488     while (cur != NULL) {
489         tmp = cur;
490         cur = cur->next;
491         xmlDebugDumpOneNode(output, tmp, depth);
492     }
493 }
494
495 static void
496 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
497     int i;
498     char shift[100];
499
500     for (i = 0;((i < depth) && (i < 25));i++)
501         shift[2 * i] = shift[2 * i + 1] = ' ';
502     shift[2 * i] = shift[2 * i + 1] = 0;
503
504     if (cur == NULL) {
505         fprintf(output, shift);
506         fprintf(output, "NodeSet is NULL !\n");
507         return;
508         
509     }
510
511     if (cur != NULL) {
512         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513         for (i = 0;i < cur->nodeNr;i++) {
514             fprintf(output, shift);
515             fprintf(output, "%d", i + 1);
516             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517         }
518     }
519 }
520
521 static void
522 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
523     int i;
524     char shift[100];
525
526     for (i = 0;((i < depth) && (i < 25));i++)
527         shift[2 * i] = shift[2 * i + 1] = ' ';
528     shift[2 * i] = shift[2 * i + 1] = 0;
529
530     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531         fprintf(output, shift);
532         fprintf(output, "Value Tree is NULL !\n");
533         return;
534         
535     }
536
537     fprintf(output, shift);
538     fprintf(output, "%d", i + 1);
539     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540 }
541 #if defined(LIBXML_XPTR_ENABLED)
542 static void
543 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
544     int i;
545     char shift[100];
546
547     for (i = 0;((i < depth) && (i < 25));i++)
548         shift[2 * i] = shift[2 * i + 1] = ' ';
549     shift[2 * i] = shift[2 * i + 1] = 0;
550
551     if (cur == NULL) {
552         fprintf(output, shift);
553         fprintf(output, "LocationSet is NULL !\n");
554         return;
555         
556     }
557
558     for (i = 0;i < cur->locNr;i++) {
559         fprintf(output, shift);
560         fprintf(output, "%d : ", i + 1);
561         xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562     }
563 }
564 #endif /* LIBXML_XPTR_ENABLED */
565
566 /**
567  * xmlXPathDebugDumpObject:
568  * @output:  the FILE * to dump the output
569  * @cur:  the object to inspect
570  * @depth:  indentation level
571  *
572  * Dump the content of the object for debugging purposes
573  */
574 void
575 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
576     int i;
577     char shift[100];
578
579     for (i = 0;((i < depth) && (i < 25));i++)
580         shift[2 * i] = shift[2 * i + 1] = ' ';
581     shift[2 * i] = shift[2 * i + 1] = 0;
582
583     fprintf(output, shift);
584
585     if (cur == NULL) {
586         fprintf(output, "Object is empty (NULL)\n");
587         return;
588     }
589     switch(cur->type) {
590         case XPATH_UNDEFINED:
591             fprintf(output, "Object is uninitialized\n");
592             break;
593         case XPATH_NODESET:
594             fprintf(output, "Object is a Node Set :\n");
595             xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596             break;
597         case XPATH_XSLT_TREE:
598             fprintf(output, "Object is an XSLT value tree :\n");
599             xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
600             break;
601         case XPATH_BOOLEAN:
602             fprintf(output, "Object is a Boolean : ");
603             if (cur->boolval) fprintf(output, "true\n");
604             else fprintf(output, "false\n");
605             break;
606         case XPATH_NUMBER:
607             switch (xmlXPathIsInf(cur->floatval)) {
608             case 1:
609                 fprintf(output, "Object is a number : Infinity\n");
610                 break;
611             case -1:
612                 fprintf(output, "Object is a number : -Infinity\n");
613                 break;
614             default:
615                 if (xmlXPathIsNaN(cur->floatval)) {
616                     fprintf(output, "Object is a number : NaN\n");
617                 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618                     fprintf(output, "Object is a number : 0\n");
619                 } else {
620                     fprintf(output, "Object is a number : %0g\n", cur->floatval);
621                 }
622             }
623             break;
624         case XPATH_STRING:
625             fprintf(output, "Object is a string : ");
626             xmlDebugDumpString(output, cur->stringval);
627             fprintf(output, "\n");
628             break;
629         case XPATH_POINT:
630             fprintf(output, "Object is a point : index %d in node", cur->index);
631             xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632             fprintf(output, "\n");
633             break;
634         case XPATH_RANGE:
635             if ((cur->user2 == NULL) ||
636                 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637                 fprintf(output, "Object is a collapsed range :\n");
638                 fprintf(output, shift);
639                 if (cur->index >= 0)
640                     fprintf(output, "index %d in ", cur->index);
641                 fprintf(output, "node\n");
642                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643                                       depth + 1);
644             } else  {
645                 fprintf(output, "Object is a range :\n");
646                 fprintf(output, shift);
647                 fprintf(output, "From ");
648                 if (cur->index >= 0)
649                     fprintf(output, "index %d in ", cur->index);
650                 fprintf(output, "node\n");
651                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652                                       depth + 1);
653                 fprintf(output, shift);
654                 fprintf(output, "To ");
655                 if (cur->index2 >= 0)
656                     fprintf(output, "index %d in ", cur->index2);
657                 fprintf(output, "node\n");
658                 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659                                       depth + 1);
660                 fprintf(output, "\n");
661             }
662             break;
663         case XPATH_LOCATIONSET:
664 #if defined(LIBXML_XPTR_ENABLED)
665             fprintf(output, "Object is a Location Set:\n");
666             xmlXPathDebugDumpLocationSet(output,
667                     (xmlLocationSetPtr) cur->user, depth);
668 #endif
669             break;
670         case XPATH_USERS:
671             fprintf(output, "Object is user defined\n");
672             break;
673     }
674 }
675
676 static void
677 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
678                              xmlXPathStepOpPtr op, int depth) {
679     int i;
680     char shift[100];
681
682     for (i = 0;((i < depth) && (i < 25));i++)
683         shift[2 * i] = shift[2 * i + 1] = ' ';
684     shift[2 * i] = shift[2 * i + 1] = 0;
685
686     fprintf(output, shift);
687     if (op == NULL) {
688         fprintf(output, "Step is NULL\n");
689         return;
690     }
691     switch (op->op) {
692         case XPATH_OP_END:
693             fprintf(output, "END"); break;
694         case XPATH_OP_AND:
695             fprintf(output, "AND"); break;
696         case XPATH_OP_OR:
697             fprintf(output, "OR"); break;
698         case XPATH_OP_EQUAL:
699              if (op->value)
700                  fprintf(output, "EQUAL =");
701              else
702                  fprintf(output, "EQUAL !=");
703              break;
704         case XPATH_OP_CMP:
705              if (op->value)
706                  fprintf(output, "CMP <");
707              else
708                  fprintf(output, "CMP >");
709              if (!op->value2)
710                  fprintf(output, "=");
711              break;
712         case XPATH_OP_PLUS:
713              if (op->value == 0)
714                  fprintf(output, "PLUS -");
715              else if (op->value == 1)
716                  fprintf(output, "PLUS +");
717              else if (op->value == 2)
718                  fprintf(output, "PLUS unary -");
719              else if (op->value == 3)
720                  fprintf(output, "PLUS unary - -");
721              break;
722         case XPATH_OP_MULT:
723              if (op->value == 0)
724                  fprintf(output, "MULT *");
725              else if (op->value == 1)
726                  fprintf(output, "MULT div");
727              else
728                  fprintf(output, "MULT mod");
729              break;
730         case XPATH_OP_UNION:
731              fprintf(output, "UNION"); break;
732         case XPATH_OP_ROOT:
733              fprintf(output, "ROOT"); break;
734         case XPATH_OP_NODE:
735              fprintf(output, "NODE"); break;
736         case XPATH_OP_RESET:
737              fprintf(output, "RESET"); break;
738         case XPATH_OP_SORT:
739              fprintf(output, "SORT"); break;
740         case XPATH_OP_COLLECT: {
741             xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
742             xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
743             xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
744             const xmlChar *prefix = op->value4;
745             const xmlChar *name = op->value5;
746
747             fprintf(output, "COLLECT ");
748             switch (axis) {
749                 case AXIS_ANCESTOR:
750                     fprintf(output, " 'ancestors' "); break;
751                 case AXIS_ANCESTOR_OR_SELF:
752                     fprintf(output, " 'ancestors-or-self' "); break;
753                 case AXIS_ATTRIBUTE:
754                     fprintf(output, " 'attributes' "); break;
755                 case AXIS_CHILD:
756                     fprintf(output, " 'child' "); break;
757                 case AXIS_DESCENDANT:
758                     fprintf(output, " 'descendant' "); break;
759                 case AXIS_DESCENDANT_OR_SELF:
760                     fprintf(output, " 'descendant-or-self' "); break;
761                 case AXIS_FOLLOWING:
762                     fprintf(output, " 'following' "); break;
763                 case AXIS_FOLLOWING_SIBLING:
764                     fprintf(output, " 'following-siblings' "); break;
765                 case AXIS_NAMESPACE:
766                     fprintf(output, " 'namespace' "); break;
767                 case AXIS_PARENT:
768                     fprintf(output, " 'parent' "); break;
769                 case AXIS_PRECEDING:
770                     fprintf(output, " 'preceding' "); break;
771                 case AXIS_PRECEDING_SIBLING:
772                     fprintf(output, " 'preceding-sibling' "); break;
773                 case AXIS_SELF:
774                     fprintf(output, " 'self' "); break;
775             }
776             switch (test) {
777                 case NODE_TEST_NONE:
778                     fprintf(output, "'none' "); break;
779                 case NODE_TEST_TYPE:
780                     fprintf(output, "'type' "); break;
781                 case NODE_TEST_PI:
782                     fprintf(output, "'PI' "); break;
783                 case NODE_TEST_ALL:
784                     fprintf(output, "'all' "); break;
785                 case NODE_TEST_NS:
786                     fprintf(output, "'namespace' "); break;
787                 case NODE_TEST_NAME:
788                     fprintf(output, "'name' "); break;
789             }
790             switch (type) {
791                 case NODE_TYPE_NODE:
792                     fprintf(output, "'node' "); break;
793                 case NODE_TYPE_COMMENT:
794                     fprintf(output, "'comment' "); break;
795                 case NODE_TYPE_TEXT:
796                     fprintf(output, "'text' "); break;
797                 case NODE_TYPE_PI:
798                     fprintf(output, "'PI' "); break;
799             }
800             if (prefix != NULL)
801                 fprintf(output, "%s:", prefix);
802             if (name != NULL)
803                 fprintf(output, "%s", (const char *) name);
804             break;
805
806         }
807         case XPATH_OP_VALUE: {
808             xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810             fprintf(output, "ELEM ");
811             xmlXPathDebugDumpObject(output, object, 0);
812             goto finish;
813         }
814         case XPATH_OP_VARIABLE: {
815             const xmlChar *prefix = op->value5;
816             const xmlChar *name = op->value4;
817
818             if (prefix != NULL)
819                 fprintf(output, "VARIABLE %s:%s", prefix, name);
820             else
821                 fprintf(output, "VARIABLE %s", name);
822             break;
823         }
824         case XPATH_OP_FUNCTION: {
825             int nbargs = op->value;
826             const xmlChar *prefix = op->value5;
827             const xmlChar *name = op->value4;
828
829             if (prefix != NULL)
830                 fprintf(output, "FUNCTION %s:%s(%d args)",
831                         prefix, name, nbargs);
832             else
833                 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834             break;
835         }
836         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
838         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
839 #ifdef LIBXML_XPTR_ENABLED
840         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841 #endif
842         default:
843         fprintf(output, "UNKNOWN %d\n", op->op); return;
844     }
845     fprintf(output, "\n");
846 finish:
847     if (op->ch1 >= 0)
848         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849     if (op->ch2 >= 0)
850         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851 }
852
853 /**
854  * xmlXPathDebugDumpCompExpr:
855  * @output:  the FILE * for the output
856  * @comp:  the precompiled XPath expression
857  * @depth:  the indentation level.
858  *
859  * Dumps the tree of the compiled XPath expression.
860  */
861 void
862 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863                           int depth) {
864     int i;
865     char shift[100];
866
867     for (i = 0;((i < depth) && (i < 25));i++)
868         shift[2 * i] = shift[2 * i + 1] = ' ';
869     shift[2 * i] = shift[2 * i + 1] = 0;
870
871     fprintf(output, shift);
872
873     if (comp == NULL) {
874         fprintf(output, "Compiled Expression is NULL\n");
875         return;
876     }
877     fprintf(output, "Compiled Expression : %d elements\n",
878             comp->nbStep);
879     i = comp->last;
880     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881 }
882 #endif /* LIBXML_DEBUG_ENABLED */
883
884 /************************************************************************
885  *                                                                      *
886  *              Parser stacks related functions and macros              *
887  *                                                                      *
888  ************************************************************************/
889
890 /**
891  * valuePop:
892  * @ctxt: an XPath evaluation context
893  *
894  * Pops the top XPath object from the value stack
895  *
896  * Returns the XPath object just removed
897  */
898 extern xmlXPathObjectPtr
899 valuePop(xmlXPathParserContextPtr ctxt)
900 {
901     xmlXPathObjectPtr ret;
902
903     if (ctxt->valueNr <= 0)
904         return (0);
905     ctxt->valueNr--;
906     if (ctxt->valueNr > 0)
907         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908     else
909         ctxt->value = NULL;
910     ret = ctxt->valueTab[ctxt->valueNr];
911     ctxt->valueTab[ctxt->valueNr] = 0;
912     return (ret);
913 }
914 /**
915  * valuePush:
916  * @ctxt:  an XPath evaluation context
917  * @value:  the XPath object
918  *
919  * Pushes a new XPath object on top of the value stack
920  *
921  * returns the number of items on the value stack
922  */
923 extern int
924 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925 {
926     if (ctxt->valueNr >= ctxt->valueMax) {
927         ctxt->valueMax *= 2;
928         ctxt->valueTab =
929             (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930                                              ctxt->valueMax *
931                                              sizeof(ctxt->valueTab[0]));
932         if (ctxt->valueTab == NULL) {
933             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934             return (0);
935         }
936     }
937     ctxt->valueTab[ctxt->valueNr] = value;
938     ctxt->value = value;
939     return (ctxt->valueNr++);
940 }
941
942 /**
943  * xmlXPathPopBoolean:
944  * @ctxt:  an XPath parser context
945  *
946  * Pops a boolean from the stack, handling conversion if needed.
947  * Check error with #xmlXPathCheckError.
948  *
949  * Returns the boolean
950  */
951 int
952 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953     xmlXPathObjectPtr obj;
954     int ret;
955
956     obj = valuePop(ctxt);
957     if (obj == NULL) {
958         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959         return(0);
960     }
961     ret = xmlXPathCastToBoolean(obj);
962     xmlXPathFreeObject(obj);
963     return(ret);
964 }
965
966 /**
967  * xmlXPathPopNumber:
968  * @ctxt:  an XPath parser context
969  *
970  * Pops a number from the stack, handling conversion if needed.
971  * Check error with #xmlXPathCheckError.
972  *
973  * Returns the number
974  */
975 double
976 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977     xmlXPathObjectPtr obj;
978     double ret;
979
980     obj = valuePop(ctxt);
981     if (obj == NULL) {
982         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983         return(0);
984     }
985     ret = xmlXPathCastToNumber(obj);
986     xmlXPathFreeObject(obj);
987     return(ret);
988 }
989
990 /**
991  * xmlXPathPopString:
992  * @ctxt:  an XPath parser context
993  *
994  * Pops a string from the stack, handling conversion if needed.
995  * Check error with #xmlXPathCheckError.
996  *
997  * Returns the string
998  */
999 xmlChar *
1000 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001     xmlXPathObjectPtr obj;
1002     xmlChar * ret;
1003
1004     obj = valuePop(ctxt);
1005     if (obj == NULL) {
1006         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007         return(NULL);
1008     }
1009     ret = xmlXPathCastToString(obj);
1010     /* TODO: needs refactoring somewhere else */
1011     if (obj->stringval == ret)
1012         obj->stringval = NULL;
1013     xmlXPathFreeObject(obj);
1014     return(ret);
1015 }
1016
1017 /**
1018  * xmlXPathPopNodeSet:
1019  * @ctxt:  an XPath parser context
1020  *
1021  * Pops a node-set from the stack, handling conversion if needed.
1022  * Check error with #xmlXPathCheckError.
1023  *
1024  * Returns the node-set
1025  */
1026 xmlNodeSetPtr
1027 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028     xmlXPathObjectPtr obj;
1029     xmlNodeSetPtr ret;
1030
1031     if (ctxt->value == NULL) {
1032         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033         return(NULL);
1034     }
1035     if (!xmlXPathStackIsNodeSet(ctxt)) {
1036         xmlXPathSetTypeError(ctxt);
1037         return(NULL);
1038     }
1039     obj = valuePop(ctxt);
1040     ret = obj->nodesetval;
1041     /* to fix memory leak of not clearing obj->user */
1042     if (obj->boolval && obj->user != NULL)
1043         xmlFreeNodeList((xmlNodePtr) obj->user);
1044     xmlXPathFreeNodeSetList(obj);
1045     return(ret);
1046 }
1047
1048 /**
1049  * xmlXPathPopExternal:
1050  * @ctxt:  an XPath parser context
1051  *
1052  * Pops an external object from the stack, handling conversion if needed.
1053  * Check error with #xmlXPathCheckError.
1054  *
1055  * Returns the object
1056  */
1057 void *
1058 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1059     xmlXPathObjectPtr obj;
1060     void * ret;
1061
1062     if (ctxt->value == NULL) {
1063         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1064         return(NULL);
1065     }
1066     if (ctxt->value->type != XPATH_USERS) {
1067         xmlXPathSetTypeError(ctxt);
1068         return(NULL);
1069     }
1070     obj = valuePop(ctxt);
1071     ret = obj->user;
1072     xmlXPathFreeObject(obj);
1073     return(ret);
1074 }
1075
1076 /*
1077  * Macros for accessing the content. Those should be used only by the parser,
1078  * and not exported.
1079  *
1080  * Dirty macros, i.e. one need to make assumption on the context to use them
1081  *
1082  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
1083  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
1084  *           in ISO-Latin or UTF-8.
1085  *           This should be used internally by the parser
1086  *           only to compare to ASCII values otherwise it would break when
1087  *           running with UTF-8 encoding.
1088  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
1089  *           to compare on ASCII based substring.
1090  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1091  *           strings within the parser.
1092  *   CURRENT Returns the current char value, with the full decoding of
1093  *           UTF-8 if we are using this mode. It returns an int.
1094  *   NEXT    Skip to the next character, this does the proper decoding
1095  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
1096  *           It returns the pointer to the current xmlChar.
1097  */
1098
1099 #define CUR (*ctxt->cur)
1100 #define SKIP(val) ctxt->cur += (val)
1101 #define NXT(val) ctxt->cur[(val)]
1102 #define CUR_PTR ctxt->cur
1103 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1104
1105 #define COPY_BUF(l,b,i,v)                                              \
1106     if (l == 1) b[i++] = (xmlChar) v;                                  \
1107     else i += xmlCopyChar(l,&b[i],v)
1108
1109 #define NEXTL(l)  ctxt->cur += l
1110
1111 #define SKIP_BLANKS                                                     \
1112     while (IS_BLANK(*(ctxt->cur))) NEXT
1113
1114 #define CURRENT (*ctxt->cur)
1115 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
1116
1117
1118 #ifndef DBL_DIG
1119 #define DBL_DIG 16
1120 #endif
1121 #ifndef DBL_EPSILON
1122 #define DBL_EPSILON 1E-9
1123 #endif
1124
1125 #define UPPER_DOUBLE 1E9
1126 #define LOWER_DOUBLE 1E-5
1127
1128 #define INTEGER_DIGITS DBL_DIG
1129 #define FRACTION_DIGITS (DBL_DIG + 1)
1130 #define EXPONENT_DIGITS (3 + 2)
1131
1132 /**
1133  * xmlXPathFormatNumber:
1134  * @number:     number to format
1135  * @buffer:     output buffer
1136  * @buffersize: size of output buffer
1137  *
1138  * Convert the number into a string representation.
1139  */
1140 static void
1141 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1142 {
1143     switch (xmlXPathIsInf(number)) {
1144     case 1:
1145         if (buffersize > (int)sizeof("Infinity"))
1146             snprintf(buffer, buffersize, "Infinity");
1147         break;
1148     case -1:
1149         if (buffersize > (int)sizeof("-Infinity"))
1150             snprintf(buffer, buffersize, "-Infinity");
1151         break;
1152     default:
1153         if (xmlXPathIsNaN(number)) {
1154             if (buffersize > (int)sizeof("NaN"))
1155                 snprintf(buffer, buffersize, "NaN");
1156         } else if (number == 0 && xmlXPathGetSign(number) != 0) {
1157             snprintf(buffer, buffersize, "0");
1158         } else if (number == ((int) number)) {
1159             char work[30];
1160             char *ptr, *cur;
1161             int res, value = (int) number;
1162
1163             ptr = &buffer[0];
1164             if (value < 0) {
1165                 *ptr++ = '-';
1166                 value = -value;
1167             }
1168             if (value == 0) {
1169                 *ptr++ = '0';
1170             } else {
1171                 cur = &work[0];
1172                 while (value != 0) {
1173                     res = value % 10;
1174                     value = value / 10;
1175                     *cur++ = '0' + res;
1176                 }
1177                 cur--;
1178                 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1179                     *ptr++ = *cur--;
1180                 }
1181             }
1182             if (ptr - buffer < buffersize) {
1183                 *ptr = 0;
1184             } else if (buffersize > 0) {
1185                 ptr--;
1186                 *ptr = 0;
1187             }
1188         } else {
1189             /* 3 is sign, decimal point, and terminating zero */
1190             char work[DBL_DIG + EXPONENT_DIGITS + 3];
1191             int integer_place, fraction_place;
1192             char *ptr;
1193             char *after_fraction;
1194             double absolute_value;
1195             int size;
1196
1197             absolute_value = fabs(number);
1198
1199             /*
1200              * First choose format - scientific or regular floating point.
1201              * In either case, result is in work, and after_fraction points
1202              * just past the fractional part.
1203             */
1204             if ( ((absolute_value > UPPER_DOUBLE) ||
1205                   (absolute_value < LOWER_DOUBLE)) &&
1206                  (absolute_value != 0.0) ) {
1207                 /* Use scientific notation */
1208                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1209                 fraction_place = DBL_DIG - 1;
1210                 snprintf(work, sizeof(work),"%*.*e",
1211                          integer_place, fraction_place, number);
1212                 after_fraction = strchr(work + DBL_DIG, 'e');
1213             }
1214             else {
1215                 /* Use regular notation */
1216                 if (absolute_value > 0.0)
1217                     integer_place = 1 + (int)log10(absolute_value);
1218                 else
1219                     integer_place = 0;
1220                 fraction_place = (integer_place > 0)
1221                     ? DBL_DIG - integer_place
1222                     : DBL_DIG;
1223                 size = snprintf(work, sizeof(work), "%0.*f",
1224                                 fraction_place, number);
1225                 after_fraction = work + size;
1226             }
1227
1228             /* Remove fractional trailing zeroes */
1229             ptr = after_fraction;
1230             while (*(--ptr) == '0')
1231                 ;
1232             if (*ptr != '.')
1233                 ptr++;
1234             strcpy(ptr, after_fraction);
1235
1236             /* Finally copy result back to caller */
1237             size = strlen(work) + 1;
1238             if (size > buffersize) {
1239                 work[buffersize - 1] = 0;
1240                 size = buffersize;
1241             }
1242             memcpy(buffer, work, size);
1243         }
1244         break;
1245     }
1246 }
1247
1248 /************************************************************************
1249  *                                                                      *
1250  *                      Error handling routines                         *
1251  *                                                                      *
1252  ************************************************************************/
1253
1254
1255 static const char *xmlXPathErrorMessages[] = {
1256     "Ok",
1257     "Number encoding",
1258     "Unfinished literal",
1259     "Start of literal",
1260     "Expected $ for variable reference",
1261     "Undefined variable",
1262     "Invalid predicate",
1263     "Invalid expression",
1264     "Missing closing curly brace",
1265     "Unregistered function",
1266     "Invalid operand",
1267     "Invalid type",
1268     "Invalid number of arguments",
1269     "Invalid context size",
1270     "Invalid context position",
1271     "Memory allocation error",
1272     "Syntax error",
1273     "Resource error",
1274     "Sub resource error",
1275     "Undefined namespace prefix",
1276     "Encoding error",
1277     "Char out of XML range"
1278 };
1279
1280 /**
1281  * xmlXPatherror:
1282  * @ctxt:  the XPath Parser context
1283  * @file:  the file name
1284  * @line:  the line number
1285  * @no:  the error number
1286  *
1287  * Formats an error message.
1288  */
1289 void
1290 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1291               int line ATTRIBUTE_UNUSED, int no) {
1292     int n;
1293     const xmlChar *cur;
1294     const xmlChar *base;
1295
1296     cur = ctxt->cur;
1297     base = ctxt->base;
1298     if ((cur == NULL) || (base == NULL)) {
1299         if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1300             xmlGenericError(xmlGenericErrorContext,
1301                     "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1302                             ctxt->comp->expr);
1303         } else {
1304             xmlGenericError(xmlGenericErrorContext,
1305                     "XPath error %s\n", xmlXPathErrorMessages[no]);
1306         }
1307
1308         return;
1309     }
1310     xmlGenericError(xmlGenericErrorContext,
1311             "XPath error %s\n", xmlXPathErrorMessages[no]);
1312
1313     while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1314         cur--;
1315     }
1316     n = 0;
1317     while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1318         cur--;
1319     if ((*cur == '\n') || (*cur == '\r')) cur++;
1320     base = cur;
1321     n = 0;
1322     while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1323         xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1324         n++;
1325     }
1326     xmlGenericError(xmlGenericErrorContext, "\n");
1327     cur = ctxt->cur;
1328     while ((*cur == '\n') || (*cur == '\r'))
1329         cur--;
1330     n = 0;
1331     while ((cur != base) && (n++ < 80)) {
1332         xmlGenericError(xmlGenericErrorContext, " ");
1333         base++;
1334     }
1335     xmlGenericError(xmlGenericErrorContext,"^\n");
1336 }
1337
1338
1339 /************************************************************************
1340  *                                                                      *
1341  *                      Routines to handle NodeSets                     *
1342  *                                                                      *
1343  ************************************************************************/
1344
1345 /**
1346  * xmlXPathOrderDocElems:
1347  * @doc:  an input document
1348  *
1349  * Call this routine to speed up XPath computation on static documents.
1350  * This stamps all the element nodes with the document order
1351  * Like for line information, the order is kept in the element->content
1352  * field, the value stored is actually - the node number (startting at -1)
1353  * to be able to differenciate from line numbers.
1354  *
1355  * Returns the number of element found in the document or -1 in case
1356  *    of error.
1357  */
1358 long
1359 xmlXPathOrderDocElems(xmlDocPtr doc) {
1360     long count = 0;
1361     xmlNodePtr cur;
1362
1363     if (doc == NULL)
1364         return(-1);
1365     cur = doc->children;
1366     while (cur != NULL) {
1367         if (cur->type == XML_ELEMENT_NODE) {
1368             cur->content = (void *) (-(++count));
1369             if (cur->children != NULL) {
1370                 cur = cur->children;
1371                 continue;
1372             }
1373         }
1374         if (cur->next != NULL) {
1375             cur = cur->next;
1376             continue;
1377         }
1378         do {
1379             cur = cur->parent;
1380             if (cur == NULL)
1381                 break;
1382             if (cur == (xmlNodePtr) doc) {
1383                 cur = NULL;
1384                 break;
1385             }
1386             if (cur->next != NULL) {
1387                 cur = cur->next;
1388                 break;
1389             }
1390         } while (cur != NULL);
1391     }
1392     return(count);
1393 }
1394
1395 /**
1396  * xmlXPathCmpNodes:
1397  * @node1:  the first node
1398  * @node2:  the second node
1399  *
1400  * Compare two nodes w.r.t document order
1401  *
1402  * Returns -2 in case of error 1 if first point < second point, 0 if
1403  *         that's the same node, -1 otherwise
1404  */
1405 int
1406 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1407     int depth1, depth2;
1408     int attr1 = 0, attr2 = 0;
1409     xmlNodePtr cur, root;
1410
1411     if ((node1 == NULL) || (node2 == NULL))
1412         return(-2);
1413     /*
1414      * a couple of optimizations which will avoid computations in most cases
1415      */
1416     if (node1->type == XML_ATTRIBUTE_NODE) {
1417         attr1 = 1;
1418         node1 = node1->parent;
1419     }
1420     if (node2->type == XML_ATTRIBUTE_NODE) {
1421         attr2 = 1;
1422         node2 = node2->parent;
1423     }
1424     if (node1 == node2) {
1425         if (attr1 == attr2)
1426             return(0);
1427         if (attr2 == 1)
1428             return(1);
1429         return(-1);
1430     }
1431     if ((node1->type == XML_NAMESPACE_DECL) ||
1432         (node2->type == XML_NAMESPACE_DECL))
1433         return(1);
1434     if (node1 == node2->prev)
1435         return(1);
1436     if (node1 == node2->next)
1437         return(-1);
1438
1439     /*
1440      * Speedup using document order if availble.
1441      */
1442     if ((node1->type == XML_ELEMENT_NODE) &&
1443         (node2->type == XML_ELEMENT_NODE) &&
1444         (0 > (long) node1->content) &&
1445         (0 > (long) node2->content) &&
1446         (node1->doc == node2->doc)) {
1447         long l1, l2;
1448
1449         l1 = -((long) node1->content);
1450         l2 = -((long) node2->content);
1451         if (l1 < l2)
1452             return(1);
1453         if (l1 > l2)
1454             return(-1);
1455     }
1456
1457     /*
1458      * compute depth to root
1459      */
1460     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1461         if (cur == node1)
1462             return(1);
1463         depth2++;
1464     }
1465     root = cur;
1466     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1467         if (cur == node2)
1468             return(-1);
1469         depth1++;
1470     }
1471     /*
1472      * Distinct document (or distinct entities :-( ) case.
1473      */
1474     if (root != cur) {
1475         return(-2);
1476     }
1477     /*
1478      * get the nearest common ancestor.
1479      */
1480     while (depth1 > depth2) {
1481         depth1--;
1482         node1 = node1->parent;
1483     }
1484     while (depth2 > depth1) {
1485         depth2--;
1486         node2 = node2->parent;
1487     }
1488     while (node1->parent != node2->parent) {
1489         node1 = node1->parent;
1490         node2 = node2->parent;
1491         /* should not happen but just in case ... */
1492         if ((node1 == NULL) || (node2 == NULL))
1493             return(-2);
1494     }
1495     /*
1496      * Find who's first.
1497      */
1498     if (node1 == node2->next)
1499         return(-1);
1500     for (cur = node1->next;cur != NULL;cur = cur->next)
1501         if (cur == node2)
1502             return(1);
1503     return(-1); /* assume there is no sibling list corruption */
1504 }
1505
1506 /**
1507  * xmlXPathNodeSetSort:
1508  * @set:  the node set
1509  *
1510  * Sort the node set in document order
1511  */
1512 void
1513 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
1514     int i, j, incr, len;
1515     xmlNodePtr tmp;
1516
1517     if (set == NULL)
1518         return;
1519
1520     /* Use Shell's sort to sort the node-set */
1521     len = set->nodeNr;
1522     for (incr = len / 2; incr > 0; incr /= 2) {
1523         for (i = incr; i < len; i++) {
1524             j = i - incr;
1525             while (j >= 0) {
1526                 if (xmlXPathCmpNodes(set->nodeTab[j],
1527                                      set->nodeTab[j + incr]) == -1) {
1528                     tmp = set->nodeTab[j];
1529                     set->nodeTab[j] = set->nodeTab[j + incr];
1530                     set->nodeTab[j + incr] = tmp;
1531                     j -= incr;
1532                 } else
1533                     break;
1534             }
1535         }
1536     }
1537 }
1538
1539 #define XML_NODESET_DEFAULT     10
1540 /**
1541  * xmlXPathNodeSetDupNs:
1542  * @node:  the parent node of the namespace XPath node
1543  * @ns:  the libxml namespace declaration node.
1544  *
1545  * Namespace node in libxml don't match the XPath semantic. In a node set
1546  * the namespace nodes are duplicated and the next pointer is set to the
1547  * parent node in the XPath semantic.
1548  *
1549  * Returns the newly created object.
1550  */
1551 static xmlNodePtr
1552 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1553     xmlNsPtr cur;
1554
1555     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1556         return(NULL);
1557     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1558         return((xmlNodePtr) ns);
1559
1560     /*
1561      * Allocate a new Namespace and fill the fields.
1562      */
1563     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1564     if (cur == NULL) {
1565         xmlGenericError(xmlGenericErrorContext,
1566                 "xmlXPathNodeSetDupNs : malloc failed\n");
1567         return(NULL);
1568     }
1569     memset(cur, 0, sizeof(xmlNs));
1570     cur->type = XML_NAMESPACE_DECL;
1571     if (ns->href != NULL)
1572         cur->href = xmlStrdup(ns->href); 
1573     if (ns->prefix != NULL)
1574         cur->prefix = xmlStrdup(ns->prefix); 
1575     cur->next = (xmlNsPtr) node;
1576     return((xmlNodePtr) cur);
1577 }
1578
1579 /**
1580  * xmlXPathNodeSetFreeNs:
1581  * @ns:  the XPath namespace node found in a nodeset.
1582  *
1583  * Namespace node in libxml don't match the XPath semantic. In a node set
1584  * the namespace nodes are duplicated and the next pointer is set to the
1585  * parent node in the XPath semantic. Check if such a node need to be freed
1586  */
1587 void
1588 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1589     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1590         return;
1591
1592     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1593         if (ns->href != NULL)
1594             xmlFree((xmlChar *)ns->href);
1595         if (ns->prefix != NULL)
1596             xmlFree((xmlChar *)ns->prefix);
1597         xmlFree(ns);
1598     }
1599 }
1600
1601 /**
1602  * xmlXPathNodeSetCreate:
1603  * @val:  an initial xmlNodePtr, or NULL
1604  *
1605  * Create a new xmlNodeSetPtr of type double and of value @val
1606  *
1607  * Returns the newly created object.
1608  */
1609 xmlNodeSetPtr
1610 xmlXPathNodeSetCreate(xmlNodePtr val) {
1611     xmlNodeSetPtr ret;
1612
1613     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1614     if (ret == NULL) {
1615         xmlGenericError(xmlGenericErrorContext,
1616                 "xmlXPathNodeSetCreate: out of memory\n");
1617         return(NULL);
1618     }
1619     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1620     if (val != NULL) {
1621         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1622                                              sizeof(xmlNodePtr));
1623         if (ret->nodeTab == NULL) {
1624             xmlGenericError(xmlGenericErrorContext,
1625                     "xmlXPathNodeSetCreate: out of memory\n");
1626             return(NULL);
1627         }
1628         memset(ret->nodeTab, 0 ,
1629                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1630         ret->nodeMax = XML_NODESET_DEFAULT;
1631         if (val->type == XML_NAMESPACE_DECL) {
1632             xmlNsPtr ns = (xmlNsPtr) val;
1633
1634             ret->nodeTab[ret->nodeNr++] =
1635                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1636         } else
1637             ret->nodeTab[ret->nodeNr++] = val;
1638     }
1639     return(ret);
1640 }
1641
1642 /**
1643  * xmlXPathNodeSetContains:
1644  * @cur:  the node-set
1645  * @val:  the node
1646  *
1647  * checks whether @cur contains @val
1648  *
1649  * Returns true (1) if @cur contains @val, false (0) otherwise
1650  */
1651 int
1652 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1653     int i;
1654
1655     if (val->type == XML_NAMESPACE_DECL) {
1656         for (i = 0; i < cur->nodeNr; i++) {
1657             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1658                 xmlNsPtr ns1, ns2;
1659
1660                 ns1 = (xmlNsPtr) val;
1661                 ns2 = (xmlNsPtr) cur->nodeTab[i];
1662                 if (ns1 == ns2)
1663                     return(1);
1664                 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1665                     (xmlStrEqual(ns1->prefix, ns2->prefix)))
1666                     return(1);
1667             }
1668         }
1669     } else {
1670         for (i = 0; i < cur->nodeNr; i++) {
1671             if (cur->nodeTab[i] == val)
1672                 return(1);
1673         }
1674     }
1675     return(0);
1676 }
1677
1678 /**
1679  * xmlXPathNodeSetAddNs:
1680  * @cur:  the initial node set
1681  * @node:  the hosting node
1682  * @ns:  a the namespace node
1683  *
1684  * add a new namespace node to an existing NodeSet
1685  */
1686 void
1687 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1688     int i;
1689
1690     if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1691         (node->type != XML_ELEMENT_NODE))
1692         return;
1693
1694     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1695     /*
1696      * check against doublons
1697      */
1698     for (i = 0;i < cur->nodeNr;i++) {
1699         if ((cur->nodeTab[i] != NULL) &&
1700             (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
1701             (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
1702             (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1703             return;
1704     }
1705
1706     /*
1707      * grow the nodeTab if needed
1708      */
1709     if (cur->nodeMax == 0) {
1710         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1711                                              sizeof(xmlNodePtr));
1712         if (cur->nodeTab == NULL) {
1713             xmlGenericError(xmlGenericErrorContext,
1714                     "xmlXPathNodeSetAdd: out of memory\n");
1715             return;
1716         }
1717         memset(cur->nodeTab, 0 ,
1718                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1719         cur->nodeMax = XML_NODESET_DEFAULT;
1720     } else if (cur->nodeNr == cur->nodeMax) {
1721         xmlNodePtr *temp;
1722
1723         cur->nodeMax *= 2;
1724         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1725                                       sizeof(xmlNodePtr));
1726         if (temp == NULL) {
1727             xmlGenericError(xmlGenericErrorContext,
1728                     "xmlXPathNodeSetAdd: out of memory\n");
1729             return;
1730         }
1731         cur->nodeTab = temp;
1732     }
1733     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1734 }
1735
1736 /**
1737  * xmlXPathNodeSetAdd:
1738  * @cur:  the initial node set
1739  * @val:  a new xmlNodePtr
1740  *
1741  * add a new xmlNodePtr to an existing NodeSet
1742  */
1743 void
1744 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1745     int i;
1746
1747     if (val == NULL) return;
1748
1749 #if 0
1750     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1751         return; /* an XSLT fake node */
1752 #endif
1753
1754     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1755     /*
1756      * check against doublons
1757      */
1758     for (i = 0;i < cur->nodeNr;i++)
1759         if (cur->nodeTab[i] == val) return;
1760
1761     /*
1762      * grow the nodeTab if needed
1763      */
1764     if (cur->nodeMax == 0) {
1765         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1766                                              sizeof(xmlNodePtr));
1767         if (cur->nodeTab == NULL) {
1768             xmlGenericError(xmlGenericErrorContext,
1769                     "xmlXPathNodeSetAdd: out of memory\n");
1770             return;
1771         }
1772         memset(cur->nodeTab, 0 ,
1773                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1774         cur->nodeMax = XML_NODESET_DEFAULT;
1775     } else if (cur->nodeNr == cur->nodeMax) {
1776         xmlNodePtr *temp;
1777
1778         cur->nodeMax *= 2;
1779         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1780                                       sizeof(xmlNodePtr));
1781         if (temp == NULL) {
1782             xmlGenericError(xmlGenericErrorContext,
1783                     "xmlXPathNodeSetAdd: out of memory\n");
1784             return;
1785         }
1786         cur->nodeTab = temp;
1787     }
1788     if (val->type == XML_NAMESPACE_DECL) {
1789         xmlNsPtr ns = (xmlNsPtr) val;
1790
1791         cur->nodeTab[cur->nodeNr++] = 
1792             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793     } else
1794         cur->nodeTab[cur->nodeNr++] = val;
1795 }
1796
1797 /**
1798  * xmlXPathNodeSetAddUnique:
1799  * @cur:  the initial node set
1800  * @val:  a new xmlNodePtr
1801  *
1802  * add a new xmlNodePtr to an existing NodeSet, optimized version
1803  * when we are sure the node is not already in the set.
1804  */
1805 void
1806 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1807     if (val == NULL) return;
1808
1809 #if 0
1810     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1811         return; /* an XSLT fake node */
1812 #endif
1813
1814     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1815     /*
1816      * grow the nodeTab if needed
1817      */
1818     if (cur->nodeMax == 0) {
1819         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1820                                              sizeof(xmlNodePtr));
1821         if (cur->nodeTab == NULL) {
1822             xmlGenericError(xmlGenericErrorContext,
1823                     "xmlXPathNodeSetAddUnique: out of memory\n");
1824             return;
1825         }
1826         memset(cur->nodeTab, 0 ,
1827                XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1828         cur->nodeMax = XML_NODESET_DEFAULT;
1829     } else if (cur->nodeNr == cur->nodeMax) {
1830         xmlNodePtr *temp;
1831
1832         cur->nodeMax *= 2;
1833         temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1834                                       sizeof(xmlNodePtr));
1835         if (temp == NULL) {
1836             xmlGenericError(xmlGenericErrorContext,
1837                     "xmlXPathNodeSetAddUnique: out of memory\n");
1838             return;
1839         }
1840         cur->nodeTab = temp;
1841     }
1842     if (val->type == XML_NAMESPACE_DECL) {
1843         xmlNsPtr ns = (xmlNsPtr) val;
1844
1845         cur->nodeTab[cur->nodeNr++] = 
1846             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847     } else
1848         cur->nodeTab[cur->nodeNr++] = val;
1849 }
1850
1851 /**
1852  * xmlXPathNodeSetMerge:
1853  * @val1:  the first NodeSet or NULL
1854  * @val2:  the second NodeSet
1855  *
1856  * Merges two nodesets, all nodes from @val2 are added to @val1
1857  * if @val1 is NULL, a new set is created and copied from @val2
1858  *
1859  * Returns @val1 once extended or NULL in case of error.
1860  */
1861 xmlNodeSetPtr
1862 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1863     int i, j, initNr, skip;
1864
1865     if (val2 == NULL) return(val1);
1866     if (val1 == NULL) {
1867         val1 = xmlXPathNodeSetCreate(NULL);
1868     }
1869
1870     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1871     initNr = val1->nodeNr;
1872
1873     for (i = 0;i < val2->nodeNr;i++) {
1874         /*
1875          * check against doublons
1876          */
1877         skip = 0;
1878         for (j = 0; j < initNr; j++) {
1879             if (val1->nodeTab[j] == val2->nodeTab[i]) {
1880                 skip = 1;
1881                 break;
1882             } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1883                        (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1884                 xmlNsPtr ns1, ns2;
1885                 ns1 = (xmlNsPtr) val1->nodeTab[j];
1886                 ns2 = (xmlNsPtr) val2->nodeTab[i];
1887                 if ((ns1->next == ns2->next) &&
1888                     (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1889                     skip = 1;
1890                     break;
1891                 }
1892             }
1893         }
1894         if (skip)
1895             continue;
1896
1897         /*
1898          * grow the nodeTab if needed
1899          */
1900         if (val1->nodeMax == 0) {
1901             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1902                                                     sizeof(xmlNodePtr));
1903             if (val1->nodeTab == NULL) {
1904                 xmlGenericError(xmlGenericErrorContext,
1905                                 "xmlXPathNodeSetMerge: out of memory\n");
1906                 return(NULL);
1907             }
1908             memset(val1->nodeTab, 0 ,
1909                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1910             val1->nodeMax = XML_NODESET_DEFAULT;
1911         } else if (val1->nodeNr == val1->nodeMax) {
1912             xmlNodePtr *temp;
1913
1914             val1->nodeMax *= 2;
1915             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1916                                              sizeof(xmlNodePtr));
1917             if (temp == NULL) {
1918                 xmlGenericError(xmlGenericErrorContext,
1919                                 "xmlXPathNodeSetMerge: out of memory\n");
1920                 return(NULL);
1921             }
1922             val1->nodeTab = temp;
1923         }
1924         if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1925             xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1926
1927             val1->nodeTab[val1->nodeNr++] =
1928                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1929         } else
1930             val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1931     }
1932
1933     return(val1);
1934 }
1935
1936 /**
1937  * xmlXPathNodeSetMergeUnique:
1938  * @val1:  the first NodeSet or NULL
1939  * @val2:  the second NodeSet
1940  *
1941  * Merges two nodesets, all nodes from @val2 are added to @val1
1942  * if @val1 is NULL, a new set is created and copied from @val2
1943  *
1944  * Returns @val1 once extended or NULL in case of error.
1945  */
1946 static xmlNodeSetPtr
1947 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1948     int i;
1949
1950     if (val2 == NULL) return(val1);
1951     if (val1 == NULL) {
1952         val1 = xmlXPathNodeSetCreate(NULL);
1953     }
1954
1955     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1956
1957     for (i = 0;i < val2->nodeNr;i++) {
1958         /*
1959          * grow the nodeTab if needed
1960          */
1961         if (val1->nodeMax == 0) {
1962             val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1963                                                     sizeof(xmlNodePtr));
1964             if (val1->nodeTab == NULL) {
1965                 xmlGenericError(xmlGenericErrorContext,
1966                                 "xmlXPathNodeSetMerge: out of memory\n");
1967                 return(NULL);
1968             }
1969             memset(val1->nodeTab, 0 ,
1970                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1971             val1->nodeMax = XML_NODESET_DEFAULT;
1972         } else if (val1->nodeNr == val1->nodeMax) {
1973             xmlNodePtr *temp;
1974
1975             val1->nodeMax *= 2;
1976             temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1977                                              sizeof(xmlNodePtr));
1978             if (temp == NULL) {
1979                 xmlGenericError(xmlGenericErrorContext,
1980                                 "xmlXPathNodeSetMerge: out of memory\n");
1981                 return(NULL);
1982             }
1983             val1->nodeTab = temp;
1984         }
1985         if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1986             xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1987
1988             val1->nodeTab[val1->nodeNr++] =
1989                 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1990         } else
1991             val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1992     }
1993
1994     return(val1);
1995 }
1996
1997 /**
1998  * xmlXPathNodeSetDel:
1999  * @cur:  the initial node set
2000  * @val:  an xmlNodePtr
2001  *
2002  * Removes an xmlNodePtr from an existing NodeSet
2003  */
2004 void
2005 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2006     int i;
2007
2008     if (cur == NULL) return;
2009     if (val == NULL) return;
2010
2011     /*
2012      * check against doublons
2013      */
2014     for (i = 0;i < cur->nodeNr;i++)
2015         if (cur->nodeTab[i] == val) break;
2016
2017     if (i >= cur->nodeNr) {
2018 #ifdef DEBUG
2019         xmlGenericError(xmlGenericErrorContext, 
2020                 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2021                 val->name);
2022 #endif
2023         return;
2024     }
2025     if ((cur->nodeTab[i] != NULL) &&
2026         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2027         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
2028     cur->nodeNr--;
2029     for (;i < cur->nodeNr;i++)
2030         cur->nodeTab[i] = cur->nodeTab[i + 1];
2031     cur->nodeTab[cur->nodeNr] = NULL;
2032 }
2033
2034 /**
2035  * xmlXPathNodeSetRemove:
2036  * @cur:  the initial node set
2037  * @val:  the index to remove
2038  *
2039  * Removes an entry from an existing NodeSet list.
2040  */
2041 void
2042 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2043     if (cur == NULL) return;
2044     if (val >= cur->nodeNr) return;
2045     if ((cur->nodeTab[val] != NULL) &&
2046         (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2047         xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
2048     cur->nodeNr--;
2049     for (;val < cur->nodeNr;val++)
2050         cur->nodeTab[val] = cur->nodeTab[val + 1];
2051     cur->nodeTab[cur->nodeNr] = NULL;
2052 }
2053
2054 /**
2055  * xmlXPathFreeNodeSet:
2056  * @obj:  the xmlNodeSetPtr to free
2057  *
2058  * Free the NodeSet compound (not the actual nodes !).
2059  */
2060 void
2061 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2062     if (obj == NULL) return;
2063     if (obj->nodeTab != NULL) {
2064         int i;
2065
2066         /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2067         for (i = 0;i < obj->nodeNr;i++)
2068             if ((obj->nodeTab[i] != NULL) &&
2069                 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2070                 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2071         xmlFree(obj->nodeTab);
2072     }
2073     xmlFree(obj);
2074 }
2075
2076 /**
2077  * xmlXPathFreeValueTree:
2078  * @obj:  the xmlNodeSetPtr to free
2079  *
2080  * Free the NodeSet compound and the actual tree, this is different
2081  * from xmlXPathFreeNodeSet()
2082  */
2083 static void
2084 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2085     int i;
2086
2087     if (obj == NULL) return;
2088
2089     if (obj->nodeTab != NULL) {
2090         for (i = 0;i < obj->nodeNr;i++) {
2091             if (obj->nodeTab[i] != NULL) {
2092                 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2093                     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2094                 } else {
2095                     xmlFreeNodeList(obj->nodeTab[i]);
2096                 }
2097             }
2098         }
2099         xmlFree(obj->nodeTab);
2100     }
2101     xmlFree(obj);
2102 }
2103
2104 #if defined(DEBUG) || defined(DEBUG_STEP)
2105 /**
2106  * xmlGenericErrorContextNodeSet:
2107  * @output:  a FILE * for the output
2108  * @obj:  the xmlNodeSetPtr to free
2109  *
2110  * Quick display of a NodeSet
2111  */
2112 void
2113 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2114     int i;
2115
2116     if (output == NULL) output = xmlGenericErrorContext;
2117     if (obj == NULL)  {
2118         fprintf(output, "NodeSet == NULL !\n");
2119         return;
2120     }
2121     if (obj->nodeNr == 0) {
2122         fprintf(output, "NodeSet is empty\n");
2123         return;
2124     }
2125     if (obj->nodeTab == NULL) {
2126         fprintf(output, " nodeTab == NULL !\n");
2127         return;
2128     }
2129     for (i = 0; i < obj->nodeNr; i++) {
2130         if (obj->nodeTab[i] == NULL) {
2131             fprintf(output, " NULL !\n");
2132             return;
2133         }
2134         if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2135             (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2136             fprintf(output, " /");
2137         else if (obj->nodeTab[i]->name == NULL)
2138             fprintf(output, " noname!");
2139         else fprintf(output, " %s", obj->nodeTab[i]->name);
2140     }
2141     fprintf(output, "\n");
2142 }
2143 #endif
2144
2145 /**
2146  * xmlXPathNewNodeSet:
2147  * @val:  the NodePtr value
2148  *
2149  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2150  * it with the single Node @val
2151  *
2152  * Returns the newly created object.
2153  */
2154 xmlXPathObjectPtr
2155 xmlXPathNewNodeSet(xmlNodePtr val) {
2156     xmlXPathObjectPtr ret;
2157
2158     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2159     if (ret == NULL) {
2160         xmlGenericError(xmlGenericErrorContext,
2161                 "xmlXPathNewNodeSet: out of memory\n");
2162         return(NULL);
2163     }
2164     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2165     ret->type = XPATH_NODESET;
2166     ret->boolval = 0;
2167     ret->nodesetval = xmlXPathNodeSetCreate(val);
2168     /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2169     return(ret);
2170 }
2171
2172 /**
2173  * xmlXPathNewValueTree:
2174  * @val:  the NodePtr value
2175  *
2176  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2177  * it with the tree root @val
2178  *
2179  * Returns the newly created object.
2180  */
2181 xmlXPathObjectPtr
2182 xmlXPathNewValueTree(xmlNodePtr val) {
2183     xmlXPathObjectPtr ret;
2184
2185     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2186     if (ret == NULL) {
2187         xmlGenericError(xmlGenericErrorContext,
2188                 "xmlXPathNewNodeSet: out of memory\n");
2189         return(NULL);
2190     }
2191     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2192     ret->type = XPATH_XSLT_TREE;
2193     ret->boolval = 1;
2194     ret->user = (void *) val;
2195     ret->nodesetval = xmlXPathNodeSetCreate(val);
2196     return(ret);
2197 }
2198
2199 /**
2200  * xmlXPathNewNodeSetList:
2201  * @val:  an existing NodeSet
2202  *
2203  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2204  * it with the Nodeset @val
2205  *
2206  * Returns the newly created object.
2207  */
2208 xmlXPathObjectPtr
2209 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2210 {
2211     xmlXPathObjectPtr ret;
2212     int i;
2213
2214     if (val == NULL)
2215         ret = NULL;
2216     else if (val->nodeTab == NULL)
2217         ret = xmlXPathNewNodeSet(NULL);
2218     else {
2219         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2220         for (i = 1; i < val->nodeNr; ++i)
2221             xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2222     }
2223
2224     return (ret);
2225 }
2226
2227 /**
2228  * xmlXPathWrapNodeSet:
2229  * @val:  the NodePtr value
2230  *
2231  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2232  *
2233  * Returns the newly created object.
2234  */
2235 xmlXPathObjectPtr
2236 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2237     xmlXPathObjectPtr ret;
2238
2239     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2240     if (ret == NULL) {
2241         xmlGenericError(xmlGenericErrorContext,
2242                 "xmlXPathWrapNodeSet: out of memory\n");
2243         return(NULL);
2244     }
2245     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2246     ret->type = XPATH_NODESET;
2247     ret->nodesetval = val;
2248     return(ret);
2249 }
2250
2251 /**
2252  * xmlXPathFreeNodeSetList:
2253  * @obj:  an existing NodeSetList object
2254  *
2255  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2256  * the list contrary to xmlXPathFreeObject().
2257  */
2258 void
2259 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2260     if (obj == NULL) return;
2261     xmlFree(obj);
2262 }
2263
2264 /**
2265  * xmlXPathDifference:
2266  * @nodes1:  a node-set
2267  * @nodes2:  a node-set
2268  *
2269  * Implements the EXSLT - Sets difference() function:
2270  *    node-set set:difference (node-set, node-set)
2271  *
2272  * Returns the difference between the two node sets, or nodes1 if
2273  *         nodes2 is empty
2274  */
2275 xmlNodeSetPtr
2276 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2277     xmlNodeSetPtr ret;
2278     int i, l1;
2279     xmlNodePtr cur;
2280
2281     if (xmlXPathNodeSetIsEmpty(nodes2))
2282         return(nodes1);
2283
2284     ret = xmlXPathNodeSetCreate(NULL);
2285     if (xmlXPathNodeSetIsEmpty(nodes1))
2286         return(ret);
2287
2288     l1 = xmlXPathNodeSetGetLength(nodes1);
2289
2290     for (i = 0; i < l1; i++) {
2291         cur = xmlXPathNodeSetItem(nodes1, i);
2292         if (!xmlXPathNodeSetContains(nodes2, cur))
2293             xmlXPathNodeSetAddUnique(ret, cur);
2294     }
2295     return(ret);
2296 }
2297
2298 /**
2299  * xmlXPathIntersection:
2300  * @nodes1:  a node-set
2301  * @nodes2:  a node-set
2302  *
2303  * Implements the EXSLT - Sets intersection() function:
2304  *    node-set set:intersection (node-set, node-set)
2305  *
2306  * Returns a node set comprising the nodes that are within both the
2307  *         node sets passed as arguments
2308  */
2309 xmlNodeSetPtr
2310 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2311     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2312     int i, l1;
2313     xmlNodePtr cur;
2314
2315     if (xmlXPathNodeSetIsEmpty(nodes1))
2316         return(ret);
2317     if (xmlXPathNodeSetIsEmpty(nodes2))
2318         return(ret);
2319
2320     l1 = xmlXPathNodeSetGetLength(nodes1);
2321
2322     for (i = 0; i < l1; i++) {
2323         cur = xmlXPathNodeSetItem(nodes1, i);
2324         if (xmlXPathNodeSetContains(nodes2, cur))
2325             xmlXPathNodeSetAddUnique(ret, cur);
2326     }
2327     return(ret);
2328 }
2329
2330 /**
2331  * xmlXPathDistinctSorted:
2332  * @nodes:  a node-set, sorted by document order
2333  *
2334  * Implements the EXSLT - Sets distinct() function:
2335  *    node-set set:distinct (node-set)
2336  * 
2337  * Returns a subset of the nodes contained in @nodes, or @nodes if
2338  *         it is empty
2339  */
2340 xmlNodeSetPtr
2341 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2342     xmlNodeSetPtr ret;
2343     xmlHashTablePtr hash;
2344     int i, l;
2345     xmlChar * strval;
2346     xmlNodePtr cur;
2347
2348     if (xmlXPathNodeSetIsEmpty(nodes))
2349         return(nodes);
2350
2351     ret = xmlXPathNodeSetCreate(NULL);
2352     l = xmlXPathNodeSetGetLength(nodes);
2353     hash = xmlHashCreate (l);
2354     for (i = 0; i < l; i++) {
2355         cur = xmlXPathNodeSetItem(nodes, i);
2356         strval = xmlXPathCastNodeToString(cur);
2357         if (xmlHashLookup(hash, strval) == NULL) {
2358             xmlHashAddEntry(hash, strval, strval);
2359             xmlXPathNodeSetAddUnique(ret, cur);
2360         } else {
2361             xmlFree(strval);
2362         }
2363     }
2364     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2365     return(ret);
2366 }
2367
2368 /**
2369  * xmlXPathDistinct:
2370  * @nodes:  a node-set
2371  *
2372  * Implements the EXSLT - Sets distinct() function:
2373  *    node-set set:distinct (node-set)
2374  * @nodes is sorted by document order, then #exslSetsDistinctSorted
2375  * is called with the sorted node-set
2376  *
2377  * Returns a subset of the nodes contained in @nodes, or @nodes if
2378  *         it is empty
2379  */
2380 xmlNodeSetPtr
2381 xmlXPathDistinct (xmlNodeSetPtr nodes) {
2382     if (xmlXPathNodeSetIsEmpty(nodes))
2383         return(nodes);
2384
2385     xmlXPathNodeSetSort(nodes);
2386     return(xmlXPathDistinctSorted(nodes));
2387 }
2388
2389 /**
2390  * xmlXPathHasSameNodes:
2391  * @nodes1:  a node-set
2392  * @nodes2:  a node-set
2393  *
2394  * Implements the EXSLT - Sets has-same-nodes function:
2395  *    boolean set:has-same-node(node-set, node-set)
2396  *
2397  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2398  *         otherwise
2399  */
2400 int
2401 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2402     int i, l;
2403     xmlNodePtr cur;
2404
2405     if (xmlXPathNodeSetIsEmpty(nodes1) ||
2406         xmlXPathNodeSetIsEmpty(nodes2))
2407         return(0);
2408
2409     l = xmlXPathNodeSetGetLength(nodes1);
2410     for (i = 0; i < l; i++) {
2411         cur = xmlXPathNodeSetItem(nodes1, i);
2412         if (xmlXPathNodeSetContains(nodes2, cur))
2413             return(1);
2414     }
2415     return(0);
2416 }
2417
2418 /**
2419  * xmlXPathNodeLeadingSorted:
2420  * @nodes: a node-set, sorted by document order
2421  * @node: a node
2422  *
2423  * Implements the EXSLT - Sets leading() function:
2424  *    node-set set:leading (node-set, node-set)
2425  *
2426  * Returns the nodes in @nodes that precede @node in document order,
2427  *         @nodes if @node is NULL or an empty node-set if @nodes
2428  *         doesn't contain @node
2429  */
2430 xmlNodeSetPtr
2431 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2432     int i, l;
2433     xmlNodePtr cur;
2434     xmlNodeSetPtr ret;
2435
2436     if (node == NULL)
2437         return(nodes);
2438
2439     ret = xmlXPathNodeSetCreate(NULL);
2440     if (xmlXPathNodeSetIsEmpty(nodes) ||
2441         (!xmlXPathNodeSetContains(nodes, node)))
2442         return(ret);
2443
2444     l = xmlXPathNodeSetGetLength(nodes);
2445     for (i = 0; i < l; i++) {
2446         cur = xmlXPathNodeSetItem(nodes, i);
2447         if (cur == node)
2448             break;
2449         xmlXPathNodeSetAddUnique(ret, cur);
2450     }
2451     return(ret);
2452 }
2453
2454 /**
2455  * xmlXPathNodeLeading:
2456  * @nodes:  a node-set
2457  * @node:  a node
2458  *
2459  * Implements the EXSLT - Sets leading() function:
2460  *    node-set set:leading (node-set, node-set)
2461  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2462  * is called.
2463  *
2464  * Returns the nodes in @nodes that precede @node in document order,
2465  *         @nodes if @node is NULL or an empty node-set if @nodes
2466  *         doesn't contain @node
2467  */
2468 xmlNodeSetPtr
2469 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2470     xmlXPathNodeSetSort(nodes);
2471     return(xmlXPathNodeLeadingSorted(nodes, node));
2472 }
2473
2474 /**
2475  * xmlXPathLeadingSorted:
2476  * @nodes1:  a node-set, sorted by document order
2477  * @nodes2:  a node-set, sorted by document order
2478  *
2479  * Implements the EXSLT - Sets leading() function:
2480  *    node-set set:leading (node-set, node-set)
2481  *
2482  * Returns the nodes in @nodes1 that precede the first node in @nodes2
2483  *         in document order, @nodes1 if @nodes2 is NULL or empty or
2484  *         an empty node-set if @nodes1 doesn't contain @nodes2
2485  */
2486 xmlNodeSetPtr
2487 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2488     if (xmlXPathNodeSetIsEmpty(nodes2))
2489         return(nodes1);
2490     return(xmlXPathNodeLeadingSorted(nodes1,
2491                                      xmlXPathNodeSetItem(nodes2, 1)));
2492 }
2493
2494 /**
2495  * xmlXPathLeading:
2496  * @nodes1:  a node-set
2497  * @nodes2:  a node-set
2498  *
2499  * Implements the EXSLT - Sets leading() function:
2500  *    node-set set:leading (node-set, node-set)
2501  * @nodes1 and @nodes2 are sorted by document order, then
2502  * #exslSetsLeadingSorted is called.
2503  *
2504  * Returns the nodes in @nodes1 that precede the first node in @nodes2
2505  *         in document order, @nodes1 if @nodes2 is NULL or empty or
2506  *         an empty node-set if @nodes1 doesn't contain @nodes2
2507  */
2508 xmlNodeSetPtr
2509 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2510     if (xmlXPathNodeSetIsEmpty(nodes2))
2511         return(nodes1);
2512     if (xmlXPathNodeSetIsEmpty(nodes1))
2513         return(xmlXPathNodeSetCreate(NULL));
2514     xmlXPathNodeSetSort(nodes1);
2515     xmlXPathNodeSetSort(nodes2);
2516     return(xmlXPathNodeLeadingSorted(nodes1,
2517                                      xmlXPathNodeSetItem(nodes2, 1)));
2518 }
2519
2520 /**
2521  * xmlXPathNodeTrailingSorted:
2522  * @nodes: a node-set, sorted by document order
2523  * @node: a node
2524  *
2525  * Implements the EXSLT - Sets trailing() function:
2526  *    node-set set:trailing (node-set, node-set)
2527  *
2528  * Returns the nodes in @nodes that follow @node in document order,
2529  *         @nodes if @node is NULL or an empty node-set if @nodes
2530  *         doesn't contain @node
2531  */
2532 xmlNodeSetPtr
2533 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2534     int i, l;
2535     xmlNodePtr cur;
2536     xmlNodeSetPtr ret;
2537
2538     if (node == NULL)
2539         return(nodes);
2540
2541     ret = xmlXPathNodeSetCreate(NULL);
2542     if (xmlXPathNodeSetIsEmpty(nodes) ||
2543         (!xmlXPathNodeSetContains(nodes, node)))
2544         return(ret);
2545
2546     l = xmlXPathNodeSetGetLength(nodes);
2547     for (i = l; i > 0; i--) {
2548         cur = xmlXPathNodeSetItem(nodes, i);
2549         if (cur == node)
2550             break;
2551         xmlXPathNodeSetAddUnique(ret, cur);
2552     }
2553     return(ret);
2554 }
2555
2556 /**
2557  * xmlXPathNodeTrailing:
2558  * @nodes:  a node-set
2559  * @node:  a node
2560  *
2561  * Implements the EXSLT - Sets trailing() function:
2562  *    node-set set:trailing (node-set, node-set)
2563  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2564  * is called.
2565  *
2566  * Returns the nodes in @nodes that follow @node in document order,
2567  *         @nodes if @node is NULL or an empty node-set if @nodes
2568  *         doesn't contain @node
2569  */
2570 xmlNodeSetPtr
2571 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2572     xmlXPathNodeSetSort(nodes);
2573     return(xmlXPathNodeTrailingSorted(nodes, node));
2574 }
2575
2576 /**
2577  * xmlXPathTrailingSorted:
2578  * @nodes1:  a node-set, sorted by document order
2579  * @nodes2:  a node-set, sorted by document order
2580  *
2581  * Implements the EXSLT - Sets trailing() function:
2582  *    node-set set:trailing (node-set, node-set)
2583  *
2584  * Returns the nodes in @nodes1 that follow the first node in @nodes2
2585  *         in document order, @nodes1 if @nodes2 is NULL or empty or
2586  *         an empty node-set if @nodes1 doesn't contain @nodes2
2587  */
2588 xmlNodeSetPtr
2589 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2590     if (xmlXPathNodeSetIsEmpty(nodes2))
2591         return(nodes1);
2592     return(xmlXPathNodeTrailingSorted(nodes1,
2593                                       xmlXPathNodeSetItem(nodes2, 0)));
2594 }
2595
2596 /**
2597  * xmlXPathTrailing:
2598  * @nodes1:  a node-set
2599  * @nodes2:  a node-set
2600  *
2601  * Implements the EXSLT - Sets trailing() function:
2602  *    node-set set:trailing (node-set, node-set)
2603  * @nodes1 and @nodes2 are sorted by document order, then
2604  * #xmlXPathTrailingSorted is called.
2605  *
2606  * Returns the nodes in @nodes1 that follow the first node in @nodes2
2607  *         in document order, @nodes1 if @nodes2 is NULL or empty or
2608  *         an empty node-set if @nodes1 doesn't contain @nodes2
2609  */
2610 xmlNodeSetPtr
2611 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2612     if (xmlXPathNodeSetIsEmpty(nodes2))
2613         return(nodes1);
2614     if (xmlXPathNodeSetIsEmpty(nodes1))
2615         return(xmlXPathNodeSetCreate(NULL));
2616     xmlXPathNodeSetSort(nodes1);
2617     xmlXPathNodeSetSort(nodes2);
2618     return(xmlXPathNodeTrailingSorted(nodes1,
2619                                       xmlXPathNodeSetItem(nodes2, 0)));
2620 }
2621
2622 /************************************************************************
2623  *                                                                      *
2624  *              Routines to handle extra functions                      *
2625  *                                                                      *
2626  ************************************************************************/
2627
2628 /**
2629  * xmlXPathRegisterFunc:
2630  * @ctxt:  the XPath context
2631  * @name:  the function name
2632  * @f:  the function implementation or NULL
2633  *
2634  * Register a new function. If @f is NULL it unregisters the function
2635  *
2636  * Returns 0 in case of success, -1 in case of error
2637  */
2638 int               
2639 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2640                      xmlXPathFunction f) {
2641     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2642 }
2643
2644 /**
2645  * xmlXPathRegisterFuncNS:
2646  * @ctxt:  the XPath context
2647  * @name:  the function name
2648  * @ns_uri:  the function namespace URI
2649  * @f:  the function implementation or NULL
2650  *
2651  * Register a new function. If @f is NULL it unregisters the function
2652  *
2653  * Returns 0 in case of success, -1 in case of error
2654  */
2655 int
2656 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2657                        const xmlChar *ns_uri, xmlXPathFunction f) {
2658     if (ctxt == NULL)
2659         return(-1);
2660     if (name == NULL)
2661         return(-1);
2662
2663     if (ctxt->funcHash == NULL)
2664         ctxt->funcHash = xmlHashCreate(0);
2665     if (ctxt->funcHash == NULL)
2666         return(-1);
2667     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2668 }
2669
2670 /**
2671  * xmlXPathRegisterFuncLookup:
2672  * @ctxt:  the XPath context
2673  * @f:  the lookup function
2674  * @funcCtxt:  the lookup data
2675  *
2676  * Registers an external mechanism to do function lookup.
2677  */
2678 void
2679 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2680                             xmlXPathFuncLookupFunc f,
2681                             void *funcCtxt) {
2682     if (ctxt == NULL)
2683         return;
2684     ctxt->funcLookupFunc = (void *) f;
2685     ctxt->funcLookupData = funcCtxt;
2686 }
2687
2688 /**
2689  * xmlXPathFunctionLookup:
2690  * @ctxt:  the XPath context
2691  * @name:  the function name
2692  *
2693  * Search in the Function array of the context for the given
2694  * function.
2695  *
2696  * Returns the xmlXPathFunction or NULL if not found
2697  */
2698 xmlXPathFunction
2699 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2700     if (ctxt == NULL)
2701         return (NULL);
2702
2703     if (ctxt->funcLookupFunc != NULL) {
2704         xmlXPathFunction ret;
2705         xmlXPathFuncLookupFunc f;
2706
2707         f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
2708         ret = f(ctxt->funcLookupData, name, NULL);
2709         if (ret != NULL)
2710             return(ret);
2711     }
2712     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2713 }
2714
2715 /**
2716  * xmlXPathFunctionLookupNS:
2717  * @ctxt:  the XPath context
2718  * @name:  the function name
2719  * @ns_uri:  the function namespace URI
2720  *
2721  * Search in the Function array of the context for the given
2722  * function.
2723  *
2724  * Returns the xmlXPathFunction or NULL if not found
2725  */
2726 xmlXPathFunction
2727 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2728                          const xmlChar *ns_uri) {
2729     if (ctxt == NULL)
2730         return(NULL);
2731     if (name == NULL)
2732         return(NULL);
2733
2734     if (ctxt->funcLookupFunc != NULL) {
2735         xmlXPathFunction ret;
2736         xmlXPathFuncLookupFunc f;
2737
2738         f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
2739         ret = f(ctxt->funcLookupData, name, ns_uri);
2740         if (ret != NULL)
2741             return(ret);
2742     }
2743
2744     if (ctxt->funcHash == NULL)
2745         return(NULL);
2746
2747     return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2748 }
2749
2750 /**
2751  * xmlXPathRegisteredFuncsCleanup:
2752  * @ctxt:  the XPath context
2753  *
2754  * Cleanup the XPath context data associated to registered functions
2755  */
2756 void
2757 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2758     if (ctxt == NULL)
2759         return;
2760
2761     xmlHashFree(ctxt->funcHash, NULL);
2762     ctxt->funcHash = NULL;
2763 }
2764
2765 /************************************************************************
2766  *                                                                      *
2767  *                      Routines to handle Variable                     *
2768  *                                                                      *
2769  ************************************************************************/
2770
2771 /**
2772  * xmlXPathRegisterVariable:
2773  * @ctxt:  the XPath context
2774  * @name:  the variable name
2775  * @value:  the variable value or NULL
2776  *
2777  * Register a new variable value. If @value is NULL it unregisters
2778  * the variable
2779  *
2780  * Returns 0 in case of success, -1 in case of error
2781  */
2782 int               
2783 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2784                          xmlXPathObjectPtr value) {
2785     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2786 }
2787
2788 /**
2789  * xmlXPathRegisterVariableNS:
2790  * @ctxt:  the XPath context
2791  * @name:  the variable name
2792  * @ns_uri:  the variable namespace URI
2793  * @value:  the variable value or NULL
2794  *
2795  * Register a new variable value. If @value is NULL it unregisters
2796  * the variable
2797  *
2798  * Returns 0 in case of success, -1 in case of error
2799  */
2800 int
2801 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2802                            const xmlChar *ns_uri,
2803                            xmlXPathObjectPtr value) {
2804     if (ctxt == NULL)
2805         return(-1);
2806     if (name == NULL)
2807         return(-1);
2808
2809     if (ctxt->varHash == NULL)
2810         ctxt->varHash = xmlHashCreate(0);
2811     if (ctxt->varHash == NULL)
2812         return(-1);
2813     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2814                                (void *) value,
2815                                (xmlHashDeallocator)xmlXPathFreeObject));
2816 }
2817
2818 /**
2819  * xmlXPathRegisterVariableLookup:
2820  * @ctxt:  the XPath context
2821  * @f:  the lookup function
2822  * @data:  the lookup data
2823  *
2824  * register an external mechanism to do variable lookup
2825  */
2826 void
2827 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2828          xmlXPathVariableLookupFunc f, void *data) {
2829     if (ctxt == NULL)
2830         return;
2831     ctxt->varLookupFunc = (void *) f;
2832     ctxt->varLookupData = data;
2833 }
2834
2835 /**
2836  * xmlXPathVariableLookup:
2837  * @ctxt:  the XPath context
2838  * @name:  the variable name
2839  *
2840  * Search in the Variable array of the context for the given
2841  * variable value.
2842  *
2843  * Returns a copy of the value or NULL if not found
2844  */
2845 xmlXPathObjectPtr
2846 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2847     if (ctxt == NULL)
2848         return(NULL);
2849
2850     if (ctxt->varLookupFunc != NULL) {
2851         xmlXPathObjectPtr ret;
2852
2853         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2854                 (ctxt->varLookupData, name, NULL);
2855         return(ret);
2856     }
2857     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2858 }
2859
2860 /**
2861  * xmlXPathVariableLookupNS:
2862  * @ctxt:  the XPath context
2863  * @name:  the variable name
2864  * @ns_uri:  the variable namespace URI
2865  *
2866  * Search in the Variable array of the context for the given
2867  * variable value. 
2868  *
2869  * Returns the a copy of the value or NULL if not found
2870  */
2871 xmlXPathObjectPtr
2872 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2873                          const xmlChar *ns_uri) {
2874     if (ctxt == NULL)
2875         return(NULL);
2876
2877     if (ctxt->varLookupFunc != NULL) {
2878         xmlXPathObjectPtr ret;
2879
2880         ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2881                 (ctxt->varLookupData, name, ns_uri);
2882         if (ret != NULL) return(ret);
2883     }
2884
2885     if (ctxt->varHash == NULL)
2886         return(NULL);
2887     if (name == NULL)
2888         return(NULL);
2889
2890     return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2891                 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
2892 }
2893
2894 /**
2895  * xmlXPathRegisteredVariablesCleanup:
2896  * @ctxt:  the XPath context
2897  *
2898  * Cleanup the XPath context data associated to registered variables
2899  */
2900 void
2901 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2902     if (ctxt == NULL)
2903         return;
2904
2905     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
2906     ctxt->varHash = NULL;
2907 }
2908
2909 /**
2910  * xmlXPathRegisterNs:
2911  * @ctxt:  the XPath context
2912  * @prefix:  the namespace prefix
2913  * @ns_uri:  the namespace name
2914  *
2915  * Register a new namespace. If @ns_uri is NULL it unregisters
2916  * the namespace
2917  *
2918  * Returns 0 in case of success, -1 in case of error
2919  */
2920 int
2921 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2922                            const xmlChar *ns_uri) {
2923     if (ctxt == NULL)
2924         return(-1);
2925     if (prefix == NULL)
2926         return(-1);
2927
2928     if (ctxt->nsHash == NULL)
2929         ctxt->nsHash = xmlHashCreate(10);
2930     if (ctxt->nsHash == NULL)
2931         return(-1);
2932     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
2933                               (xmlHashDeallocator)xmlFree));
2934 }
2935
2936 /**
2937  * xmlXPathNsLookup:
2938  * @ctxt:  the XPath context
2939  * @prefix:  the namespace prefix value
2940  *
2941  * Search in the namespace declaration array of the context for the given
2942  * namespace name associated to the given prefix
2943  *
2944  * Returns the value or NULL if not found
2945  */
2946 const xmlChar *
2947 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2948     if (ctxt == NULL)
2949         return(NULL);
2950     if (prefix == NULL)
2951         return(NULL);
2952
2953 #ifdef XML_XML_NAMESPACE
2954     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2955         return(XML_XML_NAMESPACE);
2956 #endif
2957
2958     if (ctxt->namespaces != NULL) {
2959         int i;
2960
2961         for (i = 0;i < ctxt->nsNr;i++) {
2962             if ((ctxt->namespaces[i] != NULL) &&
2963                 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2964                 return(ctxt->namespaces[i]->href);
2965         }
2966     }
2967
2968     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2969 }
2970
2971 /**
2972  * xmlXPathRegisteredNsCleanup:
2973  * @ctxt:  the XPath context
2974  *
2975  * Cleanup the XPath context data associated to registered variables
2976  */
2977 void
2978 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2979     if (ctxt == NULL)
2980         return;
2981
2982     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
2983     ctxt->nsHash = NULL;
2984 }
2985
2986 /************************************************************************
2987  *                                                                      *
2988  *                      Routines to handle Values                       *
2989  *                                                                      *
2990  ************************************************************************/
2991
2992 /* Allocations are terrible, one need to optimize all this !!! */
2993
2994 /**
2995  * xmlXPathNewFloat:
2996  * @val:  the double value
2997  *
2998  * Create a new xmlXPathObjectPtr of type double and of value @val
2999  *
3000  * Returns the newly created object.
3001  */
3002 xmlXPathObjectPtr
3003 xmlXPathNewFloat(double val) {
3004     xmlXPathObjectPtr ret;
3005
3006     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3007     if (ret == NULL) {
3008         xmlGenericError(xmlGenericErrorContext,
3009                 "xmlXPathNewFloat: out of memory\n");
3010         return(NULL);
3011     }
3012     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3013     ret->type = XPATH_NUMBER;
3014     ret->floatval = val;
3015     return(ret);
3016 }
3017
3018 /**
3019  * xmlXPathNewBoolean:
3020  * @val:  the boolean value
3021  *
3022  * Create a new xmlXPathObjectPtr of type boolean and of value @val
3023  *
3024  * Returns the newly created object.
3025  */
3026 xmlXPathObjectPtr
3027 xmlXPathNewBoolean(int val) {
3028     xmlXPathObjectPtr ret;
3029
3030     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3031     if (ret == NULL) {
3032         xmlGenericError(xmlGenericErrorContext,
3033                 "xmlXPathNewBoolean: out of memory\n");
3034         return(NULL);
3035     }
3036     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3037     ret->type = XPATH_BOOLEAN;
3038     ret->boolval = (val != 0);
3039     return(ret);
3040 }
3041
3042 /**
3043  * xmlXPathNewString:
3044  * @val:  the xmlChar * value
3045  *
3046  * Create a new xmlXPathObjectPtr of type string and of value @val
3047  *
3048  * Returns the newly created object.
3049  */
3050 xmlXPathObjectPtr
3051 xmlXPathNewString(const xmlChar *val) {
3052     xmlXPathObjectPtr ret;
3053
3054     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3055     if (ret == NULL) {
3056         xmlGenericError(xmlGenericErrorContext,
3057                 "xmlXPathNewString: out of memory\n");
3058         return(NULL);
3059     }
3060     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3061     ret->type = XPATH_STRING;
3062     if (val != NULL)
3063         ret->stringval = xmlStrdup(val);
3064     else
3065         ret->stringval = xmlStrdup((const xmlChar *)"");
3066     return(ret);
3067 }
3068
3069 /**
3070  * xmlXPathWrapString:
3071  * @val:  the xmlChar * value
3072  *
3073  * Wraps the @val string into an XPath object.
3074  *
3075  * Returns the newly created object.
3076  */
3077 xmlXPathObjectPtr
3078 xmlXPathWrapString (xmlChar *val) {
3079     xmlXPathObjectPtr ret;
3080
3081     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3082     if (ret == NULL) {
3083         xmlGenericError(xmlGenericErrorContext,
3084                 "xmlXPathWrapString: out of memory\n");
3085         return(NULL);
3086     }
3087     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3088     ret->type = XPATH_STRING;
3089     ret->stringval = val;
3090     return(ret);
3091 }
3092
3093 /**
3094  * xmlXPathNewCString:
3095  * @val:  the char * value
3096  *
3097  * Create a new xmlXPathObjectPtr of type string and of value @val
3098  *
3099  * Returns the newly created object.
3100  */
3101 xmlXPathObjectPtr
3102 xmlXPathNewCString(const char *val) {
3103     xmlXPathObjectPtr ret;
3104
3105     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3106     if (ret == NULL) {
3107         xmlGenericError(xmlGenericErrorContext,
3108                 "xmlXPathNewCString: out of memory\n");
3109         return(NULL);
3110     }
3111     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3112     ret->type = XPATH_STRING;
3113     ret->stringval = xmlStrdup(BAD_CAST val);
3114     return(ret);
3115 }
3116
3117 /**
3118  * xmlXPathWrapCString:
3119  * @val:  the char * value
3120  *
3121  * Wraps a string into an XPath object.
3122  *
3123  * Returns the newly created object.
3124  */
3125 xmlXPathObjectPtr
3126 xmlXPathWrapCString (char * val) {
3127     return(xmlXPathWrapString((xmlChar *)(val)));
3128 }
3129
3130 /**
3131  * xmlXPathWrapExternal:
3132  * @val:  the user data
3133  *
3134  * Wraps the @val data into an XPath object.
3135  *
3136  * Returns the newly created object.
3137  */
3138 xmlXPathObjectPtr
3139 xmlXPathWrapExternal (void *val) {
3140     xmlXPathObjectPtr ret;
3141
3142     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3143     if (ret == NULL) {
3144         xmlGenericError(xmlGenericErrorContext,
3145                 "xmlXPathWrapExternal: out of memory\n");
3146         return(NULL);
3147     }
3148     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3149     ret->type = XPATH_USERS;
3150     ret->user = val;
3151     return(ret);
3152 }
3153
3154 /**
3155  * xmlXPathObjectCopy:
3156  * @val:  the original object
3157  *
3158  * allocate a new copy of a given object
3159  *
3160  * Returns the newly created object.
3161  */
3162 xmlXPathObjectPtr
3163 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3164     xmlXPathObjectPtr ret;
3165
3166     if (val == NULL)
3167         return(NULL);
3168
3169     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3170     if (ret == NULL) {
3171         xmlGenericError(xmlGenericErrorContext,
3172                 "xmlXPathObjectCopy: out of memory\n");
3173         return(NULL);
3174     }
3175     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3176     switch (val->type) {
3177         case XPATH_BOOLEAN:
3178         case XPATH_NUMBER:
3179         case XPATH_POINT:
3180         case XPATH_RANGE:
3181             break;
3182         case XPATH_STRING:
3183             ret->stringval = xmlStrdup(val->stringval);
3184             break;
3185         case XPATH_XSLT_TREE:
3186             if ((val->nodesetval != NULL) &&
3187                 (val->nodesetval->nodeTab != NULL)) {
3188                 xmlNodePtr cur, tmp;
3189                 xmlDocPtr top;
3190
3191                 ret->boolval = 1;
3192                 top =  xmlNewDoc(NULL);
3193                 top->name = (char *)
3194                     xmlStrdup(val->nodesetval->nodeTab[0]->name);
3195                 ret->user = top;
3196                 if (top != NULL) {
3197                     top->doc = top;
3198                     cur = val->nodesetval->nodeTab[0]->children;
3199                     while (cur != NULL) {
3200                         tmp = xmlDocCopyNode(cur, top, 1);
3201                         xmlAddChild((xmlNodePtr) top, tmp);
3202                         cur = cur->next;
3203                     }
3204                 }
3205                 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
3206             } else
3207                 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
3208             /* Deallocate the copied tree value */
3209             break;
3210         case XPATH_NODESET:
3211             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
3212             /* Do not deallocate the copied tree value */
3213             ret->boolval = 0;
3214             break;
3215         case XPATH_LOCATIONSET:
3216 #ifdef LIBXML_XPTR_ENABLED
3217         {
3218             xmlLocationSetPtr loc = val->user;
3219             ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3220             break;
3221         }
3222 #endif
3223         case XPATH_USERS:
3224             ret->user = val->user;
3225             break; 
3226         case XPATH_UNDEFINED:
3227             xmlGenericError(xmlGenericErrorContext,
3228                     "xmlXPathObjectCopy: unsupported type %d\n",
3229                     val->type);
3230             break;
3231     }
3232     return(ret);
3233 }
3234
3235 /**
3236  * xmlXPathFreeObject:
3237  * @obj:  the object to free
3238  *
3239  * Free up an xmlXPathObjectPtr object.
3240  */
3241 void
3242 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3243     if (obj == NULL) return;
3244     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
3245         if (obj->boolval) {
3246             if (obj->user != NULL) {
3247                 xmlXPathFreeNodeSet(obj->nodesetval);
3248                 xmlFreeNodeList((xmlNodePtr) obj->user);
3249             } else if (obj->nodesetval != NULL)
3250                 xmlXPathFreeValueTree(obj->nodesetval);
3251         } else {
3252             if (obj->nodesetval != NULL)
3253                 xmlXPathFreeNodeSet(obj->nodesetval);
3254         }
3255 #ifdef LIBXML_XPTR_ENABLED
3256     } else if (obj->type == XPATH_LOCATIONSET) {
3257         if (obj->user != NULL)
3258             xmlXPtrFreeLocationSet(obj->user);
3259 #endif
3260     } else if (obj->type == XPATH_STRING) {
3261         if (obj->stringval != NULL)
3262             xmlFree(obj->stringval);
3263     }
3264
3265     xmlFree(obj);
3266 }
3267
3268
3269 /************************************************************************
3270  *                                                                      *
3271  *                      Type Casting Routines                           *
3272  *                                                                      *
3273  ************************************************************************/
3274
3275 /**
3276  * xmlXPathCastBooleanToString:
3277  * @val:  a boolean
3278  *
3279  * Converts a boolean to its string value.
3280  *
3281  * Returns a newly allocated string.
3282  */
3283 xmlChar *
3284 xmlXPathCastBooleanToString (int val) {
3285     xmlChar *ret;
3286     if (val)
3287         ret = xmlStrdup((const xmlChar *) "true");
3288     else
3289         ret = xmlStrdup((const xmlChar *) "false");
3290     return(ret);
3291 }
3292
3293 /**
3294  * xmlXPathCastNumberToString:
3295  * @val:  a number
3296  *
3297  * Converts a number to its string value.
3298  *
3299  * Returns a newly allocated string.
3300  */
3301 xmlChar *
3302 xmlXPathCastNumberToString (double val) {
3303     xmlChar *ret;
3304     switch (xmlXPathIsInf(val)) {
3305     case 1:
3306         ret = xmlStrdup((const xmlChar *) "Infinity");
3307         break;
3308     case -1:
3309         ret = xmlStrdup((const xmlChar *) "-Infinity");
3310         break;
3311     default:
3312         if (xmlXPathIsNaN(val)) {
3313             ret = xmlStrdup((const xmlChar *) "NaN");
3314         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3315             ret = xmlStrdup((const xmlChar *) "0");
3316         } else {
3317             /* could be improved */
3318             char buf[100];
3319             xmlXPathFormatNumber(val, buf, 100);
3320             ret = xmlStrdup((const xmlChar *) buf);
3321         }
3322     }
3323     return(ret);
3324 }
3325
3326 /**
3327  * xmlXPathCastNodeToString:
3328  * @node:  a node
3329  *
3330  * Converts a node to its string value.
3331  *
3332  * Returns a newly allocated string.
3333  */
3334 xmlChar *
3335 xmlXPathCastNodeToString (xmlNodePtr node) {
3336     return(xmlNodeGetContent(node));
3337 }
3338
3339 /**
3340  * xmlXPathCastNodeSetToString:
3341  * @ns:  a node-set
3342  *
3343  * Converts a node-set to its string value.
3344  *
3345  * Returns a newly allocated string.
3346  */
3347 xmlChar *
3348 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3349     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3350         return(xmlStrdup((const xmlChar *) ""));
3351
3352     xmlXPathNodeSetSort(ns);
3353     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3354 }
3355
3356 /**
3357  * xmlXPathCastToString:
3358  * @val:  an XPath object
3359  *
3360  * Converts an existing object to its string() equivalent
3361  *
3362  * Returns the string value of the object, NULL in case of error.
3363  *         A new string is allocated only if needed (@val isn't a
3364  *         string object).
3365  */
3366 xmlChar *
3367 xmlXPathCastToString(xmlXPathObjectPtr val) {
3368     xmlChar *ret = NULL;
3369
3370     if (val == NULL)
3371         return(xmlStrdup((const xmlChar *) ""));
3372     switch (val->type) {
3373         case XPATH_UNDEFINED:
3374 #ifdef DEBUG_EXPR
3375             xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3376 #endif
3377             ret = xmlStrdup((const xmlChar *) "");
3378             break;
3379         case XPATH_NODESET:
3380         case XPATH_XSLT_TREE:
3381             ret = xmlXPathCastNodeSetToString(val->nodesetval);
3382             break;
3383         case XPATH_STRING:
3384             return(xmlStrdup(val->stringval));
3385         case XPATH_BOOLEAN:
3386             ret = xmlXPathCastBooleanToString(val->boolval);
3387             break;
3388         case XPATH_NUMBER: {
3389             ret = xmlXPathCastNumberToString(val->floatval);
3390             break;
3391         }
3392         case XPATH_USERS:
3393         case XPATH_POINT:
3394         case XPATH_RANGE:
3395         case XPATH_LOCATIONSET:
3396             TODO
3397             ret = xmlStrdup((const xmlChar *) "");
3398             break;
3399     }
3400     return(ret);
3401 }
3402
3403 /**
3404  * xmlXPathConvertString:
3405  * @val:  an XPath object
3406  *
3407  * Converts an existing object to its string() equivalent
3408  *
3409  * Returns the new object, the old one is freed (or the operation
3410  *         is done directly on @val)
3411  */
3412 xmlXPathObjectPtr
3413 xmlXPathConvertString(xmlXPathObjectPtr val) {
3414     xmlChar *res = NULL;
3415
3416     if (val == NULL)
3417         return(xmlXPathNewCString(""));
3418
3419     switch (val->type) {
3420     case XPATH_UNDEFINED:
3421 #ifdef DEBUG_EXPR
3422         xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3423 #endif
3424         break;
3425     case XPATH_NODESET:
3426     case XPATH_XSLT_TREE:
3427         res = xmlXPathCastNodeSetToString(val->nodesetval);
3428         break;
3429     case XPATH_STRING:
3430         return(val);
3431     case XPATH_BOOLEAN:
3432         res = xmlXPathCastBooleanToString(val->boolval);
3433         break;
3434     case XPATH_NUMBER:
3435         res = xmlXPathCastNumberToString(val->floatval);
3436         break;
3437     case XPATH_USERS:
3438     case XPATH_POINT:
3439     case XPATH_RANGE:
3440     case XPATH_LOCATIONSET:
3441         TODO;
3442         break;
3443     }
3444     xmlXPathFreeObject(val);
3445     if (res == NULL)
3446         return(xmlXPathNewCString(""));
3447     return(xmlXPathWrapString(res));
3448 }
3449
3450 /**
3451  * xmlXPathCastBooleanToNumber:
3452  * @val:  a boolean
3453  *
3454  * Converts a boolean to its number value
3455  *
3456  * Returns the number value
3457  */
3458 double
3459 xmlXPathCastBooleanToNumber(int val) {
3460     if (val)
3461         return(1.0);
3462     return(0.0);
3463 }
3464
3465 /**
3466  * xmlXPathCastStringToNumber:
3467  * @val:  a string
3468  *
3469  * Converts a string to its number value
3470  *
3471  * Returns the number value
3472  */
3473 double
3474 xmlXPathCastStringToNumber(const xmlChar * val) {
3475     return(xmlXPathStringEvalNumber(val));
3476 }
3477
3478 /**
3479  * xmlXPathCastNodeToNumber:
3480  * @node:  a node
3481  *
3482  * Converts a node to its number value
3483  *
3484  * Returns the number value
3485  */
3486 double
3487 xmlXPathCastNodeToNumber (xmlNodePtr node) {
3488     xmlChar *strval;
3489     double ret;
3490
3491     if (node == NULL)
3492         return(xmlXPathNAN);
3493     strval = xmlXPathCastNodeToString(node);
3494     if (strval == NULL)
3495         return(xmlXPathNAN);
3496     ret = xmlXPathCastStringToNumber(strval);
3497     xmlFree(strval);
3498
3499     return(ret);
3500 }
3501
3502 /**
3503  * xmlXPathCastNodeSetToNumber:
3504  * @ns:  a node-set
3505  *
3506  * Converts a node-set to its number value
3507  *
3508  * Returns the number value
3509  */
3510 double
3511 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3512     xmlChar *str;
3513     double ret;
3514
3515     if (ns == NULL)
3516         return(xmlXPathNAN);
3517     str = xmlXPathCastNodeSetToString(ns);
3518     ret = xmlXPathCastStringToNumber(str);
3519     xmlFree(str);
3520     return(ret);
3521 }
3522
3523 /**
3524  * xmlXPathCastToNumber:
3525  * @val:  an XPath object
3526  *
3527  * Converts an XPath object to its number value
3528  *
3529  * Returns the number value
3530  */
3531 double
3532 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3533     double ret = 0.0;
3534
3535     if (val == NULL)
3536         return(xmlXPathNAN);
3537     switch (val->type) {
3538     case XPATH_UNDEFINED:
3539 #ifdef DEGUB_EXPR
3540         xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3541 #endif
3542         ret = xmlXPathNAN;
3543         break;
3544     case XPATH_NODESET:
3545     case XPATH_XSLT_TREE:
3546         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3547         break;
3548     case XPATH_STRING:
3549         ret = xmlXPathCastStringToNumber(val->stringval);
3550         break;
3551     case XPATH_NUMBER:
3552         ret = val->floatval;
3553         break;
3554     case XPATH_BOOLEAN:
3555         ret = xmlXPathCastBooleanToNumber(val->boolval);
3556         break;
3557     case XPATH_USERS:
3558     case XPATH_POINT:
3559     case XPATH_RANGE:
3560     case XPATH_LOCATIONSET:
3561         TODO;
3562         ret = xmlXPathNAN;
3563         break;
3564     }
3565     return(ret);
3566 }
3567
3568 /**
3569  * xmlXPathConvertNumber:
3570  * @val:  an XPath object
3571  *
3572  * Converts an existing object to its number() equivalent
3573  *
3574  * Returns the new object, the old one is freed (or the operation
3575  *         is done directly on @val)
3576  */
3577 xmlXPathObjectPtr
3578 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3579     xmlXPathObjectPtr ret;
3580
3581     if (val == NULL)
3582         return(xmlXPathNewFloat(0.0));
3583     if (val->type == XPATH_NUMBER)
3584         return(val);
3585     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3586     xmlXPathFreeObject(val);
3587     return(ret);
3588 }
3589
3590 /**
3591  * xmlXPathCastNumberToBoolean:
3592  * @val:  a number
3593  *
3594  * Converts a number to its boolean value
3595  *
3596  * Returns the boolean value
3597  */
3598 int
3599 xmlXPathCastNumberToBoolean (double val) {
3600      if (xmlXPathIsNaN(val) || (val == 0.0))
3601          return(0);
3602      return(1);
3603 }
3604
3605 /**
3606  * xmlXPathCastStringToBoolean:
3607  * @val:  a string
3608  *
3609  * Converts a string to its boolean value
3610  *
3611  * Returns the boolean value
3612  */
3613 int
3614 xmlXPathCastStringToBoolean (const xmlChar *val) {
3615     if ((val == NULL) || (xmlStrlen(val) == 0))
3616         return(0);
3617     return(1);
3618 }
3619
3620 /**
3621  * xmlXPathCastNodeSetToBoolean:
3622  * @ns:  a node-set
3623  *
3624  * Converts a node-set to its boolean value
3625  *
3626  * Returns the boolean value
3627  */
3628 int
3629 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3630     if ((ns == NULL) || (ns->nodeNr == 0))
3631         return(0);
3632     return(1);
3633 }
3634
3635 /**
3636  * xmlXPathCastToBoolean:
3637  * @val:  an XPath object
3638  *
3639  * Converts an XPath object to its boolean value
3640  *
3641  * Returns the boolean value