added Info.plist
[TestXSLT.git] / libxml2 / 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
3642  */
3643 int
3644 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3645     int ret = 0;
3646
3647     if (val == NULL)
3648         return(0);
3649     switch (val->type) {
3650     case XPATH_UNDEFINED:
3651 #ifdef DEBUG_EXPR
3652         xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3653 #endif
3654         ret = 0;
3655         break;
3656     case XPATH_NODESET:
3657     case XPATH_XSLT_TREE:
3658         ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3659         break;
3660     case XPATH_STRING:
3661         ret = xmlXPathCastStringToBoolean(val->stringval);
3662         break;
3663     case XPATH_NUMBER:
3664         ret = xmlXPathCastNumberToBoolean(val->floatval);
3665         break;
3666     case XPATH_BOOLEAN:
3667         ret = val->boolval;
3668         break;
3669     case XPATH_USERS:
3670     case XPATH_POINT:
3671     case XPATH_RANGE:
3672     case XPATH_LOCATIONSET:
3673         TODO;
3674         ret = 0;
3675         break;
3676     }
3677     return(ret);
3678 }
3679
3680
3681 /**
3682  * xmlXPathConvertBoolean:
3683  * @val:  an XPath object
3684  *
3685  * Converts an existing object to its boolean() equivalent
3686  *
3687  * Returns the new object, the old one is freed (or the operation
3688  *         is done directly on @val)
3689  */
3690 xmlXPathObjectPtr
3691 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3692     xmlXPathObjectPtr ret;
3693
3694     if (val == NULL)
3695         return(xmlXPathNewBoolean(0));
3696     if (val->type == XPATH_BOOLEAN)
3697         return(val);
3698     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3699     xmlXPathFreeObject(val);
3700     return(ret);
3701 }
3702
3703 /************************************************************************
3704  *                                                                      *
3705  *              Routines to handle XPath contexts                       *
3706  *                                                                      *
3707  ************************************************************************/
3708
3709 /**
3710  * xmlXPathNewContext:
3711  * @doc:  the XML document
3712  *
3713  * Create a new xmlXPathContext
3714  *
3715  * Returns the xmlXPathContext just allocated. The caller will need to free it.
3716  */
3717 xmlXPathContextPtr
3718 xmlXPathNewContext(xmlDocPtr doc) {
3719     xmlXPathContextPtr ret;
3720
3721     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3722     if (ret == NULL) {
3723         xmlGenericError(xmlGenericErrorContext,
3724                 "xmlXPathNewContext: out of memory\n");
3725         return(NULL);
3726     }
3727     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3728     ret->doc = doc;
3729     ret->node = NULL;
3730
3731     ret->varHash = NULL;
3732
3733     ret->nb_types = 0;
3734     ret->max_types = 0;
3735     ret->types = NULL;
3736
3737     ret->funcHash = xmlHashCreate(0);
3738
3739     ret->nb_axis = 0;
3740     ret->max_axis = 0;
3741     ret->axis = NULL;
3742
3743     ret->nsHash = NULL;
3744     ret->user = NULL;
3745
3746     ret->contextSize = -1;
3747     ret->proximityPosition = -1;
3748
3749     xmlXPathRegisterAllFunctions(ret);
3750     
3751     return(ret);
3752 }
3753
3754 /**
3755  * xmlXPathFreeContext:
3756  * @ctxt:  the context to free
3757  *
3758  * Free up an xmlXPathContext
3759  */
3760 void
3761 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3762     xmlXPathRegisteredNsCleanup(ctxt);
3763     xmlXPathRegisteredFuncsCleanup(ctxt);
3764     xmlXPathRegisteredVariablesCleanup(ctxt);
3765     xmlFree(ctxt);
3766 }
3767
3768 /************************************************************************
3769  *                                                                      *
3770  *              Routines to handle XPath parser contexts                *
3771  *                                                                      *
3772  ************************************************************************/
3773
3774 #define CHECK_CTXT(ctxt)                                                \
3775     if (ctxt == NULL) {                                                 \
3776         xmlGenericError(xmlGenericErrorContext,                         \
3777                 "%s:%d Internal error: ctxt == NULL\n",                 \
3778                 __FILE__, __LINE__);                                    \
3779     }                                                                   \
3780
3781
3782 #define CHECK_CONTEXT(ctxt)                                             \
3783     if (ctxt == NULL) {                                                 \
3784         xmlGenericError(xmlGenericErrorContext,                         \
3785                 "%s:%d Internal error: no context\n",                   \
3786                 __FILE__, __LINE__);                                    \
3787     }                                                                   \
3788     else if (ctxt->doc == NULL) {                                       \
3789         xmlGenericError(xmlGenericErrorContext,                         \
3790                 "%s:%d Internal error: no document\n",                  \
3791                 __FILE__, __LINE__);                                    \
3792     }                                                                   \
3793     else if (ctxt->doc->children == NULL) {                             \
3794         xmlGenericError(xmlGenericErrorContext,                         \
3795                 "%s:%d Internal error: document without root\n",        \
3796                 __FILE__, __LINE__);                                    \
3797     }                                                                   \
3798
3799
3800 /**
3801  * xmlXPathNewParserContext:
3802  * @str:  the XPath expression
3803  * @ctxt:  the XPath context
3804  *
3805  * Create a new xmlXPathParserContext
3806  *
3807  * Returns the xmlXPathParserContext just allocated.
3808  */
3809 xmlXPathParserContextPtr
3810 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3811     xmlXPathParserContextPtr ret;
3812
3813     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3814     if (ret == NULL) {
3815         xmlGenericError(xmlGenericErrorContext,
3816                 "xmlXPathNewParserContext: out of memory\n");
3817         return(NULL);
3818     }
3819     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3820     ret->cur = ret->base = str;
3821     ret->context = ctxt;
3822
3823     ret->comp = xmlXPathNewCompExpr();
3824     if (ret->comp == NULL) {
3825         xmlFree(ret->valueTab);
3826         xmlFree(ret);
3827         return(NULL);
3828     }
3829
3830     return(ret);
3831 }
3832
3833 /**
3834  * xmlXPathCompParserContext:
3835  * @comp:  the XPath compiled expression
3836  * @ctxt:  the XPath context
3837  *
3838  * Create a new xmlXPathParserContext when processing a compiled expression
3839  *
3840  * Returns the xmlXPathParserContext just allocated.
3841  */
3842 static xmlXPathParserContextPtr
3843 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3844     xmlXPathParserContextPtr ret;
3845
3846     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3847     if (ret == NULL) {
3848         xmlGenericError(xmlGenericErrorContext,
3849                 "xmlXPathCompParserContext: out of memory\n");
3850         return(NULL);
3851     }
3852     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3853
3854     /* Allocate the value stack */
3855     ret->valueTab = (xmlXPathObjectPtr *) 
3856                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
3857     if (ret->valueTab == NULL) {
3858         xmlFree(ret);
3859         xmlGenericError(xmlGenericErrorContext,
3860                 "xmlXPathCompParserContext: out of memory\n");
3861         return(NULL);
3862     }
3863     ret->valueNr = 0;
3864     ret->valueMax = 10;
3865     ret->value = NULL;
3866
3867     ret->context = ctxt;
3868     ret->comp = comp;
3869
3870     return(ret);
3871 }
3872
3873 /**
3874  * xmlXPathFreeParserContext:
3875  * @ctxt:  the context to free
3876  *
3877  * Free up an xmlXPathParserContext
3878  */
3879 void
3880 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3881     if (ctxt->valueTab != NULL) {
3882         xmlFree(ctxt->valueTab);
3883     }
3884     if (ctxt->comp)
3885         xmlXPathFreeCompExpr(ctxt->comp);
3886     xmlFree(ctxt);
3887 }
3888
3889 /************************************************************************
3890  *                                                                      *
3891  *              The implicit core function library                      *
3892  *                                                                      *
3893  ************************************************************************/
3894
3895 /**
3896  * xmlXPathNodeValHash:
3897  * @node:  a node pointer
3898  *
3899  * Function computing the beginning of the string value of the node,
3900  * used to speed up comparisons
3901  *
3902  * Returns an int usable as a hash
3903  */
3904 static unsigned int
3905 xmlXPathNodeValHash(xmlNodePtr node) {
3906     int len = 2;
3907     const xmlChar * string = NULL;
3908     xmlNodePtr tmp = NULL;
3909     unsigned int ret = 0;
3910
3911     if (node == NULL)
3912         return(0);
3913
3914     if (node->type == XML_DOCUMENT_NODE) {
3915         tmp = xmlDocGetRootElement((xmlDocPtr) node);
3916         if (tmp == NULL)
3917             node = node->children;
3918         else
3919             node = tmp;
3920
3921         if (node == NULL)
3922             return(0);
3923     }
3924
3925     switch (node->type) {
3926         case XML_COMMENT_NODE:
3927         case XML_PI_NODE:
3928         case XML_CDATA_SECTION_NODE:
3929         case XML_TEXT_NODE:
3930             string = node->content;
3931             if (string == NULL)
3932                 return(0);
3933             if (string[0] == 0)
3934                 return(0);
3935             return(((unsigned int) string[0]) +
3936                    (((unsigned int) string[1]) << 8));
3937         case XML_NAMESPACE_DECL:
3938             string = ((xmlNsPtr)node)->href;
3939             if (string == NULL)
3940                 return(0);
3941             if (string[0] == 0)
3942                 return(0);
3943             return(((unsigned int) string[0]) +
3944                    (((unsigned int) string[1]) << 8));
3945         case XML_ATTRIBUTE_NODE:
3946             tmp = ((xmlAttrPtr) node)->children;
3947             break;
3948         case XML_ELEMENT_NODE:
3949             tmp = node->children;
3950             break;
3951         default:
3952             return(0);
3953     }
3954     while (tmp != NULL) {
3955         switch (tmp->type) {
3956             case XML_COMMENT_NODE:
3957             case XML_PI_NODE:
3958             case XML_CDATA_SECTION_NODE:
3959             case XML_TEXT_NODE:
3960                 string = tmp->content;
3961                 break;
3962             case XML_NAMESPACE_DECL:
3963                 string = ((xmlNsPtr)tmp)->href;
3964                 break;
3965             default:
3966                 break;
3967         }
3968         if ((string != NULL) && (string[0] != 0)) {
3969             if (string[0] == 0)
3970                 return(0);
3971             if (len == 1) {
3972                 return(ret + (((unsigned int) string[0]) << 8));
3973             }
3974             if (string[1] == 0) {
3975                 len = 1;
3976                 ret = (unsigned int) string[0];
3977             } else {
3978                 return(((unsigned int) string[0]) +
3979                        (((unsigned int) string[1]) << 8));
3980             }
3981         }
3982         /*
3983          * Skip to next node
3984          */
3985         if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3986             if (tmp->children->type != XML_ENTITY_DECL) {
3987                 tmp = tmp->children;
3988                 continue;
3989             }
3990         }
3991         if (tmp == node)
3992             break;
3993
3994         if (tmp->next != NULL) {
3995             tmp = tmp->next;
3996             continue;
3997         }
3998         
3999         do {
4000             tmp = tmp->parent;
4001             if (tmp == NULL)
4002                 break;
4003             if (tmp == node) {
4004                 tmp = NULL;
4005                 break;
4006             }
4007             if (tmp->next != NULL) {
4008                 tmp = tmp->next;
4009                 break;
4010             }
4011         } while (tmp != NULL);
4012     }
4013     return(ret);
4014 }
4015
4016 /**
4017  * xmlXPathStringHash:
4018  * @string:  a string
4019  *
4020  * Function computing the beginning of the string value of the node,
4021  * used to speed up comparisons
4022  *
4023  * Returns an int usable as a hash
4024  */
4025 static unsigned int
4026 xmlXPathStringHash(const xmlChar * string) {
4027     if (string == NULL)
4028         return((unsigned int) 0);
4029     if (string[0] == 0)
4030         return(0);
4031     return(((unsigned int) string[0]) +
4032            (((unsigned int) string[1]) << 8));
4033 }
4034
4035 /**
4036  * xmlXPathCompareNodeSetFloat:
4037  * @ctxt:  the XPath Parser context
4038  * @inf:  less than (1) or greater than (0)
4039  * @strict:  is the comparison strict
4040  * @arg:  the node set
4041  * @f:  the value
4042  *
4043  * Implement the compare operation between a nodeset and a number
4044  *     @ns < @val    (1, 1, ...
4045  *     @ns <= @val   (1, 0, ...
4046  *     @ns > @val    (0, 1, ...
4047  *     @ns >= @val   (0, 0, ...
4048  *
4049  * If one object to be compared is a node-set and the other is a number,
4050  * then the comparison will be true if and only if there is a node in the
4051  * node-set such that the result of performing the comparison on the number
4052  * to be compared and on the result of converting the string-value of that
4053  * node to a number using the number function is true.
4054  *
4055  * Returns 0 or 1 depending on the results of the test.
4056  */
4057 static int
4058 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4059                             xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4060     int i, ret = 0;
4061     xmlNodeSetPtr ns;
4062     xmlChar *str2;
4063
4064     if ((f == NULL) || (arg == NULL) ||
4065         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4066         xmlXPathFreeObject(arg);
4067         xmlXPathFreeObject(f);
4068         return(0);
4069     }
4070     ns = arg->nodesetval;
4071     if (ns != NULL) {
4072         for (i = 0;i < ns->nodeNr;i++) {
4073              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4074              if (str2 != NULL) {
4075                  valuePush(ctxt,
4076                            xmlXPathNewString(str2));
4077                  xmlFree(str2);
4078                  xmlXPathNumberFunction(ctxt, 1);
4079                  valuePush(ctxt, xmlXPathObjectCopy(f));
4080                  ret = xmlXPathCompareValues(ctxt, inf, strict);
4081                  if (ret)
4082                      break;
4083              }
4084         }
4085     }
4086     xmlXPathFreeObject(arg);
4087     xmlXPathFreeObject(f);
4088     return(ret);
4089 }
4090
4091 /**
4092  * xmlXPathCompareNodeSetString:
4093  * @ctxt:  the XPath Parser context
4094  * @inf:  less than (1) or greater than (0)
4095  * @strict:  is the comparison strict
4096  * @arg:  the node set
4097  * @s:  the value
4098  *
4099  * Implement the compare operation between a nodeset and a string
4100  *     @ns < @val    (1, 1, ...
4101  *     @ns <= @val   (1, 0, ...
4102  *     @ns > @val    (0, 1, ...
4103  *     @ns >= @val   (0, 0, ...
4104  *
4105  * If one object to be compared is a node-set and the other is a string,
4106  * then the comparison will be true if and only if there is a node in
4107  * the node-set such that the result of performing the comparison on the
4108  * string-value of the node and the other string is true.
4109  *
4110  * Returns 0 or 1 depending on the results of the test.
4111  */
4112 static int
4113 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4114                             xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4115     int i, ret = 0;
4116     xmlNodeSetPtr ns;
4117     xmlChar *str2;
4118
4119     if ((s == NULL) || (arg == NULL) ||
4120         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4121         xmlXPathFreeObject(arg);
4122         xmlXPathFreeObject(s);
4123         return(0);
4124     }
4125     ns = arg->nodesetval;
4126     if (ns != NULL) {
4127         for (i = 0;i < ns->nodeNr;i++) {
4128              str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4129              if (str2 != NULL) {
4130                  valuePush(ctxt,
4131                            xmlXPathNewString(str2));
4132                  xmlFree(str2);
4133                  valuePush(ctxt, xmlXPathObjectCopy(s));
4134                  ret = xmlXPathCompareValues(ctxt, inf, strict);
4135                  if (ret)
4136                      break;
4137              }
4138         }
4139     }
4140     xmlXPathFreeObject(arg);
4141     xmlXPathFreeObject(s);
4142     return(ret);
4143 }
4144
4145 /**
4146  * xmlXPathCompareNodeSets:
4147  * @inf:  less than (1) or greater than (0)
4148  * @strict:  is the comparison strict
4149  * @arg1:  the first node set object
4150  * @arg2:  the second node set object
4151  *
4152  * Implement the compare operation on nodesets:
4153  *
4154  * If both objects to be compared are node-sets, then the comparison
4155  * will be true if and only if there is a node in the first node-set
4156  * and a node in the second node-set such that the result of performing
4157  * the comparison on the string-values of the two nodes is true. 
4158  * ....
4159  * When neither object to be compared is a node-set and the operator
4160  * is <=, <, >= or >, then the objects are compared by converting both
4161  * objects to numbers and comparing the numbers according to IEEE 754.
4162  * ....
4163  * The number function converts its argument to a number as follows:
4164  *  - a string that consists of optional whitespace followed by an
4165  *    optional minus sign followed by a Number followed by whitespace
4166  *    is converted to the IEEE 754 number that is nearest (according
4167  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
4168  *    represented by the string; any other string is converted to NaN
4169  *
4170  * Conclusion all nodes need to be converted first to their string value
4171  * and then the comparison must be done when possible 
4172  */
4173 static int
4174 xmlXPathCompareNodeSets(int inf, int strict,
4175                         xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4176     int i, j, init = 0;
4177     double val1;
4178     double *values2;
4179     int ret = 0;
4180     xmlNodeSetPtr ns1;
4181     xmlNodeSetPtr ns2;
4182
4183     if ((arg1 == NULL) ||
4184         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4185         xmlXPathFreeObject(arg2);
4186         return(0);
4187     }
4188     if ((arg2 == NULL) ||
4189         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4190         xmlXPathFreeObject(arg1);
4191         xmlXPathFreeObject(arg2);
4192         return(0);
4193     }
4194
4195     ns1 = arg1->nodesetval;
4196     ns2 = arg2->nodesetval;
4197
4198     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
4199         xmlXPathFreeObject(arg1);
4200         xmlXPathFreeObject(arg2);
4201         return(0);
4202     }
4203     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
4204         xmlXPathFreeObject(arg1);
4205         xmlXPathFreeObject(arg2);
4206         return(0);
4207     }
4208
4209     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4210     if (values2 == NULL) {
4211         xmlXPathFreeObject(arg1);
4212         xmlXPathFreeObject(arg2);
4213         return(0);
4214     }
4215     for (i = 0;i < ns1->nodeNr;i++) {
4216         val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
4217         if (xmlXPathIsNaN(val1))
4218             continue;
4219         for (j = 0;j < ns2->nodeNr;j++) {
4220             if (init == 0) {
4221                 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
4222             }
4223             if (xmlXPathIsNaN(values2[j]))
4224                 continue;
4225             if (inf && strict) 
4226                 ret = (val1 < values2[j]);
4227             else if (inf && !strict)
4228                 ret = (val1 <= values2[j]);
4229             else if (!inf && strict)
4230                 ret = (val1 > values2[j]);
4231             else if (!inf && !strict)
4232                 ret = (val1 >= values2[j]);
4233             if (ret)
4234                 break;
4235         }
4236         if (ret)
4237             break;
4238         init = 1;
4239     }
4240     xmlFree(values2);
4241     xmlXPathFreeObject(arg1);
4242     xmlXPathFreeObject(arg2);
4243     return(ret);
4244 }
4245
4246 /**
4247  * xmlXPathCompareNodeSetValue:
4248  * @ctxt:  the XPath Parser context
4249  * @inf:  less than (1) or greater than (0)
4250  * @strict:  is the comparison strict
4251  * @arg:  the node set
4252  * @val:  the value
4253  *
4254  * Implement the compare operation between a nodeset and a value
4255  *     @ns < @val    (1, 1, ...
4256  *     @ns <= @val   (1, 0, ...
4257  *     @ns > @val    (0, 1, ...
4258  *     @ns >= @val   (0, 0, ...
4259  *
4260  * If one object to be compared is a node-set and the other is a boolean,
4261  * then the comparison will be true if and only if the result of performing
4262  * the comparison on the boolean and on the result of converting
4263  * the node-set to a boolean using the boolean function is true.
4264  *
4265  * Returns 0 or 1 depending on the results of the test.
4266  */
4267 static int
4268 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4269                             xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4270     if ((val == NULL) || (arg == NULL) ||
4271         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4272         return(0);
4273
4274     switch(val->type) {
4275         case XPATH_NUMBER:
4276             return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4277         case XPATH_NODESET:
4278         case XPATH_XSLT_TREE:
4279             return(xmlXPathCompareNodeSets(inf, strict, arg, val));
4280         case XPATH_STRING:
4281             return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4282         case XPATH_BOOLEAN:
4283             valuePush(ctxt, arg);
4284             xmlXPathBooleanFunction(ctxt, 1);
4285             valuePush(ctxt, val);
4286             return(xmlXPathCompareValues(ctxt, inf, strict));
4287         default:
4288             TODO
4289     }
4290     return(0);
4291 }
4292
4293 /**
4294  * xmlXPathEqualNodeSetString:
4295  * @arg:  the nodeset object argument
4296  * @str:  the string to compare to.
4297  * @neq:  flag to show whether for '=' (0) or '!=' (1)
4298  *
4299  * Implement the equal operation on XPath objects content: @arg1 == @arg2
4300  * If one object to be compared is a node-set and the other is a string,
4301  * then the comparison will be true if and only if there is a node in
4302  * the node-set such that the result of performing the comparison on the
4303  * string-value of the node and the other string is true.
4304  *
4305  * Returns 0 or 1 depending on the results of the test.
4306  */
4307 static int
4308 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
4309 {
4310     int i;
4311     xmlNodeSetPtr ns;
4312     xmlChar *str2;
4313     unsigned int hash;
4314
4315     if ((str == NULL) || (arg == NULL) ||
4316         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4317         return (0);
4318     ns = arg->nodesetval;
4319     hash = xmlXPathStringHash(str);
4320     if (ns == NULL)
4321         return (0);
4322     if (ns->nodeNr <= 0) {
4323         if (hash == 0)
4324             return(neq ^ 1);
4325         return(neq);
4326     }
4327     for (i = 0; i < ns->nodeNr; i++) {
4328         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4329             str2 = xmlNodeGetContent(ns->nodeTab[i]);
4330             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4331                 xmlFree(str2);
4332                 if (neq)
4333                     continue;
4334                 return (1);
4335             } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4336                 if (neq)
4337                     continue;
4338                 return (1);
4339             } else if (neq) {
4340                 if (str2 != NULL)
4341                     xmlFree(str2);
4342                 return (1);
4343             }
4344             if (str2 != NULL)
4345                 xmlFree(str2);
4346         } else if (neq)
4347             return (1);
4348     }
4349     return (0);
4350 }
4351
4352 /**
4353  * xmlXPathEqualNodeSetFloat:
4354  * @arg:  the nodeset object argument
4355  * @f:  the float to compare to
4356  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
4357  *
4358  * Implement the equal operation on XPath objects content: @arg1 == @arg2
4359  * If one object to be compared is a node-set and the other is a number,
4360  * then the comparison will be true if and only if there is a node in
4361  * the node-set such that the result of performing the comparison on the
4362  * number to be compared and on the result of converting the string-value
4363  * of that node to a number using the number function is true.
4364  *
4365  * Returns 0 or 1 depending on the results of the test.
4366  */
4367 static int
4368 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4369     xmlXPathObjectPtr arg, double f, int neq) {
4370   int i, ret=0;
4371   xmlNodeSetPtr ns;
4372   xmlChar *str2;
4373   xmlXPathObjectPtr val;
4374   double v;
4375
4376     if ((arg == NULL) ||
4377         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4378         return(0);
4379
4380     ns = arg->nodesetval;
4381     if (ns != NULL) {
4382         for (i=0;i<ns->nodeNr;i++) {
4383             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4384             if (str2 != NULL) {
4385                 valuePush(ctxt, xmlXPathNewString(str2));
4386                 xmlFree(str2);
4387                 xmlXPathNumberFunction(ctxt, 1);
4388                 val = valuePop(ctxt);
4389                 v = val->floatval;
4390                 xmlXPathFreeObject(val);
4391                 if (!xmlXPathIsNaN(v)) {
4392                     if ((!neq) && (v==f)) {
4393                         ret = 1;
4394                         break;
4395                     } else if ((neq) && (v!=f)) {
4396                         ret = 1;
4397                         break;
4398                     }
4399                 }
4400             }
4401         }
4402     }
4403
4404     return(ret);
4405 }
4406
4407
4408 /**
4409  * xmlXPathEqualNodeSets:
4410  * @arg1:  first nodeset object argument
4411  * @arg2:  second nodeset object argument
4412  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
4413  *
4414  * Implement the equal / not equal operation on XPath nodesets:
4415  * @arg1 == @arg2  or  @arg1 != @arg2
4416  * If both objects to be compared are node-sets, then the comparison
4417  * will be true if and only if there is a node in the first node-set and
4418  * a node in the second node-set such that the result of performing the
4419  * comparison on the string-values of the two nodes is true.
4420  *
4421  * (needless to say, this is a costly operation)
4422  *
4423  * Returns 0 or 1 depending on the results of the test.
4424  */
4425 static int
4426 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
4427     int i, j;
4428     unsigned int *hashs1;
4429     unsigned int *hashs2;
4430     xmlChar **values1;
4431     xmlChar **values2;
4432     int ret = 0;
4433     xmlNodeSetPtr ns1;
4434     xmlNodeSetPtr ns2;
4435
4436     if ((arg1 == NULL) ||
4437         ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4438         return(0);
4439     if ((arg2 == NULL) ||
4440         ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4441         return(0);
4442
4443     ns1 = arg1->nodesetval;
4444     ns2 = arg2->nodesetval;
4445
4446     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
4447         return(0);
4448     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
4449         return(0);
4450
4451     /*
4452      * for equal, check if there is a node pertaining to both sets
4453      */
4454     if (neq == 0)
4455         for (i = 0;i < ns1->nodeNr;i++)
4456             for (j = 0;j < ns2->nodeNr;j++)
4457                 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4458                     return(1);
4459
4460     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4461     if (values1 == NULL)
4462         return(0);
4463     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4464     if (hashs1 == NULL) {
4465         xmlFree(values1);
4466         return(0);
4467     }
4468     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4469     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4470     if (values2 == NULL) {
4471         xmlFree(hashs1);
4472         xmlFree(values1);
4473         return(0);
4474     }
4475     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4476     if (hashs2 == NULL) {
4477         xmlFree(hashs1);
4478         xmlFree(values1);
4479         xmlFree(values2);
4480         return(0);
4481     }
4482     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4483     for (i = 0;i < ns1->nodeNr;i++) {
4484         hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
4485         for (j = 0;j < ns2->nodeNr;j++) {
4486             if (i == 0)
4487                 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4488             if (hashs1[i] != hashs2[j]) {
4489                 if (neq) {
4490                     ret = 1;
4491                     break;
4492                 }
4493             }
4494             else {
4495                 if (values1[i] == NULL)
4496                     values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4497                 if (values2[j] == NULL)
4498                     values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4499                 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
4500                 if (ret)
4501                     break;
4502             }
4503         }
4504         if (ret)
4505             break;
4506     }
4507     for (i = 0;i < ns1->nodeNr;i++)
4508         if (values1[i] != NULL)
4509             xmlFree(values1[i]);
4510     for (j = 0;j < ns2->nodeNr;j++)
4511         if (values2[j] != NULL)
4512             xmlFree(values2[j]);
4513     xmlFree(values1);
4514     xmlFree(values2);
4515     xmlFree(hashs1);
4516     xmlFree(hashs2);
4517     return(ret);
4518 }
4519
4520 static int
4521 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4522   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4523     int ret = 0;
4524     /*
4525      *At this point we are assured neither arg1 nor arg2
4526      *is a nodeset, so we can just pick the appropriate routine.
4527      */
4528     switch (arg1->type) {
4529         case XPATH_UNDEFINED:
4530 #ifdef DEBUG_EXPR
4531             xmlGenericError(xmlGenericErrorContext,
4532                     "Equal: undefined\n");
4533 #endif
4534             break;
4535         case XPATH_BOOLEAN:
4536             switch (arg2->type) {
4537                 case XPATH_UNDEFINED:
4538 #ifdef DEBUG_EXPR
4539                     xmlGenericError(xmlGenericErrorContext,
4540                             "Equal: undefined\n");
4541 #endif
4542                     break;
4543                 case XPATH_BOOLEAN:
4544 #ifdef DEBUG_EXPR
4545                     xmlGenericError(xmlGenericErrorContext,
4546                             "Equal: %d boolean %d \n",
4547                             arg1->boolval, arg2->boolval);
4548 #endif
4549                     ret = (arg1->boolval == arg2->boolval);
4550                     break;
4551                 case XPATH_NUMBER:
4552                     ret = (arg1->boolval ==
4553                            xmlXPathCastNumberToBoolean(arg2->floatval));
4554                     break;
4555                 case XPATH_STRING:
4556                     if ((arg2->stringval == NULL) ||
4557                         (arg2->stringval[0] == 0)) ret = 0;
4558                     else 
4559                         ret = 1;
4560                     ret = (arg1->boolval == ret);
4561                     break;
4562                 case XPATH_USERS:
4563                 case XPATH_POINT:
4564                 case XPATH_RANGE:
4565                 case XPATH_LOCATIONSET:
4566                     TODO
4567                     break;
4568                 case XPATH_NODESET:
4569                 case XPATH_XSLT_TREE:
4570                     break;
4571             }
4572             break;
4573         case XPATH_NUMBER:
4574             switch (arg2->type) {
4575                 case XPATH_UNDEFINED:
4576 #ifdef DEBUG_EXPR
4577                     xmlGenericError(xmlGenericErrorContext,
4578                             "Equal: undefined\n");
4579 #endif
4580                     break;
4581                 case XPATH_BOOLEAN:
4582                     ret = (arg2->boolval==
4583                            xmlXPathCastNumberToBoolean(arg1->floatval));
4584                     break;
4585                 case XPATH_STRING:
4586                     valuePush(ctxt, arg2);
4587                     xmlXPathNumberFunction(ctxt, 1);
4588                     arg2 = valuePop(ctxt);
4589                     /* no break on purpose */
4590                 case XPATH_NUMBER:
4591                     /* Hand check NaN and Infinity equalities */
4592                     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4593                         ret = 0;
4594                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4595                         if (xmlXPathIsInf(arg2->floatval) == 1)
4596                             ret = 1;
4597                         else
4598                             ret = 0;
4599                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4600                         if (xmlXPathIsInf(arg2->floatval) == -1)
4601                             ret = 1;
4602                         else
4603                             ret = 0;
4604                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4605                         if (xmlXPathIsInf(arg1->floatval) == 1)
4606                             ret = 1;
4607                         else
4608                             ret = 0;
4609                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4610                         if (xmlXPathIsInf(arg1->floatval) == -1)
4611                             ret = 1;
4612                         else
4613                             ret = 0;
4614                     } else {
4615                         ret = (arg1->floatval == arg2->floatval);
4616                     }
4617                     break;
4618                 case XPATH_USERS:
4619                 case XPATH_POINT:
4620                 case XPATH_RANGE:
4621                 case XPATH_LOCATIONSET:
4622                     TODO
4623                     break;
4624                 case XPATH_NODESET:
4625                 case XPATH_XSLT_TREE:
4626                     break;
4627             }
4628             break;
4629         case XPATH_STRING:
4630             switch (arg2->type) {
4631                 case XPATH_UNDEFINED:
4632 #ifdef DEBUG_EXPR
4633                     xmlGenericError(xmlGenericErrorContext,
4634                             "Equal: undefined\n");
4635 #endif
4636                     break;
4637                 case XPATH_BOOLEAN:
4638                     if ((arg1->stringval == NULL) ||
4639                         (arg1->stringval[0] == 0)) ret = 0;
4640                     else 
4641                         ret = 1;
4642                     ret = (arg2->boolval == ret);
4643                     break;
4644                 case XPATH_STRING:
4645                     ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4646                     break;
4647                 case XPATH_NUMBER:
4648                     valuePush(ctxt, arg1);
4649                     xmlXPathNumberFunction(ctxt, 1);
4650                     arg1 = valuePop(ctxt);
4651                     /* Hand check NaN and Infinity equalities */
4652                     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4653                         ret = 0;
4654                     } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4655                         if (xmlXPathIsInf(arg2->floatval) == 1)
4656                             ret = 1;
4657                         else
4658                             ret = 0;
4659                     } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4660                         if (xmlXPathIsInf(arg2->floatval) == -1)
4661                             ret = 1;
4662                         else
4663                             ret = 0;
4664                     } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4665                         if (xmlXPathIsInf(arg1->floatval) == 1)
4666                             ret = 1;
4667                         else
4668                             ret = 0;
4669                     } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4670                         if (xmlXPathIsInf(arg1->floatval) == -1)
4671                             ret = 1;
4672                         else
4673                             ret = 0;
4674                     } else {
4675                         ret = (arg1->floatval == arg2->floatval);
4676                     }
4677                     break;
4678                 case XPATH_USERS:
4679                 case XPATH_POINT:
4680                 case XPATH_RANGE:
4681                 case XPATH_LOCATIONSET:
4682                     TODO
4683                     break;
4684                 case XPATH_NODESET:
4685                 case XPATH_XSLT_TREE:
4686                     break;
4687             }
4688             break;
4689         case XPATH_USERS:
4690         case XPATH_POINT:
4691         case XPATH_RANGE:
4692         case XPATH_LOCATIONSET:
4693             TODO
4694             break;
4695         case XPATH_NODESET:
4696         case XPATH_XSLT_TREE:
4697             break;
4698     }
4699     xmlXPathFreeObject(arg1);
4700     xmlXPathFreeObject(arg2);
4701     return(ret);
4702 }
4703
4704 /**
4705  * xmlXPathEqualValues:
4706  * @ctxt:  the XPath Parser context
4707  *
4708  * Implement the equal operation on XPath objects content: @arg1 == @arg2
4709  *
4710  * Returns 0 or 1 depending on the results of the test.
4711  */
4712 int
4713 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4714     xmlXPathObjectPtr arg1, arg2, argtmp;
4715     int ret = 0;
4716
4717     arg2 = valuePop(ctxt); 
4718     arg1 = valuePop(ctxt);
4719     if ((arg1 == NULL) || (arg2 == NULL)) {
4720         if (arg1 != NULL)
4721             xmlXPathFreeObject(arg1);
4722         else
4723             xmlXPathFreeObject(arg2);
4724         XP_ERROR0(XPATH_INVALID_OPERAND);
4725     }
4726
4727     if (arg1 == arg2) {
4728 #ifdef DEBUG_EXPR
4729         xmlGenericError(xmlGenericErrorContext,
4730                 "Equal: by pointer\n");
4731 #endif
4732         return(1);
4733     }
4734
4735     /*
4736      *If either argument is a nodeset, it's a 'special case'
4737      */
4738     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4739       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4740         /*
4741          *Hack it to assure arg1 is the nodeset
4742          */
4743         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4744                 argtmp = arg2;
4745                 arg2 = arg1;
4746                 arg1 = argtmp;
4747         }
4748         switch (arg2->type) {
4749             case XPATH_UNDEFINED:
4750 #ifdef DEBUG_EXPR
4751                 xmlGenericError(xmlGenericErrorContext,
4752                         "Equal: undefined\n");
4753 #endif
4754                 break;
4755             case XPATH_NODESET:
4756             case XPATH_XSLT_TREE:
4757                 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4758                 break;
4759             case XPATH_BOOLEAN:
4760                 if ((arg1->nodesetval == NULL) ||
4761                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
4762                 else 
4763                     ret = 1;
4764                 ret = (ret == arg2->boolval);
4765                 break;
4766             case XPATH_NUMBER:
4767                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4768                 break;
4769             case XPATH_STRING:
4770                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4771                 break;
4772             case XPATH_USERS:
4773             case XPATH_POINT:
4774             case XPATH_RANGE:
4775             case XPATH_LOCATIONSET:
4776                 TODO
4777                 break;
4778         }
4779         xmlXPathFreeObject(arg1);
4780         xmlXPathFreeObject(arg2);
4781         return(ret);
4782     }
4783
4784     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4785 }
4786
4787 /**
4788  * xmlXPathNotEqualValues:
4789  * @ctxt:  the XPath Parser context
4790  *
4791  * Implement the equal operation on XPath objects content: @arg1 == @arg2
4792  *
4793  * Returns 0 or 1 depending on the results of the test.
4794  */
4795 int
4796 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4797     xmlXPathObjectPtr arg1, arg2, argtmp;
4798     int ret = 0;
4799
4800     arg2 = valuePop(ctxt); 
4801     arg1 = valuePop(ctxt);
4802     if ((arg1 == NULL) || (arg2 == NULL)) {
4803         if (arg1 != NULL)
4804             xmlXPathFreeObject(arg1);
4805         else
4806             xmlXPathFreeObject(arg2);
4807         XP_ERROR0(XPATH_INVALID_OPERAND);
4808     }
4809
4810     if (arg1 == arg2) {
4811 #ifdef DEBUG_EXPR
4812         xmlGenericError(xmlGenericErrorContext,
4813                 "NotEqual: by pointer\n");
4814 #endif
4815         return(0);
4816     }
4817
4818     /*
4819      *If either argument is a nodeset, it's a 'special case'
4820      */
4821     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4822       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4823         /*
4824          *Hack it to assure arg1 is the nodeset
4825          */
4826         if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4827                 argtmp = arg2;
4828                 arg2 = arg1;
4829                 arg1 = argtmp;
4830         }
4831         switch (arg2->type) {
4832             case XPATH_UNDEFINED:
4833 #ifdef DEBUG_EXPR
4834                 xmlGenericError(xmlGenericErrorContext,
4835                         "NotEqual: undefined\n");
4836 #endif
4837                 break;
4838             case XPATH_NODESET:
4839             case XPATH_XSLT_TREE:
4840                 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4841                 break;
4842             case XPATH_BOOLEAN:
4843                 if ((arg1->nodesetval == NULL) ||
4844                   (arg1->nodesetval->nodeNr == 0)) ret = 0;
4845                 else 
4846                     ret = 1;
4847                 ret = (ret != arg2->boolval);
4848                 break;
4849             case XPATH_NUMBER:
4850                 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4851                 break;
4852             case XPATH_STRING:
4853                 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4854                 break;
4855             case XPATH_USERS:
4856             case XPATH_POINT:
4857             case XPATH_RANGE:
4858             case XPATH_LOCATIONSET:
4859                 TODO
4860                 break;
4861         }
4862         xmlXPathFreeObject(arg1);
4863         xmlXPathFreeObject(arg2);
4864         return(ret);
4865     }
4866
4867     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4868 }
4869
4870 /**
4871  * xmlXPathCompareValues:
4872  * @ctxt:  the XPath Parser context
4873  * @inf:  less than (1) or greater than (0)
4874  * @strict:  is the comparison strict
4875  *
4876  * Implement the compare operation on XPath objects: 
4877  *     @arg1 < @arg2    (1, 1, ...
4878  *     @arg1 <= @arg2   (1, 0, ...
4879  *     @arg1 > @arg2    (0, 1, ...
4880  *     @arg1 >= @arg2   (0, 0, ...
4881  *
4882  * When neither object to be compared is a node-set and the operator is
4883  * <=, <, >=, >, then the objects are compared by converted both objects
4884  * to numbers and comparing the numbers according to IEEE 754. The <
4885  * comparison will be true if and only if the first number is less than the
4886  * second number. The <= comparison will be true if and only if the first
4887  * number is less than or equal to the second number. The > comparison
4888  * will be true if and only if the first number is greater than the second
4889  * number. The >= comparison will be true if and only if the first number
4890  * is greater than or equal to the second number.
4891  *
4892  * Returns 1 if the comparison succeeded, 0 if it failed
4893  */
4894 int
4895 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4896     int ret = 0, arg1i = 0, arg2i = 0;
4897     xmlXPathObjectPtr arg1, arg2;
4898
4899     arg2 = valuePop(ctxt); 
4900     arg1 = valuePop(ctxt);
4901     if ((arg1 == NULL) || (arg2 == NULL)) {
4902         if (arg1 != NULL)
4903             xmlXPathFreeObject(arg1);
4904         else
4905             xmlXPathFreeObject(arg2);
4906         XP_ERROR0(XPATH_INVALID_OPERAND);
4907     }
4908
4909     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4910       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4911         if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4912           ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
4913             ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
4914         } else {
4915             if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4916                 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4917                                                   arg1, arg2);
4918             } else {
4919                 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4920                                                   arg2, arg1);
4921             }
4922         }
4923         return(ret);
4924     }
4925
4926     if (arg1->type != XPATH_NUMBER) {
4927         valuePush(ctxt, arg1);
4928         xmlXPathNumberFunction(ctxt, 1);
4929         arg1 = valuePop(ctxt);
4930     }
4931     if (arg1->type != XPATH_NUMBER) {
4932         xmlXPathFreeObject(arg1);
4933         xmlXPathFreeObject(arg2);
4934         XP_ERROR0(XPATH_INVALID_OPERAND);
4935     }
4936     if (arg2->type != XPATH_NUMBER) {
4937         valuePush(ctxt, arg2);
4938         xmlXPathNumberFunction(ctxt, 1);
4939         arg2 = valuePop(ctxt);
4940     }
4941     if (arg2->type != XPATH_NUMBER) {
4942         xmlXPathFreeObject(arg1);
4943         xmlXPathFreeObject(arg2);
4944         XP_ERROR0(XPATH_INVALID_OPERAND);
4945     }
4946     /*
4947      * Add tests for infinity and nan
4948      * => feedback on 3.4 for Inf and NaN
4949      */
4950     /* Hand check NaN and Infinity comparisons */
4951     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4952         ret=0;
4953     } else {
4954         arg1i=xmlXPathIsInf(arg1->floatval);
4955         arg2i=xmlXPathIsInf(arg2->floatval);
4956         if (inf && strict) {
4957             if ((arg1i == -1 && arg2i != -1) ||
4958                 (arg2i == 1 && arg1i != 1)) {
4959                 ret = 1;
4960             } else if (arg1i == 0 && arg2i == 0) {
4961                 ret = (arg1->floatval < arg2->floatval);
4962             } else {
4963                 ret = 0;
4964             }
4965         }
4966         else if (inf && !strict) {
4967             if (arg1i == -1 || arg2i == 1) {
4968                 ret = 1;
4969             } else if (arg1i == 0 && arg2i == 0) {
4970                 ret = (arg1->floatval <= arg2->floatval);
4971             } else {
4972                 ret = 0;
4973             }
4974         }
4975         else if (!inf && strict) {
4976             if ((arg1i == 1 && arg2i != 1) ||
4977                 (arg2i == -1 && arg1i != -1)) {
4978                 ret = 1;
4979             } else if (arg1i == 0 && arg2i == 0) {
4980                 ret = (arg1->floatval > arg2->floatval);
4981             } else {
4982                 ret = 0;
4983             }
4984         }
4985         else if (!inf && !strict) {
4986             if (arg1i == 1 || arg2i == -1) {
4987                 ret = 1;
4988             } else if (arg1i == 0 && arg2i == 0) {
4989                 ret = (arg1->floatval >= arg2->floatval);
4990             } else {
4991                 ret = 0;
4992             }
4993         }
4994     }
4995     xmlXPathFreeObject(arg1);
4996     xmlXPathFreeObject(arg2);
4997     return(ret);
4998 }
4999
5000 /**
5001  * xmlXPathValueFlipSign:
5002  * @ctxt:  the XPath Parser context
5003  *
5004  * Implement the unary - operation on an XPath object
5005  * The numeric operators convert their operands to numbers as if
5006  * by calling the number function.
5007  */
5008 void
5009 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
5010     CAST_TO_NUMBER;
5011     CHECK_TYPE(XPATH_NUMBER);
5012     if (xmlXPathIsNaN(ctxt->value->floatval))
5013         ctxt->value->floatval=xmlXPathNAN;
5014     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5015         ctxt->value->floatval=xmlXPathNINF;
5016     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5017         ctxt->value->floatval=xmlXPathPINF;
5018     else if (ctxt->value->floatval == 0) {
5019         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5020             ctxt->value->floatval = xmlXPathNZERO;
5021         else
5022             ctxt->value->floatval = 0;
5023     }
5024     else
5025         ctxt->value->floatval = - ctxt->value->floatval;
5026 }
5027
5028 /**
5029  * xmlXPathAddValues:
5030  * @ctxt:  the XPath Parser context
5031  *
5032  * Implement the add operation on XPath objects:
5033  * The numeric operators convert their operands to numbers as if
5034  * by calling the number function.
5035  */
5036 void
5037 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5038     xmlXPathObjectPtr arg;
5039     double val;
5040
5041     arg = valuePop(ctxt);
5042     if (arg == NULL)
5043         XP_ERROR(XPATH_INVALID_OPERAND);
5044     val = xmlXPathCastToNumber(arg);
5045     xmlXPathFreeObject(arg);
5046
5047     CAST_TO_NUMBER;
5048     CHECK_TYPE(XPATH_NUMBER);
5049     ctxt->value->floatval += val;
5050 }
5051
5052 /**
5053  * xmlXPathSubValues:
5054  * @ctxt:  the XPath Parser context
5055  *
5056  * Implement the subtraction operation on XPath objects:
5057  * The numeric operators convert their operands to numbers as if
5058  * by calling the number function.
5059  */
5060 void
5061 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5062     xmlXPathObjectPtr arg;
5063     double val;
5064
5065     arg = valuePop(ctxt);
5066     if (arg == NULL)
5067         XP_ERROR(XPATH_INVALID_OPERAND);
5068     val = xmlXPathCastToNumber(arg);
5069     xmlXPathFreeObject(arg);
5070
5071     CAST_TO_NUMBER;
5072     CHECK_TYPE(XPATH_NUMBER);
5073     ctxt->value->floatval -= val;
5074 }
5075
5076 /**
5077  * xmlXPathMultValues:
5078  * @ctxt:  the XPath Parser context
5079  *
5080  * Implement the multiply operation on XPath objects:
5081  * The numeric operators convert their operands to numbers as if
5082  * by calling the number function.
5083  */
5084 void
5085 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5086     xmlXPathObjectPtr arg;
5087     double val;
5088
5089     arg = valuePop(ctxt);
5090     if (arg == NULL)
5091         XP_ERROR(XPATH_INVALID_OPERAND);
5092     val = xmlXPathCastToNumber(arg);
5093     xmlXPathFreeObject(arg);
5094
5095     CAST_TO_NUMBER;
5096     CHECK_TYPE(XPATH_NUMBER);
5097     ctxt->value->floatval *= val;
5098 }
5099
5100 /**
5101  * xmlXPathDivValues:
5102  * @ctxt:  the XPath Parser context
5103  *
5104  * Implement the div operation on XPath objects @arg1 / @arg2:
5105  * The numeric operators convert their operands to numbers as if
5106  * by calling the number function.
5107  */
5108 void
5109 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5110     xmlXPathObjectPtr arg;
5111     double val;
5112
5113     arg = valuePop(ctxt);
5114     if (arg == NULL)
5115         XP_ERROR(XPATH_INVALID_OPERAND);
5116     val = xmlXPathCastToNumber(arg);
5117     xmlXPathFreeObject(arg);
5118
5119     CAST_TO_NUMBER;
5120     CHECK_TYPE(XPATH_NUMBER);
5121     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5122         ctxt->value->floatval = xmlXPathNAN;
5123     else if (val == 0 && xmlXPathGetSign(val) != 0) {
5124         if (ctxt->value->floatval == 0)
5125             ctxt->value->floatval = xmlXPathNAN;
5126         else if (ctxt->value->floatval > 0)
5127             ctxt->value->floatval = xmlXPathNINF;
5128         else if (ctxt->value->floatval < 0)
5129             ctxt->value->floatval = xmlXPathPINF;
5130     }
5131     else if (val == 0) {
5132         if (ctxt->value->floatval == 0)
5133             ctxt->value->floatval = xmlXPathNAN;
5134         else if (ctxt->value->floatval > 0)
5135             ctxt->value->floatval = xmlXPathPINF;
5136         else if (ctxt->value->floatval < 0)
5137             ctxt->value->floatval = xmlXPathNINF;
5138     } else 
5139         ctxt->value->floatval /= val;
5140 }
5141
5142 /**
5143  * xmlXPathModValues:
5144  * @ctxt:  the XPath Parser context
5145  *
5146  * Implement the mod operation on XPath objects: @arg1 / @arg2
5147  * The numeric operators convert their operands to numbers as if
5148  * by calling the number function.
5149  */
5150 void
5151 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5152     xmlXPathObjectPtr arg;
5153     double arg1, arg2;
5154
5155     arg = valuePop(ctxt);
5156     if (arg == NULL)
5157         XP_ERROR(XPATH_INVALID_OPERAND);
5158     arg2 = xmlXPathCastToNumber(arg);
5159     xmlXPathFreeObject(arg);
5160
5161     CAST_TO_NUMBER;
5162     CHECK_TYPE(XPATH_NUMBER);
5163     arg1 = ctxt->value->floatval;
5164     if (arg2 == 0)
5165         ctxt->value->floatval = xmlXPathNAN;
5166     else {
5167         ctxt->value->floatval = fmod(arg1, arg2);
5168     }
5169 }
5170
5171 /************************************************************************
5172  *                                                                      *
5173  *              The traversal functions                                 *
5174  *                                                                      *
5175  ************************************************************************/
5176
5177 /*
5178  * A traversal function enumerates nodes along an axis.
5179  * Initially it must be called with NULL, and it indicates
5180  * termination on the axis by returning NULL.
5181  */
5182 typedef xmlNodePtr (*xmlXPathTraversalFunction)
5183                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5184
5185 /**
5186  * xmlXPathNextSelf:
5187  * @ctxt:  the XPath Parser context
5188  * @cur:  the current node in the traversal
5189  *
5190  * Traversal function for the "self" direction
5191  * The self axis contains just the context node itself
5192  *
5193  * Returns the next element following that axis
5194  */
5195 xmlNodePtr
5196 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5197     if (cur == NULL)
5198         return(ctxt->context->node);
5199     return(NULL);
5200 }
5201
5202 /**
5203  * xmlXPathNextChild:
5204  * @ctxt:  the XPath Parser context
5205  * @cur:  the current node in the traversal
5206  *
5207  * Traversal function for the "child" direction
5208  * The child axis contains the children of the context node in document order.
5209  *
5210  * Returns the next element following that axis
5211  */
5212 xmlNodePtr
5213 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5214     if (cur == NULL) {
5215         if (ctxt->context->node == NULL) return(NULL);
5216         switch (ctxt->context->node->type) {
5217             case XML_ELEMENT_NODE:
5218             case XML_TEXT_NODE:
5219             case XML_CDATA_SECTION_NODE:
5220             case XML_ENTITY_REF_NODE:
5221             case XML_ENTITY_NODE:
5222             case XML_PI_NODE:
5223             case XML_COMMENT_NODE:
5224             case XML_NOTATION_NODE:
5225             case XML_DTD_NODE:
5226                 return(ctxt->context->node->children);
5227             case XML_DOCUMENT_NODE:
5228             case XML_DOCUMENT_TYPE_NODE:
5229             case XML_DOCUMENT_FRAG_NODE:
5230             case XML_HTML_DOCUMENT_NODE:
5231 #ifdef LIBXML_DOCB_ENABLED
5232             case XML_DOCB_DOCUMENT_NODE:
5233 #endif
5234                 return(((xmlDocPtr) ctxt->context->node)->children);
5235             case XML_ELEMENT_DECL:
5236             case XML_ATTRIBUTE_DECL:
5237             case XML_ENTITY_DECL:
5238             case XML_ATTRIBUTE_NODE:
5239             case XML_NAMESPACE_DECL:
5240             case XML_XINCLUDE_START:
5241             case XML_XINCLUDE_END:
5242                 return(NULL);
5243         }
5244         return(NULL);
5245     }
5246     if ((cur->type == XML_DOCUMENT_NODE) ||
5247         (cur->type == XML_HTML_DOCUMENT_NODE))
5248         return(NULL);
5249     return(cur->next);
5250 }
5251
5252 /**
5253  * xmlXPathNextDescendant:
5254  * @ctxt:  the XPath Parser context
5255  * @cur:  the current node in the traversal
5256  *
5257  * Traversal function for the "descendant" direction
5258  * the descendant axis contains the descendants of the context node in document
5259  * order; a descendant is a child or a child of a child and so on.
5260  *
5261  * Returns the next element following that axis
5262  */
5263 xmlNodePtr
5264 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5265     if (cur == NULL) {
5266         if (ctxt->context->node == NULL)
5267             return(NULL);
5268         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5269             (ctxt->context->node->type == XML_NAMESPACE_DECL))
5270             return(NULL);
5271
5272         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5273             return(ctxt->context->doc->children);
5274         return(ctxt->context->node->children);
5275     }
5276
5277     if (cur->children != NULL) {
5278         /*
5279          * Do not descend on entities declarations
5280          */
5281         if (cur->children->type != XML_ENTITY_DECL) {
5282             cur = cur->children;
5283             /*
5284              * Skip DTDs
5285              */
5286             if (cur->type != XML_DTD_NODE)
5287                 return(cur);
5288         }
5289     }
5290
5291     if (cur == ctxt->context->node) return(NULL);
5292
5293     while (cur->next != NULL) {
5294         cur = cur->next;
5295         if ((cur->type != XML_ENTITY_DECL) &&
5296             (cur->type != XML_DTD_NODE))
5297             return(cur);
5298     }
5299     
5300     do {
5301         cur = cur->parent;
5302         if (cur == NULL) return(NULL);
5303         if (cur == ctxt->context->node) return(NULL);
5304         if (cur->next != NULL) {
5305             cur = cur->next;
5306             return(cur);
5307         }
5308     } while (cur != NULL);
5309     return(cur);
5310 }
5311
5312 /**
5313  * xmlXPathNextDescendantOrSelf:
5314  * @ctxt:  the XPath Parser context
5315  * @cur:  the current node in the traversal
5316  *
5317  * Traversal function for the "descendant-or-self" direction
5318  * the descendant-or-self axis contains the context node and the descendants
5319  * of the context node in document order; thus the context node is the first
5320  * node on the axis, and the first child of the context node is the second node
5321  * on the axis
5322  *
5323  * Returns the next element following that axis
5324  */
5325 xmlNodePtr
5326 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5327     if (cur == NULL) {
5328         if (ctxt->context->node == NULL)
5329             return(NULL);
5330         if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5331             (ctxt->context->node->type == XML_NAMESPACE_DECL))
5332             return(NULL);
5333         return(ctxt->context->node);
5334     }
5335
5336     return(xmlXPathNextDescendant(ctxt, cur));
5337 }
5338
5339 /**
5340  * xmlXPathNextParent:
5341  * @ctxt:  the XPath Parser context
5342  * @cur:  the current node in the traversal
5343  *
5344  * Traversal function for the "parent" direction
5345  * The parent axis contains the parent of the context node, if there is one.
5346  *
5347  * Returns the next element following that axis
5348  */
5349 xmlNodePtr
5350 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5351     /*
5352      * the parent of an attribute or namespace node is the element
5353      * to which the attribute or namespace node is attached
5354      * Namespace handling !!!
5355      */
5356     if (cur == NULL) {
5357         if (ctxt->context->node == NULL) return(NULL);
5358         switch (ctxt->context->node->type) {
5359             case XML_ELEMENT_NODE:
5360             case XML_TEXT_NODE:
5361             case XML_CDATA_SECTION_NODE:
5362             case XML_ENTITY_REF_NODE:
5363             case XML_ENTITY_NODE:
5364             case XML_PI_NODE:
5365             case XML_COMMENT_NODE:
5366             case XML_NOTATION_NODE:
5367             case XML_DTD_NODE:
5368             case XML_ELEMENT_DECL:
5369             case XML_ATTRIBUTE_DECL:
5370             case XML_XINCLUDE_START:
5371             case XML_XINCLUDE_END:
5372             case XML_ENTITY_DECL:
5373                 if (ctxt->context->node->parent == NULL)
5374                     return((xmlNodePtr) ctxt->context->doc);
5375                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5376                     ((ctxt->context->node->parent->name[0] == ' ') ||
5377                      (xmlStrEqual(ctxt->context->node->parent->name,
5378                                  BAD_CAST "fake node libxslt"))))
5379                     return(NULL);
5380                 return(ctxt->context->node->parent);
5381             case XML_ATTRIBUTE_NODE: {
5382                 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5383
5384                 return(att->parent);
5385             }
5386             case XML_DOCUMENT_NODE:
5387             case XML_DOCUMENT_TYPE_NODE:
5388             case XML_DOCUMENT_FRAG_NODE:
5389             case XML_HTML_DOCUMENT_NODE:
5390 #ifdef LIBXML_DOCB_ENABLED
5391             case XML_DOCB_DOCUMENT_NODE:
5392 #endif
5393                 return(NULL);
5394             case XML_NAMESPACE_DECL: {
5395                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5396                 
5397                 if ((ns->next != NULL) &&
5398                     (ns->next->type != XML_NAMESPACE_DECL))
5399                     return((xmlNodePtr) ns->next);
5400                 return(NULL);
5401             }
5402         }
5403     }
5404     return(NULL);
5405 }
5406
5407 /**
5408  * xmlXPathNextAncestor:
5409  * @ctxt:  the XPath Parser context
5410  * @cur:  the current node in the traversal
5411  *
5412  * Traversal function for the "ancestor" direction
5413  * the ancestor axis contains the ancestors of the context node; the ancestors
5414  * of the context node consist of the parent of context node and the parent's
5415  * parent and so on; the nodes are ordered in reverse document order; thus the
5416  * parent is the first node on the axis, and the parent's parent is the second
5417  * node on the axis
5418  *
5419  * Returns the next element following that axis
5420  */
5421 xmlNodePtr
5422 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5423     /*
5424      * the parent of an attribute or namespace node is the element
5425      * to which the attribute or namespace node is attached
5426      * !!!!!!!!!!!!!
5427      */
5428     if (cur == NULL) {
5429         if (ctxt->context->node == NULL) return(NULL);
5430         switch (ctxt->context->node->type) {
5431             case XML_ELEMENT_NODE:
5432             case XML_TEXT_NODE:
5433             case XML_CDATA_SECTION_NODE:
5434             case XML_ENTITY_REF_NODE:
5435             case XML_ENTITY_NODE:
5436             case XML_PI_NODE:
5437             case XML_COMMENT_NODE:
5438             case XML_DTD_NODE:
5439             case XML_ELEMENT_DECL:
5440             case XML_ATTRIBUTE_DECL:
5441             case XML_ENTITY_DECL:
5442             case XML_NOTATION_NODE:
5443             case XML_XINCLUDE_START:
5444             case XML_XINCLUDE_END:
5445                 if (ctxt->context->node->parent == NULL)
5446                     return((xmlNodePtr) ctxt->context->doc);
5447                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5448                     ((ctxt->context->node->parent->name[0] == ' ') ||
5449                      (xmlStrEqual(ctxt->context->node->parent->name,
5450                                  BAD_CAST "fake node libxslt"))))
5451                     return(NULL);
5452                 return(ctxt->context->node->parent);
5453             case XML_ATTRIBUTE_NODE: {
5454                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
5455
5456                 return(tmp->parent);
5457             }
5458             case XML_DOCUMENT_NODE:
5459             case XML_DOCUMENT_TYPE_NODE:
5460             case XML_DOCUMENT_FRAG_NODE:
5461             case XML_HTML_DOCUMENT_NODE:
5462 #ifdef LIBXML_DOCB_ENABLED
5463             case XML_DOCB_DOCUMENT_NODE:
5464 #endif
5465                 return(NULL);
5466             case XML_NAMESPACE_DECL: {
5467                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5468                 
5469                 if ((ns->next != NULL) &&
5470                     (ns->next->type != XML_NAMESPACE_DECL))
5471                     return((xmlNodePtr) ns->next);
5472                 /* Bad, how did that namespace ended-up there ? */
5473                 return(NULL);
5474             }
5475         }
5476         return(NULL);
5477     }
5478     if (cur == ctxt->context->doc->children)
5479         return((xmlNodePtr) ctxt->context->doc);
5480     if (cur == (xmlNodePtr) ctxt->context->doc)
5481         return(NULL);
5482     switch (cur->type) {
5483         case XML_ELEMENT_NODE:
5484         case XML_TEXT_NODE:
5485         case XML_CDATA_SECTION_NODE:
5486         case XML_ENTITY_REF_NODE:
5487         case XML_ENTITY_NODE:
5488         case XML_PI_NODE:
5489         case XML_COMMENT_NODE:
5490         case XML_NOTATION_NODE:
5491         case XML_DTD_NODE:
5492         case XML_ELEMENT_DECL:
5493         case XML_ATTRIBUTE_DECL:
5494         case XML_ENTITY_DECL:
5495         case XML_XINCLUDE_START:
5496         case XML_XINCLUDE_END:
5497             if (cur->parent == NULL)
5498                 return(NULL);
5499             if ((cur->parent->type == XML_ELEMENT_NODE) &&
5500                 ((cur->parent->name[0] == ' ') ||
5501                  (xmlStrEqual(cur->parent->name,
5502                               BAD_CAST "fake node libxslt"))))
5503                 return(NULL);
5504             return(cur->parent);
5505         case XML_ATTRIBUTE_NODE: {
5506             xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5507
5508             return(att->parent);
5509         }
5510         case XML_NAMESPACE_DECL: {
5511             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5512                 
5513             if ((ns->next != NULL) &&
5514                 (ns->next->type != XML_NAMESPACE_DECL))
5515                 return((xmlNodePtr) ns->next);
5516             /* Bad, how did that namespace ended-up there ? */
5517             return(NULL);
5518         }
5519         case XML_DOCUMENT_NODE:
5520         case XML_DOCUMENT_TYPE_NODE:
5521         case XML_DOCUMENT_FRAG_NODE:
5522         case XML_HTML_DOCUMENT_NODE:
5523 #ifdef LIBXML_DOCB_ENABLED
5524         case XML_DOCB_DOCUMENT_NODE:
5525 #endif
5526             return(NULL);
5527     }
5528     return(NULL);
5529 }
5530
5531 /**
5532  * xmlXPathNextAncestorOrSelf:
5533  * @ctxt:  the XPath Parser context
5534  * @cur:  the current node in the traversal
5535  *
5536  * Traversal function for the "ancestor-or-self" direction
5537  * he ancestor-or-self axis contains the context node and ancestors of
5538  * the context node in reverse document order; thus the context node is
5539  * the first node on the axis, and the context node's parent the second;
5540  * parent here is defined the same as with the parent axis.
5541  *
5542  * Returns the next element following that axis
5543  */
5544 xmlNodePtr
5545 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5546     if (cur == NULL)
5547         return(ctxt->context->node);
5548     return(xmlXPathNextAncestor(ctxt, cur));
5549 }
5550
5551 /**
5552  * xmlXPathNextFollowingSibling:
5553  * @ctxt:  the XPath Parser context
5554  * @cur:  the current node in the traversal
5555  *
5556  * Traversal function for the "following-sibling" direction
5557  * The following-sibling axis contains the following siblings of the context
5558  * node in document order.
5559  *
5560  * Returns the next element following that axis
5561  */
5562 xmlNodePtr
5563 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5564     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5565         (ctxt->context->node->type == XML_NAMESPACE_DECL))
5566         return(NULL);
5567     if (cur == (xmlNodePtr) ctxt->context->doc)
5568         return(NULL);
5569     if (cur == NULL)
5570         return(ctxt->context->node->next);
5571     return(cur->next);
5572 }
5573
5574 /**
5575  * xmlXPathNextPrecedingSibling:
5576  * @ctxt:  the XPath Parser context
5577  * @cur:  the current node in the traversal
5578  *
5579  * Traversal function for the "preceding-sibling" direction
5580  * The preceding-sibling axis contains the preceding siblings of the context
5581  * node in reverse document order; the first preceding sibling is first on the
5582  * axis; the sibling preceding that node is the second on the axis and so on.
5583  *
5584  * Returns the next element following that axis
5585  */
5586 xmlNodePtr
5587 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5588     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5589         (ctxt->context->node->type == XML_NAMESPACE_DECL))
5590         return(NULL);
5591     if (cur == (xmlNodePtr) ctxt->context->doc)
5592         return(NULL);
5593     if (cur == NULL)
5594         return(ctxt->context->node->prev);
5595     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5596         cur = cur->prev;
5597         if (cur == NULL)
5598             return(ctxt->context->node->prev);
5599     }
5600     return(cur->prev);
5601 }
5602
5603 /**
5604  * xmlXPathNextFollowing:
5605  * @ctxt:  the XPath Parser context
5606  * @cur:  the current node in the traversal
5607  *
5608  * Traversal function for the "following" direction
5609  * The following axis contains all nodes in the same document as the context
5610  * node that are after the context node in document order, excluding any
5611  * descendants and excluding attribute nodes and namespace nodes; the nodes
5612  * are ordered in document order
5613  *
5614  * Returns the next element following that axis
5615  */
5616 xmlNodePtr
5617 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5618     if (cur != NULL && cur->children != NULL)
5619         return cur->children ;
5620     if (cur == NULL) cur = ctxt->context->node;
5621     if (cur == NULL) return(NULL) ; /* ERROR */
5622     if (cur->next != NULL) return(cur->next) ;
5623     do {
5624         cur = cur->parent;
5625         if (cur == NULL) return(NULL);
5626         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5627         if (cur->next != NULL) return(cur->next);
5628     } while (cur != NULL);
5629     return(cur);
5630 }
5631
5632 /*
5633  * xmlXPathIsAncestor:
5634  * @ancestor:  the ancestor node
5635  * @node:  the current node
5636  *
5637  * Check that @ancestor is a @node's ancestor
5638  *
5639  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5640  */
5641 static int
5642 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5643     if ((ancestor == NULL) || (node == NULL)) return(0);
5644     /* nodes need to be in the same document */
5645     if (ancestor->doc != node->doc) return(0);
5646     /* avoid searching if ancestor or node is the root node */
5647     if (ancestor == (xmlNodePtr) node->doc) return(1);
5648     if (node == (xmlNodePtr) ancestor->doc) return(0);
5649     while (node->parent != NULL) {
5650         if (node->parent == ancestor)
5651             return(1);
5652         node = node->parent;
5653     }
5654     return(0);
5655 }
5656
5657 /**
5658  * xmlXPathNextPreceding:
5659  * @ctxt:  the XPath Parser context
5660  * @cur:  the current node in the traversal
5661  *
5662  * Traversal function for the "preceding" direction
5663  * the preceding axis contains all nodes in the same document as the context
5664  * node that are before the context node in document order, excluding any
5665  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5666  * ordered in reverse document order
5667  *
5668  * Returns the next element following that axis
5669  */
5670 xmlNodePtr
5671 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5672 {
5673     if (cur == NULL)
5674         cur = ctxt->context->node;
5675     if (cur == NULL)
5676         return (NULL);
5677     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5678         cur = cur->prev;
5679     do {
5680         if (cur->prev != NULL) {
5681             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5682             return (cur);
5683         }
5684
5685         cur = cur->parent;
5686         if (cur == NULL)
5687             return (NULL);
5688         if (cur == ctxt->context->doc->children)
5689             return (NULL);
5690     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
5691     return (cur);
5692 }
5693
5694 /**
5695  * xmlXPathNextPrecedingInternal:
5696  * @ctxt:  the XPath Parser context
5697  * @cur:  the current node in the traversal
5698  *
5699  * Traversal function for the "preceding" direction
5700  * the preceding axis contains all nodes in the same document as the context
5701  * node that are before the context node in document order, excluding any
5702  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5703  * ordered in reverse document order
5704  * This is a faster implementation but internal only since it requires a 
5705  * state kept in the parser context: ctxt->ancestor.
5706  *
5707  * Returns the next element following that axis
5708  */
5709 static xmlNodePtr
5710 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5711                               xmlNodePtr cur)
5712 {
5713     if (cur == NULL) {
5714         cur = ctxt->context->node;
5715         if (cur == NULL)
5716             return (NULL);
5717         ctxt->ancestor = cur->parent;
5718     }
5719     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5720         cur = cur->prev;
5721     while (cur->prev == NULL) {
5722         cur = cur->parent;
5723         if (cur == NULL)
5724             return (NULL);
5725         if (cur == ctxt->context->doc->children)
5726             return (NULL);
5727         if (cur != ctxt->ancestor)
5728             return (cur);
5729         ctxt->ancestor = cur->parent;
5730     }
5731     cur = cur->prev;
5732     while (cur->last != NULL)
5733         cur = cur->last;
5734     return (cur);
5735 }
5736
5737 /**
5738  * xmlXPathNextNamespace:
5739  * @ctxt:  the XPath Parser context
5740  * @cur:  the current attribute in the traversal
5741  *
5742  * Traversal function for the "namespace" direction
5743  * the namespace axis contains the namespace nodes of the context node;
5744  * the order of nodes on this axis is implementation-defined; the axis will
5745  * be empty unless the context node is an element
5746  *
5747  * We keep the XML namespace node at the end of the list.
5748  *
5749  * Returns the next element following that axis
5750  */
5751 xmlNodePtr
5752 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5753     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
5754     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
5755         if (ctxt->context->tmpNsList != NULL)
5756             xmlFree(ctxt->context->tmpNsList);
5757         ctxt->context->tmpNsList = 
5758             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
5759         ctxt->context->tmpNsNr = 0;
5760         if (ctxt->context->tmpNsList != NULL) {
5761             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5762                 ctxt->context->tmpNsNr++;
5763             }
5764         }
5765         return((xmlNodePtr) xmlXPathXMLNamespace);
5766     }
5767     if (ctxt->context->tmpNsNr > 0) {
5768         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5769     } else {
5770         if (ctxt->context->tmpNsList != NULL)
5771             xmlFree(ctxt->context->tmpNsList);
5772         ctxt->context->tmpNsList = NULL;
5773         return(NULL);
5774     }
5775 }
5776
5777 /**
5778  * xmlXPathNextAttribute:
5779  * @ctxt:  the XPath Parser context
5780  * @cur:  the current attribute in the traversal
5781  *
5782  * Traversal function for the "attribute" direction
5783  * TODO: support DTD inherited default attributes
5784  *
5785  * Returns the next element following that axis
5786  */
5787 xmlNodePtr
5788 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5789     if (ctxt->context->node == NULL)
5790         return(NULL);
5791     if (ctxt->context->node->type != XML_ELEMENT_NODE)
5792         return(NULL);
5793     if (cur == NULL) {
5794         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5795             return(NULL);
5796         return((xmlNodePtr)ctxt->context->node->properties);
5797     }
5798     return((xmlNodePtr)cur->next);
5799 }
5800
5801 /************************************************************************
5802  *                                                                      *
5803  *              NodeTest Functions                                      *
5804  *                                                                      *
5805  ************************************************************************/
5806
5807 #define IS_FUNCTION                     200
5808
5809
5810 /************************************************************************
5811  *                                                                      *
5812  *              Implicit tree core function library                     *
5813  *                                                                      *
5814  ************************************************************************/
5815
5816 /**
5817  * xmlXPathRoot:
5818  * @ctxt:  the XPath Parser context
5819  *
5820  * Initialize the context to the root of the document
5821  */
5822 void
5823 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5824     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5825     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5826 }
5827
5828 /************************************************************************
5829  *                                                                      *
5830  *              The explicit core function library                      *
5831  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5832  *                                                                      *
5833  ************************************************************************/
5834
5835
5836 /**
5837  * xmlXPathLastFunction:
5838  * @ctxt:  the XPath Parser context
5839  * @nargs:  the number of arguments
5840  *
5841  * Implement the last() XPath function
5842  *    number last()
5843  * The last function returns the number of nodes in the context node list.
5844  */
5845 void
5846 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5847     CHECK_ARITY(0);
5848     if (ctxt->context->contextSize >= 0) {
5849         valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5850 #ifdef DEBUG_EXPR
5851         xmlGenericError(xmlGenericErrorContext,
5852                 "last() : %d\n", ctxt->context->contextSize);
5853 #endif
5854     } else {
5855         XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5856     }
5857 }
5858
5859 /**
5860  * xmlXPathPositionFunction:
5861  * @ctxt:  the XPath Parser context
5862  * @nargs:  the number of arguments
5863  *
5864  * Implement the position() XPath function
5865  *    number position()
5866  * The position function returns the position of the context node in the
5867  * context node list. The first position is 1, and so the last position
5868  * will be equal to last().
5869  */
5870 void
5871 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5872     CHECK_ARITY(0);
5873     if (ctxt->context->proximityPosition >= 0) {
5874         valuePush(ctxt,
5875               xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5876 #ifdef DEBUG_EXPR
5877         xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5878                 ctxt->context->proximityPosition);
5879 #endif
5880     } else {
5881         XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5882     }
5883 }
5884
5885 /**
5886  * xmlXPathCountFunction:
5887  * @ctxt:  the XPath Parser context
5888  * @nargs:  the number of arguments
5889  *
5890  * Implement the count() XPath function
5891  *    number count(node-set)
5892  */
5893 void
5894 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5895     xmlXPathObjectPtr cur;
5896
5897     CHECK_ARITY(1);
5898     if ((ctxt->value == NULL) || 
5899         ((ctxt->value->type != XPATH_NODESET) &&
5900          (ctxt->value->type != XPATH_XSLT_TREE)))
5901         XP_ERROR(XPATH_INVALID_TYPE);
5902     cur = valuePop(ctxt);
5903
5904     if ((cur == NULL) || (cur->nodesetval == NULL))
5905         valuePush(ctxt, xmlXPathNewFloat((double) 0));
5906     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
5907         valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
5908     } else {
5909         if ((cur->nodesetval->nodeNr != 1) ||
5910             (cur->nodesetval->nodeTab == NULL)) {
5911             valuePush(ctxt, xmlXPathNewFloat((double) 0));
5912         } else {
5913             xmlNodePtr tmp;
5914             int i = 0;
5915
5916             tmp = cur->nodesetval->nodeTab[0];
5917             if (tmp != NULL) {
5918                 tmp = tmp->children;
5919                 while (tmp != NULL) {
5920                     tmp = tmp->next;
5921                     i++;
5922                 }
5923             }
5924             valuePush(ctxt, xmlXPathNewFloat((double) i));
5925         }
5926     }
5927     xmlXPathFreeObject(cur);
5928 }
5929
5930 /**
5931  * xmlXPathGetElementsByIds:
5932  * @doc:  the document
5933  * @ids:  a whitespace separated list of IDs
5934  *
5935  * Selects elements by their unique ID.
5936  *
5937  * Returns a node-set of selected elements.
5938  */
5939 static xmlNodeSetPtr
5940 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5941     xmlNodeSetPtr ret;
5942     const xmlChar *cur = ids;
5943     xmlChar *ID;
5944     xmlAttrPtr attr;
5945     xmlNodePtr elem = NULL;
5946
5947     if (ids == NULL) return(NULL);
5948
5949     ret = xmlXPathNodeSetCreate(NULL);
5950
5951     while (IS_BLANK(*cur)) cur++;
5952     while (*cur != 0) {
5953         while ((!IS_BLANK(*cur)) && (*cur != 0))
5954             cur++;
5955
5956         ID = xmlStrndup(ids, cur - ids);
5957         if (ID != NULL) {
5958             if (xmlValidateNCName(ID, 1) == 0) {
5959                 attr = xmlGetID(doc, ID);
5960                 if (attr != NULL) {
5961                     if (attr->type == XML_ATTRIBUTE_NODE)
5962                         elem = attr->parent;
5963                     else if (attr->type == XML_ELEMENT_NODE)
5964                         elem = (xmlNodePtr) attr;
5965                     else
5966                         elem = NULL;
5967                     if (elem != NULL)
5968                         xmlXPathNodeSetAdd(ret, elem);
5969                 }
5970             }
5971             xmlFree(ID);
5972         }
5973
5974         while (IS_BLANK(*cur)) cur++;
5975         ids = cur;
5976     }
5977     return(ret);
5978 }
5979
5980 /**
5981  * xmlXPathIdFunction:
5982  * @ctxt:  the XPath Parser context
5983  * @nargs:  the number of arguments
5984  *
5985  * Implement the id() XPath function
5986  *    node-set id(object)
5987  * The id function selects elements by their unique ID
5988  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5989  * then the result is the union of the result of applying id to the
5990  * string value of each of the nodes in the argument node-set. When the
5991  * argument to id is of any other type, the argument is converted to a
5992  * string as if by a call to the string function; the string is split
5993  * into a whitespace-separated list of tokens (whitespace is any sequence
5994  * of characters matching the production S); the result is a node-set
5995  * containing the elements in the same document as the context node that
5996  * have a unique ID equal to any of the tokens in the list.
5997  */
5998 void
5999 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6000     xmlChar *tokens;
6001     xmlNodeSetPtr ret;
6002     xmlXPathObjectPtr obj;
6003
6004     CHECK_ARITY(1);
6005     obj = valuePop(ctxt);
6006     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6007     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
6008         xmlNodeSetPtr ns;
6009         int i;
6010
6011         ret = xmlXPathNodeSetCreate(NULL);
6012
6013         if (obj->nodesetval != NULL) {
6014             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
6015                 tokens =
6016                     xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6017                 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6018                 ret = xmlXPathNodeSetMerge(ret, ns);
6019                 xmlXPathFreeNodeSet(ns);
6020                 if (tokens != NULL)
6021                     xmlFree(tokens);
6022             }
6023         }
6024
6025         xmlXPathFreeObject(obj);
6026         valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6027         return;
6028     }
6029     obj = xmlXPathConvertString(obj);
6030
6031     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6032     valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6033
6034     xmlXPathFreeObject(obj);
6035     return;
6036 }
6037
6038 /**
6039  * xmlXPathLocalNameFunction:
6040  * @ctxt:  the XPath Parser context
6041  * @nargs:  the number of arguments
6042  *
6043  * Implement the local-name() XPath function
6044  *    string local-name(node-set?)
6045  * The local-name function returns a string containing the local part
6046  * of the name of the node in the argument node-set that is first in
6047  * document order. If the node-set is empty or the first node has no
6048  * name, an empty string is returned. If the argument is omitted it
6049  * defaults to the context node.
6050  */
6051 void
6052 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6053     xmlXPathObjectPtr cur;
6054
6055     if (nargs == 0) {
6056         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6057         nargs = 1;
6058     }
6059
6060     CHECK_ARITY(1);
6061     if ((ctxt->value == NULL) || 
6062         ((ctxt->value->type != XPATH_NODESET) &&
6063          (ctxt->value->type != XPATH_XSLT_TREE)))
6064         XP_ERROR(XPATH_INVALID_TYPE);
6065     cur = valuePop(ctxt);
6066
6067     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6068         valuePush(ctxt, xmlXPathNewCString(""));
6069     } else {
6070         int i = 0; /* Should be first in document order !!!!! */
6071         switch (cur->nodesetval->nodeTab[i]->type) {
6072         case XML_ELEMENT_NODE:
6073         case XML_ATTRIBUTE_NODE:
6074         case XML_PI_NODE:
6075             if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6076                 valuePush(ctxt, xmlXPathNewCString(""));
6077             else
6078                 valuePush(ctxt,
6079                       xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6080             break;
6081         case XML_NAMESPACE_DECL:
6082             valuePush(ctxt, xmlXPathNewString(
6083                         ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6084             break;
6085         default:
6086             valuePush(ctxt, xmlXPathNewCString(""));
6087         }
6088     }
6089     xmlXPathFreeObject(cur);
6090 }
6091
6092 /**
6093  * xmlXPathNamespaceURIFunction:
6094  * @ctxt:  the XPath Parser context
6095  * @nargs:  the number of arguments
6096  *
6097  * Implement the namespace-uri() XPath function
6098  *    string namespace-uri(node-set?)
6099  * The namespace-uri function returns a string containing the
6100  * namespace URI of the expanded name of the node in the argument
6101  * node-set that is first in document order. If the node-set is empty,
6102  * the first node has no name, or the expanded name has no namespace
6103  * URI, an empty string is returned. If the argument is omitted it
6104  * defaults to the context node.
6105  */
6106 void
6107 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6108     xmlXPathObjectPtr cur;
6109
6110     if (nargs == 0) {
6111         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6112         nargs = 1;
6113     }
6114     CHECK_ARITY(1);
6115     if ((ctxt->value == NULL) || 
6116         ((ctxt->value->type != XPATH_NODESET) &&
6117          (ctxt->value->type != XPATH_XSLT_TREE)))
6118         XP_ERROR(XPATH_INVALID_TYPE);
6119     cur = valuePop(ctxt);
6120
6121     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6122         valuePush(ctxt, xmlXPathNewCString(""));
6123     } else {
6124         int i = 0; /* Should be first in document order !!!!! */
6125         switch (cur->nodesetval->nodeTab[i]->type) {
6126         case XML_ELEMENT_NODE:
6127         case XML_ATTRIBUTE_NODE:
6128             if (cur->nodesetval->nodeTab[i]->ns == NULL)
6129                 valuePush(ctxt, xmlXPathNewCString(""));
6130             else
6131                 valuePush(ctxt, xmlXPathNewString(
6132                           cur->nodesetval->nodeTab[i]->ns->href));
6133             break;
6134         default:
6135             valuePush(ctxt, xmlXPathNewCString(""));
6136         }
6137     }
6138     xmlXPathFreeObject(cur);
6139 }
6140
6141 /**
6142  * xmlXPathNameFunction:
6143  * @ctxt:  the XPath Parser context
6144  * @nargs:  the number of arguments
6145  *
6146  * Implement the name() XPath function
6147  *    string name(node-set?)
6148  * The name function returns a string containing a QName representing
6149  * the name of the node in the argument node-set that is first in document
6150  * order. The QName must represent the name with respect to the namespace
6151  * declarations in effect on the node whose name is being represented.
6152  * Typically, this will be the form in which the name occurred in the XML
6153  * source. This need not be the case if there are namespace declarations
6154  * in effect on the node that associate multiple prefixes with the same
6155  * namespace. However, an implementation may include information about
6156  * the original prefix in its representation of nodes; in this case, an
6157  * implementation can ensure that the returned string is always the same
6158  * as the QName used in the XML source. If the argument it omitted it
6159  * defaults to the context node.
6160  * Libxml keep the original prefix so the "real qualified name" used is
6161  * returned.
6162  */
6163 static void
6164 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6165 {
6166     xmlXPathObjectPtr cur;
6167
6168     if (nargs == 0) {
6169         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6170         nargs = 1;
6171     }
6172
6173     CHECK_ARITY(1);
6174     if ((ctxt->value == NULL) ||
6175         ((ctxt->value->type != XPATH_NODESET) &&
6176          (ctxt->value->type != XPATH_XSLT_TREE)))
6177         XP_ERROR(XPATH_INVALID_TYPE);
6178     cur = valuePop(ctxt);
6179
6180     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6181         valuePush(ctxt, xmlXPathNewCString(""));
6182     } else {
6183         int i = 0;              /* Should be first in document order !!!!! */
6184
6185         switch (cur->nodesetval->nodeTab[i]->type) {
6186             case XML_ELEMENT_NODE:
6187             case XML_ATTRIBUTE_NODE:
6188                 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6189                     valuePush(ctxt, xmlXPathNewCString(""));
6190                 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6191                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
6192                     valuePush(ctxt,
6193                         xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6194
6195                 } else {
6196                     xmlChar *fullname;
6197                     
6198                     fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6199                                      cur->nodesetval->nodeTab[i]->ns->prefix,
6200                                      NULL, 0);
6201                     if (fullname == cur->nodesetval->nodeTab[i]->name)
6202                         fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6203                     if (fullname == NULL) {
6204                         XP_ERROR(XPATH_MEMORY_ERROR);
6205                     }
6206                     valuePush(ctxt, xmlXPathWrapString(fullname));
6207                 }
6208                 break;
6209             default:
6210                 valuePush(ctxt,
6211                           xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6212                 xmlXPathLocalNameFunction(ctxt, 1);
6213         }
6214     }
6215     xmlXPathFreeObject(cur);
6216 }
6217
6218
6219 /**
6220  * xmlXPathStringFunction:
6221  * @ctxt:  the XPath Parser context
6222  * @nargs:  the number of arguments
6223  *
6224  * Implement the string() XPath function
6225  *    string string(object?)
6226  * he string function converts an object to a string as follows:
6227  *    - A node-set is converted to a string by returning the value of
6228  *      the node in the node-set that is first in document order.
6229  *      If the node-set is empty, an empty string is returned.
6230  *    - A number is converted to a string as follows
6231  *      + NaN is converted to the string NaN 
6232  *      + positive zero is converted to the string 0 
6233  *      + negative zero is converted to the string 0 
6234  *      + positive infinity is converted to the string Infinity 
6235  *      + negative infinity is converted to the string -Infinity 
6236  *      + if the number is an integer, the number is represented in
6237  *        decimal form as a Number with no decimal point and no leading
6238  *        zeros, preceded by a minus sign (-) if the number is negative
6239  *      + otherwise, the number is represented in decimal form as a
6240  *        Number including a decimal point with at least one digit
6241  *        before the decimal point and at least one digit after the
6242  *        decimal point, preceded by a minus sign (-) if the number
6243  *        is negative; there must be no leading zeros before the decimal
6244  *        point apart possibly from the one required digit immediately
6245  *        before the decimal point; beyond the one required digit
6246  *        after the decimal point there must be as many, but only as
6247  *        many, more digits as are needed to uniquely distinguish the
6248  *        number from all other IEEE 754 numeric values.
6249  *    - The boolean false value is converted to the string false.
6250  *      The boolean true value is converted to the string true.
6251  *
6252  * If the argument is omitted, it defaults to a node-set with the
6253  * context node as its only member.
6254  */
6255 void
6256 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6257     xmlXPathObjectPtr cur;
6258
6259     if (nargs == 0) {
6260         valuePush(ctxt,
6261                   xmlXPathWrapString(
6262                         xmlXPathCastNodeToString(ctxt->context->node)));
6263         return;
6264     }
6265
6266     CHECK_ARITY(1);
6267     cur = valuePop(ctxt);
6268     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6269     cur = xmlXPathConvertString(cur);
6270     valuePush(ctxt, cur);
6271 }
6272
6273 /**
6274  * xmlXPathStringLengthFunction:
6275  * @ctxt:  the XPath Parser context
6276  * @nargs:  the number of arguments
6277  *
6278  * Implement the string-length() XPath function
6279  *    number string-length(string?)
6280  * The string-length returns the number of characters in the string
6281  * (see [3.6 Strings]). If the argument is omitted, it defaults to
6282  * the context node converted to a string, in other words the value
6283  * of the context node.
6284  */
6285 void
6286 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6287     xmlXPathObjectPtr cur;
6288
6289     if (nargs == 0) {
6290         if (ctxt->context->node == NULL) {
6291             valuePush(ctxt, xmlXPathNewFloat(0));
6292         } else {
6293             xmlChar *content;
6294
6295             content = xmlXPathCastNodeToString(ctxt->context->node);
6296             valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
6297             xmlFree(content);
6298         }
6299         return;
6300     }
6301     CHECK_ARITY(1);
6302     CAST_TO_STRING;
6303     CHECK_TYPE(XPATH_STRING);
6304     cur = valuePop(ctxt);
6305     valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
6306     xmlXPathFreeObject(cur);
6307 }
6308
6309 /**
6310  * xmlXPathConcatFunction:
6311  * @ctxt:  the XPath Parser context
6312  * @nargs:  the number of arguments
6313  *
6314  * Implement the concat() XPath function
6315  *    string concat(string, string, string*)
6316  * The concat function returns the concatenation of its arguments.
6317  */
6318 void
6319 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6320     xmlXPathObjectPtr cur, newobj;
6321     xmlChar *tmp;
6322
6323     if (nargs < 2) {
6324         CHECK_ARITY(2);
6325     }
6326
6327     CAST_TO_STRING;
6328     cur = valuePop(ctxt);
6329     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6330         xmlXPathFreeObject(cur);
6331         return;
6332     }
6333     nargs--;
6334
6335     while (nargs > 0) {
6336         CAST_TO_STRING;
6337         newobj = valuePop(ctxt);
6338         if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6339             xmlXPathFreeObject(newobj);
6340             xmlXPathFreeObject(cur);
6341             XP_ERROR(XPATH_INVALID_TYPE);
6342         }
6343         tmp = xmlStrcat(newobj->stringval, cur->stringval);
6344         newobj->stringval = cur->stringval;
6345         cur->stringval = tmp;
6346
6347         xmlXPathFreeObject(newobj);
6348         nargs--;
6349     }
6350     valuePush(ctxt, cur);
6351 }
6352
6353 /**
6354  * xmlXPathContainsFunction:
6355  * @ctxt:  the XPath Parser context
6356  * @nargs:  the number of arguments
6357  *
6358  * Implement the contains() XPath function
6359  *    boolean contains(string, string)
6360  * The contains function returns true if the first argument string
6361  * contains the second argument string, and otherwise returns false.
6362  */
6363 void
6364 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6365     xmlXPathObjectPtr hay, needle;
6366
6367     CHECK_ARITY(2);
6368     CAST_TO_STRING;
6369     CHECK_TYPE(XPATH_STRING);
6370     needle = valuePop(ctxt);
6371     CAST_TO_STRING;
6372     hay = valuePop(ctxt);
6373     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6374         xmlXPathFreeObject(hay);
6375         xmlXPathFreeObject(needle);
6376         XP_ERROR(XPATH_INVALID_TYPE);
6377     }
6378     if (xmlStrstr(hay->stringval, needle->stringval))
6379         valuePush(ctxt, xmlXPathNewBoolean(1));
6380     else
6381         valuePush(ctxt, xmlXPathNewBoolean(0));
6382     xmlXPathFreeObject(hay);
6383     xmlXPathFreeObject(needle);
6384 }
6385
6386 /**
6387  * xmlXPathStartsWithFunction:
6388  * @ctxt:  the XPath Parser context
6389  * @nargs:  the number of arguments
6390  *
6391  * Implement the starts-with() XPath function
6392  *    boolean starts-with(string, string)
6393  * The starts-with function returns true if the first argument string
6394  * starts with the second argument string, and otherwise returns false.
6395  */
6396 void
6397 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6398     xmlXPathObjectPtr hay, needle;
6399     int n;
6400
6401     CHECK_ARITY(2);
6402     CAST_TO_STRING;
6403     CHECK_TYPE(XPATH_STRING);
6404     needle = valuePop(ctxt);
6405     CAST_TO_STRING;
6406     hay = valuePop(ctxt);
6407     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6408         xmlXPathFreeObject(hay);
6409         xmlXPathFreeObject(needle);
6410         XP_ERROR(XPATH_INVALID_TYPE);
6411     }
6412     n = xmlStrlen(needle->stringval);
6413     if (xmlStrncmp(hay->stringval, needle->stringval, n))
6414         valuePush(ctxt, xmlXPathNewBoolean(0));
6415     else
6416         valuePush(ctxt, xmlXPathNewBoolean(1));
6417     xmlXPathFreeObject(hay);
6418     xmlXPathFreeObject(needle);
6419 }
6420
6421 /**
6422  * xmlXPathSubstringFunction:
6423  * @ctxt:  the XPath Parser context
6424  * @nargs:  the number of arguments
6425  *
6426  * Implement the substring() XPath function
6427  *    string substring(string, number, number?)
6428  * The substring function returns the substring of the first argument
6429  * starting at the position specified in the second argument with
6430  * length specified in the third argument. For example,
6431  * substring("12345",2,3) returns "234". If the third argument is not
6432  * specified, it returns the substring starting at the position specified
6433  * in the second argument and continuing to the end of the string. For
6434  * example, substring("12345",2) returns "2345".  More precisely, each
6435  * character in the string (see [3.6 Strings]) is considered to have a
6436  * numeric position: the position of the first character is 1, the position
6437  * of the second character is 2 and so on. The returned substring contains
6438  * those characters for which the position of the character is greater than
6439  * or equal to the second argument and, if the third argument is specified,
6440  * less than the sum of the second and third arguments; the comparisons
6441  * and addition used for the above follow the standard IEEE 754 rules. Thus:
6442  *  - substring("12345", 1.5, 2.6) returns "234" 
6443  *  - substring("12345", 0, 3) returns "12" 
6444  *  - substring("12345", 0 div 0, 3) returns "" 
6445  *  - substring("12345", 1, 0 div 0) returns "" 
6446  *  - substring("12345", -42, 1 div 0) returns "12345" 
6447  *  - substring("12345", -1 div 0, 1 div 0) returns "" 
6448  */
6449 void
6450 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6451     xmlXPathObjectPtr str, start, len;
6452     double le=0, in;
6453     int i, l, m;
6454     xmlChar *ret;
6455
6456     if (nargs < 2) {
6457         CHECK_ARITY(2);
6458     }
6459     if (nargs > 3) {
6460         CHECK_ARITY(3);
6461     }
6462     /*
6463      * take care of possible last (position) argument
6464     */
6465     if (nargs == 3) {
6466         CAST_TO_NUMBER;
6467         CHECK_TYPE(XPATH_NUMBER);
6468         len = valuePop(ctxt);
6469         le = len->floatval;
6470         xmlXPathFreeObject(len);
6471     }
6472
6473     CAST_TO_NUMBER;
6474     CHECK_TYPE(XPATH_NUMBER);
6475     start = valuePop(ctxt);
6476     in = start->floatval;
6477     xmlXPathFreeObject(start);
6478     CAST_TO_STRING;
6479     CHECK_TYPE(XPATH_STRING);
6480     str = valuePop(ctxt);
6481     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
6482
6483     /*
6484      * If last pos not present, calculate last position
6485     */
6486     if (nargs != 3) {
6487         le = (double)m;
6488         if (in < 1.0) 
6489             in = 1.0;
6490     }
6491
6492     /* Need to check for the special cases where either 
6493      * the index is NaN, the length is NaN, or both
6494      * arguments are infinity (relying on Inf + -Inf = NaN)
6495      */
6496     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
6497         /*
6498          * To meet the requirements of the spec, the arguments
6499          * must be converted to integer format before 
6500          * initial index calculations are done
6501          *
6502          * First we go to integer form, rounding up
6503          * and checking for special cases
6504          */
6505         i = (int) in;
6506         if (((double)i)+0.5 <= in) i++;
6507
6508         if (xmlXPathIsInf(le) == 1) {
6509             l = m;
6510             if (i < 1)
6511                 i = 1;
6512         }
6513         else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6514             l = 0;
6515         else {
6516             l = (int) le;
6517             if (((double)l)+0.5 <= le) l++;
6518         }
6519
6520         /* Now we normalize inidices */
6521         i -= 1;
6522         l += i;
6523         if (i < 0)
6524             i = 0;
6525         if (l > m)
6526             l = m;
6527
6528         /* number of chars to copy */
6529         l -= i;
6530
6531         ret = xmlUTF8Strsub(str->stringval, i, l);
6532     }
6533     else {
6534         ret = NULL;
6535     }
6536
6537     if (ret == NULL)
6538         valuePush(ctxt, xmlXPathNewCString(""));
6539     else {
6540         valuePush(ctxt, xmlXPathNewString(ret));
6541         xmlFree(ret);
6542     }
6543
6544     xmlXPathFreeObject(str);
6545 }
6546
6547 /**
6548  * xmlXPathSubstringBeforeFunction:
6549  * @ctxt:  the XPath Parser context
6550  * @nargs:  the number of arguments
6551  *
6552  * Implement the substring-before() XPath function
6553  *    string substring-before(string, string)
6554  * The substring-before function returns the substring of the first
6555  * argument string that precedes the first occurrence of the second
6556  * argument string in the first argument string, or the empty string
6557  * if the first argument string does not contain the second argument
6558  * string. For example, substring-before("1999/04/01","/") returns 1999.
6559  */
6560 void
6561 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562   xmlXPathObjectPtr str;
6563   xmlXPathObjectPtr find;
6564   xmlBufferPtr target;
6565   const xmlChar *point;
6566   int offset;
6567   
6568   CHECK_ARITY(2);
6569   CAST_TO_STRING;
6570   find = valuePop(ctxt);
6571   CAST_TO_STRING;
6572   str = valuePop(ctxt);
6573   
6574   target = xmlBufferCreate();
6575   if (target) {
6576     point = xmlStrstr(str->stringval, find->stringval);
6577     if (point) {
6578       offset = (int)(point - str->stringval);
6579       xmlBufferAdd(target, str->stringval, offset);
6580     }
6581     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6582     xmlBufferFree(target);
6583   }
6584   
6585   xmlXPathFreeObject(str);
6586   xmlXPathFreeObject(find);
6587 }
6588
6589 /**
6590  * xmlXPathSubstringAfterFunction:
6591  * @ctxt:  the XPath Parser context
6592  * @nargs:  the number of arguments
6593  *
6594  * Implement the substring-after() XPath function
6595  *    string substring-after(string, string)
6596  * The substring-after function returns the substring of the first
6597  * argument string that follows the first occurrence of the second
6598  * argument string in the first argument string, or the empty stringi
6599  * if the first argument string does not contain the second argument
6600  * string. For example, substring-after("1999/04/01","/") returns 04/01,
6601  * and substring-after("1999/04/01","19") returns 99/04/01.
6602  */
6603 void
6604 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6605   xmlXPathObjectPtr str;
6606   xmlXPathObjectPtr find;
6607   xmlBufferPtr target;
6608   const xmlChar *point;
6609   int offset;
6610   
6611   CHECK_ARITY(2);
6612   CAST_TO_STRING;
6613   find = valuePop(ctxt);
6614   CAST_TO_STRING;
6615   str = valuePop(ctxt);
6616   
6617   target = xmlBufferCreate();
6618   if (target) {
6619     point = xmlStrstr(str->stringval, find->stringval);
6620     if (point) {
6621       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6622       xmlBufferAdd(target, &str->stringval[offset],
6623                    xmlStrlen(str->stringval) - offset);
6624     }
6625     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6626     xmlBufferFree(target);
6627   }
6628   
6629   xmlXPathFreeObject(str);
6630   xmlXPathFreeObject(find);
6631 }
6632
6633 /**
6634  * xmlXPathNormalizeFunction:
6635  * @ctxt:  the XPath Parser context
6636  * @nargs:  the number of arguments
6637  *
6638  * Implement the normalize-space() XPath function
6639  *    string normalize-space(string?)
6640  * The normalize-space function returns the argument string with white
6641  * space normalized by stripping leading and trailing whitespace
6642  * and replacing sequences of whitespace characters by a single
6643  * space. Whitespace characters are the same allowed by the S production
6644  * in XML. If the argument is omitted, it defaults to the context
6645  * node converted to a string, in other words the value of the context node.
6646  */
6647 void
6648 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6649   xmlXPathObjectPtr obj = NULL;
6650   xmlChar *source = NULL;
6651   xmlBufferPtr target;
6652   xmlChar blank;
6653   
6654   if (nargs == 0) {
6655     /* Use current context node */
6656     valuePush(ctxt,
6657               xmlXPathWrapString(
6658                   xmlXPathCastNodeToString(ctxt->context->node)));
6659     nargs = 1;
6660   }
6661
6662   CHECK_ARITY(1);
6663   CAST_TO_STRING;
6664   CHECK_TYPE(XPATH_STRING);
6665   obj = valuePop(ctxt);
6666   source = obj->stringval;
6667
6668   target = xmlBufferCreate();
6669   if (target && source) {
6670     
6671     /* Skip leading whitespaces */
6672     while (IS_BLANK(*source))
6673       source++;
6674   
6675     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6676     blank = 0;
6677     while (*source) {
6678       if (IS_BLANK(*source)) {
6679         blank = 0x20;
6680       } else {
6681         if (blank) {
6682           xmlBufferAdd(target, &blank, 1);
6683           blank = 0;
6684         }
6685         xmlBufferAdd(target, source, 1);
6686       }
6687       source++;
6688     }
6689   
6690     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6691     xmlBufferFree(target);
6692   }
6693   xmlXPathFreeObject(obj);
6694 }
6695
6696 /**
6697  * xmlXPathTranslateFunction:
6698  * @ctxt:  the XPath Parser context
6699  * @nargs:  the number of arguments
6700  *
6701  * Implement the translate() XPath function
6702  *    string translate(string, string, string)
6703  * The translate function returns the first argument string with
6704  * occurrences of characters in the second argument string replaced
6705  * by the character at the corresponding position in the third argument
6706  * string. For example, translate("bar","abc","ABC") returns the string
6707  * BAr. If there is a character in the second argument string with no
6708  * character at a corresponding position in the third argument string
6709  * (because the second argument string is longer than the third argument
6710  * string), then occurrences of that character in the first argument
6711  * string are removed. For example, translate("--aaa--","abc-","ABC")
6712  * returns "AAA". If a character occurs more than once in second
6713  * argument string, then the first occurrence determines the replacement
6714  * character. If the third argument string is longer than the second
6715  * argument string, then excess characters are ignored.
6716  */
6717 void
6718 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6719     xmlXPathObjectPtr str;
6720     xmlXPathObjectPtr from;
6721     xmlXPathObjectPtr to;
6722     xmlBufferPtr target;
6723     int offset, max;
6724     xmlChar ch;
6725     xmlChar *point;
6726     xmlChar *cptr;
6727
6728     CHECK_ARITY(3);
6729
6730     CAST_TO_STRING;
6731     to = valuePop(ctxt);
6732     CAST_TO_STRING;
6733     from = valuePop(ctxt);
6734     CAST_TO_STRING;
6735     str = valuePop(ctxt);
6736
6737     target = xmlBufferCreate();
6738     if (target) {
6739         max = xmlUTF8Strlen(to->stringval);
6740         for (cptr = str->stringval; (ch=*cptr); ) {
6741             offset = xmlUTF8Strloc(from->stringval, cptr);
6742             if (offset >= 0) {
6743                 if (offset < max) {
6744                     point = xmlUTF8Strpos(to->stringval, offset);
6745                     if (point)
6746                         xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6747                 }
6748             } else
6749                 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6750
6751             /* Step to next character in input */
6752             cptr++;
6753             if ( ch & 0x80 ) {
6754                 /* if not simple ascii, verify proper format */
6755                 if ( (ch & 0xc0) != 0xc0 ) {
6756                     xmlGenericError(xmlGenericErrorContext,
6757                         "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6758                     break;
6759                 }
6760                 /* then skip over remaining bytes for this char */
6761                 while ( (ch <<= 1) & 0x80 )
6762                     if ( (*cptr++ & 0xc0) != 0x80 ) {
6763                         xmlGenericError(xmlGenericErrorContext,
6764                             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6765                         break;
6766                     }
6767                 if (ch & 0x80) /* must have had error encountered */
6768                     break;
6769             }
6770         }
6771     }
6772     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6773     xmlBufferFree(target);
6774     xmlXPathFreeObject(str);
6775     xmlXPathFreeObject(from);
6776     xmlXPathFreeObject(to);
6777 }
6778
6779 /**
6780  * xmlXPathBooleanFunction:
6781  * @ctxt:  the XPath Parser context
6782  * @nargs:  the number of arguments
6783  *
6784  * Implement the boolean() XPath function
6785  *    boolean boolean(object)
6786  * he boolean function converts its argument to a boolean as follows:
6787  *    - a number is true if and only if it is neither positive or
6788  *      negative zero nor NaN
6789  *    - a node-set is true if and only if it is non-empty
6790  *    - a string is true if and only if its length is non-zero
6791  */
6792 void
6793 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6794     xmlXPathObjectPtr cur;
6795
6796     CHECK_ARITY(1);
6797     cur = valuePop(ctxt);
6798     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6799     cur = xmlXPathConvertBoolean(cur);
6800     valuePush(ctxt, cur);
6801 }
6802
6803 /**
6804  * xmlXPathNotFunction:
6805  * @ctxt:  the XPath Parser context
6806  * @nargs:  the number of arguments
6807  *
6808  * Implement the not() XPath function
6809  *    boolean not(boolean)
6810  * The not function returns true if its argument is false,
6811  * and false otherwise.
6812  */
6813 void
6814 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6815     CHECK_ARITY(1);
6816     CAST_TO_BOOLEAN;
6817     CHECK_TYPE(XPATH_BOOLEAN);
6818     ctxt->value->boolval = ! ctxt->value->boolval;
6819 }
6820
6821 /**
6822  * xmlXPathTrueFunction:
6823  * @ctxt:  the XPath Parser context
6824  * @nargs:  the number of arguments
6825  *
6826  * Implement the true() XPath function
6827  *    boolean true()
6828  */
6829 void
6830 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6831     CHECK_ARITY(0);
6832     valuePush(ctxt, xmlXPathNewBoolean(1));
6833 }
6834
6835 /**
6836  * xmlXPathFalseFunction:
6837  * @ctxt:  the XPath Parser context
6838  * @nargs:  the number of arguments
6839  *
6840  * Implement the false() XPath function
6841  *    boolean false()
6842  */
6843 void
6844 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6845     CHECK_ARITY(0);
6846     valuePush(ctxt, xmlXPathNewBoolean(0));
6847 }
6848
6849 /**
6850  * xmlXPathLangFunction:
6851  * @ctxt:  the XPath Parser context
6852  * @nargs:  the number of arguments
6853  *
6854  * Implement the lang() XPath function
6855  *    boolean lang(string)
6856  * The lang function returns true or false depending on whether the
6857  * language of the context node as specified by xml:lang attributes
6858  * is the same as or is a sublanguage of the language specified by
6859  * the argument string. The language of the context node is determined
6860  * by the value of the xml:lang attribute on the context node, or, if
6861  * the context node has no xml:lang attribute, by the value of the
6862  * xml:lang attribute on the nearest ancestor of the context node that
6863  * has an xml:lang attribute. If there is no such attribute, then lang
6864  * returns false. If there is such an attribute, then lang returns
6865  * true if the attribute value is equal to the argument ignoring case,
6866  * or if there is some suffix starting with - such that the attribute
6867  * value is equal to the argument ignoring that suffix of the attribute
6868  * value and ignoring case.
6869  */
6870 void
6871 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6872     xmlXPathObjectPtr val;
6873     const xmlChar *theLang;
6874     const xmlChar *lang;
6875     int ret = 0;
6876     int i;
6877
6878     CHECK_ARITY(1);
6879     CAST_TO_STRING;
6880     CHECK_TYPE(XPATH_STRING);
6881     val = valuePop(ctxt);
6882     lang = val->stringval;
6883     theLang = xmlNodeGetLang(ctxt->context->node);
6884     if ((theLang != NULL) && (lang != NULL)) {
6885         for (i = 0;lang[i] != 0;i++)
6886             if (toupper(lang[i]) != toupper(theLang[i]))
6887                 goto not_equal;
6888         ret = 1;
6889     }
6890 not_equal:
6891     xmlXPathFreeObject(val);
6892     valuePush(ctxt, xmlXPathNewBoolean(ret));
6893 }
6894
6895 /**
6896  * xmlXPathNumberFunction:
6897  * @ctxt:  the XPath Parser context
6898  * @nargs:  the number of arguments
6899  *
6900  * Implement the number() XPath function
6901  *    number number(object?)
6902  */
6903 void
6904 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6905     xmlXPathObjectPtr cur;
6906     double res;
6907
6908     if (nargs == 0) {
6909         if (ctxt->context->node == NULL) {
6910             valuePush(ctxt, xmlXPathNewFloat(0.0));
6911         } else {
6912             xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6913
6914             res = xmlXPathStringEvalNumber(content);
6915             valuePush(ctxt, xmlXPathNewFloat(res));
6916             xmlFree(content);
6917         }
6918         return;
6919     }
6920
6921     CHECK_ARITY(1);
6922     cur = valuePop(ctxt);
6923     cur = xmlXPathConvertNumber(cur);
6924     valuePush(ctxt, cur);
6925 }
6926
6927 /**
6928  * xmlXPathSumFunction:
6929  * @ctxt:  the XPath Parser context
6930  * @nargs:  the number of arguments
6931  *
6932  * Implement the sum() XPath function
6933  *    number sum(node-set)
6934  * The sum function returns the sum of the values of the nodes in
6935  * the argument node-set.
6936  */
6937 void
6938 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6939     xmlXPathObjectPtr cur;
6940     int i;
6941     double res = 0.0;
6942
6943     CHECK_ARITY(1);
6944     if ((ctxt->value == NULL) || 
6945         ((ctxt->value->type != XPATH_NODESET) &&
6946          (ctxt->value->type != XPATH_XSLT_TREE)))
6947         XP_ERROR(XPATH_INVALID_TYPE);
6948     cur = valuePop(ctxt);
6949
6950     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6951         valuePush(ctxt, xmlXPathNewFloat(0.0));
6952     } else {
6953         for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6954             res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
6955         }
6956         valuePush(ctxt, xmlXPathNewFloat(res));
6957     }
6958     xmlXPathFreeObject(cur);
6959 }
6960
6961 /**
6962  * xmlXPathFloorFunction:
6963  * @ctxt:  the XPath Parser context
6964  * @nargs:  the number of arguments
6965  *
6966  * Implement the floor() XPath function
6967  *    number floor(number)
6968  * The floor function returns the largest (closest to positive infinity)
6969  * number that is not greater than the argument and that is an integer.
6970  */
6971 void
6972 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6973     double f;
6974
6975     CHECK_ARITY(1);
6976     CAST_TO_NUMBER;
6977     CHECK_TYPE(XPATH_NUMBER);
6978
6979     f = (double)((int) ctxt->value->floatval);
6980     if (f != ctxt->value->floatval) {
6981         if (ctxt->value->floatval > 0)
6982             ctxt->value->floatval = f;
6983         else
6984             ctxt->value->floatval = f - 1;
6985     }
6986 }
6987
6988 /**
6989  * xmlXPathCeilingFunction:
6990  * @ctxt:  the XPath Parser context
6991  * @nargs:  the number of arguments
6992  *
6993  * Implement the ceiling() XPath function
6994  *    number ceiling(number)
6995  * The ceiling function returns the smallest (closest to negative infinity)
6996  * number that is not less than the argument and that is an integer.
6997  */
6998 void
6999 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7000     double f;
7001
7002     CHECK_ARITY(1);
7003     CAST_TO_NUMBER;
7004     CHECK_TYPE(XPATH_NUMBER);
7005
7006 #if 0
7007     ctxt->value->floatval = ceil(ctxt->value->floatval);
7008 #else
7009     f = (double)((int) ctxt->value->floatval);
7010     if (f != ctxt->value->floatval) {
7011         if (ctxt->value->floatval > 0)
7012             ctxt->value->floatval = f + 1;
7013         else {
7014             if (ctxt->value->floatval < 0 && f == 0)
7015                 ctxt->value->floatval = xmlXPathNZERO;
7016             else
7017                 ctxt->value->floatval = f;
7018         }
7019
7020     }
7021 #endif
7022 }
7023
7024 /**
7025  * xmlXPathRoundFunction:
7026  * @ctxt:  the XPath Parser context
7027  * @nargs:  the number of arguments
7028  *
7029  * Implement the round() XPath function
7030  *    number round(number)
7031  * The round function returns the number that is closest to the
7032  * argument and that is an integer. If there are two such numbers,
7033  * then the one that is even is returned.
7034  */
7035 void
7036 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7037     double f;
7038
7039     CHECK_ARITY(1);
7040     CAST_TO_NUMBER;
7041     CHECK_TYPE(XPATH_NUMBER);
7042
7043     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7044         (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7045         (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
7046         (ctxt->value->floatval == 0.0))
7047         return;
7048
7049     f = (double)((int) ctxt->value->floatval);
7050     if (ctxt->value->floatval < 0) {
7051         if (ctxt->value->floatval < f - 0.5)
7052             ctxt->value->floatval = f - 1;
7053         else 
7054             ctxt->value->floatval = f;
7055         if (ctxt->value->floatval == 0)
7056             ctxt->value->floatval = xmlXPathNZERO;
7057     } else {
7058         if (ctxt->value->floatval < f + 0.5)
7059             ctxt->value->floatval = f;
7060         else 
7061             ctxt->value->floatval = f + 1;
7062     }
7063 }
7064
7065 /************************************************************************
7066  *                                                                      *
7067  *                      The Parser                                      *
7068  *                                                                      *
7069  ************************************************************************/
7070
7071 /*
7072  * a couple of forward declarations since we use a recursive call based
7073  * implementation.
7074  */
7075 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
7076 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
7077 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
7078 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
7079 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7080                                           int qualified);
7081
7082 /**
7083  * xmlXPathCurrentChar:
7084  * @ctxt:  the XPath parser context
7085  * @cur:  pointer to the beginning of the char
7086  * @len:  pointer to the length of the char read
7087  *
7088  * The current char value, if using UTF-8 this may actually span multiple
7089  * bytes in the input buffer.
7090  *
7091  * Returns the current char value and its length
7092  */
7093
7094 static int
7095 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7096     unsigned char c;
7097     unsigned int val;
7098     const xmlChar *cur;
7099
7100     if (ctxt == NULL)
7101         return(0);
7102     cur = ctxt->cur;
7103
7104     /*
7105      * We are supposed to handle UTF8, check it's valid
7106      * From rfc2044: encoding of the Unicode values on UTF-8:
7107      *
7108      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
7109      * 0000 0000-0000 007F   0xxxxxxx
7110      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
7111      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
7112      *
7113      * Check for the 0x110000 limit too
7114      */
7115     c = *cur;
7116     if (c & 0x80) {
7117         if ((cur[1] & 0xc0) != 0x80)
7118             goto encoding_error;
7119         if ((c & 0xe0) == 0xe0) {
7120
7121             if ((cur[2] & 0xc0) != 0x80)
7122                 goto encoding_error;
7123             if ((c & 0xf0) == 0xf0) {
7124                 if (((c & 0xf8) != 0xf0) ||
7125                     ((cur[3] & 0xc0) != 0x80))
7126                     goto encoding_error;
7127                 /* 4-byte code */
7128                 *len = 4;
7129                 val = (cur[0] & 0x7) << 18;
7130                 val |= (cur[1] & 0x3f) << 12;
7131                 val |= (cur[2] & 0x3f) << 6;
7132                 val |= cur[3] & 0x3f;
7133             } else {
7134               /* 3-byte code */
7135                 *len = 3;
7136                 val = (cur[0] & 0xf) << 12;
7137                 val |= (cur[1] & 0x3f) << 6;
7138                 val |= cur[2] & 0x3f;
7139             }
7140         } else {
7141           /* 2-byte code */
7142             *len = 2;
7143             val = (cur[0] & 0x1f) << 6;
7144             val |= cur[1] & 0x3f;
7145         }
7146         if (!IS_CHAR(val)) {
7147             XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7148         }    
7149         return(val);
7150     } else {
7151         /* 1-byte code */
7152         *len = 1;
7153         return((int) *cur);
7154     }
7155 encoding_error:
7156     /*
7157      * If we detect an UTF8 error that probably mean that the
7158      * input encoding didn't get properly advertized in the
7159      * declaration header. Report the error and switch the encoding
7160      * to ISO-Latin-1 (if you don't like this policy, just declare the
7161      * encoding !)
7162      */
7163     *len = 0;
7164     XP_ERROR0(XPATH_ENCODING_ERROR);
7165 }
7166
7167 /**
7168  * xmlXPathParseNCName:
7169  * @ctxt:  the XPath Parser context
7170  *
7171  * parse an XML namespace non qualified name.
7172  *
7173  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7174  *
7175  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7176  *                       CombiningChar | Extender
7177  *
7178  * Returns the namespace name or NULL
7179  */
7180
7181 xmlChar *
7182 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
7183     const xmlChar *in;
7184     xmlChar *ret;
7185     int count = 0;
7186
7187     /*
7188      * Accelerator for simple ASCII names
7189      */
7190     in = ctxt->cur;
7191     if (((*in >= 0x61) && (*in <= 0x7A)) ||
7192         ((*in >= 0x41) && (*in <= 0x5A)) ||
7193         (*in == '_')) {
7194         in++;
7195         while (((*in >= 0x61) && (*in <= 0x7A)) ||
7196                ((*in >= 0x41) && (*in <= 0x5A)) ||
7197                ((*in >= 0x30) && (*in <= 0x39)) ||
7198                (*in == '_') || (*in == '.') ||
7199                (*in == '-'))
7200             in++;
7201         if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7202             (*in == '[') || (*in == ']') || (*in == ':') ||
7203             (*in == '@') || (*in == '*')) {
7204             count = in - ctxt->cur;
7205             if (count == 0)
7206                 return(NULL);
7207             ret = xmlStrndup(ctxt->cur, count);
7208             ctxt->cur = in;
7209             return(ret);
7210         }
7211     }
7212     return(xmlXPathParseNameComplex(ctxt, 0));
7213 }
7214
7215
7216 /**
7217  * xmlXPathParseQName:
7218  * @ctxt:  the XPath Parser context
7219  * @prefix:  a xmlChar ** 
7220  *
7221  * parse an XML qualified name
7222  *
7223  * [NS 5] QName ::= (Prefix ':')? LocalPart
7224  *
7225  * [NS 6] Prefix ::= NCName
7226  *
7227  * [NS 7] LocalPart ::= NCName
7228  *
7229  * Returns the function returns the local part, and prefix is updated
7230  *   to get the Prefix if any.
7231  */
7232
7233 static xmlChar *
7234 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7235     xmlChar *ret = NULL;
7236
7237     *prefix = NULL;
7238     ret = xmlXPathParseNCName(ctxt);
7239     if (CUR == ':') {
7240         *prefix = ret;
7241         NEXT;
7242         ret = xmlXPathParseNCName(ctxt);
7243     }
7244     return(ret);
7245 }
7246
7247 /**
7248  * xmlXPathParseName:
7249  * @ctxt:  the XPath Parser context
7250  *
7251  * parse an XML name
7252  *
7253  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7254  *                  CombiningChar | Extender
7255  *
7256  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7257  *
7258  * Returns the namespace name or NULL
7259  */
7260
7261 xmlChar *
7262 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
7263     const xmlChar *in;
7264     xmlChar *ret;
7265     int count = 0;
7266
7267     /*
7268      * Accelerator for simple ASCII names
7269      */
7270     in = ctxt->cur;
7271     if (((*in >= 0x61) && (*in <= 0x7A)) ||
7272         ((*in >= 0x41) && (*in <= 0x5A)) ||
7273         (*in == '_') || (*in == ':')) {
7274         in++;
7275         while (((*in >= 0x61) && (*in <= 0x7A)) ||
7276                ((*in >= 0x41) && (*in <= 0x5A)) ||
7277                ((*in >= 0x30) && (*in <= 0x39)) ||
7278                (*in == '_') || (*in == '-') ||
7279                (*in == ':') || (*in == '.'))
7280             in++;
7281         if ((*in > 0) && (*in < 0x80)) {
7282             count = in - ctxt->cur;
7283             ret = xmlStrndup(ctxt->cur, count);
7284             ctxt->cur = in;
7285             return(ret);
7286         }
7287     }
7288     return(xmlXPathParseNameComplex(ctxt, 1));
7289 }
7290
7291 static xmlChar *
7292 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
7293     xmlChar buf[XML_MAX_NAMELEN + 5];
7294     int len = 0, l;
7295     int c;
7296
7297     /*
7298      * Handler for more complex cases
7299      */
7300     c = CUR_CHAR(l);
7301     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
7302         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7303         (c == '*') || /* accelerators */
7304         (!IS_LETTER(c) && (c != '_') &&
7305          ((qualified) && (c != ':')))) {
7306         return(NULL);
7307     }
7308
7309     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7310            ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7311             (c == '.') || (c == '-') ||
7312             (c == '_') || ((qualified) && (c == ':')) || 
7313             (IS_COMBINING(c)) ||
7314             (IS_EXTENDER(c)))) {
7315         COPY_BUF(l,buf,len,c);
7316         NEXTL(l);
7317         c = CUR_CHAR(l);
7318         if (len >= XML_MAX_NAMELEN) {
7319             /*
7320              * Okay someone managed to make a huge name, so he's ready to pay
7321              * for the processing speed.
7322              */
7323             xmlChar *buffer;
7324             int max = len * 2;
7325             
7326             buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
7327             if (buffer == NULL) {
7328                 XP_ERROR0(XPATH_MEMORY_ERROR);
7329             }
7330             memcpy(buffer, buf, len);
7331             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7332                    (c == '.') || (c == '-') ||
7333                    (c == '_') || ((qualified) && (c == ':')) || 
7334                    (IS_COMBINING(c)) ||
7335                    (IS_EXTENDER(c))) {
7336                 if (len + 10 > max) {
7337                     max *= 2;
7338                     buffer = (xmlChar *) xmlRealloc(buffer,
7339                                                     max * sizeof(xmlChar));
7340                     if (buffer == NULL) {
7341                         XP_ERROR0(XPATH_MEMORY_ERROR);
7342                     }
7343                 }
7344                 COPY_BUF(l,buffer,len,c);
7345                 NEXTL(l);
7346                 c = CUR_CHAR(l);
7347             }
7348             buffer[len] = 0;
7349             return(buffer);
7350         }
7351     }
7352     if (len == 0)
7353         return(NULL);
7354     return(xmlStrndup(buf, len));
7355 }
7356
7357 #define MAX_FRAC 20
7358
7359 static double my_pow10[MAX_FRAC] = {
7360     1.0, 10.0, 100.0, 1000.0, 10000.0,
7361     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7362     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7363     100000000000000.0,
7364     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7365     1000000000000000000.0, 10000000000000000000.0
7366 };
7367
7368 /**
7369  * xmlXPathStringEvalNumber:
7370  * @str:  A string to scan
7371  *
7372  *  [30a]  Float  ::= Number ('e' Digits?)?
7373  *
7374  *  [30]   Number ::=   Digits ('.' Digits?)?
7375  *                    | '.' Digits 
7376  *  [31]   Digits ::=   [0-9]+
7377  *
7378  * Compile a Number in the string
7379  * In complement of the Number expression, this function also handles
7380  * negative values : '-' Number.
7381  *
7382  * Returns the double value.
7383  */
7384 double
7385 xmlXPathStringEvalNumber(const xmlChar *str) {
7386     const xmlChar *cur = str;
7387     double ret;
7388     int ok = 0;
7389     int isneg = 0;
7390     int exponent = 0;
7391     int is_exponent_negative = 0;
7392 #ifdef __GNUC__
7393     unsigned long tmp = 0;
7394     double temp;
7395 #endif
7396     if (cur == NULL) return(0);
7397     while (IS_BLANK(*cur)) cur++;
7398     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7399         return(xmlXPathNAN);
7400     }
7401     if (*cur == '-') {
7402         isneg = 1;
7403         cur++;
7404     }
7405
7406 #ifdef __GNUC__
7407     /*
7408      * tmp/temp is a workaround against a gcc compiler bug
7409      * http://veillard.com/gcc.bug
7410      */
7411     ret = 0;
7412     while ((*cur >= '0') && (*cur <= '9')) {
7413         ret = ret * 10;
7414         tmp = (*cur - '0');
7415         ok = 1;
7416         cur++;
7417         temp = (double) tmp;
7418         ret = ret + temp;
7419     }
7420 #else
7421     ret = 0;
7422     while ((*cur >= '0') && (*cur <= '9')) {
7423         ret = ret * 10 + (*cur - '0');
7424         ok = 1;
7425         cur++;
7426     }
7427 #endif
7428
7429     if (*cur == '.') {
7430         int v, frac = 0;
7431         double fraction = 0;
7432
7433         cur++;
7434         if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7435             return(xmlXPathNAN);
7436         }
7437         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7438             v = (*cur - '0');
7439             fraction = fraction * 10 + v;
7440             frac = frac + 1;
7441             cur++;
7442         }
7443         fraction /= my_pow10[frac];
7444         ret = ret + fraction;
7445         while ((*cur >= '0') && (*cur <= '9'))
7446             cur++;
7447     }
7448     if ((*cur == 'e') || (*cur == 'E')) {
7449       cur++;
7450       if (*cur == '-') {
7451         is_exponent_negative = 1;
7452         cur++;
7453       }
7454       while ((*cur >= '0') && (*cur <= '9')) {
7455         exponent = exponent * 10 + (*cur - '0');
7456         cur++;
7457       }
7458     }
7459     while (IS_BLANK(*cur)) cur++;
7460     if (*cur != 0) return(xmlXPathNAN);
7461     if (isneg) ret = -ret;
7462     if (is_exponent_negative) exponent = -exponent;
7463     ret *= pow(10.0, (double)exponent);
7464     return(ret);
7465 }
7466
7467 /**
7468  * xmlXPathCompNumber:
7469  * @ctxt:  the XPath Parser context
7470  *
7471  *  [30]   Number ::=   Digits ('.' Digits?)?
7472  *                    | '.' Digits 
7473  *  [31]   Digits ::=   [0-9]+
7474  *
7475  * Compile a Number, then push it on the stack
7476  *
7477  */
7478 static void
7479 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7480 {
7481     double ret = 0.0;
7482     double mult = 1;
7483     int ok = 0;
7484     int exponent = 0;
7485     int is_exponent_negative = 0;
7486 #ifdef __GNUC__
7487     unsigned long tmp = 0;
7488     double temp;
7489 #endif
7490
7491     CHECK_ERROR;
7492     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7493         XP_ERROR(XPATH_NUMBER_ERROR);
7494     }
7495 #ifdef __GNUC__
7496     /*
7497      * tmp/temp is a workaround against a gcc compiler bug
7498      * http://veillard.com/gcc.bug
7499      */
7500     ret = 0;
7501     while ((CUR >= '0') && (CUR <= '9')) {
7502         ret = ret * 10;
7503         tmp = (CUR - '0');
7504         ok = 1;
7505         NEXT;
7506         temp = (double) tmp;
7507         ret = ret + temp;
7508     }
7509 #else
7510     ret = 0;
7511     while ((CUR >= '0') && (CUR <= '9')) {
7512         ret = ret * 10 + (CUR - '0');
7513         ok = 1;
7514         NEXT;
7515     }
7516 #endif
7517     if (CUR == '.') {
7518         NEXT;
7519         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7520             XP_ERROR(XPATH_NUMBER_ERROR);
7521         }
7522         while ((CUR >= '0') && (CUR <= '9')) {
7523             mult /= 10;
7524             ret = ret + (CUR - '0') * mult;
7525             NEXT;
7526         }
7527     }
7528     if ((CUR == 'e') || (CUR == 'E')) {
7529         NEXT;
7530         if (CUR == '-') {
7531             is_exponent_negative = 1;
7532             NEXT;
7533         }
7534         while ((CUR >= '0') && (CUR <= '9')) {
7535             exponent = exponent * 10 + (CUR - '0');
7536             NEXT;
7537         }
7538         if (is_exponent_negative)
7539             exponent = -exponent;
7540         ret *= pow(10.0, (double) exponent);
7541     }
7542     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
7543                    xmlXPathNewFloat(ret), NULL);
7544 }
7545
7546 /**
7547  * xmlXPathParseLiteral:
7548  * @ctxt:  the XPath Parser context
7549  *
7550  * Parse a Literal
7551  *
7552  *  [29]   Literal ::=   '"' [^"]* '"'
7553  *                    | "'" [^']* "'"
7554  *
7555  * Returns the value found or NULL in case of error
7556  */
7557 static xmlChar *
7558 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7559     const xmlChar *q;
7560     xmlChar *ret = NULL;
7561
7562     if (CUR == '"') {
7563         NEXT;
7564         q = CUR_PTR;
7565         while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
7566             NEXT;
7567         if (!IS_CHAR((unsigned int) CUR)) {
7568             XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7569         } else {
7570             ret = xmlStrndup(q, CUR_PTR - q);
7571             NEXT;
7572         }
7573     } else if (CUR == '\'') {
7574         NEXT;
7575         q = CUR_PTR;
7576         while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
7577             NEXT;
7578         if (!IS_CHAR((unsigned int) CUR)) {
7579             XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7580         } else {
7581             ret = xmlStrndup(q, CUR_PTR - q);
7582             NEXT;
7583         }
7584     } else {
7585         XP_ERROR0(XPATH_START_LITERAL_ERROR);
7586     }
7587     return(ret);
7588 }
7589
7590 /**
7591  * xmlXPathCompLiteral:
7592  * @ctxt:  the XPath Parser context
7593  *
7594  * Parse a Literal and push it on the stack.
7595  *
7596  *  [29]   Literal ::=   '"' [^"]* '"'
7597  *                    | "'" [^']* "'"
7598  *
7599  * TODO: xmlXPathCompLiteral memory allocation could be improved.
7600  */
7601 static void
7602 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
7603     const xmlChar *q;
7604     xmlChar *ret = NULL;
7605
7606     if (CUR == '"') {
7607         NEXT;
7608         q = CUR_PTR;
7609         while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
7610             NEXT;
7611         if (!IS_CHAR((unsigned int) CUR)) {
7612             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7613         } else {
7614             ret = xmlStrndup(q, CUR_PTR - q);
7615             NEXT;
7616         }
7617     } else if (CUR == '\'') {
7618         NEXT;
7619         q = CUR_PTR;
7620         while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
7621             NEXT;
7622         if (!IS_CHAR((unsigned int) CUR)) {
7623             XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7624         } else {
7625             ret = xmlStrndup(q, CUR_PTR - q);
7626             NEXT;
7627         }
7628     } else {
7629         XP_ERROR(XPATH_START_LITERAL_ERROR);
7630     }
7631     if (ret == NULL) return;
7632     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7633                    xmlXPathNewString(ret), NULL);
7634     xmlFree(ret);
7635 }
7636
7637 /**
7638  * xmlXPathCompVariableReference:
7639  * @ctxt:  the XPath Parser context
7640  *
7641  * Parse a VariableReference, evaluate it and push it on the stack.
7642  *
7643  * The variable bindings consist of a mapping from variable names
7644  * to variable values. The value of a variable is an object, which
7645  * of any of the types that are possible for the value of an expression,
7646  * and may also be of additional types not specified here.
7647  *
7648  * Early evaluation is possible since:
7649  * The variable bindings [...] used to evaluate a subexpression are
7650  * always the same as those used to evaluate the containing expression. 
7651  *
7652  *  [36]   VariableReference ::=   '$' QName 
7653  */
7654 static void
7655 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
7656     xmlChar *name;
7657     xmlChar *prefix;
7658
7659     SKIP_BLANKS;
7660     if (CUR != '$') {
7661         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7662     }
7663     NEXT;
7664     name = xmlXPathParseQName(ctxt, &prefix);
7665     if (name == NULL) {
7666         XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7667     }
7668     ctxt->comp->last = -1;
7669     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7670                    name, prefix);
7671     SKIP_BLANKS;
7672 }
7673
7674 /**
7675  * xmlXPathIsNodeType:
7676  * @name:  a name string
7677  *
7678  * Is the name given a NodeType one.
7679  *
7680  *  [38]   NodeType ::=   'comment'
7681  *                    | 'text'
7682  *                    | 'processing-instruction'
7683  *                    | 'node'
7684  *
7685  * Returns 1 if true 0 otherwise
7686  */
7687 int
7688 xmlXPathIsNodeType(const xmlChar *name) {
7689     if (name == NULL)
7690         return(0);
7691
7692     if (xmlStrEqual(name, BAD_CAST "node"))
7693         return(1);
7694     if (xmlStrEqual(name, BAD_CAST "text"))
7695         return(1);
7696     if (xmlStrEqual(name, BAD_CAST "comment"))
7697         return(1);
7698     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7699         return(1);
7700     return(0);
7701 }
7702
7703 /**
7704  * xmlXPathCompFunctionCall:
7705  * @ctxt:  the XPath Parser context
7706  *
7707  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7708  *  [17]   Argument ::=   Expr 
7709  *
7710  * Compile a function call, the evaluation of all arguments are
7711  * pushed on the stack
7712  */
7713 static void
7714 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
7715     xmlChar *name;
7716     xmlChar *prefix;
7717     int nbargs = 0;
7718
7719     name = xmlXPathParseQName(ctxt, &prefix);
7720     if (name == NULL) {
7721         XP_ERROR(XPATH_EXPR_ERROR);
7722     }
7723     SKIP_BLANKS;
7724 #ifdef DEBUG_EXPR
7725     if (prefix == NULL)
7726         xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7727                         name);
7728     else
7729         xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7730                         prefix, name);
7731 #endif
7732
7733     if (CUR != '(') {
7734         XP_ERROR(XPATH_EXPR_ERROR);
7735     }
7736     NEXT;
7737     SKIP_BLANKS;
7738
7739     ctxt->comp->last = -1;
7740     if (CUR != ')') {
7741         while (CUR != 0) {
7742             int op1 = ctxt->comp->last;
7743             ctxt->comp->last = -1;
7744             xmlXPathCompileExpr(ctxt);
7745             CHECK_ERROR;
7746             PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7747             nbargs++;
7748             if (CUR == ')') break;
7749             if (CUR != ',') {
7750                 XP_ERROR(XPATH_EXPR_ERROR);
7751             }
7752             NEXT;
7753             SKIP_BLANKS;
7754         }
7755     }
7756     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7757                    name, prefix);
7758     NEXT;
7759     SKIP_BLANKS;
7760 }
7761
7762 /**
7763  * xmlXPathCompPrimaryExpr:
7764  * @ctxt:  the XPath Parser context
7765  *
7766  *  [15]   PrimaryExpr ::=   VariableReference 
7767  *                | '(' Expr ')'
7768  *                | Literal 
7769  *                | Number 
7770  *                | FunctionCall 
7771  *
7772  * Compile a primary expression.
7773  */
7774 static void
7775 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
7776     SKIP_BLANKS;
7777     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
7778     else if (CUR == '(') {
7779         NEXT;
7780         SKIP_BLANKS;
7781         xmlXPathCompileExpr(ctxt);
7782         CHECK_ERROR;
7783         if (CUR != ')') {
7784             XP_ERROR(XPATH_EXPR_ERROR);
7785         }
7786         NEXT;
7787         SKIP_BLANKS;
7788     } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
7789         xmlXPathCompNumber(ctxt);
7790     } else if ((CUR == '\'') || (CUR == '"')) {
7791         xmlXPathCompLiteral(ctxt);
7792     } else {
7793         xmlXPathCompFunctionCall(ctxt);
7794     }
7795     SKIP_BLANKS;
7796 }
7797
7798 /**
7799  * xmlXPathCompFilterExpr:
7800  * @ctxt:  the XPath Parser context
7801  *
7802  *  [20]   FilterExpr ::=   PrimaryExpr 
7803  *               | FilterExpr Predicate 
7804  *
7805  * Compile a filter expression.
7806  * Square brackets are used to filter expressions in the same way that
7807  * they are used in location paths. It is an error if the expression to
7808  * be filtered does not evaluate to a node-set. The context node list
7809  * used for evaluating the expression in square brackets is the node-set
7810  * to be filtered listed in document order.
7811  */
7812
7813 static void
7814 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7815     xmlXPathCompPrimaryExpr(ctxt);
7816     CHECK_ERROR;
7817     SKIP_BLANKS;
7818     
7819     while (CUR == '[') {
7820         xmlXPathCompPredicate(ctxt, 1);
7821         SKIP_BLANKS;
7822     }
7823
7824     
7825 }
7826
7827 /**
7828  * xmlXPathScanName:
7829  * @ctxt:  the XPath Parser context
7830  *
7831  * Trickery: parse an XML name but without consuming the input flow
7832  * Needed to avoid insanity in the parser state.
7833  *
7834  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7835  *                  CombiningChar | Extender
7836  *
7837  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7838  *
7839  * [6] Names ::= Name (S Name)*
7840  *
7841  * Returns the Name parsed or NULL
7842  */
7843
7844 static xmlChar *
7845 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7846     xmlChar buf[XML_MAX_NAMELEN];
7847     int len = 0;
7848
7849     SKIP_BLANKS;
7850     if (!IS_LETTER(CUR) && (CUR != '_') &&
7851         (CUR != ':')) {
7852         return(NULL);
7853     }
7854
7855     while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7856            (NXT(len) == '.') || (NXT(len) == '-') ||
7857            (NXT(len) == '_') || (NXT(len) == ':') || 
7858            (IS_COMBINING(NXT(len))) ||
7859            (IS_EXTENDER(NXT(len)))) {
7860         buf[len] = NXT(len);
7861         len++;
7862         if (len >= XML_MAX_NAMELEN) {
7863             xmlGenericError(xmlGenericErrorContext, 
7864                "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7865             while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7866                    (NXT(len) == '.') || (NXT(len) == '-') ||
7867                    (NXT(len) == '_') || (NXT(len) == ':') || 
7868                    (IS_COMBINING(NXT(len))) ||
7869                    (IS_EXTENDER(NXT(len))))
7870                  len++;
7871             break;
7872         }
7873     }
7874     return(xmlStrndup(buf, len));
7875 }
7876
7877 /**
7878  * xmlXPathCompPathExpr:
7879  * @ctxt:  the XPath Parser context
7880  *
7881  *  [19]   PathExpr ::=   LocationPath 
7882  *               | FilterExpr 
7883  *               | FilterExpr '/' RelativeLocationPath 
7884  *               | FilterExpr '//' RelativeLocationPath 
7885  *
7886  * Compile a path expression.
7887  * The / operator and // operators combine an arbitrary expression
7888  * and a relative location path. It is an error if the expression
7889  * does not evaluate to a node-set.
7890  * The / operator does composition in the same way as when / is
7891  * used in a location path. As in location paths, // is short for
7892  * /descendant-or-self::node()/.
7893  */
7894
7895 static void
7896 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
7897     int lc = 1;           /* Should we branch to LocationPath ?         */
7898     xmlChar *name = NULL; /* we may have to preparse a name to find out */
7899
7900     SKIP_BLANKS;
7901     if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7902         (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
7903         lc = 0;
7904     } else if (CUR == '*') {
7905         /* relative or absolute location path */
7906         lc = 1;
7907     } else if (CUR == '/') {
7908         /* relative or absolute location path */
7909         lc = 1;
7910     } else if (CUR == '@') {
7911         /* relative abbreviated attribute location path */
7912         lc = 1;
7913     } else if (CUR == '.') {
7914         /* relative abbreviated attribute location path */
7915         lc = 1;
7916     } else {
7917         /*
7918          * Problem is finding if we have a name here whether it's:
7919          *   - a nodetype
7920          *   - a function call in which case it's followed by '('
7921          *   - an axis in which case it's followed by ':'
7922          *   - a element name
7923          * We do an a priori analysis here rather than having to
7924          * maintain parsed token content through the recursive function
7925          * calls. This looks uglier but makes the code quite easier to
7926          * read/write/debug.
7927          */
7928         SKIP_BLANKS;
7929         name = xmlXPathScanName(ctxt);
7930         if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7931 #ifdef DEBUG_STEP
7932             xmlGenericError(xmlGenericErrorContext,
7933                     "PathExpr: Axis\n");
7934 #endif
7935             lc = 1;
7936             xmlFree(name);
7937         } else if (name != NULL) {
7938             int len =xmlStrlen(name);
7939
7940             
7941             while (NXT(len) != 0) {
7942                 if (NXT(len) == '/') {
7943                     /* element name */
7944 #ifdef DEBUG_STEP
7945                     xmlGenericError(xmlGenericErrorContext,
7946                             "PathExpr: AbbrRelLocation\n");
7947 #endif
7948                     lc = 1;
7949                     break;
7950                 } else if (IS_BLANK(NXT(len))) {
7951                     /* ignore blanks */
7952                     ;
7953                 } else if (NXT(len) == ':') {
7954 #ifdef DEBUG_STEP
7955                     xmlGenericError(xmlGenericErrorContext,
7956                             "PathExpr: AbbrRelLocation\n");
7957 #endif
7958                     lc = 1;
7959                     break;
7960                 } else if ((NXT(len) == '(')) {
7961                     /* Note Type or Function */
7962                     if (xmlXPathIsNodeType(name)) {
7963 #ifdef DEBUG_STEP
7964                         xmlGenericError(xmlGenericErrorContext,
7965                                 "PathExpr: Type search\n");
7966 #endif
7967                         lc = 1;
7968                     } else {
7969 #ifdef DEBUG_STEP
7970                         xmlGenericError(xmlGenericErrorContext,
7971                                 "PathExpr: function call\n");
7972 #endif
7973                         lc = 0;
7974                     }
7975                     break;
7976                 } else if ((NXT(len) == '[')) {
7977                     /* element name */
7978 #ifdef DEBUG_STEP
7979                     xmlGenericError(xmlGenericErrorContext,
7980                             "PathExpr: AbbrRelLocation\n");
7981 #endif
7982                     lc = 1;
7983                     break;
7984                 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7985                            (NXT(len) == '=')) {
7986                     lc = 1;
7987                     break;
7988                 } else {
7989                     lc = 1;
7990                     break;
7991                 }
7992                 len++;
7993             }
7994             if (NXT(len) == 0) {
7995 #ifdef DEBUG_STEP
7996                 xmlGenericError(xmlGenericErrorContext,
7997                         "PathExpr: AbbrRelLocation\n");
7998 #endif
7999                 /* element name */
8000                 lc = 1;
8001             }
8002             xmlFree(name);
8003         } else {
8004             /* make sure all cases are covered explicitely */
8005             XP_ERROR(XPATH_EXPR_ERROR);
8006         }
8007     } 
8008
8009     if (lc) {
8010         if (CUR == '/') {
8011             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8012         } else {
8013             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8014         }
8015         xmlXPathCompLocationPath(ctxt);
8016     } else {
8017         xmlXPathCompFilterExpr(ctxt);
8018         CHECK_ERROR;
8019         if ((CUR == '/') && (NXT(1) == '/')) {
8020             SKIP(2);
8021             SKIP_BLANKS;
8022
8023             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8024                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8025             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8026
8027             xmlXPathCompRelativeLocationPath(ctxt);
8028         } else if (CUR == '/') {
8029             xmlXPathCompRelativeLocationPath(ctxt);
8030         }
8031     }
8032     SKIP_BLANKS;
8033 }
8034
8035 /**
8036  * xmlXPathCompUnionExpr:
8037  * @ctxt:  the XPath Parser context
8038  *
8039  *  [18]   UnionExpr ::=   PathExpr 
8040  *               | UnionExpr '|' PathExpr 
8041  *
8042  * Compile an union expression.
8043  */
8044
8045 static void
8046 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8047     xmlXPathCompPathExpr(ctxt);
8048     CHECK_ERROR;
8049     SKIP_BLANKS;
8050     while (CUR == '|') {
8051         int op1 = ctxt->comp->last;
8052         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8053
8054         NEXT;
8055         SKIP_BLANKS;
8056         xmlXPathCompPathExpr(ctxt);
8057
8058         PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8059
8060         SKIP_BLANKS;
8061     }
8062 }
8063
8064 /**
8065  * xmlXPathCompUnaryExpr:
8066  * @ctxt:  the XPath Parser context
8067  *
8068  *  [27]   UnaryExpr ::=   UnionExpr 
8069  *                   | '-' UnaryExpr 
8070  *
8071  * Compile an unary expression.
8072  */
8073
8074 static void
8075 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8076     int minus = 0;
8077     int found = 0;
8078
8079     SKIP_BLANKS;
8080     while (CUR == '-') {
8081         minus = 1 - minus;
8082         found = 1;
8083         NEXT;
8084         SKIP_BLANKS;
8085     }
8086
8087     xmlXPathCompUnionExpr(ctxt);
8088     CHECK_ERROR;
8089     if (found) {
8090         if (minus)
8091             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8092         else
8093             PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8094     }
8095 }
8096
8097 /**
8098  * xmlXPathCompMultiplicativeExpr:
8099  * @ctxt:  the XPath Parser context
8100  *
8101  *  [26]   MultiplicativeExpr ::=   UnaryExpr 
8102  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr 
8103  *                   | MultiplicativeExpr 'div' UnaryExpr 
8104  *                   | MultiplicativeExpr 'mod' UnaryExpr 
8105  *  [34]   MultiplyOperator ::=   '*'
8106  *
8107  * Compile an Additive expression.
8108  */
8109
8110 static void
8111 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8112     xmlXPathCompUnaryExpr(ctxt);
8113     CHECK_ERROR;
8114     SKIP_BLANKS;
8115     while ((CUR == '*') || 
8116            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8117            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8118         int op = -1;
8119         int op1 = ctxt->comp->last;
8120
8121         if (CUR == '*') {
8122             op = 0;
8123             NEXT;
8124         } else if (CUR == 'd') {
8125             op = 1;
8126             SKIP(3);
8127         } else if (CUR == 'm') {
8128             op = 2;
8129             SKIP(3);
8130         }
8131         SKIP_BLANKS;
8132         xmlXPathCompUnaryExpr(ctxt);
8133         CHECK_ERROR;
8134         PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8135         SKIP_BLANKS;
8136     }
8137 }
8138
8139 /**
8140  * xmlXPathCompAdditiveExpr:
8141  * @ctxt:  the XPath Parser context
8142  *
8143  *  [25]   AdditiveExpr ::=   MultiplicativeExpr 
8144  *                   | AdditiveExpr '+' MultiplicativeExpr 
8145  *                   | AdditiveExpr '-' MultiplicativeExpr 
8146  *
8147  * Compile an Additive expression.
8148  */
8149
8150 static void
8151 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8152
8153     xmlXPathCompMultiplicativeExpr(ctxt);
8154     CHECK_ERROR;
8155     SKIP_BLANKS;
8156     while ((CUR == '+') || (CUR == '-')) {
8157         int plus;
8158         int op1 = ctxt->comp->last;
8159
8160         if (CUR == '+') plus = 1;
8161         else plus = 0;
8162         NEXT;
8163         SKIP_BLANKS;
8164         xmlXPathCompMultiplicativeExpr(ctxt);
8165         CHECK_ERROR;
8166         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8167         SKIP_BLANKS;
8168     }
8169 }
8170
8171 /**
8172  * xmlXPathCompRelationalExpr:
8173  * @ctxt:  the XPath Parser context
8174  *
8175  *  [24]   RelationalExpr ::=   AdditiveExpr 
8176  *                 | RelationalExpr '<' AdditiveExpr 
8177  *                 | RelationalExpr '>' AdditiveExpr 
8178  *                 | RelationalExpr '<=' AdditiveExpr 
8179  *                 | RelationalExpr '>=' AdditiveExpr 
8180  *
8181  *  A <= B > C is allowed ? Answer from James, yes with
8182  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8183  *  which is basically what got implemented.
8184  *
8185  * Compile a Relational expression, then push the result
8186  * on the stack
8187  */
8188
8189 static void
8190 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8191     xmlXPathCompAdditiveExpr(ctxt);
8192     CHECK_ERROR;
8193     SKIP_BLANKS;
8194     while ((CUR == '<') ||
8195            (CUR == '>') ||
8196            ((CUR == '<') && (NXT(1) == '=')) ||
8197            ((CUR == '>') && (NXT(1) == '='))) {
8198         int inf, strict;
8199         int op1 = ctxt->comp->last;
8200
8201         if (CUR == '<') inf = 1;
8202         else inf = 0;
8203         if (NXT(1) == '=') strict = 0;
8204         else strict = 1;
8205         NEXT;
8206         if (!strict) NEXT;
8207         SKIP_BLANKS;
8208         xmlXPathCompAdditiveExpr(ctxt);
8209         CHECK_ERROR;
8210         PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8211         SKIP_BLANKS;
8212     }
8213 }
8214
8215 /**
8216  * xmlXPathCompEqualityExpr:
8217  * @ctxt:  the XPath Parser context
8218  *
8219  *  [23]   EqualityExpr ::=   RelationalExpr 
8220  *                 | EqualityExpr '=' RelationalExpr 
8221  *                 | EqualityExpr '!=' RelationalExpr 
8222  *
8223  *  A != B != C is allowed ? Answer from James, yes with
8224  *  (RelationalExpr = RelationalExpr) = RelationalExpr
8225  *  (RelationalExpr != RelationalExpr) != RelationalExpr
8226  *  which is basically what got implemented.
8227  *
8228  * Compile an Equality expression.
8229  *
8230  */
8231 static void
8232 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8233     xmlXPathCompRelationalExpr(ctxt);
8234     CHECK_ERROR;
8235     SKIP_BLANKS;
8236     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
8237         int eq;
8238         int op1 = ctxt->comp->last;
8239
8240         if (CUR == '=') eq = 1;
8241         else eq = 0;
8242         NEXT;
8243         if (!eq) NEXT;
8244         SKIP_BLANKS;
8245         xmlXPathCompRelationalExpr(ctxt);
8246         CHECK_ERROR;
8247         PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
8248         SKIP_BLANKS;
8249     }
8250 }
8251
8252 /**
8253  * xmlXPathCompAndExpr:
8254  * @ctxt:  the XPath Parser context
8255  *
8256  *  [22]   AndExpr ::=   EqualityExpr 
8257  *                 | AndExpr 'and' EqualityExpr 
8258  *
8259  * Compile an AND expression.
8260  *
8261  */
8262 static void
8263 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8264     xmlXPathCompEqualityExpr(ctxt);
8265     CHECK_ERROR;
8266     SKIP_BLANKS;
8267     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
8268         int op1 = ctxt->comp->last;
8269         SKIP(3);
8270         SKIP_BLANKS;
8271         xmlXPathCompEqualityExpr(ctxt);
8272         CHECK_ERROR;
8273         PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
8274         SKIP_BLANKS;
8275     }
8276 }
8277
8278 /**
8279  * xmlXPathCompileExpr:
8280  * @ctxt:  the XPath Parser context
8281  *
8282  *  [14]   Expr ::=   OrExpr 
8283  *  [21]   OrExpr ::=   AndExpr 
8284  *                 | OrExpr 'or' AndExpr 
8285  *
8286  * Parse and compile an expression
8287  */
8288 static void
8289 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8290     xmlXPathCompAndExpr(ctxt);
8291     CHECK_ERROR;
8292     SKIP_BLANKS;
8293     while ((CUR == 'o') && (NXT(1) == 'r')) {
8294         int op1 = ctxt->comp->last;
8295         SKIP(2);
8296         SKIP_BLANKS;
8297         xmlXPathCompAndExpr(ctxt);
8298         CHECK_ERROR;
8299         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8300         op1 = ctxt->comp->nbStep;
8301         SKIP_BLANKS;
8302     }
8303     if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8304         /* more ops could be optimized too */
8305         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8306     }
8307 }
8308
8309 /**
8310  * xmlXPathCompPredicate:
8311  * @ctxt:  the XPath Parser context
8312  * @filter:  act as a filter
8313  *
8314  *  [8]   Predicate ::=   '[' PredicateExpr ']'
8315  *  [9]   PredicateExpr ::=   Expr 
8316  *
8317  * Compile a predicate expression
8318  */
8319 static void
8320 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
8321     int op1 = ctxt->comp->last;
8322
8323     SKIP_BLANKS;
8324     if (CUR != '[') {
8325         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8326     }
8327     NEXT;
8328     SKIP_BLANKS;
8329
8330     ctxt->comp->last = -1;
8331     xmlXPathCompileExpr(ctxt);
8332     CHECK_ERROR;
8333
8334     if (CUR != ']') {
8335         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8336     }
8337
8338     if (filter)
8339         PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8340     else
8341         PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
8342
8343     NEXT;
8344     SKIP_BLANKS;
8345 }
8346
8347 /**
8348  * xmlXPathCompNodeTest:
8349  * @ctxt:  the XPath Parser context
8350  * @test:  pointer to a xmlXPathTestVal
8351  * @type:  pointer to a xmlXPathTypeVal
8352  * @prefix:  placeholder for a possible name prefix
8353  *
8354  * [7] NodeTest ::=   NameTest
8355  *                  | NodeType '(' ')'
8356  *                  | 'processing-instruction' '(' Literal ')'
8357  *
8358  * [37] NameTest ::=  '*'
8359  *                  | NCName ':' '*'
8360  *                  | QName
8361  * [38] NodeType ::= 'comment'
8362  *                 | 'text'
8363  *                 | 'processing-instruction'
8364  *                 | 'node'
8365  *
8366  * Returns the name found and update @test, @type and @prefix appropriately
8367  */
8368 static xmlChar *
8369 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8370                      xmlXPathTypeVal *type, const xmlChar **prefix,
8371                      xmlChar *name) {
8372     int blanks;
8373
8374     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8375         STRANGE;
8376         return(NULL);
8377     }
8378     *type = (xmlXPathTypeVal) 0;
8379     *test = (xmlXPathTestVal) 0;
8380     *prefix = NULL;
8381     SKIP_BLANKS;
8382
8383     if ((name == NULL) && (CUR == '*')) {
8384         /*
8385          * All elements
8386          */
8387         NEXT;
8388         *test = NODE_TEST_ALL;
8389         return(NULL);
8390     }
8391
8392     if (name == NULL)
8393         name = xmlXPathParseNCName(ctxt);
8394     if (name == NULL) {
8395         XP_ERROR0(XPATH_EXPR_ERROR);
8396     }
8397
8398     blanks = IS_BLANK(CUR);
8399     SKIP_BLANKS;
8400     if (CUR == '(') {
8401         NEXT;
8402         /*
8403          * NodeType or PI search
8404          */
8405         if (xmlStrEqual(name, BAD_CAST "comment"))
8406             *type = NODE_TYPE_COMMENT;
8407         else if (xmlStrEqual(name, BAD_CAST "node"))
8408             *type = NODE_TYPE_NODE;
8409         else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8410             *type = NODE_TYPE_PI;
8411         else if (xmlStrEqual(name, BAD_CAST "text"))
8412             *type = NODE_TYPE_TEXT;
8413         else {
8414             if (name != NULL)
8415                 xmlFree(name);
8416             XP_ERROR0(XPATH_EXPR_ERROR);
8417         }
8418
8419         *test = NODE_TEST_TYPE;
8420         
8421         SKIP_BLANKS;
8422         if (*type == NODE_TYPE_PI) {
8423             /*
8424              * Specific case: search a PI by name.
8425              */
8426             if (name != NULL)
8427                 xmlFree(name);
8428             name = NULL;
8429             if (CUR != ')') {
8430                 name = xmlXPathParseLiteral(ctxt);
8431                 CHECK_ERROR 0;
8432                 *test = NODE_TEST_PI;
8433                 SKIP_BLANKS;
8434             }
8435         }
8436         if (CUR != ')') {
8437             if (name != NULL)
8438                 xmlFree(name);
8439             XP_ERROR0(XPATH_UNCLOSED_ERROR);
8440         }
8441         NEXT;
8442         return(name);
8443     }
8444     *test = NODE_TEST_NAME;
8445     if ((!blanks) && (CUR == ':')) {
8446         NEXT;
8447
8448         /*
8449          * Since currently the parser context don't have a
8450          * namespace list associated:
8451          * The namespace name for this prefix can be computed
8452          * only at evaluation time. The compilation is done
8453          * outside of any context.
8454          */
8455 #if 0
8456         *prefix = xmlXPathNsLookup(ctxt->context, name);
8457         if (name != NULL)
8458             xmlFree(name);
8459         if (*prefix == NULL) {
8460             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8461         }
8462 #else
8463         *prefix = name;
8464 #endif
8465
8466         if (CUR == '*') {
8467             /*
8468              * All elements
8469              */
8470             NEXT;
8471             *test = NODE_TEST_ALL;
8472             return(NULL);
8473         }
8474
8475         name = xmlXPathParseNCName(ctxt);
8476         if (name == NULL) {
8477             XP_ERROR0(XPATH_EXPR_ERROR);
8478         }
8479     }
8480     return(name);
8481 }
8482
8483 /**
8484  * xmlXPathIsAxisName:
8485  * @name:  a preparsed name token
8486  *
8487  * [6] AxisName ::=   'ancestor'
8488  *                  | 'ancestor-or-self'
8489  *                  | 'attribute'
8490  *                  | 'child'
8491  *                  | 'descendant'
8492  *                  | 'descendant-or-self'
8493  *                  | 'following'
8494  *                  | 'following-sibling'
8495  *                  | 'namespace'
8496  *                  | 'parent'
8497  *                  | 'preceding'
8498  *                  | 'preceding-sibling'
8499  *                  | 'self'
8500  *
8501  * Returns the axis or 0
8502  */
8503 static xmlXPathAxisVal
8504 xmlXPathIsAxisName(const xmlChar *name) {
8505     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
8506     switch (name[0]) {
8507         case 'a':
8508             if (xmlStrEqual(name, BAD_CAST "ancestor"))
8509                 ret = AXIS_ANCESTOR;
8510             if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8511                 ret = AXIS_ANCESTOR_OR_SELF;
8512             if (xmlStrEqual(name, BAD_CAST "attribute"))
8513                 ret = AXIS_ATTRIBUTE;
8514             break;
8515         case 'c':
8516             if (xmlStrEqual(name, BAD_CAST "child"))
8517                 ret = AXIS_CHILD;
8518             break;
8519         case 'd':
8520             if (xmlStrEqual(name, BAD_CAST "descendant"))
8521                 ret = AXIS_DESCENDANT;
8522             if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8523                 ret = AXIS_DESCENDANT_OR_SELF;
8524             break;
8525         case 'f':
8526             if (xmlStrEqual(name, BAD_CAST "following"))
8527                 ret = AXIS_FOLLOWING;
8528             if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8529                 ret = AXIS_FOLLOWING_SIBLING;
8530             break;
8531         case 'n':
8532             if (xmlStrEqual(name, BAD_CAST "namespace"))
8533                 ret = AXIS_NAMESPACE;
8534             break;
8535         case 'p':
8536             if (xmlStrEqual(name, BAD_CAST "parent"))
8537                 ret = AXIS_PARENT;
8538             if (xmlStrEqual(name, BAD_CAST "preceding"))
8539                 ret = AXIS_PRECEDING;
8540             if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8541                 ret = AXIS_PRECEDING_SIBLING;
8542             break;
8543         case 's':
8544             if (xmlStrEqual(name, BAD_CAST "self"))
8545                 ret = AXIS_SELF;
8546             break;
8547     }
8548     return(ret);
8549 }
8550
8551 /**
8552  * xmlXPathCompStep:
8553  * @ctxt:  the XPath Parser context
8554  *
8555  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
8556  *                  | AbbreviatedStep 
8557  *
8558  * [12] AbbreviatedStep ::=   '.' | '..'
8559  *
8560  * [5] AxisSpecifier ::= AxisName '::'
8561  *                  | AbbreviatedAxisSpecifier
8562  *
8563  * [13] AbbreviatedAxisSpecifier ::= '@'?
8564  *
8565  * Modified for XPtr range support as:
8566  *
8567  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8568  *                     | AbbreviatedStep
8569  *                     | 'range-to' '(' Expr ')' Predicate*
8570  *
8571  * Compile one step in a Location Path
8572  * A location step of . is short for self::node(). This is
8573  * particularly useful in conjunction with //. For example, the
8574  * location path .//para is short for
8575  * self::node()/descendant-or-self::node()/child::para
8576  * and so will select all para descendant elements of the context
8577  * node.
8578  * Similarly, a location step of .. is short for parent::node().
8579  * For example, ../title is short for parent::node()/child::title
8580  * and so will select the title children of the parent of the context
8581  * node.
8582  */
8583 static void
8584 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
8585 #ifdef LIBXML_XPTR_ENABLED
8586     int rangeto = 0;
8587     int op2 = -1;
8588 #endif
8589
8590     SKIP_BLANKS;
8591     if ((CUR == '.') && (NXT(1) == '.')) {
8592         SKIP(2);
8593         SKIP_BLANKS;
8594         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8595                     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8596     } else if (CUR == '.') {
8597         NEXT;
8598         SKIP_BLANKS;
8599     } else {
8600         xmlChar *name = NULL;
8601         const xmlChar *prefix = NULL;
8602         xmlXPathTestVal test;
8603         xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
8604         xmlXPathTypeVal type;
8605         int op1;
8606
8607         /*
8608          * The modification needed for XPointer change to the production
8609          */
8610 #ifdef LIBXML_XPTR_ENABLED
8611         if (ctxt->xptr) {
8612             name = xmlXPathParseNCName(ctxt);
8613             if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
8614                 op2 = ctxt->comp->last;
8615                 xmlFree(name);
8616                 SKIP_BLANKS;
8617                 if (CUR != '(') {
8618                     XP_ERROR(XPATH_EXPR_ERROR);
8619                 }
8620                 NEXT;
8621                 SKIP_BLANKS;
8622
8623                 xmlXPathCompileExpr(ctxt);
8624                 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
8625                 CHECK_ERROR;
8626
8627                 SKIP_BLANKS;
8628                 if (CUR != ')') {
8629                     XP_ERROR(XPATH_EXPR_ERROR);
8630                 }
8631                 NEXT;
8632                 rangeto = 1;
8633                 goto eval_predicates;
8634             }
8635         }
8636 #endif
8637         if (CUR == '*') {
8638             axis = AXIS_CHILD;
8639         } else {
8640             if (name == NULL)
8641                 name = xmlXPathParseNCName(ctxt);
8642             if (name != NULL) {
8643                 axis = xmlXPathIsAxisName(name);
8644                 if (axis != 0) {
8645                     SKIP_BLANKS;
8646                     if ((CUR == ':') && (NXT(1) == ':')) {
8647                         SKIP(2);
8648                         xmlFree(name);
8649                         name = NULL;
8650                     } else {
8651                         /* an element name can conflict with an axis one :-\ */
8652                         axis = AXIS_CHILD;
8653                     }
8654                 } else {
8655                     axis = AXIS_CHILD;
8656                 }
8657             } else if (CUR == '@') {
8658                 NEXT;
8659                 axis = AXIS_ATTRIBUTE;
8660             } else {
8661                 axis = AXIS_CHILD;
8662             }
8663         }
8664
8665         CHECK_ERROR;
8666
8667         name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
8668         if (test == 0)
8669             return;
8670
8671 #ifdef DEBUG_STEP
8672         xmlGenericError(xmlGenericErrorContext,
8673                 "Basis : computing new set\n");
8674 #endif
8675
8676 #ifdef DEBUG_STEP
8677         xmlGenericError(xmlGenericErrorContext, "Basis : ");
8678         if (ctxt->value == NULL)
8679             xmlGenericError(xmlGenericErrorContext, "no value\n");
8680         else if (ctxt->value->nodesetval == NULL)
8681             xmlGenericError(xmlGenericErrorContext, "Empty\n");
8682         else
8683             xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
8684 #endif
8685
8686 eval_predicates:
8687         op1 = ctxt->comp->last;
8688         ctxt->comp->last = -1;
8689
8690         SKIP_BLANKS;
8691         while (CUR == '[') {
8692             xmlXPathCompPredicate(ctxt, 0);
8693         }
8694
8695 #ifdef LIBXML_XPTR_ENABLED
8696         if (rangeto) {
8697             PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8698         } else
8699 #endif
8700             PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8701                            test, type, (void *)prefix, (void *)name);
8702
8703     }
8704 #ifdef DEBUG_STEP
8705     xmlGenericError(xmlGenericErrorContext, "Step : ");
8706     if (ctxt->value == NULL)
8707         xmlGenericError(xmlGenericErrorContext, "no value\n");
8708     else if (ctxt->value->nodesetval == NULL)
8709         xmlGenericError(xmlGenericErrorContext, "Empty\n");
8710     else
8711         xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8712                 ctxt->value->nodesetval);
8713 #endif
8714 }
8715
8716 /**
8717  * xmlXPathCompRelativeLocationPath:
8718  * @ctxt:  the XPath Parser context
8719  *
8720  *  [3]   RelativeLocationPath ::=   Step 
8721  *                     | RelativeLocationPath '/' Step 
8722  *                     | AbbreviatedRelativeLocationPath 
8723  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step 
8724  *
8725  * Compile a relative location path.
8726  */
8727 static void
8728 xmlXPathCompRelativeLocationPath
8729 (xmlXPathParserContextPtr ctxt) {
8730     SKIP_BLANKS;
8731     if ((CUR == '/') && (NXT(1) == '/')) {
8732         SKIP(2);
8733         SKIP_BLANKS;
8734         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8735                          NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8736     } else if (CUR == '/') {
8737             NEXT;
8738         SKIP_BLANKS;
8739     }
8740     xmlXPathCompStep(ctxt);
8741     SKIP_BLANKS;
8742     while (CUR == '/') {
8743         if ((CUR == '/') && (NXT(1) == '/')) {
8744             SKIP(2);
8745             SKIP_BLANKS;
8746             PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8747                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8748             xmlXPathCompStep(ctxt);
8749         } else if (CUR == '/') {
8750             NEXT;
8751             SKIP_BLANKS;
8752             xmlXPathCompStep(ctxt);
8753         }
8754         SKIP_BLANKS;
8755     }
8756 }
8757
8758 /**
8759  * xmlXPathCompLocationPath:
8760  * @ctxt:  the XPath Parser context
8761  *
8762  *  [1]   LocationPath ::=   RelativeLocationPath 
8763  *                     | AbsoluteLocationPath 
8764  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
8765  *                     | AbbreviatedAbsoluteLocationPath 
8766  *  [10]   AbbreviatedAbsoluteLocationPath ::=   
8767  *                           '//' RelativeLocationPath 
8768  *
8769  * Compile a location path
8770  *
8771  * // is short for /descendant-or-self::node()/. For example,
8772  * //para is short for /descendant-or-self::node()/child::para and
8773  * so will select any para element in the document (even a para element
8774  * that is a document element will be selected by //para since the
8775  * document element node is a child of the root node); div//para is
8776  * short for div/descendant-or-self::node()/child::para and so will
8777  * select all para descendants of div children.
8778  */
8779 static void
8780 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
8781     SKIP_BLANKS;
8782     if (CUR != '/') {
8783         xmlXPathCompRelativeLocationPath(ctxt);
8784     } else {
8785         while (CUR == '/') {
8786             if ((CUR == '/') && (NXT(1) == '/')) {
8787                 SKIP(2);
8788                 SKIP_BLANKS;
8789                 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8790                              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8791                 xmlXPathCompRelativeLocationPath(ctxt);
8792             } else if (CUR == '/') {
8793                 NEXT;
8794                 SKIP_BLANKS;
8795                 if ((CUR != 0 ) &&
8796                     ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8797                      (CUR == '@') || (CUR == '*')))
8798                     xmlXPathCompRelativeLocationPath(ctxt);
8799             }
8800         }
8801     }
8802 }
8803
8804 /************************************************************************
8805  *                                                                      *
8806  *              XPath precompiled expression evaluation                 *
8807  *                                                                      *
8808  ************************************************************************/
8809
8810 static int
8811 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8812
8813 /**
8814  * xmlXPathNodeCollectAndTest:
8815  * @ctxt:  the XPath Parser context
8816  * @op:  the XPath precompiled step operation
8817  * @first:  pointer to the first element in document order
8818  * @last:  pointer to the last element in document order
8819  *
8820  * This is the function implementing a step: based on the current list
8821  * of nodes, it builds up a new list, looking at all nodes under that
8822  * axis and selecting them it also do the predicate filtering
8823  *
8824  * Pushes the new NodeSet resulting from the search.
8825  *
8826  * Returns the number of node traversed
8827  */
8828 static int
8829 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
8830                            xmlXPathStepOpPtr op,
8831                            xmlNodePtr * first, xmlNodePtr * last)
8832 {
8833     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8834     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8835     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
8836     const xmlChar *prefix = op->value4;
8837     const xmlChar *name = op->value5;
8838     const xmlChar *URI = NULL;
8839
8840 #ifdef DEBUG_STEP
8841     int n = 0;
8842 #endif
8843     int i, t = 0;
8844     xmlNodeSetPtr ret, list;
8845     xmlXPathTraversalFunction next = NULL;
8846     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8847     xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
8848     xmlNodePtr cur = NULL;
8849     xmlXPathObjectPtr obj;
8850     xmlNodeSetPtr nodelist;
8851     xmlNodePtr tmp;
8852
8853     CHECK_TYPE0(XPATH_NODESET);
8854     obj = valuePop(ctxt);
8855     addNode = xmlXPathNodeSetAdd;
8856     mergeNodeSet = xmlXPathNodeSetMerge;
8857     if (prefix != NULL) {
8858         URI = xmlXPathNsLookup(ctxt->context, prefix);
8859         if (URI == NULL)
8860             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8861     }
8862 #ifdef DEBUG_STEP
8863     xmlGenericError(xmlGenericErrorContext, "new step : ");
8864 #endif
8865     switch (axis) {
8866         case AXIS_ANCESTOR:
8867 #ifdef DEBUG_STEP
8868             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8869 #endif
8870             first = NULL;
8871             next = xmlXPathNextAncestor;
8872             break;
8873         case AXIS_ANCESTOR_OR_SELF:
8874 #ifdef DEBUG_STEP
8875             xmlGenericError(xmlGenericErrorContext,
8876                             "axis 'ancestors-or-self' ");
8877 #endif
8878             first = NULL;
8879             next = xmlXPathNextAncestorOrSelf;
8880             break;
8881         case AXIS_ATTRIBUTE:
8882 #ifdef DEBUG_STEP
8883             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8884 #endif
8885             first = NULL;
8886             last = NULL;
8887             next = xmlXPathNextAttribute;
8888             mergeNodeSet = xmlXPathNodeSetMergeUnique;
8889             break;
8890         case AXIS_CHILD:
8891 #ifdef DEBUG_STEP
8892             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8893 #endif
8894             last = NULL;
8895             next = xmlXPathNextChild;
8896             mergeNodeSet = xmlXPathNodeSetMergeUnique;
8897             break;
8898         case AXIS_DESCENDANT:
8899 #ifdef DEBUG_STEP
8900             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8901 #endif
8902             last = NULL;
8903             next = xmlXPathNextDescendant;
8904             break;
8905         case AXIS_DESCENDANT_OR_SELF:
8906 #ifdef DEBUG_STEP
8907             xmlGenericError(xmlGenericErrorContext,
8908                             "axis 'descendant-or-self' ");
8909 #endif
8910             last = NULL;
8911             next = xmlXPathNextDescendantOrSelf;
8912             break;
8913         case AXIS_FOLLOWING:
8914 #ifdef DEBUG_STEP
8915             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8916 #endif
8917             last = NULL;
8918             next = xmlXPathNextFollowing;
8919             break;
8920         case AXIS_FOLLOWING_SIBLING:
8921 #ifdef DEBUG_STEP
8922             xmlGenericError(xmlGenericErrorContext,
8923                             "axis 'following-siblings' ");
8924 #endif
8925             last = NULL;
8926             next = xmlXPathNextFollowingSibling;
8927             break;
8928         case AXIS_NAMESPACE:
8929 #ifdef DEBUG_STEP
8930             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8931 #endif
8932             first = NULL;
8933             last = NULL;
8934             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8935             mergeNodeSet = xmlXPathNodeSetMergeUnique;
8936             break;
8937         case AXIS_PARENT:
8938 #ifdef DEBUG_STEP
8939             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8940 #endif
8941             first = NULL;
8942             next = xmlXPathNextParent;
8943             break;
8944         case AXIS_PRECEDING:
8945 #ifdef DEBUG_STEP
8946             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8947 #endif
8948             first = NULL;
8949             next = xmlXPathNextPrecedingInternal;
8950             break;
8951         case AXIS_PRECEDING_SIBLING:
8952 #ifdef DEBUG_STEP
8953             xmlGenericError(xmlGenericErrorContext,
8954                             "axis 'preceding-sibling' ");
8955 #endif
8956             first = NULL;
8957             next = xmlXPathNextPrecedingSibling;
8958             break;
8959         case AXIS_SELF:
8960 #ifdef DEBUG_STEP
8961             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8962 #endif
8963             first = NULL;
8964             last = NULL;
8965             next = xmlXPathNextSelf;
8966             mergeNodeSet = xmlXPathNodeSetMergeUnique;
8967             break;
8968     }
8969     if (next == NULL)
8970         return(0);
8971
8972     nodelist = obj->nodesetval;
8973     if (nodelist == NULL) {
8974         xmlXPathFreeObject(obj);
8975         valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8976         return(0);
8977     }
8978     addNode = xmlXPathNodeSetAddUnique;
8979     ret = NULL;
8980 #ifdef DEBUG_STEP
8981     xmlGenericError(xmlGenericErrorContext,
8982                     " context contains %d nodes\n", nodelist->nodeNr);
8983     switch (test) {
8984         case NODE_TEST_NONE:
8985             xmlGenericError(xmlGenericErrorContext,
8986                             "           searching for none !!!\n");
8987             break;
8988         case NODE_TEST_TYPE:
8989             xmlGenericError(xmlGenericErrorContext,
8990                             "           searching for type %d\n", type);
8991             break;
8992         case NODE_TEST_PI:
8993             xmlGenericError(xmlGenericErrorContext,
8994                             "           searching for PI !!!\n");
8995             break;
8996         case NODE_TEST_ALL:
8997             xmlGenericError(xmlGenericErrorContext,
8998                             "           searching for *\n");
8999             break;
9000         case NODE_TEST_NS:
9001             xmlGenericError(xmlGenericErrorContext,
9002                             "           searching for namespace %s\n",
9003                             prefix);
9004             break;
9005         case NODE_TEST_NAME:
9006             xmlGenericError(xmlGenericErrorContext,
9007                             "           searching for name %s\n", name);
9008             if (prefix != NULL)
9009                 xmlGenericError(xmlGenericErrorContext,
9010                                 "           with namespace %s\n", prefix);
9011             break;
9012     }
9013     xmlGenericError(xmlGenericErrorContext, "Testing : ");
9014 #endif
9015     /*
9016      * 2.3 Node Tests
9017      *  - For the attribute axis, the principal node type is attribute. 
9018      *  - For the namespace axis, the principal node type is namespace. 
9019      *  - For other axes, the principal node type is element. 
9020      *
9021      * A node test * is true for any node of the
9022      * principal node type. For example, child::* will
9023      * select all element children of the context node
9024      */
9025     tmp = ctxt->context->node;
9026     for (i = 0; i < nodelist->nodeNr; i++) {
9027         ctxt->context->node = nodelist->nodeTab[i];
9028
9029         cur = NULL;
9030         list = xmlXPathNodeSetCreate(NULL);
9031         do {
9032             cur = next(ctxt, cur);
9033             if (cur == NULL)
9034                 break;
9035             if ((first != NULL) && (*first == cur))
9036                 break;
9037             if (((t % 256) == 0) &&
9038                 (first != NULL) && (*first != NULL) &&
9039                 (xmlXPathCmpNodes(*first, cur) >= 0))
9040                 break;
9041             if ((last != NULL) && (*last == cur))
9042                 break;
9043             if (((t % 256) == 0) &&
9044                 (last != NULL) && (*last != NULL) &&
9045                 (xmlXPathCmpNodes(cur, *last) >= 0))
9046                 break;
9047             t++;
9048 #ifdef DEBUG_STEP
9049             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9050 #endif
9051             switch (test) {
9052                 case NODE_TEST_NONE:
9053                     ctxt->context->node = tmp;
9054                     STRANGE return(t);
9055                 case NODE_TEST_TYPE:
9056                     if ((cur->type == type) ||
9057                         ((type == NODE_TYPE_NODE) &&
9058                          ((cur->type == XML_DOCUMENT_NODE) ||
9059                           (cur->type == XML_HTML_DOCUMENT_NODE) ||
9060                           (cur->type == XML_ELEMENT_NODE) ||
9061                           (cur->type == XML_NAMESPACE_DECL) ||
9062                           (cur->type == XML_ATTRIBUTE_NODE) ||
9063                           (cur->type == XML_PI_NODE) ||
9064                           (cur->type == XML_COMMENT_NODE) ||
9065                           (cur->type == XML_CDATA_SECTION_NODE) ||
9066                           (cur->type == XML_TEXT_NODE))) ||
9067                         ((type == NODE_TYPE_TEXT) &&
9068                          (cur->type == XML_CDATA_SECTION_NODE))) {
9069 #ifdef DEBUG_STEP
9070                         n++;
9071 #endif
9072                         addNode(list, cur);
9073                     }
9074                     break;
9075                 case NODE_TEST_PI:
9076                     if (cur->type == XML_PI_NODE) {
9077                         if ((name != NULL) &&
9078                             (!xmlStrEqual(name, cur->name)))
9079                             break;
9080 #ifdef DEBUG_STEP
9081                         n++;
9082 #endif
9083                         addNode(list, cur);
9084                     }
9085                     break;
9086                 case NODE_TEST_ALL:
9087                     if (axis == AXIS_ATTRIBUTE) {
9088                         if (cur->type == XML_ATTRIBUTE_NODE) {
9089 #ifdef DEBUG_STEP
9090                             n++;
9091 #endif
9092                             addNode(list, cur);
9093                         }
9094                     } else if (axis == AXIS_NAMESPACE) {
9095                         if (cur->type == XML_NAMESPACE_DECL) {
9096 #ifdef DEBUG_STEP
9097                             n++;
9098 #endif
9099                             xmlXPathNodeSetAddNs(list, ctxt->context->node, 
9100                                                  (xmlNsPtr) cur);
9101                         }
9102                     } else {
9103                         if (cur->type == XML_ELEMENT_NODE) {
9104                             if (prefix == NULL) {
9105 #ifdef DEBUG_STEP
9106                                 n++;
9107 #endif
9108                                 addNode(list, cur);
9109                             } else if ((cur->ns != NULL) &&
9110                                        (xmlStrEqual(URI, cur->ns->href))) {
9111 #ifdef DEBUG_STEP
9112                                 n++;
9113 #endif
9114                                 addNode(list, cur);
9115                             }
9116                         }
9117                     }
9118                     break;
9119                 case NODE_TEST_NS:{
9120                         TODO;
9121                         break;
9122                     }
9123                 case NODE_TEST_NAME:
9124                     switch (cur->type) {
9125                         case XML_ELEMENT_NODE:
9126                             if (xmlStrEqual(name, cur->name)) {
9127                                 if (prefix == NULL) {
9128                                     if (cur->ns == NULL) {
9129 #ifdef DEBUG_STEP
9130                                         n++;
9131 #endif
9132                                         addNode(list, cur);
9133                                     }
9134                                 } else {
9135                                     if ((cur->ns != NULL) &&
9136                                         (xmlStrEqual(URI,
9137                                                      cur->ns->href))) {
9138 #ifdef DEBUG_STEP
9139                                         n++;
9140 #endif
9141                                         addNode(list, cur);
9142                                     }
9143                                 }
9144                             }
9145                             break;
9146                         case XML_ATTRIBUTE_NODE:{
9147                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
9148
9149                                 if (xmlStrEqual(name, attr->name)) {
9150                                     if (prefix == NULL) {
9151                                         if ((attr->ns == NULL) ||
9152                                             (attr->ns->prefix == NULL)) {
9153 #ifdef DEBUG_STEP
9154                                             n++;
9155 #endif
9156                                             addNode(list,
9157                                                     (xmlNodePtr) attr);
9158                                         }
9159                                     } else {
9160                                         if ((attr->ns != NULL) &&
9161                                             (xmlStrEqual(URI,
9162                                                          attr->ns->
9163                                                          href))) {
9164 #ifdef DEBUG_STEP
9165                                             n++;
9166 #endif
9167                                             addNode(list,
9168                                                     (xmlNodePtr) attr);
9169                                         }
9170                                     }
9171                                 }
9172                                 break;
9173                             }
9174                         case XML_NAMESPACE_DECL:
9175                             if (cur->type == XML_NAMESPACE_DECL) {
9176                                 xmlNsPtr ns = (xmlNsPtr) cur;
9177
9178                                 if ((ns->prefix != NULL) && (name != NULL)
9179                                     && (xmlStrEqual(ns->prefix, name))) {
9180 #ifdef DEBUG_STEP
9181                                     n++;
9182 #endif
9183                                     xmlXPathNodeSetAddNs(list,
9184                                         ctxt->context->node, (xmlNsPtr) cur);
9185                                 }
9186                             }
9187                             break;
9188                         default:
9189                             break;
9190                     }
9191                     break;
9192                     break;
9193             }
9194         } while (cur != NULL);
9195
9196         /*
9197          * If there is some predicate filtering do it now
9198          */
9199         if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
9200             xmlXPathObjectPtr obj2;
9201
9202             valuePush(ctxt, xmlXPathWrapNodeSet(list));
9203             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9204             CHECK_TYPE0(XPATH_NODESET);
9205             obj2 = valuePop(ctxt);
9206             list = obj2->nodesetval;
9207             obj2->nodesetval = NULL;
9208             xmlXPathFreeObject(obj2);
9209         }
9210         if (ret == NULL) {
9211             ret = list;
9212         } else {
9213             ret = mergeNodeSet(ret, list);
9214             xmlXPathFreeNodeSet(list);
9215         }
9216     }
9217     ctxt->context->node = tmp;
9218 #ifdef DEBUG_STEP
9219     xmlGenericError(xmlGenericErrorContext,
9220                     "\nExamined %d nodes, found %d nodes at that step\n",
9221                     t, n);
9222 #endif
9223     valuePush(ctxt, xmlXPathWrapNodeSet(ret));
9224     if ((obj->boolval) && (obj->user != NULL)) {
9225         ctxt->value->boolval = 1;
9226         ctxt->value->user = obj->user;
9227         obj->user = NULL;
9228         obj->boolval = 0;
9229     }
9230     xmlXPathFreeObject(obj);
9231     return(t);
9232 }
9233
9234 /**
9235  * xmlXPathNodeCollectAndTestNth:
9236  * @ctxt:  the XPath Parser context
9237  * @op:  the XPath precompiled step operation
9238  * @indx:  the index to collect
9239  * @first:  pointer to the first element in document order
9240  * @last:  pointer to the last element in document order
9241  *
9242  * This is the function implementing a step: based on the current list
9243  * of nodes, it builds up a new list, looking at all nodes under that
9244  * axis and selecting them it also do the predicate filtering
9245  *
9246  * Pushes the new NodeSet resulting from the search.
9247  * Returns the number of node traversed
9248  */
9249 static int
9250 xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9251                               xmlXPathStepOpPtr op, int indx,
9252                               xmlNodePtr * first, xmlNodePtr * last)
9253 {
9254     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9255     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9256     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9257     const xmlChar *prefix = op->value4;
9258     const xmlChar *name = op->value5;
9259     const xmlChar *URI = NULL;
9260     int n = 0, t = 0;
9261
9262     int i;
9263     xmlNodeSetPtr list;
9264     xmlXPathTraversalFunction next = NULL;
9265     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9266     xmlNodePtr cur = NULL;
9267     xmlXPathObjectPtr obj;
9268     xmlNodeSetPtr nodelist;
9269     xmlNodePtr tmp;
9270
9271     CHECK_TYPE0(XPATH_NODESET);
9272     obj = valuePop(ctxt);
9273     addNode = xmlXPathNodeSetAdd;
9274     if (prefix != NULL) {
9275         URI = xmlXPathNsLookup(ctxt->context, prefix);
9276         if (URI == NULL)
9277             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9278     }
9279 #ifdef DEBUG_STEP_NTH
9280     xmlGenericError(xmlGenericErrorContext, "new step : ");
9281     if (first != NULL) {
9282         if (*first != NULL)
9283             xmlGenericError(xmlGenericErrorContext, "first = %s ",
9284                     (*first)->name);
9285         else
9286             xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9287     }
9288     if (last != NULL) {
9289         if (*last != NULL)
9290             xmlGenericError(xmlGenericErrorContext, "last = %s ",
9291                     (*last)->name);
9292         else
9293             xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9294     }
9295 #endif
9296     switch (axis) {
9297         case AXIS_ANCESTOR:
9298 #ifdef DEBUG_STEP_NTH
9299             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9300 #endif
9301             first = NULL;
9302             next = xmlXPathNextAncestor;
9303             break;
9304         case AXIS_ANCESTOR_OR_SELF:
9305 #ifdef DEBUG_STEP_NTH
9306             xmlGenericError(xmlGenericErrorContext,
9307                             "axis 'ancestors-or-self' ");
9308 #endif
9309             first = NULL;
9310             next = xmlXPathNextAncestorOrSelf;
9311             break;
9312         case AXIS_ATTRIBUTE:
9313 #ifdef DEBUG_STEP_NTH
9314             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9315 #endif
9316             first = NULL;
9317             last = NULL;
9318             next = xmlXPathNextAttribute;
9319             break;
9320         case AXIS_CHILD:
9321 #ifdef DEBUG_STEP_NTH
9322             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9323 #endif
9324             last = NULL;
9325             next = xmlXPathNextChild;
9326             break;
9327         case AXIS_DESCENDANT:
9328 #ifdef DEBUG_STEP_NTH
9329             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9330 #endif
9331             last = NULL;
9332             next = xmlXPathNextDescendant;
9333             break;
9334         case AXIS_DESCENDANT_OR_SELF:
9335 #ifdef DEBUG_STEP_NTH
9336             xmlGenericError(xmlGenericErrorContext,
9337                             "axis 'descendant-or-self' ");
9338 #endif
9339             last = NULL;
9340             next = xmlXPathNextDescendantOrSelf;
9341             break;
9342         case AXIS_FOLLOWING:
9343 #ifdef DEBUG_STEP_NTH
9344             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9345 #endif
9346             last = NULL;
9347             next = xmlXPathNextFollowing;
9348             break;
9349         case AXIS_FOLLOWING_SIBLING:
9350 #ifdef DEBUG_STEP_NTH
9351             xmlGenericError(xmlGenericErrorContext,
9352                             "axis 'following-siblings' ");
9353 #endif
9354             last = NULL;
9355             next = xmlXPathNextFollowingSibling;
9356             break;
9357         case AXIS_NAMESPACE:
9358 #ifdef DEBUG_STEP_NTH
9359             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9360 #endif
9361             last = NULL;
9362             first = NULL;
9363             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9364             break;
9365         case AXIS_PARENT:
9366 #ifdef DEBUG_STEP_NTH
9367             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9368 #endif
9369             first = NULL;
9370             next = xmlXPathNextParent;
9371             break;
9372         case AXIS_PRECEDING:
9373 #ifdef DEBUG_STEP_NTH
9374             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9375 #endif
9376             first = NULL;
9377             next = xmlXPathNextPrecedingInternal;
9378             break;
9379         case AXIS_PRECEDING_SIBLING:
9380 #ifdef DEBUG_STEP_NTH
9381             xmlGenericError(xmlGenericErrorContext,
9382                             "axis 'preceding-sibling' ");
9383 #endif
9384             first = NULL;
9385             next = xmlXPathNextPrecedingSibling;
9386             break;
9387         case AXIS_SELF:
9388 #ifdef DEBUG_STEP_NTH
9389             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9390 #endif
9391             first = NULL;
9392             last = NULL;
9393             next = xmlXPathNextSelf;
9394             break;
9395     }
9396     if (next == NULL)
9397         return(0);
9398
9399     nodelist = obj->nodesetval;
9400     if (nodelist == NULL) {
9401         xmlXPathFreeObject(obj);
9402         valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9403         return(0);
9404     }
9405     addNode = xmlXPathNodeSetAddUnique;
9406 #ifdef DEBUG_STEP_NTH
9407     xmlGenericError(xmlGenericErrorContext,
9408                     " context contains %d nodes\n", nodelist->nodeNr);
9409     switch (test) {
9410         case NODE_TEST_NONE:
9411             xmlGenericError(xmlGenericErrorContext,
9412                             "           searching for none !!!\n");
9413             break;
9414         case NODE_TEST_TYPE:
9415             xmlGenericError(xmlGenericErrorContext,
9416                             "           searching for type %d\n", type);
9417             break;
9418         case NODE_TEST_PI:
9419             xmlGenericError(xmlGenericErrorContext,
9420                             "           searching for PI !!!\n");
9421             break;
9422         case NODE_TEST_ALL:
9423             xmlGenericError(xmlGenericErrorContext,
9424                             "           searching for *\n");
9425             break;
9426         case NODE_TEST_NS:
9427             xmlGenericError(xmlGenericErrorContext,
9428                             "           searching for namespace %s\n",
9429                             prefix);
9430             break;
9431         case NODE_TEST_NAME:
9432             xmlGenericError(xmlGenericErrorContext,
9433                             "           searching for name %s\n", name);
9434             if (prefix != NULL)
9435                 xmlGenericError(xmlGenericErrorContext,
9436                                 "           with namespace %s\n", prefix);
9437             break;
9438     }
9439     xmlGenericError(xmlGenericErrorContext, "Testing : ");
9440 #endif
9441     /*
9442      * 2.3 Node Tests
9443      *  - For the attribute axis, the principal node type is attribute. 
9444      *  - For the namespace axis, the principal node type is namespace. 
9445      *  - For other axes, the principal node type is element. 
9446      *
9447      * A node test * is true for any node of the
9448      * principal node type. For example, child::* will
9449      * select all element children of the context node
9450      */
9451     tmp = ctxt->context->node;
9452     list = xmlXPathNodeSetCreate(NULL);
9453     for (i = 0; i < nodelist->nodeNr; i++) {
9454         ctxt->context->node = nodelist->nodeTab[i];
9455
9456         cur = NULL;
9457         n = 0;
9458         do {
9459             cur = next(ctxt, cur);
9460             if (cur == NULL)
9461                 break;
9462             if ((first != NULL) && (*first == cur))
9463                 break;
9464             if (((t % 256) == 0) &&
9465                 (first != NULL) && (*first != NULL) &&
9466                 (xmlXPathCmpNodes(*first, cur) >= 0))
9467                 break;
9468             if ((last != NULL) && (*last == cur))
9469                 break;
9470             if (((t % 256) == 0) &&
9471                 (last != NULL) && (*last != NULL) &&
9472                 (xmlXPathCmpNodes(cur, *last) >= 0))
9473                 break;
9474             t++;
9475             switch (test) {
9476                 case NODE_TEST_NONE:
9477                     ctxt->context->node = tmp;
9478                     STRANGE return(0);
9479                 case NODE_TEST_TYPE:
9480                     if ((cur->type == type) ||
9481                         ((type == NODE_TYPE_NODE) &&
9482                          ((cur->type == XML_DOCUMENT_NODE) ||
9483                           (cur->type == XML_HTML_DOCUMENT_NODE) ||
9484                           (cur->type == XML_ELEMENT_NODE) ||
9485                           (cur->type == XML_PI_NODE) ||
9486                           (cur->type == XML_COMMENT_NODE) ||
9487                           (cur->type == XML_CDATA_SECTION_NODE) ||
9488                           (cur->type == XML_TEXT_NODE))) ||
9489                         ((type == NODE_TYPE_TEXT) &&
9490                          (cur->type == XML_CDATA_SECTION_NODE))) {
9491                         n++;
9492                         if (n == indx)
9493                             addNode(list, cur);
9494                     }
9495                     break;
9496                 case NODE_TEST_PI:
9497                     if (cur->type == XML_PI_NODE) {
9498                         if ((name != NULL) &&
9499                             (!xmlStrEqual(name, cur->name)))
9500                             break;
9501                         n++;
9502                         if (n == indx)
9503                             addNode(list, cur);
9504                     }
9505                     break;
9506                 case NODE_TEST_ALL:
9507                     if (axis == AXIS_ATTRIBUTE) {
9508                         if (cur->type == XML_ATTRIBUTE_NODE) {
9509                             n++;
9510                             if (n == indx)
9511                                 addNode(list, cur);
9512                         }
9513                     } else if (axis == AXIS_NAMESPACE) {
9514                         if (cur->type == XML_NAMESPACE_DECL) {
9515                             n++;
9516                             if (n == indx)
9517                                 xmlXPathNodeSetAddNs(list, ctxt->context->node, 
9518                                                      (xmlNsPtr) cur);
9519                         }
9520                     } else {
9521                         if (cur->type == XML_ELEMENT_NODE) {
9522                             if (prefix == NULL) {
9523                                 n++;
9524                                 if (n == indx)
9525                                     addNode(list, cur);
9526                             } else if ((cur->ns != NULL) &&
9527                                        (xmlStrEqual(URI, cur->ns->href))) {
9528                                 n++;
9529                                 if (n == indx)
9530                                     addNode(list, cur);
9531                             }
9532                         }
9533                     }
9534                     break;
9535                 case NODE_TEST_NS:{
9536                         TODO;
9537                         break;
9538                     }
9539                 case NODE_TEST_NAME:
9540                     switch (cur->type) {
9541                         case XML_ELEMENT_NODE:
9542                             if (xmlStrEqual(name, cur->name)) {
9543                                 if (prefix == NULL) {
9544                                     if (cur->ns == NULL) {
9545                                         n++;
9546                                         if (n == indx)
9547                                             addNode(list, cur);
9548                                     }
9549                                 } else {
9550                                     if ((cur->ns != NULL) &&
9551                                         (xmlStrEqual(URI,
9552                                                      cur->ns->href))) {
9553                                         n++;
9554                                         if (n == indx)
9555                                             addNode(list, cur);
9556                                     }
9557                                 }
9558                             }
9559                             break;
9560                         case XML_ATTRIBUTE_NODE:{
9561                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
9562
9563                                 if (xmlStrEqual(name, attr->name)) {
9564                                     if (prefix == NULL) {
9565                                         if ((attr->ns == NULL) ||
9566                                             (attr->ns->prefix == NULL)) {
9567                                             n++;
9568                                             if (n == indx)
9569                                                 addNode(list, cur);
9570                                         }
9571                                     } else {
9572                                         if ((attr->ns != NULL) &&
9573                                             (xmlStrEqual(URI,
9574                                                          attr->ns->
9575                                                          href))) {
9576                                             n++;
9577                                             if (n == indx)
9578                                                 addNode(list, cur);
9579                                         }
9580                                     }
9581                                 }
9582                                 break;
9583                             }
9584                         case XML_NAMESPACE_DECL:
9585                             if (cur->type == XML_NAMESPACE_DECL) {
9586                                 xmlNsPtr ns = (xmlNsPtr) cur;
9587
9588                                 if ((ns->prefix != NULL) && (name != NULL)
9589                                     && (xmlStrEqual(ns->prefix, name))) {
9590                                     n++;
9591                                     if (n == indx)
9592                                         xmlXPathNodeSetAddNs(list,
9593                                            ctxt->context->node, (xmlNsPtr) cur);
9594                                 }
9595                             }
9596                             break;
9597                         default:
9598                             break;
9599                     }
9600                     break;
9601                     break;
9602             }
9603         } while (n < indx);
9604     }
9605     ctxt->context->node = tmp;
9606 #ifdef DEBUG_STEP_NTH
9607     xmlGenericError(xmlGenericErrorContext,
9608                     "\nExamined %d nodes, found %d nodes at that step\n",
9609                     t, list->nodeNr);
9610 #endif
9611     valuePush(ctxt, xmlXPathWrapNodeSet(list));
9612     if ((obj->boolval) && (obj->user != NULL)) {
9613         ctxt->value->boolval = 1;
9614         ctxt->value->user = obj->user;
9615         obj->user = NULL;
9616         obj->boolval = 0;
9617     }
9618     xmlXPathFreeObject(obj);
9619     return(t);
9620 }
9621
9622 /**
9623  * xmlXPathCompOpEvalFirst:
9624  * @ctxt:  the XPath parser context with the compiled expression
9625  * @op:  an XPath compiled operation
9626  * @first:  the first elem found so far
9627  *
9628  * Evaluate the Precompiled XPath operation searching only the first
9629  * element in document order
9630  *
9631  * Returns the number of examined objects.
9632  */
9633 static int
9634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9635                         xmlXPathStepOpPtr op, xmlNodePtr * first)
9636 {
9637     int total = 0, cur;
9638     xmlXPathCompExprPtr comp;
9639     xmlXPathObjectPtr arg1, arg2;
9640
9641     CHECK_ERROR0;
9642     comp = ctxt->comp;
9643     switch (op->op) {
9644         case XPATH_OP_END:
9645             return (0);
9646         case XPATH_OP_UNION:
9647             total =
9648                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9649                                         first);
9650             CHECK_ERROR0;
9651             if ((ctxt->value != NULL)
9652                 && (ctxt->value->type == XPATH_NODESET)
9653                 && (ctxt->value->nodesetval != NULL)
9654                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9655                 /*
9656                  * limit tree traversing to first node in the result
9657                  */
9658                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9659                 *first = ctxt->value->nodesetval->nodeTab[0];
9660             }
9661             cur =
9662                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9663                                         first);
9664             CHECK_ERROR0;
9665             CHECK_TYPE0(XPATH_NODESET);
9666             arg2 = valuePop(ctxt);
9667
9668             CHECK_TYPE0(XPATH_NODESET);
9669             arg1 = valuePop(ctxt);
9670
9671             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9672                                                     arg2->nodesetval);
9673             valuePush(ctxt, arg1);
9674             xmlXPathFreeObject(arg2);
9675             /* optimizer */
9676             if (total > cur)
9677                 xmlXPathCompSwap(op);
9678             return (total + cur);
9679         case XPATH_OP_ROOT:
9680             xmlXPathRoot(ctxt);
9681             return (0);
9682         case XPATH_OP_NODE:
9683             if (op->ch1 != -1)
9684                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9685             CHECK_ERROR0;
9686             if (op->ch2 != -1)
9687                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9688             CHECK_ERROR0;
9689             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9690             return (total);
9691         case XPATH_OP_RESET:
9692             if (op->ch1 != -1)
9693                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9694             CHECK_ERROR0;
9695             if (op->ch2 != -1)
9696                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9697             CHECK_ERROR0;
9698             ctxt->context->node = NULL;
9699             return (total);
9700         case XPATH_OP_COLLECT:{
9701                 if (op->ch1 == -1)
9702                     return (total);
9703
9704                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9705                 CHECK_ERROR0;
9706
9707                 /*
9708                  * Optimization for [n] selection where n is a number
9709                  */
9710                 if ((op->ch2 != -1) &&
9711                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9712                     (comp->steps[op->ch2].ch1 == -1) &&
9713                     (comp->steps[op->ch2].ch2 != -1) &&
9714                     (comp->steps[comp->steps[op->ch2].ch2].op ==
9715                      XPATH_OP_VALUE)) {
9716                     xmlXPathObjectPtr val;
9717
9718                     val = comp->steps[comp->steps[op->ch2].ch2].value4;
9719                     if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9720                         int indx = (int) val->floatval;
9721
9722                         if (val->floatval == (float) indx) {
9723                             xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9724                                                           first, NULL);
9725                             return (total);
9726                         }
9727                     }
9728                 }
9729                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9730                 return (total);
9731             }
9732         case XPATH_OP_VALUE:
9733             valuePush(ctxt,
9734                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9735             return (0);
9736         case XPATH_OP_SORT:
9737             if (op->ch1 != -1)
9738                 total +=
9739                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9740                                             first);
9741             CHECK_ERROR0;
9742             if ((ctxt->value != NULL)
9743                 && (ctxt->value->type == XPATH_NODESET)
9744                 && (ctxt->value->nodesetval != NULL))
9745                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9746             return (total);
9747         default:
9748             return (xmlXPathCompOpEval(ctxt, op));
9749     }
9750 }
9751
9752 /**
9753  * xmlXPathCompOpEvalLast:
9754  * @ctxt:  the XPath parser context with the compiled expression
9755  * @op:  an XPath compiled operation
9756  * @last:  the last elem found so far
9757  *
9758  * Evaluate the Precompiled XPath operation searching only the last
9759  * element in document order
9760  *
9761  * Returns the number of node traversed
9762  */
9763 static int
9764 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9765                        xmlNodePtr * last)
9766 {
9767     int total = 0, cur;
9768     xmlXPathCompExprPtr comp;
9769     xmlXPathObjectPtr arg1, arg2;
9770
9771     CHECK_ERROR0;
9772     comp = ctxt->comp;
9773     switch (op->op) {
9774         case XPATH_OP_END:
9775             return (0);
9776         case XPATH_OP_UNION:
9777             total =
9778                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
9779             CHECK_ERROR0;
9780             if ((ctxt->value != NULL)
9781                 && (ctxt->value->type == XPATH_NODESET)
9782                 && (ctxt->value->nodesetval != NULL)
9783                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9784                 /*
9785                  * limit tree traversing to first node in the result
9786                  */
9787                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9788                 *last =
9789                     ctxt->value->nodesetval->nodeTab[ctxt->value->
9790                                                      nodesetval->nodeNr -
9791                                                      1];
9792             }
9793             cur =
9794                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
9795             CHECK_ERROR0;
9796             if ((ctxt->value != NULL)
9797                 && (ctxt->value->type == XPATH_NODESET)
9798                 && (ctxt->value->nodesetval != NULL)
9799                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9800             }
9801             CHECK_TYPE0(XPATH_NODESET);
9802             arg2 = valuePop(ctxt);
9803
9804             CHECK_TYPE0(XPATH_NODESET);
9805             arg1 = valuePop(ctxt);
9806
9807             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9808                                                     arg2->nodesetval);
9809             valuePush(ctxt, arg1);
9810             xmlXPathFreeObject(arg2);
9811             /* optimizer */
9812             if (total > cur)
9813                 xmlXPathCompSwap(op);
9814             return (total + cur);
9815         case XPATH_OP_ROOT:
9816             xmlXPathRoot(ctxt);
9817             return (0);
9818         case XPATH_OP_NODE:
9819             if (op->ch1 != -1)
9820                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9821             CHECK_ERROR0;
9822             if (op->ch2 != -1)
9823                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9824             CHECK_ERROR0;
9825             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9826             return (total);
9827         case XPATH_OP_RESET:
9828             if (op->ch1 != -1)
9829                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9830             CHECK_ERROR0;
9831             if (op->ch2 != -1)
9832                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9833             CHECK_ERROR0;
9834             ctxt->context->node = NULL;
9835             return (total);
9836         case XPATH_OP_COLLECT:{
9837                 if (op->ch1 == -1)
9838                     return (0);
9839
9840                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9841                 CHECK_ERROR0;
9842
9843                 /*
9844                  * Optimization for [n] selection where n is a number
9845                  */
9846                 if ((op->ch2 != -1) &&
9847                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9848                     (comp->steps[op->ch2].ch1 == -1) &&
9849                     (comp->steps[op->ch2].ch2 != -1) &&
9850                     (comp->steps[comp->steps[op->ch2].ch2].op ==
9851                      XPATH_OP_VALUE)) {
9852                     xmlXPathObjectPtr val;
9853
9854                     val = comp->steps[comp->steps[op->ch2].ch2].value4;
9855                     if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9856                         int indx = (int) val->floatval;
9857
9858                         if (val->floatval == (float) indx) {
9859                             total +=
9860                                 xmlXPathNodeCollectAndTestNth(ctxt, op,
9861                                                               indx, NULL,
9862                                                               last);
9863                             return (total);
9864                         }
9865                     }
9866                 }
9867                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9868                 return (total);
9869             }
9870         case XPATH_OP_VALUE:
9871             valuePush(ctxt,
9872                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9873             return (0);
9874         case XPATH_OP_SORT:
9875             if (op->ch1 != -1)
9876                 total +=
9877                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9878                                            last);
9879             CHECK_ERROR0;
9880             if ((ctxt->value != NULL)
9881                 && (ctxt->value->type == XPATH_NODESET)
9882                 && (ctxt->value->nodesetval != NULL))
9883                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9884             return (total);
9885         default:
9886             return (xmlXPathCompOpEval(ctxt, op));
9887     }
9888 }
9889
9890 /**
9891  * xmlXPathCompOpEval:
9892  * @ctxt:  the XPath parser context with the compiled expression
9893  * @op:  an XPath compiled operation
9894  *
9895  * Evaluate the Precompiled XPath operation
9896  * Returns the number of node traversed
9897  */
9898 static int
9899 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9900 {
9901     int total = 0;
9902     int equal, ret;
9903     xmlXPathCompExprPtr comp;
9904     xmlXPathObjectPtr arg1, arg2;
9905     xmlNodePtr bak;
9906     xmlDocPtr bakd;
9907     int pp;
9908     int cs;
9909
9910     CHECK_ERROR0;
9911     comp = ctxt->comp;
9912     switch (op->op) {
9913         case XPATH_OP_END:
9914             return (0);
9915         case XPATH_OP_AND:
9916             bakd = ctxt->context->doc;
9917             bak = ctxt->context->node;
9918             pp = ctxt->context->proximityPosition;
9919             cs = ctxt->context->contextSize;
9920             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9921             CHECK_ERROR0;
9922             xmlXPathBooleanFunction(ctxt, 1);
9923             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9924                 return (total);
9925             arg2 = valuePop(ctxt);
9926             ctxt->context->doc = bakd;
9927             ctxt->context->node = bak;
9928             ctxt->context->proximityPosition = pp;
9929             ctxt->context->contextSize = cs;
9930             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9931             if (ctxt->error) {
9932                 xmlXPathFreeObject(arg2);
9933                 return(0);
9934             }
9935             xmlXPathBooleanFunction(ctxt, 1);
9936             arg1 = valuePop(ctxt);
9937             arg1->boolval &= arg2->boolval;
9938             valuePush(ctxt, arg1);
9939             xmlXPathFreeObject(arg2);
9940             return (total);
9941         case XPATH_OP_OR:
9942             bakd = ctxt->context->doc;
9943             bak = ctxt->context->node;
9944             pp = ctxt->context->proximityPosition;
9945             cs = ctxt->context->contextSize;
9946             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9947             CHECK_ERROR0;
9948             xmlXPathBooleanFunction(ctxt, 1);
9949             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9950                 return (total);
9951             arg2 = valuePop(ctxt);
9952             ctxt->context->doc = bakd;
9953             ctxt->context->node = bak;
9954             ctxt->context->proximityPosition = pp;
9955             ctxt->context->contextSize = cs;
9956             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9957             if (ctxt->error) {
9958                 xmlXPathFreeObject(arg2);
9959                 return(0);
9960             }
9961             xmlXPathBooleanFunction(ctxt, 1);
9962             arg1 = valuePop(ctxt);
9963             arg1->boolval |= arg2->boolval;
9964             valuePush(ctxt, arg1);
9965             xmlXPathFreeObject(arg2);
9966             return (total);
9967         case XPATH_OP_EQUAL:
9968             bakd = ctxt->context->doc;
9969             bak = ctxt->context->node;
9970             pp = ctxt->context->proximityPosition;
9971             cs = ctxt->context->contextSize;
9972             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9973             CHECK_ERROR0;
9974             ctxt->context->doc = bakd;
9975             ctxt->context->node = bak;
9976             ctxt->context->proximityPosition = pp;
9977             ctxt->context->contextSize = cs;
9978             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9979             CHECK_ERROR0;
9980             if (op->value)
9981                 equal = xmlXPathEqualValues(ctxt);
9982             else
9983                 equal = xmlXPathNotEqualValues(ctxt);
9984             valuePush(ctxt, xmlXPathNewBoolean(equal));
9985             return (total);
9986         case XPATH_OP_CMP:
9987             bakd = ctxt->context->doc;
9988             bak = ctxt->context->node;
9989             pp = ctxt->context->proximityPosition;
9990             cs = ctxt->context->contextSize;
9991             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9992             CHECK_ERROR0;
9993             ctxt->context->doc = bakd;
9994             ctxt->context->node = bak;
9995             ctxt->context->proximityPosition = pp;
9996             ctxt->context->contextSize = cs;
9997             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9998             CHECK_ERROR0;
9999             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10000             valuePush(ctxt, xmlXPathNewBoolean(ret));
10001             return (total);
10002         case XPATH_OP_PLUS:
10003             bakd = ctxt->context->doc;
10004             bak = ctxt->context->node;
10005             pp = ctxt->context->proximityPosition;
10006             cs = ctxt->context->contextSize;
10007             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10008             CHECK_ERROR0;
10009             if (op->ch2 != -1) {
10010                 ctxt->context->doc = bakd;
10011                 ctxt->context->node = bak;
10012                 ctxt->context->proximityPosition = pp;
10013                 ctxt->context->contextSize = cs;
10014                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10015             }
10016             CHECK_ERROR0;
10017             if (op->value == 0)
10018                 xmlXPathSubValues(ctxt);
10019             else if (op->value == 1)
10020                 xmlXPathAddValues(ctxt);
10021             else if (op->value == 2)
10022                 xmlXPathValueFlipSign(ctxt);
10023             else if (op->value == 3) {
10024                 CAST_TO_NUMBER;
10025                 CHECK_TYPE0(XPATH_NUMBER);
10026             }
10027             return (total);
10028         case XPATH_OP_MULT:
10029             bakd = ctxt->context->doc;
10030             bak = ctxt->context->node;
10031             pp = ctxt->context->proximityPosition;
10032             cs = ctxt->context->contextSize;
10033             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10034             CHECK_ERROR0;
10035             ctxt->context->doc = bakd;
10036             ctxt->context->node = bak;
10037             ctxt->context->proximityPosition = pp;
10038             ctxt->context->contextSize = cs;
10039             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10040             CHECK_ERROR0;
10041             if (op->value == 0)
10042                 xmlXPathMultValues(ctxt);
10043             else if (op->value == 1)
10044                 xmlXPathDivValues(ctxt);
10045             else if (op->value == 2)
10046                 xmlXPathModValues(ctxt);
10047             return (total);
10048         case XPATH_OP_UNION:
10049             bakd = ctxt->context->doc;
10050             bak = ctxt->context->node;
10051             pp = ctxt->context->proximityPosition;
10052             cs = ctxt->context->contextSize;
10053             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10054             CHECK_ERROR0;
10055             ctxt->context->doc = bakd;
10056             ctxt->context->node = bak;
10057             ctxt->context->proximityPosition = pp;
10058             ctxt->context->contextSize = cs;
10059             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10060             CHECK_ERROR0;
10061             CHECK_TYPE0(XPATH_NODESET);
10062             arg2 = valuePop(ctxt);
10063
10064             CHECK_TYPE0(XPATH_NODESET);
10065             arg1 = valuePop(ctxt);
10066
10067             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10068                                                     arg2->nodesetval);
10069             valuePush(ctxt, arg1);
10070             xmlXPathFreeObject(arg2);
10071             return (total);
10072         case XPATH_OP_ROOT:
10073             xmlXPathRoot(ctxt);
10074             return (total);
10075         case XPATH_OP_NODE:
10076             if (op->ch1 != -1)
10077                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10078             CHECK_ERROR0;
10079             if (op->ch2 != -1)
10080                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10081             CHECK_ERROR0;
10082             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10083             return (total);
10084         case XPATH_OP_RESET:
10085             if (op->ch1 != -1)
10086                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10087             CHECK_ERROR0;
10088             if (op->ch2 != -1)
10089                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10090             CHECK_ERROR0;
10091             ctxt->context->node = NULL;
10092             return (total);
10093         case XPATH_OP_COLLECT:{
10094                 if (op->ch1 == -1)
10095                     return (total);
10096
10097                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10098                 CHECK_ERROR0;
10099
10100                 /*
10101                  * Optimization for [n] selection where n is a number
10102                  */
10103                 if ((op->ch2 != -1) &&
10104                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10105                     (comp->steps[op->ch2].ch1 == -1) &&
10106                     (comp->steps[op->ch2].ch2 != -1) &&
10107                     (comp->steps[comp->steps[op->ch2].ch2].op ==
10108                      XPATH_OP_VALUE)) {
10109                     xmlXPathObjectPtr val;
10110
10111                     val = comp->steps[comp->steps[op->ch2].ch2].value4;
10112                     if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10113                         int indx = (int) val->floatval;
10114
10115                         if (val->floatval == (float) indx) {
10116                             total +=
10117                                 xmlXPathNodeCollectAndTestNth(ctxt, op,
10118                                                               indx, NULL,
10119                                                               NULL);
10120                             return (total);
10121                         }
10122                     }
10123                 }
10124                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10125                 return (total);
10126             }
10127         case XPATH_OP_VALUE:
10128             valuePush(ctxt,
10129                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10130             return (total);
10131         case XPATH_OP_VARIABLE:{
10132                 xmlXPathObjectPtr val;
10133
10134                 if (op->ch1 != -1)
10135                     total +=
10136                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10137                 if (op->value5 == NULL) {
10138                     val = xmlXPathVariableLookup(ctxt->context, op->value4);
10139                     if (val == NULL) {
10140                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10141                         return(0);
10142                     }
10143                     valuePush(ctxt, val);
10144                 } else {
10145                     const xmlChar *URI;
10146
10147                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
10148                     if (URI == NULL) {
10149                         xmlGenericError(xmlGenericErrorContext,
10150                                         "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
10151                                         op->value4, op->value5);
10152                         return (total);
10153                     }
10154                     val = xmlXPathVariableLookupNS(ctxt->context,
10155                                                        op->value4, URI);
10156                     if (val == NULL) {
10157                         ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10158                         return(0);
10159                     }
10160                     valuePush(ctxt, val);
10161                 }
10162                 return (total);
10163             }
10164         case XPATH_OP_FUNCTION:{
10165                 xmlXPathFunction func;
10166                 const xmlChar *oldFunc, *oldFuncURI;
10167                 int i;
10168
10169                 if (op->ch1 != -1)
10170                     total +=
10171                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10172                 if (ctxt->valueNr < op->value) {
10173                     xmlGenericError(xmlGenericErrorContext,
10174                             "xmlXPathCompOpEval: parameter error\n");
10175                     ctxt->error = XPATH_INVALID_OPERAND;
10176                     return (total);
10177                 }
10178                 for (i = 0; i < op->value; i++)
10179                     if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10180                         xmlGenericError(xmlGenericErrorContext,
10181                                 "xmlXPathCompOpEval: parameter error\n");
10182                         ctxt->error = XPATH_INVALID_OPERAND;
10183                         return (total);
10184                     }
10185                 if (op->cache != NULL)
10186                     func = (xmlXPathFunction) op->cache;
10187                 else {
10188                     const xmlChar *URI = NULL;
10189
10190                     if (op->value5 == NULL)
10191                         func =
10192                             xmlXPathFunctionLookup(ctxt->context,
10193                                                    op->value4);
10194                     else {
10195                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
10196                         if (URI == NULL) {
10197                             xmlGenericError(xmlGenericErrorContext,
10198                                             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
10199                                             op->value4, op->value5);
10200                             return (total);
10201                         }
10202                         func = xmlXPathFunctionLookupNS(ctxt->context,
10203                                                         op->value4, URI);
10204                     }
10205                     if (func == NULL) {
10206                         xmlGenericError(xmlGenericErrorContext,
10207                                         "xmlXPathCompOpEval: function %s not found\n",
10208                                         op->value4);
10209                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
10210                     }
10211                     op->cache = (void *) func;
10212                     op->cacheURI = (void *) URI;
10213                 }
10214                 oldFunc = ctxt->context->function;
10215                 oldFuncURI = ctxt->context->functionURI;
10216                 ctxt->context->function = op->value4;
10217                 ctxt->context->functionURI = op->cacheURI;
10218                 func(ctxt, op->value);
10219                 ctxt->context->function = oldFunc;
10220                 ctxt->context->functionURI = oldFuncURI;
10221                 return (total);
10222             }
10223         case XPATH_OP_ARG:
10224             bakd = ctxt->context->doc;
10225             bak = ctxt->context->node;
10226             if (op->ch1 != -1)
10227                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10228             ctxt->context->doc = bakd;
10229             ctxt->context->node = bak;
10230             CHECK_ERROR0;
10231             if (op->ch2 != -1)
10232                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10233             ctxt->context->doc = bakd;
10234             ctxt->context->node = bak;
10235             CHECK_ERROR0;
10236             return (total);
10237         case XPATH_OP_PREDICATE:
10238         case XPATH_OP_FILTER:{
10239                 xmlXPathObjectPtr res;
10240                 xmlXPathObjectPtr obj, tmp;
10241                 xmlNodeSetPtr newset = NULL;
10242                 xmlNodeSetPtr oldset;
10243                 xmlNodePtr oldnode;
10244                 int i;
10245
10246                 /*
10247                  * Optimization for ()[1] selection i.e. the first elem
10248                  */
10249                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10250                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10251                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10252                     xmlXPathObjectPtr val;
10253
10254                     val = comp->steps[op->ch2].value4;
10255                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10256                         (val->floatval == 1.0)) {
10257                         xmlNodePtr first = NULL;
10258
10259                         total +=
10260                             xmlXPathCompOpEvalFirst(ctxt,
10261                                                     &comp->steps[op->ch1],
10262                                                     &first);
10263                         CHECK_ERROR0;
10264                         /*
10265                          * The nodeset should be in document order,
10266                          * Keep only the first value
10267                          */
10268                         if ((ctxt->value != NULL) &&
10269                             (ctxt->value->type == XPATH_NODESET) &&
10270                             (ctxt->value->nodesetval != NULL) &&
10271                             (ctxt->value->nodesetval->nodeNr > 1))
10272                             ctxt->value->nodesetval->nodeNr = 1;
10273                         return (total);
10274                     }
10275                 }
10276                 /*
10277                  * Optimization for ()[last()] selection i.e. the last elem
10278                  */
10279                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10280                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10281                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10282                     int f = comp->steps[op->ch2].ch1;
10283
10284                     if ((f != -1) &&
10285                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10286                         (comp->steps[f].value5 == NULL) &&
10287                         (comp->steps[f].value == 0) &&
10288                         (comp->steps[f].value4 != NULL) &&
10289                         (xmlStrEqual
10290                          (comp->steps[f].value4, BAD_CAST "last"))) {
10291                         xmlNodePtr last = NULL;
10292
10293                         total +=
10294                             xmlXPathCompOpEvalLast(ctxt,
10295                                                    &comp->steps[op->ch1],
10296                                                    &last);
10297                         CHECK_ERROR0;
10298                         /*
10299                          * The nodeset should be in document order,
10300                          * Keep only the last value
10301                          */
10302                         if ((ctxt->value != NULL) &&
10303                             (ctxt->value->type == XPATH_NODESET) &&
10304                             (ctxt->value->nodesetval != NULL) &&
10305                             (ctxt->value->nodesetval->nodeTab != NULL) &&
10306                             (ctxt->value->nodesetval->nodeNr > 1)) {
10307                             ctxt->value->nodesetval->nodeTab[0] =
10308                                 ctxt->value->nodesetval->nodeTab[ctxt->
10309                                                                  value->
10310                                                                  nodesetval->
10311                                                                  nodeNr -
10312                                                                  1];
10313                             ctxt->value->nodesetval->nodeNr = 1;
10314                         }
10315                         return (total);
10316                     }
10317                 }
10318
10319                 if (op->ch1 != -1)
10320                     total +=
10321                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10322                 CHECK_ERROR0;
10323                 if (op->ch2 == -1)
10324                     return (total);
10325                 if (ctxt->value == NULL)
10326                     return (total);
10327
10328                 oldnode = ctxt->context->node;
10329
10330 #ifdef LIBXML_XPTR_ENABLED
10331                 /*
10332                  * Hum are we filtering the result of an XPointer expression
10333                  */
10334                 if (ctxt->value->type == XPATH_LOCATIONSET) {
10335                     xmlLocationSetPtr newlocset = NULL;
10336                     xmlLocationSetPtr oldlocset;
10337
10338                     /*
10339                      * Extract the old locset, and then evaluate the result of the
10340                      * expression for all the element in the locset. use it to grow
10341                      * up a new locset.
10342                      */
10343                     CHECK_TYPE0(XPATH_LOCATIONSET);
10344                     obj = valuePop(ctxt);
10345                     oldlocset = obj->user;
10346                     ctxt->context->node = NULL;
10347
10348                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10349                         ctxt->context->contextSize = 0;
10350                         ctxt->context->proximityPosition = 0;
10351                         if (op->ch2 != -1)
10352                             total +=
10353                                 xmlXPathCompOpEval(ctxt,
10354                                                    &comp->steps[op->ch2]);
10355                         res = valuePop(ctxt);
10356                         if (res != NULL)
10357                             xmlXPathFreeObject(res);
10358                         valuePush(ctxt, obj);
10359                         CHECK_ERROR0;
10360                         return (total);
10361                     }
10362                     newlocset = xmlXPtrLocationSetCreate(NULL);
10363
10364                     for (i = 0; i < oldlocset->locNr; i++) {
10365                         /*
10366                          * Run the evaluation with a node list made of a
10367                          * single item in the nodelocset.
10368                          */
10369                         ctxt->context->node = oldlocset->locTab[i]->user;
10370                         tmp = xmlXPathNewNodeSet(ctxt->context->node);
10371                         valuePush(ctxt, tmp);
10372                         ctxt->context->contextSize = oldlocset->locNr;
10373                         ctxt->context->proximityPosition = i + 1;
10374
10375                         if (op->ch2 != -1)
10376                             total +=
10377                                 xmlXPathCompOpEval(ctxt,
10378                                                    &comp->steps[op->ch2]);
10379                         CHECK_ERROR0;
10380
10381                         /*
10382                          * The result of the evaluation need to be tested to
10383                          * decided whether the filter succeeded or not
10384                          */
10385                         res = valuePop(ctxt);
10386                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10387                             xmlXPtrLocationSetAdd(newlocset,
10388                                                   xmlXPathObjectCopy
10389                                                   (oldlocset->locTab[i]));
10390                         }
10391
10392                         /*
10393                          * Cleanup
10394                          */
10395                         if (res != NULL)
10396                             xmlXPathFreeObject(res);
10397                         if (ctxt->value == tmp) {
10398                             res = valuePop(ctxt);
10399                             xmlXPathFreeObject(res);
10400                         }
10401
10402                         ctxt->context->node = NULL;
10403                     }
10404
10405                     /*
10406                      * The result is used as the new evaluation locset.
10407                      */
10408                     xmlXPathFreeObject(obj);
10409                     ctxt->context->node = NULL;
10410                     ctxt->context->contextSize = -1;
10411                     ctxt->context->proximityPosition = -1;
10412                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10413                     ctxt->context->node = oldnode;
10414                     return (total);
10415                 }
10416 #endif /* LIBXML_XPTR_ENABLED */
10417
10418                 /*
10419                  * Extract the old set, and then evaluate the result of the
10420                  * expression for all the element in the set. use it to grow
10421                  * up a new set.
10422                  */
10423                 CHECK_TYPE0(XPATH_NODESET);
10424                 obj = valuePop(ctxt);
10425                 oldset = obj->nodesetval;
10426
10427                 oldnode = ctxt->context->node;
10428                 ctxt->context->node = NULL;
10429
10430                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10431                     ctxt->context->contextSize = 0;
10432                     ctxt->context->proximityPosition = 0;
10433                     if (op->ch2 != -1)
10434                         total +=
10435                             xmlXPathCompOpEval(ctxt,
10436                                                &comp->steps[op->ch2]);
10437                     CHECK_ERROR0;
10438                     res = valuePop(ctxt);
10439                     if (res != NULL)
10440                         xmlXPathFreeObject(res);
10441                     valuePush(ctxt, obj);
10442                     ctxt->context->node = oldnode;
10443                     CHECK_ERROR0;
10444                 } else {
10445                     /*
10446                      * Initialize the new set.
10447                      */
10448                     newset = xmlXPathNodeSetCreate(NULL);
10449
10450                     for (i = 0; i < oldset->nodeNr; i++) {
10451                         /*
10452                          * Run the evaluation with a node list made of
10453                          * a single item in the nodeset.
10454                          */
10455                         ctxt->context->node = oldset->nodeTab[i];
10456                         tmp = xmlXPathNewNodeSet(ctxt->context->node);
10457                         valuePush(ctxt, tmp);
10458                         ctxt->context->contextSize = oldset->nodeNr;
10459                         ctxt->context->proximityPosition = i + 1;
10460
10461                         if (op->ch2 != -1)
10462                             total +=
10463                                 xmlXPathCompOpEval(ctxt,
10464                                                    &comp->steps[op->ch2]);
10465                         CHECK_ERROR0;
10466
10467                         /*
10468                          * The result of the evaluation need to be tested to
10469                          * decided whether the filter succeeded or not
10470                          */
10471                         res = valuePop(ctxt);
10472                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10473                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10474                         }
10475
10476                         /*
10477                          * Cleanup
10478                          */
10479                         if (res != NULL)
10480                             xmlXPathFreeObject(res);
10481                         if (ctxt->value == tmp) {
10482                             res = valuePop(ctxt);
10483                             xmlXPathFreeObject(res);
10484                         }
10485
10486                         ctxt->context->node = NULL;
10487                     }
10488
10489                     /*
10490                      * The result is used as the new evaluation set.
10491                      */
10492                     xmlXPathFreeObject(obj);
10493                     ctxt->context->node = NULL;
10494                     ctxt->context->contextSize = -1;
10495                     ctxt->context->proximityPosition = -1;
10496                     valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10497                 }
10498                 ctxt->context->node = oldnode;
10499                 return (total);
10500             }
10501         case XPATH_OP_SORT:
10502             if (op->ch1 != -1)
10503                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10504             CHECK_ERROR0;
10505             if ((ctxt->value != NULL) &&
10506                 (ctxt->value->type == XPATH_NODESET) &&
10507                 (ctxt->value->nodesetval != NULL))
10508                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10509             return (total);
10510 #ifdef LIBXML_XPTR_ENABLED
10511         case XPATH_OP_RANGETO:{
10512                 xmlXPathObjectPtr range;
10513                 xmlXPathObjectPtr res, obj;
10514                 xmlXPathObjectPtr tmp;
10515                 xmlLocationSetPtr newset = NULL;
10516                 xmlNodeSetPtr oldset;
10517                 int i;
10518
10519                 if (op->ch1 != -1)
10520                     total +=
10521                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10522                 if (op->ch2 == -1)
10523                     return (total);
10524
10525                 CHECK_TYPE0(XPATH_NODESET);
10526                 obj = valuePop(ctxt);
10527                 oldset = obj->nodesetval;
10528                 ctxt->context->node = NULL;
10529
10530                 newset = xmlXPtrLocationSetCreate(NULL);
10531
10532                 if (oldset != NULL) {
10533                     for (i = 0; i < oldset->nodeNr; i++) {
10534                         /*
10535                          * Run the evaluation with a node list made of a single item
10536                          * in the nodeset.
10537                          */
10538                         ctxt->context->node = oldset->nodeTab[i];
10539                         tmp = xmlXPathNewNodeSet(ctxt->context->node);
10540                         valuePush(ctxt, tmp);
10541
10542                         if (op->ch2 != -1)
10543                             total +=
10544                                 xmlXPathCompOpEval(ctxt,
10545                                                    &comp->steps[op->ch2]);
10546                         CHECK_ERROR0;
10547
10548                         /*
10549                          * The result of the evaluation need to be tested to
10550                          * decided whether the filter succeeded or not
10551                          */
10552                         res = valuePop(ctxt);
10553                         range =
10554                             xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10555                                                       res);
10556                         if (range != NULL) {
10557                             xmlXPtrLocationSetAdd(newset, range);
10558                         }
10559
10560                         /*
10561                          * Cleanup
10562                          */
10563                         if (res != NULL)
10564                             xmlXPathFreeObject(res);
10565                         if (ctxt->value == tmp) {
10566                             res = valuePop(ctxt);
10567                             xmlXPathFreeObject(res);
10568                         }
10569
10570                         ctxt->context->node = NULL;
10571                     }
10572                 }
10573
10574                 /*
10575                  * The result is used as the new evaluation set.
10576                  */
10577                 xmlXPathFreeObject(obj);
10578                 ctxt->context->node = NULL;
10579                 ctxt->context->contextSize = -1;
10580                 ctxt->context->proximityPosition = -1;
10581                 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10582                 return (total);
10583             }
10584 #endif /* LIBXML_XPTR_ENABLED */
10585     }
10586     xmlGenericError(xmlGenericErrorContext,
10587                     "XPath: unknown precompiled operation %d\n", op->op);
10588     return (total);
10589 }
10590
10591 /**
10592  * xmlXPathRunEval:
10593  * @ctxt:  the XPath parser context with the compiled expression
10594  *
10595  * Evaluate the Precompiled XPath expression in the given context.
10596  */
10597 static void
10598 xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10599     xmlXPathCompExprPtr comp;
10600
10601     if ((ctxt == NULL) || (ctxt->comp == NULL))
10602         return;
10603
10604     if (ctxt->valueTab == NULL) {
10605         /* Allocate the value stack */
10606         ctxt->valueTab = (xmlXPathObjectPtr *) 
10607                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10608         if (ctxt->valueTab == NULL) {
10609             xmlFree(ctxt);
10610         }
10611         ctxt->valueNr = 0;
10612         ctxt->valueMax = 10;
10613         ctxt->value = NULL;
10614     }
10615     comp = ctxt->comp;
10616     if(comp->last < 0) {
10617         xmlGenericError(xmlGenericErrorContext,
10618             "xmlXPathRunEval: last is less than zero\n");
10619         return;
10620     }
10621     xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10622 }
10623
10624 /************************************************************************
10625  *                                                                      *
10626  *                      Public interfaces                               *
10627  *                                                                      *
10628  ************************************************************************/
10629
10630 /**
10631  * xmlXPathEvalPredicate:
10632  * @ctxt:  the XPath context
10633  * @res:  the Predicate Expression evaluation result
10634  *
10635  * Evaluate a predicate result for the current node.
10636  * A PredicateExpr is evaluated by evaluating the Expr and converting
10637  * the result to a boolean. If the result is a number, the result will
10638  * be converted to true if the number is equal to the position of the
10639  * context node in the context node list (as returned by the position
10640  * function) and will be converted to false otherwise; if the result
10641  * is not a number, then the result will be converted as if by a call
10642  * to the boolean function. 
10643  *
10644  * Returns 1 if predicate is true, 0 otherwise
10645  */
10646 int
10647 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10648     if (res == NULL) return(0);
10649     switch (res->type) {
10650         case XPATH_BOOLEAN:
10651             return(res->boolval);
10652         case XPATH_NUMBER:
10653             return(res->floatval == ctxt->proximityPosition);
10654         case XPATH_NODESET:
10655         case XPATH_XSLT_TREE:
10656             if (res->nodesetval == NULL)
10657                 return(0);
10658             return(res->nodesetval->nodeNr != 0);
10659         case XPATH_STRING:
10660             return((res->stringval != NULL) &&
10661                    (xmlStrlen(res->stringval) != 0));
10662         default:
10663             STRANGE
10664     }
10665     return(0);
10666 }
10667
10668 /**
10669  * xmlXPathEvaluatePredicateResult:
10670  * @ctxt:  the XPath Parser context
10671  * @res:  the Predicate Expression evaluation result
10672  *
10673  * Evaluate a predicate result for the current node.
10674  * A PredicateExpr is evaluated by evaluating the Expr and converting
10675  * the result to a boolean. If the result is a number, the result will
10676  * be converted to true if the number is equal to the position of the
10677  * context node in the context node list (as returned by the position
10678  * function) and will be converted to false otherwise; if the result
10679  * is not a number, then the result will be converted as if by a call
10680  * to the boolean function. 
10681  *
10682  * Returns 1 if predicate is true, 0 otherwise
10683  */
10684 int
10685 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
10686                                 xmlXPathObjectPtr res) {
10687     if (res == NULL) return(0);
10688     switch (res->type) {
10689         case XPATH_BOOLEAN:
10690             return(res->boolval);
10691         case XPATH_NUMBER:
10692             return(res->floatval == ctxt->context->proximityPosition);
10693         case XPATH_NODESET:
10694         case XPATH_XSLT_TREE:
10695             if (res->nodesetval == NULL)
10696                 return(0);
10697             return(res->nodesetval->nodeNr != 0);
10698         case XPATH_STRING:
10699             return((res->stringval != NULL) &&
10700                    (xmlStrlen(res->stringval) != 0));
10701         default:
10702             STRANGE
10703     }
10704     return(0);
10705 }
10706
10707 /**
10708  * xmlXPathCompile:
10709  * @str:  the XPath expression
10710  *
10711  * Compile an XPath expression
10712  *
10713  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10714  *         the caller has to free the object.
10715  */
10716 xmlXPathCompExprPtr
10717 xmlXPathCompile(const xmlChar *str) {
10718     xmlXPathParserContextPtr ctxt;
10719     xmlXPathCompExprPtr comp;
10720
10721     xmlXPathInit();
10722
10723     ctxt = xmlXPathNewParserContext(str, NULL);
10724     xmlXPathCompileExpr(ctxt);
10725     
10726     if (*ctxt->cur != 0) {
10727         /* 
10728          * aleksey: in some cases this line prints *second* error message
10729          * (see bug #78858) and probably this should be fixed.
10730          * However, we are not sure that all error messages are printed
10731          * out in other places. It's not critical so we leave it as-is for now
10732          */
10733         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10734         comp = NULL;
10735     } else {
10736         comp = ctxt->comp;
10737         ctxt->comp = NULL;
10738     }
10739     xmlXPathFreeParserContext(ctxt);
10740     if (comp != NULL) {
10741         comp->expr = xmlStrdup(str);
10742 #ifdef DEBUG_EVAL_COUNTS
10743         comp->string = xmlStrdup(str);
10744         comp->nb = 0;
10745 #endif
10746     }
10747     return(comp);
10748 }
10749
10750 /**
10751  * xmlXPathCompiledEval:
10752  * @comp:  the compiled XPath expression
10753  * @ctx:  the XPath context
10754  *
10755  * Evaluate the Precompiled XPath expression in the given context.
10756  *
10757  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10758  *         the caller has to free the object.
10759  */
10760 xmlXPathObjectPtr
10761 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
10762     xmlXPathParserContextPtr ctxt;
10763     xmlXPathObjectPtr res, tmp, init = NULL;
10764     int stack = 0;
10765 #ifndef LIBXML_THREAD_ENABLED
10766     static int reentance = 0;
10767 #endif
10768
10769     if ((comp == NULL) || (ctx == NULL))
10770         return(NULL);
10771     xmlXPathInit();
10772
10773     CHECK_CONTEXT(ctx)
10774
10775 #ifndef LIBXML_THREAD_ENABLED
10776     reentance++;
10777     if (reentance > 1)
10778         xmlXPathDisableOptimizer = 1;
10779 #endif
10780
10781 #ifdef DEBUG_EVAL_COUNTS
10782     comp->nb++;
10783     if ((comp->string != NULL) && (comp->nb > 100)) {
10784         fprintf(stderr, "100 x %s\n", comp->string);
10785         comp->nb = 0;
10786     }
10787 #endif
10788     ctxt = xmlXPathCompParserContext(comp, ctx);
10789     xmlXPathRunEval(ctxt);
10790
10791     if (ctxt->value == NULL) {
10792         xmlGenericError(xmlGenericErrorContext,
10793                 "xmlXPathCompiledEval: evaluation failed\n");
10794         res = NULL;
10795     } else {
10796         res = valuePop(ctxt);
10797     }
10798
10799     
10800     do {
10801         tmp = valuePop(ctxt);
10802         if (tmp != NULL) {
10803             if (tmp != init)
10804                 stack++;    
10805             xmlXPathFreeObject(tmp);
10806         }
10807     } while (tmp != NULL);
10808     if ((stack != 0) && (res != NULL)) {
10809         xmlGenericError(xmlGenericErrorContext,
10810                 "xmlXPathCompiledEval: %d object left on the stack\n",
10811                 stack);
10812     }
10813     if (ctxt->error != XPATH_EXPRESSION_OK) {
10814         xmlXPathFreeObject(res);
10815         res = NULL;
10816     }
10817         
10818
10819     ctxt->comp = NULL;
10820     xmlXPathFreeParserContext(ctxt);
10821 #ifndef LIBXML_THREAD_ENABLED
10822     reentance--;
10823 #endif
10824     return(res);
10825 }
10826
10827 /**
10828  * xmlXPathEvalExpr:
10829  * @ctxt:  the XPath Parser context
10830  *
10831  * Parse and evaluate an XPath expression in the given context,
10832  * then push the result on the context stack
10833  */
10834 void
10835 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10836     xmlXPathCompileExpr(ctxt);
10837     CHECK_ERROR;
10838     xmlXPathRunEval(ctxt);
10839 }
10840
10841 /**
10842  * xmlXPathEval:
10843  * @str:  the XPath expression
10844  * @ctx:  the XPath context
10845  *
10846  * Evaluate the XPath Location Path in the given context.
10847  *
10848  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10849  *         the caller has to free the object.
10850  */
10851 xmlXPathObjectPtr
10852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10853     xmlXPathParserContextPtr ctxt;
10854     xmlXPathObjectPtr res, tmp, init = NULL;
10855     int stack = 0;
10856
10857     xmlXPathInit();
10858
10859     CHECK_CONTEXT(ctx)
10860
10861     ctxt = xmlXPathNewParserContext(str, ctx);
10862     xmlXPathEvalExpr(ctxt);
10863
10864     if (ctxt->value == NULL) {
10865         xmlGenericError(xmlGenericErrorContext,
10866                 "xmlXPathEval: evaluation failed\n");
10867         res = NULL;
10868     } else if (*ctxt->cur != 0) {
10869         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10870         res = NULL;
10871     } else {
10872         res = valuePop(ctxt);
10873     }
10874
10875     do {
10876         tmp = valuePop(ctxt);
10877         if (tmp != NULL) {
10878             if (tmp != init)
10879                 stack++;    
10880             xmlXPathFreeObject(tmp);
10881         }
10882     } while (tmp != NULL);
10883     if ((stack != 0) && (res != NULL)) {
10884         xmlGenericError(xmlGenericErrorContext,
10885                 "xmlXPathEval: %d object left on the stack\n",
10886                 stack);
10887     }
10888     if (ctxt->error != XPATH_EXPRESSION_OK) {
10889         xmlXPathFreeObject(res);
10890         res = NULL;
10891     }
10892
10893     xmlXPathFreeParserContext(ctxt);
10894     return(res);
10895 }
10896
10897 /**
10898  * xmlXPathEvalExpression:
10899  * @str:  the XPath expression
10900  * @ctxt:  the XPath context
10901  *
10902  * Evaluate the XPath expression in the given context.
10903  *
10904  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10905  *         the caller has to free the object.
10906  */
10907 xmlXPathObjectPtr
10908 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10909     xmlXPathParserContextPtr pctxt;
10910     xmlXPathObjectPtr res, tmp;
10911     int stack = 0;
10912
10913     xmlXPathInit();
10914
10915     CHECK_CONTEXT(ctxt)
10916
10917     pctxt = xmlXPathNewParserContext(str, ctxt);
10918     xmlXPathEvalExpr(pctxt);
10919
10920     if (*pctxt->cur != 0) {
10921         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10922         res = NULL;
10923     } else {
10924         res = valuePop(pctxt);
10925     }
10926     do {
10927         tmp = valuePop(pctxt);
10928         if (tmp != NULL) {
10929             xmlXPathFreeObject(tmp);
10930             stack++;
10931         }
10932     } while (tmp != NULL);
10933     if ((stack != 0) && (res != NULL)) {
10934         xmlGenericError(xmlGenericErrorContext,
10935                 "xmlXPathEvalExpression: %d object left on the stack\n",
10936                 stack);
10937     }
10938     xmlXPathFreeParserContext(pctxt);
10939     return(res);
10940 }
10941
10942 /************************************************************************
10943  *                                                                      *
10944  *      Extra functions not pertaining to the XPath spec                *
10945  *                                                                      *
10946  ************************************************************************/
10947 /**
10948  * xmlXPathEscapeUriFunction:
10949  * @ctxt:  the XPath Parser context
10950  * @nargs:  the number of arguments
10951  *
10952  * Implement the escape-uri() XPath function
10953  *    string escape-uri(string $str, bool $escape-reserved)
10954  *
10955  * This function applies the URI escaping rules defined in section 2 of [RFC
10956  * 2396] to the string supplied as $uri-part, which typically represents all
10957  * or part of a URI. The effect of the function is to replace any special
10958  * character in the string by an escape sequence of the form %xx%yy...,
10959  * where xxyy... is the hexadecimal representation of the octets used to
10960  * represent the character in UTF-8.
10961  *
10962  * The set of characters that are escaped depends on the setting of the
10963  * boolean argument $escape-reserved.
10964  *
10965  * If $escape-reserved is true, all characters are escaped other than lower
10966  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10967  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10968  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10969  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10970  * A-F).
10971  *
10972  * If $escape-reserved is false, the behavior differs in that characters
10973  * referred to in [RFC 2396] as reserved characters are not escaped. These
10974  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10975  * 
10976  * [RFC 2396] does not define whether escaped URIs should use lower case or
10977  * upper case for hexadecimal digits. To ensure that escaped URIs can be
10978  * compared using string comparison functions, this function must always use
10979  * the upper-case letters A-F.
10980  * 
10981  * Generally, $escape-reserved should be set to true when escaping a string
10982  * that is to form a single part of a URI, and to false when escaping an
10983  * entire URI or URI reference.
10984  * 
10985  * In the case of non-ascii characters, the string is encoded according to 
10986  * utf-8 and then converted according to RFC 2396.
10987  *
10988  * Examples
10989  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 
10990  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10991  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10992  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10993  *
10994  */
10995 static void
10996 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10997     xmlXPathObjectPtr str;
10998     int escape_reserved;
10999     xmlBufferPtr target;
11000     xmlChar *cptr;
11001     xmlChar escape[4];
11002     
11003     CHECK_ARITY(2);
11004     
11005     escape_reserved = xmlXPathPopBoolean(ctxt);
11006     
11007     CAST_TO_STRING;
11008     str = valuePop(ctxt);
11009     
11010     target = xmlBufferCreate();
11011     
11012     escape[0] = '%';
11013     escape[3] = 0;
11014     
11015     if (target) {
11016         for (cptr = str->stringval; *cptr; cptr++) {
11017             if ((*cptr >= 'A' && *cptr <= 'Z') ||
11018                 (*cptr >= 'a' && *cptr <= 'z') ||
11019                 (*cptr >= '0' && *cptr <= '9') ||
11020                 *cptr == '-' || *cptr == '_' || *cptr == '.' || 
11021                 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11022                 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11023                 (*cptr == '%' && 
11024                  ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11025                   (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11026                   (cptr[1] >= '0' && cptr[1] <= '9')) &&
11027                  ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11028                   (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11029                   (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11030                 (!escape_reserved &&
11031                  (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11032                   *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11033                   *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11034                   *cptr == ','))) {
11035                 xmlBufferAdd(target, cptr, 1);
11036             } else {
11037                 if ((*cptr >> 4) < 10)
11038                     escape[1] = '0' + (*cptr >> 4);
11039                 else
11040                     escape[1] = 'A' - 10 + (*cptr >> 4);
11041                 if ((*cptr & 0xF) < 10)
11042                     escape[2] = '0' + (*cptr & 0xF);
11043                 else
11044                     escape[2] = 'A' - 10 + (*cptr & 0xF);
11045                 
11046                 xmlBufferAdd(target, &escape[0], 3);
11047             }
11048         }
11049     }
11050     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11051     xmlBufferFree(target);
11052     xmlXPathFreeObject(str);
11053 }
11054
11055 /**
11056  * xmlXPathRegisterAllFunctions:
11057  * @ctxt:  the XPath context
11058  *
11059  * Registers all default XPath functions in this context
11060  */
11061 void
11062 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11063 {
11064     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11065                          xmlXPathBooleanFunction);
11066     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11067                          xmlXPathCeilingFunction);
11068     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11069                          xmlXPathCountFunction);
11070     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11071                          xmlXPathConcatFunction);
11072     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11073                          xmlXPathContainsFunction);
11074     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11075                          xmlXPathIdFunction);
11076     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11077                          xmlXPathFalseFunction);
11078     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11079                          xmlXPathFloorFunction);
11080     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11081                          xmlXPathLastFunction);
11082     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11083                          xmlXPathLangFunction);
11084     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11085                          xmlXPathLocalNameFunction);
11086     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11087                          xmlXPathNotFunction);
11088     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11089                          xmlXPathNameFunction);
11090     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11091                          xmlXPathNamespaceURIFunction);
11092     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11093                          xmlXPathNormalizeFunction);
11094     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11095                          xmlXPathNumberFunction);
11096     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11097                          xmlXPathPositionFunction);
11098     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11099                          xmlXPathRoundFunction);
11100     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11101                          xmlXPathStringFunction);
11102     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11103                          xmlXPathStringLengthFunction);
11104     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11105                          xmlXPathStartsWithFunction);
11106     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11107                          xmlXPathSubstringFunction);
11108     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11109                          xmlXPathSubstringBeforeFunction);
11110     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11111                          xmlXPathSubstringAfterFunction);
11112     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11113                          xmlXPathSumFunction);
11114     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11115                          xmlXPathTrueFunction);
11116     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11117                          xmlXPathTranslateFunction);
11118
11119     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11120          (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11121                          xmlXPathEscapeUriFunction);
11122 }
11123
11124 #endif /* LIBXML_XPATH_ENABLED */