• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 #define IN_LIBXML
18 #include "libxml.h"
19 
20 #include <string.h>
21 
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37 
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57 
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61 
62 #define TODO								\
63     xmlGenericError(xmlGenericErrorContext,				\
64 	    "Unimplemented block at %s:%d\n",				\
65             __FILE__, __LINE__);
66 
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77 
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84 
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91 
92 /*
93  * TODO:
94  * There are a few spots where some tests are done which depend upon ascii
95  * data.  These should be enhanced for full UTF8 support (see particularly
96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97  */
98 
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100 
101 /************************************************************************
102  *									*
103  *			Floating point stuff				*
104  *									*
105  ************************************************************************/
106 
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111 
112 /*
113  * The lack of portability of this section of the libc is annoying !
114  */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120 
121 /**
122  * xmlXPathInit:
123  *
124  * Initialize the XPath environment
125  */
126 void
xmlXPathInit(void)127 xmlXPathInit(void) {
128     if (xmlXPathInitialized) return;
129 
130     xmlXPathPINF = trio_pinf();
131     xmlXPathNINF = trio_ninf();
132     xmlXPathNAN = trio_nan();
133     xmlXPathNZERO = trio_nzero();
134 
135     xmlXPathInitialized = 1;
136 }
137 
138 /**
139  * xmlXPathIsNaN:
140  * @val:  a double value
141  *
142  * Provides a portable isnan() function to detect whether a double
143  * is a NotaNumber. Based on trio code
144  * http://sourceforge.net/projects/ctrio/
145  *
146  * Returns 1 if the value is a NaN, 0 otherwise
147  */
148 int
xmlXPathIsNaN(double val)149 xmlXPathIsNaN(double val) {
150     return(trio_isnan(val));
151 }
152 
153 /**
154  * xmlXPathIsInf:
155  * @val:  a double value
156  *
157  * Provides a portable isinf() function to detect whether a double
158  * is a +Infinite or -Infinite. Based on trio code
159  * http://sourceforge.net/projects/ctrio/
160  *
161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162  */
163 int
xmlXPathIsInf(double val)164 xmlXPathIsInf(double val) {
165     return(trio_isinf(val));
166 }
167 
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171  * xmlXPathGetSign:
172  * @val:  a double value
173  *
174  * Provides a portable function to detect the sign of a double
175  * Modified from trio code
176  * http://sourceforge.net/projects/ctrio/
177  *
178  * Returns 1 if the value is Negative, 0 if positive
179  */
180 static int
xmlXPathGetSign(double val)181 xmlXPathGetSign(double val) {
182     return(trio_signbit(val));
183 }
184 
185 
186 /*
187  * TODO: when compatibility allows remove all "fake node libxslt" strings
188  *       the test should just be name[0] = ' '
189  */
190 #ifdef DEBUG_XPATH_EXPRESSION
191 #define DEBUG_STEP
192 #define DEBUG_EXPR
193 #define DEBUG_EVAL_COUNTS
194 #endif
195 
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197     NULL,
198     XML_NAMESPACE_DECL,
199     XML_XML_NAMESPACE,
200     BAD_CAST "xml",
201     NULL,
202     NULL
203 };
204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205 #ifndef LIBXML_THREAD_ENABLED
206 /*
207  * Optimizer is disabled only when threaded apps are detected while
208  * the library ain't compiled for thread safety.
209  */
210 static int xmlXPathDisableOptimizer = 0;
211 #endif
212 
213 /************************************************************************
214  *									*
215  *			Error handling routines				*
216  *									*
217  ************************************************************************/
218 
219 /**
220  * XP_ERRORNULL:
221  * @X:  the error code
222  *
223  * Macro to raise an XPath error and return NULL.
224  */
225 #define XP_ERRORNULL(X)							\
226     { xmlXPathErr(ctxt, X); return(NULL); }
227 
228 /*
229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230  */
231 static const char *xmlXPathErrorMessages[] = {
232     "Ok\n",
233     "Number encoding\n",
234     "Unfinished literal\n",
235     "Start of literal\n",
236     "Expected $ for variable reference\n",
237     "Undefined variable\n",
238     "Invalid predicate\n",
239     "Invalid expression\n",
240     "Missing closing curly brace\n",
241     "Unregistered function\n",
242     "Invalid operand\n",
243     "Invalid type\n",
244     "Invalid number of arguments\n",
245     "Invalid context size\n",
246     "Invalid context position\n",
247     "Memory allocation error\n",
248     "Syntax error\n",
249     "Resource error\n",
250     "Sub resource error\n",
251     "Undefined namespace prefix\n",
252     "Encoding error\n",
253     "Char out of XML range\n",
254     "Invalid or incomplete context\n",
255     "?? Unknown error ??\n"	/* Must be last in the list! */
256 };
257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
258 		   sizeof(xmlXPathErrorMessages[0])) - 1)
259 /**
260  * xmlXPathErrMemory:
261  * @ctxt:  an XPath context
262  * @extra:  extra informations
263  *
264  * Handle a redefinition of attribute error
265  */
266 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268 {
269     if (ctxt != NULL) {
270         if (extra) {
271             xmlChar buf[200];
272 
273             xmlStrPrintf(buf, 200,
274                          BAD_CAST "Memory allocation failed : %s\n",
275                          extra);
276             ctxt->lastError.message = (char *) xmlStrdup(buf);
277         } else {
278             ctxt->lastError.message = (char *)
279 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
280         }
281         ctxt->lastError.domain = XML_FROM_XPATH;
282         ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 	if (ctxt->error != NULL)
284 	    ctxt->error(ctxt->userData, &ctxt->lastError);
285     } else {
286         if (extra)
287             __xmlRaiseError(NULL, NULL, NULL,
288                             NULL, NULL, XML_FROM_XPATH,
289                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290                             extra, NULL, NULL, 0, 0,
291                             "Memory allocation failed : %s\n", extra);
292         else
293             __xmlRaiseError(NULL, NULL, NULL,
294                             NULL, NULL, XML_FROM_XPATH,
295                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296                             NULL, NULL, NULL, 0, 0,
297                             "Memory allocation failed\n");
298     }
299 }
300 
301 /**
302  * xmlXPathPErrMemory:
303  * @ctxt:  an XPath parser context
304  * @extra:  extra informations
305  *
306  * Handle a redefinition of attribute error
307  */
308 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310 {
311     if (ctxt == NULL)
312 	xmlXPathErrMemory(NULL, extra);
313     else {
314 	ctxt->error = XPATH_MEMORY_ERROR;
315 	xmlXPathErrMemory(ctxt->context, extra);
316     }
317 }
318 
319 /**
320  * xmlXPathErr:
321  * @ctxt:  a XPath parser context
322  * @error:  the error code
323  *
324  * Handle an XPath error
325  */
326 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328 {
329     if ((error < 0) || (error > MAXERRNO))
330 	error = MAXERRNO;
331     if (ctxt == NULL) {
332 	__xmlRaiseError(NULL, NULL, NULL,
333 			NULL, NULL, XML_FROM_XPATH,
334 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 			XML_ERR_ERROR, NULL, 0,
336 			NULL, NULL, NULL, 0, 0,
337 			"%s", xmlXPathErrorMessages[error]);
338 	return;
339     }
340     ctxt->error = error;
341     if (ctxt->context == NULL) {
342 	__xmlRaiseError(NULL, NULL, NULL,
343 			NULL, NULL, XML_FROM_XPATH,
344 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 			XML_ERR_ERROR, NULL, 0,
346 			(const char *) ctxt->base, NULL, NULL,
347 			ctxt->cur - ctxt->base, 0,
348 			"%s", xmlXPathErrorMessages[error]);
349 	return;
350     }
351 
352     /* cleanup current last error */
353     xmlResetError(&ctxt->context->lastError);
354 
355     ctxt->context->lastError.domain = XML_FROM_XPATH;
356     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357                            XPATH_EXPRESSION_OK;
358     ctxt->context->lastError.level = XML_ERR_ERROR;
359     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361     ctxt->context->lastError.node = ctxt->context->debugNode;
362     if (ctxt->context->error != NULL) {
363 	ctxt->context->error(ctxt->context->userData,
364 	                     &ctxt->context->lastError);
365     } else {
366 	__xmlRaiseError(NULL, NULL, NULL,
367 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 			XML_ERR_ERROR, NULL, 0,
370 			(const char *) ctxt->base, NULL, NULL,
371 			ctxt->cur - ctxt->base, 0,
372 			"%s", xmlXPathErrorMessages[error]);
373     }
374 
375 }
376 
377 /**
378  * xmlXPatherror:
379  * @ctxt:  the XPath Parser context
380  * @file:  the file name
381  * @line:  the line number
382  * @no:  the error number
383  *
384  * Formats an error message.
385  */
386 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388               int line ATTRIBUTE_UNUSED, int no) {
389     xmlXPathErr(ctxt, no);
390 }
391 
392 /************************************************************************
393  *									*
394  *			Utilities					*
395  *									*
396  ************************************************************************/
397 
398 /**
399  * xsltPointerList:
400  *
401  * Pointer-list for various purposes.
402  */
403 typedef struct _xmlPointerList xmlPointerList;
404 typedef xmlPointerList *xmlPointerListPtr;
405 struct _xmlPointerList {
406     void **items;
407     int number;
408     int size;
409 };
410 /*
411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412 * and here, we should make the functions public.
413 */
414 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)415 xmlPointerListAddSize(xmlPointerListPtr list,
416 		       void *item,
417 		       int initialSize)
418 {
419     if (list->items == NULL) {
420 	if (initialSize <= 0)
421 	    initialSize = 1;
422 	list->items = (void **) xmlMalloc(
423 	    initialSize * sizeof(void *));
424 	if (list->items == NULL) {
425 	    xmlXPathErrMemory(NULL,
426 		"xmlPointerListCreate: allocating item\n");
427 	    return(-1);
428 	}
429 	list->number = 0;
430 	list->size = initialSize;
431     } else if (list->size <= list->number) {
432 	list->size *= 2;
433 	list->items = (void **) xmlRealloc(list->items,
434 	    list->size * sizeof(void *));
435 	if (list->items == NULL) {
436 	    xmlXPathErrMemory(NULL,
437 		"xmlPointerListCreate: re-allocating item\n");
438 	    list->size = 0;
439 	    return(-1);
440 	}
441     }
442     list->items[list->number++] = item;
443     return(0);
444 }
445 
446 /**
447  * xsltPointerListCreate:
448  *
449  * Creates an xsltPointerList structure.
450  *
451  * Returns a xsltPointerList structure or NULL in case of an error.
452  */
453 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)454 xmlPointerListCreate(int initialSize)
455 {
456     xmlPointerListPtr ret;
457 
458     ret = xmlMalloc(sizeof(xmlPointerList));
459     if (ret == NULL) {
460 	xmlXPathErrMemory(NULL,
461 	    "xmlPointerListCreate: allocating item\n");
462 	return (NULL);
463     }
464     memset(ret, 0, sizeof(xmlPointerList));
465     if (initialSize > 0) {
466 	xmlPointerListAddSize(ret, NULL, initialSize);
467 	ret->number = 0;
468     }
469     return (ret);
470 }
471 
472 /**
473  * xsltPointerListFree:
474  *
475  * Frees the xsltPointerList structure. This does not free
476  * the content of the list.
477  */
478 static void
xmlPointerListFree(xmlPointerListPtr list)479 xmlPointerListFree(xmlPointerListPtr list)
480 {
481     if (list == NULL)
482 	return;
483     if (list->items != NULL)
484 	xmlFree(list->items);
485     xmlFree(list);
486 }
487 
488 /************************************************************************
489  *									*
490  *			Parser Types					*
491  *									*
492  ************************************************************************/
493 
494 /*
495  * Types are private:
496  */
497 
498 typedef enum {
499     XPATH_OP_END=0,
500     XPATH_OP_AND,
501     XPATH_OP_OR,
502     XPATH_OP_EQUAL,
503     XPATH_OP_CMP,
504     XPATH_OP_PLUS,
505     XPATH_OP_MULT,
506     XPATH_OP_UNION,
507     XPATH_OP_ROOT,
508     XPATH_OP_NODE,
509     XPATH_OP_RESET, /* 10 */
510     XPATH_OP_COLLECT,
511     XPATH_OP_VALUE, /* 12 */
512     XPATH_OP_VARIABLE,
513     XPATH_OP_FUNCTION,
514     XPATH_OP_ARG,
515     XPATH_OP_PREDICATE,
516     XPATH_OP_FILTER, /* 17 */
517     XPATH_OP_SORT /* 18 */
518 #ifdef LIBXML_XPTR_ENABLED
519     ,XPATH_OP_RANGETO
520 #endif
521 } xmlXPathOp;
522 
523 typedef enum {
524     AXIS_ANCESTOR = 1,
525     AXIS_ANCESTOR_OR_SELF,
526     AXIS_ATTRIBUTE,
527     AXIS_CHILD,
528     AXIS_DESCENDANT,
529     AXIS_DESCENDANT_OR_SELF,
530     AXIS_FOLLOWING,
531     AXIS_FOLLOWING_SIBLING,
532     AXIS_NAMESPACE,
533     AXIS_PARENT,
534     AXIS_PRECEDING,
535     AXIS_PRECEDING_SIBLING,
536     AXIS_SELF
537 } xmlXPathAxisVal;
538 
539 typedef enum {
540     NODE_TEST_NONE = 0,
541     NODE_TEST_TYPE = 1,
542     NODE_TEST_PI = 2,
543     NODE_TEST_ALL = 3,
544     NODE_TEST_NS = 4,
545     NODE_TEST_NAME = 5
546 } xmlXPathTestVal;
547 
548 typedef enum {
549     NODE_TYPE_NODE = 0,
550     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551     NODE_TYPE_TEXT = XML_TEXT_NODE,
552     NODE_TYPE_PI = XML_PI_NODE
553 } xmlXPathTypeVal;
554 
555 #define XP_REWRITE_DOS_CHILD_ELEM 1
556 
557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559 struct _xmlXPathStepOp {
560     xmlXPathOp op;		/* The identifier of the operation */
561     int ch1;			/* First child */
562     int ch2;			/* Second child */
563     int value;
564     int value2;
565     int value3;
566     void *value4;
567     void *value5;
568     void *cache;
569     void *cacheURI;
570     int rewriteType;
571 };
572 
573 struct _xmlXPathCompExpr {
574     int nbStep;			/* Number of steps in this expression */
575     int maxStep;		/* Maximum number of steps allocated */
576     xmlXPathStepOp *steps;	/* ops for computation of this expression */
577     int last;			/* index of last step in expression */
578     xmlChar *expr;		/* the expression being computed */
579     xmlDictPtr dict;		/* the dictionnary to use if any */
580 #ifdef DEBUG_EVAL_COUNTS
581     int nb;
582     xmlChar *string;
583 #endif
584 #ifdef XPATH_STREAMING
585     xmlPatternPtr stream;
586 #endif
587 };
588 
589 /************************************************************************
590  *									*
591  *			Forward declarations				*
592  *									*
593  ************************************************************************/
594 static void
595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596 static void
597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598 static int
599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600                         xmlXPathStepOpPtr op, xmlNodePtr *first);
601 static int
602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603 			    xmlXPathStepOpPtr op,
604 			    int isPredicate);
605 
606 /************************************************************************
607  *									*
608  *			Parser Type functions				*
609  *									*
610  ************************************************************************/
611 
612 /**
613  * xmlXPathNewCompExpr:
614  *
615  * Create a new Xpath component
616  *
617  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618  */
619 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)620 xmlXPathNewCompExpr(void) {
621     xmlXPathCompExprPtr cur;
622 
623     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624     if (cur == NULL) {
625         xmlXPathErrMemory(NULL, "allocating component\n");
626 	return(NULL);
627     }
628     memset(cur, 0, sizeof(xmlXPathCompExpr));
629     cur->maxStep = 10;
630     cur->nbStep = 0;
631     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 	                                   sizeof(xmlXPathStepOp));
633     if (cur->steps == NULL) {
634         xmlXPathErrMemory(NULL, "allocating steps\n");
635 	xmlFree(cur);
636 	return(NULL);
637     }
638     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639     cur->last = -1;
640 #ifdef DEBUG_EVAL_COUNTS
641     cur->nb = 0;
642 #endif
643     return(cur);
644 }
645 
646 /**
647  * xmlXPathFreeCompExpr:
648  * @comp:  an XPATH comp
649  *
650  * Free up the memory allocated by @comp
651  */
652 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654 {
655     xmlXPathStepOpPtr op;
656     int i;
657 
658     if (comp == NULL)
659         return;
660     if (comp->dict == NULL) {
661 	for (i = 0; i < comp->nbStep; i++) {
662 	    op = &comp->steps[i];
663 	    if (op->value4 != NULL) {
664 		if (op->op == XPATH_OP_VALUE)
665 		    xmlXPathFreeObject(op->value4);
666 		else
667 		    xmlFree(op->value4);
668 	    }
669 	    if (op->value5 != NULL)
670 		xmlFree(op->value5);
671 	}
672     } else {
673 	for (i = 0; i < comp->nbStep; i++) {
674 	    op = &comp->steps[i];
675 	    if (op->value4 != NULL) {
676 		if (op->op == XPATH_OP_VALUE)
677 		    xmlXPathFreeObject(op->value4);
678 	    }
679 	}
680         xmlDictFree(comp->dict);
681     }
682     if (comp->steps != NULL) {
683         xmlFree(comp->steps);
684     }
685 #ifdef DEBUG_EVAL_COUNTS
686     if (comp->string != NULL) {
687         xmlFree(comp->string);
688     }
689 #endif
690 #ifdef XPATH_STREAMING
691     if (comp->stream != NULL) {
692         xmlFreePatternList(comp->stream);
693     }
694 #endif
695     if (comp->expr != NULL) {
696         xmlFree(comp->expr);
697     }
698 
699     xmlFree(comp);
700 }
701 
702 /**
703  * xmlXPathCompExprAdd:
704  * @comp:  the compiled expression
705  * @ch1: first child index
706  * @ch2: second child index
707  * @op:  an op
708  * @value:  the first int value
709  * @value2:  the second int value
710  * @value3:  the third int value
711  * @value4:  the first string value
712  * @value5:  the second string value
713  *
714  * Add a step to an XPath Compiled Expression
715  *
716  * Returns -1 in case of failure, the index otherwise
717  */
718 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720    xmlXPathOp op, int value,
721    int value2, int value3, void *value4, void *value5) {
722     if (comp->nbStep >= comp->maxStep) {
723 	xmlXPathStepOp *real;
724 
725 	comp->maxStep *= 2;
726 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 		                      comp->maxStep * sizeof(xmlXPathStepOp));
728 	if (real == NULL) {
729 	    comp->maxStep /= 2;
730 	    xmlXPathErrMemory(NULL, "adding step\n");
731 	    return(-1);
732 	}
733 	comp->steps = real;
734     }
735     comp->last = comp->nbStep;
736     comp->steps[comp->nbStep].rewriteType = 0;
737     comp->steps[comp->nbStep].ch1 = ch1;
738     comp->steps[comp->nbStep].ch2 = ch2;
739     comp->steps[comp->nbStep].op = op;
740     comp->steps[comp->nbStep].value = value;
741     comp->steps[comp->nbStep].value2 = value2;
742     comp->steps[comp->nbStep].value3 = value3;
743     if ((comp->dict != NULL) &&
744         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 	 (op == XPATH_OP_COLLECT))) {
746         if (value4 != NULL) {
747 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
748 	        (void *)xmlDictLookup(comp->dict, value4, -1);
749 	    xmlFree(value4);
750 	} else
751 	    comp->steps[comp->nbStep].value4 = NULL;
752         if (value5 != NULL) {
753 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
754 	        (void *)xmlDictLookup(comp->dict, value5, -1);
755 	    xmlFree(value5);
756 	} else
757 	    comp->steps[comp->nbStep].value5 = NULL;
758     } else {
759 	comp->steps[comp->nbStep].value4 = value4;
760 	comp->steps[comp->nbStep].value5 = value5;
761     }
762     comp->steps[comp->nbStep].cache = NULL;
763     return(comp->nbStep++);
764 }
765 
766 /**
767  * xmlXPathCompSwap:
768  * @comp:  the compiled expression
769  * @op: operation index
770  *
771  * Swaps 2 operations in the compiled expression
772  */
773 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775     int tmp;
776 
777 #ifndef LIBXML_THREAD_ENABLED
778     /*
779      * Since this manipulates possibly shared variables, this is
780      * disabled if one detects that the library is used in a multithreaded
781      * application
782      */
783     if (xmlXPathDisableOptimizer)
784 	return;
785 #endif
786 
787     tmp = op->ch1;
788     op->ch1 = op->ch2;
789     op->ch2 = tmp;
790 }
791 
792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
793     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
794 	                (op), (val), (val2), (val3), (val4), (val5))
795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
796     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
797 	                (op), (val), (val2), (val3), (val4), (val5))
798 
799 #define PUSH_LEAVE_EXPR(op, val, val2)					\
800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801 
802 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804 
805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
807 			(val), (val2), 0 ,NULL ,NULL)
808 
809 /************************************************************************
810  *									*
811  *		XPath object cache structures				*
812  *									*
813  ************************************************************************/
814 
815 /* #define XP_DEFAULT_CACHE_ON */
816 
817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818 
819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821 struct _xmlXPathContextCache {
822     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
823     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
824     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
825     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
826     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
827     int maxNodeset;
828     int maxString;
829     int maxBoolean;
830     int maxNumber;
831     int maxMisc;
832 #ifdef XP_DEBUG_OBJ_USAGE
833     int dbgCachedAll;
834     int dbgCachedNodeset;
835     int dbgCachedString;
836     int dbgCachedBool;
837     int dbgCachedNumber;
838     int dbgCachedPoint;
839     int dbgCachedRange;
840     int dbgCachedLocset;
841     int dbgCachedUsers;
842     int dbgCachedXSLTTree;
843     int dbgCachedUndefined;
844 
845 
846     int dbgReusedAll;
847     int dbgReusedNodeset;
848     int dbgReusedString;
849     int dbgReusedBool;
850     int dbgReusedNumber;
851     int dbgReusedPoint;
852     int dbgReusedRange;
853     int dbgReusedLocset;
854     int dbgReusedUsers;
855     int dbgReusedXSLTTree;
856     int dbgReusedUndefined;
857 
858 #endif
859 };
860 
861 /************************************************************************
862  *									*
863  *		Debugging related functions				*
864  *									*
865  ************************************************************************/
866 
867 #define STRANGE							\
868     xmlGenericError(xmlGenericErrorContext,				\
869 	    "Internal error at %s:%d\n",				\
870             __FILE__, __LINE__);
871 
872 #ifdef LIBXML_DEBUG_ENABLED
873 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
875     int i;
876     char shift[100];
877 
878     for (i = 0;((i < depth) && (i < 25));i++)
879         shift[2 * i] = shift[2 * i + 1] = ' ';
880     shift[2 * i] = shift[2 * i + 1] = 0;
881     if (cur == NULL) {
882 	fprintf(output, "%s", shift);
883 	fprintf(output, "Node is NULL !\n");
884 	return;
885 
886     }
887 
888     if ((cur->type == XML_DOCUMENT_NODE) ||
889 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 	fprintf(output, "%s", shift);
891 	fprintf(output, " /\n");
892     } else if (cur->type == XML_ATTRIBUTE_NODE)
893 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894     else
895 	xmlDebugDumpOneNode(output, cur, depth);
896 }
897 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
899     xmlNodePtr tmp;
900     int i;
901     char shift[100];
902 
903     for (i = 0;((i < depth) && (i < 25));i++)
904         shift[2 * i] = shift[2 * i + 1] = ' ';
905     shift[2 * i] = shift[2 * i + 1] = 0;
906     if (cur == NULL) {
907 	fprintf(output, "%s", shift);
908 	fprintf(output, "Node is NULL !\n");
909 	return;
910 
911     }
912 
913     while (cur != NULL) {
914 	tmp = cur;
915 	cur = cur->next;
916 	xmlDebugDumpOneNode(output, tmp, depth);
917     }
918 }
919 
920 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
922     int i;
923     char shift[100];
924 
925     for (i = 0;((i < depth) && (i < 25));i++)
926         shift[2 * i] = shift[2 * i + 1] = ' ';
927     shift[2 * i] = shift[2 * i + 1] = 0;
928 
929     if (cur == NULL) {
930 	fprintf(output, "%s", shift);
931 	fprintf(output, "NodeSet is NULL !\n");
932 	return;
933 
934     }
935 
936     if (cur != NULL) {
937 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 	for (i = 0;i < cur->nodeNr;i++) {
939 	    fprintf(output, "%s", shift);
940 	    fprintf(output, "%d", i + 1);
941 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 	}
943     }
944 }
945 
946 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
948     int i;
949     char shift[100];
950 
951     for (i = 0;((i < depth) && (i < 25));i++)
952         shift[2 * i] = shift[2 * i + 1] = ' ';
953     shift[2 * i] = shift[2 * i + 1] = 0;
954 
955     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 	fprintf(output, "%s", shift);
957 	fprintf(output, "Value Tree is NULL !\n");
958 	return;
959 
960     }
961 
962     fprintf(output, "%s", shift);
963     fprintf(output, "%d", i + 1);
964     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965 }
966 #if defined(LIBXML_XPTR_ENABLED)
967 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
969     int i;
970     char shift[100];
971 
972     for (i = 0;((i < depth) && (i < 25));i++)
973         shift[2 * i] = shift[2 * i + 1] = ' ';
974     shift[2 * i] = shift[2 * i + 1] = 0;
975 
976     if (cur == NULL) {
977 	fprintf(output, "%s", shift);
978 	fprintf(output, "LocationSet is NULL !\n");
979 	return;
980 
981     }
982 
983     for (i = 0;i < cur->locNr;i++) {
984 	fprintf(output, "%s", shift);
985         fprintf(output, "%d : ", i + 1);
986 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987     }
988 }
989 #endif /* LIBXML_XPTR_ENABLED */
990 
991 /**
992  * xmlXPathDebugDumpObject:
993  * @output:  the FILE * to dump the output
994  * @cur:  the object to inspect
995  * @depth:  indentation level
996  *
997  * Dump the content of the object for debugging purposes
998  */
999 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1001     int i;
1002     char shift[100];
1003 
1004     if (output == NULL) return;
1005 
1006     for (i = 0;((i < depth) && (i < 25));i++)
1007         shift[2 * i] = shift[2 * i + 1] = ' ';
1008     shift[2 * i] = shift[2 * i + 1] = 0;
1009 
1010 
1011     fprintf(output, "%s", shift);
1012 
1013     if (cur == NULL) {
1014         fprintf(output, "Object is empty (NULL)\n");
1015 	return;
1016     }
1017     switch(cur->type) {
1018         case XPATH_UNDEFINED:
1019 	    fprintf(output, "Object is uninitialized\n");
1020 	    break;
1021         case XPATH_NODESET:
1022 	    fprintf(output, "Object is a Node Set :\n");
1023 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 	    break;
1025 	case XPATH_XSLT_TREE:
1026 	    fprintf(output, "Object is an XSLT value tree :\n");
1027 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1028 	    break;
1029         case XPATH_BOOLEAN:
1030 	    fprintf(output, "Object is a Boolean : ");
1031 	    if (cur->boolval) fprintf(output, "true\n");
1032 	    else fprintf(output, "false\n");
1033 	    break;
1034         case XPATH_NUMBER:
1035 	    switch (xmlXPathIsInf(cur->floatval)) {
1036 	    case 1:
1037 		fprintf(output, "Object is a number : Infinity\n");
1038 		break;
1039 	    case -1:
1040 		fprintf(output, "Object is a number : -Infinity\n");
1041 		break;
1042 	    default:
1043 		if (xmlXPathIsNaN(cur->floatval)) {
1044 		    fprintf(output, "Object is a number : NaN\n");
1045 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 		    fprintf(output, "Object is a number : 0\n");
1047 		} else {
1048 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 		}
1050 	    }
1051 	    break;
1052         case XPATH_STRING:
1053 	    fprintf(output, "Object is a string : ");
1054 	    xmlDebugDumpString(output, cur->stringval);
1055 	    fprintf(output, "\n");
1056 	    break;
1057 	case XPATH_POINT:
1058 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1059 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 	    fprintf(output, "\n");
1061 	    break;
1062 	case XPATH_RANGE:
1063 	    if ((cur->user2 == NULL) ||
1064 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 		fprintf(output, "Object is a collapsed range :\n");
1066 		fprintf(output, "%s", shift);
1067 		if (cur->index >= 0)
1068 		    fprintf(output, "index %d in ", cur->index);
1069 		fprintf(output, "node\n");
1070 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 			              depth + 1);
1072 	    } else  {
1073 		fprintf(output, "Object is a range :\n");
1074 		fprintf(output, "%s", shift);
1075 		fprintf(output, "From ");
1076 		if (cur->index >= 0)
1077 		    fprintf(output, "index %d in ", cur->index);
1078 		fprintf(output, "node\n");
1079 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 			              depth + 1);
1081 		fprintf(output, "%s", shift);
1082 		fprintf(output, "To ");
1083 		if (cur->index2 >= 0)
1084 		    fprintf(output, "index %d in ", cur->index2);
1085 		fprintf(output, "node\n");
1086 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 			              depth + 1);
1088 		fprintf(output, "\n");
1089 	    }
1090 	    break;
1091 	case XPATH_LOCATIONSET:
1092 #if defined(LIBXML_XPTR_ENABLED)
1093 	    fprintf(output, "Object is a Location Set:\n");
1094 	    xmlXPathDebugDumpLocationSet(output,
1095 		    (xmlLocationSetPtr) cur->user, depth);
1096 #endif
1097 	    break;
1098 	case XPATH_USERS:
1099 	    fprintf(output, "Object is user defined\n");
1100 	    break;
1101     }
1102 }
1103 
1104 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106 	                     xmlXPathStepOpPtr op, int depth) {
1107     int i;
1108     char shift[100];
1109 
1110     for (i = 0;((i < depth) && (i < 25));i++)
1111         shift[2 * i] = shift[2 * i + 1] = ' ';
1112     shift[2 * i] = shift[2 * i + 1] = 0;
1113 
1114     fprintf(output, "%s", shift);
1115     if (op == NULL) {
1116 	fprintf(output, "Step is NULL\n");
1117 	return;
1118     }
1119     switch (op->op) {
1120         case XPATH_OP_END:
1121 	    fprintf(output, "END"); break;
1122         case XPATH_OP_AND:
1123 	    fprintf(output, "AND"); break;
1124         case XPATH_OP_OR:
1125 	    fprintf(output, "OR"); break;
1126         case XPATH_OP_EQUAL:
1127 	     if (op->value)
1128 		 fprintf(output, "EQUAL =");
1129 	     else
1130 		 fprintf(output, "EQUAL !=");
1131 	     break;
1132         case XPATH_OP_CMP:
1133 	     if (op->value)
1134 		 fprintf(output, "CMP <");
1135 	     else
1136 		 fprintf(output, "CMP >");
1137 	     if (!op->value2)
1138 		 fprintf(output, "=");
1139 	     break;
1140         case XPATH_OP_PLUS:
1141 	     if (op->value == 0)
1142 		 fprintf(output, "PLUS -");
1143 	     else if (op->value == 1)
1144 		 fprintf(output, "PLUS +");
1145 	     else if (op->value == 2)
1146 		 fprintf(output, "PLUS unary -");
1147 	     else if (op->value == 3)
1148 		 fprintf(output, "PLUS unary - -");
1149 	     break;
1150         case XPATH_OP_MULT:
1151 	     if (op->value == 0)
1152 		 fprintf(output, "MULT *");
1153 	     else if (op->value == 1)
1154 		 fprintf(output, "MULT div");
1155 	     else
1156 		 fprintf(output, "MULT mod");
1157 	     break;
1158         case XPATH_OP_UNION:
1159 	     fprintf(output, "UNION"); break;
1160         case XPATH_OP_ROOT:
1161 	     fprintf(output, "ROOT"); break;
1162         case XPATH_OP_NODE:
1163 	     fprintf(output, "NODE"); break;
1164         case XPATH_OP_RESET:
1165 	     fprintf(output, "RESET"); break;
1166         case XPATH_OP_SORT:
1167 	     fprintf(output, "SORT"); break;
1168         case XPATH_OP_COLLECT: {
1169 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172 	    const xmlChar *prefix = op->value4;
1173 	    const xmlChar *name = op->value5;
1174 
1175 	    fprintf(output, "COLLECT ");
1176 	    switch (axis) {
1177 		case AXIS_ANCESTOR:
1178 		    fprintf(output, " 'ancestors' "); break;
1179 		case AXIS_ANCESTOR_OR_SELF:
1180 		    fprintf(output, " 'ancestors-or-self' "); break;
1181 		case AXIS_ATTRIBUTE:
1182 		    fprintf(output, " 'attributes' "); break;
1183 		case AXIS_CHILD:
1184 		    fprintf(output, " 'child' "); break;
1185 		case AXIS_DESCENDANT:
1186 		    fprintf(output, " 'descendant' "); break;
1187 		case AXIS_DESCENDANT_OR_SELF:
1188 		    fprintf(output, " 'descendant-or-self' "); break;
1189 		case AXIS_FOLLOWING:
1190 		    fprintf(output, " 'following' "); break;
1191 		case AXIS_FOLLOWING_SIBLING:
1192 		    fprintf(output, " 'following-siblings' "); break;
1193 		case AXIS_NAMESPACE:
1194 		    fprintf(output, " 'namespace' "); break;
1195 		case AXIS_PARENT:
1196 		    fprintf(output, " 'parent' "); break;
1197 		case AXIS_PRECEDING:
1198 		    fprintf(output, " 'preceding' "); break;
1199 		case AXIS_PRECEDING_SIBLING:
1200 		    fprintf(output, " 'preceding-sibling' "); break;
1201 		case AXIS_SELF:
1202 		    fprintf(output, " 'self' "); break;
1203 	    }
1204 	    switch (test) {
1205                 case NODE_TEST_NONE:
1206 		    fprintf(output, "'none' "); break;
1207                 case NODE_TEST_TYPE:
1208 		    fprintf(output, "'type' "); break;
1209                 case NODE_TEST_PI:
1210 		    fprintf(output, "'PI' "); break;
1211                 case NODE_TEST_ALL:
1212 		    fprintf(output, "'all' "); break;
1213                 case NODE_TEST_NS:
1214 		    fprintf(output, "'namespace' "); break;
1215                 case NODE_TEST_NAME:
1216 		    fprintf(output, "'name' "); break;
1217 	    }
1218 	    switch (type) {
1219                 case NODE_TYPE_NODE:
1220 		    fprintf(output, "'node' "); break;
1221                 case NODE_TYPE_COMMENT:
1222 		    fprintf(output, "'comment' "); break;
1223                 case NODE_TYPE_TEXT:
1224 		    fprintf(output, "'text' "); break;
1225                 case NODE_TYPE_PI:
1226 		    fprintf(output, "'PI' "); break;
1227 	    }
1228 	    if (prefix != NULL)
1229 		fprintf(output, "%s:", prefix);
1230 	    if (name != NULL)
1231 		fprintf(output, "%s", (const char *) name);
1232 	    break;
1233 
1234         }
1235 	case XPATH_OP_VALUE: {
1236 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237 
1238 	    fprintf(output, "ELEM ");
1239 	    xmlXPathDebugDumpObject(output, object, 0);
1240 	    goto finish;
1241 	}
1242 	case XPATH_OP_VARIABLE: {
1243 	    const xmlChar *prefix = op->value5;
1244 	    const xmlChar *name = op->value4;
1245 
1246 	    if (prefix != NULL)
1247 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 	    else
1249 		fprintf(output, "VARIABLE %s", name);
1250 	    break;
1251 	}
1252 	case XPATH_OP_FUNCTION: {
1253 	    int nbargs = op->value;
1254 	    const xmlChar *prefix = op->value5;
1255 	    const xmlChar *name = op->value4;
1256 
1257 	    if (prefix != NULL)
1258 		fprintf(output, "FUNCTION %s:%s(%d args)",
1259 			prefix, name, nbargs);
1260 	    else
1261 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 	    break;
1263 	}
1264         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267 #ifdef LIBXML_XPTR_ENABLED
1268         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269 #endif
1270 	default:
1271         fprintf(output, "UNKNOWN %d\n", op->op); return;
1272     }
1273     fprintf(output, "\n");
1274 finish:
1275     if (op->ch1 >= 0)
1276 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277     if (op->ch2 >= 0)
1278 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279 }
1280 
1281 /**
1282  * xmlXPathDebugDumpCompExpr:
1283  * @output:  the FILE * for the output
1284  * @comp:  the precompiled XPath expression
1285  * @depth:  the indentation level.
1286  *
1287  * Dumps the tree of the compiled XPath expression.
1288  */
1289 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 	                  int depth) {
1292     int i;
1293     char shift[100];
1294 
1295     if ((output == NULL) || (comp == NULL)) return;
1296 
1297     for (i = 0;((i < depth) && (i < 25));i++)
1298         shift[2 * i] = shift[2 * i + 1] = ' ';
1299     shift[2 * i] = shift[2 * i + 1] = 0;
1300 
1301     fprintf(output, "%s", shift);
1302 
1303     fprintf(output, "Compiled Expression : %d elements\n",
1304 	    comp->nbStep);
1305     i = comp->last;
1306     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307 }
1308 
1309 #ifdef XP_DEBUG_OBJ_USAGE
1310 
1311 /*
1312 * XPath object usage related debugging variables.
1313 */
1314 static int xmlXPathDebugObjCounterUndefined = 0;
1315 static int xmlXPathDebugObjCounterNodeset = 0;
1316 static int xmlXPathDebugObjCounterBool = 0;
1317 static int xmlXPathDebugObjCounterNumber = 0;
1318 static int xmlXPathDebugObjCounterString = 0;
1319 static int xmlXPathDebugObjCounterPoint = 0;
1320 static int xmlXPathDebugObjCounterRange = 0;
1321 static int xmlXPathDebugObjCounterLocset = 0;
1322 static int xmlXPathDebugObjCounterUsers = 0;
1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
1324 static int xmlXPathDebugObjCounterAll = 0;
1325 
1326 static int xmlXPathDebugObjTotalUndefined = 0;
1327 static int xmlXPathDebugObjTotalNodeset = 0;
1328 static int xmlXPathDebugObjTotalBool = 0;
1329 static int xmlXPathDebugObjTotalNumber = 0;
1330 static int xmlXPathDebugObjTotalString = 0;
1331 static int xmlXPathDebugObjTotalPoint = 0;
1332 static int xmlXPathDebugObjTotalRange = 0;
1333 static int xmlXPathDebugObjTotalLocset = 0;
1334 static int xmlXPathDebugObjTotalUsers = 0;
1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
1336 static int xmlXPathDebugObjTotalAll = 0;
1337 
1338 static int xmlXPathDebugObjMaxUndefined = 0;
1339 static int xmlXPathDebugObjMaxNodeset = 0;
1340 static int xmlXPathDebugObjMaxBool = 0;
1341 static int xmlXPathDebugObjMaxNumber = 0;
1342 static int xmlXPathDebugObjMaxString = 0;
1343 static int xmlXPathDebugObjMaxPoint = 0;
1344 static int xmlXPathDebugObjMaxRange = 0;
1345 static int xmlXPathDebugObjMaxLocset = 0;
1346 static int xmlXPathDebugObjMaxUsers = 0;
1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
1348 static int xmlXPathDebugObjMaxAll = 0;
1349 
1350 /* REVISIT TODO: Make this static when committing */
1351 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353 {
1354     if (ctxt != NULL) {
1355 	if (ctxt->cache != NULL) {
1356 	    xmlXPathContextCachePtr cache =
1357 		(xmlXPathContextCachePtr) ctxt->cache;
1358 
1359 	    cache->dbgCachedAll = 0;
1360 	    cache->dbgCachedNodeset = 0;
1361 	    cache->dbgCachedString = 0;
1362 	    cache->dbgCachedBool = 0;
1363 	    cache->dbgCachedNumber = 0;
1364 	    cache->dbgCachedPoint = 0;
1365 	    cache->dbgCachedRange = 0;
1366 	    cache->dbgCachedLocset = 0;
1367 	    cache->dbgCachedUsers = 0;
1368 	    cache->dbgCachedXSLTTree = 0;
1369 	    cache->dbgCachedUndefined = 0;
1370 
1371 	    cache->dbgReusedAll = 0;
1372 	    cache->dbgReusedNodeset = 0;
1373 	    cache->dbgReusedString = 0;
1374 	    cache->dbgReusedBool = 0;
1375 	    cache->dbgReusedNumber = 0;
1376 	    cache->dbgReusedPoint = 0;
1377 	    cache->dbgReusedRange = 0;
1378 	    cache->dbgReusedLocset = 0;
1379 	    cache->dbgReusedUsers = 0;
1380 	    cache->dbgReusedXSLTTree = 0;
1381 	    cache->dbgReusedUndefined = 0;
1382 	}
1383     }
1384 
1385     xmlXPathDebugObjCounterUndefined = 0;
1386     xmlXPathDebugObjCounterNodeset = 0;
1387     xmlXPathDebugObjCounterBool = 0;
1388     xmlXPathDebugObjCounterNumber = 0;
1389     xmlXPathDebugObjCounterString = 0;
1390     xmlXPathDebugObjCounterPoint = 0;
1391     xmlXPathDebugObjCounterRange = 0;
1392     xmlXPathDebugObjCounterLocset = 0;
1393     xmlXPathDebugObjCounterUsers = 0;
1394     xmlXPathDebugObjCounterXSLTTree = 0;
1395     xmlXPathDebugObjCounterAll = 0;
1396 
1397     xmlXPathDebugObjTotalUndefined = 0;
1398     xmlXPathDebugObjTotalNodeset = 0;
1399     xmlXPathDebugObjTotalBool = 0;
1400     xmlXPathDebugObjTotalNumber = 0;
1401     xmlXPathDebugObjTotalString = 0;
1402     xmlXPathDebugObjTotalPoint = 0;
1403     xmlXPathDebugObjTotalRange = 0;
1404     xmlXPathDebugObjTotalLocset = 0;
1405     xmlXPathDebugObjTotalUsers = 0;
1406     xmlXPathDebugObjTotalXSLTTree = 0;
1407     xmlXPathDebugObjTotalAll = 0;
1408 
1409     xmlXPathDebugObjMaxUndefined = 0;
1410     xmlXPathDebugObjMaxNodeset = 0;
1411     xmlXPathDebugObjMaxBool = 0;
1412     xmlXPathDebugObjMaxNumber = 0;
1413     xmlXPathDebugObjMaxString = 0;
1414     xmlXPathDebugObjMaxPoint = 0;
1415     xmlXPathDebugObjMaxRange = 0;
1416     xmlXPathDebugObjMaxLocset = 0;
1417     xmlXPathDebugObjMaxUsers = 0;
1418     xmlXPathDebugObjMaxXSLTTree = 0;
1419     xmlXPathDebugObjMaxAll = 0;
1420 
1421 }
1422 
1423 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 			      xmlXPathObjectType objType)
1426 {
1427     int isCached = 0;
1428 
1429     if (ctxt != NULL) {
1430 	if (ctxt->cache != NULL) {
1431 	    xmlXPathContextCachePtr cache =
1432 		(xmlXPathContextCachePtr) ctxt->cache;
1433 
1434 	    isCached = 1;
1435 
1436 	    cache->dbgReusedAll++;
1437 	    switch (objType) {
1438 		case XPATH_UNDEFINED:
1439 		    cache->dbgReusedUndefined++;
1440 		    break;
1441 		case XPATH_NODESET:
1442 		    cache->dbgReusedNodeset++;
1443 		    break;
1444 		case XPATH_BOOLEAN:
1445 		    cache->dbgReusedBool++;
1446 		    break;
1447 		case XPATH_NUMBER:
1448 		    cache->dbgReusedNumber++;
1449 		    break;
1450 		case XPATH_STRING:
1451 		    cache->dbgReusedString++;
1452 		    break;
1453 		case XPATH_POINT:
1454 		    cache->dbgReusedPoint++;
1455 		    break;
1456 		case XPATH_RANGE:
1457 		    cache->dbgReusedRange++;
1458 		    break;
1459 		case XPATH_LOCATIONSET:
1460 		    cache->dbgReusedLocset++;
1461 		    break;
1462 		case XPATH_USERS:
1463 		    cache->dbgReusedUsers++;
1464 		    break;
1465 		case XPATH_XSLT_TREE:
1466 		    cache->dbgReusedXSLTTree++;
1467 		    break;
1468 		default:
1469 		    break;
1470 	    }
1471 	}
1472     }
1473 
1474     switch (objType) {
1475 	case XPATH_UNDEFINED:
1476 	    if (! isCached)
1477 		xmlXPathDebugObjTotalUndefined++;
1478 	    xmlXPathDebugObjCounterUndefined++;
1479 	    if (xmlXPathDebugObjCounterUndefined >
1480 		xmlXPathDebugObjMaxUndefined)
1481 		xmlXPathDebugObjMaxUndefined =
1482 		    xmlXPathDebugObjCounterUndefined;
1483 	    break;
1484 	case XPATH_NODESET:
1485 	    if (! isCached)
1486 		xmlXPathDebugObjTotalNodeset++;
1487 	    xmlXPathDebugObjCounterNodeset++;
1488 	    if (xmlXPathDebugObjCounterNodeset >
1489 		xmlXPathDebugObjMaxNodeset)
1490 		xmlXPathDebugObjMaxNodeset =
1491 		    xmlXPathDebugObjCounterNodeset;
1492 	    break;
1493 	case XPATH_BOOLEAN:
1494 	    if (! isCached)
1495 		xmlXPathDebugObjTotalBool++;
1496 	    xmlXPathDebugObjCounterBool++;
1497 	    if (xmlXPathDebugObjCounterBool >
1498 		xmlXPathDebugObjMaxBool)
1499 		xmlXPathDebugObjMaxBool =
1500 		    xmlXPathDebugObjCounterBool;
1501 	    break;
1502 	case XPATH_NUMBER:
1503 	    if (! isCached)
1504 		xmlXPathDebugObjTotalNumber++;
1505 	    xmlXPathDebugObjCounterNumber++;
1506 	    if (xmlXPathDebugObjCounterNumber >
1507 		xmlXPathDebugObjMaxNumber)
1508 		xmlXPathDebugObjMaxNumber =
1509 		    xmlXPathDebugObjCounterNumber;
1510 	    break;
1511 	case XPATH_STRING:
1512 	    if (! isCached)
1513 		xmlXPathDebugObjTotalString++;
1514 	    xmlXPathDebugObjCounterString++;
1515 	    if (xmlXPathDebugObjCounterString >
1516 		xmlXPathDebugObjMaxString)
1517 		xmlXPathDebugObjMaxString =
1518 		    xmlXPathDebugObjCounterString;
1519 	    break;
1520 	case XPATH_POINT:
1521 	    if (! isCached)
1522 		xmlXPathDebugObjTotalPoint++;
1523 	    xmlXPathDebugObjCounterPoint++;
1524 	    if (xmlXPathDebugObjCounterPoint >
1525 		xmlXPathDebugObjMaxPoint)
1526 		xmlXPathDebugObjMaxPoint =
1527 		    xmlXPathDebugObjCounterPoint;
1528 	    break;
1529 	case XPATH_RANGE:
1530 	    if (! isCached)
1531 		xmlXPathDebugObjTotalRange++;
1532 	    xmlXPathDebugObjCounterRange++;
1533 	    if (xmlXPathDebugObjCounterRange >
1534 		xmlXPathDebugObjMaxRange)
1535 		xmlXPathDebugObjMaxRange =
1536 		    xmlXPathDebugObjCounterRange;
1537 	    break;
1538 	case XPATH_LOCATIONSET:
1539 	    if (! isCached)
1540 		xmlXPathDebugObjTotalLocset++;
1541 	    xmlXPathDebugObjCounterLocset++;
1542 	    if (xmlXPathDebugObjCounterLocset >
1543 		xmlXPathDebugObjMaxLocset)
1544 		xmlXPathDebugObjMaxLocset =
1545 		    xmlXPathDebugObjCounterLocset;
1546 	    break;
1547 	case XPATH_USERS:
1548 	    if (! isCached)
1549 		xmlXPathDebugObjTotalUsers++;
1550 	    xmlXPathDebugObjCounterUsers++;
1551 	    if (xmlXPathDebugObjCounterUsers >
1552 		xmlXPathDebugObjMaxUsers)
1553 		xmlXPathDebugObjMaxUsers =
1554 		    xmlXPathDebugObjCounterUsers;
1555 	    break;
1556 	case XPATH_XSLT_TREE:
1557 	    if (! isCached)
1558 		xmlXPathDebugObjTotalXSLTTree++;
1559 	    xmlXPathDebugObjCounterXSLTTree++;
1560 	    if (xmlXPathDebugObjCounterXSLTTree >
1561 		xmlXPathDebugObjMaxXSLTTree)
1562 		xmlXPathDebugObjMaxXSLTTree =
1563 		    xmlXPathDebugObjCounterXSLTTree;
1564 	    break;
1565 	default:
1566 	    break;
1567     }
1568     if (! isCached)
1569 	xmlXPathDebugObjTotalAll++;
1570     xmlXPathDebugObjCounterAll++;
1571     if (xmlXPathDebugObjCounterAll >
1572 	xmlXPathDebugObjMaxAll)
1573 	xmlXPathDebugObjMaxAll =
1574 	    xmlXPathDebugObjCounterAll;
1575 }
1576 
1577 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 			      xmlXPathObjectType objType)
1580 {
1581     int isCached = 0;
1582 
1583     if (ctxt != NULL) {
1584 	if (ctxt->cache != NULL) {
1585 	    xmlXPathContextCachePtr cache =
1586 		(xmlXPathContextCachePtr) ctxt->cache;
1587 
1588 	    isCached = 1;
1589 
1590 	    cache->dbgCachedAll++;
1591 	    switch (objType) {
1592 		case XPATH_UNDEFINED:
1593 		    cache->dbgCachedUndefined++;
1594 		    break;
1595 		case XPATH_NODESET:
1596 		    cache->dbgCachedNodeset++;
1597 		    break;
1598 		case XPATH_BOOLEAN:
1599 		    cache->dbgCachedBool++;
1600 		    break;
1601 		case XPATH_NUMBER:
1602 		    cache->dbgCachedNumber++;
1603 		    break;
1604 		case XPATH_STRING:
1605 		    cache->dbgCachedString++;
1606 		    break;
1607 		case XPATH_POINT:
1608 		    cache->dbgCachedPoint++;
1609 		    break;
1610 		case XPATH_RANGE:
1611 		    cache->dbgCachedRange++;
1612 		    break;
1613 		case XPATH_LOCATIONSET:
1614 		    cache->dbgCachedLocset++;
1615 		    break;
1616 		case XPATH_USERS:
1617 		    cache->dbgCachedUsers++;
1618 		    break;
1619 		case XPATH_XSLT_TREE:
1620 		    cache->dbgCachedXSLTTree++;
1621 		    break;
1622 		default:
1623 		    break;
1624 	    }
1625 
1626 	}
1627     }
1628     switch (objType) {
1629 	case XPATH_UNDEFINED:
1630 	    xmlXPathDebugObjCounterUndefined--;
1631 	    break;
1632 	case XPATH_NODESET:
1633 	    xmlXPathDebugObjCounterNodeset--;
1634 	    break;
1635 	case XPATH_BOOLEAN:
1636 	    xmlXPathDebugObjCounterBool--;
1637 	    break;
1638 	case XPATH_NUMBER:
1639 	    xmlXPathDebugObjCounterNumber--;
1640 	    break;
1641 	case XPATH_STRING:
1642 	    xmlXPathDebugObjCounterString--;
1643 	    break;
1644 	case XPATH_POINT:
1645 	    xmlXPathDebugObjCounterPoint--;
1646 	    break;
1647 	case XPATH_RANGE:
1648 	    xmlXPathDebugObjCounterRange--;
1649 	    break;
1650 	case XPATH_LOCATIONSET:
1651 	    xmlXPathDebugObjCounterLocset--;
1652 	    break;
1653 	case XPATH_USERS:
1654 	    xmlXPathDebugObjCounterUsers--;
1655 	    break;
1656 	case XPATH_XSLT_TREE:
1657 	    xmlXPathDebugObjCounterXSLTTree--;
1658 	    break;
1659 	default:
1660 	    break;
1661     }
1662     xmlXPathDebugObjCounterAll--;
1663 }
1664 
1665 /* REVISIT TODO: Make this static when committing */
1666 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668 {
1669     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 	reqXSLTTree, reqUndefined;
1671     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675     int leftObjs = xmlXPathDebugObjCounterAll;
1676 
1677     reqAll = xmlXPathDebugObjTotalAll;
1678     reqNodeset = xmlXPathDebugObjTotalNodeset;
1679     reqString = xmlXPathDebugObjTotalString;
1680     reqBool = xmlXPathDebugObjTotalBool;
1681     reqNumber = xmlXPathDebugObjTotalNumber;
1682     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683     reqUndefined = xmlXPathDebugObjTotalUndefined;
1684 
1685     printf("# XPath object usage:\n");
1686 
1687     if (ctxt != NULL) {
1688 	if (ctxt->cache != NULL) {
1689 	    xmlXPathContextCachePtr cache =
1690 		(xmlXPathContextCachePtr) ctxt->cache;
1691 
1692 	    reAll = cache->dbgReusedAll;
1693 	    reqAll += reAll;
1694 	    reNodeset = cache->dbgReusedNodeset;
1695 	    reqNodeset += reNodeset;
1696 	    reString = cache->dbgReusedString;
1697 	    reqString += reString;
1698 	    reBool = cache->dbgReusedBool;
1699 	    reqBool += reBool;
1700 	    reNumber = cache->dbgReusedNumber;
1701 	    reqNumber += reNumber;
1702 	    reXSLTTree = cache->dbgReusedXSLTTree;
1703 	    reqXSLTTree += reXSLTTree;
1704 	    reUndefined = cache->dbgReusedUndefined;
1705 	    reqUndefined += reUndefined;
1706 
1707 	    caAll = cache->dbgCachedAll;
1708 	    caBool = cache->dbgCachedBool;
1709 	    caNodeset = cache->dbgCachedNodeset;
1710 	    caString = cache->dbgCachedString;
1711 	    caNumber = cache->dbgCachedNumber;
1712 	    caXSLTTree = cache->dbgCachedXSLTTree;
1713 	    caUndefined = cache->dbgCachedUndefined;
1714 
1715 	    if (cache->nodesetObjs)
1716 		leftObjs -= cache->nodesetObjs->number;
1717 	    if (cache->stringObjs)
1718 		leftObjs -= cache->stringObjs->number;
1719 	    if (cache->booleanObjs)
1720 		leftObjs -= cache->booleanObjs->number;
1721 	    if (cache->numberObjs)
1722 		leftObjs -= cache->numberObjs->number;
1723 	    if (cache->miscObjs)
1724 		leftObjs -= cache->miscObjs->number;
1725 	}
1726     }
1727 
1728     printf("# all\n");
1729     printf("#   total  : %d\n", reqAll);
1730     printf("#   left  : %d\n", leftObjs);
1731     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1732     printf("#   reused : %d\n", reAll);
1733     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1734 
1735     printf("# node-sets\n");
1736     printf("#   total  : %d\n", reqNodeset);
1737     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1738     printf("#   reused : %d\n", reNodeset);
1739     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1740 
1741     printf("# strings\n");
1742     printf("#   total  : %d\n", reqString);
1743     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1744     printf("#   reused : %d\n", reString);
1745     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1746 
1747     printf("# booleans\n");
1748     printf("#   total  : %d\n", reqBool);
1749     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1750     printf("#   reused : %d\n", reBool);
1751     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1752 
1753     printf("# numbers\n");
1754     printf("#   total  : %d\n", reqNumber);
1755     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1756     printf("#   reused : %d\n", reNumber);
1757     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1758 
1759     printf("# XSLT result tree fragments\n");
1760     printf("#   total  : %d\n", reqXSLTTree);
1761     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762     printf("#   reused : %d\n", reXSLTTree);
1763     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764 
1765     printf("# undefined\n");
1766     printf("#   total  : %d\n", reqUndefined);
1767     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1768     printf("#   reused : %d\n", reUndefined);
1769     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1770 
1771 }
1772 
1773 #endif /* XP_DEBUG_OBJ_USAGE */
1774 
1775 #endif /* LIBXML_DEBUG_ENABLED */
1776 
1777 /************************************************************************
1778  *									*
1779  *			XPath object caching				*
1780  *									*
1781  ************************************************************************/
1782 
1783 /**
1784  * xmlXPathNewCache:
1785  *
1786  * Create a new object cache
1787  *
1788  * Returns the xmlXPathCache just allocated.
1789  */
1790 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1791 xmlXPathNewCache(void)
1792 {
1793     xmlXPathContextCachePtr ret;
1794 
1795     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796     if (ret == NULL) {
1797         xmlXPathErrMemory(NULL, "creating object cache\n");
1798 	return(NULL);
1799     }
1800     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801     ret->maxNodeset = 100;
1802     ret->maxString = 100;
1803     ret->maxBoolean = 100;
1804     ret->maxNumber = 100;
1805     ret->maxMisc = 100;
1806     return(ret);
1807 }
1808 
1809 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1811 {
1812     int i;
1813     xmlXPathObjectPtr obj;
1814 
1815     if (list == NULL)
1816 	return;
1817 
1818     for (i = 0; i < list->number; i++) {
1819 	obj = list->items[i];
1820 	/*
1821 	* Note that it is already assured that we don't need to
1822 	* look out for namespace nodes in the node-set.
1823 	*/
1824 	if (obj->nodesetval != NULL) {
1825 	    if (obj->nodesetval->nodeTab != NULL)
1826 		xmlFree(obj->nodesetval->nodeTab);
1827 	    xmlFree(obj->nodesetval);
1828 	}
1829 	xmlFree(obj);
1830 #ifdef XP_DEBUG_OBJ_USAGE
1831 	xmlXPathDebugObjCounterAll--;
1832 #endif
1833     }
1834     xmlPointerListFree(list);
1835 }
1836 
1837 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1839 {
1840     if (cache == NULL)
1841 	return;
1842     if (cache->nodesetObjs)
1843 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844     if (cache->stringObjs)
1845 	xmlXPathCacheFreeObjectList(cache->stringObjs);
1846     if (cache->booleanObjs)
1847 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848     if (cache->numberObjs)
1849 	xmlXPathCacheFreeObjectList(cache->numberObjs);
1850     if (cache->miscObjs)
1851 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1852     xmlFree(cache);
1853 }
1854 
1855 /**
1856  * xmlXPathContextSetCache:
1857  *
1858  * @ctxt:  the XPath context
1859  * @active: enables/disables (creates/frees) the cache
1860  * @value: a value with semantics dependant on @options
1861  * @options: options (currently only the value 0 is used)
1862  *
1863  * Creates/frees an object cache on the XPath context.
1864  * If activates XPath objects (xmlXPathObject) will be cached internally
1865  * to be reused.
1866  * @options:
1867  *   0: This will set the XPath object caching:
1868  *      @value:
1869  *        This will set the maximum number of XPath objects
1870  *        to be cached per slot
1871  *        There are 5 slots for: node-set, string, number, boolean, and
1872  *        misc objects. Use <0 for the default number (100).
1873  *   Other values for @options have currently no effect.
1874  *
1875  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876  */
1877 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 			int active,
1880 			int value,
1881 			int options)
1882 {
1883     if (ctxt == NULL)
1884 	return(-1);
1885     if (active) {
1886 	xmlXPathContextCachePtr cache;
1887 
1888 	if (ctxt->cache == NULL) {
1889 	    ctxt->cache = xmlXPathNewCache();
1890 	    if (ctxt->cache == NULL)
1891 		return(-1);
1892 	}
1893 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1894 	if (options == 0) {
1895 	    if (value < 0)
1896 		value = 100;
1897 	    cache->maxNodeset = value;
1898 	    cache->maxString = value;
1899 	    cache->maxNumber = value;
1900 	    cache->maxBoolean = value;
1901 	    cache->maxMisc = value;
1902 	}
1903     } else if (ctxt->cache != NULL) {
1904 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 	ctxt->cache = NULL;
1906     }
1907     return(0);
1908 }
1909 
1910 /**
1911  * xmlXPathCacheWrapNodeSet:
1912  * @ctxt: the XPath context
1913  * @val:  the NodePtr value
1914  *
1915  * This is the cached version of xmlXPathWrapNodeSet().
1916  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917  *
1918  * Returns the created or reused object.
1919  */
1920 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922 {
1923     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 	xmlXPathContextCachePtr cache =
1925 	    (xmlXPathContextCachePtr) ctxt->cache;
1926 
1927 	if ((cache->miscObjs != NULL) &&
1928 	    (cache->miscObjs->number != 0))
1929 	{
1930 	    xmlXPathObjectPtr ret;
1931 
1932 	    ret = (xmlXPathObjectPtr)
1933 		cache->miscObjs->items[--cache->miscObjs->number];
1934 	    ret->type = XPATH_NODESET;
1935 	    ret->nodesetval = val;
1936 #ifdef XP_DEBUG_OBJ_USAGE
1937 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938 #endif
1939 	    return(ret);
1940 	}
1941     }
1942 
1943     return(xmlXPathWrapNodeSet(val));
1944 
1945 }
1946 
1947 /**
1948  * xmlXPathCacheWrapString:
1949  * @ctxt: the XPath context
1950  * @val:  the xmlChar * value
1951  *
1952  * This is the cached version of xmlXPathWrapString().
1953  * Wraps the @val string into an XPath object.
1954  *
1955  * Returns the created or reused object.
1956  */
1957 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959 {
1960     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962 
1963 	if ((cache->stringObjs != NULL) &&
1964 	    (cache->stringObjs->number != 0))
1965 	{
1966 
1967 	    xmlXPathObjectPtr ret;
1968 
1969 	    ret = (xmlXPathObjectPtr)
1970 		cache->stringObjs->items[--cache->stringObjs->number];
1971 	    ret->type = XPATH_STRING;
1972 	    ret->stringval = val;
1973 #ifdef XP_DEBUG_OBJ_USAGE
1974 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975 #endif
1976 	    return(ret);
1977 	} else if ((cache->miscObjs != NULL) &&
1978 	    (cache->miscObjs->number != 0))
1979 	{
1980 	    xmlXPathObjectPtr ret;
1981 	    /*
1982 	    * Fallback to misc-cache.
1983 	    */
1984 	    ret = (xmlXPathObjectPtr)
1985 		cache->miscObjs->items[--cache->miscObjs->number];
1986 
1987 	    ret->type = XPATH_STRING;
1988 	    ret->stringval = val;
1989 #ifdef XP_DEBUG_OBJ_USAGE
1990 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991 #endif
1992 	    return(ret);
1993 	}
1994     }
1995     return(xmlXPathWrapString(val));
1996 }
1997 
1998 /**
1999  * xmlXPathCacheNewNodeSet:
2000  * @ctxt: the XPath context
2001  * @val:  the NodePtr value
2002  *
2003  * This is the cached version of xmlXPathNewNodeSet().
2004  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005  * it with the single Node @val
2006  *
2007  * Returns the created or reused object.
2008  */
2009 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011 {
2012     if ((ctxt != NULL) && (ctxt->cache)) {
2013 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014 
2015 	if ((cache->nodesetObjs != NULL) &&
2016 	    (cache->nodesetObjs->number != 0))
2017 	{
2018 	    xmlXPathObjectPtr ret;
2019 	    /*
2020 	    * Use the nodset-cache.
2021 	    */
2022 	    ret = (xmlXPathObjectPtr)
2023 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 	    ret->type = XPATH_NODESET;
2025 	    ret->boolval = 0;
2026 	    if (val) {
2027 		if ((ret->nodesetval->nodeMax == 0) ||
2028 		    (val->type == XML_NAMESPACE_DECL))
2029 		{
2030 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 		} else {
2032 		    ret->nodesetval->nodeTab[0] = val;
2033 		    ret->nodesetval->nodeNr = 1;
2034 		}
2035 	    }
2036 #ifdef XP_DEBUG_OBJ_USAGE
2037 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038 #endif
2039 	    return(ret);
2040 	} else if ((cache->miscObjs != NULL) &&
2041 	    (cache->miscObjs->number != 0))
2042 	{
2043 	    xmlXPathObjectPtr ret;
2044 	    /*
2045 	    * Fallback to misc-cache.
2046 	    */
2047 
2048 	    ret = (xmlXPathObjectPtr)
2049 		cache->miscObjs->items[--cache->miscObjs->number];
2050 
2051 	    ret->type = XPATH_NODESET;
2052 	    ret->boolval = 0;
2053 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056 #endif
2057 	    return(ret);
2058 	}
2059     }
2060     return(xmlXPathNewNodeSet(val));
2061 }
2062 
2063 /**
2064  * xmlXPathCacheNewCString:
2065  * @ctxt: the XPath context
2066  * @val:  the char * value
2067  *
2068  * This is the cached version of xmlXPathNewCString().
2069  * Acquire an xmlXPathObjectPtr of type string and of value @val
2070  *
2071  * Returns the created or reused object.
2072  */
2073 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075 {
2076     if ((ctxt != NULL) && (ctxt->cache)) {
2077 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078 
2079 	if ((cache->stringObjs != NULL) &&
2080 	    (cache->stringObjs->number != 0))
2081 	{
2082 	    xmlXPathObjectPtr ret;
2083 
2084 	    ret = (xmlXPathObjectPtr)
2085 		cache->stringObjs->items[--cache->stringObjs->number];
2086 
2087 	    ret->type = XPATH_STRING;
2088 	    ret->stringval = xmlStrdup(BAD_CAST val);
2089 #ifdef XP_DEBUG_OBJ_USAGE
2090 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091 #endif
2092 	    return(ret);
2093 	} else if ((cache->miscObjs != NULL) &&
2094 	    (cache->miscObjs->number != 0))
2095 	{
2096 	    xmlXPathObjectPtr ret;
2097 
2098 	    ret = (xmlXPathObjectPtr)
2099 		cache->miscObjs->items[--cache->miscObjs->number];
2100 
2101 	    ret->type = XPATH_STRING;
2102 	    ret->stringval = xmlStrdup(BAD_CAST val);
2103 #ifdef XP_DEBUG_OBJ_USAGE
2104 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105 #endif
2106 	    return(ret);
2107 	}
2108     }
2109     return(xmlXPathNewCString(val));
2110 }
2111 
2112 /**
2113  * xmlXPathCacheNewString:
2114  * @ctxt: the XPath context
2115  * @val:  the xmlChar * value
2116  *
2117  * This is the cached version of xmlXPathNewString().
2118  * Acquire an xmlXPathObjectPtr of type string and of value @val
2119  *
2120  * Returns the created or reused object.
2121  */
2122 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124 {
2125     if ((ctxt != NULL) && (ctxt->cache)) {
2126 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127 
2128 	if ((cache->stringObjs != NULL) &&
2129 	    (cache->stringObjs->number != 0))
2130 	{
2131 	    xmlXPathObjectPtr ret;
2132 
2133 	    ret = (xmlXPathObjectPtr)
2134 		cache->stringObjs->items[--cache->stringObjs->number];
2135 	    ret->type = XPATH_STRING;
2136 	    if (val != NULL)
2137 		ret->stringval = xmlStrdup(val);
2138 	    else
2139 		ret->stringval = xmlStrdup((const xmlChar *)"");
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142 #endif
2143 	    return(ret);
2144 	} else if ((cache->miscObjs != NULL) &&
2145 	    (cache->miscObjs->number != 0))
2146 	{
2147 	    xmlXPathObjectPtr ret;
2148 
2149 	    ret = (xmlXPathObjectPtr)
2150 		cache->miscObjs->items[--cache->miscObjs->number];
2151 
2152 	    ret->type = XPATH_STRING;
2153 	    if (val != NULL)
2154 		ret->stringval = xmlStrdup(val);
2155 	    else
2156 		ret->stringval = xmlStrdup((const xmlChar *)"");
2157 #ifdef XP_DEBUG_OBJ_USAGE
2158 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159 #endif
2160 	    return(ret);
2161 	}
2162     }
2163     return(xmlXPathNewString(val));
2164 }
2165 
2166 /**
2167  * xmlXPathCacheNewBoolean:
2168  * @ctxt: the XPath context
2169  * @val:  the boolean value
2170  *
2171  * This is the cached version of xmlXPathNewBoolean().
2172  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173  *
2174  * Returns the created or reused object.
2175  */
2176 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178 {
2179     if ((ctxt != NULL) && (ctxt->cache)) {
2180 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181 
2182 	if ((cache->booleanObjs != NULL) &&
2183 	    (cache->booleanObjs->number != 0))
2184 	{
2185 	    xmlXPathObjectPtr ret;
2186 
2187 	    ret = (xmlXPathObjectPtr)
2188 		cache->booleanObjs->items[--cache->booleanObjs->number];
2189 	    ret->type = XPATH_BOOLEAN;
2190 	    ret->boolval = (val != 0);
2191 #ifdef XP_DEBUG_OBJ_USAGE
2192 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193 #endif
2194 	    return(ret);
2195 	} else if ((cache->miscObjs != NULL) &&
2196 	    (cache->miscObjs->number != 0))
2197 	{
2198 	    xmlXPathObjectPtr ret;
2199 
2200 	    ret = (xmlXPathObjectPtr)
2201 		cache->miscObjs->items[--cache->miscObjs->number];
2202 
2203 	    ret->type = XPATH_BOOLEAN;
2204 	    ret->boolval = (val != 0);
2205 #ifdef XP_DEBUG_OBJ_USAGE
2206 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207 #endif
2208 	    return(ret);
2209 	}
2210     }
2211     return(xmlXPathNewBoolean(val));
2212 }
2213 
2214 /**
2215  * xmlXPathCacheNewFloat:
2216  * @ctxt: the XPath context
2217  * @val:  the double value
2218  *
2219  * This is the cached version of xmlXPathNewFloat().
2220  * Acquires an xmlXPathObjectPtr of type double and of value @val
2221  *
2222  * Returns the created or reused object.
2223  */
2224 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226 {
2227      if ((ctxt != NULL) && (ctxt->cache)) {
2228 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229 
2230 	if ((cache->numberObjs != NULL) &&
2231 	    (cache->numberObjs->number != 0))
2232 	{
2233 	    xmlXPathObjectPtr ret;
2234 
2235 	    ret = (xmlXPathObjectPtr)
2236 		cache->numberObjs->items[--cache->numberObjs->number];
2237 	    ret->type = XPATH_NUMBER;
2238 	    ret->floatval = val;
2239 #ifdef XP_DEBUG_OBJ_USAGE
2240 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241 #endif
2242 	    return(ret);
2243 	} else if ((cache->miscObjs != NULL) &&
2244 	    (cache->miscObjs->number != 0))
2245 	{
2246 	    xmlXPathObjectPtr ret;
2247 
2248 	    ret = (xmlXPathObjectPtr)
2249 		cache->miscObjs->items[--cache->miscObjs->number];
2250 
2251 	    ret->type = XPATH_NUMBER;
2252 	    ret->floatval = val;
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255 #endif
2256 	    return(ret);
2257 	}
2258     }
2259     return(xmlXPathNewFloat(val));
2260 }
2261 
2262 /**
2263  * xmlXPathCacheConvertString:
2264  * @ctxt: the XPath context
2265  * @val:  an XPath object
2266  *
2267  * This is the cached version of xmlXPathConvertString().
2268  * Converts an existing object to its string() equivalent
2269  *
2270  * Returns a created or reused object, the old one is freed (cached)
2271  *         (or the operation is done directly on @val)
2272  */
2273 
2274 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276     xmlChar *res = NULL;
2277 
2278     if (val == NULL)
2279 	return(xmlXPathCacheNewCString(ctxt, ""));
2280 
2281     switch (val->type) {
2282     case XPATH_UNDEFINED:
2283 #ifdef DEBUG_EXPR
2284 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285 #endif
2286 	break;
2287     case XPATH_NODESET:
2288     case XPATH_XSLT_TREE:
2289 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 	break;
2291     case XPATH_STRING:
2292 	return(val);
2293     case XPATH_BOOLEAN:
2294 	res = xmlXPathCastBooleanToString(val->boolval);
2295 	break;
2296     case XPATH_NUMBER:
2297 	res = xmlXPathCastNumberToString(val->floatval);
2298 	break;
2299     case XPATH_USERS:
2300     case XPATH_POINT:
2301     case XPATH_RANGE:
2302     case XPATH_LOCATIONSET:
2303 	TODO;
2304 	break;
2305     }
2306     xmlXPathReleaseObject(ctxt, val);
2307     if (res == NULL)
2308 	return(xmlXPathCacheNewCString(ctxt, ""));
2309     return(xmlXPathCacheWrapString(ctxt, res));
2310 }
2311 
2312 /**
2313  * xmlXPathCacheObjectCopy:
2314  * @ctxt: the XPath context
2315  * @val:  the original object
2316  *
2317  * This is the cached version of xmlXPathObjectCopy().
2318  * Acquire a copy of a given object
2319  *
2320  * Returns a created or reused created object.
2321  */
2322 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324 {
2325     if (val == NULL)
2326 	return(NULL);
2327 
2328     if (XP_HAS_CACHE(ctxt)) {
2329 	switch (val->type) {
2330 	    case XPATH_NODESET:
2331 		return(xmlXPathCacheWrapNodeSet(ctxt,
2332 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333 	    case XPATH_STRING:
2334 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2335 	    case XPATH_BOOLEAN:
2336 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337 	    case XPATH_NUMBER:
2338 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 	    default:
2340 		break;
2341 	}
2342     }
2343     return(xmlXPathObjectCopy(val));
2344 }
2345 
2346 /**
2347  * xmlXPathCacheConvertBoolean:
2348  * @ctxt: the XPath context
2349  * @val:  an XPath object
2350  *
2351  * This is the cached version of xmlXPathConvertBoolean().
2352  * Converts an existing object to its boolean() equivalent
2353  *
2354  * Returns a created or reused object, the old one is freed (or the operation
2355  *         is done directly on @val)
2356  */
2357 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359     xmlXPathObjectPtr ret;
2360 
2361     if (val == NULL)
2362 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2363     if (val->type == XPATH_BOOLEAN)
2364 	return(val);
2365     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366     xmlXPathReleaseObject(ctxt, val);
2367     return(ret);
2368 }
2369 
2370 /**
2371  * xmlXPathCacheConvertNumber:
2372  * @ctxt: the XPath context
2373  * @val:  an XPath object
2374  *
2375  * This is the cached version of xmlXPathConvertNumber().
2376  * Converts an existing object to its number() equivalent
2377  *
2378  * Returns a created or reused object, the old one is freed (or the operation
2379  *         is done directly on @val)
2380  */
2381 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383     xmlXPathObjectPtr ret;
2384 
2385     if (val == NULL)
2386 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387     if (val->type == XPATH_NUMBER)
2388 	return(val);
2389     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390     xmlXPathReleaseObject(ctxt, val);
2391     return(ret);
2392 }
2393 
2394 /************************************************************************
2395  *									*
2396  *		Parser stacks related functions and macros		*
2397  *									*
2398  ************************************************************************/
2399 
2400 /**
2401  * valuePop:
2402  * @ctxt: an XPath evaluation context
2403  *
2404  * Pops the top XPath object from the value stack
2405  *
2406  * Returns the XPath object just removed
2407  */
2408 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2409 valuePop(xmlXPathParserContextPtr ctxt)
2410 {
2411     xmlXPathObjectPtr ret;
2412 
2413     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2414         return (NULL);
2415     ctxt->valueNr--;
2416     if (ctxt->valueNr > 0)
2417         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418     else
2419         ctxt->value = NULL;
2420     ret = ctxt->valueTab[ctxt->valueNr];
2421     ctxt->valueTab[ctxt->valueNr] = NULL;
2422     return (ret);
2423 }
2424 /**
2425  * valuePush:
2426  * @ctxt:  an XPath evaluation context
2427  * @value:  the XPath object
2428  *
2429  * Pushes a new XPath object on top of the value stack
2430  *
2431  * returns the number of items on the value stack
2432  */
2433 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435 {
2436     if ((ctxt == NULL) || (value == NULL)) return(-1);
2437     if (ctxt->valueNr >= ctxt->valueMax) {
2438         xmlXPathObjectPtr *tmp;
2439 
2440         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441                                              2 * ctxt->valueMax *
2442                                              sizeof(ctxt->valueTab[0]));
2443         if (tmp == NULL) {
2444             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445             return (0);
2446         }
2447         ctxt->valueMax *= 2;
2448 	ctxt->valueTab = tmp;
2449     }
2450     ctxt->valueTab[ctxt->valueNr] = value;
2451     ctxt->value = value;
2452     return (ctxt->valueNr++);
2453 }
2454 
2455 /**
2456  * xmlXPathPopBoolean:
2457  * @ctxt:  an XPath parser context
2458  *
2459  * Pops a boolean from the stack, handling conversion if needed.
2460  * Check error with #xmlXPathCheckError.
2461  *
2462  * Returns the boolean
2463  */
2464 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466     xmlXPathObjectPtr obj;
2467     int ret;
2468 
2469     obj = valuePop(ctxt);
2470     if (obj == NULL) {
2471 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 	return(0);
2473     }
2474     if (obj->type != XPATH_BOOLEAN)
2475 	ret = xmlXPathCastToBoolean(obj);
2476     else
2477         ret = obj->boolval;
2478     xmlXPathReleaseObject(ctxt->context, obj);
2479     return(ret);
2480 }
2481 
2482 /**
2483  * xmlXPathPopNumber:
2484  * @ctxt:  an XPath parser context
2485  *
2486  * Pops a number from the stack, handling conversion if needed.
2487  * Check error with #xmlXPathCheckError.
2488  *
2489  * Returns the number
2490  */
2491 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493     xmlXPathObjectPtr obj;
2494     double ret;
2495 
2496     obj = valuePop(ctxt);
2497     if (obj == NULL) {
2498 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 	return(0);
2500     }
2501     if (obj->type != XPATH_NUMBER)
2502 	ret = xmlXPathCastToNumber(obj);
2503     else
2504         ret = obj->floatval;
2505     xmlXPathReleaseObject(ctxt->context, obj);
2506     return(ret);
2507 }
2508 
2509 /**
2510  * xmlXPathPopString:
2511  * @ctxt:  an XPath parser context
2512  *
2513  * Pops a string from the stack, handling conversion if needed.
2514  * Check error with #xmlXPathCheckError.
2515  *
2516  * Returns the string
2517  */
2518 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520     xmlXPathObjectPtr obj;
2521     xmlChar * ret;
2522 
2523     obj = valuePop(ctxt);
2524     if (obj == NULL) {
2525 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 	return(NULL);
2527     }
2528     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2529     /* TODO: needs refactoring somewhere else */
2530     if (obj->stringval == ret)
2531 	obj->stringval = NULL;
2532     xmlXPathReleaseObject(ctxt->context, obj);
2533     return(ret);
2534 }
2535 
2536 /**
2537  * xmlXPathPopNodeSet:
2538  * @ctxt:  an XPath parser context
2539  *
2540  * Pops a node-set from the stack, handling conversion if needed.
2541  * Check error with #xmlXPathCheckError.
2542  *
2543  * Returns the node-set
2544  */
2545 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547     xmlXPathObjectPtr obj;
2548     xmlNodeSetPtr ret;
2549 
2550     if (ctxt == NULL) return(NULL);
2551     if (ctxt->value == NULL) {
2552 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 	return(NULL);
2554     }
2555     if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 	xmlXPathSetTypeError(ctxt);
2557 	return(NULL);
2558     }
2559     obj = valuePop(ctxt);
2560     ret = obj->nodesetval;
2561 #if 0
2562     /* to fix memory leak of not clearing obj->user */
2563     if (obj->boolval && obj->user != NULL)
2564         xmlFreeNodeList((xmlNodePtr) obj->user);
2565 #endif
2566     obj->nodesetval = NULL;
2567     xmlXPathReleaseObject(ctxt->context, obj);
2568     return(ret);
2569 }
2570 
2571 /**
2572  * xmlXPathPopExternal:
2573  * @ctxt:  an XPath parser context
2574  *
2575  * Pops an external object from the stack, handling conversion if needed.
2576  * Check error with #xmlXPathCheckError.
2577  *
2578  * Returns the object
2579  */
2580 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582     xmlXPathObjectPtr obj;
2583     void * ret;
2584 
2585     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 	return(NULL);
2588     }
2589     if (ctxt->value->type != XPATH_USERS) {
2590 	xmlXPathSetTypeError(ctxt);
2591 	return(NULL);
2592     }
2593     obj = valuePop(ctxt);
2594     ret = obj->user;
2595     obj->user = NULL;
2596     xmlXPathReleaseObject(ctxt->context, obj);
2597     return(ret);
2598 }
2599 
2600 /*
2601  * Macros for accessing the content. Those should be used only by the parser,
2602  * and not exported.
2603  *
2604  * Dirty macros, i.e. one need to make assumption on the context to use them
2605  *
2606  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2607  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2608  *           in ISO-Latin or UTF-8.
2609  *           This should be used internally by the parser
2610  *           only to compare to ASCII values otherwise it would break when
2611  *           running with UTF-8 encoding.
2612  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2613  *           to compare on ASCII based substring.
2614  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615  *           strings within the parser.
2616  *   CURRENT Returns the current char value, with the full decoding of
2617  *           UTF-8 if we are using this mode. It returns an int.
2618  *   NEXT    Skip to the next character, this does the proper decoding
2619  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620  *           It returns the pointer to the current xmlChar.
2621  */
2622 
2623 #define CUR (*ctxt->cur)
2624 #define SKIP(val) ctxt->cur += (val)
2625 #define NXT(val) ctxt->cur[(val)]
2626 #define CUR_PTR ctxt->cur
2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628 
2629 #define COPY_BUF(l,b,i,v)                                              \
2630     if (l == 1) b[i++] = (xmlChar) v;                                  \
2631     else i += xmlCopyChar(l,&b[i],v)
2632 
2633 #define NEXTL(l)  ctxt->cur += l
2634 
2635 #define SKIP_BLANKS							\
2636     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637 
2638 #define CURRENT (*ctxt->cur)
2639 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2640 
2641 
2642 #ifndef DBL_DIG
2643 #define DBL_DIG 16
2644 #endif
2645 #ifndef DBL_EPSILON
2646 #define DBL_EPSILON 1E-9
2647 #endif
2648 
2649 #define UPPER_DOUBLE 1E9
2650 #define LOWER_DOUBLE 1E-5
2651 #define	LOWER_DOUBLE_EXP 5
2652 
2653 #define INTEGER_DIGITS DBL_DIG
2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655 #define EXPONENT_DIGITS (3 + 2)
2656 
2657 /**
2658  * xmlXPathFormatNumber:
2659  * @number:     number to format
2660  * @buffer:     output buffer
2661  * @buffersize: size of output buffer
2662  *
2663  * Convert the number into a string representation.
2664  */
2665 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667 {
2668     switch (xmlXPathIsInf(number)) {
2669     case 1:
2670 	if (buffersize > (int)sizeof("Infinity"))
2671 	    snprintf(buffer, buffersize, "Infinity");
2672 	break;
2673     case -1:
2674 	if (buffersize > (int)sizeof("-Infinity"))
2675 	    snprintf(buffer, buffersize, "-Infinity");
2676 	break;
2677     default:
2678 	if (xmlXPathIsNaN(number)) {
2679 	    if (buffersize > (int)sizeof("NaN"))
2680 		snprintf(buffer, buffersize, "NaN");
2681 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682 	    snprintf(buffer, buffersize, "0");
2683 	} else if (number == ((int) number)) {
2684 	    char work[30];
2685 	    char *ptr, *cur;
2686 	    int value = (int) number;
2687 
2688             ptr = &buffer[0];
2689 	    if (value == 0) {
2690 		*ptr++ = '0';
2691 	    } else {
2692 		snprintf(work, 29, "%d", value);
2693 		cur = &work[0];
2694 		while ((*cur) && (ptr - buffer < buffersize)) {
2695 		    *ptr++ = *cur++;
2696 		}
2697 	    }
2698 	    if (ptr - buffer < buffersize) {
2699 		*ptr = 0;
2700 	    } else if (buffersize > 0) {
2701 		ptr--;
2702 		*ptr = 0;
2703 	    }
2704 	} else {
2705 	    /*
2706 	      For the dimension of work,
2707 	          DBL_DIG is number of significant digits
2708 		  EXPONENT is only needed for "scientific notation"
2709 	          3 is sign, decimal point, and terminating zero
2710 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 	      Note that this dimension is slightly (a few characters)
2712 	      larger than actually necessary.
2713 	    */
2714 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715 	    int integer_place, fraction_place;
2716 	    char *ptr;
2717 	    char *after_fraction;
2718 	    double absolute_value;
2719 	    int size;
2720 
2721 	    absolute_value = fabs(number);
2722 
2723 	    /*
2724 	     * First choose format - scientific or regular floating point.
2725 	     * In either case, result is in work, and after_fraction points
2726 	     * just past the fractional part.
2727 	    */
2728 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2729 		  (absolute_value < LOWER_DOUBLE)) &&
2730 		 (absolute_value != 0.0) ) {
2731 		/* Use scientific notation */
2732 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 		fraction_place = DBL_DIG - 1;
2734 		size = snprintf(work, sizeof(work),"%*.*e",
2735 			 integer_place, fraction_place, number);
2736 		while ((size > 0) && (work[size] != 'e')) size--;
2737 
2738 	    }
2739 	    else {
2740 		/* Use regular notation */
2741 		if (absolute_value > 0.0) {
2742 		    integer_place = (int)log10(absolute_value);
2743 		    if (integer_place > 0)
2744 		        fraction_place = DBL_DIG - integer_place - 1;
2745 		    else
2746 		        fraction_place = DBL_DIG - integer_place;
2747 		} else {
2748 		    fraction_place = 1;
2749 		}
2750 		size = snprintf(work, sizeof(work), "%0.*f",
2751 				fraction_place, number);
2752 	    }
2753 
2754 	    /* Remove fractional trailing zeroes */
2755 	    after_fraction = work + size;
2756 	    ptr = after_fraction;
2757 	    while (*(--ptr) == '0')
2758 		;
2759 	    if (*ptr != '.')
2760 	        ptr++;
2761 	    while ((*ptr++ = *after_fraction++) != 0);
2762 
2763 	    /* Finally copy result back to caller */
2764 	    size = strlen(work) + 1;
2765 	    if (size > buffersize) {
2766 		work[buffersize - 1] = 0;
2767 		size = buffersize;
2768 	    }
2769 	    memmove(buffer, work, size);
2770 	}
2771 	break;
2772     }
2773 }
2774 
2775 
2776 /************************************************************************
2777  *									*
2778  *			Routines to handle NodeSets			*
2779  *									*
2780  ************************************************************************/
2781 
2782 /**
2783  * xmlXPathOrderDocElems:
2784  * @doc:  an input document
2785  *
2786  * Call this routine to speed up XPath computation on static documents.
2787  * This stamps all the element nodes with the document order
2788  * Like for line information, the order is kept in the element->content
2789  * field, the value stored is actually - the node number (starting at -1)
2790  * to be able to differentiate from line numbers.
2791  *
2792  * Returns the number of elements found in the document or -1 in case
2793  *    of error.
2794  */
2795 long
xmlXPathOrderDocElems(xmlDocPtr doc)2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
2797     long count = 0;
2798     xmlNodePtr cur;
2799 
2800     if (doc == NULL)
2801 	return(-1);
2802     cur = doc->children;
2803     while (cur != NULL) {
2804 	if (cur->type == XML_ELEMENT_NODE) {
2805 	    cur->content = (void *) (-(++count));
2806 	    if (cur->children != NULL) {
2807 		cur = cur->children;
2808 		continue;
2809 	    }
2810 	}
2811 	if (cur->next != NULL) {
2812 	    cur = cur->next;
2813 	    continue;
2814 	}
2815 	do {
2816 	    cur = cur->parent;
2817 	    if (cur == NULL)
2818 		break;
2819 	    if (cur == (xmlNodePtr) doc) {
2820 		cur = NULL;
2821 		break;
2822 	    }
2823 	    if (cur->next != NULL) {
2824 		cur = cur->next;
2825 		break;
2826 	    }
2827 	} while (cur != NULL);
2828     }
2829     return(count);
2830 }
2831 
2832 /**
2833  * xmlXPathCmpNodes:
2834  * @node1:  the first node
2835  * @node2:  the second node
2836  *
2837  * Compare two nodes w.r.t document order
2838  *
2839  * Returns -2 in case of error 1 if first point < second point, 0 if
2840  *         it's the same node, -1 otherwise
2841  */
2842 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844     int depth1, depth2;
2845     int attr1 = 0, attr2 = 0;
2846     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847     xmlNodePtr cur, root;
2848 
2849     if ((node1 == NULL) || (node2 == NULL))
2850 	return(-2);
2851     /*
2852      * a couple of optimizations which will avoid computations in most cases
2853      */
2854     if (node1 == node2)		/* trivial case */
2855 	return(0);
2856     if (node1->type == XML_ATTRIBUTE_NODE) {
2857 	attr1 = 1;
2858 	attrNode1 = node1;
2859 	node1 = node1->parent;
2860     }
2861     if (node2->type == XML_ATTRIBUTE_NODE) {
2862 	attr2 = 1;
2863 	attrNode2 = node2;
2864 	node2 = node2->parent;
2865     }
2866     if (node1 == node2) {
2867 	if (attr1 == attr2) {
2868 	    /* not required, but we keep attributes in order */
2869 	    if (attr1 != 0) {
2870 	        cur = attrNode2->prev;
2871 		while (cur != NULL) {
2872 		    if (cur == attrNode1)
2873 		        return (1);
2874 		    cur = cur->prev;
2875 		}
2876 		return (-1);
2877 	    }
2878 	    return(0);
2879 	}
2880 	if (attr2 == 1)
2881 	    return(1);
2882 	return(-1);
2883     }
2884     if ((node1->type == XML_NAMESPACE_DECL) ||
2885         (node2->type == XML_NAMESPACE_DECL))
2886 	return(1);
2887     if (node1 == node2->prev)
2888 	return(1);
2889     if (node1 == node2->next)
2890 	return(-1);
2891 
2892     /*
2893      * Speedup using document order if availble.
2894      */
2895     if ((node1->type == XML_ELEMENT_NODE) &&
2896 	(node2->type == XML_ELEMENT_NODE) &&
2897 	(0 > (long) node1->content) &&
2898 	(0 > (long) node2->content) &&
2899 	(node1->doc == node2->doc)) {
2900 	long l1, l2;
2901 
2902 	l1 = -((long) node1->content);
2903 	l2 = -((long) node2->content);
2904 	if (l1 < l2)
2905 	    return(1);
2906 	if (l1 > l2)
2907 	    return(-1);
2908     }
2909 
2910     /*
2911      * compute depth to root
2912      */
2913     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 	if (cur == node1)
2915 	    return(1);
2916 	depth2++;
2917     }
2918     root = cur;
2919     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 	if (cur == node2)
2921 	    return(-1);
2922 	depth1++;
2923     }
2924     /*
2925      * Distinct document (or distinct entities :-( ) case.
2926      */
2927     if (root != cur) {
2928 	return(-2);
2929     }
2930     /*
2931      * get the nearest common ancestor.
2932      */
2933     while (depth1 > depth2) {
2934 	depth1--;
2935 	node1 = node1->parent;
2936     }
2937     while (depth2 > depth1) {
2938 	depth2--;
2939 	node2 = node2->parent;
2940     }
2941     while (node1->parent != node2->parent) {
2942 	node1 = node1->parent;
2943 	node2 = node2->parent;
2944 	/* should not happen but just in case ... */
2945 	if ((node1 == NULL) || (node2 == NULL))
2946 	    return(-2);
2947     }
2948     /*
2949      * Find who's first.
2950      */
2951     if (node1 == node2->prev)
2952 	return(1);
2953     if (node1 == node2->next)
2954 	return(-1);
2955     /*
2956      * Speedup using document order if availble.
2957      */
2958     if ((node1->type == XML_ELEMENT_NODE) &&
2959 	(node2->type == XML_ELEMENT_NODE) &&
2960 	(0 > (long) node1->content) &&
2961 	(0 > (long) node2->content) &&
2962 	(node1->doc == node2->doc)) {
2963 	long l1, l2;
2964 
2965 	l1 = -((long) node1->content);
2966 	l2 = -((long) node2->content);
2967 	if (l1 < l2)
2968 	    return(1);
2969 	if (l1 > l2)
2970 	    return(-1);
2971     }
2972 
2973     for (cur = node1->next;cur != NULL;cur = cur->next)
2974 	if (cur == node2)
2975 	    return(1);
2976     return(-1); /* assume there is no sibling list corruption */
2977 }
2978 
2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2980 /**
2981  * xmlXPathCmpNodesExt:
2982  * @node1:  the first node
2983  * @node2:  the second node
2984  *
2985  * Compare two nodes w.r.t document order.
2986  * This one is optimized for handling of non-element nodes.
2987  *
2988  * Returns -2 in case of error 1 if first point < second point, 0 if
2989  *         it's the same node, -1 otherwise
2990  */
2991 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993     int depth1, depth2;
2994     int misc = 0, precedence1 = 0, precedence2 = 0;
2995     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996     xmlNodePtr cur, root;
2997     long l1, l2;
2998 
2999     if ((node1 == NULL) || (node2 == NULL))
3000 	return(-2);
3001 
3002     if (node1 == node2)
3003 	return(0);
3004 
3005     /*
3006      * a couple of optimizations which will avoid computations in most cases
3007      */
3008     switch (node1->type) {
3009 	case XML_ELEMENT_NODE:
3010 	    if (node2->type == XML_ELEMENT_NODE) {
3011 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 		    (0 > (long) node2->content) &&
3013 		    (node1->doc == node2->doc))
3014 		{
3015 		    l1 = -((long) node1->content);
3016 		    l2 = -((long) node2->content);
3017 		    if (l1 < l2)
3018 			return(1);
3019 		    if (l1 > l2)
3020 			return(-1);
3021 		} else
3022 		    goto turtle_comparison;
3023 	    }
3024 	    break;
3025 	case XML_ATTRIBUTE_NODE:
3026 	    precedence1 = 1; /* element is owner */
3027 	    miscNode1 = node1;
3028 	    node1 = node1->parent;
3029 	    misc = 1;
3030 	    break;
3031 	case XML_TEXT_NODE:
3032 	case XML_CDATA_SECTION_NODE:
3033 	case XML_COMMENT_NODE:
3034 	case XML_PI_NODE: {
3035 	    miscNode1 = node1;
3036 	    /*
3037 	    * Find nearest element node.
3038 	    */
3039 	    if (node1->prev != NULL) {
3040 		do {
3041 		    node1 = node1->prev;
3042 		    if (node1->type == XML_ELEMENT_NODE) {
3043 			precedence1 = 3; /* element in prev-sibl axis */
3044 			break;
3045 		    }
3046 		    if (node1->prev == NULL) {
3047 			precedence1 = 2; /* element is parent */
3048 			/*
3049 			* URGENT TODO: Are there any cases, where the
3050 			* parent of such a node is not an element node?
3051 			*/
3052 			node1 = node1->parent;
3053 			break;
3054 		    }
3055 		} while (1);
3056 	    } else {
3057 		precedence1 = 2; /* element is parent */
3058 		node1 = node1->parent;
3059 	    }
3060 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061 		(0 <= (long) node1->content)) {
3062 		/*
3063 		* Fallback for whatever case.
3064 		*/
3065 		node1 = miscNode1;
3066 		precedence1 = 0;
3067 	    } else
3068 		misc = 1;
3069 	}
3070 	    break;
3071 	case XML_NAMESPACE_DECL:
3072 	    /*
3073 	    * TODO: why do we return 1 for namespace nodes?
3074 	    */
3075 	    return(1);
3076 	default:
3077 	    break;
3078     }
3079     switch (node2->type) {
3080 	case XML_ELEMENT_NODE:
3081 	    break;
3082 	case XML_ATTRIBUTE_NODE:
3083 	    precedence2 = 1; /* element is owner */
3084 	    miscNode2 = node2;
3085 	    node2 = node2->parent;
3086 	    misc = 1;
3087 	    break;
3088 	case XML_TEXT_NODE:
3089 	case XML_CDATA_SECTION_NODE:
3090 	case XML_COMMENT_NODE:
3091 	case XML_PI_NODE: {
3092 	    miscNode2 = node2;
3093 	    if (node2->prev != NULL) {
3094 		do {
3095 		    node2 = node2->prev;
3096 		    if (node2->type == XML_ELEMENT_NODE) {
3097 			precedence2 = 3; /* element in prev-sibl axis */
3098 			break;
3099 		    }
3100 		    if (node2->prev == NULL) {
3101 			precedence2 = 2; /* element is parent */
3102 			node2 = node2->parent;
3103 			break;
3104 		    }
3105 		} while (1);
3106 	    } else {
3107 		precedence2 = 2; /* element is parent */
3108 		node2 = node2->parent;
3109 	    }
3110 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111 		(0 <= (long) node1->content))
3112 	    {
3113 		node2 = miscNode2;
3114 		precedence2 = 0;
3115 	    } else
3116 		misc = 1;
3117 	}
3118 	    break;
3119 	case XML_NAMESPACE_DECL:
3120 	    return(1);
3121 	default:
3122 	    break;
3123     }
3124     if (misc) {
3125 	if (node1 == node2) {
3126 	    if (precedence1 == precedence2) {
3127 		/*
3128 		* The ugly case; but normally there aren't many
3129 		* adjacent non-element nodes around.
3130 		*/
3131 		cur = miscNode2->prev;
3132 		while (cur != NULL) {
3133 		    if (cur == miscNode1)
3134 			return(1);
3135 		    if (cur->type == XML_ELEMENT_NODE)
3136 			return(-1);
3137 		    cur = cur->prev;
3138 		}
3139 		return (-1);
3140 	    } else {
3141 		/*
3142 		* Evaluate based on higher precedence wrt to the element.
3143 		* TODO: This assumes attributes are sorted before content.
3144 		*   Is this 100% correct?
3145 		*/
3146 		if (precedence1 < precedence2)
3147 		    return(1);
3148 		else
3149 		    return(-1);
3150 	    }
3151 	}
3152 	/*
3153 	* Special case: One of the helper-elements is contained by the other.
3154 	* <foo>
3155 	*   <node2>
3156 	*     <node1>Text-1(precedence1 == 2)</node1>
3157 	*   </node2>
3158 	*   Text-6(precedence2 == 3)
3159 	* </foo>
3160 	*/
3161 	if ((precedence2 == 3) && (precedence1 > 1)) {
3162 	    cur = node1->parent;
3163 	    while (cur) {
3164 		if (cur == node2)
3165 		    return(1);
3166 		cur = cur->parent;
3167 	    }
3168 	}
3169 	if ((precedence1 == 3) && (precedence2 > 1)) {
3170 	    cur = node2->parent;
3171 	    while (cur) {
3172 		if (cur == node1)
3173 		    return(-1);
3174 		cur = cur->parent;
3175 	    }
3176 	}
3177     }
3178 
3179     /*
3180      * Speedup using document order if availble.
3181      */
3182     if ((node1->type == XML_ELEMENT_NODE) &&
3183 	(node2->type == XML_ELEMENT_NODE) &&
3184 	(0 > (long) node1->content) &&
3185 	(0 > (long) node2->content) &&
3186 	(node1->doc == node2->doc)) {
3187 
3188 	l1 = -((long) node1->content);
3189 	l2 = -((long) node2->content);
3190 	if (l1 < l2)
3191 	    return(1);
3192 	if (l1 > l2)
3193 	    return(-1);
3194     }
3195 
3196 turtle_comparison:
3197 
3198     if (node1 == node2->prev)
3199 	return(1);
3200     if (node1 == node2->next)
3201 	return(-1);
3202     /*
3203      * compute depth to root
3204      */
3205     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206 	if (cur == node1)
3207 	    return(1);
3208 	depth2++;
3209     }
3210     root = cur;
3211     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212 	if (cur == node2)
3213 	    return(-1);
3214 	depth1++;
3215     }
3216     /*
3217      * Distinct document (or distinct entities :-( ) case.
3218      */
3219     if (root != cur) {
3220 	return(-2);
3221     }
3222     /*
3223      * get the nearest common ancestor.
3224      */
3225     while (depth1 > depth2) {
3226 	depth1--;
3227 	node1 = node1->parent;
3228     }
3229     while (depth2 > depth1) {
3230 	depth2--;
3231 	node2 = node2->parent;
3232     }
3233     while (node1->parent != node2->parent) {
3234 	node1 = node1->parent;
3235 	node2 = node2->parent;
3236 	/* should not happen but just in case ... */
3237 	if ((node1 == NULL) || (node2 == NULL))
3238 	    return(-2);
3239     }
3240     /*
3241      * Find who's first.
3242      */
3243     if (node1 == node2->prev)
3244 	return(1);
3245     if (node1 == node2->next)
3246 	return(-1);
3247     /*
3248      * Speedup using document order if availble.
3249      */
3250     if ((node1->type == XML_ELEMENT_NODE) &&
3251 	(node2->type == XML_ELEMENT_NODE) &&
3252 	(0 > (long) node1->content) &&
3253 	(0 > (long) node2->content) &&
3254 	(node1->doc == node2->doc)) {
3255 
3256 	l1 = -((long) node1->content);
3257 	l2 = -((long) node2->content);
3258 	if (l1 < l2)
3259 	    return(1);
3260 	if (l1 > l2)
3261 	    return(-1);
3262     }
3263 
3264     for (cur = node1->next;cur != NULL;cur = cur->next)
3265 	if (cur == node2)
3266 	    return(1);
3267     return(-1); /* assume there is no sibling list corruption */
3268 }
3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3270 
3271 /**
3272  * xmlXPathNodeSetSort:
3273  * @set:  the node set
3274  *
3275  * Sort the node set in document order
3276  */
3277 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279     int i, j, incr, len;
3280     xmlNodePtr tmp;
3281 
3282     if (set == NULL)
3283 	return;
3284 
3285     /* Use Shell's sort to sort the node-set */
3286     len = set->nodeNr;
3287     for (incr = len / 2; incr > 0; incr /= 2) {
3288 	for (i = incr; i < len; i++) {
3289 	    j = i - incr;
3290 	    while (j >= 0) {
3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293 			set->nodeTab[j + incr]) == -1)
3294 #else
3295 		if (xmlXPathCmpNodes(set->nodeTab[j],
3296 			set->nodeTab[j + incr]) == -1)
3297 #endif
3298 		{
3299 		    tmp = set->nodeTab[j];
3300 		    set->nodeTab[j] = set->nodeTab[j + incr];
3301 		    set->nodeTab[j + incr] = tmp;
3302 		    j -= incr;
3303 		} else
3304 		    break;
3305 	    }
3306 	}
3307     }
3308 }
3309 
3310 #define XML_NODESET_DEFAULT	10
3311 /**
3312  * xmlXPathNodeSetDupNs:
3313  * @node:  the parent node of the namespace XPath node
3314  * @ns:  the libxml namespace declaration node.
3315  *
3316  * Namespace node in libxml don't match the XPath semantic. In a node set
3317  * the namespace nodes are duplicated and the next pointer is set to the
3318  * parent node in the XPath semantic.
3319  *
3320  * Returns the newly created object.
3321  */
3322 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324     xmlNsPtr cur;
3325 
3326     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327 	return(NULL);
3328     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329 	return((xmlNodePtr) ns);
3330 
3331     /*
3332      * Allocate a new Namespace and fill the fields.
3333      */
3334     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335     if (cur == NULL) {
3336         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3337 	return(NULL);
3338     }
3339     memset(cur, 0, sizeof(xmlNs));
3340     cur->type = XML_NAMESPACE_DECL;
3341     if (ns->href != NULL)
3342 	cur->href = xmlStrdup(ns->href);
3343     if (ns->prefix != NULL)
3344 	cur->prefix = xmlStrdup(ns->prefix);
3345     cur->next = (xmlNsPtr) node;
3346     return((xmlNodePtr) cur);
3347 }
3348 
3349 /**
3350  * xmlXPathNodeSetFreeNs:
3351  * @ns:  the XPath namespace node found in a nodeset.
3352  *
3353  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354  * the namespace nodes are duplicated and the next pointer is set to the
3355  * parent node in the XPath semantic. Check if such a node needs to be freed
3356  */
3357 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360 	return;
3361 
3362     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363 	if (ns->href != NULL)
3364 	    xmlFree((xmlChar *)ns->href);
3365 	if (ns->prefix != NULL)
3366 	    xmlFree((xmlChar *)ns->prefix);
3367 	xmlFree(ns);
3368     }
3369 }
3370 
3371 /**
3372  * xmlXPathNodeSetCreate:
3373  * @val:  an initial xmlNodePtr, or NULL
3374  *
3375  * Create a new xmlNodeSetPtr of type double and of value @val
3376  *
3377  * Returns the newly created object.
3378  */
3379 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
3381     xmlNodeSetPtr ret;
3382 
3383     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384     if (ret == NULL) {
3385         xmlXPathErrMemory(NULL, "creating nodeset\n");
3386 	return(NULL);
3387     }
3388     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389     if (val != NULL) {
3390         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391 					     sizeof(xmlNodePtr));
3392 	if (ret->nodeTab == NULL) {
3393 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3394 	    xmlFree(ret);
3395 	    return(NULL);
3396 	}
3397 	memset(ret->nodeTab, 0 ,
3398 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399         ret->nodeMax = XML_NODESET_DEFAULT;
3400 	if (val->type == XML_NAMESPACE_DECL) {
3401 	    xmlNsPtr ns = (xmlNsPtr) val;
3402 
3403 	    ret->nodeTab[ret->nodeNr++] =
3404 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405 	} else
3406 	    ret->nodeTab[ret->nodeNr++] = val;
3407     }
3408     return(ret);
3409 }
3410 
3411 /**
3412  * xmlXPathNodeSetCreateSize:
3413  * @size:  the initial size of the set
3414  *
3415  * Create a new xmlNodeSetPtr of type double and of value @val
3416  *
3417  * Returns the newly created object.
3418  */
3419 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3420 xmlXPathNodeSetCreateSize(int size) {
3421     xmlNodeSetPtr ret;
3422 
3423     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424     if (ret == NULL) {
3425         xmlXPathErrMemory(NULL, "creating nodeset\n");
3426 	return(NULL);
3427     }
3428     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429     if (size < XML_NODESET_DEFAULT)
3430 	size = XML_NODESET_DEFAULT;
3431     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432     if (ret->nodeTab == NULL) {
3433 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3434 	xmlFree(ret);
3435 	return(NULL);
3436     }
3437     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438     ret->nodeMax = size;
3439     return(ret);
3440 }
3441 
3442 /**
3443  * xmlXPathNodeSetContains:
3444  * @cur:  the node-set
3445  * @val:  the node
3446  *
3447  * checks whether @cur contains @val
3448  *
3449  * Returns true (1) if @cur contains @val, false (0) otherwise
3450  */
3451 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453     int i;
3454 
3455     if ((cur == NULL) || (val == NULL)) return(0);
3456     if (val->type == XML_NAMESPACE_DECL) {
3457 	for (i = 0; i < cur->nodeNr; i++) {
3458 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459 		xmlNsPtr ns1, ns2;
3460 
3461 		ns1 = (xmlNsPtr) val;
3462 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3463 		if (ns1 == ns2)
3464 		    return(1);
3465 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467 		    return(1);
3468 	    }
3469 	}
3470     } else {
3471 	for (i = 0; i < cur->nodeNr; i++) {
3472 	    if (cur->nodeTab[i] == val)
3473 		return(1);
3474 	}
3475     }
3476     return(0);
3477 }
3478 
3479 /**
3480  * xmlXPathNodeSetAddNs:
3481  * @cur:  the initial node set
3482  * @node:  the hosting node
3483  * @ns:  a the namespace node
3484  *
3485  * add a new namespace node to an existing NodeSet
3486  */
3487 void
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489     int i;
3490 
3491 
3492     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493         (ns->type != XML_NAMESPACE_DECL) ||
3494 	(node->type != XML_ELEMENT_NODE))
3495 	return;
3496 
3497     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3498     /*
3499      * prevent duplicates
3500      */
3501     for (i = 0;i < cur->nodeNr;i++) {
3502         if ((cur->nodeTab[i] != NULL) &&
3503 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506 	    return;
3507     }
3508 
3509     /*
3510      * grow the nodeTab if needed
3511      */
3512     if (cur->nodeMax == 0) {
3513         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514 					     sizeof(xmlNodePtr));
3515 	if (cur->nodeTab == NULL) {
3516 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3517 	    return;
3518 	}
3519 	memset(cur->nodeTab, 0 ,
3520 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521         cur->nodeMax = XML_NODESET_DEFAULT;
3522     } else if (cur->nodeNr == cur->nodeMax) {
3523         xmlNodePtr *temp;
3524 
3525         cur->nodeMax *= 2;
3526 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527 				      sizeof(xmlNodePtr));
3528 	if (temp == NULL) {
3529 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3530 	    return;
3531 	}
3532 	cur->nodeTab = temp;
3533     }
3534     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535 }
3536 
3537 /**
3538  * xmlXPathNodeSetAdd:
3539  * @cur:  the initial node set
3540  * @val:  a new xmlNodePtr
3541  *
3542  * add a new xmlNodePtr to an existing NodeSet
3543  */
3544 void
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546     int i;
3547 
3548     if ((cur == NULL) || (val == NULL)) return;
3549 
3550 #if 0
3551     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552 	return;	/* an XSLT fake node */
3553 #endif
3554 
3555     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3556     /*
3557      * prevent duplcates
3558      */
3559     for (i = 0;i < cur->nodeNr;i++)
3560         if (cur->nodeTab[i] == val) return;
3561 
3562     /*
3563      * grow the nodeTab if needed
3564      */
3565     if (cur->nodeMax == 0) {
3566         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567 					     sizeof(xmlNodePtr));
3568 	if (cur->nodeTab == NULL) {
3569 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3570 	    return;
3571 	}
3572 	memset(cur->nodeTab, 0 ,
3573 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574         cur->nodeMax = XML_NODESET_DEFAULT;
3575     } else if (cur->nodeNr == cur->nodeMax) {
3576         xmlNodePtr *temp;
3577 
3578         cur->nodeMax *= 2;
3579 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580 				      sizeof(xmlNodePtr));
3581 	if (temp == NULL) {
3582 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3583 	    return;
3584 	}
3585 	cur->nodeTab = temp;
3586     }
3587     if (val->type == XML_NAMESPACE_DECL) {
3588 	xmlNsPtr ns = (xmlNsPtr) val;
3589 
3590 	cur->nodeTab[cur->nodeNr++] =
3591 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592     } else
3593 	cur->nodeTab[cur->nodeNr++] = val;
3594 }
3595 
3596 /**
3597  * xmlXPathNodeSetAddUnique:
3598  * @cur:  the initial node set
3599  * @val:  a new xmlNodePtr
3600  *
3601  * add a new xmlNodePtr to an existing NodeSet, optimized version
3602  * when we are sure the node is not already in the set.
3603  */
3604 void
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606     if ((cur == NULL) || (val == NULL)) return;
3607 
3608 #if 0
3609     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610 	return;	/* an XSLT fake node */
3611 #endif
3612 
3613     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3614     /*
3615      * grow the nodeTab if needed
3616      */
3617     if (cur->nodeMax == 0) {
3618         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619 					     sizeof(xmlNodePtr));
3620 	if (cur->nodeTab == NULL) {
3621 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3622 	    return;
3623 	}
3624 	memset(cur->nodeTab, 0 ,
3625 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626         cur->nodeMax = XML_NODESET_DEFAULT;
3627     } else if (cur->nodeNr == cur->nodeMax) {
3628         xmlNodePtr *temp;
3629 
3630         cur->nodeMax *= 2;
3631 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632 				      sizeof(xmlNodePtr));
3633 	if (temp == NULL) {
3634 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3635 	    return;
3636 	}
3637 	cur->nodeTab = temp;
3638     }
3639     if (val->type == XML_NAMESPACE_DECL) {
3640 	xmlNsPtr ns = (xmlNsPtr) val;
3641 
3642 	cur->nodeTab[cur->nodeNr++] =
3643 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644     } else
3645 	cur->nodeTab[cur->nodeNr++] = val;
3646 }
3647 
3648 /**
3649  * xmlXPathNodeSetMerge:
3650  * @val1:  the first NodeSet or NULL
3651  * @val2:  the second NodeSet
3652  *
3653  * Merges two nodesets, all nodes from @val2 are added to @val1
3654  * if @val1 is NULL, a new set is created and copied from @val2
3655  *
3656  * Returns @val1 once extended or NULL in case of error.
3657  */
3658 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660     int i, j, initNr, skip;
3661     xmlNodePtr n1, n2;
3662 
3663     if (val2 == NULL) return(val1);
3664     if (val1 == NULL) {
3665 	val1 = xmlXPathNodeSetCreate(NULL);
3666     if (val1 == NULL)
3667         return (NULL);
3668 #if 0
3669 	/*
3670 	* TODO: The optimization won't work in every case, since
3671 	*  those nasty namespace nodes need to be added with
3672 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3673 	*  memcpy is not possible.
3674 	*  If there was a flag on the nodesetval, indicating that
3675 	*  some temporary nodes are in, that would be helpfull.
3676 	*/
3677 	/*
3678 	* Optimization: Create an equally sized node-set
3679 	* and memcpy the content.
3680 	*/
3681 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682 	if (val1 == NULL)
3683 	    return(NULL);
3684 	if (val2->nodeNr != 0) {
3685 	    if (val2->nodeNr == 1)
3686 		*(val1->nodeTab) = *(val2->nodeTab);
3687 	    else {
3688 		memcpy(val1->nodeTab, val2->nodeTab,
3689 		    val2->nodeNr * sizeof(xmlNodePtr));
3690 	    }
3691 	    val1->nodeNr = val2->nodeNr;
3692 	}
3693 	return(val1);
3694 #endif
3695     }
3696 
3697     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698     initNr = val1->nodeNr;
3699 
3700     for (i = 0;i < val2->nodeNr;i++) {
3701 	n2 = val2->nodeTab[i];
3702 	/*
3703 	 * check against duplicates
3704 	 */
3705 	skip = 0;
3706 	for (j = 0; j < initNr; j++) {
3707 	    n1 = val1->nodeTab[j];
3708 	    if (n1 == n2) {
3709 		skip = 1;
3710 		break;
3711 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712 		       (n2->type == XML_NAMESPACE_DECL)) {
3713 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715 			((xmlNsPtr) n2)->prefix)))
3716 		{
3717 		    skip = 1;
3718 		    break;
3719 		}
3720 	    }
3721 	}
3722 	if (skip)
3723 	    continue;
3724 
3725 	/*
3726 	 * grow the nodeTab if needed
3727 	 */
3728 	if (val1->nodeMax == 0) {
3729 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730 						    sizeof(xmlNodePtr));
3731 	    if (val1->nodeTab == NULL) {
3732 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3733 		return(NULL);
3734 	    }
3735 	    memset(val1->nodeTab, 0 ,
3736 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737 	    val1->nodeMax = XML_NODESET_DEFAULT;
3738 	} else if (val1->nodeNr == val1->nodeMax) {
3739 	    xmlNodePtr *temp;
3740 
3741 	    val1->nodeMax *= 2;
3742 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743 					     sizeof(xmlNodePtr));
3744 	    if (temp == NULL) {
3745 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3746 		return(NULL);
3747 	    }
3748 	    val1->nodeTab = temp;
3749 	}
3750 	if (n2->type == XML_NAMESPACE_DECL) {
3751 	    xmlNsPtr ns = (xmlNsPtr) n2;
3752 
3753 	    val1->nodeTab[val1->nodeNr++] =
3754 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755 	} else
3756 	    val1->nodeTab[val1->nodeNr++] = n2;
3757     }
3758 
3759     return(val1);
3760 }
3761 
3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3763 /**
3764  * xmlXPathNodeSetMergeUnique:
3765  * @val1:  the first NodeSet or NULL
3766  * @val2:  the second NodeSet
3767  *
3768  * Merges two nodesets, all nodes from @val2 are added to @val1
3769  * if @val1 is NULL, a new set is created and copied from @val2
3770  *
3771  * Returns @val1 once extended or NULL in case of error.
3772  */
3773 static xmlNodeSetPtr
3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3775     int i;
3776 
3777     if (val2 == NULL) return(val1);
3778     if (val1 == NULL) {
3779 	val1 = xmlXPathNodeSetCreate(NULL);
3780     }
3781     if (val1 == NULL)
3782         return (NULL);
3783 
3784     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3785 
3786     for (i = 0;i < val2->nodeNr;i++) {
3787 	/*
3788 	 * grow the nodeTab if needed
3789 	 */
3790 	if (val1->nodeMax == 0) {
3791 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 						    sizeof(xmlNodePtr));
3793 	    if (val1->nodeTab == NULL) {
3794 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3795 		return(NULL);
3796 	    }
3797 	    memset(val1->nodeTab, 0 ,
3798 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 	    val1->nodeMax = XML_NODESET_DEFAULT;
3800 	} else if (val1->nodeNr == val1->nodeMax) {
3801 	    xmlNodePtr *temp;
3802 
3803 	    val1->nodeMax *= 2;
3804 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805 					     sizeof(xmlNodePtr));
3806 	    if (temp == NULL) {
3807 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3808 		return(NULL);
3809 	    }
3810 	    val1->nodeTab = temp;
3811 	}
3812 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814 
3815 	    val1->nodeTab[val1->nodeNr++] =
3816 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 	} else
3818 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819     }
3820 
3821     return(val1);
3822 }
3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824 
3825 /**
3826  * xmlXPathNodeSetMergeAndClear:
3827  * @set1:  the first NodeSet or NULL
3828  * @set2:  the second NodeSet
3829  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830  *
3831  * Merges two nodesets, all nodes from @set2 are added to @set1
3832  * if @set1 is NULL, a new set is created and copied from @set2.
3833  * Checks for duplicate nodes. Clears set2.
3834  *
3835  * Returns @set1 once extended or NULL in case of error.
3836  */
3837 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839 			     int hasNullEntries)
3840 {
3841     if ((set1 == NULL) && (hasNullEntries == 0)) {
3842 	/*
3843 	* Note that doing a memcpy of the list, namespace nodes are
3844 	* just assigned to set1, since set2 is cleared anyway.
3845 	*/
3846 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847 	if (set1 == NULL)
3848 	    return(NULL);
3849 	if (set2->nodeNr != 0) {
3850 	    memcpy(set1->nodeTab, set2->nodeTab,
3851 		set2->nodeNr * sizeof(xmlNodePtr));
3852 	    set1->nodeNr = set2->nodeNr;
3853 	}
3854     } else {
3855 	int i, j, initNbSet1;
3856 	xmlNodePtr n1, n2;
3857 
3858 	if (set1 == NULL)
3859             set1 = xmlXPathNodeSetCreate(NULL);
3860         if (set1 == NULL)
3861             return (NULL);
3862 
3863 	initNbSet1 = set1->nodeNr;
3864 	for (i = 0;i < set2->nodeNr;i++) {
3865 	    n2 = set2->nodeTab[i];
3866 	    /*
3867 	    * Skip NULLed entries.
3868 	    */
3869 	    if (n2 == NULL)
3870 		continue;
3871 	    /*
3872 	    * Skip duplicates.
3873 	    */
3874 	    for (j = 0; j < initNbSet1; j++) {
3875 		n1 = set1->nodeTab[j];
3876 		if (n1 == n2) {
3877 		    goto skip_node;
3878 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3879 		    (n2->type == XML_NAMESPACE_DECL))
3880 		{
3881 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883 			((xmlNsPtr) n2)->prefix)))
3884 		    {
3885 			/*
3886 			* Free the namespace node.
3887 			*/
3888 			set2->nodeTab[i] = NULL;
3889 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890 			goto skip_node;
3891 		    }
3892 		}
3893 	    }
3894 	    /*
3895 	    * grow the nodeTab if needed
3896 	    */
3897 	    if (set1->nodeMax == 0) {
3898 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900 		if (set1->nodeTab == NULL) {
3901 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3902 		    return(NULL);
3903 		}
3904 		memset(set1->nodeTab, 0,
3905 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 		set1->nodeMax = XML_NODESET_DEFAULT;
3907 	    } else if (set1->nodeNr >= set1->nodeMax) {
3908 		xmlNodePtr *temp;
3909 
3910 		set1->nodeMax *= 2;
3911 		temp = (xmlNodePtr *) xmlRealloc(
3912 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913 		if (temp == NULL) {
3914 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3915 		    return(NULL);
3916 		}
3917 		set1->nodeTab = temp;
3918 	    }
3919 	    if (n2->type == XML_NAMESPACE_DECL) {
3920 		xmlNsPtr ns = (xmlNsPtr) n2;
3921 
3922 		set1->nodeTab[set1->nodeNr++] =
3923 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924 	    } else
3925 		set1->nodeTab[set1->nodeNr++] = n2;
3926 skip_node:
3927 	    {}
3928 	}
3929     }
3930     set2->nodeNr = 0;
3931     return(set1);
3932 }
3933 
3934 /**
3935  * xmlXPathNodeSetMergeAndClearNoDupls:
3936  * @set1:  the first NodeSet or NULL
3937  * @set2:  the second NodeSet
3938  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939  *
3940  * Merges two nodesets, all nodes from @set2 are added to @set1
3941  * if @set1 is NULL, a new set is created and copied from @set2.
3942  * Doesn't chack for duplicate nodes. Clears set2.
3943  *
3944  * Returns @set1 once extended or NULL in case of error.
3945  */
3946 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948 				    int hasNullEntries)
3949 {
3950     if (set2 == NULL)
3951 	return(set1);
3952     if ((set1 == NULL) && (hasNullEntries == 0)) {
3953 	/*
3954 	* Note that doing a memcpy of the list, namespace nodes are
3955 	* just assigned to set1, since set2 is cleared anyway.
3956 	*/
3957 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958 	if (set1 == NULL)
3959 	    return(NULL);
3960 	if (set2->nodeNr != 0) {
3961 	    memcpy(set1->nodeTab, set2->nodeTab,
3962 		set2->nodeNr * sizeof(xmlNodePtr));
3963 	    set1->nodeNr = set2->nodeNr;
3964 	}
3965     } else {
3966 	int i;
3967 	xmlNodePtr n2;
3968 
3969 	if (set1 == NULL)
3970 	    set1 = xmlXPathNodeSetCreate(NULL);
3971         if (set1 == NULL)
3972             return (NULL);
3973 
3974 	for (i = 0;i < set2->nodeNr;i++) {
3975 	    n2 = set2->nodeTab[i];
3976 	    /*
3977 	    * Skip NULLed entries.
3978 	    */
3979 	    if (n2 == NULL)
3980 		continue;
3981 	    if (set1->nodeMax == 0) {
3982 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984 		if (set1->nodeTab == NULL) {
3985 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3986 		    return(NULL);
3987 		}
3988 		memset(set1->nodeTab, 0,
3989 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990 		set1->nodeMax = XML_NODESET_DEFAULT;
3991 	    } else if (set1->nodeNr >= set1->nodeMax) {
3992 		xmlNodePtr *temp;
3993 
3994 		set1->nodeMax *= 2;
3995 		temp = (xmlNodePtr *) xmlRealloc(
3996 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997 		if (temp == NULL) {
3998 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3999 		    return(NULL);
4000 		}
4001 		set1->nodeTab = temp;
4002 	    }
4003 	    set1->nodeTab[set1->nodeNr++] = n2;
4004 	}
4005     }
4006     set2->nodeNr = 0;
4007     return(set1);
4008 }
4009 
4010 /**
4011  * xmlXPathNodeSetDel:
4012  * @cur:  the initial node set
4013  * @val:  an xmlNodePtr
4014  *
4015  * Removes an xmlNodePtr from an existing NodeSet
4016  */
4017 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019     int i;
4020 
4021     if (cur == NULL) return;
4022     if (val == NULL) return;
4023 
4024     /*
4025      * find node in nodeTab
4026      */
4027     for (i = 0;i < cur->nodeNr;i++)
4028         if (cur->nodeTab[i] == val) break;
4029 
4030     if (i >= cur->nodeNr) {	/* not found */
4031 #ifdef DEBUG
4032         xmlGenericError(xmlGenericErrorContext,
4033 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034 		val->name);
4035 #endif
4036         return;
4037     }
4038     if ((cur->nodeTab[i] != NULL) &&
4039 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4041     cur->nodeNr--;
4042     for (;i < cur->nodeNr;i++)
4043         cur->nodeTab[i] = cur->nodeTab[i + 1];
4044     cur->nodeTab[cur->nodeNr] = NULL;
4045 }
4046 
4047 /**
4048  * xmlXPathNodeSetRemove:
4049  * @cur:  the initial node set
4050  * @val:  the index to remove
4051  *
4052  * Removes an entry from an existing NodeSet list.
4053  */
4054 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056     if (cur == NULL) return;
4057     if (val >= cur->nodeNr) return;
4058     if ((cur->nodeTab[val] != NULL) &&
4059 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4061     cur->nodeNr--;
4062     for (;val < cur->nodeNr;val++)
4063         cur->nodeTab[val] = cur->nodeTab[val + 1];
4064     cur->nodeTab[cur->nodeNr] = NULL;
4065 }
4066 
4067 /**
4068  * xmlXPathFreeNodeSet:
4069  * @obj:  the xmlNodeSetPtr to free
4070  *
4071  * Free the NodeSet compound (not the actual nodes !).
4072  */
4073 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075     if (obj == NULL) return;
4076     if (obj->nodeTab != NULL) {
4077 	int i;
4078 
4079 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080 	for (i = 0;i < obj->nodeNr;i++)
4081 	    if ((obj->nodeTab[i] != NULL) &&
4082 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084 	xmlFree(obj->nodeTab);
4085     }
4086     xmlFree(obj);
4087 }
4088 
4089 /**
4090  * xmlXPathNodeSetClear:
4091  * @set:  the node set to clear
4092  *
4093  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094  * are feed), but does *not* free the list itself. Sets the length of the
4095  * list to 0.
4096  */
4097 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099 {
4100     if ((set == NULL) || (set->nodeNr <= 0))
4101 	return;
4102     else if (hasNsNodes) {
4103 	int i;
4104 	xmlNodePtr node;
4105 
4106 	for (i = 0; i < set->nodeNr; i++) {
4107 	    node = set->nodeTab[i];
4108 	    if ((node != NULL) &&
4109 		(node->type == XML_NAMESPACE_DECL))
4110 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4111 	}
4112     }
4113     set->nodeNr = 0;
4114 }
4115 
4116 /**
4117  * xmlXPathNodeSetClearFromPos:
4118  * @set: the node set to be cleared
4119  * @pos: the start position to clear from
4120  *
4121  * Clears the list from temporary XPath objects (e.g. namespace nodes
4122  * are feed) starting with the entry at @pos, but does *not* free the list
4123  * itself. Sets the length of the list to @pos.
4124  */
4125 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127 {
4128     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129 	return;
4130     else if ((hasNsNodes)) {
4131 	int i;
4132 	xmlNodePtr node;
4133 
4134 	for (i = pos; i < set->nodeNr; i++) {
4135 	    node = set->nodeTab[i];
4136 	    if ((node != NULL) &&
4137 		(node->type == XML_NAMESPACE_DECL))
4138 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4139 	}
4140     }
4141     set->nodeNr = pos;
4142 }
4143 
4144 /**
4145  * xmlXPathFreeValueTree:
4146  * @obj:  the xmlNodeSetPtr to free
4147  *
4148  * Free the NodeSet compound and the actual tree, this is different
4149  * from xmlXPathFreeNodeSet()
4150  */
4151 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153     int i;
4154 
4155     if (obj == NULL) return;
4156 
4157     if (obj->nodeTab != NULL) {
4158 	for (i = 0;i < obj->nodeNr;i++) {
4159 	    if (obj->nodeTab[i] != NULL) {
4160 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162 		} else {
4163 		    xmlFreeNodeList(obj->nodeTab[i]);
4164 		}
4165 	    }
4166 	}
4167 	xmlFree(obj->nodeTab);
4168     }
4169     xmlFree(obj);
4170 }
4171 
4172 #if defined(DEBUG) || defined(DEBUG_STEP)
4173 /**
4174  * xmlGenericErrorContextNodeSet:
4175  * @output:  a FILE * for the output
4176  * @obj:  the xmlNodeSetPtr to display
4177  *
4178  * Quick display of a NodeSet
4179  */
4180 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182     int i;
4183 
4184     if (output == NULL) output = xmlGenericErrorContext;
4185     if (obj == NULL)  {
4186         fprintf(output, "NodeSet == NULL !\n");
4187 	return;
4188     }
4189     if (obj->nodeNr == 0) {
4190         fprintf(output, "NodeSet is empty\n");
4191 	return;
4192     }
4193     if (obj->nodeTab == NULL) {
4194 	fprintf(output, " nodeTab == NULL !\n");
4195 	return;
4196     }
4197     for (i = 0; i < obj->nodeNr; i++) {
4198         if (obj->nodeTab[i] == NULL) {
4199 	    fprintf(output, " NULL !\n");
4200 	    return;
4201         }
4202 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204 	    fprintf(output, " /");
4205 	else if (obj->nodeTab[i]->name == NULL)
4206 	    fprintf(output, " noname!");
4207 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4208     }
4209     fprintf(output, "\n");
4210 }
4211 #endif
4212 
4213 /**
4214  * xmlXPathNewNodeSet:
4215  * @val:  the NodePtr value
4216  *
4217  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218  * it with the single Node @val
4219  *
4220  * Returns the newly created object.
4221  */
4222 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4223 xmlXPathNewNodeSet(xmlNodePtr val) {
4224     xmlXPathObjectPtr ret;
4225 
4226     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227     if (ret == NULL) {
4228         xmlXPathErrMemory(NULL, "creating nodeset\n");
4229 	return(NULL);
4230     }
4231     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232     ret->type = XPATH_NODESET;
4233     ret->boolval = 0;
4234     ret->nodesetval = xmlXPathNodeSetCreate(val);
4235     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236 #ifdef XP_DEBUG_OBJ_USAGE
4237     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238 #endif
4239     return(ret);
4240 }
4241 
4242 /**
4243  * xmlXPathNewValueTree:
4244  * @val:  the NodePtr value
4245  *
4246  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247  * it with the tree root @val
4248  *
4249  * Returns the newly created object.
4250  */
4251 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4252 xmlXPathNewValueTree(xmlNodePtr val) {
4253     xmlXPathObjectPtr ret;
4254 
4255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256     if (ret == NULL) {
4257         xmlXPathErrMemory(NULL, "creating result value tree\n");
4258 	return(NULL);
4259     }
4260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261     ret->type = XPATH_XSLT_TREE;
4262     ret->boolval = 1;
4263     ret->user = (void *) val;
4264     ret->nodesetval = xmlXPathNodeSetCreate(val);
4265 #ifdef XP_DEBUG_OBJ_USAGE
4266     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267 #endif
4268     return(ret);
4269 }
4270 
4271 /**
4272  * xmlXPathNewNodeSetList:
4273  * @val:  an existing NodeSet
4274  *
4275  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276  * it with the Nodeset @val
4277  *
4278  * Returns the newly created object.
4279  */
4280 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282 {
4283     xmlXPathObjectPtr ret;
4284     int i;
4285 
4286     if (val == NULL)
4287         ret = NULL;
4288     else if (val->nodeTab == NULL)
4289         ret = xmlXPathNewNodeSet(NULL);
4290     else {
4291         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4292         if (ret)
4293             for (i = 1; i < val->nodeNr; ++i)
4294                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4295     }
4296 
4297     return (ret);
4298 }
4299 
4300 /**
4301  * xmlXPathWrapNodeSet:
4302  * @val:  the NodePtr value
4303  *
4304  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305  *
4306  * Returns the newly created object.
4307  */
4308 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310     xmlXPathObjectPtr ret;
4311 
4312     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313     if (ret == NULL) {
4314         xmlXPathErrMemory(NULL, "creating node set object\n");
4315 	return(NULL);
4316     }
4317     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318     ret->type = XPATH_NODESET;
4319     ret->nodesetval = val;
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322 #endif
4323     return(ret);
4324 }
4325 
4326 /**
4327  * xmlXPathFreeNodeSetList:
4328  * @obj:  an existing NodeSetList object
4329  *
4330  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331  * the list contrary to xmlXPathFreeObject().
4332  */
4333 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335     if (obj == NULL) return;
4336 #ifdef XP_DEBUG_OBJ_USAGE
4337     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338 #endif
4339     xmlFree(obj);
4340 }
4341 
4342 /**
4343  * xmlXPathDifference:
4344  * @nodes1:  a node-set
4345  * @nodes2:  a node-set
4346  *
4347  * Implements the EXSLT - Sets difference() function:
4348  *    node-set set:difference (node-set, node-set)
4349  *
4350  * Returns the difference between the two node sets, or nodes1 if
4351  *         nodes2 is empty
4352  */
4353 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355     xmlNodeSetPtr ret;
4356     int i, l1;
4357     xmlNodePtr cur;
4358 
4359     if (xmlXPathNodeSetIsEmpty(nodes2))
4360 	return(nodes1);
4361 
4362     ret = xmlXPathNodeSetCreate(NULL);
4363     if (xmlXPathNodeSetIsEmpty(nodes1))
4364 	return(ret);
4365 
4366     l1 = xmlXPathNodeSetGetLength(nodes1);
4367 
4368     for (i = 0; i < l1; i++) {
4369 	cur = xmlXPathNodeSetItem(nodes1, i);
4370 	if (!xmlXPathNodeSetContains(nodes2, cur))
4371 	    xmlXPathNodeSetAddUnique(ret, cur);
4372     }
4373     return(ret);
4374 }
4375 
4376 /**
4377  * xmlXPathIntersection:
4378  * @nodes1:  a node-set
4379  * @nodes2:  a node-set
4380  *
4381  * Implements the EXSLT - Sets intersection() function:
4382  *    node-set set:intersection (node-set, node-set)
4383  *
4384  * Returns a node set comprising the nodes that are within both the
4385  *         node sets passed as arguments
4386  */
4387 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390     int i, l1;
4391     xmlNodePtr cur;
4392 
4393     if (ret == NULL)
4394         return(ret);
4395     if (xmlXPathNodeSetIsEmpty(nodes1))
4396 	return(ret);
4397     if (xmlXPathNodeSetIsEmpty(nodes2))
4398 	return(ret);
4399 
4400     l1 = xmlXPathNodeSetGetLength(nodes1);
4401 
4402     for (i = 0; i < l1; i++) {
4403 	cur = xmlXPathNodeSetItem(nodes1, i);
4404 	if (xmlXPathNodeSetContains(nodes2, cur))
4405 	    xmlXPathNodeSetAddUnique(ret, cur);
4406     }
4407     return(ret);
4408 }
4409 
4410 /**
4411  * xmlXPathDistinctSorted:
4412  * @nodes:  a node-set, sorted by document order
4413  *
4414  * Implements the EXSLT - Sets distinct() function:
4415  *    node-set set:distinct (node-set)
4416  *
4417  * Returns a subset of the nodes contained in @nodes, or @nodes if
4418  *         it is empty
4419  */
4420 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422     xmlNodeSetPtr ret;
4423     xmlHashTablePtr hash;
4424     int i, l;
4425     xmlChar * strval;
4426     xmlNodePtr cur;
4427 
4428     if (xmlXPathNodeSetIsEmpty(nodes))
4429 	return(nodes);
4430 
4431     ret = xmlXPathNodeSetCreate(NULL);
4432     if (ret == NULL)
4433         return(ret);
4434     l = xmlXPathNodeSetGetLength(nodes);
4435     hash = xmlHashCreate (l);
4436     for (i = 0; i < l; i++) {
4437 	cur = xmlXPathNodeSetItem(nodes, i);
4438 	strval = xmlXPathCastNodeToString(cur);
4439 	if (xmlHashLookup(hash, strval) == NULL) {
4440 	    xmlHashAddEntry(hash, strval, strval);
4441 	    xmlXPathNodeSetAddUnique(ret, cur);
4442 	} else {
4443 	    xmlFree(strval);
4444 	}
4445     }
4446     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447     return(ret);
4448 }
4449 
4450 /**
4451  * xmlXPathDistinct:
4452  * @nodes:  a node-set
4453  *
4454  * Implements the EXSLT - Sets distinct() function:
4455  *    node-set set:distinct (node-set)
4456  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457  * is called with the sorted node-set
4458  *
4459  * Returns a subset of the nodes contained in @nodes, or @nodes if
4460  *         it is empty
4461  */
4462 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464     if (xmlXPathNodeSetIsEmpty(nodes))
4465 	return(nodes);
4466 
4467     xmlXPathNodeSetSort(nodes);
4468     return(xmlXPathDistinctSorted(nodes));
4469 }
4470 
4471 /**
4472  * xmlXPathHasSameNodes:
4473  * @nodes1:  a node-set
4474  * @nodes2:  a node-set
4475  *
4476  * Implements the EXSLT - Sets has-same-nodes function:
4477  *    boolean set:has-same-node(node-set, node-set)
4478  *
4479  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480  *         otherwise
4481  */
4482 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484     int i, l;
4485     xmlNodePtr cur;
4486 
4487     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488 	xmlXPathNodeSetIsEmpty(nodes2))
4489 	return(0);
4490 
4491     l = xmlXPathNodeSetGetLength(nodes1);
4492     for (i = 0; i < l; i++) {
4493 	cur = xmlXPathNodeSetItem(nodes1, i);
4494 	if (xmlXPathNodeSetContains(nodes2, cur))
4495 	    return(1);
4496     }
4497     return(0);
4498 }
4499 
4500 /**
4501  * xmlXPathNodeLeadingSorted:
4502  * @nodes: a node-set, sorted by document order
4503  * @node: a node
4504  *
4505  * Implements the EXSLT - Sets leading() function:
4506  *    node-set set:leading (node-set, node-set)
4507  *
4508  * Returns the nodes in @nodes that precede @node in document order,
4509  *         @nodes if @node is NULL or an empty node-set if @nodes
4510  *         doesn't contain @node
4511  */
4512 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514     int i, l;
4515     xmlNodePtr cur;
4516     xmlNodeSetPtr ret;
4517 
4518     if (node == NULL)
4519 	return(nodes);
4520 
4521     ret = xmlXPathNodeSetCreate(NULL);
4522     if (ret == NULL)
4523         return(ret);
4524     if (xmlXPathNodeSetIsEmpty(nodes) ||
4525 	(!xmlXPathNodeSetContains(nodes, node)))
4526 	return(ret);
4527 
4528     l = xmlXPathNodeSetGetLength(nodes);
4529     for (i = 0; i < l; i++) {
4530 	cur = xmlXPathNodeSetItem(nodes, i);
4531 	if (cur == node)
4532 	    break;
4533 	xmlXPathNodeSetAddUnique(ret, cur);
4534     }
4535     return(ret);
4536 }
4537 
4538 /**
4539  * xmlXPathNodeLeading:
4540  * @nodes:  a node-set
4541  * @node:  a node
4542  *
4543  * Implements the EXSLT - Sets leading() function:
4544  *    node-set set:leading (node-set, node-set)
4545  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546  * is called.
4547  *
4548  * Returns the nodes in @nodes that precede @node in document order,
4549  *         @nodes if @node is NULL or an empty node-set if @nodes
4550  *         doesn't contain @node
4551  */
4552 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554     xmlXPathNodeSetSort(nodes);
4555     return(xmlXPathNodeLeadingSorted(nodes, node));
4556 }
4557 
4558 /**
4559  * xmlXPathLeadingSorted:
4560  * @nodes1:  a node-set, sorted by document order
4561  * @nodes2:  a node-set, sorted by document order
4562  *
4563  * Implements the EXSLT - Sets leading() function:
4564  *    node-set set:leading (node-set, node-set)
4565  *
4566  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4568  *         an empty node-set if @nodes1 doesn't contain @nodes2
4569  */
4570 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572     if (xmlXPathNodeSetIsEmpty(nodes2))
4573 	return(nodes1);
4574     return(xmlXPathNodeLeadingSorted(nodes1,
4575 				     xmlXPathNodeSetItem(nodes2, 1)));
4576 }
4577 
4578 /**
4579  * xmlXPathLeading:
4580  * @nodes1:  a node-set
4581  * @nodes2:  a node-set
4582  *
4583  * Implements the EXSLT - Sets leading() function:
4584  *    node-set set:leading (node-set, node-set)
4585  * @nodes1 and @nodes2 are sorted by document order, then
4586  * #exslSetsLeadingSorted is called.
4587  *
4588  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4590  *         an empty node-set if @nodes1 doesn't contain @nodes2
4591  */
4592 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594     if (xmlXPathNodeSetIsEmpty(nodes2))
4595 	return(nodes1);
4596     if (xmlXPathNodeSetIsEmpty(nodes1))
4597 	return(xmlXPathNodeSetCreate(NULL));
4598     xmlXPathNodeSetSort(nodes1);
4599     xmlXPathNodeSetSort(nodes2);
4600     return(xmlXPathNodeLeadingSorted(nodes1,
4601 				     xmlXPathNodeSetItem(nodes2, 1)));
4602 }
4603 
4604 /**
4605  * xmlXPathNodeTrailingSorted:
4606  * @nodes: a node-set, sorted by document order
4607  * @node: a node
4608  *
4609  * Implements the EXSLT - Sets trailing() function:
4610  *    node-set set:trailing (node-set, node-set)
4611  *
4612  * Returns the nodes in @nodes that follow @node in document order,
4613  *         @nodes if @node is NULL or an empty node-set if @nodes
4614  *         doesn't contain @node
4615  */
4616 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618     int i, l;
4619     xmlNodePtr cur;
4620     xmlNodeSetPtr ret;
4621 
4622     if (node == NULL)
4623 	return(nodes);
4624 
4625     ret = xmlXPathNodeSetCreate(NULL);
4626     if (ret == NULL)
4627         return(ret);
4628     if (xmlXPathNodeSetIsEmpty(nodes) ||
4629 	(!xmlXPathNodeSetContains(nodes, node)))
4630 	return(ret);
4631 
4632     l = xmlXPathNodeSetGetLength(nodes);
4633     for (i = l - 1; i >= 0; i--) {
4634 	cur = xmlXPathNodeSetItem(nodes, i);
4635 	if (cur == node)
4636 	    break;
4637 	xmlXPathNodeSetAddUnique(ret, cur);
4638     }
4639     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4640     return(ret);
4641 }
4642 
4643 /**
4644  * xmlXPathNodeTrailing:
4645  * @nodes:  a node-set
4646  * @node:  a node
4647  *
4648  * Implements the EXSLT - Sets trailing() function:
4649  *    node-set set:trailing (node-set, node-set)
4650  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651  * is called.
4652  *
4653  * Returns the nodes in @nodes that follow @node in document order,
4654  *         @nodes if @node is NULL or an empty node-set if @nodes
4655  *         doesn't contain @node
4656  */
4657 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659     xmlXPathNodeSetSort(nodes);
4660     return(xmlXPathNodeTrailingSorted(nodes, node));
4661 }
4662 
4663 /**
4664  * xmlXPathTrailingSorted:
4665  * @nodes1:  a node-set, sorted by document order
4666  * @nodes2:  a node-set, sorted by document order
4667  *
4668  * Implements the EXSLT - Sets trailing() function:
4669  *    node-set set:trailing (node-set, node-set)
4670  *
4671  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4673  *         an empty node-set if @nodes1 doesn't contain @nodes2
4674  */
4675 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677     if (xmlXPathNodeSetIsEmpty(nodes2))
4678 	return(nodes1);
4679     return(xmlXPathNodeTrailingSorted(nodes1,
4680 				      xmlXPathNodeSetItem(nodes2, 0)));
4681 }
4682 
4683 /**
4684  * xmlXPathTrailing:
4685  * @nodes1:  a node-set
4686  * @nodes2:  a node-set
4687  *
4688  * Implements the EXSLT - Sets trailing() function:
4689  *    node-set set:trailing (node-set, node-set)
4690  * @nodes1 and @nodes2 are sorted by document order, then
4691  * #xmlXPathTrailingSorted is called.
4692  *
4693  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4695  *         an empty node-set if @nodes1 doesn't contain @nodes2
4696  */
4697 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699     if (xmlXPathNodeSetIsEmpty(nodes2))
4700 	return(nodes1);
4701     if (xmlXPathNodeSetIsEmpty(nodes1))
4702 	return(xmlXPathNodeSetCreate(NULL));
4703     xmlXPathNodeSetSort(nodes1);
4704     xmlXPathNodeSetSort(nodes2);
4705     return(xmlXPathNodeTrailingSorted(nodes1,
4706 				      xmlXPathNodeSetItem(nodes2, 0)));
4707 }
4708 
4709 /************************************************************************
4710  *									*
4711  *		Routines to handle extra functions			*
4712  *									*
4713  ************************************************************************/
4714 
4715 /**
4716  * xmlXPathRegisterFunc:
4717  * @ctxt:  the XPath context
4718  * @name:  the function name
4719  * @f:  the function implementation or NULL
4720  *
4721  * Register a new function. If @f is NULL it unregisters the function
4722  *
4723  * Returns 0 in case of success, -1 in case of error
4724  */
4725 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 		     xmlXPathFunction f) {
4728     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729 }
4730 
4731 /**
4732  * xmlXPathRegisterFuncNS:
4733  * @ctxt:  the XPath context
4734  * @name:  the function name
4735  * @ns_uri:  the function namespace URI
4736  * @f:  the function implementation or NULL
4737  *
4738  * Register a new function. If @f is NULL it unregisters the function
4739  *
4740  * Returns 0 in case of success, -1 in case of error
4741  */
4742 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4745     if (ctxt == NULL)
4746 	return(-1);
4747     if (name == NULL)
4748 	return(-1);
4749 
4750     if (ctxt->funcHash == NULL)
4751 	ctxt->funcHash = xmlHashCreate(0);
4752     if (ctxt->funcHash == NULL)
4753 	return(-1);
4754     if (f == NULL)
4755         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4757 }
4758 
4759 /**
4760  * xmlXPathRegisterFuncLookup:
4761  * @ctxt:  the XPath context
4762  * @f:  the lookup function
4763  * @funcCtxt:  the lookup data
4764  *
4765  * Registers an external mechanism to do function lookup.
4766  */
4767 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769 			    xmlXPathFuncLookupFunc f,
4770 			    void *funcCtxt) {
4771     if (ctxt == NULL)
4772 	return;
4773     ctxt->funcLookupFunc = f;
4774     ctxt->funcLookupData = funcCtxt;
4775 }
4776 
4777 /**
4778  * xmlXPathFunctionLookup:
4779  * @ctxt:  the XPath context
4780  * @name:  the function name
4781  *
4782  * Search in the Function array of the context for the given
4783  * function.
4784  *
4785  * Returns the xmlXPathFunction or NULL if not found
4786  */
4787 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4789     if (ctxt == NULL)
4790 	return (NULL);
4791 
4792     if (ctxt->funcLookupFunc != NULL) {
4793 	xmlXPathFunction ret;
4794 	xmlXPathFuncLookupFunc f;
4795 
4796 	f = ctxt->funcLookupFunc;
4797 	ret = f(ctxt->funcLookupData, name, NULL);
4798 	if (ret != NULL)
4799 	    return(ret);
4800     }
4801     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802 }
4803 
4804 /**
4805  * xmlXPathFunctionLookupNS:
4806  * @ctxt:  the XPath context
4807  * @name:  the function name
4808  * @ns_uri:  the function namespace URI
4809  *
4810  * Search in the Function array of the context for the given
4811  * function.
4812  *
4813  * Returns the xmlXPathFunction or NULL if not found
4814  */
4815 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817 			 const xmlChar *ns_uri) {
4818     xmlXPathFunction ret;
4819 
4820     if (ctxt == NULL)
4821 	return(NULL);
4822     if (name == NULL)
4823 	return(NULL);
4824 
4825     if (ctxt->funcLookupFunc != NULL) {
4826 	xmlXPathFuncLookupFunc f;
4827 
4828 	f = ctxt->funcLookupFunc;
4829 	ret = f(ctxt->funcLookupData, name, ns_uri);
4830 	if (ret != NULL)
4831 	    return(ret);
4832     }
4833 
4834     if (ctxt->funcHash == NULL)
4835 	return(NULL);
4836 
4837     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838     return(ret);
4839 }
4840 
4841 /**
4842  * xmlXPathRegisteredFuncsCleanup:
4843  * @ctxt:  the XPath context
4844  *
4845  * Cleanup the XPath context data associated to registered functions
4846  */
4847 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849     if (ctxt == NULL)
4850 	return;
4851 
4852     xmlHashFree(ctxt->funcHash, NULL);
4853     ctxt->funcHash = NULL;
4854 }
4855 
4856 /************************************************************************
4857  *									*
4858  *			Routines to handle Variables			*
4859  *									*
4860  ************************************************************************/
4861 
4862 /**
4863  * xmlXPathRegisterVariable:
4864  * @ctxt:  the XPath context
4865  * @name:  the variable name
4866  * @value:  the variable value or NULL
4867  *
4868  * Register a new variable value. If @value is NULL it unregisters
4869  * the variable
4870  *
4871  * Returns 0 in case of success, -1 in case of error
4872  */
4873 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875 			 xmlXPathObjectPtr value) {
4876     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877 }
4878 
4879 /**
4880  * xmlXPathRegisterVariableNS:
4881  * @ctxt:  the XPath context
4882  * @name:  the variable name
4883  * @ns_uri:  the variable namespace URI
4884  * @value:  the variable value or NULL
4885  *
4886  * Register a new variable value. If @value is NULL it unregisters
4887  * the variable
4888  *
4889  * Returns 0 in case of success, -1 in case of error
4890  */
4891 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893 			   const xmlChar *ns_uri,
4894 			   xmlXPathObjectPtr value) {
4895     if (ctxt == NULL)
4896 	return(-1);
4897     if (name == NULL)
4898 	return(-1);
4899 
4900     if (ctxt->varHash == NULL)
4901 	ctxt->varHash = xmlHashCreate(0);
4902     if (ctxt->varHash == NULL)
4903 	return(-1);
4904     if (value == NULL)
4905         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906 	                           (xmlHashDeallocator)xmlXPathFreeObject));
4907     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908 			       (void *) value,
4909 			       (xmlHashDeallocator)xmlXPathFreeObject));
4910 }
4911 
4912 /**
4913  * xmlXPathRegisterVariableLookup:
4914  * @ctxt:  the XPath context
4915  * @f:  the lookup function
4916  * @data:  the lookup data
4917  *
4918  * register an external mechanism to do variable lookup
4919  */
4920 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922 	 xmlXPathVariableLookupFunc f, void *data) {
4923     if (ctxt == NULL)
4924 	return;
4925     ctxt->varLookupFunc = f;
4926     ctxt->varLookupData = data;
4927 }
4928 
4929 /**
4930  * xmlXPathVariableLookup:
4931  * @ctxt:  the XPath context
4932  * @name:  the variable name
4933  *
4934  * Search in the Variable array of the context for the given
4935  * variable value.
4936  *
4937  * Returns a copy of the value or NULL if not found
4938  */
4939 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941     if (ctxt == NULL)
4942 	return(NULL);
4943 
4944     if (ctxt->varLookupFunc != NULL) {
4945 	xmlXPathObjectPtr ret;
4946 
4947 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948 	        (ctxt->varLookupData, name, NULL);
4949 	return(ret);
4950     }
4951     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952 }
4953 
4954 /**
4955  * xmlXPathVariableLookupNS:
4956  * @ctxt:  the XPath context
4957  * @name:  the variable name
4958  * @ns_uri:  the variable namespace URI
4959  *
4960  * Search in the Variable array of the context for the given
4961  * variable value.
4962  *
4963  * Returns the a copy of the value or NULL if not found
4964  */
4965 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967 			 const xmlChar *ns_uri) {
4968     if (ctxt == NULL)
4969 	return(NULL);
4970 
4971     if (ctxt->varLookupFunc != NULL) {
4972 	xmlXPathObjectPtr ret;
4973 
4974 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975 	        (ctxt->varLookupData, name, ns_uri);
4976 	if (ret != NULL) return(ret);
4977     }
4978 
4979     if (ctxt->varHash == NULL)
4980 	return(NULL);
4981     if (name == NULL)
4982 	return(NULL);
4983 
4984     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4986 }
4987 
4988 /**
4989  * xmlXPathRegisteredVariablesCleanup:
4990  * @ctxt:  the XPath context
4991  *
4992  * Cleanup the XPath context data associated to registered variables
4993  */
4994 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996     if (ctxt == NULL)
4997 	return;
4998 
4999     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000     ctxt->varHash = NULL;
5001 }
5002 
5003 /**
5004  * xmlXPathRegisterNs:
5005  * @ctxt:  the XPath context
5006  * @prefix:  the namespace prefix
5007  * @ns_uri:  the namespace name
5008  *
5009  * Register a new namespace. If @ns_uri is NULL it unregisters
5010  * the namespace
5011  *
5012  * Returns 0 in case of success, -1 in case of error
5013  */
5014 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016 			   const xmlChar *ns_uri) {
5017     if (ctxt == NULL)
5018 	return(-1);
5019     if (prefix == NULL)
5020 	return(-1);
5021 
5022     if (ctxt->nsHash == NULL)
5023 	ctxt->nsHash = xmlHashCreate(10);
5024     if (ctxt->nsHash == NULL)
5025 	return(-1);
5026     if (ns_uri == NULL)
5027         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5028 	                          (xmlHashDeallocator)xmlFree));
5029     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5030 			      (xmlHashDeallocator)xmlFree));
5031 }
5032 
5033 /**
5034  * xmlXPathNsLookup:
5035  * @ctxt:  the XPath context
5036  * @prefix:  the namespace prefix value
5037  *
5038  * Search in the namespace declaration array of the context for the given
5039  * namespace name associated to the given prefix
5040  *
5041  * Returns the value or NULL if not found
5042  */
5043 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5044 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5045     if (ctxt == NULL)
5046 	return(NULL);
5047     if (prefix == NULL)
5048 	return(NULL);
5049 
5050 #ifdef XML_XML_NAMESPACE
5051     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5052 	return(XML_XML_NAMESPACE);
5053 #endif
5054 
5055     if (ctxt->namespaces != NULL) {
5056 	int i;
5057 
5058 	for (i = 0;i < ctxt->nsNr;i++) {
5059 	    if ((ctxt->namespaces[i] != NULL) &&
5060 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5061 		return(ctxt->namespaces[i]->href);
5062 	}
5063     }
5064 
5065     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5066 }
5067 
5068 /**
5069  * xmlXPathRegisteredNsCleanup:
5070  * @ctxt:  the XPath context
5071  *
5072  * Cleanup the XPath context data associated to registered variables
5073  */
5074 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5075 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5076     if (ctxt == NULL)
5077 	return;
5078 
5079     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5080     ctxt->nsHash = NULL;
5081 }
5082 
5083 /************************************************************************
5084  *									*
5085  *			Routines to handle Values			*
5086  *									*
5087  ************************************************************************/
5088 
5089 /* Allocations are terrible, one needs to optimize all this !!! */
5090 
5091 /**
5092  * xmlXPathNewFloat:
5093  * @val:  the double value
5094  *
5095  * Create a new xmlXPathObjectPtr of type double and of value @val
5096  *
5097  * Returns the newly created object.
5098  */
5099 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5100 xmlXPathNewFloat(double val) {
5101     xmlXPathObjectPtr ret;
5102 
5103     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5104     if (ret == NULL) {
5105         xmlXPathErrMemory(NULL, "creating float object\n");
5106 	return(NULL);
5107     }
5108     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5109     ret->type = XPATH_NUMBER;
5110     ret->floatval = val;
5111 #ifdef XP_DEBUG_OBJ_USAGE
5112     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5113 #endif
5114     return(ret);
5115 }
5116 
5117 /**
5118  * xmlXPathNewBoolean:
5119  * @val:  the boolean value
5120  *
5121  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5122  *
5123  * Returns the newly created object.
5124  */
5125 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5126 xmlXPathNewBoolean(int val) {
5127     xmlXPathObjectPtr ret;
5128 
5129     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5130     if (ret == NULL) {
5131         xmlXPathErrMemory(NULL, "creating boolean object\n");
5132 	return(NULL);
5133     }
5134     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5135     ret->type = XPATH_BOOLEAN;
5136     ret->boolval = (val != 0);
5137 #ifdef XP_DEBUG_OBJ_USAGE
5138     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5139 #endif
5140     return(ret);
5141 }
5142 
5143 /**
5144  * xmlXPathNewString:
5145  * @val:  the xmlChar * value
5146  *
5147  * Create a new xmlXPathObjectPtr of type string and of value @val
5148  *
5149  * Returns the newly created object.
5150  */
5151 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5152 xmlXPathNewString(const xmlChar *val) {
5153     xmlXPathObjectPtr ret;
5154 
5155     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5156     if (ret == NULL) {
5157         xmlXPathErrMemory(NULL, "creating string object\n");
5158 	return(NULL);
5159     }
5160     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5161     ret->type = XPATH_STRING;
5162     if (val != NULL)
5163 	ret->stringval = xmlStrdup(val);
5164     else
5165 	ret->stringval = xmlStrdup((const xmlChar *)"");
5166 #ifdef XP_DEBUG_OBJ_USAGE
5167     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5168 #endif
5169     return(ret);
5170 }
5171 
5172 /**
5173  * xmlXPathWrapString:
5174  * @val:  the xmlChar * value
5175  *
5176  * Wraps the @val string into an XPath object.
5177  *
5178  * Returns the newly created object.
5179  */
5180 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5181 xmlXPathWrapString (xmlChar *val) {
5182     xmlXPathObjectPtr ret;
5183 
5184     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5185     if (ret == NULL) {
5186         xmlXPathErrMemory(NULL, "creating string object\n");
5187 	return(NULL);
5188     }
5189     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5190     ret->type = XPATH_STRING;
5191     ret->stringval = val;
5192 #ifdef XP_DEBUG_OBJ_USAGE
5193     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5194 #endif
5195     return(ret);
5196 }
5197 
5198 /**
5199  * xmlXPathNewCString:
5200  * @val:  the char * value
5201  *
5202  * Create a new xmlXPathObjectPtr of type string and of value @val
5203  *
5204  * Returns the newly created object.
5205  */
5206 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5207 xmlXPathNewCString(const char *val) {
5208     xmlXPathObjectPtr ret;
5209 
5210     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5211     if (ret == NULL) {
5212         xmlXPathErrMemory(NULL, "creating string object\n");
5213 	return(NULL);
5214     }
5215     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5216     ret->type = XPATH_STRING;
5217     ret->stringval = xmlStrdup(BAD_CAST val);
5218 #ifdef XP_DEBUG_OBJ_USAGE
5219     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5220 #endif
5221     return(ret);
5222 }
5223 
5224 /**
5225  * xmlXPathWrapCString:
5226  * @val:  the char * value
5227  *
5228  * Wraps a string into an XPath object.
5229  *
5230  * Returns the newly created object.
5231  */
5232 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5233 xmlXPathWrapCString (char * val) {
5234     return(xmlXPathWrapString((xmlChar *)(val)));
5235 }
5236 
5237 /**
5238  * xmlXPathWrapExternal:
5239  * @val:  the user data
5240  *
5241  * Wraps the @val data into an XPath object.
5242  *
5243  * Returns the newly created object.
5244  */
5245 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5246 xmlXPathWrapExternal (void *val) {
5247     xmlXPathObjectPtr ret;
5248 
5249     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5250     if (ret == NULL) {
5251         xmlXPathErrMemory(NULL, "creating user object\n");
5252 	return(NULL);
5253     }
5254     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5255     ret->type = XPATH_USERS;
5256     ret->user = val;
5257 #ifdef XP_DEBUG_OBJ_USAGE
5258     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5259 #endif
5260     return(ret);
5261 }
5262 
5263 /**
5264  * xmlXPathObjectCopy:
5265  * @val:  the original object
5266  *
5267  * allocate a new copy of a given object
5268  *
5269  * Returns the newly created object.
5270  */
5271 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5272 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5273     xmlXPathObjectPtr ret;
5274 
5275     if (val == NULL)
5276 	return(NULL);
5277 
5278     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5279     if (ret == NULL) {
5280         xmlXPathErrMemory(NULL, "copying object\n");
5281 	return(NULL);
5282     }
5283     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5284 #ifdef XP_DEBUG_OBJ_USAGE
5285     xmlXPathDebugObjUsageRequested(NULL, val->type);
5286 #endif
5287     switch (val->type) {
5288 	case XPATH_BOOLEAN:
5289 	case XPATH_NUMBER:
5290 	case XPATH_POINT:
5291 	case XPATH_RANGE:
5292 	    break;
5293 	case XPATH_STRING:
5294 	    ret->stringval = xmlStrdup(val->stringval);
5295 	    break;
5296 	case XPATH_XSLT_TREE:
5297 #if 0
5298 /*
5299   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5300   this previous handling is no longer correct, and can cause some serious
5301   problems (ref. bug 145547)
5302 */
5303 	    if ((val->nodesetval != NULL) &&
5304 		(val->nodesetval->nodeTab != NULL)) {
5305 		xmlNodePtr cur, tmp;
5306 		xmlDocPtr top;
5307 
5308 		ret->boolval = 1;
5309 		top =  xmlNewDoc(NULL);
5310 		top->name = (char *)
5311 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5312 		ret->user = top;
5313 		if (top != NULL) {
5314 		    top->doc = top;
5315 		    cur = val->nodesetval->nodeTab[0]->children;
5316 		    while (cur != NULL) {
5317 			tmp = xmlDocCopyNode(cur, top, 1);
5318 			xmlAddChild((xmlNodePtr) top, tmp);
5319 			cur = cur->next;
5320 		    }
5321 		}
5322 
5323 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5324 	    } else
5325 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5326 	    /* Deallocate the copied tree value */
5327 	    break;
5328 #endif
5329 	case XPATH_NODESET:
5330 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5331 	    /* Do not deallocate the copied tree value */
5332 	    ret->boolval = 0;
5333 	    break;
5334 	case XPATH_LOCATIONSET:
5335 #ifdef LIBXML_XPTR_ENABLED
5336 	{
5337 	    xmlLocationSetPtr loc = val->user;
5338 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5339 	    break;
5340 	}
5341 #endif
5342         case XPATH_USERS:
5343 	    ret->user = val->user;
5344 	    break;
5345         case XPATH_UNDEFINED:
5346 	    xmlGenericError(xmlGenericErrorContext,
5347 		    "xmlXPathObjectCopy: unsupported type %d\n",
5348 		    val->type);
5349 	    break;
5350     }
5351     return(ret);
5352 }
5353 
5354 /**
5355  * xmlXPathFreeObject:
5356  * @obj:  the object to free
5357  *
5358  * Free up an xmlXPathObjectPtr object.
5359  */
5360 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5361 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5362     if (obj == NULL) return;
5363     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5364 	if (obj->boolval) {
5365 #if 0
5366 	    if (obj->user != NULL) {
5367                 xmlXPathFreeNodeSet(obj->nodesetval);
5368 		xmlFreeNodeList((xmlNodePtr) obj->user);
5369 	    } else
5370 #endif
5371 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5372 	    if (obj->nodesetval != NULL)
5373 		xmlXPathFreeValueTree(obj->nodesetval);
5374 	} else {
5375 	    if (obj->nodesetval != NULL)
5376 		xmlXPathFreeNodeSet(obj->nodesetval);
5377 	}
5378 #ifdef LIBXML_XPTR_ENABLED
5379     } else if (obj->type == XPATH_LOCATIONSET) {
5380 	if (obj->user != NULL)
5381 	    xmlXPtrFreeLocationSet(obj->user);
5382 #endif
5383     } else if (obj->type == XPATH_STRING) {
5384 	if (obj->stringval != NULL)
5385 	    xmlFree(obj->stringval);
5386     }
5387 #ifdef XP_DEBUG_OBJ_USAGE
5388     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5389 #endif
5390     xmlFree(obj);
5391 }
5392 
5393 /**
5394  * xmlXPathReleaseObject:
5395  * @obj:  the xmlXPathObjectPtr to free or to cache
5396  *
5397  * Depending on the state of the cache this frees the given
5398  * XPath object or stores it in the cache.
5399  */
5400 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5401 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5402 {
5403 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5404 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5405     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5406 
5407 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5408 
5409     if (obj == NULL)
5410 	return;
5411     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5412 	 xmlXPathFreeObject(obj);
5413     } else {
5414 	xmlXPathContextCachePtr cache =
5415 	    (xmlXPathContextCachePtr) ctxt->cache;
5416 
5417 	switch (obj->type) {
5418 	    case XPATH_NODESET:
5419 	    case XPATH_XSLT_TREE:
5420 		if (obj->nodesetval != NULL) {
5421 		    if (obj->boolval) {
5422 			/*
5423 			* It looks like the @boolval is used for
5424 			* evaluation if this an XSLT Result Tree Fragment.
5425 			* TODO: Check if this assumption is correct.
5426 			*/
5427 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5428 			xmlXPathFreeValueTree(obj->nodesetval);
5429 			obj->nodesetval = NULL;
5430 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5431 			(XP_CACHE_WANTS(cache->nodesetObjs,
5432 					cache->maxNodeset)))
5433 		    {
5434 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5435 			goto obj_cached;
5436 		    } else {
5437 			xmlXPathFreeNodeSet(obj->nodesetval);
5438 			obj->nodesetval = NULL;
5439 		    }
5440 		}
5441 		break;
5442 	    case XPATH_STRING:
5443 		if (obj->stringval != NULL)
5444 		    xmlFree(obj->stringval);
5445 
5446 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5447 		    XP_CACHE_ADD(cache->stringObjs, obj);
5448 		    goto obj_cached;
5449 		}
5450 		break;
5451 	    case XPATH_BOOLEAN:
5452 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5453 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5454 		    goto obj_cached;
5455 		}
5456 		break;
5457 	    case XPATH_NUMBER:
5458 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5459 		    XP_CACHE_ADD(cache->numberObjs, obj);
5460 		    goto obj_cached;
5461 		}
5462 		break;
5463 #ifdef LIBXML_XPTR_ENABLED
5464 	    case XPATH_LOCATIONSET:
5465 		if (obj->user != NULL) {
5466 		    xmlXPtrFreeLocationSet(obj->user);
5467 		}
5468 		goto free_obj;
5469 #endif
5470 	    default:
5471 		goto free_obj;
5472 	}
5473 
5474 	/*
5475 	* Fallback to adding to the misc-objects slot.
5476 	*/
5477 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5478 	    XP_CACHE_ADD(cache->miscObjs, obj);
5479 	} else
5480 	    goto free_obj;
5481 
5482 obj_cached:
5483 
5484 #ifdef XP_DEBUG_OBJ_USAGE
5485 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5486 #endif
5487 
5488 	if (obj->nodesetval != NULL) {
5489 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5490 
5491 	    /*
5492 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5493 	    *  the list and free the ns-nodes.
5494 	    * URGENT TODO: Check if it's actually slowing things down.
5495 	    *  Maybe we shouldn't try to preserve the list.
5496 	    */
5497 	    if (tmpset->nodeNr > 1) {
5498 		int i;
5499 		xmlNodePtr node;
5500 
5501 		for (i = 0; i < tmpset->nodeNr; i++) {
5502 		    node = tmpset->nodeTab[i];
5503 		    if ((node != NULL) &&
5504 			(node->type == XML_NAMESPACE_DECL))
5505 		    {
5506 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5507 		    }
5508 		}
5509 	    } else if (tmpset->nodeNr == 1) {
5510 		if ((tmpset->nodeTab[0] != NULL) &&
5511 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5512 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5513 	    }
5514 	    tmpset->nodeNr = 0;
5515 	    memset(obj, 0, sizeof(xmlXPathObject));
5516 	    obj->nodesetval = tmpset;
5517 	} else
5518 	    memset(obj, 0, sizeof(xmlXPathObject));
5519 
5520 	return;
5521 
5522 free_obj:
5523 	/*
5524 	* Cache is full; free the object.
5525 	*/
5526 	if (obj->nodesetval != NULL)
5527 	    xmlXPathFreeNodeSet(obj->nodesetval);
5528 #ifdef XP_DEBUG_OBJ_USAGE
5529 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5530 #endif
5531 	xmlFree(obj);
5532     }
5533     return;
5534 }
5535 
5536 
5537 /************************************************************************
5538  *									*
5539  *			Type Casting Routines				*
5540  *									*
5541  ************************************************************************/
5542 
5543 /**
5544  * xmlXPathCastBooleanToString:
5545  * @val:  a boolean
5546  *
5547  * Converts a boolean to its string value.
5548  *
5549  * Returns a newly allocated string.
5550  */
5551 xmlChar *
xmlXPathCastBooleanToString(int val)5552 xmlXPathCastBooleanToString (int val) {
5553     xmlChar *ret;
5554     if (val)
5555 	ret = xmlStrdup((const xmlChar *) "true");
5556     else
5557 	ret = xmlStrdup((const xmlChar *) "false");
5558     return(ret);
5559 }
5560 
5561 /**
5562  * xmlXPathCastNumberToString:
5563  * @val:  a number
5564  *
5565  * Converts a number to its string value.
5566  *
5567  * Returns a newly allocated string.
5568  */
5569 xmlChar *
xmlXPathCastNumberToString(double val)5570 xmlXPathCastNumberToString (double val) {
5571     xmlChar *ret;
5572     switch (xmlXPathIsInf(val)) {
5573     case 1:
5574 	ret = xmlStrdup((const xmlChar *) "Infinity");
5575 	break;
5576     case -1:
5577 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5578 	break;
5579     default:
5580 	if (xmlXPathIsNaN(val)) {
5581 	    ret = xmlStrdup((const xmlChar *) "NaN");
5582 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5583 	    ret = xmlStrdup((const xmlChar *) "0");
5584 	} else {
5585 	    /* could be improved */
5586 	    char buf[100];
5587 	    xmlXPathFormatNumber(val, buf, 99);
5588 	    buf[99] = 0;
5589 	    ret = xmlStrdup((const xmlChar *) buf);
5590 	}
5591     }
5592     return(ret);
5593 }
5594 
5595 /**
5596  * xmlXPathCastNodeToString:
5597  * @node:  a node
5598  *
5599  * Converts a node to its string value.
5600  *
5601  * Returns a newly allocated string.
5602  */
5603 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5604 xmlXPathCastNodeToString (xmlNodePtr node) {
5605 xmlChar *ret;
5606     if ((ret = xmlNodeGetContent(node)) == NULL)
5607 	ret = xmlStrdup((const xmlChar *) "");
5608     return(ret);
5609 }
5610 
5611 /**
5612  * xmlXPathCastNodeSetToString:
5613  * @ns:  a node-set
5614  *
5615  * Converts a node-set to its string value.
5616  *
5617  * Returns a newly allocated string.
5618  */
5619 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5620 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5621     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5622 	return(xmlStrdup((const xmlChar *) ""));
5623 
5624     if (ns->nodeNr > 1)
5625 	xmlXPathNodeSetSort(ns);
5626     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5627 }
5628 
5629 /**
5630  * xmlXPathCastToString:
5631  * @val:  an XPath object
5632  *
5633  * Converts an existing object to its string() equivalent
5634  *
5635  * Returns the allocated string value of the object, NULL in case of error.
5636  *         It's up to the caller to free the string memory with xmlFree().
5637  */
5638 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5639 xmlXPathCastToString(xmlXPathObjectPtr val) {
5640     xmlChar *ret = NULL;
5641 
5642     if (val == NULL)
5643 	return(xmlStrdup((const xmlChar *) ""));
5644     switch (val->type) {
5645 	case XPATH_UNDEFINED:
5646 #ifdef DEBUG_EXPR
5647 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5648 #endif
5649 	    ret = xmlStrdup((const xmlChar *) "");
5650 	    break;
5651         case XPATH_NODESET:
5652         case XPATH_XSLT_TREE:
5653 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5654 	    break;
5655 	case XPATH_STRING:
5656 	    return(xmlStrdup(val->stringval));
5657         case XPATH_BOOLEAN:
5658 	    ret = xmlXPathCastBooleanToString(val->boolval);
5659 	    break;
5660 	case XPATH_NUMBER: {
5661 	    ret = xmlXPathCastNumberToString(val->floatval);
5662 	    break;
5663 	}
5664 	case XPATH_USERS:
5665 	case XPATH_POINT:
5666 	case XPATH_RANGE:
5667 	case XPATH_LOCATIONSET:
5668 	    TODO
5669 	    ret = xmlStrdup((const xmlChar *) "");
5670 	    break;
5671     }
5672     return(ret);
5673 }
5674 
5675 /**
5676  * xmlXPathConvertString:
5677  * @val:  an XPath object
5678  *
5679  * Converts an existing object to its string() equivalent
5680  *
5681  * Returns the new object, the old one is freed (or the operation
5682  *         is done directly on @val)
5683  */
5684 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5685 xmlXPathConvertString(xmlXPathObjectPtr val) {
5686     xmlChar *res = NULL;
5687 
5688     if (val == NULL)
5689 	return(xmlXPathNewCString(""));
5690 
5691     switch (val->type) {
5692     case XPATH_UNDEFINED:
5693 #ifdef DEBUG_EXPR
5694 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5695 #endif
5696 	break;
5697     case XPATH_NODESET:
5698     case XPATH_XSLT_TREE:
5699 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5700 	break;
5701     case XPATH_STRING:
5702 	return(val);
5703     case XPATH_BOOLEAN:
5704 	res = xmlXPathCastBooleanToString(val->boolval);
5705 	break;
5706     case XPATH_NUMBER:
5707 	res = xmlXPathCastNumberToString(val->floatval);
5708 	break;
5709     case XPATH_USERS:
5710     case XPATH_POINT:
5711     case XPATH_RANGE:
5712     case XPATH_LOCATIONSET:
5713 	TODO;
5714 	break;
5715     }
5716     xmlXPathFreeObject(val);
5717     if (res == NULL)
5718 	return(xmlXPathNewCString(""));
5719     return(xmlXPathWrapString(res));
5720 }
5721 
5722 /**
5723  * xmlXPathCastBooleanToNumber:
5724  * @val:  a boolean
5725  *
5726  * Converts a boolean to its number value
5727  *
5728  * Returns the number value
5729  */
5730 double
xmlXPathCastBooleanToNumber(int val)5731 xmlXPathCastBooleanToNumber(int val) {
5732     if (val)
5733 	return(1.0);
5734     return(0.0);
5735 }
5736 
5737 /**
5738  * xmlXPathCastStringToNumber:
5739  * @val:  a string
5740  *
5741  * Converts a string to its number value
5742  *
5743  * Returns the number value
5744  */
5745 double
xmlXPathCastStringToNumber(const xmlChar * val)5746 xmlXPathCastStringToNumber(const xmlChar * val) {
5747     return(xmlXPathStringEvalNumber(val));
5748 }
5749 
5750 /**
5751  * xmlXPathCastNodeToNumber:
5752  * @node:  a node
5753  *
5754  * Converts a node to its number value
5755  *
5756  * Returns the number value
5757  */
5758 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5759 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5760     xmlChar *strval;
5761     double ret;
5762 
5763     if (node == NULL)
5764 	return(xmlXPathNAN);
5765     strval = xmlXPathCastNodeToString(node);
5766     if (strval == NULL)
5767 	return(xmlXPathNAN);
5768     ret = xmlXPathCastStringToNumber(strval);
5769     xmlFree(strval);
5770 
5771     return(ret);
5772 }
5773 
5774 /**
5775  * xmlXPathCastNodeSetToNumber:
5776  * @ns:  a node-set
5777  *
5778  * Converts a node-set to its number value
5779  *
5780  * Returns the number value
5781  */
5782 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5783 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5784     xmlChar *str;
5785     double ret;
5786 
5787     if (ns == NULL)
5788 	return(xmlXPathNAN);
5789     str = xmlXPathCastNodeSetToString(ns);
5790     ret = xmlXPathCastStringToNumber(str);
5791     xmlFree(str);
5792     return(ret);
5793 }
5794 
5795 /**
5796  * xmlXPathCastToNumber:
5797  * @val:  an XPath object
5798  *
5799  * Converts an XPath object to its number value
5800  *
5801  * Returns the number value
5802  */
5803 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5804 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5805     double ret = 0.0;
5806 
5807     if (val == NULL)
5808 	return(xmlXPathNAN);
5809     switch (val->type) {
5810     case XPATH_UNDEFINED:
5811 #ifdef DEGUB_EXPR
5812 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5813 #endif
5814 	ret = xmlXPathNAN;
5815 	break;
5816     case XPATH_NODESET:
5817     case XPATH_XSLT_TREE:
5818 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5819 	break;
5820     case XPATH_STRING:
5821 	ret = xmlXPathCastStringToNumber(val->stringval);
5822 	break;
5823     case XPATH_NUMBER:
5824 	ret = val->floatval;
5825 	break;
5826     case XPATH_BOOLEAN:
5827 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5828 	break;
5829     case XPATH_USERS:
5830     case XPATH_POINT:
5831     case XPATH_RANGE:
5832     case XPATH_LOCATIONSET:
5833 	TODO;
5834 	ret = xmlXPathNAN;
5835 	break;
5836     }
5837     return(ret);
5838 }
5839 
5840 /**
5841  * xmlXPathConvertNumber:
5842  * @val:  an XPath object
5843  *
5844  * Converts an existing object to its number() equivalent
5845  *
5846  * Returns the new object, the old one is freed (or the operation
5847  *         is done directly on @val)
5848  */
5849 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5850 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5851     xmlXPathObjectPtr ret;
5852 
5853     if (val == NULL)
5854 	return(xmlXPathNewFloat(0.0));
5855     if (val->type == XPATH_NUMBER)
5856 	return(val);
5857     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5858     xmlXPathFreeObject(val);
5859     return(ret);
5860 }
5861 
5862 /**
5863  * xmlXPathCastNumberToBoolean:
5864  * @val:  a number
5865  *
5866  * Converts a number to its boolean value
5867  *
5868  * Returns the boolean value
5869  */
5870 int
xmlXPathCastNumberToBoolean(double val)5871 xmlXPathCastNumberToBoolean (double val) {
5872      if (xmlXPathIsNaN(val) || (val == 0.0))
5873 	 return(0);
5874      return(1);
5875 }
5876 
5877 /**
5878  * xmlXPathCastStringToBoolean:
5879  * @val:  a string
5880  *
5881  * Converts a string to its boolean value
5882  *
5883  * Returns the boolean value
5884  */
5885 int
xmlXPathCastStringToBoolean(const xmlChar * val)5886 xmlXPathCastStringToBoolean (const xmlChar *val) {
5887     if ((val == NULL) || (xmlStrlen(val) == 0))
5888 	return(0);
5889     return(1);
5890 }
5891 
5892 /**
5893  * xmlXPathCastNodeSetToBoolean:
5894  * @ns:  a node-set
5895  *
5896  * Converts a node-set to its boolean value
5897  *
5898  * Returns the boolean value
5899  */
5900 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5901 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5902     if ((ns == NULL) || (ns->nodeNr == 0))
5903 	return(0);
5904     return(1);
5905 }
5906 
5907 /**
5908  * xmlXPathCastToBoolean:
5909  * @val:  an XPath object
5910  *
5911  * Converts an XPath object to its boolean value
5912  *
5913  * Returns the boolean value
5914  */
5915 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5916 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5917     int ret = 0;
5918 
5919     if (val == NULL)
5920 	return(0);
5921     switch (val->type) {
5922     case XPATH_UNDEFINED:
5923 #ifdef DEBUG_EXPR
5924 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5925 #endif
5926 	ret = 0;
5927 	break;
5928     case XPATH_NODESET:
5929     case XPATH_XSLT_TREE:
5930 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5931 	break;
5932     case XPATH_STRING:
5933 	ret = xmlXPathCastStringToBoolean(val->stringval);
5934 	break;
5935     case XPATH_NUMBER:
5936 	ret = xmlXPathCastNumberToBoolean(val->floatval);
5937 	break;
5938     case XPATH_BOOLEAN:
5939 	ret = val->boolval;
5940 	break;
5941     case XPATH_USERS:
5942     case XPATH_POINT:
5943     case XPATH_RANGE:
5944     case XPATH_LOCATIONSET:
5945 	TODO;
5946 	ret = 0;
5947 	break;
5948     }
5949     return(ret);
5950 }
5951 
5952 
5953 /**
5954  * xmlXPathConvertBoolean:
5955  * @val:  an XPath object
5956  *
5957  * Converts an existing object to its boolean() equivalent
5958  *
5959  * Returns the new object, the old one is freed (or the operation
5960  *         is done directly on @val)
5961  */
5962 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)5963 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5964     xmlXPathObjectPtr ret;
5965 
5966     if (val == NULL)
5967 	return(xmlXPathNewBoolean(0));
5968     if (val->type == XPATH_BOOLEAN)
5969 	return(val);
5970     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5971     xmlXPathFreeObject(val);
5972     return(ret);
5973 }
5974 
5975 /************************************************************************
5976  *									*
5977  *		Routines to handle XPath contexts			*
5978  *									*
5979  ************************************************************************/
5980 
5981 /**
5982  * xmlXPathNewContext:
5983  * @doc:  the XML document
5984  *
5985  * Create a new xmlXPathContext
5986  *
5987  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5988  */
5989 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)5990 xmlXPathNewContext(xmlDocPtr doc) {
5991     xmlXPathContextPtr ret;
5992 
5993     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5994     if (ret == NULL) {
5995         xmlXPathErrMemory(NULL, "creating context\n");
5996 	return(NULL);
5997     }
5998     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5999     ret->doc = doc;
6000     ret->node = NULL;
6001 
6002     ret->varHash = NULL;
6003 
6004     ret->nb_types = 0;
6005     ret->max_types = 0;
6006     ret->types = NULL;
6007 
6008     ret->funcHash = xmlHashCreate(0);
6009 
6010     ret->nb_axis = 0;
6011     ret->max_axis = 0;
6012     ret->axis = NULL;
6013 
6014     ret->nsHash = NULL;
6015     ret->user = NULL;
6016 
6017     ret->contextSize = -1;
6018     ret->proximityPosition = -1;
6019 
6020 #ifdef XP_DEFAULT_CACHE_ON
6021     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6022 	xmlXPathFreeContext(ret);
6023 	return(NULL);
6024     }
6025 #endif
6026 
6027     xmlXPathRegisterAllFunctions(ret);
6028 
6029     return(ret);
6030 }
6031 
6032 /**
6033  * xmlXPathFreeContext:
6034  * @ctxt:  the context to free
6035  *
6036  * Free up an xmlXPathContext
6037  */
6038 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6039 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6040     if (ctxt == NULL) return;
6041 
6042     if (ctxt->cache != NULL)
6043 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6044     xmlXPathRegisteredNsCleanup(ctxt);
6045     xmlXPathRegisteredFuncsCleanup(ctxt);
6046     xmlXPathRegisteredVariablesCleanup(ctxt);
6047     xmlResetError(&ctxt->lastError);
6048     xmlFree(ctxt);
6049 }
6050 
6051 /************************************************************************
6052  *									*
6053  *		Routines to handle XPath parser contexts		*
6054  *									*
6055  ************************************************************************/
6056 
6057 #define CHECK_CTXT(ctxt)						\
6058     if (ctxt == NULL) {						\
6059 	__xmlRaiseError(NULL, NULL, NULL,				\
6060 		NULL, NULL, XML_FROM_XPATH,				\
6061 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6062 		__FILE__, __LINE__,					\
6063 		NULL, NULL, NULL, 0, 0,					\
6064 		"NULL context pointer\n");				\
6065 	return(NULL);							\
6066     }									\
6067 
6068 #define CHECK_CTXT_NEG(ctxt)						\
6069     if (ctxt == NULL) {						\
6070 	__xmlRaiseError(NULL, NULL, NULL,				\
6071 		NULL, NULL, XML_FROM_XPATH,				\
6072 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6073 		__FILE__, __LINE__,					\
6074 		NULL, NULL, NULL, 0, 0,					\
6075 		"NULL context pointer\n");				\
6076 	return(-1);							\
6077     }									\
6078 
6079 
6080 #define CHECK_CONTEXT(ctxt)						\
6081     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6082         (ctxt->doc->children == NULL)) {				\
6083 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6084 	return(NULL);							\
6085     }
6086 
6087 
6088 /**
6089  * xmlXPathNewParserContext:
6090  * @str:  the XPath expression
6091  * @ctxt:  the XPath context
6092  *
6093  * Create a new xmlXPathParserContext
6094  *
6095  * Returns the xmlXPathParserContext just allocated.
6096  */
6097 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6098 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6099     xmlXPathParserContextPtr ret;
6100 
6101     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6102     if (ret == NULL) {
6103         xmlXPathErrMemory(ctxt, "creating parser context\n");
6104 	return(NULL);
6105     }
6106     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6107     ret->cur = ret->base = str;
6108     ret->context = ctxt;
6109 
6110     ret->comp = xmlXPathNewCompExpr();
6111     if (ret->comp == NULL) {
6112 	xmlFree(ret->valueTab);
6113 	xmlFree(ret);
6114 	return(NULL);
6115     }
6116     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6117         ret->comp->dict = ctxt->dict;
6118 	xmlDictReference(ret->comp->dict);
6119     }
6120 
6121     return(ret);
6122 }
6123 
6124 /**
6125  * xmlXPathCompParserContext:
6126  * @comp:  the XPath compiled expression
6127  * @ctxt:  the XPath context
6128  *
6129  * Create a new xmlXPathParserContext when processing a compiled expression
6130  *
6131  * Returns the xmlXPathParserContext just allocated.
6132  */
6133 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6134 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6135     xmlXPathParserContextPtr ret;
6136 
6137     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6138     if (ret == NULL) {
6139         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6140 	return(NULL);
6141     }
6142     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6143 
6144     /* Allocate the value stack */
6145     ret->valueTab = (xmlXPathObjectPtr *)
6146                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6147     if (ret->valueTab == NULL) {
6148 	xmlFree(ret);
6149 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6150 	return(NULL);
6151     }
6152     ret->valueNr = 0;
6153     ret->valueMax = 10;
6154     ret->value = NULL;
6155 
6156     ret->context = ctxt;
6157     ret->comp = comp;
6158 
6159     return(ret);
6160 }
6161 
6162 /**
6163  * xmlXPathFreeParserContext:
6164  * @ctxt:  the context to free
6165  *
6166  * Free up an xmlXPathParserContext
6167  */
6168 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6169 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6170     if (ctxt->valueTab != NULL) {
6171         xmlFree(ctxt->valueTab);
6172     }
6173     if (ctxt->comp != NULL) {
6174 #ifdef XPATH_STREAMING
6175 	if (ctxt->comp->stream != NULL) {
6176 	    xmlFreePatternList(ctxt->comp->stream);
6177 	    ctxt->comp->stream = NULL;
6178 	}
6179 #endif
6180 	xmlXPathFreeCompExpr(ctxt->comp);
6181     }
6182     xmlFree(ctxt);
6183 }
6184 
6185 /************************************************************************
6186  *									*
6187  *		The implicit core function library			*
6188  *									*
6189  ************************************************************************/
6190 
6191 /**
6192  * xmlXPathNodeValHash:
6193  * @node:  a node pointer
6194  *
6195  * Function computing the beginning of the string value of the node,
6196  * used to speed up comparisons
6197  *
6198  * Returns an int usable as a hash
6199  */
6200 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6201 xmlXPathNodeValHash(xmlNodePtr node) {
6202     int len = 2;
6203     const xmlChar * string = NULL;
6204     xmlNodePtr tmp = NULL;
6205     unsigned int ret = 0;
6206 
6207     if (node == NULL)
6208 	return(0);
6209 
6210     if (node->type == XML_DOCUMENT_NODE) {
6211 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6212 	if (tmp == NULL)
6213 	    node = node->children;
6214 	else
6215 	    node = tmp;
6216 
6217 	if (node == NULL)
6218 	    return(0);
6219     }
6220 
6221     switch (node->type) {
6222 	case XML_COMMENT_NODE:
6223 	case XML_PI_NODE:
6224 	case XML_CDATA_SECTION_NODE:
6225 	case XML_TEXT_NODE:
6226 	    string = node->content;
6227 	    if (string == NULL)
6228 		return(0);
6229 	    if (string[0] == 0)
6230 		return(0);
6231 	    return(((unsigned int) string[0]) +
6232 		   (((unsigned int) string[1]) << 8));
6233 	case XML_NAMESPACE_DECL:
6234 	    string = ((xmlNsPtr)node)->href;
6235 	    if (string == NULL)
6236 		return(0);
6237 	    if (string[0] == 0)
6238 		return(0);
6239 	    return(((unsigned int) string[0]) +
6240 		   (((unsigned int) string[1]) << 8));
6241 	case XML_ATTRIBUTE_NODE:
6242 	    tmp = ((xmlAttrPtr) node)->children;
6243 	    break;
6244 	case XML_ELEMENT_NODE:
6245 	    tmp = node->children;
6246 	    break;
6247 	default:
6248 	    return(0);
6249     }
6250     while (tmp != NULL) {
6251 	switch (tmp->type) {
6252 	    case XML_COMMENT_NODE:
6253 	    case XML_PI_NODE:
6254 	    case XML_CDATA_SECTION_NODE:
6255 	    case XML_TEXT_NODE:
6256 		string = tmp->content;
6257 		break;
6258 	    case XML_NAMESPACE_DECL:
6259 		string = ((xmlNsPtr)tmp)->href;
6260 		break;
6261 	    default:
6262 		break;
6263 	}
6264 	if ((string != NULL) && (string[0] != 0)) {
6265 	    if (len == 1) {
6266 		return(ret + (((unsigned int) string[0]) << 8));
6267 	    }
6268 	    if (string[1] == 0) {
6269 		len = 1;
6270 		ret = (unsigned int) string[0];
6271 	    } else {
6272 		return(((unsigned int) string[0]) +
6273 		       (((unsigned int) string[1]) << 8));
6274 	    }
6275 	}
6276 	/*
6277 	 * Skip to next node
6278 	 */
6279 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6280 	    if (tmp->children->type != XML_ENTITY_DECL) {
6281 		tmp = tmp->children;
6282 		continue;
6283 	    }
6284 	}
6285 	if (tmp == node)
6286 	    break;
6287 
6288 	if (tmp->next != NULL) {
6289 	    tmp = tmp->next;
6290 	    continue;
6291 	}
6292 
6293 	do {
6294 	    tmp = tmp->parent;
6295 	    if (tmp == NULL)
6296 		break;
6297 	    if (tmp == node) {
6298 		tmp = NULL;
6299 		break;
6300 	    }
6301 	    if (tmp->next != NULL) {
6302 		tmp = tmp->next;
6303 		break;
6304 	    }
6305 	} while (tmp != NULL);
6306     }
6307     return(ret);
6308 }
6309 
6310 /**
6311  * xmlXPathStringHash:
6312  * @string:  a string
6313  *
6314  * Function computing the beginning of the string value of the node,
6315  * used to speed up comparisons
6316  *
6317  * Returns an int usable as a hash
6318  */
6319 static unsigned int
xmlXPathStringHash(const xmlChar * string)6320 xmlXPathStringHash(const xmlChar * string) {
6321     if (string == NULL)
6322 	return((unsigned int) 0);
6323     if (string[0] == 0)
6324 	return(0);
6325     return(((unsigned int) string[0]) +
6326 	   (((unsigned int) string[1]) << 8));
6327 }
6328 
6329 /**
6330  * xmlXPathCompareNodeSetFloat:
6331  * @ctxt:  the XPath Parser context
6332  * @inf:  less than (1) or greater than (0)
6333  * @strict:  is the comparison strict
6334  * @arg:  the node set
6335  * @f:  the value
6336  *
6337  * Implement the compare operation between a nodeset and a number
6338  *     @ns < @val    (1, 1, ...
6339  *     @ns <= @val   (1, 0, ...
6340  *     @ns > @val    (0, 1, ...
6341  *     @ns >= @val   (0, 0, ...
6342  *
6343  * If one object to be compared is a node-set and the other is a number,
6344  * then the comparison will be true if and only if there is a node in the
6345  * node-set such that the result of performing the comparison on the number
6346  * to be compared and on the result of converting the string-value of that
6347  * node to a number using the number function is true.
6348  *
6349  * Returns 0 or 1 depending on the results of the test.
6350  */
6351 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6352 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6353 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6354     int i, ret = 0;
6355     xmlNodeSetPtr ns;
6356     xmlChar *str2;
6357 
6358     if ((f == NULL) || (arg == NULL) ||
6359 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6360 	xmlXPathReleaseObject(ctxt->context, arg);
6361 	xmlXPathReleaseObject(ctxt->context, f);
6362         return(0);
6363     }
6364     ns = arg->nodesetval;
6365     if (ns != NULL) {
6366 	for (i = 0;i < ns->nodeNr;i++) {
6367 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6368 	     if (str2 != NULL) {
6369 		 valuePush(ctxt,
6370 			   xmlXPathCacheNewString(ctxt->context, str2));
6371 		 xmlFree(str2);
6372 		 xmlXPathNumberFunction(ctxt, 1);
6373 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6374 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6375 		 if (ret)
6376 		     break;
6377 	     }
6378 	}
6379     }
6380     xmlXPathReleaseObject(ctxt->context, arg);
6381     xmlXPathReleaseObject(ctxt->context, f);
6382     return(ret);
6383 }
6384 
6385 /**
6386  * xmlXPathCompareNodeSetString:
6387  * @ctxt:  the XPath Parser context
6388  * @inf:  less than (1) or greater than (0)
6389  * @strict:  is the comparison strict
6390  * @arg:  the node set
6391  * @s:  the value
6392  *
6393  * Implement the compare operation between a nodeset and a string
6394  *     @ns < @val    (1, 1, ...
6395  *     @ns <= @val   (1, 0, ...
6396  *     @ns > @val    (0, 1, ...
6397  *     @ns >= @val   (0, 0, ...
6398  *
6399  * If one object to be compared is a node-set and the other is a string,
6400  * then the comparison will be true if and only if there is a node in
6401  * the node-set such that the result of performing the comparison on the
6402  * string-value of the node and the other string is true.
6403  *
6404  * Returns 0 or 1 depending on the results of the test.
6405  */
6406 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6407 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6408 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6409     int i, ret = 0;
6410     xmlNodeSetPtr ns;
6411     xmlChar *str2;
6412 
6413     if ((s == NULL) || (arg == NULL) ||
6414 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6415 	xmlXPathReleaseObject(ctxt->context, arg);
6416 	xmlXPathReleaseObject(ctxt->context, s);
6417         return(0);
6418     }
6419     ns = arg->nodesetval;
6420     if (ns != NULL) {
6421 	for (i = 0;i < ns->nodeNr;i++) {
6422 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6423 	     if (str2 != NULL) {
6424 		 valuePush(ctxt,
6425 			   xmlXPathCacheNewString(ctxt->context, str2));
6426 		 xmlFree(str2);
6427 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6428 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6429 		 if (ret)
6430 		     break;
6431 	     }
6432 	}
6433     }
6434     xmlXPathReleaseObject(ctxt->context, arg);
6435     xmlXPathReleaseObject(ctxt->context, s);
6436     return(ret);
6437 }
6438 
6439 /**
6440  * xmlXPathCompareNodeSets:
6441  * @inf:  less than (1) or greater than (0)
6442  * @strict:  is the comparison strict
6443  * @arg1:  the first node set object
6444  * @arg2:  the second node set object
6445  *
6446  * Implement the compare operation on nodesets:
6447  *
6448  * If both objects to be compared are node-sets, then the comparison
6449  * will be true if and only if there is a node in the first node-set
6450  * and a node in the second node-set such that the result of performing
6451  * the comparison on the string-values of the two nodes is true.
6452  * ....
6453  * When neither object to be compared is a node-set and the operator
6454  * is <=, <, >= or >, then the objects are compared by converting both
6455  * objects to numbers and comparing the numbers according to IEEE 754.
6456  * ....
6457  * The number function converts its argument to a number as follows:
6458  *  - a string that consists of optional whitespace followed by an
6459  *    optional minus sign followed by a Number followed by whitespace
6460  *    is converted to the IEEE 754 number that is nearest (according
6461  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6462  *    represented by the string; any other string is converted to NaN
6463  *
6464  * Conclusion all nodes need to be converted first to their string value
6465  * and then the comparison must be done when possible
6466  */
6467 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6468 xmlXPathCompareNodeSets(int inf, int strict,
6469 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6470     int i, j, init = 0;
6471     double val1;
6472     double *values2;
6473     int ret = 0;
6474     xmlNodeSetPtr ns1;
6475     xmlNodeSetPtr ns2;
6476 
6477     if ((arg1 == NULL) ||
6478 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6479 	xmlXPathFreeObject(arg2);
6480         return(0);
6481     }
6482     if ((arg2 == NULL) ||
6483 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6484 	xmlXPathFreeObject(arg1);
6485 	xmlXPathFreeObject(arg2);
6486         return(0);
6487     }
6488 
6489     ns1 = arg1->nodesetval;
6490     ns2 = arg2->nodesetval;
6491 
6492     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6493 	xmlXPathFreeObject(arg1);
6494 	xmlXPathFreeObject(arg2);
6495 	return(0);
6496     }
6497     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6498 	xmlXPathFreeObject(arg1);
6499 	xmlXPathFreeObject(arg2);
6500 	return(0);
6501     }
6502 
6503     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6504     if (values2 == NULL) {
6505         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6506 	xmlXPathFreeObject(arg1);
6507 	xmlXPathFreeObject(arg2);
6508 	return(0);
6509     }
6510     for (i = 0;i < ns1->nodeNr;i++) {
6511 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6512 	if (xmlXPathIsNaN(val1))
6513 	    continue;
6514 	for (j = 0;j < ns2->nodeNr;j++) {
6515 	    if (init == 0) {
6516 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6517 	    }
6518 	    if (xmlXPathIsNaN(values2[j]))
6519 		continue;
6520 	    if (inf && strict)
6521 		ret = (val1 < values2[j]);
6522 	    else if (inf && !strict)
6523 		ret = (val1 <= values2[j]);
6524 	    else if (!inf && strict)
6525 		ret = (val1 > values2[j]);
6526 	    else if (!inf && !strict)
6527 		ret = (val1 >= values2[j]);
6528 	    if (ret)
6529 		break;
6530 	}
6531 	if (ret)
6532 	    break;
6533 	init = 1;
6534     }
6535     xmlFree(values2);
6536     xmlXPathFreeObject(arg1);
6537     xmlXPathFreeObject(arg2);
6538     return(ret);
6539 }
6540 
6541 /**
6542  * xmlXPathCompareNodeSetValue:
6543  * @ctxt:  the XPath Parser context
6544  * @inf:  less than (1) or greater than (0)
6545  * @strict:  is the comparison strict
6546  * @arg:  the node set
6547  * @val:  the value
6548  *
6549  * Implement the compare operation between a nodeset and a value
6550  *     @ns < @val    (1, 1, ...
6551  *     @ns <= @val   (1, 0, ...
6552  *     @ns > @val    (0, 1, ...
6553  *     @ns >= @val   (0, 0, ...
6554  *
6555  * If one object to be compared is a node-set and the other is a boolean,
6556  * then the comparison will be true if and only if the result of performing
6557  * the comparison on the boolean and on the result of converting
6558  * the node-set to a boolean using the boolean function is true.
6559  *
6560  * Returns 0 or 1 depending on the results of the test.
6561  */
6562 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6563 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6564 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6565     if ((val == NULL) || (arg == NULL) ||
6566 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6567         return(0);
6568 
6569     switch(val->type) {
6570         case XPATH_NUMBER:
6571 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6572         case XPATH_NODESET:
6573         case XPATH_XSLT_TREE:
6574 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6575         case XPATH_STRING:
6576 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6577         case XPATH_BOOLEAN:
6578 	    valuePush(ctxt, arg);
6579 	    xmlXPathBooleanFunction(ctxt, 1);
6580 	    valuePush(ctxt, val);
6581 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6582 	default:
6583 	    TODO
6584     }
6585     return(0);
6586 }
6587 
6588 /**
6589  * xmlXPathEqualNodeSetString:
6590  * @arg:  the nodeset object argument
6591  * @str:  the string to compare to.
6592  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6593  *
6594  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6595  * If one object to be compared is a node-set and the other is a string,
6596  * then the comparison will be true if and only if there is a node in
6597  * the node-set such that the result of performing the comparison on the
6598  * string-value of the node and the other string is true.
6599  *
6600  * Returns 0 or 1 depending on the results of the test.
6601  */
6602 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6603 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6604 {
6605     int i;
6606     xmlNodeSetPtr ns;
6607     xmlChar *str2;
6608     unsigned int hash;
6609 
6610     if ((str == NULL) || (arg == NULL) ||
6611         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6612         return (0);
6613     ns = arg->nodesetval;
6614     /*
6615      * A NULL nodeset compared with a string is always false
6616      * (since there is no node equal, and no node not equal)
6617      */
6618     if ((ns == NULL) || (ns->nodeNr <= 0) )
6619         return (0);
6620     hash = xmlXPathStringHash(str);
6621     for (i = 0; i < ns->nodeNr; i++) {
6622         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6623             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6624             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6625                 xmlFree(str2);
6626 		if (neq)
6627 		    continue;
6628                 return (1);
6629 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6630 		if (neq)
6631 		    continue;
6632                 return (1);
6633             } else if (neq) {
6634 		if (str2 != NULL)
6635 		    xmlFree(str2);
6636 		return (1);
6637 	    }
6638             if (str2 != NULL)
6639                 xmlFree(str2);
6640         } else if (neq)
6641 	    return (1);
6642     }
6643     return (0);
6644 }
6645 
6646 /**
6647  * xmlXPathEqualNodeSetFloat:
6648  * @arg:  the nodeset object argument
6649  * @f:  the float to compare to
6650  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6651  *
6652  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6653  * If one object to be compared is a node-set and the other is a number,
6654  * then the comparison will be true if and only if there is a node in
6655  * the node-set such that the result of performing the comparison on the
6656  * number to be compared and on the result of converting the string-value
6657  * of that node to a number using the number function is true.
6658  *
6659  * Returns 0 or 1 depending on the results of the test.
6660  */
6661 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6662 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6663     xmlXPathObjectPtr arg, double f, int neq) {
6664   int i, ret=0;
6665   xmlNodeSetPtr ns;
6666   xmlChar *str2;
6667   xmlXPathObjectPtr val;
6668   double v;
6669 
6670     if ((arg == NULL) ||
6671 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6672         return(0);
6673 
6674     ns = arg->nodesetval;
6675     if (ns != NULL) {
6676 	for (i=0;i<ns->nodeNr;i++) {
6677 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6678 	    if (str2 != NULL) {
6679 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6680 		xmlFree(str2);
6681 		xmlXPathNumberFunction(ctxt, 1);
6682 		val = valuePop(ctxt);
6683 		v = val->floatval;
6684 		xmlXPathReleaseObject(ctxt->context, val);
6685 		if (!xmlXPathIsNaN(v)) {
6686 		    if ((!neq) && (v==f)) {
6687 			ret = 1;
6688 			break;
6689 		    } else if ((neq) && (v!=f)) {
6690 			ret = 1;
6691 			break;
6692 		    }
6693 		} else {	/* NaN is unequal to any value */
6694 		    if (neq)
6695 			ret = 1;
6696 		}
6697 	    }
6698 	}
6699     }
6700 
6701     return(ret);
6702 }
6703 
6704 
6705 /**
6706  * xmlXPathEqualNodeSets:
6707  * @arg1:  first nodeset object argument
6708  * @arg2:  second nodeset object argument
6709  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6710  *
6711  * Implement the equal / not equal operation on XPath nodesets:
6712  * @arg1 == @arg2  or  @arg1 != @arg2
6713  * If both objects to be compared are node-sets, then the comparison
6714  * will be true if and only if there is a node in the first node-set and
6715  * a node in the second node-set such that the result of performing the
6716  * comparison on the string-values of the two nodes is true.
6717  *
6718  * (needless to say, this is a costly operation)
6719  *
6720  * Returns 0 or 1 depending on the results of the test.
6721  */
6722 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6723 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6724     int i, j;
6725     unsigned int *hashs1;
6726     unsigned int *hashs2;
6727     xmlChar **values1;
6728     xmlChar **values2;
6729     int ret = 0;
6730     xmlNodeSetPtr ns1;
6731     xmlNodeSetPtr ns2;
6732 
6733     if ((arg1 == NULL) ||
6734 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6735         return(0);
6736     if ((arg2 == NULL) ||
6737 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6738         return(0);
6739 
6740     ns1 = arg1->nodesetval;
6741     ns2 = arg2->nodesetval;
6742 
6743     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6744 	return(0);
6745     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6746 	return(0);
6747 
6748     /*
6749      * for equal, check if there is a node pertaining to both sets
6750      */
6751     if (neq == 0)
6752 	for (i = 0;i < ns1->nodeNr;i++)
6753 	    for (j = 0;j < ns2->nodeNr;j++)
6754 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6755 		    return(1);
6756 
6757     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6758     if (values1 == NULL) {
6759         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6760 	return(0);
6761     }
6762     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6763     if (hashs1 == NULL) {
6764         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6765 	xmlFree(values1);
6766 	return(0);
6767     }
6768     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6769     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6770     if (values2 == NULL) {
6771         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6772 	xmlFree(hashs1);
6773 	xmlFree(values1);
6774 	return(0);
6775     }
6776     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6777     if (hashs2 == NULL) {
6778         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6779 	xmlFree(hashs1);
6780 	xmlFree(values1);
6781 	xmlFree(values2);
6782 	return(0);
6783     }
6784     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6785     for (i = 0;i < ns1->nodeNr;i++) {
6786 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6787 	for (j = 0;j < ns2->nodeNr;j++) {
6788 	    if (i == 0)
6789 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6790 	    if (hashs1[i] != hashs2[j]) {
6791 		if (neq) {
6792 		    ret = 1;
6793 		    break;
6794 		}
6795 	    }
6796 	    else {
6797 		if (values1[i] == NULL)
6798 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6799 		if (values2[j] == NULL)
6800 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6801 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6802 		if (ret)
6803 		    break;
6804 	    }
6805 	}
6806 	if (ret)
6807 	    break;
6808     }
6809     for (i = 0;i < ns1->nodeNr;i++)
6810 	if (values1[i] != NULL)
6811 	    xmlFree(values1[i]);
6812     for (j = 0;j < ns2->nodeNr;j++)
6813 	if (values2[j] != NULL)
6814 	    xmlFree(values2[j]);
6815     xmlFree(values1);
6816     xmlFree(values2);
6817     xmlFree(hashs1);
6818     xmlFree(hashs2);
6819     return(ret);
6820 }
6821 
6822 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6823 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6824   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6825     int ret = 0;
6826     /*
6827      *At this point we are assured neither arg1 nor arg2
6828      *is a nodeset, so we can just pick the appropriate routine.
6829      */
6830     switch (arg1->type) {
6831         case XPATH_UNDEFINED:
6832 #ifdef DEBUG_EXPR
6833 	    xmlGenericError(xmlGenericErrorContext,
6834 		    "Equal: undefined\n");
6835 #endif
6836 	    break;
6837         case XPATH_BOOLEAN:
6838 	    switch (arg2->type) {
6839 	        case XPATH_UNDEFINED:
6840 #ifdef DEBUG_EXPR
6841 		    xmlGenericError(xmlGenericErrorContext,
6842 			    "Equal: undefined\n");
6843 #endif
6844 		    break;
6845 		case XPATH_BOOLEAN:
6846 #ifdef DEBUG_EXPR
6847 		    xmlGenericError(xmlGenericErrorContext,
6848 			    "Equal: %d boolean %d \n",
6849 			    arg1->boolval, arg2->boolval);
6850 #endif
6851 		    ret = (arg1->boolval == arg2->boolval);
6852 		    break;
6853 		case XPATH_NUMBER:
6854 		    ret = (arg1->boolval ==
6855 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6856 		    break;
6857 		case XPATH_STRING:
6858 		    if ((arg2->stringval == NULL) ||
6859 			(arg2->stringval[0] == 0)) ret = 0;
6860 		    else
6861 			ret = 1;
6862 		    ret = (arg1->boolval == ret);
6863 		    break;
6864 		case XPATH_USERS:
6865 		case XPATH_POINT:
6866 		case XPATH_RANGE:
6867 		case XPATH_LOCATIONSET:
6868 		    TODO
6869 		    break;
6870 		case XPATH_NODESET:
6871 		case XPATH_XSLT_TREE:
6872 		    break;
6873 	    }
6874 	    break;
6875         case XPATH_NUMBER:
6876 	    switch (arg2->type) {
6877 	        case XPATH_UNDEFINED:
6878 #ifdef DEBUG_EXPR
6879 		    xmlGenericError(xmlGenericErrorContext,
6880 			    "Equal: undefined\n");
6881 #endif
6882 		    break;
6883 		case XPATH_BOOLEAN:
6884 		    ret = (arg2->boolval==
6885 			   xmlXPathCastNumberToBoolean(arg1->floatval));
6886 		    break;
6887 		case XPATH_STRING:
6888 		    valuePush(ctxt, arg2);
6889 		    xmlXPathNumberFunction(ctxt, 1);
6890 		    arg2 = valuePop(ctxt);
6891 		    /* no break on purpose */
6892 		case XPATH_NUMBER:
6893 		    /* Hand check NaN and Infinity equalities */
6894 		    if (xmlXPathIsNaN(arg1->floatval) ||
6895 			    xmlXPathIsNaN(arg2->floatval)) {
6896 		        ret = 0;
6897 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6898 		        if (xmlXPathIsInf(arg2->floatval) == 1)
6899 			    ret = 1;
6900 			else
6901 			    ret = 0;
6902 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6903 			if (xmlXPathIsInf(arg2->floatval) == -1)
6904 			    ret = 1;
6905 			else
6906 			    ret = 0;
6907 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6908 			if (xmlXPathIsInf(arg1->floatval) == 1)
6909 			    ret = 1;
6910 			else
6911 			    ret = 0;
6912 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6913 			if (xmlXPathIsInf(arg1->floatval) == -1)
6914 			    ret = 1;
6915 			else
6916 			    ret = 0;
6917 		    } else {
6918 		        ret = (arg1->floatval == arg2->floatval);
6919 		    }
6920 		    break;
6921 		case XPATH_USERS:
6922 		case XPATH_POINT:
6923 		case XPATH_RANGE:
6924 		case XPATH_LOCATIONSET:
6925 		    TODO
6926 		    break;
6927 		case XPATH_NODESET:
6928 		case XPATH_XSLT_TREE:
6929 		    break;
6930 	    }
6931 	    break;
6932         case XPATH_STRING:
6933 	    switch (arg2->type) {
6934 	        case XPATH_UNDEFINED:
6935 #ifdef DEBUG_EXPR
6936 		    xmlGenericError(xmlGenericErrorContext,
6937 			    "Equal: undefined\n");
6938 #endif
6939 		    break;
6940 		case XPATH_BOOLEAN:
6941 		    if ((arg1->stringval == NULL) ||
6942 			(arg1->stringval[0] == 0)) ret = 0;
6943 		    else
6944 			ret = 1;
6945 		    ret = (arg2->boolval == ret);
6946 		    break;
6947 		case XPATH_STRING:
6948 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6949 		    break;
6950 		case XPATH_NUMBER:
6951 		    valuePush(ctxt, arg1);
6952 		    xmlXPathNumberFunction(ctxt, 1);
6953 		    arg1 = valuePop(ctxt);
6954 		    /* Hand check NaN and Infinity equalities */
6955 		    if (xmlXPathIsNaN(arg1->floatval) ||
6956 			    xmlXPathIsNaN(arg2->floatval)) {
6957 		        ret = 0;
6958 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6959 			if (xmlXPathIsInf(arg2->floatval) == 1)
6960 			    ret = 1;
6961 			else
6962 			    ret = 0;
6963 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6964 			if (xmlXPathIsInf(arg2->floatval) == -1)
6965 			    ret = 1;
6966 			else
6967 			    ret = 0;
6968 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6969 			if (xmlXPathIsInf(arg1->floatval) == 1)
6970 			    ret = 1;
6971 			else
6972 			    ret = 0;
6973 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6974 			if (xmlXPathIsInf(arg1->floatval) == -1)
6975 			    ret = 1;
6976 			else
6977 			    ret = 0;
6978 		    } else {
6979 		        ret = (arg1->floatval == arg2->floatval);
6980 		    }
6981 		    break;
6982 		case XPATH_USERS:
6983 		case XPATH_POINT:
6984 		case XPATH_RANGE:
6985 		case XPATH_LOCATIONSET:
6986 		    TODO
6987 		    break;
6988 		case XPATH_NODESET:
6989 		case XPATH_XSLT_TREE:
6990 		    break;
6991 	    }
6992 	    break;
6993         case XPATH_USERS:
6994 	case XPATH_POINT:
6995 	case XPATH_RANGE:
6996 	case XPATH_LOCATIONSET:
6997 	    TODO
6998 	    break;
6999 	case XPATH_NODESET:
7000 	case XPATH_XSLT_TREE:
7001 	    break;
7002     }
7003     xmlXPathReleaseObject(ctxt->context, arg1);
7004     xmlXPathReleaseObject(ctxt->context, arg2);
7005     return(ret);
7006 }
7007 
7008 /**
7009  * xmlXPathEqualValues:
7010  * @ctxt:  the XPath Parser context
7011  *
7012  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7013  *
7014  * Returns 0 or 1 depending on the results of the test.
7015  */
7016 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7017 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7018     xmlXPathObjectPtr arg1, arg2, argtmp;
7019     int ret = 0;
7020 
7021     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7022     arg2 = valuePop(ctxt);
7023     arg1 = valuePop(ctxt);
7024     if ((arg1 == NULL) || (arg2 == NULL)) {
7025 	if (arg1 != NULL)
7026 	    xmlXPathReleaseObject(ctxt->context, arg1);
7027 	else
7028 	    xmlXPathReleaseObject(ctxt->context, arg2);
7029 	XP_ERROR0(XPATH_INVALID_OPERAND);
7030     }
7031 
7032     if (arg1 == arg2) {
7033 #ifdef DEBUG_EXPR
7034         xmlGenericError(xmlGenericErrorContext,
7035 		"Equal: by pointer\n");
7036 #endif
7037 	xmlXPathFreeObject(arg1);
7038         return(1);
7039     }
7040 
7041     /*
7042      *If either argument is a nodeset, it's a 'special case'
7043      */
7044     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7045       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7046 	/*
7047 	 *Hack it to assure arg1 is the nodeset
7048 	 */
7049 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7050 		argtmp = arg2;
7051 		arg2 = arg1;
7052 		arg1 = argtmp;
7053 	}
7054 	switch (arg2->type) {
7055 	    case XPATH_UNDEFINED:
7056 #ifdef DEBUG_EXPR
7057 		xmlGenericError(xmlGenericErrorContext,
7058 			"Equal: undefined\n");
7059 #endif
7060 		break;
7061 	    case XPATH_NODESET:
7062 	    case XPATH_XSLT_TREE:
7063 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7064 		break;
7065 	    case XPATH_BOOLEAN:
7066 		if ((arg1->nodesetval == NULL) ||
7067 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7068 		else
7069 		    ret = 1;
7070 		ret = (ret == arg2->boolval);
7071 		break;
7072 	    case XPATH_NUMBER:
7073 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7074 		break;
7075 	    case XPATH_STRING:
7076 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7077 		break;
7078 	    case XPATH_USERS:
7079 	    case XPATH_POINT:
7080 	    case XPATH_RANGE:
7081 	    case XPATH_LOCATIONSET:
7082 		TODO
7083 		break;
7084 	}
7085 	xmlXPathReleaseObject(ctxt->context, arg1);
7086 	xmlXPathReleaseObject(ctxt->context, arg2);
7087 	return(ret);
7088     }
7089 
7090     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7091 }
7092 
7093 /**
7094  * xmlXPathNotEqualValues:
7095  * @ctxt:  the XPath Parser context
7096  *
7097  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7098  *
7099  * Returns 0 or 1 depending on the results of the test.
7100  */
7101 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7102 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7103     xmlXPathObjectPtr arg1, arg2, argtmp;
7104     int ret = 0;
7105 
7106     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7107     arg2 = valuePop(ctxt);
7108     arg1 = valuePop(ctxt);
7109     if ((arg1 == NULL) || (arg2 == NULL)) {
7110 	if (arg1 != NULL)
7111 	    xmlXPathReleaseObject(ctxt->context, arg1);
7112 	else
7113 	    xmlXPathReleaseObject(ctxt->context, arg2);
7114 	XP_ERROR0(XPATH_INVALID_OPERAND);
7115     }
7116 
7117     if (arg1 == arg2) {
7118 #ifdef DEBUG_EXPR
7119         xmlGenericError(xmlGenericErrorContext,
7120 		"NotEqual: by pointer\n");
7121 #endif
7122 	xmlXPathReleaseObject(ctxt->context, arg1);
7123         return(0);
7124     }
7125 
7126     /*
7127      *If either argument is a nodeset, it's a 'special case'
7128      */
7129     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7130       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7131 	/*
7132 	 *Hack it to assure arg1 is the nodeset
7133 	 */
7134 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7135 		argtmp = arg2;
7136 		arg2 = arg1;
7137 		arg1 = argtmp;
7138 	}
7139 	switch (arg2->type) {
7140 	    case XPATH_UNDEFINED:
7141 #ifdef DEBUG_EXPR
7142 		xmlGenericError(xmlGenericErrorContext,
7143 			"NotEqual: undefined\n");
7144 #endif
7145 		break;
7146 	    case XPATH_NODESET:
7147 	    case XPATH_XSLT_TREE:
7148 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7149 		break;
7150 	    case XPATH_BOOLEAN:
7151 		if ((arg1->nodesetval == NULL) ||
7152 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7153 		else
7154 		    ret = 1;
7155 		ret = (ret != arg2->boolval);
7156 		break;
7157 	    case XPATH_NUMBER:
7158 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7159 		break;
7160 	    case XPATH_STRING:
7161 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7162 		break;
7163 	    case XPATH_USERS:
7164 	    case XPATH_POINT:
7165 	    case XPATH_RANGE:
7166 	    case XPATH_LOCATIONSET:
7167 		TODO
7168 		break;
7169 	}
7170 	xmlXPathReleaseObject(ctxt->context, arg1);
7171 	xmlXPathReleaseObject(ctxt->context, arg2);
7172 	return(ret);
7173     }
7174 
7175     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7176 }
7177 
7178 /**
7179  * xmlXPathCompareValues:
7180  * @ctxt:  the XPath Parser context
7181  * @inf:  less than (1) or greater than (0)
7182  * @strict:  is the comparison strict
7183  *
7184  * Implement the compare operation on XPath objects:
7185  *     @arg1 < @arg2    (1, 1, ...
7186  *     @arg1 <= @arg2   (1, 0, ...
7187  *     @arg1 > @arg2    (0, 1, ...
7188  *     @arg1 >= @arg2   (0, 0, ...
7189  *
7190  * When neither object to be compared is a node-set and the operator is
7191  * <=, <, >=, >, then the objects are compared by converted both objects
7192  * to numbers and comparing the numbers according to IEEE 754. The <
7193  * comparison will be true if and only if the first number is less than the
7194  * second number. The <= comparison will be true if and only if the first
7195  * number is less than or equal to the second number. The > comparison
7196  * will be true if and only if the first number is greater than the second
7197  * number. The >= comparison will be true if and only if the first number
7198  * is greater than or equal to the second number.
7199  *
7200  * Returns 1 if the comparison succeeded, 0 if it failed
7201  */
7202 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7203 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7204     int ret = 0, arg1i = 0, arg2i = 0;
7205     xmlXPathObjectPtr arg1, arg2;
7206 
7207     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7208     arg2 = valuePop(ctxt);
7209     arg1 = valuePop(ctxt);
7210     if ((arg1 == NULL) || (arg2 == NULL)) {
7211 	if (arg1 != NULL)
7212 	    xmlXPathReleaseObject(ctxt->context, arg1);
7213 	else
7214 	    xmlXPathReleaseObject(ctxt->context, arg2);
7215 	XP_ERROR0(XPATH_INVALID_OPERAND);
7216     }
7217 
7218     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7219       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7220 	/*
7221 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7222 	 * are not freed from within this routine; they will be freed from the
7223 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7224 	 */
7225 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7226 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7227 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7228 	} else {
7229 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7230 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7231 			                          arg1, arg2);
7232 	    } else {
7233 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7234 			                          arg2, arg1);
7235 	    }
7236 	}
7237 	return(ret);
7238     }
7239 
7240     if (arg1->type != XPATH_NUMBER) {
7241 	valuePush(ctxt, arg1);
7242 	xmlXPathNumberFunction(ctxt, 1);
7243 	arg1 = valuePop(ctxt);
7244     }
7245     if (arg1->type != XPATH_NUMBER) {
7246 	xmlXPathFreeObject(arg1);
7247 	xmlXPathFreeObject(arg2);
7248 	XP_ERROR0(XPATH_INVALID_OPERAND);
7249     }
7250     if (arg2->type != XPATH_NUMBER) {
7251 	valuePush(ctxt, arg2);
7252 	xmlXPathNumberFunction(ctxt, 1);
7253 	arg2 = valuePop(ctxt);
7254     }
7255     if (arg2->type != XPATH_NUMBER) {
7256 	xmlXPathReleaseObject(ctxt->context, arg1);
7257 	xmlXPathReleaseObject(ctxt->context, arg2);
7258 	XP_ERROR0(XPATH_INVALID_OPERAND);
7259     }
7260     /*
7261      * Add tests for infinity and nan
7262      * => feedback on 3.4 for Inf and NaN
7263      */
7264     /* Hand check NaN and Infinity comparisons */
7265     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7266 	ret=0;
7267     } else {
7268 	arg1i=xmlXPathIsInf(arg1->floatval);
7269 	arg2i=xmlXPathIsInf(arg2->floatval);
7270 	if (inf && strict) {
7271 	    if ((arg1i == -1 && arg2i != -1) ||
7272 		(arg2i == 1 && arg1i != 1)) {
7273 		ret = 1;
7274 	    } else if (arg1i == 0 && arg2i == 0) {
7275 		ret = (arg1->floatval < arg2->floatval);
7276 	    } else {
7277 		ret = 0;
7278 	    }
7279 	}
7280 	else if (inf && !strict) {
7281 	    if (arg1i == -1 || arg2i == 1) {
7282 		ret = 1;
7283 	    } else if (arg1i == 0 && arg2i == 0) {
7284 		ret = (arg1->floatval <= arg2->floatval);
7285 	    } else {
7286 		ret = 0;
7287 	    }
7288 	}
7289 	else if (!inf && strict) {
7290 	    if ((arg1i == 1 && arg2i != 1) ||
7291 		(arg2i == -1 && arg1i != -1)) {
7292 		ret = 1;
7293 	    } else if (arg1i == 0 && arg2i == 0) {
7294 		ret = (arg1->floatval > arg2->floatval);
7295 	    } else {
7296 		ret = 0;
7297 	    }
7298 	}
7299 	else if (!inf && !strict) {
7300 	    if (arg1i == 1 || arg2i == -1) {
7301 		ret = 1;
7302 	    } else if (arg1i == 0 && arg2i == 0) {
7303 		ret = (arg1->floatval >= arg2->floatval);
7304 	    } else {
7305 		ret = 0;
7306 	    }
7307 	}
7308     }
7309     xmlXPathReleaseObject(ctxt->context, arg1);
7310     xmlXPathReleaseObject(ctxt->context, arg2);
7311     return(ret);
7312 }
7313 
7314 /**
7315  * xmlXPathValueFlipSign:
7316  * @ctxt:  the XPath Parser context
7317  *
7318  * Implement the unary - operation on an XPath object
7319  * The numeric operators convert their operands to numbers as if
7320  * by calling the number function.
7321  */
7322 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7323 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7324     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7325     CAST_TO_NUMBER;
7326     CHECK_TYPE(XPATH_NUMBER);
7327     if (xmlXPathIsNaN(ctxt->value->floatval))
7328         ctxt->value->floatval=xmlXPathNAN;
7329     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7330         ctxt->value->floatval=xmlXPathNINF;
7331     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7332         ctxt->value->floatval=xmlXPathPINF;
7333     else if (ctxt->value->floatval == 0) {
7334         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7335 	    ctxt->value->floatval = xmlXPathNZERO;
7336 	else
7337 	    ctxt->value->floatval = 0;
7338     }
7339     else
7340         ctxt->value->floatval = - ctxt->value->floatval;
7341 }
7342 
7343 /**
7344  * xmlXPathAddValues:
7345  * @ctxt:  the XPath Parser context
7346  *
7347  * Implement the add operation on XPath objects:
7348  * The numeric operators convert their operands to numbers as if
7349  * by calling the number function.
7350  */
7351 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7352 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7353     xmlXPathObjectPtr arg;
7354     double val;
7355 
7356     arg = valuePop(ctxt);
7357     if (arg == NULL)
7358 	XP_ERROR(XPATH_INVALID_OPERAND);
7359     val = xmlXPathCastToNumber(arg);
7360     xmlXPathReleaseObject(ctxt->context, arg);
7361     CAST_TO_NUMBER;
7362     CHECK_TYPE(XPATH_NUMBER);
7363     ctxt->value->floatval += val;
7364 }
7365 
7366 /**
7367  * xmlXPathSubValues:
7368  * @ctxt:  the XPath Parser context
7369  *
7370  * Implement the subtraction operation on XPath objects:
7371  * The numeric operators convert their operands to numbers as if
7372  * by calling the number function.
7373  */
7374 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7375 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7376     xmlXPathObjectPtr arg;
7377     double val;
7378 
7379     arg = valuePop(ctxt);
7380     if (arg == NULL)
7381 	XP_ERROR(XPATH_INVALID_OPERAND);
7382     val = xmlXPathCastToNumber(arg);
7383     xmlXPathReleaseObject(ctxt->context, arg);
7384     CAST_TO_NUMBER;
7385     CHECK_TYPE(XPATH_NUMBER);
7386     ctxt->value->floatval -= val;
7387 }
7388 
7389 /**
7390  * xmlXPathMultValues:
7391  * @ctxt:  the XPath Parser context
7392  *
7393  * Implement the multiply operation on XPath objects:
7394  * The numeric operators convert their operands to numbers as if
7395  * by calling the number function.
7396  */
7397 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7398 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7399     xmlXPathObjectPtr arg;
7400     double val;
7401 
7402     arg = valuePop(ctxt);
7403     if (arg == NULL)
7404 	XP_ERROR(XPATH_INVALID_OPERAND);
7405     val = xmlXPathCastToNumber(arg);
7406     xmlXPathReleaseObject(ctxt->context, arg);
7407     CAST_TO_NUMBER;
7408     CHECK_TYPE(XPATH_NUMBER);
7409     ctxt->value->floatval *= val;
7410 }
7411 
7412 /**
7413  * xmlXPathDivValues:
7414  * @ctxt:  the XPath Parser context
7415  *
7416  * Implement the div operation on XPath objects @arg1 / @arg2:
7417  * The numeric operators convert their operands to numbers as if
7418  * by calling the number function.
7419  */
7420 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7421 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7422     xmlXPathObjectPtr arg;
7423     double val;
7424 
7425     arg = valuePop(ctxt);
7426     if (arg == NULL)
7427 	XP_ERROR(XPATH_INVALID_OPERAND);
7428     val = xmlXPathCastToNumber(arg);
7429     xmlXPathReleaseObject(ctxt->context, arg);
7430     CAST_TO_NUMBER;
7431     CHECK_TYPE(XPATH_NUMBER);
7432     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7433 	ctxt->value->floatval = xmlXPathNAN;
7434     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7435 	if (ctxt->value->floatval == 0)
7436 	    ctxt->value->floatval = xmlXPathNAN;
7437 	else if (ctxt->value->floatval > 0)
7438 	    ctxt->value->floatval = xmlXPathNINF;
7439 	else if (ctxt->value->floatval < 0)
7440 	    ctxt->value->floatval = xmlXPathPINF;
7441     }
7442     else if (val == 0) {
7443 	if (ctxt->value->floatval == 0)
7444 	    ctxt->value->floatval = xmlXPathNAN;
7445 	else if (ctxt->value->floatval > 0)
7446 	    ctxt->value->floatval = xmlXPathPINF;
7447 	else if (ctxt->value->floatval < 0)
7448 	    ctxt->value->floatval = xmlXPathNINF;
7449     } else
7450 	ctxt->value->floatval /= val;
7451 }
7452 
7453 /**
7454  * xmlXPathModValues:
7455  * @ctxt:  the XPath Parser context
7456  *
7457  * Implement the mod operation on XPath objects: @arg1 / @arg2
7458  * The numeric operators convert their operands to numbers as if
7459  * by calling the number function.
7460  */
7461 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7462 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7463     xmlXPathObjectPtr arg;
7464     double arg1, arg2;
7465 
7466     arg = valuePop(ctxt);
7467     if (arg == NULL)
7468 	XP_ERROR(XPATH_INVALID_OPERAND);
7469     arg2 = xmlXPathCastToNumber(arg);
7470     xmlXPathReleaseObject(ctxt->context, arg);
7471     CAST_TO_NUMBER;
7472     CHECK_TYPE(XPATH_NUMBER);
7473     arg1 = ctxt->value->floatval;
7474     if (arg2 == 0)
7475 	ctxt->value->floatval = xmlXPathNAN;
7476     else {
7477 	ctxt->value->floatval = fmod(arg1, arg2);
7478     }
7479 }
7480 
7481 /************************************************************************
7482  *									*
7483  *		The traversal functions					*
7484  *									*
7485  ************************************************************************/
7486 
7487 /*
7488  * A traversal function enumerates nodes along an axis.
7489  * Initially it must be called with NULL, and it indicates
7490  * termination on the axis by returning NULL.
7491  */
7492 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7493                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7494 
7495 /*
7496  * xmlXPathTraversalFunctionExt:
7497  * A traversal function enumerates nodes along an axis.
7498  * Initially it must be called with NULL, and it indicates
7499  * termination on the axis by returning NULL.
7500  * The context node of the traversal is specified via @contextNode.
7501  */
7502 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7503                     (xmlNodePtr cur, xmlNodePtr contextNode);
7504 
7505 /*
7506  * xmlXPathNodeSetMergeFunction:
7507  * Used for merging node sets in xmlXPathCollectAndTest().
7508  */
7509 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7510 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7511 
7512 
7513 /**
7514  * xmlXPathNextSelf:
7515  * @ctxt:  the XPath Parser context
7516  * @cur:  the current node in the traversal
7517  *
7518  * Traversal function for the "self" direction
7519  * The self axis contains just the context node itself
7520  *
7521  * Returns the next element following that axis
7522  */
7523 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7524 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7525     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7526     if (cur == NULL)
7527         return(ctxt->context->node);
7528     return(NULL);
7529 }
7530 
7531 /**
7532  * xmlXPathNextChild:
7533  * @ctxt:  the XPath Parser context
7534  * @cur:  the current node in the traversal
7535  *
7536  * Traversal function for the "child" direction
7537  * The child axis contains the children of the context node in document order.
7538  *
7539  * Returns the next element following that axis
7540  */
7541 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7542 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7543     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7544     if (cur == NULL) {
7545 	if (ctxt->context->node == NULL) return(NULL);
7546 	switch (ctxt->context->node->type) {
7547             case XML_ELEMENT_NODE:
7548             case XML_TEXT_NODE:
7549             case XML_CDATA_SECTION_NODE:
7550             case XML_ENTITY_REF_NODE:
7551             case XML_ENTITY_NODE:
7552             case XML_PI_NODE:
7553             case XML_COMMENT_NODE:
7554             case XML_NOTATION_NODE:
7555             case XML_DTD_NODE:
7556 		return(ctxt->context->node->children);
7557             case XML_DOCUMENT_NODE:
7558             case XML_DOCUMENT_TYPE_NODE:
7559             case XML_DOCUMENT_FRAG_NODE:
7560             case XML_HTML_DOCUMENT_NODE:
7561 #ifdef LIBXML_DOCB_ENABLED
7562 	    case XML_DOCB_DOCUMENT_NODE:
7563 #endif
7564 		return(((xmlDocPtr) ctxt->context->node)->children);
7565 	    case XML_ELEMENT_DECL:
7566 	    case XML_ATTRIBUTE_DECL:
7567 	    case XML_ENTITY_DECL:
7568             case XML_ATTRIBUTE_NODE:
7569 	    case XML_NAMESPACE_DECL:
7570 	    case XML_XINCLUDE_START:
7571 	    case XML_XINCLUDE_END:
7572 		return(NULL);
7573 	}
7574 	return(NULL);
7575     }
7576     if ((cur->type == XML_DOCUMENT_NODE) ||
7577         (cur->type == XML_HTML_DOCUMENT_NODE))
7578 	return(NULL);
7579     return(cur->next);
7580 }
7581 
7582 /**
7583  * xmlXPathNextChildElement:
7584  * @ctxt:  the XPath Parser context
7585  * @cur:  the current node in the traversal
7586  *
7587  * Traversal function for the "child" direction and nodes of type element.
7588  * The child axis contains the children of the context node in document order.
7589  *
7590  * Returns the next element following that axis
7591  */
7592 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7593 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7594     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7595     if (cur == NULL) {
7596 	cur = ctxt->context->node;
7597 	if (cur == NULL) return(NULL);
7598 	/*
7599 	* Get the first element child.
7600 	*/
7601 	switch (cur->type) {
7602             case XML_ELEMENT_NODE:
7603 	    case XML_DOCUMENT_FRAG_NODE:
7604 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7605             case XML_ENTITY_NODE:
7606 		cur = cur->children;
7607 		if (cur != NULL) {
7608 		    if (cur->type == XML_ELEMENT_NODE)
7609 			return(cur);
7610 		    do {
7611 			cur = cur->next;
7612 		    } while ((cur != NULL) &&
7613 			(cur->type != XML_ELEMENT_NODE));
7614 		    return(cur);
7615 		}
7616 		return(NULL);
7617             case XML_DOCUMENT_NODE:
7618             case XML_HTML_DOCUMENT_NODE:
7619 #ifdef LIBXML_DOCB_ENABLED
7620 	    case XML_DOCB_DOCUMENT_NODE:
7621 #endif
7622 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7623 	    default:
7624 		return(NULL);
7625 	}
7626 	return(NULL);
7627     }
7628     /*
7629     * Get the next sibling element node.
7630     */
7631     switch (cur->type) {
7632 	case XML_ELEMENT_NODE:
7633 	case XML_TEXT_NODE:
7634 	case XML_ENTITY_REF_NODE:
7635 	case XML_ENTITY_NODE:
7636 	case XML_CDATA_SECTION_NODE:
7637 	case XML_PI_NODE:
7638 	case XML_COMMENT_NODE:
7639 	case XML_XINCLUDE_END:
7640 	    break;
7641 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7642 	default:
7643 	    return(NULL);
7644     }
7645     if (cur->next != NULL) {
7646 	if (cur->next->type == XML_ELEMENT_NODE)
7647 	    return(cur->next);
7648 	cur = cur->next;
7649 	do {
7650 	    cur = cur->next;
7651 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7652 	return(cur);
7653     }
7654     return(NULL);
7655 }
7656 
7657 /**
7658  * xmlXPathNextDescendantOrSelfElemParent:
7659  * @ctxt:  the XPath Parser context
7660  * @cur:  the current node in the traversal
7661  *
7662  * Traversal function for the "descendant-or-self" axis.
7663  * Additionally it returns only nodes which can be parents of
7664  * element nodes.
7665  *
7666  *
7667  * Returns the next element following that axis
7668  */
7669 static xmlNodePtr
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,xmlNodePtr contextNode)7670 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7671 				       xmlNodePtr contextNode)
7672 {
7673     if (cur == NULL) {
7674 	if (contextNode == NULL)
7675 	    return(NULL);
7676 	switch (contextNode->type) {
7677 	    case XML_ELEMENT_NODE:
7678 	    case XML_XINCLUDE_START:
7679 	    case XML_DOCUMENT_FRAG_NODE:
7680 	    case XML_DOCUMENT_NODE:
7681 #ifdef LIBXML_DOCB_ENABLED
7682 	    case XML_DOCB_DOCUMENT_NODE:
7683 #endif
7684 	    case XML_HTML_DOCUMENT_NODE:
7685 		return(contextNode);
7686 	    default:
7687 		return(NULL);
7688 	}
7689 	return(NULL);
7690     } else {
7691 	xmlNodePtr start = cur;
7692 
7693 	while (cur != NULL) {
7694 	    switch (cur->type) {
7695 		case XML_ELEMENT_NODE:
7696 		/* TODO: OK to have XInclude here? */
7697 		case XML_XINCLUDE_START:
7698 		case XML_DOCUMENT_FRAG_NODE:
7699 		    if (cur != start)
7700 			return(cur);
7701 		    if (cur->children != NULL) {
7702 			cur = cur->children;
7703 			continue;
7704 		    }
7705 		    break;
7706 		/* Not sure if we need those here. */
7707 		case XML_DOCUMENT_NODE:
7708 #ifdef LIBXML_DOCB_ENABLED
7709 		case XML_DOCB_DOCUMENT_NODE:
7710 #endif
7711 		case XML_HTML_DOCUMENT_NODE:
7712 		    if (cur != start)
7713 			return(cur);
7714 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7715 		default:
7716 		    break;
7717 	    }
7718 
7719 next_sibling:
7720 	    if ((cur == NULL) || (cur == contextNode))
7721 		return(NULL);
7722 	    if (cur->next != NULL) {
7723 		cur = cur->next;
7724 	    } else {
7725 		cur = cur->parent;
7726 		goto next_sibling;
7727 	    }
7728 	}
7729     }
7730     return(NULL);
7731 }
7732 
7733 /**
7734  * xmlXPathNextDescendant:
7735  * @ctxt:  the XPath Parser context
7736  * @cur:  the current node in the traversal
7737  *
7738  * Traversal function for the "descendant" direction
7739  * the descendant axis contains the descendants of the context node in document
7740  * order; a descendant is a child or a child of a child and so on.
7741  *
7742  * Returns the next element following that axis
7743  */
7744 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7745 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7746     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7747     if (cur == NULL) {
7748 	if (ctxt->context->node == NULL)
7749 	    return(NULL);
7750 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7751 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7752 	    return(NULL);
7753 
7754         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7755 	    return(ctxt->context->doc->children);
7756         return(ctxt->context->node->children);
7757     }
7758 
7759     if (cur->children != NULL) {
7760 	/*
7761 	 * Do not descend on entities declarations
7762 	 */
7763 	if (cur->children->type != XML_ENTITY_DECL) {
7764 	    cur = cur->children;
7765 	    /*
7766 	     * Skip DTDs
7767 	     */
7768 	    if (cur->type != XML_DTD_NODE)
7769 		return(cur);
7770 	}
7771     }
7772 
7773     if (cur == ctxt->context->node) return(NULL);
7774 
7775     while (cur->next != NULL) {
7776 	cur = cur->next;
7777 	if ((cur->type != XML_ENTITY_DECL) &&
7778 	    (cur->type != XML_DTD_NODE))
7779 	    return(cur);
7780     }
7781 
7782     do {
7783         cur = cur->parent;
7784 	if (cur == NULL) break;
7785 	if (cur == ctxt->context->node) return(NULL);
7786 	if (cur->next != NULL) {
7787 	    cur = cur->next;
7788 	    return(cur);
7789 	}
7790     } while (cur != NULL);
7791     return(cur);
7792 }
7793 
7794 /**
7795  * xmlXPathNextDescendantOrSelf:
7796  * @ctxt:  the XPath Parser context
7797  * @cur:  the current node in the traversal
7798  *
7799  * Traversal function for the "descendant-or-self" direction
7800  * the descendant-or-self axis contains the context node and the descendants
7801  * of the context node in document order; thus the context node is the first
7802  * node on the axis, and the first child of the context node is the second node
7803  * on the axis
7804  *
7805  * Returns the next element following that axis
7806  */
7807 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7808 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7809     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7810     if (cur == NULL) {
7811 	if (ctxt->context->node == NULL)
7812 	    return(NULL);
7813 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7814 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7815 	    return(NULL);
7816         return(ctxt->context->node);
7817     }
7818 
7819     return(xmlXPathNextDescendant(ctxt, cur));
7820 }
7821 
7822 /**
7823  * xmlXPathNextParent:
7824  * @ctxt:  the XPath Parser context
7825  * @cur:  the current node in the traversal
7826  *
7827  * Traversal function for the "parent" direction
7828  * The parent axis contains the parent of the context node, if there is one.
7829  *
7830  * Returns the next element following that axis
7831  */
7832 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7833 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7834     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7835     /*
7836      * the parent of an attribute or namespace node is the element
7837      * to which the attribute or namespace node is attached
7838      * Namespace handling !!!
7839      */
7840     if (cur == NULL) {
7841 	if (ctxt->context->node == NULL) return(NULL);
7842 	switch (ctxt->context->node->type) {
7843             case XML_ELEMENT_NODE:
7844             case XML_TEXT_NODE:
7845             case XML_CDATA_SECTION_NODE:
7846             case XML_ENTITY_REF_NODE:
7847             case XML_ENTITY_NODE:
7848             case XML_PI_NODE:
7849             case XML_COMMENT_NODE:
7850             case XML_NOTATION_NODE:
7851             case XML_DTD_NODE:
7852 	    case XML_ELEMENT_DECL:
7853 	    case XML_ATTRIBUTE_DECL:
7854 	    case XML_XINCLUDE_START:
7855 	    case XML_XINCLUDE_END:
7856 	    case XML_ENTITY_DECL:
7857 		if (ctxt->context->node->parent == NULL)
7858 		    return((xmlNodePtr) ctxt->context->doc);
7859 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7860 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7861 		     (xmlStrEqual(ctxt->context->node->parent->name,
7862 				 BAD_CAST "fake node libxslt"))))
7863 		    return(NULL);
7864 		return(ctxt->context->node->parent);
7865             case XML_ATTRIBUTE_NODE: {
7866 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7867 
7868 		return(att->parent);
7869 	    }
7870             case XML_DOCUMENT_NODE:
7871             case XML_DOCUMENT_TYPE_NODE:
7872             case XML_DOCUMENT_FRAG_NODE:
7873             case XML_HTML_DOCUMENT_NODE:
7874 #ifdef LIBXML_DOCB_ENABLED
7875 	    case XML_DOCB_DOCUMENT_NODE:
7876 #endif
7877                 return(NULL);
7878 	    case XML_NAMESPACE_DECL: {
7879 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7880 
7881 		if ((ns->next != NULL) &&
7882 		    (ns->next->type != XML_NAMESPACE_DECL))
7883 		    return((xmlNodePtr) ns->next);
7884                 return(NULL);
7885 	    }
7886 	}
7887     }
7888     return(NULL);
7889 }
7890 
7891 /**
7892  * xmlXPathNextAncestor:
7893  * @ctxt:  the XPath Parser context
7894  * @cur:  the current node in the traversal
7895  *
7896  * Traversal function for the "ancestor" direction
7897  * the ancestor axis contains the ancestors of the context node; the ancestors
7898  * of the context node consist of the parent of context node and the parent's
7899  * parent and so on; the nodes are ordered in reverse document order; thus the
7900  * parent is the first node on the axis, and the parent's parent is the second
7901  * node on the axis
7902  *
7903  * Returns the next element following that axis
7904  */
7905 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7906 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7907     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7908     /*
7909      * the parent of an attribute or namespace node is the element
7910      * to which the attribute or namespace node is attached
7911      * !!!!!!!!!!!!!
7912      */
7913     if (cur == NULL) {
7914 	if (ctxt->context->node == NULL) return(NULL);
7915 	switch (ctxt->context->node->type) {
7916             case XML_ELEMENT_NODE:
7917             case XML_TEXT_NODE:
7918             case XML_CDATA_SECTION_NODE:
7919             case XML_ENTITY_REF_NODE:
7920             case XML_ENTITY_NODE:
7921             case XML_PI_NODE:
7922             case XML_COMMENT_NODE:
7923 	    case XML_DTD_NODE:
7924 	    case XML_ELEMENT_DECL:
7925 	    case XML_ATTRIBUTE_DECL:
7926 	    case XML_ENTITY_DECL:
7927             case XML_NOTATION_NODE:
7928 	    case XML_XINCLUDE_START:
7929 	    case XML_XINCLUDE_END:
7930 		if (ctxt->context->node->parent == NULL)
7931 		    return((xmlNodePtr) ctxt->context->doc);
7932 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7933 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7934 		     (xmlStrEqual(ctxt->context->node->parent->name,
7935 				 BAD_CAST "fake node libxslt"))))
7936 		    return(NULL);
7937 		return(ctxt->context->node->parent);
7938             case XML_ATTRIBUTE_NODE: {
7939 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7940 
7941 		return(tmp->parent);
7942 	    }
7943             case XML_DOCUMENT_NODE:
7944             case XML_DOCUMENT_TYPE_NODE:
7945             case XML_DOCUMENT_FRAG_NODE:
7946             case XML_HTML_DOCUMENT_NODE:
7947 #ifdef LIBXML_DOCB_ENABLED
7948 	    case XML_DOCB_DOCUMENT_NODE:
7949 #endif
7950                 return(NULL);
7951 	    case XML_NAMESPACE_DECL: {
7952 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7953 
7954 		if ((ns->next != NULL) &&
7955 		    (ns->next->type != XML_NAMESPACE_DECL))
7956 		    return((xmlNodePtr) ns->next);
7957 		/* Bad, how did that namespace end up here ? */
7958                 return(NULL);
7959 	    }
7960 	}
7961 	return(NULL);
7962     }
7963     if (cur == ctxt->context->doc->children)
7964 	return((xmlNodePtr) ctxt->context->doc);
7965     if (cur == (xmlNodePtr) ctxt->context->doc)
7966 	return(NULL);
7967     switch (cur->type) {
7968 	case XML_ELEMENT_NODE:
7969 	case XML_TEXT_NODE:
7970 	case XML_CDATA_SECTION_NODE:
7971 	case XML_ENTITY_REF_NODE:
7972 	case XML_ENTITY_NODE:
7973 	case XML_PI_NODE:
7974 	case XML_COMMENT_NODE:
7975 	case XML_NOTATION_NODE:
7976 	case XML_DTD_NODE:
7977         case XML_ELEMENT_DECL:
7978         case XML_ATTRIBUTE_DECL:
7979         case XML_ENTITY_DECL:
7980 	case XML_XINCLUDE_START:
7981 	case XML_XINCLUDE_END:
7982 	    if (cur->parent == NULL)
7983 		return(NULL);
7984 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7985 		((cur->parent->name[0] == ' ') ||
7986 		 (xmlStrEqual(cur->parent->name,
7987 			      BAD_CAST "fake node libxslt"))))
7988 		return(NULL);
7989 	    return(cur->parent);
7990 	case XML_ATTRIBUTE_NODE: {
7991 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7992 
7993 	    return(att->parent);
7994 	}
7995 	case XML_NAMESPACE_DECL: {
7996 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7997 
7998 	    if ((ns->next != NULL) &&
7999 	        (ns->next->type != XML_NAMESPACE_DECL))
8000 	        return((xmlNodePtr) ns->next);
8001 	    /* Bad, how did that namespace end up here ? */
8002             return(NULL);
8003 	}
8004 	case XML_DOCUMENT_NODE:
8005 	case XML_DOCUMENT_TYPE_NODE:
8006 	case XML_DOCUMENT_FRAG_NODE:
8007 	case XML_HTML_DOCUMENT_NODE:
8008 #ifdef LIBXML_DOCB_ENABLED
8009 	case XML_DOCB_DOCUMENT_NODE:
8010 #endif
8011 	    return(NULL);
8012     }
8013     return(NULL);
8014 }
8015 
8016 /**
8017  * xmlXPathNextAncestorOrSelf:
8018  * @ctxt:  the XPath Parser context
8019  * @cur:  the current node in the traversal
8020  *
8021  * Traversal function for the "ancestor-or-self" direction
8022  * he ancestor-or-self axis contains the context node and ancestors of
8023  * the context node in reverse document order; thus the context node is
8024  * the first node on the axis, and the context node's parent the second;
8025  * parent here is defined the same as with the parent axis.
8026  *
8027  * Returns the next element following that axis
8028  */
8029 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8030 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8031     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8032     if (cur == NULL)
8033         return(ctxt->context->node);
8034     return(xmlXPathNextAncestor(ctxt, cur));
8035 }
8036 
8037 /**
8038  * xmlXPathNextFollowingSibling:
8039  * @ctxt:  the XPath Parser context
8040  * @cur:  the current node in the traversal
8041  *
8042  * Traversal function for the "following-sibling" direction
8043  * The following-sibling axis contains the following siblings of the context
8044  * node in document order.
8045  *
8046  * Returns the next element following that axis
8047  */
8048 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8049 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8050     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8051     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8052 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8053 	return(NULL);
8054     if (cur == (xmlNodePtr) ctxt->context->doc)
8055         return(NULL);
8056     if (cur == NULL)
8057         return(ctxt->context->node->next);
8058     return(cur->next);
8059 }
8060 
8061 /**
8062  * xmlXPathNextPrecedingSibling:
8063  * @ctxt:  the XPath Parser context
8064  * @cur:  the current node in the traversal
8065  *
8066  * Traversal function for the "preceding-sibling" direction
8067  * The preceding-sibling axis contains the preceding siblings of the context
8068  * node in reverse document order; the first preceding sibling is first on the
8069  * axis; the sibling preceding that node is the second on the axis and so on.
8070  *
8071  * Returns the next element following that axis
8072  */
8073 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8074 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8075     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8076     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8077 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8078 	return(NULL);
8079     if (cur == (xmlNodePtr) ctxt->context->doc)
8080         return(NULL);
8081     if (cur == NULL)
8082         return(ctxt->context->node->prev);
8083     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8084 	cur = cur->prev;
8085 	if (cur == NULL)
8086 	    return(ctxt->context->node->prev);
8087     }
8088     return(cur->prev);
8089 }
8090 
8091 /**
8092  * xmlXPathNextFollowing:
8093  * @ctxt:  the XPath Parser context
8094  * @cur:  the current node in the traversal
8095  *
8096  * Traversal function for the "following" direction
8097  * The following axis contains all nodes in the same document as the context
8098  * node that are after the context node in document order, excluding any
8099  * descendants and excluding attribute nodes and namespace nodes; the nodes
8100  * are ordered in document order
8101  *
8102  * Returns the next element following that axis
8103  */
8104 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8105 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8106     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8107     if (cur != NULL && cur->children != NULL)
8108         return cur->children ;
8109     if (cur == NULL) cur = ctxt->context->node;
8110     if (cur == NULL) return(NULL) ; /* ERROR */
8111     if (cur->next != NULL) return(cur->next) ;
8112     do {
8113         cur = cur->parent;
8114         if (cur == NULL) break;
8115         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8116         if (cur->next != NULL) return(cur->next);
8117     } while (cur != NULL);
8118     return(cur);
8119 }
8120 
8121 /*
8122  * xmlXPathIsAncestor:
8123  * @ancestor:  the ancestor node
8124  * @node:  the current node
8125  *
8126  * Check that @ancestor is a @node's ancestor
8127  *
8128  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8129  */
8130 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8131 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8132     if ((ancestor == NULL) || (node == NULL)) return(0);
8133     /* nodes need to be in the same document */
8134     if (ancestor->doc != node->doc) return(0);
8135     /* avoid searching if ancestor or node is the root node */
8136     if (ancestor == (xmlNodePtr) node->doc) return(1);
8137     if (node == (xmlNodePtr) ancestor->doc) return(0);
8138     while (node->parent != NULL) {
8139         if (node->parent == ancestor)
8140             return(1);
8141 	node = node->parent;
8142     }
8143     return(0);
8144 }
8145 
8146 /**
8147  * xmlXPathNextPreceding:
8148  * @ctxt:  the XPath Parser context
8149  * @cur:  the current node in the traversal
8150  *
8151  * Traversal function for the "preceding" direction
8152  * the preceding axis contains all nodes in the same document as the context
8153  * node that are before the context node in document order, excluding any
8154  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8155  * ordered in reverse document order
8156  *
8157  * Returns the next element following that axis
8158  */
8159 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8160 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8161 {
8162     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163     if (cur == NULL)
8164         cur = ctxt->context->node;
8165     if (cur == NULL)
8166 	return (NULL);
8167     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8168 	cur = cur->prev;
8169     do {
8170         if (cur->prev != NULL) {
8171             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8172             return (cur);
8173         }
8174 
8175         cur = cur->parent;
8176         if (cur == NULL)
8177             return (NULL);
8178         if (cur == ctxt->context->doc->children)
8179             return (NULL);
8180     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8181     return (cur);
8182 }
8183 
8184 /**
8185  * xmlXPathNextPrecedingInternal:
8186  * @ctxt:  the XPath Parser context
8187  * @cur:  the current node in the traversal
8188  *
8189  * Traversal function for the "preceding" direction
8190  * the preceding axis contains all nodes in the same document as the context
8191  * node that are before the context node in document order, excluding any
8192  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8193  * ordered in reverse document order
8194  * This is a faster implementation but internal only since it requires a
8195  * state kept in the parser context: ctxt->ancestor.
8196  *
8197  * Returns the next element following that axis
8198  */
8199 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8200 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8201                               xmlNodePtr cur)
8202 {
8203     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8204     if (cur == NULL) {
8205         cur = ctxt->context->node;
8206         if (cur == NULL)
8207             return (NULL);
8208 	if (cur->type == XML_NAMESPACE_DECL)
8209 	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8210         ctxt->ancestor = cur->parent;
8211     }
8212     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8213 	cur = cur->prev;
8214     while (cur->prev == NULL) {
8215         cur = cur->parent;
8216         if (cur == NULL)
8217             return (NULL);
8218         if (cur == ctxt->context->doc->children)
8219             return (NULL);
8220         if (cur != ctxt->ancestor)
8221             return (cur);
8222         ctxt->ancestor = cur->parent;
8223     }
8224     cur = cur->prev;
8225     while (cur->last != NULL)
8226         cur = cur->last;
8227     return (cur);
8228 }
8229 
8230 /**
8231  * xmlXPathNextNamespace:
8232  * @ctxt:  the XPath Parser context
8233  * @cur:  the current attribute in the traversal
8234  *
8235  * Traversal function for the "namespace" direction
8236  * the namespace axis contains the namespace nodes of the context node;
8237  * the order of nodes on this axis is implementation-defined; the axis will
8238  * be empty unless the context node is an element
8239  *
8240  * We keep the XML namespace node at the end of the list.
8241  *
8242  * Returns the next element following that axis
8243  */
8244 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8245 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8246     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8247     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8248     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8249         if (ctxt->context->tmpNsList != NULL)
8250 	    xmlFree(ctxt->context->tmpNsList);
8251 	ctxt->context->tmpNsList =
8252 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8253 	ctxt->context->tmpNsNr = 0;
8254 	if (ctxt->context->tmpNsList != NULL) {
8255 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8256 		ctxt->context->tmpNsNr++;
8257 	    }
8258 	}
8259 	return((xmlNodePtr) xmlXPathXMLNamespace);
8260     }
8261     if (ctxt->context->tmpNsNr > 0) {
8262 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8263     } else {
8264 	if (ctxt->context->tmpNsList != NULL)
8265 	    xmlFree(ctxt->context->tmpNsList);
8266 	ctxt->context->tmpNsList = NULL;
8267 	return(NULL);
8268     }
8269 }
8270 
8271 /**
8272  * xmlXPathNextAttribute:
8273  * @ctxt:  the XPath Parser context
8274  * @cur:  the current attribute in the traversal
8275  *
8276  * Traversal function for the "attribute" direction
8277  * TODO: support DTD inherited default attributes
8278  *
8279  * Returns the next element following that axis
8280  */
8281 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8282 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8283     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8284     if (ctxt->context->node == NULL)
8285 	return(NULL);
8286     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8287 	return(NULL);
8288     if (cur == NULL) {
8289         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8290 	    return(NULL);
8291         return((xmlNodePtr)ctxt->context->node->properties);
8292     }
8293     return((xmlNodePtr)cur->next);
8294 }
8295 
8296 /************************************************************************
8297  *									*
8298  *		NodeTest Functions					*
8299  *									*
8300  ************************************************************************/
8301 
8302 #define IS_FUNCTION			200
8303 
8304 
8305 /************************************************************************
8306  *									*
8307  *		Implicit tree core function library			*
8308  *									*
8309  ************************************************************************/
8310 
8311 /**
8312  * xmlXPathRoot:
8313  * @ctxt:  the XPath Parser context
8314  *
8315  * Initialize the context to the root of the document
8316  */
8317 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8318 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8319     if ((ctxt == NULL) || (ctxt->context == NULL))
8320 	return;
8321     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8322     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8323 	ctxt->context->node));
8324 }
8325 
8326 /************************************************************************
8327  *									*
8328  *		The explicit core function library			*
8329  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8330  *									*
8331  ************************************************************************/
8332 
8333 
8334 /**
8335  * xmlXPathLastFunction:
8336  * @ctxt:  the XPath Parser context
8337  * @nargs:  the number of arguments
8338  *
8339  * Implement the last() XPath function
8340  *    number last()
8341  * The last function returns the number of nodes in the context node list.
8342  */
8343 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8344 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8345     CHECK_ARITY(0);
8346     if (ctxt->context->contextSize >= 0) {
8347 	valuePush(ctxt,
8348 	    xmlXPathCacheNewFloat(ctxt->context,
8349 		(double) ctxt->context->contextSize));
8350 #ifdef DEBUG_EXPR
8351 	xmlGenericError(xmlGenericErrorContext,
8352 		"last() : %d\n", ctxt->context->contextSize);
8353 #endif
8354     } else {
8355 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8356     }
8357 }
8358 
8359 /**
8360  * xmlXPathPositionFunction:
8361  * @ctxt:  the XPath Parser context
8362  * @nargs:  the number of arguments
8363  *
8364  * Implement the position() XPath function
8365  *    number position()
8366  * The position function returns the position of the context node in the
8367  * context node list. The first position is 1, and so the last position
8368  * will be equal to last().
8369  */
8370 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8371 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8372     CHECK_ARITY(0);
8373     if (ctxt->context->proximityPosition >= 0) {
8374 	valuePush(ctxt,
8375 	      xmlXPathCacheNewFloat(ctxt->context,
8376 		(double) ctxt->context->proximityPosition));
8377 #ifdef DEBUG_EXPR
8378 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8379 		ctxt->context->proximityPosition);
8380 #endif
8381     } else {
8382 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8383     }
8384 }
8385 
8386 /**
8387  * xmlXPathCountFunction:
8388  * @ctxt:  the XPath Parser context
8389  * @nargs:  the number of arguments
8390  *
8391  * Implement the count() XPath function
8392  *    number count(node-set)
8393  */
8394 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8395 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8396     xmlXPathObjectPtr cur;
8397 
8398     CHECK_ARITY(1);
8399     if ((ctxt->value == NULL) ||
8400 	((ctxt->value->type != XPATH_NODESET) &&
8401 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8402 	XP_ERROR(XPATH_INVALID_TYPE);
8403     cur = valuePop(ctxt);
8404 
8405     if ((cur == NULL) || (cur->nodesetval == NULL))
8406 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8407     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8408 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8409 	    (double) cur->nodesetval->nodeNr));
8410     } else {
8411 	if ((cur->nodesetval->nodeNr != 1) ||
8412 	    (cur->nodesetval->nodeTab == NULL)) {
8413 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8414 	} else {
8415 	    xmlNodePtr tmp;
8416 	    int i = 0;
8417 
8418 	    tmp = cur->nodesetval->nodeTab[0];
8419 	    if (tmp != NULL) {
8420 		tmp = tmp->children;
8421 		while (tmp != NULL) {
8422 		    tmp = tmp->next;
8423 		    i++;
8424 		}
8425 	    }
8426 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8427 	}
8428     }
8429     xmlXPathReleaseObject(ctxt->context, cur);
8430 }
8431 
8432 /**
8433  * xmlXPathGetElementsByIds:
8434  * @doc:  the document
8435  * @ids:  a whitespace separated list of IDs
8436  *
8437  * Selects elements by their unique ID.
8438  *
8439  * Returns a node-set of selected elements.
8440  */
8441 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8442 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8443     xmlNodeSetPtr ret;
8444     const xmlChar *cur = ids;
8445     xmlChar *ID;
8446     xmlAttrPtr attr;
8447     xmlNodePtr elem = NULL;
8448 
8449     if (ids == NULL) return(NULL);
8450 
8451     ret = xmlXPathNodeSetCreate(NULL);
8452     if (ret == NULL)
8453         return(ret);
8454 
8455     while (IS_BLANK_CH(*cur)) cur++;
8456     while (*cur != 0) {
8457 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8458 	    cur++;
8459 
8460         ID = xmlStrndup(ids, cur - ids);
8461 	if (ID != NULL) {
8462 	    /*
8463 	     * We used to check the fact that the value passed
8464 	     * was an NCName, but this generated much troubles for
8465 	     * me and Aleksey Sanin, people blatantly violated that
8466 	     * constaint, like Visa3D spec.
8467 	     * if (xmlValidateNCName(ID, 1) == 0)
8468 	     */
8469 	    attr = xmlGetID(doc, ID);
8470 	    if (attr != NULL) {
8471 		if (attr->type == XML_ATTRIBUTE_NODE)
8472 		    elem = attr->parent;
8473 		else if (attr->type == XML_ELEMENT_NODE)
8474 		    elem = (xmlNodePtr) attr;
8475 		else
8476 		    elem = NULL;
8477 		if (elem != NULL)
8478 		    xmlXPathNodeSetAdd(ret, elem);
8479 	    }
8480 	    xmlFree(ID);
8481 	}
8482 
8483 	while (IS_BLANK_CH(*cur)) cur++;
8484 	ids = cur;
8485     }
8486     return(ret);
8487 }
8488 
8489 /**
8490  * xmlXPathIdFunction:
8491  * @ctxt:  the XPath Parser context
8492  * @nargs:  the number of arguments
8493  *
8494  * Implement the id() XPath function
8495  *    node-set id(object)
8496  * The id function selects elements by their unique ID
8497  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8498  * then the result is the union of the result of applying id to the
8499  * string value of each of the nodes in the argument node-set. When the
8500  * argument to id is of any other type, the argument is converted to a
8501  * string as if by a call to the string function; the string is split
8502  * into a whitespace-separated list of tokens (whitespace is any sequence
8503  * of characters matching the production S); the result is a node-set
8504  * containing the elements in the same document as the context node that
8505  * have a unique ID equal to any of the tokens in the list.
8506  */
8507 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8508 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8509     xmlChar *tokens;
8510     xmlNodeSetPtr ret;
8511     xmlXPathObjectPtr obj;
8512 
8513     CHECK_ARITY(1);
8514     obj = valuePop(ctxt);
8515     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8516     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8517 	xmlNodeSetPtr ns;
8518 	int i;
8519 
8520 	ret = xmlXPathNodeSetCreate(NULL);
8521         /*
8522          * FIXME -- in an out-of-memory condition this will behave badly.
8523          * The solution is not clear -- we already popped an item from
8524          * ctxt, so the object is in a corrupt state.
8525          */
8526 
8527 	if (obj->nodesetval != NULL) {
8528 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8529 		tokens =
8530 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8531 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8532 		ret = xmlXPathNodeSetMerge(ret, ns);
8533 		xmlXPathFreeNodeSet(ns);
8534 		if (tokens != NULL)
8535 		    xmlFree(tokens);
8536 	    }
8537 	}
8538 	xmlXPathReleaseObject(ctxt->context, obj);
8539 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8540 	return;
8541     }
8542     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8543     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8544     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8545     xmlXPathReleaseObject(ctxt->context, obj);
8546     return;
8547 }
8548 
8549 /**
8550  * xmlXPathLocalNameFunction:
8551  * @ctxt:  the XPath Parser context
8552  * @nargs:  the number of arguments
8553  *
8554  * Implement the local-name() XPath function
8555  *    string local-name(node-set?)
8556  * The local-name function returns a string containing the local part
8557  * of the name of the node in the argument node-set that is first in
8558  * document order. If the node-set is empty or the first node has no
8559  * name, an empty string is returned. If the argument is omitted it
8560  * defaults to the context node.
8561  */
8562 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8563 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8564     xmlXPathObjectPtr cur;
8565 
8566     if (ctxt == NULL) return;
8567 
8568     if (nargs == 0) {
8569 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8570 	    ctxt->context->node));
8571 	nargs = 1;
8572     }
8573 
8574     CHECK_ARITY(1);
8575     if ((ctxt->value == NULL) ||
8576 	((ctxt->value->type != XPATH_NODESET) &&
8577 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8578 	XP_ERROR(XPATH_INVALID_TYPE);
8579     cur = valuePop(ctxt);
8580 
8581     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8582 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8583     } else {
8584 	int i = 0; /* Should be first in document order !!!!! */
8585 	switch (cur->nodesetval->nodeTab[i]->type) {
8586 	case XML_ELEMENT_NODE:
8587 	case XML_ATTRIBUTE_NODE:
8588 	case XML_PI_NODE:
8589 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8590 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8591 	    else
8592 		valuePush(ctxt,
8593 		      xmlXPathCacheNewString(ctxt->context,
8594 			cur->nodesetval->nodeTab[i]->name));
8595 	    break;
8596 	case XML_NAMESPACE_DECL:
8597 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8598 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8599 	    break;
8600 	default:
8601 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8602 	}
8603     }
8604     xmlXPathReleaseObject(ctxt->context, cur);
8605 }
8606 
8607 /**
8608  * xmlXPathNamespaceURIFunction:
8609  * @ctxt:  the XPath Parser context
8610  * @nargs:  the number of arguments
8611  *
8612  * Implement the namespace-uri() XPath function
8613  *    string namespace-uri(node-set?)
8614  * The namespace-uri function returns a string containing the
8615  * namespace URI of the expanded name of the node in the argument
8616  * node-set that is first in document order. If the node-set is empty,
8617  * the first node has no name, or the expanded name has no namespace
8618  * URI, an empty string is returned. If the argument is omitted it
8619  * defaults to the context node.
8620  */
8621 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8622 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623     xmlXPathObjectPtr cur;
8624 
8625     if (ctxt == NULL) return;
8626 
8627     if (nargs == 0) {
8628 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8629 	    ctxt->context->node));
8630 	nargs = 1;
8631     }
8632     CHECK_ARITY(1);
8633     if ((ctxt->value == NULL) ||
8634 	((ctxt->value->type != XPATH_NODESET) &&
8635 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8636 	XP_ERROR(XPATH_INVALID_TYPE);
8637     cur = valuePop(ctxt);
8638 
8639     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8640 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8641     } else {
8642 	int i = 0; /* Should be first in document order !!!!! */
8643 	switch (cur->nodesetval->nodeTab[i]->type) {
8644 	case XML_ELEMENT_NODE:
8645 	case XML_ATTRIBUTE_NODE:
8646 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8647 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8648 	    else
8649 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8650 			  cur->nodesetval->nodeTab[i]->ns->href));
8651 	    break;
8652 	default:
8653 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8654 	}
8655     }
8656     xmlXPathReleaseObject(ctxt->context, cur);
8657 }
8658 
8659 /**
8660  * xmlXPathNameFunction:
8661  * @ctxt:  the XPath Parser context
8662  * @nargs:  the number of arguments
8663  *
8664  * Implement the name() XPath function
8665  *    string name(node-set?)
8666  * The name function returns a string containing a QName representing
8667  * the name of the node in the argument node-set that is first in document
8668  * order. The QName must represent the name with respect to the namespace
8669  * declarations in effect on the node whose name is being represented.
8670  * Typically, this will be the form in which the name occurred in the XML
8671  * source. This need not be the case if there are namespace declarations
8672  * in effect on the node that associate multiple prefixes with the same
8673  * namespace. However, an implementation may include information about
8674  * the original prefix in its representation of nodes; in this case, an
8675  * implementation can ensure that the returned string is always the same
8676  * as the QName used in the XML source. If the argument it omitted it
8677  * defaults to the context node.
8678  * Libxml keep the original prefix so the "real qualified name" used is
8679  * returned.
8680  */
8681 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8682 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8683 {
8684     xmlXPathObjectPtr cur;
8685 
8686     if (nargs == 0) {
8687 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8688 	    ctxt->context->node));
8689         nargs = 1;
8690     }
8691 
8692     CHECK_ARITY(1);
8693     if ((ctxt->value == NULL) ||
8694         ((ctxt->value->type != XPATH_NODESET) &&
8695          (ctxt->value->type != XPATH_XSLT_TREE)))
8696         XP_ERROR(XPATH_INVALID_TYPE);
8697     cur = valuePop(ctxt);
8698 
8699     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701     } else {
8702         int i = 0;              /* Should be first in document order !!!!! */
8703 
8704         switch (cur->nodesetval->nodeTab[i]->type) {
8705             case XML_ELEMENT_NODE:
8706             case XML_ATTRIBUTE_NODE:
8707 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8708 		    valuePush(ctxt,
8709 			xmlXPathCacheNewCString(ctxt->context, ""));
8710 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8711                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8712 		    valuePush(ctxt,
8713 		        xmlXPathCacheNewString(ctxt->context,
8714 			    cur->nodesetval->nodeTab[i]->name));
8715 		} else {
8716 		    xmlChar *fullname;
8717 
8718 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8719 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8720 				     NULL, 0);
8721 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8722 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8723 		    if (fullname == NULL) {
8724 			XP_ERROR(XPATH_MEMORY_ERROR);
8725 		    }
8726 		    valuePush(ctxt, xmlXPathCacheWrapString(
8727 			ctxt->context, fullname));
8728                 }
8729                 break;
8730             default:
8731 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8732 		    cur->nodesetval->nodeTab[i]));
8733                 xmlXPathLocalNameFunction(ctxt, 1);
8734         }
8735     }
8736     xmlXPathReleaseObject(ctxt->context, cur);
8737 }
8738 
8739 
8740 /**
8741  * xmlXPathStringFunction:
8742  * @ctxt:  the XPath Parser context
8743  * @nargs:  the number of arguments
8744  *
8745  * Implement the string() XPath function
8746  *    string string(object?)
8747  * The string function converts an object to a string as follows:
8748  *    - A node-set is converted to a string by returning the value of
8749  *      the node in the node-set that is first in document order.
8750  *      If the node-set is empty, an empty string is returned.
8751  *    - A number is converted to a string as follows
8752  *      + NaN is converted to the string NaN
8753  *      + positive zero is converted to the string 0
8754  *      + negative zero is converted to the string 0
8755  *      + positive infinity is converted to the string Infinity
8756  *      + negative infinity is converted to the string -Infinity
8757  *      + if the number is an integer, the number is represented in
8758  *        decimal form as a Number with no decimal point and no leading
8759  *        zeros, preceded by a minus sign (-) if the number is negative
8760  *      + otherwise, the number is represented in decimal form as a
8761  *        Number including a decimal point with at least one digit
8762  *        before the decimal point and at least one digit after the
8763  *        decimal point, preceded by a minus sign (-) if the number
8764  *        is negative; there must be no leading zeros before the decimal
8765  *        point apart possibly from the one required digit immediately
8766  *        before the decimal point; beyond the one required digit
8767  *        after the decimal point there must be as many, but only as
8768  *        many, more digits as are needed to uniquely distinguish the
8769  *        number from all other IEEE 754 numeric values.
8770  *    - The boolean false value is converted to the string false.
8771  *      The boolean true value is converted to the string true.
8772  *
8773  * If the argument is omitted, it defaults to a node-set with the
8774  * context node as its only member.
8775  */
8776 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8777 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8778     xmlXPathObjectPtr cur;
8779 
8780     if (ctxt == NULL) return;
8781     if (nargs == 0) {
8782     valuePush(ctxt,
8783 	xmlXPathCacheWrapString(ctxt->context,
8784 	    xmlXPathCastNodeToString(ctxt->context->node)));
8785 	return;
8786     }
8787 
8788     CHECK_ARITY(1);
8789     cur = valuePop(ctxt);
8790     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8791     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8792 }
8793 
8794 /**
8795  * xmlXPathStringLengthFunction:
8796  * @ctxt:  the XPath Parser context
8797  * @nargs:  the number of arguments
8798  *
8799  * Implement the string-length() XPath function
8800  *    number string-length(string?)
8801  * The string-length returns the number of characters in the string
8802  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8803  * the context node converted to a string, in other words the value
8804  * of the context node.
8805  */
8806 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8807 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8808     xmlXPathObjectPtr cur;
8809 
8810     if (nargs == 0) {
8811         if ((ctxt == NULL) || (ctxt->context == NULL))
8812 	    return;
8813 	if (ctxt->context->node == NULL) {
8814 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8815 	} else {
8816 	    xmlChar *content;
8817 
8818 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8819 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8820 		xmlUTF8Strlen(content)));
8821 	    xmlFree(content);
8822 	}
8823 	return;
8824     }
8825     CHECK_ARITY(1);
8826     CAST_TO_STRING;
8827     CHECK_TYPE(XPATH_STRING);
8828     cur = valuePop(ctxt);
8829     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8830 	xmlUTF8Strlen(cur->stringval)));
8831     xmlXPathReleaseObject(ctxt->context, cur);
8832 }
8833 
8834 /**
8835  * xmlXPathConcatFunction:
8836  * @ctxt:  the XPath Parser context
8837  * @nargs:  the number of arguments
8838  *
8839  * Implement the concat() XPath function
8840  *    string concat(string, string, string*)
8841  * The concat function returns the concatenation of its arguments.
8842  */
8843 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8844 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8845     xmlXPathObjectPtr cur, newobj;
8846     xmlChar *tmp;
8847 
8848     if (ctxt == NULL) return;
8849     if (nargs < 2) {
8850 	CHECK_ARITY(2);
8851     }
8852 
8853     CAST_TO_STRING;
8854     cur = valuePop(ctxt);
8855     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8856 	xmlXPathReleaseObject(ctxt->context, cur);
8857 	return;
8858     }
8859     nargs--;
8860 
8861     while (nargs > 0) {
8862 	CAST_TO_STRING;
8863 	newobj = valuePop(ctxt);
8864 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8865 	    xmlXPathReleaseObject(ctxt->context, newobj);
8866 	    xmlXPathReleaseObject(ctxt->context, cur);
8867 	    XP_ERROR(XPATH_INVALID_TYPE);
8868 	}
8869 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8870 	newobj->stringval = cur->stringval;
8871 	cur->stringval = tmp;
8872 	xmlXPathReleaseObject(ctxt->context, newobj);
8873 	nargs--;
8874     }
8875     valuePush(ctxt, cur);
8876 }
8877 
8878 /**
8879  * xmlXPathContainsFunction:
8880  * @ctxt:  the XPath Parser context
8881  * @nargs:  the number of arguments
8882  *
8883  * Implement the contains() XPath function
8884  *    boolean contains(string, string)
8885  * The contains function returns true if the first argument string
8886  * contains the second argument string, and otherwise returns false.
8887  */
8888 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)8889 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8890     xmlXPathObjectPtr hay, needle;
8891 
8892     CHECK_ARITY(2);
8893     CAST_TO_STRING;
8894     CHECK_TYPE(XPATH_STRING);
8895     needle = valuePop(ctxt);
8896     CAST_TO_STRING;
8897     hay = valuePop(ctxt);
8898 
8899     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8900 	xmlXPathReleaseObject(ctxt->context, hay);
8901 	xmlXPathReleaseObject(ctxt->context, needle);
8902 	XP_ERROR(XPATH_INVALID_TYPE);
8903     }
8904     if (xmlStrstr(hay->stringval, needle->stringval))
8905 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8906     else
8907 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8908     xmlXPathReleaseObject(ctxt->context, hay);
8909     xmlXPathReleaseObject(ctxt->context, needle);
8910 }
8911 
8912 /**
8913  * xmlXPathStartsWithFunction:
8914  * @ctxt:  the XPath Parser context
8915  * @nargs:  the number of arguments
8916  *
8917  * Implement the starts-with() XPath function
8918  *    boolean starts-with(string, string)
8919  * The starts-with function returns true if the first argument string
8920  * starts with the second argument string, and otherwise returns false.
8921  */
8922 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8923 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8924     xmlXPathObjectPtr hay, needle;
8925     int n;
8926 
8927     CHECK_ARITY(2);
8928     CAST_TO_STRING;
8929     CHECK_TYPE(XPATH_STRING);
8930     needle = valuePop(ctxt);
8931     CAST_TO_STRING;
8932     hay = valuePop(ctxt);
8933 
8934     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8935 	xmlXPathReleaseObject(ctxt->context, hay);
8936 	xmlXPathReleaseObject(ctxt->context, needle);
8937 	XP_ERROR(XPATH_INVALID_TYPE);
8938     }
8939     n = xmlStrlen(needle->stringval);
8940     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8941         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8942     else
8943         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8944     xmlXPathReleaseObject(ctxt->context, hay);
8945     xmlXPathReleaseObject(ctxt->context, needle);
8946 }
8947 
8948 /**
8949  * xmlXPathSubstringFunction:
8950  * @ctxt:  the XPath Parser context
8951  * @nargs:  the number of arguments
8952  *
8953  * Implement the substring() XPath function
8954  *    string substring(string, number, number?)
8955  * The substring function returns the substring of the first argument
8956  * starting at the position specified in the second argument with
8957  * length specified in the third argument. For example,
8958  * substring("12345",2,3) returns "234". If the third argument is not
8959  * specified, it returns the substring starting at the position specified
8960  * in the second argument and continuing to the end of the string. For
8961  * example, substring("12345",2) returns "2345".  More precisely, each
8962  * character in the string (see [3.6 Strings]) is considered to have a
8963  * numeric position: the position of the first character is 1, the position
8964  * of the second character is 2 and so on. The returned substring contains
8965  * those characters for which the position of the character is greater than
8966  * or equal to the second argument and, if the third argument is specified,
8967  * less than the sum of the second and third arguments; the comparisons
8968  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8969  *  - substring("12345", 1.5, 2.6) returns "234"
8970  *  - substring("12345", 0, 3) returns "12"
8971  *  - substring("12345", 0 div 0, 3) returns ""
8972  *  - substring("12345", 1, 0 div 0) returns ""
8973  *  - substring("12345", -42, 1 div 0) returns "12345"
8974  *  - substring("12345", -1 div 0, 1 div 0) returns ""
8975  */
8976 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)8977 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978     xmlXPathObjectPtr str, start, len;
8979     double le=0, in;
8980     int i, l, m;
8981     xmlChar *ret;
8982 
8983     if (nargs < 2) {
8984 	CHECK_ARITY(2);
8985     }
8986     if (nargs > 3) {
8987 	CHECK_ARITY(3);
8988     }
8989     /*
8990      * take care of possible last (position) argument
8991     */
8992     if (nargs == 3) {
8993 	CAST_TO_NUMBER;
8994 	CHECK_TYPE(XPATH_NUMBER);
8995 	len = valuePop(ctxt);
8996 	le = len->floatval;
8997 	xmlXPathReleaseObject(ctxt->context, len);
8998     }
8999 
9000     CAST_TO_NUMBER;
9001     CHECK_TYPE(XPATH_NUMBER);
9002     start = valuePop(ctxt);
9003     in = start->floatval;
9004     xmlXPathReleaseObject(ctxt->context, start);
9005     CAST_TO_STRING;
9006     CHECK_TYPE(XPATH_STRING);
9007     str = valuePop(ctxt);
9008     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9009 
9010     /*
9011      * If last pos not present, calculate last position
9012     */
9013     if (nargs != 3) {
9014 	le = (double)m;
9015 	if (in < 1.0)
9016 	    in = 1.0;
9017     }
9018 
9019     /* Need to check for the special cases where either
9020      * the index is NaN, the length is NaN, or both
9021      * arguments are infinity (relying on Inf + -Inf = NaN)
9022      */
9023     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
9024         /*
9025          * To meet the requirements of the spec, the arguments
9026 	 * must be converted to integer format before
9027 	 * initial index calculations are done
9028          *
9029          * First we go to integer form, rounding up
9030 	 * and checking for special cases
9031          */
9032         i = (int) in;
9033         if (((double)i)+0.5 <= in) i++;
9034 
9035 	if (xmlXPathIsInf(le) == 1) {
9036 	    l = m;
9037 	    if (i < 1)
9038 		i = 1;
9039 	}
9040 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9041 	    l = 0;
9042 	else {
9043 	    l = (int) le;
9044 	    if (((double)l)+0.5 <= le) l++;
9045 	}
9046 
9047 	/* Now we normalize inidices */
9048         i -= 1;
9049         l += i;
9050         if (i < 0)
9051             i = 0;
9052         if (l > m)
9053             l = m;
9054 
9055         /* number of chars to copy */
9056         l -= i;
9057 
9058         ret = xmlUTF8Strsub(str->stringval, i, l);
9059     }
9060     else {
9061         ret = NULL;
9062     }
9063     if (ret == NULL)
9064 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9065     else {
9066 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9067 	xmlFree(ret);
9068     }
9069     xmlXPathReleaseObject(ctxt->context, str);
9070 }
9071 
9072 /**
9073  * xmlXPathSubstringBeforeFunction:
9074  * @ctxt:  the XPath Parser context
9075  * @nargs:  the number of arguments
9076  *
9077  * Implement the substring-before() XPath function
9078  *    string substring-before(string, string)
9079  * The substring-before function returns the substring of the first
9080  * argument string that precedes the first occurrence of the second
9081  * argument string in the first argument string, or the empty string
9082  * if the first argument string does not contain the second argument
9083  * string. For example, substring-before("1999/04/01","/") returns 1999.
9084  */
9085 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9086 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087   xmlXPathObjectPtr str;
9088   xmlXPathObjectPtr find;
9089   xmlBufferPtr target;
9090   const xmlChar *point;
9091   int offset;
9092 
9093   CHECK_ARITY(2);
9094   CAST_TO_STRING;
9095   find = valuePop(ctxt);
9096   CAST_TO_STRING;
9097   str = valuePop(ctxt);
9098 
9099   target = xmlBufferCreate();
9100   if (target) {
9101     point = xmlStrstr(str->stringval, find->stringval);
9102     if (point) {
9103       offset = (int)(point - str->stringval);
9104       xmlBufferAdd(target, str->stringval, offset);
9105     }
9106     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9107 	xmlBufferContent(target)));
9108     xmlBufferFree(target);
9109   }
9110   xmlXPathReleaseObject(ctxt->context, str);
9111   xmlXPathReleaseObject(ctxt->context, find);
9112 }
9113 
9114 /**
9115  * xmlXPathSubstringAfterFunction:
9116  * @ctxt:  the XPath Parser context
9117  * @nargs:  the number of arguments
9118  *
9119  * Implement the substring-after() XPath function
9120  *    string substring-after(string, string)
9121  * The substring-after function returns the substring of the first
9122  * argument string that follows the first occurrence of the second
9123  * argument string in the first argument string, or the empty stringi
9124  * if the first argument string does not contain the second argument
9125  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9126  * and substring-after("1999/04/01","19") returns 99/04/01.
9127  */
9128 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9129 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9130   xmlXPathObjectPtr str;
9131   xmlXPathObjectPtr find;
9132   xmlBufferPtr target;
9133   const xmlChar *point;
9134   int offset;
9135 
9136   CHECK_ARITY(2);
9137   CAST_TO_STRING;
9138   find = valuePop(ctxt);
9139   CAST_TO_STRING;
9140   str = valuePop(ctxt);
9141 
9142   target = xmlBufferCreate();
9143   if (target) {
9144     point = xmlStrstr(str->stringval, find->stringval);
9145     if (point) {
9146       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9147       xmlBufferAdd(target, &str->stringval[offset],
9148 		   xmlStrlen(str->stringval) - offset);
9149     }
9150     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9151 	xmlBufferContent(target)));
9152     xmlBufferFree(target);
9153   }
9154   xmlXPathReleaseObject(ctxt->context, str);
9155   xmlXPathReleaseObject(ctxt->context, find);
9156 }
9157 
9158 /**
9159  * xmlXPathNormalizeFunction:
9160  * @ctxt:  the XPath Parser context
9161  * @nargs:  the number of arguments
9162  *
9163  * Implement the normalize-space() XPath function
9164  *    string normalize-space(string?)
9165  * The normalize-space function returns the argument string with white
9166  * space normalized by stripping leading and trailing whitespace
9167  * and replacing sequences of whitespace characters by a single
9168  * space. Whitespace characters are the same allowed by the S production
9169  * in XML. If the argument is omitted, it defaults to the context
9170  * node converted to a string, in other words the value of the context node.
9171  */
9172 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9173 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9174   xmlXPathObjectPtr obj = NULL;
9175   xmlChar *source = NULL;
9176   xmlBufferPtr target;
9177   xmlChar blank;
9178 
9179   if (ctxt == NULL) return;
9180   if (nargs == 0) {
9181     /* Use current context node */
9182       valuePush(ctxt,
9183 	  xmlXPathCacheWrapString(ctxt->context,
9184 	    xmlXPathCastNodeToString(ctxt->context->node)));
9185     nargs = 1;
9186   }
9187 
9188   CHECK_ARITY(1);
9189   CAST_TO_STRING;
9190   CHECK_TYPE(XPATH_STRING);
9191   obj = valuePop(ctxt);
9192   source = obj->stringval;
9193 
9194   target = xmlBufferCreate();
9195   if (target && source) {
9196 
9197     /* Skip leading whitespaces */
9198     while (IS_BLANK_CH(*source))
9199       source++;
9200 
9201     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9202     blank = 0;
9203     while (*source) {
9204       if (IS_BLANK_CH(*source)) {
9205 	blank = 0x20;
9206       } else {
9207 	if (blank) {
9208 	  xmlBufferAdd(target, &blank, 1);
9209 	  blank = 0;
9210 	}
9211 	xmlBufferAdd(target, source, 1);
9212       }
9213       source++;
9214     }
9215     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9216 	xmlBufferContent(target)));
9217     xmlBufferFree(target);
9218   }
9219   xmlXPathReleaseObject(ctxt->context, obj);
9220 }
9221 
9222 /**
9223  * xmlXPathTranslateFunction:
9224  * @ctxt:  the XPath Parser context
9225  * @nargs:  the number of arguments
9226  *
9227  * Implement the translate() XPath function
9228  *    string translate(string, string, string)
9229  * The translate function returns the first argument string with
9230  * occurrences of characters in the second argument string replaced
9231  * by the character at the corresponding position in the third argument
9232  * string. For example, translate("bar","abc","ABC") returns the string
9233  * BAr. If there is a character in the second argument string with no
9234  * character at a corresponding position in the third argument string
9235  * (because the second argument string is longer than the third argument
9236  * string), then occurrences of that character in the first argument
9237  * string are removed. For example, translate("--aaa--","abc-","ABC")
9238  * returns "AAA". If a character occurs more than once in second
9239  * argument string, then the first occurrence determines the replacement
9240  * character. If the third argument string is longer than the second
9241  * argument string, then excess characters are ignored.
9242  */
9243 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9244 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245     xmlXPathObjectPtr str;
9246     xmlXPathObjectPtr from;
9247     xmlXPathObjectPtr to;
9248     xmlBufferPtr target;
9249     int offset, max;
9250     xmlChar ch;
9251     const xmlChar *point;
9252     xmlChar *cptr;
9253 
9254     CHECK_ARITY(3);
9255 
9256     CAST_TO_STRING;
9257     to = valuePop(ctxt);
9258     CAST_TO_STRING;
9259     from = valuePop(ctxt);
9260     CAST_TO_STRING;
9261     str = valuePop(ctxt);
9262 
9263     target = xmlBufferCreate();
9264     if (target) {
9265 	max = xmlUTF8Strlen(to->stringval);
9266 	for (cptr = str->stringval; (ch=*cptr); ) {
9267 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9268 	    if (offset >= 0) {
9269 		if (offset < max) {
9270 		    point = xmlUTF8Strpos(to->stringval, offset);
9271 		    if (point)
9272 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9273 		}
9274 	    } else
9275 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9276 
9277 	    /* Step to next character in input */
9278 	    cptr++;
9279 	    if ( ch & 0x80 ) {
9280 		/* if not simple ascii, verify proper format */
9281 		if ( (ch & 0xc0) != 0xc0 ) {
9282 		    xmlGenericError(xmlGenericErrorContext,
9283 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9284 		    break;
9285 		}
9286 		/* then skip over remaining bytes for this char */
9287 		while ( (ch <<= 1) & 0x80 )
9288 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9289 			xmlGenericError(xmlGenericErrorContext,
9290 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9291 			break;
9292 		    }
9293 		if (ch & 0x80) /* must have had error encountered */
9294 		    break;
9295 	    }
9296 	}
9297     }
9298     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9299 	xmlBufferContent(target)));
9300     xmlBufferFree(target);
9301     xmlXPathReleaseObject(ctxt->context, str);
9302     xmlXPathReleaseObject(ctxt->context, from);
9303     xmlXPathReleaseObject(ctxt->context, to);
9304 }
9305 
9306 /**
9307  * xmlXPathBooleanFunction:
9308  * @ctxt:  the XPath Parser context
9309  * @nargs:  the number of arguments
9310  *
9311  * Implement the boolean() XPath function
9312  *    boolean boolean(object)
9313  * The boolean function converts its argument to a boolean as follows:
9314  *    - a number is true if and only if it is neither positive or
9315  *      negative zero nor NaN
9316  *    - a node-set is true if and only if it is non-empty
9317  *    - a string is true if and only if its length is non-zero
9318  */
9319 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9320 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9321     xmlXPathObjectPtr cur;
9322 
9323     CHECK_ARITY(1);
9324     cur = valuePop(ctxt);
9325     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9326     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9327     valuePush(ctxt, cur);
9328 }
9329 
9330 /**
9331  * xmlXPathNotFunction:
9332  * @ctxt:  the XPath Parser context
9333  * @nargs:  the number of arguments
9334  *
9335  * Implement the not() XPath function
9336  *    boolean not(boolean)
9337  * The not function returns true if its argument is false,
9338  * and false otherwise.
9339  */
9340 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9341 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342     CHECK_ARITY(1);
9343     CAST_TO_BOOLEAN;
9344     CHECK_TYPE(XPATH_BOOLEAN);
9345     ctxt->value->boolval = ! ctxt->value->boolval;
9346 }
9347 
9348 /**
9349  * xmlXPathTrueFunction:
9350  * @ctxt:  the XPath Parser context
9351  * @nargs:  the number of arguments
9352  *
9353  * Implement the true() XPath function
9354  *    boolean true()
9355  */
9356 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9357 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9358     CHECK_ARITY(0);
9359     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9360 }
9361 
9362 /**
9363  * xmlXPathFalseFunction:
9364  * @ctxt:  the XPath Parser context
9365  * @nargs:  the number of arguments
9366  *
9367  * Implement the false() XPath function
9368  *    boolean false()
9369  */
9370 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9371 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9372     CHECK_ARITY(0);
9373     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9374 }
9375 
9376 /**
9377  * xmlXPathLangFunction:
9378  * @ctxt:  the XPath Parser context
9379  * @nargs:  the number of arguments
9380  *
9381  * Implement the lang() XPath function
9382  *    boolean lang(string)
9383  * The lang function returns true or false depending on whether the
9384  * language of the context node as specified by xml:lang attributes
9385  * is the same as or is a sublanguage of the language specified by
9386  * the argument string. The language of the context node is determined
9387  * by the value of the xml:lang attribute on the context node, or, if
9388  * the context node has no xml:lang attribute, by the value of the
9389  * xml:lang attribute on the nearest ancestor of the context node that
9390  * has an xml:lang attribute. If there is no such attribute, then lang
9391  * returns false. If there is such an attribute, then lang returns
9392  * true if the attribute value is equal to the argument ignoring case,
9393  * or if there is some suffix starting with - such that the attribute
9394  * value is equal to the argument ignoring that suffix of the attribute
9395  * value and ignoring case.
9396  */
9397 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9398 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9399     xmlXPathObjectPtr val = NULL;
9400     const xmlChar *theLang = NULL;
9401     const xmlChar *lang;
9402     int ret = 0;
9403     int i;
9404 
9405     CHECK_ARITY(1);
9406     CAST_TO_STRING;
9407     CHECK_TYPE(XPATH_STRING);
9408     val = valuePop(ctxt);
9409     lang = val->stringval;
9410     theLang = xmlNodeGetLang(ctxt->context->node);
9411     if ((theLang != NULL) && (lang != NULL)) {
9412         for (i = 0;lang[i] != 0;i++)
9413 	    if (toupper(lang[i]) != toupper(theLang[i]))
9414 	        goto not_equal;
9415 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9416 	    ret = 1;
9417     }
9418 not_equal:
9419     if (theLang != NULL)
9420 	xmlFree((void *)theLang);
9421 
9422     xmlXPathReleaseObject(ctxt->context, val);
9423     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9424 }
9425 
9426 /**
9427  * xmlXPathNumberFunction:
9428  * @ctxt:  the XPath Parser context
9429  * @nargs:  the number of arguments
9430  *
9431  * Implement the number() XPath function
9432  *    number number(object?)
9433  */
9434 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9435 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9436     xmlXPathObjectPtr cur;
9437     double res;
9438 
9439     if (ctxt == NULL) return;
9440     if (nargs == 0) {
9441 	if (ctxt->context->node == NULL) {
9442 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9443 	} else {
9444 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9445 
9446 	    res = xmlXPathStringEvalNumber(content);
9447 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9448 	    xmlFree(content);
9449 	}
9450 	return;
9451     }
9452 
9453     CHECK_ARITY(1);
9454     cur = valuePop(ctxt);
9455     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9456 }
9457 
9458 /**
9459  * xmlXPathSumFunction:
9460  * @ctxt:  the XPath Parser context
9461  * @nargs:  the number of arguments
9462  *
9463  * Implement the sum() XPath function
9464  *    number sum(node-set)
9465  * The sum function returns the sum of the values of the nodes in
9466  * the argument node-set.
9467  */
9468 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9469 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9470     xmlXPathObjectPtr cur;
9471     int i;
9472     double res = 0.0;
9473 
9474     CHECK_ARITY(1);
9475     if ((ctxt->value == NULL) ||
9476 	((ctxt->value->type != XPATH_NODESET) &&
9477 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9478 	XP_ERROR(XPATH_INVALID_TYPE);
9479     cur = valuePop(ctxt);
9480 
9481     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9482 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9483 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9484 	}
9485     }
9486     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9487     xmlXPathReleaseObject(ctxt->context, cur);
9488 }
9489 
9490 /*
9491  * To assure working code on multiple platforms, we want to only depend
9492  * upon the characteristic truncation of converting a floating point value
9493  * to an integer.  Unfortunately, because of the different storage sizes
9494  * of our internal floating point value (double) and integer (int), we
9495  * can't directly convert (see bug 301162).  This macro is a messy
9496  * 'workaround'
9497  */
9498 #define XTRUNC(f, v)            \
9499     f = fmod((v), INT_MAX);     \
9500     f = (v) - (f) + (double)((int)(f));
9501 
9502 /**
9503  * xmlXPathFloorFunction:
9504  * @ctxt:  the XPath Parser context
9505  * @nargs:  the number of arguments
9506  *
9507  * Implement the floor() XPath function
9508  *    number floor(number)
9509  * The floor function returns the largest (closest to positive infinity)
9510  * number that is not greater than the argument and that is an integer.
9511  */
9512 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9513 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9514     double f;
9515 
9516     CHECK_ARITY(1);
9517     CAST_TO_NUMBER;
9518     CHECK_TYPE(XPATH_NUMBER);
9519 
9520     XTRUNC(f, ctxt->value->floatval);
9521     if (f != ctxt->value->floatval) {
9522 	if (ctxt->value->floatval > 0)
9523 	    ctxt->value->floatval = f;
9524 	else
9525 	    ctxt->value->floatval = f - 1;
9526     }
9527 }
9528 
9529 /**
9530  * xmlXPathCeilingFunction:
9531  * @ctxt:  the XPath Parser context
9532  * @nargs:  the number of arguments
9533  *
9534  * Implement the ceiling() XPath function
9535  *    number ceiling(number)
9536  * The ceiling function returns the smallest (closest to negative infinity)
9537  * number that is not less than the argument and that is an integer.
9538  */
9539 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9540 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541     double f;
9542 
9543     CHECK_ARITY(1);
9544     CAST_TO_NUMBER;
9545     CHECK_TYPE(XPATH_NUMBER);
9546 
9547 #if 0
9548     ctxt->value->floatval = ceil(ctxt->value->floatval);
9549 #else
9550     XTRUNC(f, ctxt->value->floatval);
9551     if (f != ctxt->value->floatval) {
9552 	if (ctxt->value->floatval > 0)
9553 	    ctxt->value->floatval = f + 1;
9554 	else {
9555 	    if (ctxt->value->floatval < 0 && f == 0)
9556 	        ctxt->value->floatval = xmlXPathNZERO;
9557 	    else
9558 	        ctxt->value->floatval = f;
9559 	}
9560 
9561     }
9562 #endif
9563 }
9564 
9565 /**
9566  * xmlXPathRoundFunction:
9567  * @ctxt:  the XPath Parser context
9568  * @nargs:  the number of arguments
9569  *
9570  * Implement the round() XPath function
9571  *    number round(number)
9572  * The round function returns the number that is closest to the
9573  * argument and that is an integer. If there are two such numbers,
9574  * then the one that is even is returned.
9575  */
9576 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9577 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578     double f;
9579 
9580     CHECK_ARITY(1);
9581     CAST_TO_NUMBER;
9582     CHECK_TYPE(XPATH_NUMBER);
9583 
9584     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9585 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9586 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9587 	(ctxt->value->floatval == 0.0))
9588 	return;
9589 
9590     XTRUNC(f, ctxt->value->floatval);
9591     if (ctxt->value->floatval < 0) {
9592 	if (ctxt->value->floatval < f - 0.5)
9593 	    ctxt->value->floatval = f - 1;
9594 	else
9595 	    ctxt->value->floatval = f;
9596 	if (ctxt->value->floatval == 0)
9597 	    ctxt->value->floatval = xmlXPathNZERO;
9598     } else {
9599 	if (ctxt->value->floatval < f + 0.5)
9600 	    ctxt->value->floatval = f;
9601 	else
9602 	    ctxt->value->floatval = f + 1;
9603     }
9604 }
9605 
9606 /************************************************************************
9607  *									*
9608  *			The Parser					*
9609  *									*
9610  ************************************************************************/
9611 
9612 /*
9613  * a few forward declarations since we use a recursive call based
9614  * implementation.
9615  */
9616 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9617 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9618 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9619 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9620 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9621 	                                  int qualified);
9622 
9623 /**
9624  * xmlXPathCurrentChar:
9625  * @ctxt:  the XPath parser context
9626  * @cur:  pointer to the beginning of the char
9627  * @len:  pointer to the length of the char read
9628  *
9629  * The current char value, if using UTF-8 this may actually span multiple
9630  * bytes in the input buffer.
9631  *
9632  * Returns the current char value and its length
9633  */
9634 
9635 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9636 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9637     unsigned char c;
9638     unsigned int val;
9639     const xmlChar *cur;
9640 
9641     if (ctxt == NULL)
9642 	return(0);
9643     cur = ctxt->cur;
9644 
9645     /*
9646      * We are supposed to handle UTF8, check it's valid
9647      * From rfc2044: encoding of the Unicode values on UTF-8:
9648      *
9649      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9650      * 0000 0000-0000 007F   0xxxxxxx
9651      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9652      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9653      *
9654      * Check for the 0x110000 limit too
9655      */
9656     c = *cur;
9657     if (c & 0x80) {
9658 	if ((cur[1] & 0xc0) != 0x80)
9659 	    goto encoding_error;
9660 	if ((c & 0xe0) == 0xe0) {
9661 
9662 	    if ((cur[2] & 0xc0) != 0x80)
9663 		goto encoding_error;
9664 	    if ((c & 0xf0) == 0xf0) {
9665 		if (((c & 0xf8) != 0xf0) ||
9666 		    ((cur[3] & 0xc0) != 0x80))
9667 		    goto encoding_error;
9668 		/* 4-byte code */
9669 		*len = 4;
9670 		val = (cur[0] & 0x7) << 18;
9671 		val |= (cur[1] & 0x3f) << 12;
9672 		val |= (cur[2] & 0x3f) << 6;
9673 		val |= cur[3] & 0x3f;
9674 	    } else {
9675 	      /* 3-byte code */
9676 		*len = 3;
9677 		val = (cur[0] & 0xf) << 12;
9678 		val |= (cur[1] & 0x3f) << 6;
9679 		val |= cur[2] & 0x3f;
9680 	    }
9681 	} else {
9682 	  /* 2-byte code */
9683 	    *len = 2;
9684 	    val = (cur[0] & 0x1f) << 6;
9685 	    val |= cur[1] & 0x3f;
9686 	}
9687 	if (!IS_CHAR(val)) {
9688 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9689 	}
9690 	return(val);
9691     } else {
9692 	/* 1-byte code */
9693 	*len = 1;
9694 	return((int) *cur);
9695     }
9696 encoding_error:
9697     /*
9698      * If we detect an UTF8 error that probably means that the
9699      * input encoding didn't get properly advertised in the
9700      * declaration header. Report the error and switch the encoding
9701      * to ISO-Latin-1 (if you don't like this policy, just declare the
9702      * encoding !)
9703      */
9704     *len = 0;
9705     XP_ERROR0(XPATH_ENCODING_ERROR);
9706 }
9707 
9708 /**
9709  * xmlXPathParseNCName:
9710  * @ctxt:  the XPath Parser context
9711  *
9712  * parse an XML namespace non qualified name.
9713  *
9714  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9715  *
9716  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9717  *                       CombiningChar | Extender
9718  *
9719  * Returns the namespace name or NULL
9720  */
9721 
9722 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9723 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9724     const xmlChar *in;
9725     xmlChar *ret;
9726     int count = 0;
9727 
9728     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9729     /*
9730      * Accelerator for simple ASCII names
9731      */
9732     in = ctxt->cur;
9733     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9734 	((*in >= 0x41) && (*in <= 0x5A)) ||
9735 	(*in == '_')) {
9736 	in++;
9737 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9738 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9739 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9740 	       (*in == '_') || (*in == '.') ||
9741 	       (*in == '-'))
9742 	    in++;
9743 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9744             (*in == '[') || (*in == ']') || (*in == ':') ||
9745             (*in == '@') || (*in == '*')) {
9746 	    count = in - ctxt->cur;
9747 	    if (count == 0)
9748 		return(NULL);
9749 	    ret = xmlStrndup(ctxt->cur, count);
9750 	    ctxt->cur = in;
9751 	    return(ret);
9752 	}
9753     }
9754     return(xmlXPathParseNameComplex(ctxt, 0));
9755 }
9756 
9757 
9758 /**
9759  * xmlXPathParseQName:
9760  * @ctxt:  the XPath Parser context
9761  * @prefix:  a xmlChar **
9762  *
9763  * parse an XML qualified name
9764  *
9765  * [NS 5] QName ::= (Prefix ':')? LocalPart
9766  *
9767  * [NS 6] Prefix ::= NCName
9768  *
9769  * [NS 7] LocalPart ::= NCName
9770  *
9771  * Returns the function returns the local part, and prefix is updated
9772  *   to get the Prefix if any.
9773  */
9774 
9775 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9776 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9777     xmlChar *ret = NULL;
9778 
9779     *prefix = NULL;
9780     ret = xmlXPathParseNCName(ctxt);
9781     if (ret && CUR == ':') {
9782         *prefix = ret;
9783 	NEXT;
9784 	ret = xmlXPathParseNCName(ctxt);
9785     }
9786     return(ret);
9787 }
9788 
9789 /**
9790  * xmlXPathParseName:
9791  * @ctxt:  the XPath Parser context
9792  *
9793  * parse an XML name
9794  *
9795  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9796  *                  CombiningChar | Extender
9797  *
9798  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9799  *
9800  * Returns the namespace name or NULL
9801  */
9802 
9803 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9804 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9805     const xmlChar *in;
9806     xmlChar *ret;
9807     int count = 0;
9808 
9809     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9810     /*
9811      * Accelerator for simple ASCII names
9812      */
9813     in = ctxt->cur;
9814     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9815 	((*in >= 0x41) && (*in <= 0x5A)) ||
9816 	(*in == '_') || (*in == ':')) {
9817 	in++;
9818 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9819 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9820 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9821 	       (*in == '_') || (*in == '-') ||
9822 	       (*in == ':') || (*in == '.'))
9823 	    in++;
9824 	if ((*in > 0) && (*in < 0x80)) {
9825 	    count = in - ctxt->cur;
9826 	    ret = xmlStrndup(ctxt->cur, count);
9827 	    ctxt->cur = in;
9828 	    return(ret);
9829 	}
9830     }
9831     return(xmlXPathParseNameComplex(ctxt, 1));
9832 }
9833 
9834 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9835 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9836     xmlChar buf[XML_MAX_NAMELEN + 5];
9837     int len = 0, l;
9838     int c;
9839 
9840     /*
9841      * Handler for more complex cases
9842      */
9843     c = CUR_CHAR(l);
9844     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9845         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9846         (c == '*') || /* accelerators */
9847 	(!IS_LETTER(c) && (c != '_') &&
9848          ((qualified) && (c != ':')))) {
9849 	return(NULL);
9850     }
9851 
9852     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9853 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9854             (c == '.') || (c == '-') ||
9855 	    (c == '_') || ((qualified) && (c == ':')) ||
9856 	    (IS_COMBINING(c)) ||
9857 	    (IS_EXTENDER(c)))) {
9858 	COPY_BUF(l,buf,len,c);
9859 	NEXTL(l);
9860 	c = CUR_CHAR(l);
9861 	if (len >= XML_MAX_NAMELEN) {
9862 	    /*
9863 	     * Okay someone managed to make a huge name, so he's ready to pay
9864 	     * for the processing speed.
9865 	     */
9866 	    xmlChar *buffer;
9867 	    int max = len * 2;
9868 
9869 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9870 	    if (buffer == NULL) {
9871 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9872 	    }
9873 	    memcpy(buffer, buf, len);
9874 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9875 		   (c == '.') || (c == '-') ||
9876 		   (c == '_') || ((qualified) && (c == ':')) ||
9877 		   (IS_COMBINING(c)) ||
9878 		   (IS_EXTENDER(c))) {
9879 		if (len + 10 > max) {
9880 		    max *= 2;
9881 		    buffer = (xmlChar *) xmlRealloc(buffer,
9882 			                            max * sizeof(xmlChar));
9883 		    if (buffer == NULL) {
9884 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9885 		    }
9886 		}
9887 		COPY_BUF(l,buffer,len,c);
9888 		NEXTL(l);
9889 		c = CUR_CHAR(l);
9890 	    }
9891 	    buffer[len] = 0;
9892 	    return(buffer);
9893 	}
9894     }
9895     if (len == 0)
9896 	return(NULL);
9897     return(xmlStrndup(buf, len));
9898 }
9899 
9900 #define MAX_FRAC 20
9901 
9902 /*
9903  * These are used as divisors for the fractional part of a number.
9904  * Since the table includes 1.0 (representing '0' fractional digits),
9905  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9906  */
9907 static double my_pow10[MAX_FRAC+1] = {
9908     1.0, 10.0, 100.0, 1000.0, 10000.0,
9909     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9910     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9911     100000000000000.0,
9912     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9913     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9914 };
9915 
9916 /**
9917  * xmlXPathStringEvalNumber:
9918  * @str:  A string to scan
9919  *
9920  *  [30a]  Float  ::= Number ('e' Digits?)?
9921  *
9922  *  [30]   Number ::=   Digits ('.' Digits?)?
9923  *                    | '.' Digits
9924  *  [31]   Digits ::=   [0-9]+
9925  *
9926  * Compile a Number in the string
9927  * In complement of the Number expression, this function also handles
9928  * negative values : '-' Number.
9929  *
9930  * Returns the double value.
9931  */
9932 double
xmlXPathStringEvalNumber(const xmlChar * str)9933 xmlXPathStringEvalNumber(const xmlChar *str) {
9934     const xmlChar *cur = str;
9935     double ret;
9936     int ok = 0;
9937     int isneg = 0;
9938     int exponent = 0;
9939     int is_exponent_negative = 0;
9940 #ifdef __GNUC__
9941     unsigned long tmp = 0;
9942     double temp;
9943 #endif
9944     if (cur == NULL) return(0);
9945     while (IS_BLANK_CH(*cur)) cur++;
9946     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9947         return(xmlXPathNAN);
9948     }
9949     if (*cur == '-') {
9950 	isneg = 1;
9951 	cur++;
9952     }
9953 
9954 #ifdef __GNUC__
9955     /*
9956      * tmp/temp is a workaround against a gcc compiler bug
9957      * http://veillard.com/gcc.bug
9958      */
9959     ret = 0;
9960     while ((*cur >= '0') && (*cur <= '9')) {
9961 	ret = ret * 10;
9962 	tmp = (*cur - '0');
9963 	ok = 1;
9964 	cur++;
9965 	temp = (double) tmp;
9966 	ret = ret + temp;
9967     }
9968 #else
9969     ret = 0;
9970     while ((*cur >= '0') && (*cur <= '9')) {
9971 	ret = ret * 10 + (*cur - '0');
9972 	ok = 1;
9973 	cur++;
9974     }
9975 #endif
9976 
9977     if (*cur == '.') {
9978 	int v, frac = 0;
9979 	double fraction = 0;
9980 
9981         cur++;
9982 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9983 	    return(xmlXPathNAN);
9984 	}
9985 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9986 	    v = (*cur - '0');
9987 	    fraction = fraction * 10 + v;
9988 	    frac = frac + 1;
9989 	    cur++;
9990 	}
9991 	fraction /= my_pow10[frac];
9992 	ret = ret + fraction;
9993 	while ((*cur >= '0') && (*cur <= '9'))
9994 	    cur++;
9995     }
9996     if ((*cur == 'e') || (*cur == 'E')) {
9997       cur++;
9998       if (*cur == '-') {
9999 	is_exponent_negative = 1;
10000 	cur++;
10001       } else if (*cur == '+') {
10002         cur++;
10003       }
10004       while ((*cur >= '0') && (*cur <= '9')) {
10005 	exponent = exponent * 10 + (*cur - '0');
10006 	cur++;
10007       }
10008     }
10009     while (IS_BLANK_CH(*cur)) cur++;
10010     if (*cur != 0) return(xmlXPathNAN);
10011     if (isneg) ret = -ret;
10012     if (is_exponent_negative) exponent = -exponent;
10013     ret *= pow(10.0, (double)exponent);
10014     return(ret);
10015 }
10016 
10017 /**
10018  * xmlXPathCompNumber:
10019  * @ctxt:  the XPath Parser context
10020  *
10021  *  [30]   Number ::=   Digits ('.' Digits?)?
10022  *                    | '.' Digits
10023  *  [31]   Digits ::=   [0-9]+
10024  *
10025  * Compile a Number, then push it on the stack
10026  *
10027  */
10028 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10029 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10030 {
10031     double ret = 0.0;
10032     double mult = 1;
10033     int ok = 0;
10034     int exponent = 0;
10035     int is_exponent_negative = 0;
10036 #ifdef __GNUC__
10037     unsigned long tmp = 0;
10038     double temp;
10039 #endif
10040 
10041     CHECK_ERROR;
10042     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10043         XP_ERROR(XPATH_NUMBER_ERROR);
10044     }
10045 #ifdef __GNUC__
10046     /*
10047      * tmp/temp is a workaround against a gcc compiler bug
10048      * http://veillard.com/gcc.bug
10049      */
10050     ret = 0;
10051     while ((CUR >= '0') && (CUR <= '9')) {
10052 	ret = ret * 10;
10053 	tmp = (CUR - '0');
10054         ok = 1;
10055         NEXT;
10056 	temp = (double) tmp;
10057 	ret = ret + temp;
10058     }
10059 #else
10060     ret = 0;
10061     while ((CUR >= '0') && (CUR <= '9')) {
10062 	ret = ret * 10 + (CUR - '0');
10063 	ok = 1;
10064 	NEXT;
10065     }
10066 #endif
10067     if (CUR == '.') {
10068         NEXT;
10069         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10070             XP_ERROR(XPATH_NUMBER_ERROR);
10071         }
10072         while ((CUR >= '0') && (CUR <= '9')) {
10073             mult /= 10;
10074             ret = ret + (CUR - '0') * mult;
10075             NEXT;
10076         }
10077     }
10078     if ((CUR == 'e') || (CUR == 'E')) {
10079         NEXT;
10080         if (CUR == '-') {
10081             is_exponent_negative = 1;
10082             NEXT;
10083         } else if (CUR == '+') {
10084 	    NEXT;
10085 	}
10086         while ((CUR >= '0') && (CUR <= '9')) {
10087             exponent = exponent * 10 + (CUR - '0');
10088             NEXT;
10089         }
10090         if (is_exponent_negative)
10091             exponent = -exponent;
10092         ret *= pow(10.0, (double) exponent);
10093     }
10094     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10095                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10096 }
10097 
10098 /**
10099  * xmlXPathParseLiteral:
10100  * @ctxt:  the XPath Parser context
10101  *
10102  * Parse a Literal
10103  *
10104  *  [29]   Literal ::=   '"' [^"]* '"'
10105  *                    | "'" [^']* "'"
10106  *
10107  * Returns the value found or NULL in case of error
10108  */
10109 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10110 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10111     const xmlChar *q;
10112     xmlChar *ret = NULL;
10113 
10114     if (CUR == '"') {
10115         NEXT;
10116 	q = CUR_PTR;
10117 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10118 	    NEXT;
10119 	if (!IS_CHAR_CH(CUR)) {
10120 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10121 	} else {
10122 	    ret = xmlStrndup(q, CUR_PTR - q);
10123 	    NEXT;
10124         }
10125     } else if (CUR == '\'') {
10126         NEXT;
10127 	q = CUR_PTR;
10128 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10129 	    NEXT;
10130 	if (!IS_CHAR_CH(CUR)) {
10131 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10132 	} else {
10133 	    ret = xmlStrndup(q, CUR_PTR - q);
10134 	    NEXT;
10135         }
10136     } else {
10137 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10138     }
10139     return(ret);
10140 }
10141 
10142 /**
10143  * xmlXPathCompLiteral:
10144  * @ctxt:  the XPath Parser context
10145  *
10146  * Parse a Literal and push it on the stack.
10147  *
10148  *  [29]   Literal ::=   '"' [^"]* '"'
10149  *                    | "'" [^']* "'"
10150  *
10151  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10152  */
10153 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10154 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10155     const xmlChar *q;
10156     xmlChar *ret = NULL;
10157 
10158     if (CUR == '"') {
10159         NEXT;
10160 	q = CUR_PTR;
10161 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10162 	    NEXT;
10163 	if (!IS_CHAR_CH(CUR)) {
10164 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10165 	} else {
10166 	    ret = xmlStrndup(q, CUR_PTR - q);
10167 	    NEXT;
10168         }
10169     } else if (CUR == '\'') {
10170         NEXT;
10171 	q = CUR_PTR;
10172 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10173 	    NEXT;
10174 	if (!IS_CHAR_CH(CUR)) {
10175 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10176 	} else {
10177 	    ret = xmlStrndup(q, CUR_PTR - q);
10178 	    NEXT;
10179         }
10180     } else {
10181 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10182     }
10183     if (ret == NULL) return;
10184     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10185 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10186     xmlFree(ret);
10187 }
10188 
10189 /**
10190  * xmlXPathCompVariableReference:
10191  * @ctxt:  the XPath Parser context
10192  *
10193  * Parse a VariableReference, evaluate it and push it on the stack.
10194  *
10195  * The variable bindings consist of a mapping from variable names
10196  * to variable values. The value of a variable is an object, which can be
10197  * of any of the types that are possible for the value of an expression,
10198  * and may also be of additional types not specified here.
10199  *
10200  * Early evaluation is possible since:
10201  * The variable bindings [...] used to evaluate a subexpression are
10202  * always the same as those used to evaluate the containing expression.
10203  *
10204  *  [36]   VariableReference ::=   '$' QName
10205  */
10206 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10207 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10208     xmlChar *name;
10209     xmlChar *prefix;
10210 
10211     SKIP_BLANKS;
10212     if (CUR != '$') {
10213 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10214     }
10215     NEXT;
10216     name = xmlXPathParseQName(ctxt, &prefix);
10217     if (name == NULL) {
10218 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10219     }
10220     ctxt->comp->last = -1;
10221     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10222 	           name, prefix);
10223     SKIP_BLANKS;
10224     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10225 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10226     }
10227 }
10228 
10229 /**
10230  * xmlXPathIsNodeType:
10231  * @name:  a name string
10232  *
10233  * Is the name given a NodeType one.
10234  *
10235  *  [38]   NodeType ::=   'comment'
10236  *                    | 'text'
10237  *                    | 'processing-instruction'
10238  *                    | 'node'
10239  *
10240  * Returns 1 if true 0 otherwise
10241  */
10242 int
xmlXPathIsNodeType(const xmlChar * name)10243 xmlXPathIsNodeType(const xmlChar *name) {
10244     if (name == NULL)
10245 	return(0);
10246 
10247     if (xmlStrEqual(name, BAD_CAST "node"))
10248 	return(1);
10249     if (xmlStrEqual(name, BAD_CAST "text"))
10250 	return(1);
10251     if (xmlStrEqual(name, BAD_CAST "comment"))
10252 	return(1);
10253     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10254 	return(1);
10255     return(0);
10256 }
10257 
10258 /**
10259  * xmlXPathCompFunctionCall:
10260  * @ctxt:  the XPath Parser context
10261  *
10262  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10263  *  [17]   Argument ::=   Expr
10264  *
10265  * Compile a function call, the evaluation of all arguments are
10266  * pushed on the stack
10267  */
10268 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10269 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10270     xmlChar *name;
10271     xmlChar *prefix;
10272     int nbargs = 0;
10273     int sort = 1;
10274 
10275     name = xmlXPathParseQName(ctxt, &prefix);
10276     if (name == NULL) {
10277 	xmlFree(prefix);
10278 	XP_ERROR(XPATH_EXPR_ERROR);
10279     }
10280     SKIP_BLANKS;
10281 #ifdef DEBUG_EXPR
10282     if (prefix == NULL)
10283 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10284 			name);
10285     else
10286 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10287 			prefix, name);
10288 #endif
10289 
10290     if (CUR != '(') {
10291 	XP_ERROR(XPATH_EXPR_ERROR);
10292     }
10293     NEXT;
10294     SKIP_BLANKS;
10295 
10296     /*
10297     * Optimization for count(): we don't need the node-set to be sorted.
10298     */
10299     if ((prefix == NULL) && (name[0] == 'c') &&
10300 	xmlStrEqual(name, BAD_CAST "count"))
10301     {
10302 	sort = 0;
10303     }
10304     ctxt->comp->last = -1;
10305     if (CUR != ')') {
10306 	while (CUR != 0) {
10307 	    int op1 = ctxt->comp->last;
10308 	    ctxt->comp->last = -1;
10309 	    xmlXPathCompileExpr(ctxt, sort);
10310 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10311 		xmlFree(name);
10312 		xmlFree(prefix);
10313 		return;
10314 	    }
10315 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10316 	    nbargs++;
10317 	    if (CUR == ')') break;
10318 	    if (CUR != ',') {
10319 		XP_ERROR(XPATH_EXPR_ERROR);
10320 	    }
10321 	    NEXT;
10322 	    SKIP_BLANKS;
10323 	}
10324     }
10325     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10326 	           name, prefix);
10327     NEXT;
10328     SKIP_BLANKS;
10329 }
10330 
10331 /**
10332  * xmlXPathCompPrimaryExpr:
10333  * @ctxt:  the XPath Parser context
10334  *
10335  *  [15]   PrimaryExpr ::=   VariableReference
10336  *                | '(' Expr ')'
10337  *                | Literal
10338  *                | Number
10339  *                | FunctionCall
10340  *
10341  * Compile a primary expression.
10342  */
10343 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10344 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10345     SKIP_BLANKS;
10346     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10347     else if (CUR == '(') {
10348 	NEXT;
10349 	SKIP_BLANKS;
10350 	xmlXPathCompileExpr(ctxt, 1);
10351 	CHECK_ERROR;
10352 	if (CUR != ')') {
10353 	    XP_ERROR(XPATH_EXPR_ERROR);
10354 	}
10355 	NEXT;
10356 	SKIP_BLANKS;
10357     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10358 	xmlXPathCompNumber(ctxt);
10359     } else if ((CUR == '\'') || (CUR == '"')) {
10360 	xmlXPathCompLiteral(ctxt);
10361     } else {
10362 	xmlXPathCompFunctionCall(ctxt);
10363     }
10364     SKIP_BLANKS;
10365 }
10366 
10367 /**
10368  * xmlXPathCompFilterExpr:
10369  * @ctxt:  the XPath Parser context
10370  *
10371  *  [20]   FilterExpr ::=   PrimaryExpr
10372  *               | FilterExpr Predicate
10373  *
10374  * Compile a filter expression.
10375  * Square brackets are used to filter expressions in the same way that
10376  * they are used in location paths. It is an error if the expression to
10377  * be filtered does not evaluate to a node-set. The context node list
10378  * used for evaluating the expression in square brackets is the node-set
10379  * to be filtered listed in document order.
10380  */
10381 
10382 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10383 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10384     xmlXPathCompPrimaryExpr(ctxt);
10385     CHECK_ERROR;
10386     SKIP_BLANKS;
10387 
10388     while (CUR == '[') {
10389 	xmlXPathCompPredicate(ctxt, 1);
10390 	SKIP_BLANKS;
10391     }
10392 
10393 
10394 }
10395 
10396 /**
10397  * xmlXPathScanName:
10398  * @ctxt:  the XPath Parser context
10399  *
10400  * Trickery: parse an XML name but without consuming the input flow
10401  * Needed to avoid insanity in the parser state.
10402  *
10403  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10404  *                  CombiningChar | Extender
10405  *
10406  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10407  *
10408  * [6] Names ::= Name (S Name)*
10409  *
10410  * Returns the Name parsed or NULL
10411  */
10412 
10413 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10414 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10415     int len = 0, l;
10416     int c;
10417     const xmlChar *cur;
10418     xmlChar *ret;
10419 
10420     cur = ctxt->cur;
10421 
10422     c = CUR_CHAR(l);
10423     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10424 	(!IS_LETTER(c) && (c != '_') &&
10425          (c != ':'))) {
10426 	return(NULL);
10427     }
10428 
10429     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10430 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10431             (c == '.') || (c == '-') ||
10432 	    (c == '_') || (c == ':') ||
10433 	    (IS_COMBINING(c)) ||
10434 	    (IS_EXTENDER(c)))) {
10435 	len += l;
10436 	NEXTL(l);
10437 	c = CUR_CHAR(l);
10438     }
10439     ret = xmlStrndup(cur, ctxt->cur - cur);
10440     ctxt->cur = cur;
10441     return(ret);
10442 }
10443 
10444 /**
10445  * xmlXPathCompPathExpr:
10446  * @ctxt:  the XPath Parser context
10447  *
10448  *  [19]   PathExpr ::=   LocationPath
10449  *               | FilterExpr
10450  *               | FilterExpr '/' RelativeLocationPath
10451  *               | FilterExpr '//' RelativeLocationPath
10452  *
10453  * Compile a path expression.
10454  * The / operator and // operators combine an arbitrary expression
10455  * and a relative location path. It is an error if the expression
10456  * does not evaluate to a node-set.
10457  * The / operator does composition in the same way as when / is
10458  * used in a location path. As in location paths, // is short for
10459  * /descendant-or-self::node()/.
10460  */
10461 
10462 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10463 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10464     int lc = 1;           /* Should we branch to LocationPath ?         */
10465     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10466 
10467     SKIP_BLANKS;
10468     if ((CUR == '$') || (CUR == '(') ||
10469 	(IS_ASCII_DIGIT(CUR)) ||
10470         (CUR == '\'') || (CUR == '"') ||
10471 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10472 	lc = 0;
10473     } else if (CUR == '*') {
10474 	/* relative or absolute location path */
10475 	lc = 1;
10476     } else if (CUR == '/') {
10477 	/* relative or absolute location path */
10478 	lc = 1;
10479     } else if (CUR == '@') {
10480 	/* relative abbreviated attribute location path */
10481 	lc = 1;
10482     } else if (CUR == '.') {
10483 	/* relative abbreviated attribute location path */
10484 	lc = 1;
10485     } else {
10486 	/*
10487 	 * Problem is finding if we have a name here whether it's:
10488 	 *   - a nodetype
10489 	 *   - a function call in which case it's followed by '('
10490 	 *   - an axis in which case it's followed by ':'
10491 	 *   - a element name
10492 	 * We do an a priori analysis here rather than having to
10493 	 * maintain parsed token content through the recursive function
10494 	 * calls. This looks uglier but makes the code easier to
10495 	 * read/write/debug.
10496 	 */
10497 	SKIP_BLANKS;
10498 	name = xmlXPathScanName(ctxt);
10499 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10500 #ifdef DEBUG_STEP
10501 	    xmlGenericError(xmlGenericErrorContext,
10502 		    "PathExpr: Axis\n");
10503 #endif
10504 	    lc = 1;
10505 	    xmlFree(name);
10506 	} else if (name != NULL) {
10507 	    int len =xmlStrlen(name);
10508 
10509 
10510 	    while (NXT(len) != 0) {
10511 		if (NXT(len) == '/') {
10512 		    /* element name */
10513 #ifdef DEBUG_STEP
10514 		    xmlGenericError(xmlGenericErrorContext,
10515 			    "PathExpr: AbbrRelLocation\n");
10516 #endif
10517 		    lc = 1;
10518 		    break;
10519 		} else if (IS_BLANK_CH(NXT(len))) {
10520 		    /* ignore blanks */
10521 		    ;
10522 		} else if (NXT(len) == ':') {
10523 #ifdef DEBUG_STEP
10524 		    xmlGenericError(xmlGenericErrorContext,
10525 			    "PathExpr: AbbrRelLocation\n");
10526 #endif
10527 		    lc = 1;
10528 		    break;
10529 		} else if ((NXT(len) == '(')) {
10530 		    /* Note Type or Function */
10531 		    if (xmlXPathIsNodeType(name)) {
10532 #ifdef DEBUG_STEP
10533 		        xmlGenericError(xmlGenericErrorContext,
10534 				"PathExpr: Type search\n");
10535 #endif
10536 			lc = 1;
10537 		    } else {
10538 #ifdef DEBUG_STEP
10539 		        xmlGenericError(xmlGenericErrorContext,
10540 				"PathExpr: function call\n");
10541 #endif
10542 			lc = 0;
10543 		    }
10544                     break;
10545 		} else if ((NXT(len) == '[')) {
10546 		    /* element name */
10547 #ifdef DEBUG_STEP
10548 		    xmlGenericError(xmlGenericErrorContext,
10549 			    "PathExpr: AbbrRelLocation\n");
10550 #endif
10551 		    lc = 1;
10552 		    break;
10553 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10554 			   (NXT(len) == '=')) {
10555 		    lc = 1;
10556 		    break;
10557 		} else {
10558 		    lc = 1;
10559 		    break;
10560 		}
10561 		len++;
10562 	    }
10563 	    if (NXT(len) == 0) {
10564 #ifdef DEBUG_STEP
10565 		xmlGenericError(xmlGenericErrorContext,
10566 			"PathExpr: AbbrRelLocation\n");
10567 #endif
10568 		/* element name */
10569 		lc = 1;
10570 	    }
10571 	    xmlFree(name);
10572 	} else {
10573 	    /* make sure all cases are covered explicitly */
10574 	    XP_ERROR(XPATH_EXPR_ERROR);
10575 	}
10576     }
10577 
10578     if (lc) {
10579 	if (CUR == '/') {
10580 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10581 	} else {
10582 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10583 	}
10584 	xmlXPathCompLocationPath(ctxt);
10585     } else {
10586 	xmlXPathCompFilterExpr(ctxt);
10587 	CHECK_ERROR;
10588 	if ((CUR == '/') && (NXT(1) == '/')) {
10589 	    SKIP(2);
10590 	    SKIP_BLANKS;
10591 
10592 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10593 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10594 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10595 
10596 	    xmlXPathCompRelativeLocationPath(ctxt);
10597 	} else if (CUR == '/') {
10598 	    xmlXPathCompRelativeLocationPath(ctxt);
10599 	}
10600     }
10601     SKIP_BLANKS;
10602 }
10603 
10604 /**
10605  * xmlXPathCompUnionExpr:
10606  * @ctxt:  the XPath Parser context
10607  *
10608  *  [18]   UnionExpr ::=   PathExpr
10609  *               | UnionExpr '|' PathExpr
10610  *
10611  * Compile an union expression.
10612  */
10613 
10614 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10615 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10616     xmlXPathCompPathExpr(ctxt);
10617     CHECK_ERROR;
10618     SKIP_BLANKS;
10619     while (CUR == '|') {
10620 	int op1 = ctxt->comp->last;
10621 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10622 
10623 	NEXT;
10624 	SKIP_BLANKS;
10625 	xmlXPathCompPathExpr(ctxt);
10626 
10627 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10628 
10629 	SKIP_BLANKS;
10630     }
10631 }
10632 
10633 /**
10634  * xmlXPathCompUnaryExpr:
10635  * @ctxt:  the XPath Parser context
10636  *
10637  *  [27]   UnaryExpr ::=   UnionExpr
10638  *                   | '-' UnaryExpr
10639  *
10640  * Compile an unary expression.
10641  */
10642 
10643 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10644 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10645     int minus = 0;
10646     int found = 0;
10647 
10648     SKIP_BLANKS;
10649     while (CUR == '-') {
10650         minus = 1 - minus;
10651 	found = 1;
10652 	NEXT;
10653 	SKIP_BLANKS;
10654     }
10655 
10656     xmlXPathCompUnionExpr(ctxt);
10657     CHECK_ERROR;
10658     if (found) {
10659 	if (minus)
10660 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10661 	else
10662 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10663     }
10664 }
10665 
10666 /**
10667  * xmlXPathCompMultiplicativeExpr:
10668  * @ctxt:  the XPath Parser context
10669  *
10670  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10671  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10672  *                   | MultiplicativeExpr 'div' UnaryExpr
10673  *                   | MultiplicativeExpr 'mod' UnaryExpr
10674  *  [34]   MultiplyOperator ::=   '*'
10675  *
10676  * Compile an Additive expression.
10677  */
10678 
10679 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10680 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10681     xmlXPathCompUnaryExpr(ctxt);
10682     CHECK_ERROR;
10683     SKIP_BLANKS;
10684     while ((CUR == '*') ||
10685            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10686            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10687 	int op = -1;
10688 	int op1 = ctxt->comp->last;
10689 
10690         if (CUR == '*') {
10691 	    op = 0;
10692 	    NEXT;
10693 	} else if (CUR == 'd') {
10694 	    op = 1;
10695 	    SKIP(3);
10696 	} else if (CUR == 'm') {
10697 	    op = 2;
10698 	    SKIP(3);
10699 	}
10700 	SKIP_BLANKS;
10701         xmlXPathCompUnaryExpr(ctxt);
10702 	CHECK_ERROR;
10703 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10704 	SKIP_BLANKS;
10705     }
10706 }
10707 
10708 /**
10709  * xmlXPathCompAdditiveExpr:
10710  * @ctxt:  the XPath Parser context
10711  *
10712  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10713  *                   | AdditiveExpr '+' MultiplicativeExpr
10714  *                   | AdditiveExpr '-' MultiplicativeExpr
10715  *
10716  * Compile an Additive expression.
10717  */
10718 
10719 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10720 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10721 
10722     xmlXPathCompMultiplicativeExpr(ctxt);
10723     CHECK_ERROR;
10724     SKIP_BLANKS;
10725     while ((CUR == '+') || (CUR == '-')) {
10726 	int plus;
10727 	int op1 = ctxt->comp->last;
10728 
10729         if (CUR == '+') plus = 1;
10730 	else plus = 0;
10731 	NEXT;
10732 	SKIP_BLANKS;
10733         xmlXPathCompMultiplicativeExpr(ctxt);
10734 	CHECK_ERROR;
10735 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10736 	SKIP_BLANKS;
10737     }
10738 }
10739 
10740 /**
10741  * xmlXPathCompRelationalExpr:
10742  * @ctxt:  the XPath Parser context
10743  *
10744  *  [24]   RelationalExpr ::=   AdditiveExpr
10745  *                 | RelationalExpr '<' AdditiveExpr
10746  *                 | RelationalExpr '>' AdditiveExpr
10747  *                 | RelationalExpr '<=' AdditiveExpr
10748  *                 | RelationalExpr '>=' AdditiveExpr
10749  *
10750  *  A <= B > C is allowed ? Answer from James, yes with
10751  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10752  *  which is basically what got implemented.
10753  *
10754  * Compile a Relational expression, then push the result
10755  * on the stack
10756  */
10757 
10758 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10759 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10760     xmlXPathCompAdditiveExpr(ctxt);
10761     CHECK_ERROR;
10762     SKIP_BLANKS;
10763     while ((CUR == '<') ||
10764            (CUR == '>') ||
10765            ((CUR == '<') && (NXT(1) == '=')) ||
10766            ((CUR == '>') && (NXT(1) == '='))) {
10767 	int inf, strict;
10768 	int op1 = ctxt->comp->last;
10769 
10770         if (CUR == '<') inf = 1;
10771 	else inf = 0;
10772 	if (NXT(1) == '=') strict = 0;
10773 	else strict = 1;
10774 	NEXT;
10775 	if (!strict) NEXT;
10776 	SKIP_BLANKS;
10777         xmlXPathCompAdditiveExpr(ctxt);
10778 	CHECK_ERROR;
10779 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10780 	SKIP_BLANKS;
10781     }
10782 }
10783 
10784 /**
10785  * xmlXPathCompEqualityExpr:
10786  * @ctxt:  the XPath Parser context
10787  *
10788  *  [23]   EqualityExpr ::=   RelationalExpr
10789  *                 | EqualityExpr '=' RelationalExpr
10790  *                 | EqualityExpr '!=' RelationalExpr
10791  *
10792  *  A != B != C is allowed ? Answer from James, yes with
10793  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10794  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10795  *  which is basically what got implemented.
10796  *
10797  * Compile an Equality expression.
10798  *
10799  */
10800 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10801 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10802     xmlXPathCompRelationalExpr(ctxt);
10803     CHECK_ERROR;
10804     SKIP_BLANKS;
10805     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10806 	int eq;
10807 	int op1 = ctxt->comp->last;
10808 
10809         if (CUR == '=') eq = 1;
10810 	else eq = 0;
10811 	NEXT;
10812 	if (!eq) NEXT;
10813 	SKIP_BLANKS;
10814         xmlXPathCompRelationalExpr(ctxt);
10815 	CHECK_ERROR;
10816 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10817 	SKIP_BLANKS;
10818     }
10819 }
10820 
10821 /**
10822  * xmlXPathCompAndExpr:
10823  * @ctxt:  the XPath Parser context
10824  *
10825  *  [22]   AndExpr ::=   EqualityExpr
10826  *                 | AndExpr 'and' EqualityExpr
10827  *
10828  * Compile an AND expression.
10829  *
10830  */
10831 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10832 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10833     xmlXPathCompEqualityExpr(ctxt);
10834     CHECK_ERROR;
10835     SKIP_BLANKS;
10836     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10837 	int op1 = ctxt->comp->last;
10838         SKIP(3);
10839 	SKIP_BLANKS;
10840         xmlXPathCompEqualityExpr(ctxt);
10841 	CHECK_ERROR;
10842 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10843 	SKIP_BLANKS;
10844     }
10845 }
10846 
10847 /**
10848  * xmlXPathCompileExpr:
10849  * @ctxt:  the XPath Parser context
10850  *
10851  *  [14]   Expr ::=   OrExpr
10852  *  [21]   OrExpr ::=   AndExpr
10853  *                 | OrExpr 'or' AndExpr
10854  *
10855  * Parse and compile an expression
10856  */
10857 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10858 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10859     xmlXPathCompAndExpr(ctxt);
10860     CHECK_ERROR;
10861     SKIP_BLANKS;
10862     while ((CUR == 'o') && (NXT(1) == 'r')) {
10863 	int op1 = ctxt->comp->last;
10864         SKIP(2);
10865 	SKIP_BLANKS;
10866         xmlXPathCompAndExpr(ctxt);
10867 	CHECK_ERROR;
10868 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10869 	op1 = ctxt->comp->nbStep;
10870 	SKIP_BLANKS;
10871     }
10872     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10873 	/* more ops could be optimized too */
10874 	/*
10875 	* This is the main place to eliminate sorting for
10876 	* operations which don't require a sorted node-set.
10877 	* E.g. count().
10878 	*/
10879 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10880     }
10881 }
10882 
10883 /**
10884  * xmlXPathCompPredicate:
10885  * @ctxt:  the XPath Parser context
10886  * @filter:  act as a filter
10887  *
10888  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10889  *  [9]   PredicateExpr ::=   Expr
10890  *
10891  * Compile a predicate expression
10892  */
10893 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10894 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10895     int op1 = ctxt->comp->last;
10896 
10897     SKIP_BLANKS;
10898     if (CUR != '[') {
10899 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10900     }
10901     NEXT;
10902     SKIP_BLANKS;
10903 
10904     ctxt->comp->last = -1;
10905     /*
10906     * This call to xmlXPathCompileExpr() will deactivate sorting
10907     * of the predicate result.
10908     * TODO: Sorting is still activated for filters, since I'm not
10909     *  sure if needed. Normally sorting should not be needed, since
10910     *  a filter can only diminish the number of items in a sequence,
10911     *  but won't change its order; so if the initial sequence is sorted,
10912     *  subsequent sorting is not needed.
10913     */
10914     if (! filter)
10915 	xmlXPathCompileExpr(ctxt, 0);
10916     else
10917 	xmlXPathCompileExpr(ctxt, 1);
10918     CHECK_ERROR;
10919 
10920     if (CUR != ']') {
10921 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922     }
10923 
10924     if (filter)
10925 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10926     else
10927 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10928 
10929     NEXT;
10930     SKIP_BLANKS;
10931 }
10932 
10933 /**
10934  * xmlXPathCompNodeTest:
10935  * @ctxt:  the XPath Parser context
10936  * @test:  pointer to a xmlXPathTestVal
10937  * @type:  pointer to a xmlXPathTypeVal
10938  * @prefix:  placeholder for a possible name prefix
10939  *
10940  * [7] NodeTest ::=   NameTest
10941  *		    | NodeType '(' ')'
10942  *		    | 'processing-instruction' '(' Literal ')'
10943  *
10944  * [37] NameTest ::=  '*'
10945  *		    | NCName ':' '*'
10946  *		    | QName
10947  * [38] NodeType ::= 'comment'
10948  *		   | 'text'
10949  *		   | 'processing-instruction'
10950  *		   | 'node'
10951  *
10952  * Returns the name found and updates @test, @type and @prefix appropriately
10953  */
10954 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)10955 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10956 	             xmlXPathTypeVal *type, const xmlChar **prefix,
10957 		     xmlChar *name) {
10958     int blanks;
10959 
10960     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10961 	STRANGE;
10962 	return(NULL);
10963     }
10964     *type = (xmlXPathTypeVal) 0;
10965     *test = (xmlXPathTestVal) 0;
10966     *prefix = NULL;
10967     SKIP_BLANKS;
10968 
10969     if ((name == NULL) && (CUR == '*')) {
10970 	/*
10971 	 * All elements
10972 	 */
10973 	NEXT;
10974 	*test = NODE_TEST_ALL;
10975 	return(NULL);
10976     }
10977 
10978     if (name == NULL)
10979 	name = xmlXPathParseNCName(ctxt);
10980     if (name == NULL) {
10981 	XP_ERRORNULL(XPATH_EXPR_ERROR);
10982     }
10983 
10984     blanks = IS_BLANK_CH(CUR);
10985     SKIP_BLANKS;
10986     if (CUR == '(') {
10987 	NEXT;
10988 	/*
10989 	 * NodeType or PI search
10990 	 */
10991 	if (xmlStrEqual(name, BAD_CAST "comment"))
10992 	    *type = NODE_TYPE_COMMENT;
10993 	else if (xmlStrEqual(name, BAD_CAST "node"))
10994 	    *type = NODE_TYPE_NODE;
10995 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10996 	    *type = NODE_TYPE_PI;
10997 	else if (xmlStrEqual(name, BAD_CAST "text"))
10998 	    *type = NODE_TYPE_TEXT;
10999 	else {
11000 	    if (name != NULL)
11001 		xmlFree(name);
11002 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11003 	}
11004 
11005 	*test = NODE_TEST_TYPE;
11006 
11007 	SKIP_BLANKS;
11008 	if (*type == NODE_TYPE_PI) {
11009 	    /*
11010 	     * Specific case: search a PI by name.
11011 	     */
11012 	    if (name != NULL)
11013 		xmlFree(name);
11014 	    name = NULL;
11015 	    if (CUR != ')') {
11016 		name = xmlXPathParseLiteral(ctxt);
11017 		CHECK_ERROR NULL;
11018 		*test = NODE_TEST_PI;
11019 		SKIP_BLANKS;
11020 	    }
11021 	}
11022 	if (CUR != ')') {
11023 	    if (name != NULL)
11024 		xmlFree(name);
11025 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11026 	}
11027 	NEXT;
11028 	return(name);
11029     }
11030     *test = NODE_TEST_NAME;
11031     if ((!blanks) && (CUR == ':')) {
11032 	NEXT;
11033 
11034 	/*
11035 	 * Since currently the parser context don't have a
11036 	 * namespace list associated:
11037 	 * The namespace name for this prefix can be computed
11038 	 * only at evaluation time. The compilation is done
11039 	 * outside of any context.
11040 	 */
11041 #if 0
11042 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11043 	if (name != NULL)
11044 	    xmlFree(name);
11045 	if (*prefix == NULL) {
11046 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11047 	}
11048 #else
11049 	*prefix = name;
11050 #endif
11051 
11052 	if (CUR == '*') {
11053 	    /*
11054 	     * All elements
11055 	     */
11056 	    NEXT;
11057 	    *test = NODE_TEST_ALL;
11058 	    return(NULL);
11059 	}
11060 
11061 	name = xmlXPathParseNCName(ctxt);
11062 	if (name == NULL) {
11063 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11064 	}
11065     }
11066     return(name);
11067 }
11068 
11069 /**
11070  * xmlXPathIsAxisName:
11071  * @name:  a preparsed name token
11072  *
11073  * [6] AxisName ::=   'ancestor'
11074  *                  | 'ancestor-or-self'
11075  *                  | 'attribute'
11076  *                  | 'child'
11077  *                  | 'descendant'
11078  *                  | 'descendant-or-self'
11079  *                  | 'following'
11080  *                  | 'following-sibling'
11081  *                  | 'namespace'
11082  *                  | 'parent'
11083  *                  | 'preceding'
11084  *                  | 'preceding-sibling'
11085  *                  | 'self'
11086  *
11087  * Returns the axis or 0
11088  */
11089 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11090 xmlXPathIsAxisName(const xmlChar *name) {
11091     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11092     switch (name[0]) {
11093 	case 'a':
11094 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11095 		ret = AXIS_ANCESTOR;
11096 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11097 		ret = AXIS_ANCESTOR_OR_SELF;
11098 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11099 		ret = AXIS_ATTRIBUTE;
11100 	    break;
11101 	case 'c':
11102 	    if (xmlStrEqual(name, BAD_CAST "child"))
11103 		ret = AXIS_CHILD;
11104 	    break;
11105 	case 'd':
11106 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11107 		ret = AXIS_DESCENDANT;
11108 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11109 		ret = AXIS_DESCENDANT_OR_SELF;
11110 	    break;
11111 	case 'f':
11112 	    if (xmlStrEqual(name, BAD_CAST "following"))
11113 		ret = AXIS_FOLLOWING;
11114 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11115 		ret = AXIS_FOLLOWING_SIBLING;
11116 	    break;
11117 	case 'n':
11118 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11119 		ret = AXIS_NAMESPACE;
11120 	    break;
11121 	case 'p':
11122 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11123 		ret = AXIS_PARENT;
11124 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11125 		ret = AXIS_PRECEDING;
11126 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11127 		ret = AXIS_PRECEDING_SIBLING;
11128 	    break;
11129 	case 's':
11130 	    if (xmlStrEqual(name, BAD_CAST "self"))
11131 		ret = AXIS_SELF;
11132 	    break;
11133     }
11134     return(ret);
11135 }
11136 
11137 /**
11138  * xmlXPathCompStep:
11139  * @ctxt:  the XPath Parser context
11140  *
11141  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11142  *                  | AbbreviatedStep
11143  *
11144  * [12] AbbreviatedStep ::=   '.' | '..'
11145  *
11146  * [5] AxisSpecifier ::= AxisName '::'
11147  *                  | AbbreviatedAxisSpecifier
11148  *
11149  * [13] AbbreviatedAxisSpecifier ::= '@'?
11150  *
11151  * Modified for XPtr range support as:
11152  *
11153  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11154  *                     | AbbreviatedStep
11155  *                     | 'range-to' '(' Expr ')' Predicate*
11156  *
11157  * Compile one step in a Location Path
11158  * A location step of . is short for self::node(). This is
11159  * particularly useful in conjunction with //. For example, the
11160  * location path .//para is short for
11161  * self::node()/descendant-or-self::node()/child::para
11162  * and so will select all para descendant elements of the context
11163  * node.
11164  * Similarly, a location step of .. is short for parent::node().
11165  * For example, ../title is short for parent::node()/child::title
11166  * and so will select the title children of the parent of the context
11167  * node.
11168  */
11169 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11170 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11171 #ifdef LIBXML_XPTR_ENABLED
11172     int rangeto = 0;
11173     int op2 = -1;
11174 #endif
11175 
11176     SKIP_BLANKS;
11177     if ((CUR == '.') && (NXT(1) == '.')) {
11178 	SKIP(2);
11179 	SKIP_BLANKS;
11180 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11181 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11182     } else if (CUR == '.') {
11183 	NEXT;
11184 	SKIP_BLANKS;
11185     } else {
11186 	xmlChar *name = NULL;
11187 	const xmlChar *prefix = NULL;
11188 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11189 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11190 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11191 	int op1;
11192 
11193 	/*
11194 	 * The modification needed for XPointer change to the production
11195 	 */
11196 #ifdef LIBXML_XPTR_ENABLED
11197 	if (ctxt->xptr) {
11198 	    name = xmlXPathParseNCName(ctxt);
11199 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11200                 op2 = ctxt->comp->last;
11201 		xmlFree(name);
11202 		SKIP_BLANKS;
11203 		if (CUR != '(') {
11204 		    XP_ERROR(XPATH_EXPR_ERROR);
11205 		}
11206 		NEXT;
11207 		SKIP_BLANKS;
11208 
11209 		xmlXPathCompileExpr(ctxt, 1);
11210 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11211 		CHECK_ERROR;
11212 
11213 		SKIP_BLANKS;
11214 		if (CUR != ')') {
11215 		    XP_ERROR(XPATH_EXPR_ERROR);
11216 		}
11217 		NEXT;
11218 		rangeto = 1;
11219 		goto eval_predicates;
11220 	    }
11221 	}
11222 #endif
11223 	if (CUR == '*') {
11224 	    axis = AXIS_CHILD;
11225 	} else {
11226 	    if (name == NULL)
11227 		name = xmlXPathParseNCName(ctxt);
11228 	    if (name != NULL) {
11229 		axis = xmlXPathIsAxisName(name);
11230 		if (axis != 0) {
11231 		    SKIP_BLANKS;
11232 		    if ((CUR == ':') && (NXT(1) == ':')) {
11233 			SKIP(2);
11234 			xmlFree(name);
11235 			name = NULL;
11236 		    } else {
11237 			/* an element name can conflict with an axis one :-\ */
11238 			axis = AXIS_CHILD;
11239 		    }
11240 		} else {
11241 		    axis = AXIS_CHILD;
11242 		}
11243 	    } else if (CUR == '@') {
11244 		NEXT;
11245 		axis = AXIS_ATTRIBUTE;
11246 	    } else {
11247 		axis = AXIS_CHILD;
11248 	    }
11249 	}
11250 
11251 	CHECK_ERROR;
11252 
11253 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11254 	if (test == 0)
11255 	    return;
11256 
11257         if ((prefix != NULL) && (ctxt->context != NULL) &&
11258 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11259 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11260 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11261 	    }
11262 	}
11263 #ifdef DEBUG_STEP
11264 	xmlGenericError(xmlGenericErrorContext,
11265 		"Basis : computing new set\n");
11266 #endif
11267 
11268 #ifdef DEBUG_STEP
11269 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11270 	if (ctxt->value == NULL)
11271 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11272 	else if (ctxt->value->nodesetval == NULL)
11273 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11274 	else
11275 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11276 #endif
11277 
11278 #ifdef LIBXML_XPTR_ENABLED
11279 eval_predicates:
11280 #endif
11281 	op1 = ctxt->comp->last;
11282 	ctxt->comp->last = -1;
11283 
11284 	SKIP_BLANKS;
11285 	while (CUR == '[') {
11286 	    xmlXPathCompPredicate(ctxt, 0);
11287 	}
11288 
11289 #ifdef LIBXML_XPTR_ENABLED
11290 	if (rangeto) {
11291 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11292 	} else
11293 #endif
11294 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11295 			   test, type, (void *)prefix, (void *)name);
11296 
11297     }
11298 #ifdef DEBUG_STEP
11299     xmlGenericError(xmlGenericErrorContext, "Step : ");
11300     if (ctxt->value == NULL)
11301 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11302     else if (ctxt->value->nodesetval == NULL)
11303 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11304     else
11305 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11306 		ctxt->value->nodesetval);
11307 #endif
11308 }
11309 
11310 /**
11311  * xmlXPathCompRelativeLocationPath:
11312  * @ctxt:  the XPath Parser context
11313  *
11314  *  [3]   RelativeLocationPath ::=   Step
11315  *                     | RelativeLocationPath '/' Step
11316  *                     | AbbreviatedRelativeLocationPath
11317  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11318  *
11319  * Compile a relative location path.
11320  */
11321 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11322 xmlXPathCompRelativeLocationPath
11323 (xmlXPathParserContextPtr ctxt) {
11324     SKIP_BLANKS;
11325     if ((CUR == '/') && (NXT(1) == '/')) {
11326 	SKIP(2);
11327 	SKIP_BLANKS;
11328 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11329 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11330     } else if (CUR == '/') {
11331 	    NEXT;
11332 	SKIP_BLANKS;
11333     }
11334     xmlXPathCompStep(ctxt);
11335     SKIP_BLANKS;
11336     while (CUR == '/') {
11337 	if ((CUR == '/') && (NXT(1) == '/')) {
11338 	    SKIP(2);
11339 	    SKIP_BLANKS;
11340 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11341 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11342 	    xmlXPathCompStep(ctxt);
11343 	} else if (CUR == '/') {
11344 	    NEXT;
11345 	    SKIP_BLANKS;
11346 	    xmlXPathCompStep(ctxt);
11347 	}
11348 	SKIP_BLANKS;
11349     }
11350 }
11351 
11352 /**
11353  * xmlXPathCompLocationPath:
11354  * @ctxt:  the XPath Parser context
11355  *
11356  *  [1]   LocationPath ::=   RelativeLocationPath
11357  *                     | AbsoluteLocationPath
11358  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11359  *                     | AbbreviatedAbsoluteLocationPath
11360  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11361  *                           '//' RelativeLocationPath
11362  *
11363  * Compile a location path
11364  *
11365  * // is short for /descendant-or-self::node()/. For example,
11366  * //para is short for /descendant-or-self::node()/child::para and
11367  * so will select any para element in the document (even a para element
11368  * that is a document element will be selected by //para since the
11369  * document element node is a child of the root node); div//para is
11370  * short for div/descendant-or-self::node()/child::para and so will
11371  * select all para descendants of div children.
11372  */
11373 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11374 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11375     SKIP_BLANKS;
11376     if (CUR != '/') {
11377         xmlXPathCompRelativeLocationPath(ctxt);
11378     } else {
11379 	while (CUR == '/') {
11380 	    if ((CUR == '/') && (NXT(1) == '/')) {
11381 		SKIP(2);
11382 		SKIP_BLANKS;
11383 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11384 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11385 		xmlXPathCompRelativeLocationPath(ctxt);
11386 	    } else if (CUR == '/') {
11387 		NEXT;
11388 		SKIP_BLANKS;
11389 		if ((CUR != 0 ) &&
11390 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11391 		     (CUR == '@') || (CUR == '*')))
11392 		    xmlXPathCompRelativeLocationPath(ctxt);
11393 	    }
11394 	}
11395     }
11396 }
11397 
11398 /************************************************************************
11399  *									*
11400  *		XPath precompiled expression evaluation			*
11401  *									*
11402  ************************************************************************/
11403 
11404 static int
11405 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11406 
11407 #ifdef DEBUG_STEP
11408 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11409 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11410 			  int nbNodes)
11411 {
11412     xmlGenericError(xmlGenericErrorContext, "new step : ");
11413     switch (op->value) {
11414         case AXIS_ANCESTOR:
11415             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11416             break;
11417         case AXIS_ANCESTOR_OR_SELF:
11418             xmlGenericError(xmlGenericErrorContext,
11419                             "axis 'ancestors-or-self' ");
11420             break;
11421         case AXIS_ATTRIBUTE:
11422             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11423             break;
11424         case AXIS_CHILD:
11425             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11426             break;
11427         case AXIS_DESCENDANT:
11428             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11429             break;
11430         case AXIS_DESCENDANT_OR_SELF:
11431             xmlGenericError(xmlGenericErrorContext,
11432                             "axis 'descendant-or-self' ");
11433             break;
11434         case AXIS_FOLLOWING:
11435             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11436             break;
11437         case AXIS_FOLLOWING_SIBLING:
11438             xmlGenericError(xmlGenericErrorContext,
11439                             "axis 'following-siblings' ");
11440             break;
11441         case AXIS_NAMESPACE:
11442             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11443             break;
11444         case AXIS_PARENT:
11445             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11446             break;
11447         case AXIS_PRECEDING:
11448             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11449             break;
11450         case AXIS_PRECEDING_SIBLING:
11451             xmlGenericError(xmlGenericErrorContext,
11452                             "axis 'preceding-sibling' ");
11453             break;
11454         case AXIS_SELF:
11455             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11456             break;
11457     }
11458     xmlGenericError(xmlGenericErrorContext,
11459 	" context contains %d nodes\n", nbNodes);
11460     switch (op->value2) {
11461         case NODE_TEST_NONE:
11462             xmlGenericError(xmlGenericErrorContext,
11463                             "           searching for none !!!\n");
11464             break;
11465         case NODE_TEST_TYPE:
11466             xmlGenericError(xmlGenericErrorContext,
11467                             "           searching for type %d\n", op->value3);
11468             break;
11469         case NODE_TEST_PI:
11470             xmlGenericError(xmlGenericErrorContext,
11471                             "           searching for PI !!!\n");
11472             break;
11473         case NODE_TEST_ALL:
11474             xmlGenericError(xmlGenericErrorContext,
11475                             "           searching for *\n");
11476             break;
11477         case NODE_TEST_NS:
11478             xmlGenericError(xmlGenericErrorContext,
11479                             "           searching for namespace %s\n",
11480                             op->value5);
11481             break;
11482         case NODE_TEST_NAME:
11483             xmlGenericError(xmlGenericErrorContext,
11484                             "           searching for name %s\n", op->value5);
11485             if (op->value4)
11486                 xmlGenericError(xmlGenericErrorContext,
11487                                 "           with namespace %s\n", op->value4);
11488             break;
11489     }
11490     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11491 }
11492 #endif /* DEBUG_STEP */
11493 
11494 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11495 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11496 			    xmlXPathStepOpPtr op,
11497 			    xmlNodeSetPtr set,
11498 			    int contextSize,
11499 			    int hasNsNodes)
11500 {
11501     if (op->ch1 != -1) {
11502 	xmlXPathCompExprPtr comp = ctxt->comp;
11503 	/*
11504 	* Process inner predicates first.
11505 	*/
11506 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11507 	    /*
11508 	    * TODO: raise an internal error.
11509 	    */
11510 	}
11511 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11512 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11513 	CHECK_ERROR0;
11514 	if (contextSize <= 0)
11515 	    return(0);
11516     }
11517     if (op->ch2 != -1) {
11518 	xmlXPathContextPtr xpctxt = ctxt->context;
11519 	xmlNodePtr contextNode, oldContextNode;
11520 	xmlDocPtr oldContextDoc;
11521 	int i, res, contextPos = 0, newContextSize;
11522 	xmlXPathStepOpPtr exprOp;
11523 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11524 
11525 #ifdef LIBXML_XPTR_ENABLED
11526 	/*
11527 	* URGENT TODO: Check the following:
11528 	*  We don't expect location sets if evaluating prediates, right?
11529 	*  Only filters should expect location sets, right?
11530 	*/
11531 #endif
11532 	/*
11533 	* SPEC XPath 1.0:
11534 	*  "For each node in the node-set to be filtered, the
11535 	*  PredicateExpr is evaluated with that node as the
11536 	*  context node, with the number of nodes in the
11537 	*  node-set as the context size, and with the proximity
11538 	*  position of the node in the node-set with respect to
11539 	*  the axis as the context position;"
11540 	* @oldset is the node-set" to be filtered.
11541 	*
11542 	* SPEC XPath 1.0:
11543 	*  "only predicates change the context position and
11544 	*  context size (see [2.4 Predicates])."
11545 	* Example:
11546 	*   node-set  context pos
11547 	*    nA         1
11548 	*    nB         2
11549 	*    nC         3
11550 	*   After applying predicate [position() > 1] :
11551 	*   node-set  context pos
11552 	*    nB         1
11553 	*    nC         2
11554 	*/
11555 	oldContextNode = xpctxt->node;
11556 	oldContextDoc = xpctxt->doc;
11557 	/*
11558 	* Get the expression of this predicate.
11559 	*/
11560 	exprOp = &ctxt->comp->steps[op->ch2];
11561 	newContextSize = 0;
11562 	for (i = 0; i < set->nodeNr; i++) {
11563 	    if (set->nodeTab[i] == NULL)
11564 		continue;
11565 
11566 	    contextNode = set->nodeTab[i];
11567 	    xpctxt->node = contextNode;
11568 	    xpctxt->contextSize = contextSize;
11569 	    xpctxt->proximityPosition = ++contextPos;
11570 
11571 	    /*
11572 	    * Also set the xpath document in case things like
11573 	    * key() are evaluated in the predicate.
11574 	    */
11575 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11576 		(contextNode->doc != NULL))
11577 		xpctxt->doc = contextNode->doc;
11578 	    /*
11579 	    * Evaluate the predicate expression with 1 context node
11580 	    * at a time; this node is packaged into a node set; this
11581 	    * node set is handed over to the evaluation mechanism.
11582 	    */
11583 	    if (contextObj == NULL)
11584 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11585 	    else
11586 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11587 		    contextNode);
11588 
11589 	    valuePush(ctxt, contextObj);
11590 
11591 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11592 
11593 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11594 		xmlXPathNodeSetClear(set, hasNsNodes);
11595 		newContextSize = 0;
11596 		goto evaluation_exit;
11597 	    }
11598 
11599 	    if (res != 0) {
11600 		newContextSize++;
11601 	    } else {
11602 		/*
11603 		* Remove the entry from the initial node set.
11604 		*/
11605 		set->nodeTab[i] = NULL;
11606 		if (contextNode->type == XML_NAMESPACE_DECL)
11607 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11608 	    }
11609 	    if (ctxt->value == contextObj) {
11610 		/*
11611 		* Don't free the temporary XPath object holding the
11612 		* context node, in order to avoid massive recreation
11613 		* inside this loop.
11614 		*/
11615 		valuePop(ctxt);
11616 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11617 	    } else {
11618 		/*
11619 		* TODO: The object was lost in the evaluation machinery.
11620 		*  Can this happen? Maybe in internal-error cases.
11621 		*/
11622 		contextObj = NULL;
11623 	    }
11624 	}
11625 
11626 	if (contextObj != NULL) {
11627 	    if (ctxt->value == contextObj)
11628 		valuePop(ctxt);
11629 	    xmlXPathReleaseObject(xpctxt, contextObj);
11630 	}
11631 evaluation_exit:
11632 	if (exprRes != NULL)
11633 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11634 	/*
11635 	* Reset/invalidate the context.
11636 	*/
11637 	xpctxt->node = oldContextNode;
11638 	xpctxt->doc = oldContextDoc;
11639 	xpctxt->contextSize = -1;
11640 	xpctxt->proximityPosition = -1;
11641 	return(newContextSize);
11642     }
11643     return(contextSize);
11644 }
11645 
11646 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11647 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11648 				      xmlXPathStepOpPtr op,
11649 				      xmlNodeSetPtr set,
11650 				      int contextSize,
11651 				      int minPos,
11652 				      int maxPos,
11653 				      int hasNsNodes)
11654 {
11655     if (op->ch1 != -1) {
11656 	xmlXPathCompExprPtr comp = ctxt->comp;
11657 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11658 	    /*
11659 	    * TODO: raise an internal error.
11660 	    */
11661 	}
11662 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11663 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11664 	CHECK_ERROR0;
11665 	if (contextSize <= 0)
11666 	    return(0);
11667     }
11668     /*
11669     * Check if the node set contains a sufficient number of nodes for
11670     * the requested range.
11671     */
11672     if (contextSize < minPos) {
11673 	xmlXPathNodeSetClear(set, hasNsNodes);
11674 	return(0);
11675     }
11676     if (op->ch2 == -1) {
11677 	/*
11678 	* TODO: Can this ever happen?
11679 	*/
11680 	return (contextSize);
11681     } else {
11682 	xmlDocPtr oldContextDoc;
11683 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11684 	xmlXPathStepOpPtr exprOp;
11685 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11686 	xmlNodePtr oldContextNode, contextNode = NULL;
11687 	xmlXPathContextPtr xpctxt = ctxt->context;
11688 
11689 #ifdef LIBXML_XPTR_ENABLED
11690 	    /*
11691 	    * URGENT TODO: Check the following:
11692 	    *  We don't expect location sets if evaluating prediates, right?
11693 	    *  Only filters should expect location sets, right?
11694 	*/
11695 #endif /* LIBXML_XPTR_ENABLED */
11696 
11697 	/*
11698 	* Save old context.
11699 	*/
11700 	oldContextNode = xpctxt->node;
11701 	oldContextDoc = xpctxt->doc;
11702 	/*
11703 	* Get the expression of this predicate.
11704 	*/
11705 	exprOp = &ctxt->comp->steps[op->ch2];
11706 	for (i = 0; i < set->nodeNr; i++) {
11707 	    if (set->nodeTab[i] == NULL)
11708 		continue;
11709 
11710 	    contextNode = set->nodeTab[i];
11711 	    xpctxt->node = contextNode;
11712 	    xpctxt->contextSize = contextSize;
11713 	    xpctxt->proximityPosition = ++contextPos;
11714 
11715 	    /*
11716 	    * Initialize the new set.
11717 	    * Also set the xpath document in case things like
11718 	    * key() evaluation are attempted on the predicate
11719 	    */
11720 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11721 		(contextNode->doc != NULL))
11722 		xpctxt->doc = contextNode->doc;
11723 	    /*
11724 	    * Evaluate the predicate expression with 1 context node
11725 	    * at a time; this node is packaged into a node set; this
11726 	    * node set is handed over to the evaluation mechanism.
11727 	    */
11728 	    if (contextObj == NULL)
11729 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11730 	    else
11731 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11732 		    contextNode);
11733 
11734 	    valuePush(ctxt, contextObj);
11735 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11736 
11737 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11738 	        xmlXPathObjectPtr tmp;
11739 		/* pop the result */
11740 		tmp = valuePop(ctxt);
11741 		xmlXPathReleaseObject(xpctxt, tmp);
11742 		/* then pop off contextObj, which will be freed later */
11743 		valuePop(ctxt);
11744 		goto evaluation_error;
11745 	    }
11746 
11747 	    if (res)
11748 		pos++;
11749 
11750 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11751 		/*
11752 		* Fits in the requested range.
11753 		*/
11754 		newContextSize++;
11755 		if (minPos == maxPos) {
11756 		    /*
11757 		    * Only 1 node was requested.
11758 		    */
11759 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11760 			/*
11761 			* As always: take care of those nasty
11762 			* namespace nodes.
11763 			*/
11764 			set->nodeTab[i] = NULL;
11765 		    }
11766 		    xmlXPathNodeSetClear(set, hasNsNodes);
11767 		    set->nodeNr = 1;
11768 		    set->nodeTab[0] = contextNode;
11769 		    goto evaluation_exit;
11770 		}
11771 		if (pos == maxPos) {
11772 		    /*
11773 		    * We are done.
11774 		    */
11775 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11776 		    goto evaluation_exit;
11777 		}
11778 	    } else {
11779 		/*
11780 		* Remove the entry from the initial node set.
11781 		*/
11782 		set->nodeTab[i] = NULL;
11783 		if (contextNode->type == XML_NAMESPACE_DECL)
11784 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11785 	    }
11786 	    if (exprRes != NULL) {
11787 		xmlXPathReleaseObject(ctxt->context, exprRes);
11788 		exprRes = NULL;
11789 	    }
11790 	    if (ctxt->value == contextObj) {
11791 		/*
11792 		* Don't free the temporary XPath object holding the
11793 		* context node, in order to avoid massive recreation
11794 		* inside this loop.
11795 		*/
11796 		valuePop(ctxt);
11797 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11798 	    } else {
11799 		/*
11800 		* The object was lost in the evaluation machinery.
11801 		* Can this happen? Maybe in case of internal-errors.
11802 		*/
11803 		contextObj = NULL;
11804 	    }
11805 	}
11806 	goto evaluation_exit;
11807 
11808 evaluation_error:
11809 	xmlXPathNodeSetClear(set, hasNsNodes);
11810 	newContextSize = 0;
11811 
11812 evaluation_exit:
11813 	if (contextObj != NULL) {
11814 	    if (ctxt->value == contextObj)
11815 		valuePop(ctxt);
11816 	    xmlXPathReleaseObject(xpctxt, contextObj);
11817 	}
11818 	if (exprRes != NULL)
11819 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11820 	/*
11821 	* Reset/invalidate the context.
11822 	*/
11823 	xpctxt->node = oldContextNode;
11824 	xpctxt->doc = oldContextDoc;
11825 	xpctxt->contextSize = -1;
11826 	xpctxt->proximityPosition = -1;
11827 	return(newContextSize);
11828     }
11829     return(contextSize);
11830 }
11831 
11832 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11833 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11834 			    xmlXPathStepOpPtr op,
11835 			    int *maxPos)
11836 {
11837 
11838     xmlXPathStepOpPtr exprOp;
11839 
11840     /*
11841     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11842     */
11843 
11844     /*
11845     * If not -1, then ch1 will point to:
11846     * 1) For predicates (XPATH_OP_PREDICATE):
11847     *    - an inner predicate operator
11848     * 2) For filters (XPATH_OP_FILTER):
11849     *    - an inner filter operater OR
11850     *    - an expression selecting the node set.
11851     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11852     */
11853     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11854 	return(0);
11855 
11856     if (op->ch2 != -1) {
11857 	exprOp = &ctxt->comp->steps[op->ch2];
11858     } else
11859 	return(0);
11860 
11861     if ((exprOp != NULL) &&
11862 	(exprOp->op == XPATH_OP_VALUE) &&
11863 	(exprOp->value4 != NULL) &&
11864 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11865     {
11866 	/*
11867 	* We have a "[n]" predicate here.
11868 	* TODO: Unfortunately this simplistic test here is not
11869 	* able to detect a position() predicate in compound
11870 	* expressions like "[@attr = 'a" and position() = 1],
11871 	* and even not the usage of position() in
11872 	* "[position() = 1]"; thus - obviously - a position-range,
11873 	* like it "[position() < 5]", is also not detected.
11874 	* Maybe we could rewrite the AST to ease the optimization.
11875 	*/
11876 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11877 
11878 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11879 	    (float) *maxPos)
11880 	{
11881 	    return(1);
11882 	}
11883     }
11884     return(0);
11885 }
11886 
11887 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11888 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11889                            xmlXPathStepOpPtr op,
11890 			   xmlNodePtr * first, xmlNodePtr * last,
11891 			   int toBool)
11892 {
11893 
11894 #define XP_TEST_HIT \
11895     if (hasAxisRange != 0) { \
11896 	if (++pos == maxPos) { \
11897 	    addNode(seq, cur); \
11898 	goto axis_range_end; } \
11899     } else { \
11900 	addNode(seq, cur); \
11901 	if (breakOnFirstHit) goto first_hit; }
11902 
11903 #define XP_TEST_HIT_NS \
11904     if (hasAxisRange != 0) { \
11905 	if (++pos == maxPos) { \
11906 	    hasNsNodes = 1; \
11907 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11908 	goto axis_range_end; } \
11909     } else { \
11910 	hasNsNodes = 1; \
11911 	xmlXPathNodeSetAddNs(seq, \
11912 	xpctxt->node, (xmlNsPtr) cur); \
11913 	if (breakOnFirstHit) goto first_hit; }
11914 
11915     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11916     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11917     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11918     const xmlChar *prefix = op->value4;
11919     const xmlChar *name = op->value5;
11920     const xmlChar *URI = NULL;
11921 
11922 #ifdef DEBUG_STEP
11923     int nbMatches = 0, prevMatches = 0;
11924 #endif
11925     int total = 0, hasNsNodes = 0;
11926     /* The popped object holding the context nodes */
11927     xmlXPathObjectPtr obj;
11928     /* The set of context nodes for the node tests */
11929     xmlNodeSetPtr contextSeq;
11930     int contextIdx;
11931     xmlNodePtr contextNode;
11932     /* The context node for a compound traversal */
11933     xmlNodePtr outerContextNode;
11934     /* The final resulting node set wrt to all context nodes */
11935     xmlNodeSetPtr outSeq;
11936     /*
11937     * The temporary resulting node set wrt 1 context node.
11938     * Used to feed predicate evaluation.
11939     */
11940     xmlNodeSetPtr seq;
11941     xmlNodePtr cur;
11942     /* First predicate operator */
11943     xmlXPathStepOpPtr predOp;
11944     int maxPos; /* The requested position() (when a "[n]" predicate) */
11945     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11946     int breakOnFirstHit;
11947 
11948     xmlXPathTraversalFunction next = NULL;
11949     /* compound axis traversal */
11950     xmlXPathTraversalFunctionExt outerNext = NULL;
11951     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11952     xmlXPathNodeSetMergeFunction mergeAndClear;
11953     xmlNodePtr oldContextNode;
11954     xmlXPathContextPtr xpctxt = ctxt->context;
11955 
11956 
11957     CHECK_TYPE0(XPATH_NODESET);
11958     obj = valuePop(ctxt);
11959     /*
11960     * Setup namespaces.
11961     */
11962     if (prefix != NULL) {
11963         URI = xmlXPathNsLookup(xpctxt, prefix);
11964         if (URI == NULL) {
11965 	    xmlXPathReleaseObject(xpctxt, obj);
11966             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11967 	}
11968     }
11969     /*
11970     * Setup axis.
11971     *
11972     * MAYBE FUTURE TODO: merging optimizations:
11973     * - If the nodes to be traversed wrt to the initial nodes and
11974     *   the current axis cannot overlap, then we could avoid searching
11975     *   for duplicates during the merge.
11976     *   But the question is how/when to evaluate if they cannot overlap.
11977     *   Example: if we know that for two initial nodes, the one is
11978     *   not in the ancestor-or-self axis of the other, then we could safely
11979     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11980     *   the descendant-or-self axis.
11981     */
11982     addNode = xmlXPathNodeSetAdd;
11983     mergeAndClear = xmlXPathNodeSetMergeAndClear;
11984     switch (axis) {
11985         case AXIS_ANCESTOR:
11986             first = NULL;
11987             next = xmlXPathNextAncestor;
11988             break;
11989         case AXIS_ANCESTOR_OR_SELF:
11990             first = NULL;
11991             next = xmlXPathNextAncestorOrSelf;
11992             break;
11993         case AXIS_ATTRIBUTE:
11994             first = NULL;
11995 	    last = NULL;
11996             next = xmlXPathNextAttribute;
11997 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11998             break;
11999         case AXIS_CHILD:
12000 	    last = NULL;
12001 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12002 		/*
12003 		* This iterator will give us only nodes which can
12004 		* hold element nodes.
12005 		*/
12006 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12007 	    }
12008 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12009 		(type == NODE_TYPE_NODE))
12010 	    {
12011 		/*
12012 		* Optimization if an element node type is 'element'.
12013 		*/
12014 		next = xmlXPathNextChildElement;
12015 	    } else
12016 		next = xmlXPathNextChild;
12017 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018             break;
12019         case AXIS_DESCENDANT:
12020 	    last = NULL;
12021             next = xmlXPathNextDescendant;
12022             break;
12023         case AXIS_DESCENDANT_OR_SELF:
12024 	    last = NULL;
12025             next = xmlXPathNextDescendantOrSelf;
12026             break;
12027         case AXIS_FOLLOWING:
12028 	    last = NULL;
12029             next = xmlXPathNextFollowing;
12030             break;
12031         case AXIS_FOLLOWING_SIBLING:
12032 	    last = NULL;
12033             next = xmlXPathNextFollowingSibling;
12034             break;
12035         case AXIS_NAMESPACE:
12036             first = NULL;
12037 	    last = NULL;
12038             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12039 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12040             break;
12041         case AXIS_PARENT:
12042             first = NULL;
12043             next = xmlXPathNextParent;
12044             break;
12045         case AXIS_PRECEDING:
12046             first = NULL;
12047             next = xmlXPathNextPrecedingInternal;
12048             break;
12049         case AXIS_PRECEDING_SIBLING:
12050             first = NULL;
12051             next = xmlXPathNextPrecedingSibling;
12052             break;
12053         case AXIS_SELF:
12054             first = NULL;
12055 	    last = NULL;
12056             next = xmlXPathNextSelf;
12057 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058             break;
12059     }
12060 
12061 #ifdef DEBUG_STEP
12062     xmlXPathDebugDumpStepAxis(op,
12063 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12064 #endif
12065 
12066     if (next == NULL) {
12067 	xmlXPathReleaseObject(xpctxt, obj);
12068         return(0);
12069     }
12070     contextSeq = obj->nodesetval;
12071     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12072 	xmlXPathReleaseObject(xpctxt, obj);
12073         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12074         return(0);
12075     }
12076     /*
12077     * Predicate optimization ---------------------------------------------
12078     * If this step has a last predicate, which contains a position(),
12079     * then we'll optimize (although not exactly "position()", but only
12080     * the  short-hand form, i.e., "[n]".
12081     *
12082     * Example - expression "/foo[parent::bar][1]":
12083     *
12084     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12085     *   ROOT                               -- op->ch1
12086     *   PREDICATE                          -- op->ch2 (predOp)
12087     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12088     *       SORT
12089     *         COLLECT  'parent' 'name' 'node' bar
12090     *           NODE
12091     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12092     *
12093     */
12094     maxPos = 0;
12095     predOp = NULL;
12096     hasPredicateRange = 0;
12097     hasAxisRange = 0;
12098     if (op->ch2 != -1) {
12099 	/*
12100 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12101 	*/
12102 	predOp = &ctxt->comp->steps[op->ch2];
12103 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12104 	    if (predOp->ch1 != -1) {
12105 		/*
12106 		* Use the next inner predicate operator.
12107 		*/
12108 		predOp = &ctxt->comp->steps[predOp->ch1];
12109 		hasPredicateRange = 1;
12110 	    } else {
12111 		/*
12112 		* There's no other predicate than the [n] predicate.
12113 		*/
12114 		predOp = NULL;
12115 		hasAxisRange = 1;
12116 	    }
12117 	}
12118     }
12119     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12120     /*
12121     * Axis traversal -----------------------------------------------------
12122     */
12123     /*
12124      * 2.3 Node Tests
12125      *  - For the attribute axis, the principal node type is attribute.
12126      *  - For the namespace axis, the principal node type is namespace.
12127      *  - For other axes, the principal node type is element.
12128      *
12129      * A node test * is true for any node of the
12130      * principal node type. For example, child::* will
12131      * select all element children of the context node
12132      */
12133     oldContextNode = xpctxt->node;
12134     addNode = xmlXPathNodeSetAddUnique;
12135     outSeq = NULL;
12136     seq = NULL;
12137     outerContextNode = NULL;
12138     contextNode = NULL;
12139     contextIdx = 0;
12140 
12141 
12142     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12143 	if (outerNext != NULL) {
12144 	    /*
12145 	    * This is a compound traversal.
12146 	    */
12147 	    if (contextNode == NULL) {
12148 		/*
12149 		* Set the context for the outer traversal.
12150 		*/
12151 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12152 		contextNode = outerNext(NULL, outerContextNode);
12153 	    } else
12154 		contextNode = outerNext(contextNode, outerContextNode);
12155 	    if (contextNode == NULL)
12156 		continue;
12157 	    /*
12158 	    * Set the context for the main traversal.
12159 	    */
12160 	    xpctxt->node = contextNode;
12161 	} else
12162 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12163 
12164 	if (seq == NULL) {
12165 	    seq = xmlXPathNodeSetCreate(NULL);
12166 	    if (seq == NULL) {
12167 		total = 0;
12168 		goto error;
12169 	    }
12170 	}
12171 	/*
12172 	* Traverse the axis and test the nodes.
12173 	*/
12174 	pos = 0;
12175 	cur = NULL;
12176 	hasNsNodes = 0;
12177         do {
12178             cur = next(ctxt, cur);
12179             if (cur == NULL)
12180                 break;
12181 
12182 	    /*
12183 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12184 	    */
12185             if ((first != NULL) && (*first != NULL)) {
12186 		if (*first == cur)
12187 		    break;
12188 		if (((total % 256) == 0) &&
12189 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12190 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12191 #else
12192 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12193 #endif
12194 		{
12195 		    break;
12196 		}
12197 	    }
12198 	    if ((last != NULL) && (*last != NULL)) {
12199 		if (*last == cur)
12200 		    break;
12201 		if (((total % 256) == 0) &&
12202 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12203 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12204 #else
12205 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12206 #endif
12207 		{
12208 		    break;
12209 		}
12210 	    }
12211 
12212             total++;
12213 
12214 #ifdef DEBUG_STEP
12215             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12216 #endif
12217 
12218 	    switch (test) {
12219                 case NODE_TEST_NONE:
12220 		    total = 0;
12221                     STRANGE
12222 		    goto error;
12223                 case NODE_TEST_TYPE:
12224 		    /*
12225 		    * TODO: Don't we need to use
12226 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12227 		    *  Surprisingly, some c14n tests fail, if we do this.
12228 		    */
12229 		    if (type == NODE_TYPE_NODE) {
12230 			switch (cur->type) {
12231 			    case XML_DOCUMENT_NODE:
12232 			    case XML_HTML_DOCUMENT_NODE:
12233 #ifdef LIBXML_DOCB_ENABLED
12234 			    case XML_DOCB_DOCUMENT_NODE:
12235 #endif
12236 			    case XML_ELEMENT_NODE:
12237 			    case XML_ATTRIBUTE_NODE:
12238 			    case XML_PI_NODE:
12239 			    case XML_COMMENT_NODE:
12240 			    case XML_CDATA_SECTION_NODE:
12241 			    case XML_TEXT_NODE:
12242 			    case XML_NAMESPACE_DECL:
12243 				XP_TEST_HIT
12244 				break;
12245 			    default:
12246 				break;
12247 			}
12248 		    } else if (cur->type == type) {
12249 			if (type == XML_NAMESPACE_DECL)
12250 			    XP_TEST_HIT_NS
12251 			else
12252 			    XP_TEST_HIT
12253 		    } else if ((type == NODE_TYPE_TEXT) &&
12254 			 (cur->type == XML_CDATA_SECTION_NODE))
12255 		    {
12256 			XP_TEST_HIT
12257 		    }
12258 		    break;
12259                 case NODE_TEST_PI:
12260                     if ((cur->type == XML_PI_NODE) &&
12261                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12262 		    {
12263 			XP_TEST_HIT
12264                     }
12265                     break;
12266                 case NODE_TEST_ALL:
12267                     if (axis == AXIS_ATTRIBUTE) {
12268                         if (cur->type == XML_ATTRIBUTE_NODE)
12269 			{
12270 			    XP_TEST_HIT
12271                         }
12272                     } else if (axis == AXIS_NAMESPACE) {
12273                         if (cur->type == XML_NAMESPACE_DECL)
12274 			{
12275 			    XP_TEST_HIT_NS
12276                         }
12277                     } else {
12278                         if (cur->type == XML_ELEMENT_NODE) {
12279                             if (prefix == NULL)
12280 			    {
12281 				XP_TEST_HIT
12282 
12283                             } else if ((cur->ns != NULL) &&
12284 				(xmlStrEqual(URI, cur->ns->href)))
12285 			    {
12286 				XP_TEST_HIT
12287                             }
12288                         }
12289                     }
12290                     break;
12291                 case NODE_TEST_NS:{
12292                         TODO;
12293                         break;
12294                     }
12295                 case NODE_TEST_NAME:
12296                     if (axis == AXIS_ATTRIBUTE) {
12297                         if (cur->type != XML_ATTRIBUTE_NODE)
12298 			    break;
12299 		    } else if (axis == AXIS_NAMESPACE) {
12300                         if (cur->type != XML_NAMESPACE_DECL)
12301 			    break;
12302 		    } else {
12303 		        if (cur->type != XML_ELEMENT_NODE)
12304 			    break;
12305 		    }
12306                     switch (cur->type) {
12307                         case XML_ELEMENT_NODE:
12308                             if (xmlStrEqual(name, cur->name)) {
12309                                 if (prefix == NULL) {
12310                                     if (cur->ns == NULL)
12311 				    {
12312 					XP_TEST_HIT
12313                                     }
12314                                 } else {
12315                                     if ((cur->ns != NULL) &&
12316                                         (xmlStrEqual(URI, cur->ns->href)))
12317 				    {
12318 					XP_TEST_HIT
12319                                     }
12320                                 }
12321                             }
12322                             break;
12323                         case XML_ATTRIBUTE_NODE:{
12324                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12325 
12326                                 if (xmlStrEqual(name, attr->name)) {
12327                                     if (prefix == NULL) {
12328                                         if ((attr->ns == NULL) ||
12329                                             (attr->ns->prefix == NULL))
12330 					{
12331 					    XP_TEST_HIT
12332                                         }
12333                                     } else {
12334                                         if ((attr->ns != NULL) &&
12335                                             (xmlStrEqual(URI,
12336 					      attr->ns->href)))
12337 					{
12338 					    XP_TEST_HIT
12339                                         }
12340                                     }
12341                                 }
12342                                 break;
12343                             }
12344                         case XML_NAMESPACE_DECL:
12345                             if (cur->type == XML_NAMESPACE_DECL) {
12346                                 xmlNsPtr ns = (xmlNsPtr) cur;
12347 
12348                                 if ((ns->prefix != NULL) && (name != NULL)
12349                                     && (xmlStrEqual(ns->prefix, name)))
12350 				{
12351 				    XP_TEST_HIT_NS
12352                                 }
12353                             }
12354                             break;
12355                         default:
12356                             break;
12357                     }
12358                     break;
12359 	    } /* switch(test) */
12360         } while (cur != NULL);
12361 
12362 	goto apply_predicates;
12363 
12364 axis_range_end: /* ----------------------------------------------------- */
12365 	/*
12366 	* We have a "/foo[n]", and position() = n was reached.
12367 	* Note that we can have as well "/foo/::parent::foo[1]", so
12368 	* a duplicate-aware merge is still needed.
12369 	* Merge with the result.
12370 	*/
12371 	if (outSeq == NULL) {
12372 	    outSeq = seq;
12373 	    seq = NULL;
12374 	} else
12375 	    outSeq = mergeAndClear(outSeq, seq, 0);
12376 	/*
12377 	* Break if only a true/false result was requested.
12378 	*/
12379 	if (toBool)
12380 	    break;
12381 	continue;
12382 
12383 first_hit: /* ---------------------------------------------------------- */
12384 	/*
12385 	* Break if only a true/false result was requested and
12386 	* no predicates existed and a node test succeeded.
12387 	*/
12388 	if (outSeq == NULL) {
12389 	    outSeq = seq;
12390 	    seq = NULL;
12391 	} else
12392 	    outSeq = mergeAndClear(outSeq, seq, 0);
12393 	break;
12394 
12395 #ifdef DEBUG_STEP
12396 	if (seq != NULL)
12397 	    nbMatches += seq->nodeNr;
12398 #endif
12399 
12400 apply_predicates: /* --------------------------------------------------- */
12401         /*
12402 	* Apply predicates.
12403 	*/
12404         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12405 	    /*
12406 	    * E.g. when we have a "/foo[some expression][n]".
12407 	    */
12408 	    /*
12409 	    * QUESTION TODO: The old predicate evaluation took into
12410 	    *  account location-sets.
12411 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12412 	    *  Do we expect such a set here?
12413 	    *  All what I learned now from the evaluation semantics
12414 	    *  does not indicate that a location-set will be processed
12415 	    *  here, so this looks OK.
12416 	    */
12417 	    /*
12418 	    * Iterate over all predicates, starting with the outermost
12419 	    * predicate.
12420 	    * TODO: Problem: we cannot execute the inner predicates first
12421 	    *  since we cannot go back *up* the operator tree!
12422 	    *  Options we have:
12423 	    *  1) Use of recursive functions (like is it currently done
12424 	    *     via xmlXPathCompOpEval())
12425 	    *  2) Add a predicate evaluation information stack to the
12426 	    *     context struct
12427 	    *  3) Change the way the operators are linked; we need a
12428 	    *     "parent" field on xmlXPathStepOp
12429 	    *
12430 	    * For the moment, I'll try to solve this with a recursive
12431 	    * function: xmlXPathCompOpEvalPredicate().
12432 	    */
12433 	    size = seq->nodeNr;
12434 	    if (hasPredicateRange != 0)
12435 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12436 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12437 	    else
12438 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12439 		    predOp, seq, size, hasNsNodes);
12440 
12441 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12442 		total = 0;
12443 		goto error;
12444 	    }
12445 	    /*
12446 	    * Add the filtered set of nodes to the result node set.
12447 	    */
12448 	    if (newSize == 0) {
12449 		/*
12450 		* The predicates filtered all nodes out.
12451 		*/
12452 		xmlXPathNodeSetClear(seq, hasNsNodes);
12453 	    } else if (seq->nodeNr > 0) {
12454 		/*
12455 		* Add to result set.
12456 		*/
12457 		if (outSeq == NULL) {
12458 		    if (size != newSize) {
12459 			/*
12460 			* We need to merge and clear here, since
12461 			* the sequence will contained NULLed entries.
12462 			*/
12463 			outSeq = mergeAndClear(NULL, seq, 1);
12464 		    } else {
12465 			outSeq = seq;
12466 			seq = NULL;
12467 		    }
12468 		} else
12469 		    outSeq = mergeAndClear(outSeq, seq,
12470 			(size != newSize) ? 1: 0);
12471 		/*
12472 		* Break if only a true/false result was requested.
12473 		*/
12474 		if (toBool)
12475 		    break;
12476 	    }
12477         } else if (seq->nodeNr > 0) {
12478 	    /*
12479 	    * Add to result set.
12480 	    */
12481 	    if (outSeq == NULL) {
12482 		outSeq = seq;
12483 		seq = NULL;
12484 	    } else {
12485 		outSeq = mergeAndClear(outSeq, seq, 0);
12486 	    }
12487 	}
12488     }
12489 
12490 error:
12491     if ((obj->boolval) && (obj->user != NULL)) {
12492 	/*
12493 	* QUESTION TODO: What does this do and why?
12494 	* TODO: Do we have to do this also for the "error"
12495 	* cleanup further down?
12496 	*/
12497 	ctxt->value->boolval = 1;
12498 	ctxt->value->user = obj->user;
12499 	obj->user = NULL;
12500 	obj->boolval = 0;
12501     }
12502     xmlXPathReleaseObject(xpctxt, obj);
12503 
12504     /*
12505     * Ensure we return at least an emtpy set.
12506     */
12507     if (outSeq == NULL) {
12508 	if ((seq != NULL) && (seq->nodeNr == 0))
12509 	    outSeq = seq;
12510 	else
12511 	    outSeq = xmlXPathNodeSetCreate(NULL);
12512         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12513     }
12514     if ((seq != NULL) && (seq != outSeq)) {
12515 	 xmlXPathFreeNodeSet(seq);
12516     }
12517     /*
12518     * Hand over the result. Better to push the set also in
12519     * case of errors.
12520     */
12521     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12522     /*
12523     * Reset the context node.
12524     */
12525     xpctxt->node = oldContextNode;
12526 
12527 #ifdef DEBUG_STEP
12528     xmlGenericError(xmlGenericErrorContext,
12529 	"\nExamined %d nodes, found %d nodes at that step\n",
12530 	total, nbMatches);
12531 #endif
12532 
12533     return(total);
12534 }
12535 
12536 static int
12537 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12538 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12539 
12540 /**
12541  * xmlXPathCompOpEvalFirst:
12542  * @ctxt:  the XPath parser context with the compiled expression
12543  * @op:  an XPath compiled operation
12544  * @first:  the first elem found so far
12545  *
12546  * Evaluate the Precompiled XPath operation searching only the first
12547  * element in document order
12548  *
12549  * Returns the number of examined objects.
12550  */
12551 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12552 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12553                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12554 {
12555     int total = 0, cur;
12556     xmlXPathCompExprPtr comp;
12557     xmlXPathObjectPtr arg1, arg2;
12558 
12559     CHECK_ERROR0;
12560     comp = ctxt->comp;
12561     switch (op->op) {
12562         case XPATH_OP_END:
12563             return (0);
12564         case XPATH_OP_UNION:
12565             total =
12566                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12567                                         first);
12568 	    CHECK_ERROR0;
12569             if ((ctxt->value != NULL)
12570                 && (ctxt->value->type == XPATH_NODESET)
12571                 && (ctxt->value->nodesetval != NULL)
12572                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12573                 /*
12574                  * limit tree traversing to first node in the result
12575                  */
12576 		/*
12577 		* OPTIMIZE TODO: This implicitely sorts
12578 		*  the result, even if not needed. E.g. if the argument
12579 		*  of the count() function, no sorting is needed.
12580 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12581 		*  aready sorted?
12582 		*/
12583 		if (ctxt->value->nodesetval->nodeNr > 1)
12584 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12585                 *first = ctxt->value->nodesetval->nodeTab[0];
12586             }
12587             cur =
12588                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12589                                         first);
12590 	    CHECK_ERROR0;
12591             CHECK_TYPE0(XPATH_NODESET);
12592             arg2 = valuePop(ctxt);
12593 
12594             CHECK_TYPE0(XPATH_NODESET);
12595             arg1 = valuePop(ctxt);
12596 
12597             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12598                                                     arg2->nodesetval);
12599             valuePush(ctxt, arg1);
12600 	    xmlXPathReleaseObject(ctxt->context, arg2);
12601             /* optimizer */
12602 	    if (total > cur)
12603 		xmlXPathCompSwap(op);
12604             return (total + cur);
12605         case XPATH_OP_ROOT:
12606             xmlXPathRoot(ctxt);
12607             return (0);
12608         case XPATH_OP_NODE:
12609             if (op->ch1 != -1)
12610                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12611 	    CHECK_ERROR0;
12612             if (op->ch2 != -1)
12613                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12614 	    CHECK_ERROR0;
12615 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12616 		ctxt->context->node));
12617             return (total);
12618         case XPATH_OP_RESET:
12619             if (op->ch1 != -1)
12620                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12621 	    CHECK_ERROR0;
12622             if (op->ch2 != -1)
12623                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12624 	    CHECK_ERROR0;
12625             ctxt->context->node = NULL;
12626             return (total);
12627         case XPATH_OP_COLLECT:{
12628                 if (op->ch1 == -1)
12629                     return (total);
12630 
12631                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12632 		CHECK_ERROR0;
12633 
12634                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12635                 return (total);
12636             }
12637         case XPATH_OP_VALUE:
12638             valuePush(ctxt,
12639                       xmlXPathCacheObjectCopy(ctxt->context,
12640 			(xmlXPathObjectPtr) op->value4));
12641             return (0);
12642         case XPATH_OP_SORT:
12643             if (op->ch1 != -1)
12644                 total +=
12645                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12646                                             first);
12647 	    CHECK_ERROR0;
12648             if ((ctxt->value != NULL)
12649                 && (ctxt->value->type == XPATH_NODESET)
12650                 && (ctxt->value->nodesetval != NULL)
12651 		&& (ctxt->value->nodesetval->nodeNr > 1))
12652                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12653             return (total);
12654 #ifdef XP_OPTIMIZED_FILTER_FIRST
12655 	case XPATH_OP_FILTER:
12656                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12657             return (total);
12658 #endif
12659         default:
12660             return (xmlXPathCompOpEval(ctxt, op));
12661     }
12662 }
12663 
12664 /**
12665  * xmlXPathCompOpEvalLast:
12666  * @ctxt:  the XPath parser context with the compiled expression
12667  * @op:  an XPath compiled operation
12668  * @last:  the last elem found so far
12669  *
12670  * Evaluate the Precompiled XPath operation searching only the last
12671  * element in document order
12672  *
12673  * Returns the number of nodes traversed
12674  */
12675 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12676 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12677                        xmlNodePtr * last)
12678 {
12679     int total = 0, cur;
12680     xmlXPathCompExprPtr comp;
12681     xmlXPathObjectPtr arg1, arg2;
12682     xmlNodePtr bak;
12683     xmlDocPtr bakd;
12684     int pp;
12685     int cs;
12686 
12687     CHECK_ERROR0;
12688     comp = ctxt->comp;
12689     switch (op->op) {
12690         case XPATH_OP_END:
12691             return (0);
12692         case XPATH_OP_UNION:
12693 	    bakd = ctxt->context->doc;
12694 	    bak = ctxt->context->node;
12695 	    pp = ctxt->context->proximityPosition;
12696 	    cs = ctxt->context->contextSize;
12697             total =
12698                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12699 	    CHECK_ERROR0;
12700             if ((ctxt->value != NULL)
12701                 && (ctxt->value->type == XPATH_NODESET)
12702                 && (ctxt->value->nodesetval != NULL)
12703                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12704                 /*
12705                  * limit tree traversing to first node in the result
12706                  */
12707 		if (ctxt->value->nodesetval->nodeNr > 1)
12708 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12709                 *last =
12710                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12711                                                      nodesetval->nodeNr -
12712                                                      1];
12713             }
12714 	    ctxt->context->doc = bakd;
12715 	    ctxt->context->node = bak;
12716 	    ctxt->context->proximityPosition = pp;
12717 	    ctxt->context->contextSize = cs;
12718             cur =
12719                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12720 	    CHECK_ERROR0;
12721             if ((ctxt->value != NULL)
12722                 && (ctxt->value->type == XPATH_NODESET)
12723                 && (ctxt->value->nodesetval != NULL)
12724                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12725             }
12726             CHECK_TYPE0(XPATH_NODESET);
12727             arg2 = valuePop(ctxt);
12728 
12729             CHECK_TYPE0(XPATH_NODESET);
12730             arg1 = valuePop(ctxt);
12731 
12732             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12733                                                     arg2->nodesetval);
12734             valuePush(ctxt, arg1);
12735 	    xmlXPathReleaseObject(ctxt->context, arg2);
12736             /* optimizer */
12737 	    if (total > cur)
12738 		xmlXPathCompSwap(op);
12739             return (total + cur);
12740         case XPATH_OP_ROOT:
12741             xmlXPathRoot(ctxt);
12742             return (0);
12743         case XPATH_OP_NODE:
12744             if (op->ch1 != -1)
12745                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12746 	    CHECK_ERROR0;
12747             if (op->ch2 != -1)
12748                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12749 	    CHECK_ERROR0;
12750 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12751 		ctxt->context->node));
12752             return (total);
12753         case XPATH_OP_RESET:
12754             if (op->ch1 != -1)
12755                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12756 	    CHECK_ERROR0;
12757             if (op->ch2 != -1)
12758                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12759 	    CHECK_ERROR0;
12760             ctxt->context->node = NULL;
12761             return (total);
12762         case XPATH_OP_COLLECT:{
12763                 if (op->ch1 == -1)
12764                     return (0);
12765 
12766                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767 		CHECK_ERROR0;
12768 
12769                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12770                 return (total);
12771             }
12772         case XPATH_OP_VALUE:
12773             valuePush(ctxt,
12774                       xmlXPathCacheObjectCopy(ctxt->context,
12775 			(xmlXPathObjectPtr) op->value4));
12776             return (0);
12777         case XPATH_OP_SORT:
12778             if (op->ch1 != -1)
12779                 total +=
12780                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12781                                            last);
12782 	    CHECK_ERROR0;
12783             if ((ctxt->value != NULL)
12784                 && (ctxt->value->type == XPATH_NODESET)
12785                 && (ctxt->value->nodesetval != NULL)
12786 		&& (ctxt->value->nodesetval->nodeNr > 1))
12787                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12788             return (total);
12789         default:
12790             return (xmlXPathCompOpEval(ctxt, op));
12791     }
12792 }
12793 
12794 #ifdef XP_OPTIMIZED_FILTER_FIRST
12795 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12796 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12797 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12798 {
12799     int total = 0;
12800     xmlXPathCompExprPtr comp;
12801     xmlXPathObjectPtr res;
12802     xmlXPathObjectPtr obj;
12803     xmlNodeSetPtr oldset;
12804     xmlNodePtr oldnode;
12805     xmlDocPtr oldDoc;
12806     int i;
12807 
12808     CHECK_ERROR0;
12809     comp = ctxt->comp;
12810     /*
12811     * Optimization for ()[last()] selection i.e. the last elem
12812     */
12813     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12814 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12815 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12816 	int f = comp->steps[op->ch2].ch1;
12817 
12818 	if ((f != -1) &&
12819 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12820 	    (comp->steps[f].value5 == NULL) &&
12821 	    (comp->steps[f].value == 0) &&
12822 	    (comp->steps[f].value4 != NULL) &&
12823 	    (xmlStrEqual
12824 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12825 	    xmlNodePtr last = NULL;
12826 
12827 	    total +=
12828 		xmlXPathCompOpEvalLast(ctxt,
12829 		    &comp->steps[op->ch1],
12830 		    &last);
12831 	    CHECK_ERROR0;
12832 	    /*
12833 	    * The nodeset should be in document order,
12834 	    * Keep only the last value
12835 	    */
12836 	    if ((ctxt->value != NULL) &&
12837 		(ctxt->value->type == XPATH_NODESET) &&
12838 		(ctxt->value->nodesetval != NULL) &&
12839 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12840 		(ctxt->value->nodesetval->nodeNr > 1)) {
12841 		ctxt->value->nodesetval->nodeTab[0] =
12842 		    ctxt->value->nodesetval->nodeTab[ctxt->
12843 		    value->
12844 		    nodesetval->
12845 		    nodeNr -
12846 		    1];
12847 		ctxt->value->nodesetval->nodeNr = 1;
12848 		*first = *(ctxt->value->nodesetval->nodeTab);
12849 	    }
12850 	    return (total);
12851 	}
12852     }
12853 
12854     if (op->ch1 != -1)
12855 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12856     CHECK_ERROR0;
12857     if (op->ch2 == -1)
12858 	return (total);
12859     if (ctxt->value == NULL)
12860 	return (total);
12861 
12862 #ifdef LIBXML_XPTR_ENABLED
12863     oldnode = ctxt->context->node;
12864     /*
12865     * Hum are we filtering the result of an XPointer expression
12866     */
12867     if (ctxt->value->type == XPATH_LOCATIONSET) {
12868 	xmlXPathObjectPtr tmp = NULL;
12869 	xmlLocationSetPtr newlocset = NULL;
12870 	xmlLocationSetPtr oldlocset;
12871 
12872 	/*
12873 	* Extract the old locset, and then evaluate the result of the
12874 	* expression for all the element in the locset. use it to grow
12875 	* up a new locset.
12876 	*/
12877 	CHECK_TYPE0(XPATH_LOCATIONSET);
12878 	obj = valuePop(ctxt);
12879 	oldlocset = obj->user;
12880 	ctxt->context->node = NULL;
12881 
12882 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12883 	    ctxt->context->contextSize = 0;
12884 	    ctxt->context->proximityPosition = 0;
12885 	    if (op->ch2 != -1)
12886 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12887 	    res = valuePop(ctxt);
12888 	    if (res != NULL) {
12889 		xmlXPathReleaseObject(ctxt->context, res);
12890 	    }
12891 	    valuePush(ctxt, obj);
12892 	    CHECK_ERROR0;
12893 	    return (total);
12894 	}
12895 	newlocset = xmlXPtrLocationSetCreate(NULL);
12896 
12897 	for (i = 0; i < oldlocset->locNr; i++) {
12898 	    /*
12899 	    * Run the evaluation with a node list made of a
12900 	    * single item in the nodelocset.
12901 	    */
12902 	    ctxt->context->node = oldlocset->locTab[i]->user;
12903 	    ctxt->context->contextSize = oldlocset->locNr;
12904 	    ctxt->context->proximityPosition = i + 1;
12905 	    if (tmp == NULL) {
12906 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12907 		    ctxt->context->node);
12908 	    } else {
12909 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12910 		    ctxt->context->node);
12911 	    }
12912 	    valuePush(ctxt, tmp);
12913 	    if (op->ch2 != -1)
12914 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12916 		xmlXPathFreeObject(obj);
12917 		return(0);
12918 	    }
12919 	    /*
12920 	    * The result of the evaluation need to be tested to
12921 	    * decided whether the filter succeeded or not
12922 	    */
12923 	    res = valuePop(ctxt);
12924 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12925 		xmlXPtrLocationSetAdd(newlocset,
12926 		    xmlXPathCacheObjectCopy(ctxt->context,
12927 			oldlocset->locTab[i]));
12928 	    }
12929 	    /*
12930 	    * Cleanup
12931 	    */
12932 	    if (res != NULL) {
12933 		xmlXPathReleaseObject(ctxt->context, res);
12934 	    }
12935 	    if (ctxt->value == tmp) {
12936 		valuePop(ctxt);
12937 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12938 		/*
12939 		* REVISIT TODO: Don't create a temporary nodeset
12940 		* for everly iteration.
12941 		*/
12942 		/* OLD: xmlXPathFreeObject(res); */
12943 	    } else
12944 		tmp = NULL;
12945 	    ctxt->context->node = NULL;
12946 	    /*
12947 	    * Only put the first node in the result, then leave.
12948 	    */
12949 	    if (newlocset->locNr > 0) {
12950 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12951 		break;
12952 	    }
12953 	}
12954 	if (tmp != NULL) {
12955 	    xmlXPathReleaseObject(ctxt->context, tmp);
12956 	}
12957 	/*
12958 	* The result is used as the new evaluation locset.
12959 	*/
12960 	xmlXPathReleaseObject(ctxt->context, obj);
12961 	ctxt->context->node = NULL;
12962 	ctxt->context->contextSize = -1;
12963 	ctxt->context->proximityPosition = -1;
12964 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12965 	ctxt->context->node = oldnode;
12966 	return (total);
12967     }
12968 #endif /* LIBXML_XPTR_ENABLED */
12969 
12970     /*
12971     * Extract the old set, and then evaluate the result of the
12972     * expression for all the element in the set. use it to grow
12973     * up a new set.
12974     */
12975     CHECK_TYPE0(XPATH_NODESET);
12976     obj = valuePop(ctxt);
12977     oldset = obj->nodesetval;
12978 
12979     oldnode = ctxt->context->node;
12980     oldDoc = ctxt->context->doc;
12981     ctxt->context->node = NULL;
12982 
12983     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12984 	ctxt->context->contextSize = 0;
12985 	ctxt->context->proximityPosition = 0;
12986 	/* QUESTION TODO: Why was this code commented out?
12987 	    if (op->ch2 != -1)
12988 		total +=
12989 		    xmlXPathCompOpEval(ctxt,
12990 			&comp->steps[op->ch2]);
12991 	    CHECK_ERROR0;
12992 	    res = valuePop(ctxt);
12993 	    if (res != NULL)
12994 		xmlXPathFreeObject(res);
12995 	*/
12996 	valuePush(ctxt, obj);
12997 	ctxt->context->node = oldnode;
12998 	CHECK_ERROR0;
12999     } else {
13000 	xmlNodeSetPtr newset;
13001 	xmlXPathObjectPtr tmp = NULL;
13002 	/*
13003 	* Initialize the new set.
13004 	* Also set the xpath document in case things like
13005 	* key() evaluation are attempted on the predicate
13006 	*/
13007 	newset = xmlXPathNodeSetCreate(NULL);
13008         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13009 
13010 	for (i = 0; i < oldset->nodeNr; i++) {
13011 	    /*
13012 	    * Run the evaluation with a node list made of
13013 	    * a single item in the nodeset.
13014 	    */
13015 	    ctxt->context->node = oldset->nodeTab[i];
13016 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13017 		(oldset->nodeTab[i]->doc != NULL))
13018 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13019 	    if (tmp == NULL) {
13020 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13021 		    ctxt->context->node);
13022 	    } else {
13023 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13024 		    ctxt->context->node);
13025 	    }
13026 	    valuePush(ctxt, tmp);
13027 	    ctxt->context->contextSize = oldset->nodeNr;
13028 	    ctxt->context->proximityPosition = i + 1;
13029 	    if (op->ch2 != -1)
13030 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13031 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13032 		xmlXPathFreeNodeSet(newset);
13033 		xmlXPathFreeObject(obj);
13034 		return(0);
13035 	    }
13036 	    /*
13037 	    * The result of the evaluation needs to be tested to
13038 	    * decide whether the filter succeeded or not
13039 	    */
13040 	    res = valuePop(ctxt);
13041 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13042 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13043 	    }
13044 	    /*
13045 	    * Cleanup
13046 	    */
13047 	    if (res != NULL) {
13048 		xmlXPathReleaseObject(ctxt->context, res);
13049 	    }
13050 	    if (ctxt->value == tmp) {
13051 		valuePop(ctxt);
13052 		/*
13053 		* Don't free the temporary nodeset
13054 		* in order to avoid massive recreation inside this
13055 		* loop.
13056 		*/
13057 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13058 	    } else
13059 		tmp = NULL;
13060 	    ctxt->context->node = NULL;
13061 	    /*
13062 	    * Only put the first node in the result, then leave.
13063 	    */
13064 	    if (newset->nodeNr > 0) {
13065 		*first = *(newset->nodeTab);
13066 		break;
13067 	    }
13068 	}
13069 	if (tmp != NULL) {
13070 	    xmlXPathReleaseObject(ctxt->context, tmp);
13071 	}
13072 	/*
13073 	* The result is used as the new evaluation set.
13074 	*/
13075 	xmlXPathReleaseObject(ctxt->context, obj);
13076 	ctxt->context->node = NULL;
13077 	ctxt->context->contextSize = -1;
13078 	ctxt->context->proximityPosition = -1;
13079 	/* may want to move this past the '}' later */
13080 	ctxt->context->doc = oldDoc;
13081 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13082     }
13083     ctxt->context->node = oldnode;
13084     return(total);
13085 }
13086 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13087 
13088 /**
13089  * xmlXPathCompOpEval:
13090  * @ctxt:  the XPath parser context with the compiled expression
13091  * @op:  an XPath compiled operation
13092  *
13093  * Evaluate the Precompiled XPath operation
13094  * Returns the number of nodes traversed
13095  */
13096 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13097 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13098 {
13099     int total = 0;
13100     int equal, ret;
13101     xmlXPathCompExprPtr comp;
13102     xmlXPathObjectPtr arg1, arg2;
13103     xmlNodePtr bak;
13104     xmlDocPtr bakd;
13105     int pp;
13106     int cs;
13107 
13108     CHECK_ERROR0;
13109     comp = ctxt->comp;
13110     switch (op->op) {
13111         case XPATH_OP_END:
13112             return (0);
13113         case XPATH_OP_AND:
13114 	    bakd = ctxt->context->doc;
13115 	    bak = ctxt->context->node;
13116 	    pp = ctxt->context->proximityPosition;
13117 	    cs = ctxt->context->contextSize;
13118             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13119 	    CHECK_ERROR0;
13120             xmlXPathBooleanFunction(ctxt, 1);
13121             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13122                 return (total);
13123             arg2 = valuePop(ctxt);
13124 	    ctxt->context->doc = bakd;
13125 	    ctxt->context->node = bak;
13126 	    ctxt->context->proximityPosition = pp;
13127 	    ctxt->context->contextSize = cs;
13128             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13129 	    if (ctxt->error) {
13130 		xmlXPathFreeObject(arg2);
13131 		return(0);
13132 	    }
13133             xmlXPathBooleanFunction(ctxt, 1);
13134             arg1 = valuePop(ctxt);
13135             arg1->boolval &= arg2->boolval;
13136             valuePush(ctxt, arg1);
13137 	    xmlXPathReleaseObject(ctxt->context, arg2);
13138             return (total);
13139         case XPATH_OP_OR:
13140 	    bakd = ctxt->context->doc;
13141 	    bak = ctxt->context->node;
13142 	    pp = ctxt->context->proximityPosition;
13143 	    cs = ctxt->context->contextSize;
13144             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145 	    CHECK_ERROR0;
13146             xmlXPathBooleanFunction(ctxt, 1);
13147             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13148                 return (total);
13149             arg2 = valuePop(ctxt);
13150 	    ctxt->context->doc = bakd;
13151 	    ctxt->context->node = bak;
13152 	    ctxt->context->proximityPosition = pp;
13153 	    ctxt->context->contextSize = cs;
13154             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155 	    if (ctxt->error) {
13156 		xmlXPathFreeObject(arg2);
13157 		return(0);
13158 	    }
13159             xmlXPathBooleanFunction(ctxt, 1);
13160             arg1 = valuePop(ctxt);
13161             arg1->boolval |= arg2->boolval;
13162             valuePush(ctxt, arg1);
13163 	    xmlXPathReleaseObject(ctxt->context, arg2);
13164             return (total);
13165         case XPATH_OP_EQUAL:
13166 	    bakd = ctxt->context->doc;
13167 	    bak = ctxt->context->node;
13168 	    pp = ctxt->context->proximityPosition;
13169 	    cs = ctxt->context->contextSize;
13170             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171 	    CHECK_ERROR0;
13172 	    ctxt->context->doc = bakd;
13173 	    ctxt->context->node = bak;
13174 	    ctxt->context->proximityPosition = pp;
13175 	    ctxt->context->contextSize = cs;
13176             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13177 	    CHECK_ERROR0;
13178 	    if (op->value)
13179 		equal = xmlXPathEqualValues(ctxt);
13180 	    else
13181 		equal = xmlXPathNotEqualValues(ctxt);
13182 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13183             return (total);
13184         case XPATH_OP_CMP:
13185 	    bakd = ctxt->context->doc;
13186 	    bak = ctxt->context->node;
13187 	    pp = ctxt->context->proximityPosition;
13188 	    cs = ctxt->context->contextSize;
13189             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13190 	    CHECK_ERROR0;
13191 	    ctxt->context->doc = bakd;
13192 	    ctxt->context->node = bak;
13193 	    ctxt->context->proximityPosition = pp;
13194 	    ctxt->context->contextSize = cs;
13195             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13196 	    CHECK_ERROR0;
13197             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13198 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13199             return (total);
13200         case XPATH_OP_PLUS:
13201 	    bakd = ctxt->context->doc;
13202 	    bak = ctxt->context->node;
13203 	    pp = ctxt->context->proximityPosition;
13204 	    cs = ctxt->context->contextSize;
13205             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206 	    CHECK_ERROR0;
13207             if (op->ch2 != -1) {
13208 		ctxt->context->doc = bakd;
13209 		ctxt->context->node = bak;
13210 		ctxt->context->proximityPosition = pp;
13211 		ctxt->context->contextSize = cs;
13212                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13213 	    }
13214 	    CHECK_ERROR0;
13215             if (op->value == 0)
13216                 xmlXPathSubValues(ctxt);
13217             else if (op->value == 1)
13218                 xmlXPathAddValues(ctxt);
13219             else if (op->value == 2)
13220                 xmlXPathValueFlipSign(ctxt);
13221             else if (op->value == 3) {
13222                 CAST_TO_NUMBER;
13223                 CHECK_TYPE0(XPATH_NUMBER);
13224             }
13225             return (total);
13226         case XPATH_OP_MULT:
13227 	    bakd = ctxt->context->doc;
13228 	    bak = ctxt->context->node;
13229 	    pp = ctxt->context->proximityPosition;
13230 	    cs = ctxt->context->contextSize;
13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232 	    CHECK_ERROR0;
13233 	    ctxt->context->doc = bakd;
13234 	    ctxt->context->node = bak;
13235 	    ctxt->context->proximityPosition = pp;
13236 	    ctxt->context->contextSize = cs;
13237             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238 	    CHECK_ERROR0;
13239             if (op->value == 0)
13240                 xmlXPathMultValues(ctxt);
13241             else if (op->value == 1)
13242                 xmlXPathDivValues(ctxt);
13243             else if (op->value == 2)
13244                 xmlXPathModValues(ctxt);
13245             return (total);
13246         case XPATH_OP_UNION:
13247 	    bakd = ctxt->context->doc;
13248 	    bak = ctxt->context->node;
13249 	    pp = ctxt->context->proximityPosition;
13250 	    cs = ctxt->context->contextSize;
13251             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13252 	    CHECK_ERROR0;
13253 	    ctxt->context->doc = bakd;
13254 	    ctxt->context->node = bak;
13255 	    ctxt->context->proximityPosition = pp;
13256 	    ctxt->context->contextSize = cs;
13257             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13258 	    CHECK_ERROR0;
13259             CHECK_TYPE0(XPATH_NODESET);
13260             arg2 = valuePop(ctxt);
13261 
13262             CHECK_TYPE0(XPATH_NODESET);
13263             arg1 = valuePop(ctxt);
13264 
13265 	    if ((arg1->nodesetval == NULL) ||
13266 		((arg2->nodesetval != NULL) &&
13267 		 (arg2->nodesetval->nodeNr != 0)))
13268 	    {
13269 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13270 							arg2->nodesetval);
13271 	    }
13272 
13273             valuePush(ctxt, arg1);
13274 	    xmlXPathReleaseObject(ctxt->context, arg2);
13275             return (total);
13276         case XPATH_OP_ROOT:
13277             xmlXPathRoot(ctxt);
13278             return (total);
13279         case XPATH_OP_NODE:
13280             if (op->ch1 != -1)
13281                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13282 	    CHECK_ERROR0;
13283             if (op->ch2 != -1)
13284                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13285 	    CHECK_ERROR0;
13286 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13287 		ctxt->context->node));
13288             return (total);
13289         case XPATH_OP_RESET:
13290             if (op->ch1 != -1)
13291                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292 	    CHECK_ERROR0;
13293             if (op->ch2 != -1)
13294                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295 	    CHECK_ERROR0;
13296             ctxt->context->node = NULL;
13297             return (total);
13298         case XPATH_OP_COLLECT:{
13299                 if (op->ch1 == -1)
13300                     return (total);
13301 
13302                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13303 		CHECK_ERROR0;
13304 
13305                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13306                 return (total);
13307             }
13308         case XPATH_OP_VALUE:
13309             valuePush(ctxt,
13310                       xmlXPathCacheObjectCopy(ctxt->context,
13311 			(xmlXPathObjectPtr) op->value4));
13312             return (total);
13313         case XPATH_OP_VARIABLE:{
13314 		xmlXPathObjectPtr val;
13315 
13316                 if (op->ch1 != -1)
13317                     total +=
13318                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13319                 if (op->value5 == NULL) {
13320 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13321 		    if (val == NULL) {
13322 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13323 			return(0);
13324 		    }
13325                     valuePush(ctxt, val);
13326 		} else {
13327                     const xmlChar *URI;
13328 
13329                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13330                     if (URI == NULL) {
13331                         xmlGenericError(xmlGenericErrorContext,
13332             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13333                                     (char *) op->value4, (char *)op->value5);
13334                         return (total);
13335                     }
13336 		    val = xmlXPathVariableLookupNS(ctxt->context,
13337                                                        op->value4, URI);
13338 		    if (val == NULL) {
13339 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13340 			return(0);
13341 		    }
13342                     valuePush(ctxt, val);
13343                 }
13344                 return (total);
13345             }
13346         case XPATH_OP_FUNCTION:{
13347                 xmlXPathFunction func;
13348                 const xmlChar *oldFunc, *oldFuncURI;
13349 		int i;
13350 
13351                 if (op->ch1 != -1)
13352                     total +=
13353                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13354 		if (ctxt->valueNr < op->value) {
13355 		    xmlGenericError(xmlGenericErrorContext,
13356 			    "xmlXPathCompOpEval: parameter error\n");
13357 		    ctxt->error = XPATH_INVALID_OPERAND;
13358 		    return (total);
13359 		}
13360 		for (i = 0; i < op->value; i++)
13361 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13362 			xmlGenericError(xmlGenericErrorContext,
13363 				"xmlXPathCompOpEval: parameter error\n");
13364 			ctxt->error = XPATH_INVALID_OPERAND;
13365 			return (total);
13366 		    }
13367                 if (op->cache != NULL)
13368                     XML_CAST_FPTR(func) = op->cache;
13369                 else {
13370                     const xmlChar *URI = NULL;
13371 
13372                     if (op->value5 == NULL)
13373                         func =
13374                             xmlXPathFunctionLookup(ctxt->context,
13375                                                    op->value4);
13376                     else {
13377                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13378                         if (URI == NULL) {
13379                             xmlGenericError(xmlGenericErrorContext,
13380             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13381                                     (char *)op->value4, (char *)op->value5);
13382                             return (total);
13383                         }
13384                         func = xmlXPathFunctionLookupNS(ctxt->context,
13385                                                         op->value4, URI);
13386                     }
13387                     if (func == NULL) {
13388                         xmlGenericError(xmlGenericErrorContext,
13389                                 "xmlXPathCompOpEval: function %s not found\n",
13390                                         (char *)op->value4);
13391                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13392                     }
13393                     op->cache = XML_CAST_FPTR(func);
13394                     op->cacheURI = (void *) URI;
13395                 }
13396                 oldFunc = ctxt->context->function;
13397                 oldFuncURI = ctxt->context->functionURI;
13398                 ctxt->context->function = op->value4;
13399                 ctxt->context->functionURI = op->cacheURI;
13400                 func(ctxt, op->value);
13401                 ctxt->context->function = oldFunc;
13402                 ctxt->context->functionURI = oldFuncURI;
13403                 return (total);
13404             }
13405         case XPATH_OP_ARG:
13406 	    bakd = ctxt->context->doc;
13407 	    bak = ctxt->context->node;
13408 	    pp = ctxt->context->proximityPosition;
13409 	    cs = ctxt->context->contextSize;
13410             if (op->ch1 != -1)
13411                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412 	    ctxt->context->contextSize = cs;
13413 	    ctxt->context->proximityPosition = pp;
13414 	    ctxt->context->node = bak;
13415 	    ctxt->context->doc = bakd;
13416 	    CHECK_ERROR0;
13417             if (op->ch2 != -1) {
13418                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419 	        ctxt->context->doc = bakd;
13420 	        ctxt->context->node = bak;
13421 	        CHECK_ERROR0;
13422 	    }
13423             return (total);
13424         case XPATH_OP_PREDICATE:
13425         case XPATH_OP_FILTER:{
13426                 xmlXPathObjectPtr res;
13427                 xmlXPathObjectPtr obj, tmp;
13428                 xmlNodeSetPtr newset = NULL;
13429                 xmlNodeSetPtr oldset;
13430                 xmlNodePtr oldnode;
13431 		xmlDocPtr oldDoc;
13432                 int i;
13433 
13434                 /*
13435                  * Optimization for ()[1] selection i.e. the first elem
13436                  */
13437                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13438 #ifdef XP_OPTIMIZED_FILTER_FIRST
13439 		    /*
13440 		    * FILTER TODO: Can we assume that the inner processing
13441 		    *  will result in an ordered list if we have an
13442 		    *  XPATH_OP_FILTER?
13443 		    *  What about an additional field or flag on
13444 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13445 		    *  to assume anything, so it would be more robust and
13446 		    *  easier to optimize.
13447 		    */
13448                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13449 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13450 #else
13451 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13452 #endif
13453                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13454                     xmlXPathObjectPtr val;
13455 
13456                     val = comp->steps[op->ch2].value4;
13457                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13458                         (val->floatval == 1.0)) {
13459                         xmlNodePtr first = NULL;
13460 
13461                         total +=
13462                             xmlXPathCompOpEvalFirst(ctxt,
13463                                                     &comp->steps[op->ch1],
13464                                                     &first);
13465 			CHECK_ERROR0;
13466                         /*
13467                          * The nodeset should be in document order,
13468                          * Keep only the first value
13469                          */
13470                         if ((ctxt->value != NULL) &&
13471                             (ctxt->value->type == XPATH_NODESET) &&
13472                             (ctxt->value->nodesetval != NULL) &&
13473                             (ctxt->value->nodesetval->nodeNr > 1))
13474                             ctxt->value->nodesetval->nodeNr = 1;
13475                         return (total);
13476                     }
13477                 }
13478                 /*
13479                  * Optimization for ()[last()] selection i.e. the last elem
13480                  */
13481                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13482                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13483                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13484                     int f = comp->steps[op->ch2].ch1;
13485 
13486                     if ((f != -1) &&
13487                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13488                         (comp->steps[f].value5 == NULL) &&
13489                         (comp->steps[f].value == 0) &&
13490                         (comp->steps[f].value4 != NULL) &&
13491                         (xmlStrEqual
13492                          (comp->steps[f].value4, BAD_CAST "last"))) {
13493                         xmlNodePtr last = NULL;
13494 
13495                         total +=
13496                             xmlXPathCompOpEvalLast(ctxt,
13497                                                    &comp->steps[op->ch1],
13498                                                    &last);
13499 			CHECK_ERROR0;
13500                         /*
13501                          * The nodeset should be in document order,
13502                          * Keep only the last value
13503                          */
13504                         if ((ctxt->value != NULL) &&
13505                             (ctxt->value->type == XPATH_NODESET) &&
13506                             (ctxt->value->nodesetval != NULL) &&
13507                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13508                             (ctxt->value->nodesetval->nodeNr > 1)) {
13509                             ctxt->value->nodesetval->nodeTab[0] =
13510                                 ctxt->value->nodesetval->nodeTab[ctxt->
13511                                                                  value->
13512                                                                  nodesetval->
13513                                                                  nodeNr -
13514                                                                  1];
13515                             ctxt->value->nodesetval->nodeNr = 1;
13516                         }
13517                         return (total);
13518                     }
13519                 }
13520 		/*
13521 		* Process inner predicates first.
13522 		* Example "index[parent::book][1]":
13523 		* ...
13524 		*   PREDICATE   <-- we are here "[1]"
13525 		*     PREDICATE <-- process "[parent::book]" first
13526 		*       SORT
13527 		*         COLLECT  'parent' 'name' 'node' book
13528 		*           NODE
13529 		*     ELEM Object is a number : 1
13530 		*/
13531                 if (op->ch1 != -1)
13532                     total +=
13533                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13534 		CHECK_ERROR0;
13535                 if (op->ch2 == -1)
13536                     return (total);
13537                 if (ctxt->value == NULL)
13538                     return (total);
13539 
13540                 oldnode = ctxt->context->node;
13541 
13542 #ifdef LIBXML_XPTR_ENABLED
13543                 /*
13544                  * Hum are we filtering the result of an XPointer expression
13545                  */
13546                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13547                     xmlLocationSetPtr newlocset = NULL;
13548                     xmlLocationSetPtr oldlocset;
13549 
13550                     /*
13551                      * Extract the old locset, and then evaluate the result of the
13552                      * expression for all the element in the locset. use it to grow
13553                      * up a new locset.
13554                      */
13555                     CHECK_TYPE0(XPATH_LOCATIONSET);
13556                     obj = valuePop(ctxt);
13557                     oldlocset = obj->user;
13558                     ctxt->context->node = NULL;
13559 
13560                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13561                         ctxt->context->contextSize = 0;
13562                         ctxt->context->proximityPosition = 0;
13563                         if (op->ch2 != -1)
13564                             total +=
13565                                 xmlXPathCompOpEval(ctxt,
13566                                                    &comp->steps[op->ch2]);
13567                         res = valuePop(ctxt);
13568                         if (res != NULL) {
13569 			    xmlXPathReleaseObject(ctxt->context, res);
13570 			}
13571                         valuePush(ctxt, obj);
13572                         CHECK_ERROR0;
13573                         return (total);
13574                     }
13575                     newlocset = xmlXPtrLocationSetCreate(NULL);
13576 
13577                     for (i = 0; i < oldlocset->locNr; i++) {
13578                         /*
13579                          * Run the evaluation with a node list made of a
13580                          * single item in the nodelocset.
13581                          */
13582                         ctxt->context->node = oldlocset->locTab[i]->user;
13583                         ctxt->context->contextSize = oldlocset->locNr;
13584                         ctxt->context->proximityPosition = i + 1;
13585 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13586 			    ctxt->context->node);
13587                         valuePush(ctxt, tmp);
13588 
13589                         if (op->ch2 != -1)
13590                             total +=
13591                                 xmlXPathCompOpEval(ctxt,
13592                                                    &comp->steps[op->ch2]);
13593 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13594 			    xmlXPathFreeObject(obj);
13595 			    return(0);
13596 			}
13597 
13598                         /*
13599                          * The result of the evaluation need to be tested to
13600                          * decided whether the filter succeeded or not
13601                          */
13602                         res = valuePop(ctxt);
13603                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13604                             xmlXPtrLocationSetAdd(newlocset,
13605                                                   xmlXPathObjectCopy
13606                                                   (oldlocset->locTab[i]));
13607                         }
13608 
13609                         /*
13610                          * Cleanup
13611                          */
13612                         if (res != NULL) {
13613 			    xmlXPathReleaseObject(ctxt->context, res);
13614 			}
13615                         if (ctxt->value == tmp) {
13616                             res = valuePop(ctxt);
13617 			    xmlXPathReleaseObject(ctxt->context, res);
13618                         }
13619 
13620                         ctxt->context->node = NULL;
13621                     }
13622 
13623                     /*
13624                      * The result is used as the new evaluation locset.
13625                      */
13626 		    xmlXPathReleaseObject(ctxt->context, obj);
13627                     ctxt->context->node = NULL;
13628                     ctxt->context->contextSize = -1;
13629                     ctxt->context->proximityPosition = -1;
13630                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13631                     ctxt->context->node = oldnode;
13632                     return (total);
13633                 }
13634 #endif /* LIBXML_XPTR_ENABLED */
13635 
13636                 /*
13637                  * Extract the old set, and then evaluate the result of the
13638                  * expression for all the element in the set. use it to grow
13639                  * up a new set.
13640                  */
13641                 CHECK_TYPE0(XPATH_NODESET);
13642                 obj = valuePop(ctxt);
13643                 oldset = obj->nodesetval;
13644 
13645                 oldnode = ctxt->context->node;
13646 		oldDoc = ctxt->context->doc;
13647                 ctxt->context->node = NULL;
13648 
13649                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13650                     ctxt->context->contextSize = 0;
13651                     ctxt->context->proximityPosition = 0;
13652 /*
13653                     if (op->ch2 != -1)
13654                         total +=
13655                             xmlXPathCompOpEval(ctxt,
13656                                                &comp->steps[op->ch2]);
13657 		    CHECK_ERROR0;
13658                     res = valuePop(ctxt);
13659                     if (res != NULL)
13660                         xmlXPathFreeObject(res);
13661 */
13662                     valuePush(ctxt, obj);
13663                     ctxt->context->node = oldnode;
13664                     CHECK_ERROR0;
13665                 } else {
13666 		    tmp = NULL;
13667                     /*
13668                      * Initialize the new set.
13669 		     * Also set the xpath document in case things like
13670 		     * key() evaluation are attempted on the predicate
13671                      */
13672                     newset = xmlXPathNodeSetCreate(NULL);
13673 		    /*
13674 		    * SPEC XPath 1.0:
13675 		    *  "For each node in the node-set to be filtered, the
13676 		    *  PredicateExpr is evaluated with that node as the
13677 		    *  context node, with the number of nodes in the
13678 		    *  node-set as the context size, and with the proximity
13679 		    *  position of the node in the node-set with respect to
13680 		    *  the axis as the context position;"
13681 		    * @oldset is the node-set" to be filtered.
13682 		    *
13683 		    * SPEC XPath 1.0:
13684 		    *  "only predicates change the context position and
13685 		    *  context size (see [2.4 Predicates])."
13686 		    * Example:
13687 		    *   node-set  context pos
13688 		    *    nA         1
13689 		    *    nB         2
13690 		    *    nC         3
13691 		    *   After applying predicate [position() > 1] :
13692 		    *   node-set  context pos
13693 		    *    nB         1
13694 		    *    nC         2
13695 		    *
13696 		    * removed the first node in the node-set, then
13697 		    * the context position of the
13698 		    */
13699                     for (i = 0; i < oldset->nodeNr; i++) {
13700                         /*
13701                          * Run the evaluation with a node list made of
13702                          * a single item in the nodeset.
13703                          */
13704                         ctxt->context->node = oldset->nodeTab[i];
13705 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13706 			    (oldset->nodeTab[i]->doc != NULL))
13707 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13708 			if (tmp == NULL) {
13709 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13710 				ctxt->context->node);
13711 			} else {
13712 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13713 				ctxt->context->node);
13714 			}
13715                         valuePush(ctxt, tmp);
13716                         ctxt->context->contextSize = oldset->nodeNr;
13717                         ctxt->context->proximityPosition = i + 1;
13718 			/*
13719 			* Evaluate the predicate against the context node.
13720 			* Can/should we optimize position() predicates
13721 			* here (e.g. "[1]")?
13722 			*/
13723                         if (op->ch2 != -1)
13724                             total +=
13725                                 xmlXPathCompOpEval(ctxt,
13726                                                    &comp->steps[op->ch2]);
13727 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13728 			    xmlXPathFreeNodeSet(newset);
13729 			    xmlXPathFreeObject(obj);
13730 			    return(0);
13731 			}
13732 
13733                         /*
13734                          * The result of the evaluation needs to be tested to
13735                          * decide whether the filter succeeded or not
13736                          */
13737 			/*
13738 			* OPTIMIZE TODO: Can we use
13739 			* xmlXPathNodeSetAdd*Unique()* instead?
13740 			*/
13741                         res = valuePop(ctxt);
13742                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13743                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13744                         }
13745 
13746                         /*
13747                          * Cleanup
13748                          */
13749                         if (res != NULL) {
13750 			    xmlXPathReleaseObject(ctxt->context, res);
13751 			}
13752                         if (ctxt->value == tmp) {
13753                             valuePop(ctxt);
13754 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13755 			    /*
13756 			    * Don't free the temporary nodeset
13757 			    * in order to avoid massive recreation inside this
13758 			    * loop.
13759 			    */
13760                         } else
13761 			    tmp = NULL;
13762                         ctxt->context->node = NULL;
13763                     }
13764 		    if (tmp != NULL)
13765 			xmlXPathReleaseObject(ctxt->context, tmp);
13766                     /*
13767                      * The result is used as the new evaluation set.
13768                      */
13769 		    xmlXPathReleaseObject(ctxt->context, obj);
13770                     ctxt->context->node = NULL;
13771                     ctxt->context->contextSize = -1;
13772                     ctxt->context->proximityPosition = -1;
13773 		    /* may want to move this past the '}' later */
13774 		    ctxt->context->doc = oldDoc;
13775 		    valuePush(ctxt,
13776 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13777                 }
13778                 ctxt->context->node = oldnode;
13779                 return (total);
13780             }
13781         case XPATH_OP_SORT:
13782             if (op->ch1 != -1)
13783                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13784 	    CHECK_ERROR0;
13785             if ((ctxt->value != NULL) &&
13786                 (ctxt->value->type == XPATH_NODESET) &&
13787                 (ctxt->value->nodesetval != NULL) &&
13788 		(ctxt->value->nodesetval->nodeNr > 1))
13789 	    {
13790                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13791 	    }
13792             return (total);
13793 #ifdef LIBXML_XPTR_ENABLED
13794         case XPATH_OP_RANGETO:{
13795                 xmlXPathObjectPtr range;
13796                 xmlXPathObjectPtr res, obj;
13797                 xmlXPathObjectPtr tmp;
13798                 xmlLocationSetPtr newlocset = NULL;
13799 		    xmlLocationSetPtr oldlocset;
13800                 xmlNodeSetPtr oldset;
13801                 int i, j;
13802 
13803                 if (op->ch1 != -1)
13804                     total +=
13805                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13806                 if (op->ch2 == -1)
13807                     return (total);
13808 
13809                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13810                     /*
13811                      * Extract the old locset, and then evaluate the result of the
13812                      * expression for all the element in the locset. use it to grow
13813                      * up a new locset.
13814                      */
13815                     CHECK_TYPE0(XPATH_LOCATIONSET);
13816                     obj = valuePop(ctxt);
13817                     oldlocset = obj->user;
13818 
13819                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13820 		        ctxt->context->node = NULL;
13821                         ctxt->context->contextSize = 0;
13822                         ctxt->context->proximityPosition = 0;
13823                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13824                         res = valuePop(ctxt);
13825                         if (res != NULL) {
13826 			    xmlXPathReleaseObject(ctxt->context, res);
13827 			}
13828                         valuePush(ctxt, obj);
13829                         CHECK_ERROR0;
13830                         return (total);
13831                     }
13832                     newlocset = xmlXPtrLocationSetCreate(NULL);
13833 
13834                     for (i = 0; i < oldlocset->locNr; i++) {
13835                         /*
13836                          * Run the evaluation with a node list made of a
13837                          * single item in the nodelocset.
13838                          */
13839                         ctxt->context->node = oldlocset->locTab[i]->user;
13840                         ctxt->context->contextSize = oldlocset->locNr;
13841                         ctxt->context->proximityPosition = i + 1;
13842 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13843 			    ctxt->context->node);
13844                         valuePush(ctxt, tmp);
13845 
13846                         if (op->ch2 != -1)
13847                             total +=
13848                                 xmlXPathCompOpEval(ctxt,
13849                                                    &comp->steps[op->ch2]);
13850 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13851 			    xmlXPathFreeObject(obj);
13852 			    return(0);
13853 			}
13854 
13855                         res = valuePop(ctxt);
13856 			if (res->type == XPATH_LOCATIONSET) {
13857 			    xmlLocationSetPtr rloc =
13858 			        (xmlLocationSetPtr)res->user;
13859 			    for (j=0; j<rloc->locNr; j++) {
13860 			        range = xmlXPtrNewRange(
13861 				  oldlocset->locTab[i]->user,
13862 				  oldlocset->locTab[i]->index,
13863 				  rloc->locTab[j]->user2,
13864 				  rloc->locTab[j]->index2);
13865 				if (range != NULL) {
13866 				    xmlXPtrLocationSetAdd(newlocset, range);
13867 				}
13868 			    }
13869 			} else {
13870 			    range = xmlXPtrNewRangeNodeObject(
13871 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13872                             if (range != NULL) {
13873                                 xmlXPtrLocationSetAdd(newlocset,range);
13874 			    }
13875                         }
13876 
13877                         /*
13878                          * Cleanup
13879                          */
13880                         if (res != NULL) {
13881 			    xmlXPathReleaseObject(ctxt->context, res);
13882 			}
13883                         if (ctxt->value == tmp) {
13884                             res = valuePop(ctxt);
13885 			    xmlXPathReleaseObject(ctxt->context, res);
13886                         }
13887 
13888                         ctxt->context->node = NULL;
13889                     }
13890 		} else {	/* Not a location set */
13891                     CHECK_TYPE0(XPATH_NODESET);
13892                     obj = valuePop(ctxt);
13893                     oldset = obj->nodesetval;
13894                     ctxt->context->node = NULL;
13895 
13896                     newlocset = xmlXPtrLocationSetCreate(NULL);
13897 
13898                     if (oldset != NULL) {
13899                         for (i = 0; i < oldset->nodeNr; i++) {
13900                             /*
13901                              * Run the evaluation with a node list made of a single item
13902                              * in the nodeset.
13903                              */
13904                             ctxt->context->node = oldset->nodeTab[i];
13905 			    /*
13906 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13907 			    */
13908 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13909 				ctxt->context->node);
13910                             valuePush(ctxt, tmp);
13911 
13912                             if (op->ch2 != -1)
13913                                 total +=
13914                                     xmlXPathCompOpEval(ctxt,
13915                                                    &comp->steps[op->ch2]);
13916 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13917 				xmlXPathFreeObject(obj);
13918 				return(0);
13919 			    }
13920 
13921                             res = valuePop(ctxt);
13922                             range =
13923                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13924                                                       res);
13925                             if (range != NULL) {
13926                                 xmlXPtrLocationSetAdd(newlocset, range);
13927                             }
13928 
13929                             /*
13930                              * Cleanup
13931                              */
13932                             if (res != NULL) {
13933 				xmlXPathReleaseObject(ctxt->context, res);
13934 			    }
13935                             if (ctxt->value == tmp) {
13936                                 res = valuePop(ctxt);
13937 				xmlXPathReleaseObject(ctxt->context, res);
13938                             }
13939 
13940                             ctxt->context->node = NULL;
13941                         }
13942                     }
13943                 }
13944 
13945                 /*
13946                  * The result is used as the new evaluation set.
13947                  */
13948 		xmlXPathReleaseObject(ctxt->context, obj);
13949                 ctxt->context->node = NULL;
13950                 ctxt->context->contextSize = -1;
13951                 ctxt->context->proximityPosition = -1;
13952                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13953                 return (total);
13954             }
13955 #endif /* LIBXML_XPTR_ENABLED */
13956     }
13957     xmlGenericError(xmlGenericErrorContext,
13958                     "XPath: unknown precompiled operation %d\n", op->op);
13959     return (total);
13960 }
13961 
13962 /**
13963  * xmlXPathCompOpEvalToBoolean:
13964  * @ctxt:  the XPath parser context
13965  *
13966  * Evaluates if the expression evaluates to true.
13967  *
13968  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13969  */
13970 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13972 			    xmlXPathStepOpPtr op,
13973 			    int isPredicate)
13974 {
13975     xmlXPathObjectPtr resObj = NULL;
13976 
13977 start:
13978     /* comp = ctxt->comp; */
13979     switch (op->op) {
13980         case XPATH_OP_END:
13981             return (0);
13982 	case XPATH_OP_VALUE:
13983 	    resObj = (xmlXPathObjectPtr) op->value4;
13984 	    if (isPredicate)
13985 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13986 	    return(xmlXPathCastToBoolean(resObj));
13987 	case XPATH_OP_SORT:
13988 	    /*
13989 	    * We don't need sorting for boolean results. Skip this one.
13990 	    */
13991             if (op->ch1 != -1) {
13992 		op = &ctxt->comp->steps[op->ch1];
13993 		goto start;
13994 	    }
13995 	    return(0);
13996 	case XPATH_OP_COLLECT:
13997 	    if (op->ch1 == -1)
13998 		return(0);
13999 
14000             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14001 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14002 		return(-1);
14003 
14004             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14005 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14006 		return(-1);
14007 
14008 	    resObj = valuePop(ctxt);
14009 	    if (resObj == NULL)
14010 		return(-1);
14011 	    break;
14012 	default:
14013 	    /*
14014 	    * Fallback to call xmlXPathCompOpEval().
14015 	    */
14016 	    xmlXPathCompOpEval(ctxt, op);
14017 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14018 		return(-1);
14019 
14020 	    resObj = valuePop(ctxt);
14021 	    if (resObj == NULL)
14022 		return(-1);
14023 	    break;
14024     }
14025 
14026     if (resObj) {
14027 	int res;
14028 
14029 	if (resObj->type == XPATH_BOOLEAN) {
14030 	    res = resObj->boolval;
14031 	} else if (isPredicate) {
14032 	    /*
14033 	    * For predicates a result of type "number" is handled
14034 	    * differently:
14035 	    * SPEC XPath 1.0:
14036 	    * "If the result is a number, the result will be converted
14037 	    *  to true if the number is equal to the context position
14038 	    *  and will be converted to false otherwise;"
14039 	    */
14040 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14041 	} else {
14042 	    res = xmlXPathCastToBoolean(resObj);
14043 	}
14044 	xmlXPathReleaseObject(ctxt->context, resObj);
14045 	return(res);
14046     }
14047 
14048     return(0);
14049 }
14050 
14051 #ifdef XPATH_STREAMING
14052 /**
14053  * xmlXPathRunStreamEval:
14054  * @ctxt:  the XPath parser context with the compiled expression
14055  *
14056  * Evaluate the Precompiled Streamable XPath expression in the given context.
14057  */
14058 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14059 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14060 		      xmlXPathObjectPtr *resultSeq, int toBool)
14061 {
14062     int max_depth, min_depth;
14063     int from_root;
14064     int ret, depth;
14065     int eval_all_nodes;
14066     xmlNodePtr cur = NULL, limit = NULL;
14067     xmlStreamCtxtPtr patstream = NULL;
14068 
14069     int nb_nodes = 0;
14070 
14071     if ((ctxt == NULL) || (comp == NULL))
14072         return(-1);
14073     max_depth = xmlPatternMaxDepth(comp);
14074     if (max_depth == -1)
14075         return(-1);
14076     if (max_depth == -2)
14077         max_depth = 10000;
14078     min_depth = xmlPatternMinDepth(comp);
14079     if (min_depth == -1)
14080         return(-1);
14081     from_root = xmlPatternFromRoot(comp);
14082     if (from_root < 0)
14083         return(-1);
14084 #if 0
14085     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14086 #endif
14087 
14088     if (! toBool) {
14089 	if (resultSeq == NULL)
14090 	    return(-1);
14091 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14092 	if (*resultSeq == NULL)
14093 	    return(-1);
14094     }
14095 
14096     /*
14097      * handle the special cases of "/" amd "." being matched
14098      */
14099     if (min_depth == 0) {
14100 	if (from_root) {
14101 	    /* Select "/" */
14102 	    if (toBool)
14103 		return(1);
14104 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14105 		(xmlNodePtr) ctxt->doc);
14106 	} else {
14107 	    /* Select "self::node()" */
14108 	    if (toBool)
14109 		return(1);
14110 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14111 	}
14112     }
14113     if (max_depth == 0) {
14114 	return(0);
14115     }
14116 
14117     if (from_root) {
14118         cur = (xmlNodePtr)ctxt->doc;
14119     } else if (ctxt->node != NULL) {
14120         switch (ctxt->node->type) {
14121             case XML_ELEMENT_NODE:
14122             case XML_DOCUMENT_NODE:
14123             case XML_DOCUMENT_FRAG_NODE:
14124             case XML_HTML_DOCUMENT_NODE:
14125 #ifdef LIBXML_DOCB_ENABLED
14126             case XML_DOCB_DOCUMENT_NODE:
14127 #endif
14128 	        cur = ctxt->node;
14129 		break;
14130             case XML_ATTRIBUTE_NODE:
14131             case XML_TEXT_NODE:
14132             case XML_CDATA_SECTION_NODE:
14133             case XML_ENTITY_REF_NODE:
14134             case XML_ENTITY_NODE:
14135             case XML_PI_NODE:
14136             case XML_COMMENT_NODE:
14137             case XML_NOTATION_NODE:
14138             case XML_DTD_NODE:
14139             case XML_DOCUMENT_TYPE_NODE:
14140             case XML_ELEMENT_DECL:
14141             case XML_ATTRIBUTE_DECL:
14142             case XML_ENTITY_DECL:
14143             case XML_NAMESPACE_DECL:
14144             case XML_XINCLUDE_START:
14145             case XML_XINCLUDE_END:
14146 		break;
14147 	}
14148 	limit = cur;
14149     }
14150     if (cur == NULL) {
14151         return(0);
14152     }
14153 
14154     patstream = xmlPatternGetStreamCtxt(comp);
14155     if (patstream == NULL) {
14156 	/*
14157 	* QUESTION TODO: Is this an error?
14158 	*/
14159 	return(0);
14160     }
14161 
14162     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14163 
14164     if (from_root) {
14165 	ret = xmlStreamPush(patstream, NULL, NULL);
14166 	if (ret < 0) {
14167 	} else if (ret == 1) {
14168 	    if (toBool)
14169 		goto return_1;
14170 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14171 	}
14172     }
14173     depth = 0;
14174     goto scan_children;
14175 next_node:
14176     do {
14177         nb_nodes++;
14178 
14179 	switch (cur->type) {
14180 	    case XML_ELEMENT_NODE:
14181 	    case XML_TEXT_NODE:
14182 	    case XML_CDATA_SECTION_NODE:
14183 	    case XML_COMMENT_NODE:
14184 	    case XML_PI_NODE:
14185 		if (cur->type == XML_ELEMENT_NODE) {
14186 		    ret = xmlStreamPush(patstream, cur->name,
14187 				(cur->ns ? cur->ns->href : NULL));
14188 		} else if (eval_all_nodes)
14189 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14190 		else
14191 		    break;
14192 
14193 		if (ret < 0) {
14194 		    /* NOP. */
14195 		} else if (ret == 1) {
14196 		    if (toBool)
14197 			goto return_1;
14198 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14199 		}
14200 		if ((cur->children == NULL) || (depth >= max_depth)) {
14201 		    ret = xmlStreamPop(patstream);
14202 		    while (cur->next != NULL) {
14203 			cur = cur->next;
14204 			if ((cur->type != XML_ENTITY_DECL) &&
14205 			    (cur->type != XML_DTD_NODE))
14206 			    goto next_node;
14207 		    }
14208 		}
14209 	    default:
14210 		break;
14211 	}
14212 
14213 scan_children:
14214 	if ((cur->children != NULL) && (depth < max_depth)) {
14215 	    /*
14216 	     * Do not descend on entities declarations
14217 	     */
14218 	    if (cur->children->type != XML_ENTITY_DECL) {
14219 		cur = cur->children;
14220 		depth++;
14221 		/*
14222 		 * Skip DTDs
14223 		 */
14224 		if (cur->type != XML_DTD_NODE)
14225 		    continue;
14226 	    }
14227 	}
14228 
14229 	if (cur == limit)
14230 	    break;
14231 
14232 	while (cur->next != NULL) {
14233 	    cur = cur->next;
14234 	    if ((cur->type != XML_ENTITY_DECL) &&
14235 		(cur->type != XML_DTD_NODE))
14236 		goto next_node;
14237 	}
14238 
14239 	do {
14240 	    cur = cur->parent;
14241 	    depth--;
14242 	    if ((cur == NULL) || (cur == limit))
14243 	        goto done;
14244 	    if (cur->type == XML_ELEMENT_NODE) {
14245 		ret = xmlStreamPop(patstream);
14246 	    } else if ((eval_all_nodes) &&
14247 		((cur->type == XML_TEXT_NODE) ||
14248 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14249 		 (cur->type == XML_COMMENT_NODE) ||
14250 		 (cur->type == XML_PI_NODE)))
14251 	    {
14252 		ret = xmlStreamPop(patstream);
14253 	    }
14254 	    if (cur->next != NULL) {
14255 		cur = cur->next;
14256 		break;
14257 	    }
14258 	} while (cur != NULL);
14259 
14260     } while ((cur != NULL) && (depth >= 0));
14261 
14262 done:
14263 
14264 #if 0
14265     printf("stream eval: checked %d nodes selected %d\n",
14266            nb_nodes, retObj->nodesetval->nodeNr);
14267 #endif
14268 
14269     if (patstream)
14270 	xmlFreeStreamCtxt(patstream);
14271     return(0);
14272 
14273 return_1:
14274     if (patstream)
14275 	xmlFreeStreamCtxt(patstream);
14276     return(1);
14277 }
14278 #endif /* XPATH_STREAMING */
14279 
14280 /**
14281  * xmlXPathRunEval:
14282  * @ctxt:  the XPath parser context with the compiled expression
14283  * @toBool:  evaluate to a boolean result
14284  *
14285  * Evaluate the Precompiled XPath expression in the given context.
14286  */
14287 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14288 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14289 {
14290     xmlXPathCompExprPtr comp;
14291 
14292     if ((ctxt == NULL) || (ctxt->comp == NULL))
14293 	return(-1);
14294 
14295     if (ctxt->valueTab == NULL) {
14296 	/* Allocate the value stack */
14297 	ctxt->valueTab = (xmlXPathObjectPtr *)
14298 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14299 	if (ctxt->valueTab == NULL) {
14300 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14301 	    xmlFree(ctxt);
14302 	}
14303 	ctxt->valueNr = 0;
14304 	ctxt->valueMax = 10;
14305 	ctxt->value = NULL;
14306     }
14307 #ifdef XPATH_STREAMING
14308     if (ctxt->comp->stream) {
14309 	int res;
14310 
14311 	if (toBool) {
14312 	    /*
14313 	    * Evaluation to boolean result.
14314 	    */
14315 	    res = xmlXPathRunStreamEval(ctxt->context,
14316 		ctxt->comp->stream, NULL, 1);
14317 	    if (res != -1)
14318 		return(res);
14319 	} else {
14320 	    xmlXPathObjectPtr resObj = NULL;
14321 
14322 	    /*
14323 	    * Evaluation to a sequence.
14324 	    */
14325 	    res = xmlXPathRunStreamEval(ctxt->context,
14326 		ctxt->comp->stream, &resObj, 0);
14327 
14328 	    if ((res != -1) && (resObj != NULL)) {
14329 		valuePush(ctxt, resObj);
14330 		return(0);
14331 	    }
14332 	    if (resObj != NULL)
14333 		xmlXPathReleaseObject(ctxt->context, resObj);
14334 	}
14335 	/*
14336 	* QUESTION TODO: This falls back to normal XPath evaluation
14337 	* if res == -1. Is this intended?
14338 	*/
14339     }
14340 #endif
14341     comp = ctxt->comp;
14342     if (comp->last < 0) {
14343 	xmlGenericError(xmlGenericErrorContext,
14344 	    "xmlXPathRunEval: last is less than zero\n");
14345 	return(-1);
14346     }
14347     if (toBool)
14348 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14349 	    &comp->steps[comp->last], 0));
14350     else
14351 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14352 
14353     return(0);
14354 }
14355 
14356 /************************************************************************
14357  *									*
14358  *			Public interfaces				*
14359  *									*
14360  ************************************************************************/
14361 
14362 /**
14363  * xmlXPathEvalPredicate:
14364  * @ctxt:  the XPath context
14365  * @res:  the Predicate Expression evaluation result
14366  *
14367  * Evaluate a predicate result for the current node.
14368  * A PredicateExpr is evaluated by evaluating the Expr and converting
14369  * the result to a boolean. If the result is a number, the result will
14370  * be converted to true if the number is equal to the position of the
14371  * context node in the context node list (as returned by the position
14372  * function) and will be converted to false otherwise; if the result
14373  * is not a number, then the result will be converted as if by a call
14374  * to the boolean function.
14375  *
14376  * Returns 1 if predicate is true, 0 otherwise
14377  */
14378 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14379 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14380     if ((ctxt == NULL) || (res == NULL)) return(0);
14381     switch (res->type) {
14382         case XPATH_BOOLEAN:
14383 	    return(res->boolval);
14384         case XPATH_NUMBER:
14385 	    return(res->floatval == ctxt->proximityPosition);
14386         case XPATH_NODESET:
14387         case XPATH_XSLT_TREE:
14388 	    if (res->nodesetval == NULL)
14389 		return(0);
14390 	    return(res->nodesetval->nodeNr != 0);
14391         case XPATH_STRING:
14392 	    return((res->stringval != NULL) &&
14393 	           (xmlStrlen(res->stringval) != 0));
14394         default:
14395 	    STRANGE
14396     }
14397     return(0);
14398 }
14399 
14400 /**
14401  * xmlXPathEvaluatePredicateResult:
14402  * @ctxt:  the XPath Parser context
14403  * @res:  the Predicate Expression evaluation result
14404  *
14405  * Evaluate a predicate result for the current node.
14406  * A PredicateExpr is evaluated by evaluating the Expr and converting
14407  * the result to a boolean. If the result is a number, the result will
14408  * be converted to true if the number is equal to the position of the
14409  * context node in the context node list (as returned by the position
14410  * function) and will be converted to false otherwise; if the result
14411  * is not a number, then the result will be converted as if by a call
14412  * to the boolean function.
14413  *
14414  * Returns 1 if predicate is true, 0 otherwise
14415  */
14416 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14417 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14418                                 xmlXPathObjectPtr res) {
14419     if ((ctxt == NULL) || (res == NULL)) return(0);
14420     switch (res->type) {
14421         case XPATH_BOOLEAN:
14422 	    return(res->boolval);
14423         case XPATH_NUMBER:
14424 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14425 	    return((res->floatval == ctxt->context->proximityPosition) &&
14426 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14427 #else
14428 	    return(res->floatval == ctxt->context->proximityPosition);
14429 #endif
14430         case XPATH_NODESET:
14431         case XPATH_XSLT_TREE:
14432 	    if (res->nodesetval == NULL)
14433 		return(0);
14434 	    return(res->nodesetval->nodeNr != 0);
14435         case XPATH_STRING:
14436 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14437 #ifdef LIBXML_XPTR_ENABLED
14438 	case XPATH_LOCATIONSET:{
14439 	    xmlLocationSetPtr ptr = res->user;
14440 	    if (ptr == NULL)
14441 	        return(0);
14442 	    return (ptr->locNr != 0);
14443 	    }
14444 #endif
14445         default:
14446 	    STRANGE
14447     }
14448     return(0);
14449 }
14450 
14451 #ifdef XPATH_STREAMING
14452 /**
14453  * xmlXPathTryStreamCompile:
14454  * @ctxt: an XPath context
14455  * @str:  the XPath expression
14456  *
14457  * Try to compile the XPath expression as a streamable subset.
14458  *
14459  * Returns the compiled expression or NULL if failed to compile.
14460  */
14461 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14462 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14463     /*
14464      * Optimization: use streaming patterns when the XPath expression can
14465      * be compiled to a stream lookup
14466      */
14467     xmlPatternPtr stream;
14468     xmlXPathCompExprPtr comp;
14469     xmlDictPtr dict = NULL;
14470     const xmlChar **namespaces = NULL;
14471     xmlNsPtr ns;
14472     int i, j;
14473 
14474     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14475         (!xmlStrchr(str, '@'))) {
14476 	const xmlChar *tmp;
14477 
14478 	/*
14479 	 * We don't try to handle expressions using the verbose axis
14480 	 * specifiers ("::"), just the simplied form at this point.
14481 	 * Additionally, if there is no list of namespaces available and
14482 	 *  there's a ":" in the expression, indicating a prefixed QName,
14483 	 *  then we won't try to compile either. xmlPatterncompile() needs
14484 	 *  to have a list of namespaces at compilation time in order to
14485 	 *  compile prefixed name tests.
14486 	 */
14487 	tmp = xmlStrchr(str, ':');
14488 	if ((tmp != NULL) &&
14489 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14490 	    return(NULL);
14491 
14492 	if (ctxt != NULL) {
14493 	    dict = ctxt->dict;
14494 	    if (ctxt->nsNr > 0) {
14495 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14496 		if (namespaces == NULL) {
14497 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14498 		    return(NULL);
14499 		}
14500 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14501 		    ns = ctxt->namespaces[j];
14502 		    namespaces[i++] = ns->href;
14503 		    namespaces[i++] = ns->prefix;
14504 		}
14505 		namespaces[i++] = NULL;
14506 		namespaces[i++] = NULL;
14507 	    }
14508 	}
14509 
14510 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14511 			&namespaces[0]);
14512 	if (namespaces != NULL) {
14513 	    xmlFree((xmlChar **)namespaces);
14514 	}
14515 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14516 	    comp = xmlXPathNewCompExpr();
14517 	    if (comp == NULL) {
14518 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14519 		return(NULL);
14520 	    }
14521 	    comp->stream = stream;
14522 	    comp->dict = dict;
14523 	    if (comp->dict)
14524 		xmlDictReference(comp->dict);
14525 	    return(comp);
14526 	}
14527 	xmlFreePattern(stream);
14528     }
14529     return(NULL);
14530 }
14531 #endif /* XPATH_STREAMING */
14532 
14533 static int
xmlXPathCanRewriteDosExpression(xmlChar * expr)14534 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14535 {
14536     if (expr == NULL)
14537 	return(0);
14538     do {
14539         if ((*expr == '/') && (*(++expr) == '/'))
14540 	    return(1);
14541     } while (*expr++);
14542     return(0);
14543 }
14544 static void
xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14545 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14546 {
14547     /*
14548     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14549     * internal representation.
14550     */
14551     if (op->ch1 != -1) {
14552 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14553 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14554 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14555 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14556 	{
14557 	    /*
14558 	    * This is a "child::foo"
14559 	    */
14560 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14561 
14562 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14563 		(prevop->ch1 != -1) &&
14564 		((xmlXPathAxisVal) prevop->value ==
14565 		    AXIS_DESCENDANT_OR_SELF) &&
14566 		(prevop->ch2 == -1) &&
14567 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14568 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14569 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14570 	    {
14571 		/*
14572 		* This is a "/descendant-or-self::node()" without predicates.
14573 		* Eliminate it.
14574 		*/
14575 		op->ch1 = prevop->ch1;
14576 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14577 	    }
14578 	}
14579 	if (op->ch1 != -1)
14580 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14581     }
14582     if (op->ch2 != -1)
14583 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14584 }
14585 
14586 /**
14587  * xmlXPathCtxtCompile:
14588  * @ctxt: an XPath context
14589  * @str:  the XPath expression
14590  *
14591  * Compile an XPath expression
14592  *
14593  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14594  *         the caller has to free the object.
14595  */
14596 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14597 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14598     xmlXPathParserContextPtr pctxt;
14599     xmlXPathCompExprPtr comp;
14600 
14601 #ifdef XPATH_STREAMING
14602     comp = xmlXPathTryStreamCompile(ctxt, str);
14603     if (comp != NULL)
14604         return(comp);
14605 #endif
14606 
14607     xmlXPathInit();
14608 
14609     pctxt = xmlXPathNewParserContext(str, ctxt);
14610     if (pctxt == NULL)
14611         return NULL;
14612     xmlXPathCompileExpr(pctxt, 1);
14613 
14614     if( pctxt->error != XPATH_EXPRESSION_OK )
14615     {
14616         xmlXPathFreeParserContext(pctxt);
14617         return(NULL);
14618     }
14619 
14620     if (*pctxt->cur != 0) {
14621 	/*
14622 	 * aleksey: in some cases this line prints *second* error message
14623 	 * (see bug #78858) and probably this should be fixed.
14624 	 * However, we are not sure that all error messages are printed
14625 	 * out in other places. It's not critical so we leave it as-is for now
14626 	 */
14627 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14628 	comp = NULL;
14629     } else {
14630 	comp = pctxt->comp;
14631 	pctxt->comp = NULL;
14632     }
14633     xmlXPathFreeParserContext(pctxt);
14634 
14635     if (comp != NULL) {
14636 	comp->expr = xmlStrdup(str);
14637 #ifdef DEBUG_EVAL_COUNTS
14638 	comp->string = xmlStrdup(str);
14639 	comp->nb = 0;
14640 #endif
14641 	if ((comp->expr != NULL) &&
14642 	    (comp->nbStep > 2) &&
14643 	    (comp->last >= 0) &&
14644 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14645 	{
14646 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14647 	}
14648     }
14649     return(comp);
14650 }
14651 
14652 /**
14653  * xmlXPathCompile:
14654  * @str:  the XPath expression
14655  *
14656  * Compile an XPath expression
14657  *
14658  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14659  *         the caller has to free the object.
14660  */
14661 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14662 xmlXPathCompile(const xmlChar *str) {
14663     return(xmlXPathCtxtCompile(NULL, str));
14664 }
14665 
14666 /**
14667  * xmlXPathCompiledEvalInternal:
14668  * @comp:  the compiled XPath expression
14669  * @ctxt:  the XPath context
14670  * @resObj: the resulting XPath object or NULL
14671  * @toBool: 1 if only a boolean result is requested
14672  *
14673  * Evaluate the Precompiled XPath expression in the given context.
14674  * The caller has to free @resObj.
14675  *
14676  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14677  *         the caller has to free the object.
14678  */
14679 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObj,int toBool)14680 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14681 			     xmlXPathContextPtr ctxt,
14682 			     xmlXPathObjectPtr *resObj,
14683 			     int toBool)
14684 {
14685     xmlXPathParserContextPtr pctxt;
14686 #ifndef LIBXML_THREAD_ENABLED
14687     static int reentance = 0;
14688 #endif
14689     int res;
14690 
14691     CHECK_CTXT_NEG(ctxt)
14692 
14693     if (comp == NULL)
14694 	return(-1);
14695     xmlXPathInit();
14696 
14697 #ifndef LIBXML_THREAD_ENABLED
14698     reentance++;
14699     if (reentance > 1)
14700 	xmlXPathDisableOptimizer = 1;
14701 #endif
14702 
14703 #ifdef DEBUG_EVAL_COUNTS
14704     comp->nb++;
14705     if ((comp->string != NULL) && (comp->nb > 100)) {
14706 	fprintf(stderr, "100 x %s\n", comp->string);
14707 	comp->nb = 0;
14708     }
14709 #endif
14710     pctxt = xmlXPathCompParserContext(comp, ctxt);
14711     res = xmlXPathRunEval(pctxt, toBool);
14712 
14713     if (resObj) {
14714 	if (pctxt->value == NULL) {
14715 	    xmlGenericError(xmlGenericErrorContext,
14716 		"xmlXPathCompiledEval: evaluation failed\n");
14717 	    *resObj = NULL;
14718 	} else {
14719 	    *resObj = valuePop(pctxt);
14720 	}
14721     }
14722 
14723     /*
14724     * Pop all remaining objects from the stack.
14725     */
14726     if (pctxt->valueNr > 0) {
14727 	xmlXPathObjectPtr tmp;
14728 	int stack = 0;
14729 
14730 	do {
14731 	    tmp = valuePop(pctxt);
14732 	    if (tmp != NULL) {
14733 		stack++;
14734 		xmlXPathReleaseObject(ctxt, tmp);
14735 	    }
14736 	} while (tmp != NULL);
14737 	if ((stack != 0) &&
14738 	    ((toBool) || ((resObj) && (*resObj))))
14739 	{
14740 	    xmlGenericError(xmlGenericErrorContext,
14741 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14742 		stack);
14743 	}
14744     }
14745 
14746     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14747 	xmlXPathFreeObject(*resObj);
14748 	*resObj = NULL;
14749     }
14750     pctxt->comp = NULL;
14751     xmlXPathFreeParserContext(pctxt);
14752 #ifndef LIBXML_THREAD_ENABLED
14753     reentance--;
14754 #endif
14755 
14756     return(res);
14757 }
14758 
14759 /**
14760  * xmlXPathCompiledEval:
14761  * @comp:  the compiled XPath expression
14762  * @ctx:  the XPath context
14763  *
14764  * Evaluate the Precompiled XPath expression in the given context.
14765  *
14766  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14767  *         the caller has to free the object.
14768  */
14769 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14770 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14771 {
14772     xmlXPathObjectPtr res = NULL;
14773 
14774     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14775     return(res);
14776 }
14777 
14778 /**
14779  * xmlXPathCompiledEvalToBoolean:
14780  * @comp:  the compiled XPath expression
14781  * @ctxt:  the XPath context
14782  *
14783  * Applies the XPath boolean() function on the result of the given
14784  * compiled expression.
14785  *
14786  * Returns 1 if the expression evaluated to true, 0 if to false and
14787  *         -1 in API and internal errors.
14788  */
14789 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14790 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14791 			      xmlXPathContextPtr ctxt)
14792 {
14793     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14794 }
14795 
14796 /**
14797  * xmlXPathEvalExpr:
14798  * @ctxt:  the XPath Parser context
14799  *
14800  * Parse and evaluate an XPath expression in the given context,
14801  * then push the result on the context stack
14802  */
14803 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14804 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14805 #ifdef XPATH_STREAMING
14806     xmlXPathCompExprPtr comp;
14807 #endif
14808 
14809     if (ctxt == NULL) return;
14810 
14811 #ifdef XPATH_STREAMING
14812     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14813     if (comp != NULL) {
14814         if (ctxt->comp != NULL)
14815 	    xmlXPathFreeCompExpr(ctxt->comp);
14816         ctxt->comp = comp;
14817 	if (ctxt->cur != NULL)
14818 	    while (*ctxt->cur != 0) ctxt->cur++;
14819     } else
14820 #endif
14821     {
14822 	xmlXPathCompileExpr(ctxt, 1);
14823 	/*
14824 	* In this scenario the expression string will sit in ctxt->base.
14825 	*/
14826 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14827 	    (ctxt->comp != NULL) &&
14828 	    (ctxt->base != NULL) &&
14829 	    (ctxt->comp->nbStep > 2) &&
14830 	    (ctxt->comp->last >= 0) &&
14831 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14832 	{
14833 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14834 		&ctxt->comp->steps[ctxt->comp->last]);
14835 	}
14836     }
14837     CHECK_ERROR;
14838     xmlXPathRunEval(ctxt, 0);
14839 }
14840 
14841 /**
14842  * xmlXPathEval:
14843  * @str:  the XPath expression
14844  * @ctx:  the XPath context
14845  *
14846  * Evaluate the XPath Location Path in the given context.
14847  *
14848  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14849  *         the caller has to free the object.
14850  */
14851 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14853     xmlXPathParserContextPtr ctxt;
14854     xmlXPathObjectPtr res, tmp, init = NULL;
14855     int stack = 0;
14856 
14857     CHECK_CTXT(ctx)
14858 
14859     xmlXPathInit();
14860 
14861     ctxt = xmlXPathNewParserContext(str, ctx);
14862     if (ctxt == NULL)
14863         return NULL;
14864     xmlXPathEvalExpr(ctxt);
14865 
14866     if (ctxt->value == NULL) {
14867 	xmlGenericError(xmlGenericErrorContext,
14868 		"xmlXPathEval: evaluation failed\n");
14869 	res = NULL;
14870     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14871 #ifdef XPATH_STREAMING
14872             && (ctxt->comp->stream == NULL)
14873 #endif
14874 	      ) {
14875 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14876 	res = NULL;
14877     } else {
14878 	res = valuePop(ctxt);
14879     }
14880 
14881     do {
14882         tmp = valuePop(ctxt);
14883 	if (tmp != NULL) {
14884 	    if (tmp != init)
14885 		stack++;
14886 	    xmlXPathReleaseObject(ctx, tmp);
14887         }
14888     } while (tmp != NULL);
14889     if ((stack != 0) && (res != NULL)) {
14890 	xmlGenericError(xmlGenericErrorContext,
14891 		"xmlXPathEval: %d object left on the stack\n",
14892 	        stack);
14893     }
14894     if (ctxt->error != XPATH_EXPRESSION_OK) {
14895 	xmlXPathFreeObject(res);
14896 	res = NULL;
14897     }
14898 
14899     xmlXPathFreeParserContext(ctxt);
14900     return(res);
14901 }
14902 
14903 /**
14904  * xmlXPathEvalExpression:
14905  * @str:  the XPath expression
14906  * @ctxt:  the XPath context
14907  *
14908  * Evaluate the XPath expression in the given context.
14909  *
14910  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14911  *         the caller has to free the object.
14912  */
14913 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14914 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14915     xmlXPathParserContextPtr pctxt;
14916     xmlXPathObjectPtr res, tmp;
14917     int stack = 0;
14918 
14919     CHECK_CTXT(ctxt)
14920 
14921     xmlXPathInit();
14922 
14923     pctxt = xmlXPathNewParserContext(str, ctxt);
14924     if (pctxt == NULL)
14925         return NULL;
14926     xmlXPathEvalExpr(pctxt);
14927 
14928     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14929 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14930 	res = NULL;
14931     } else {
14932 	res = valuePop(pctxt);
14933     }
14934     do {
14935         tmp = valuePop(pctxt);
14936 	if (tmp != NULL) {
14937 	    xmlXPathReleaseObject(ctxt, tmp);
14938 	    stack++;
14939 	}
14940     } while (tmp != NULL);
14941     if ((stack != 0) && (res != NULL)) {
14942 	xmlGenericError(xmlGenericErrorContext,
14943 		"xmlXPathEvalExpression: %d object left on the stack\n",
14944 	        stack);
14945     }
14946     xmlXPathFreeParserContext(pctxt);
14947     return(res);
14948 }
14949 
14950 /************************************************************************
14951  *									*
14952  *	Extra functions not pertaining to the XPath spec		*
14953  *									*
14954  ************************************************************************/
14955 /**
14956  * xmlXPathEscapeUriFunction:
14957  * @ctxt:  the XPath Parser context
14958  * @nargs:  the number of arguments
14959  *
14960  * Implement the escape-uri() XPath function
14961  *    string escape-uri(string $str, bool $escape-reserved)
14962  *
14963  * This function applies the URI escaping rules defined in section 2 of [RFC
14964  * 2396] to the string supplied as $uri-part, which typically represents all
14965  * or part of a URI. The effect of the function is to replace any special
14966  * character in the string by an escape sequence of the form %xx%yy...,
14967  * where xxyy... is the hexadecimal representation of the octets used to
14968  * represent the character in UTF-8.
14969  *
14970  * The set of characters that are escaped depends on the setting of the
14971  * boolean argument $escape-reserved.
14972  *
14973  * If $escape-reserved is true, all characters are escaped other than lower
14974  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14975  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14976  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14977  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14978  * A-F).
14979  *
14980  * If $escape-reserved is false, the behavior differs in that characters
14981  * referred to in [RFC 2396] as reserved characters are not escaped. These
14982  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14983  *
14984  * [RFC 2396] does not define whether escaped URIs should use lower case or
14985  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14986  * compared using string comparison functions, this function must always use
14987  * the upper-case letters A-F.
14988  *
14989  * Generally, $escape-reserved should be set to true when escaping a string
14990  * that is to form a single part of a URI, and to false when escaping an
14991  * entire URI or URI reference.
14992  *
14993  * In the case of non-ascii characters, the string is encoded according to
14994  * utf-8 and then converted according to RFC 2396.
14995  *
14996  * Examples
14997  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14998  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14999  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15000  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15001  *
15002  */
15003 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15004 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15005     xmlXPathObjectPtr str;
15006     int escape_reserved;
15007     xmlBufferPtr target;
15008     xmlChar *cptr;
15009     xmlChar escape[4];
15010 
15011     CHECK_ARITY(2);
15012 
15013     escape_reserved = xmlXPathPopBoolean(ctxt);
15014 
15015     CAST_TO_STRING;
15016     str = valuePop(ctxt);
15017 
15018     target = xmlBufferCreate();
15019 
15020     escape[0] = '%';
15021     escape[3] = 0;
15022 
15023     if (target) {
15024 	for (cptr = str->stringval; *cptr; cptr++) {
15025 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15026 		(*cptr >= 'a' && *cptr <= 'z') ||
15027 		(*cptr >= '0' && *cptr <= '9') ||
15028 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15029 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15030 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15031 		(*cptr == '%' &&
15032 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15033 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15034 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15035 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15036 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15037 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15038 		(!escape_reserved &&
15039 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15040 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15041 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15042 		  *cptr == ','))) {
15043 		xmlBufferAdd(target, cptr, 1);
15044 	    } else {
15045 		if ((*cptr >> 4) < 10)
15046 		    escape[1] = '0' + (*cptr >> 4);
15047 		else
15048 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15049 		if ((*cptr & 0xF) < 10)
15050 		    escape[2] = '0' + (*cptr & 0xF);
15051 		else
15052 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15053 
15054 		xmlBufferAdd(target, &escape[0], 3);
15055 	    }
15056 	}
15057     }
15058     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15059 	xmlBufferContent(target)));
15060     xmlBufferFree(target);
15061     xmlXPathReleaseObject(ctxt->context, str);
15062 }
15063 
15064 /**
15065  * xmlXPathRegisterAllFunctions:
15066  * @ctxt:  the XPath context
15067  *
15068  * Registers all default XPath functions in this context
15069  */
15070 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15071 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15072 {
15073     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15074                          xmlXPathBooleanFunction);
15075     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15076                          xmlXPathCeilingFunction);
15077     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15078                          xmlXPathCountFunction);
15079     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15080                          xmlXPathConcatFunction);
15081     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15082                          xmlXPathContainsFunction);
15083     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15084                          xmlXPathIdFunction);
15085     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15086                          xmlXPathFalseFunction);
15087     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15088                          xmlXPathFloorFunction);
15089     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15090                          xmlXPathLastFunction);
15091     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15092                          xmlXPathLangFunction);
15093     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15094                          xmlXPathLocalNameFunction);
15095     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15096                          xmlXPathNotFunction);
15097     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15098                          xmlXPathNameFunction);
15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15100                          xmlXPathNamespaceURIFunction);
15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15102                          xmlXPathNormalizeFunction);
15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15104                          xmlXPathNumberFunction);
15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15106                          xmlXPathPositionFunction);
15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15108                          xmlXPathRoundFunction);
15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15110                          xmlXPathStringFunction);
15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15112                          xmlXPathStringLengthFunction);
15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15114                          xmlXPathStartsWithFunction);
15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15116                          xmlXPathSubstringFunction);
15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15118                          xmlXPathSubstringBeforeFunction);
15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15120                          xmlXPathSubstringAfterFunction);
15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15122                          xmlXPathSumFunction);
15123     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15124                          xmlXPathTrueFunction);
15125     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15126                          xmlXPathTranslateFunction);
15127 
15128     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15129 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15130                          xmlXPathEscapeUriFunction);
15131 }
15132 
15133 #endif /* LIBXML_XPATH_ENABLED */
15134 #define bottom_xpath
15135 #include "elfgcchack.h"
15136