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 /* #define DEBUG */
191 /* #define DEBUG_STEP */
192 /* #define DEBUG_STEP_NTH */
193 /* #define DEBUG_EXPR */
194 /* #define DEBUG_EVAL_COUNTS */
195 
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197     NULL,
198     XML_NAMESPACE_DECL,
199     XML_XML_NAMESPACE,
200     BAD_CAST "xml",
201     NULL,
202     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 			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 			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 			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, 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, 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, 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, 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, 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, shift);
957 	fprintf(output, "Value Tree is NULL !\n");
958 	return;
959 
960     }
961 
962     fprintf(output, 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, shift);
978 	fprintf(output, "LocationSet is NULL !\n");
979 	return;
980 
981     }
982 
983     for (i = 0;i < cur->locNr;i++) {
984 	fprintf(output, 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, 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, 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, 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, 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, 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, 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 (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 	XP_ERROR(XPATH_EXPR_ERROR);
10278     }
10279     SKIP_BLANKS;
10280 #ifdef DEBUG_EXPR
10281     if (prefix == NULL)
10282 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10283 			name);
10284     else
10285 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10286 			prefix, name);
10287 #endif
10288 
10289     if (CUR != '(') {
10290 	XP_ERROR(XPATH_EXPR_ERROR);
10291     }
10292     NEXT;
10293     SKIP_BLANKS;
10294 
10295     /*
10296     * Optimization for count(): we don't need the node-set to be sorted.
10297     */
10298     if ((prefix == NULL) && (name[0] == 'c') &&
10299 	xmlStrEqual(name, BAD_CAST "count"))
10300     {
10301 	sort = 0;
10302     }
10303     ctxt->comp->last = -1;
10304     if (CUR != ')') {
10305 	while (CUR != 0) {
10306 	    int op1 = ctxt->comp->last;
10307 	    ctxt->comp->last = -1;
10308 	    xmlXPathCompileExpr(ctxt, sort);
10309 	    CHECK_ERROR;
10310 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10311 	    nbargs++;
10312 	    if (CUR == ')') break;
10313 	    if (CUR != ',') {
10314 		XP_ERROR(XPATH_EXPR_ERROR);
10315 	    }
10316 	    NEXT;
10317 	    SKIP_BLANKS;
10318 	}
10319     }
10320     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10321 	           name, prefix);
10322     NEXT;
10323     SKIP_BLANKS;
10324 }
10325 
10326 /**
10327  * xmlXPathCompPrimaryExpr:
10328  * @ctxt:  the XPath Parser context
10329  *
10330  *  [15]   PrimaryExpr ::=   VariableReference
10331  *                | '(' Expr ')'
10332  *                | Literal
10333  *                | Number
10334  *                | FunctionCall
10335  *
10336  * Compile a primary expression.
10337  */
10338 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10339 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10340     SKIP_BLANKS;
10341     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10342     else if (CUR == '(') {
10343 	NEXT;
10344 	SKIP_BLANKS;
10345 	xmlXPathCompileExpr(ctxt, 1);
10346 	CHECK_ERROR;
10347 	if (CUR != ')') {
10348 	    XP_ERROR(XPATH_EXPR_ERROR);
10349 	}
10350 	NEXT;
10351 	SKIP_BLANKS;
10352     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10353 	xmlXPathCompNumber(ctxt);
10354     } else if ((CUR == '\'') || (CUR == '"')) {
10355 	xmlXPathCompLiteral(ctxt);
10356     } else {
10357 	xmlXPathCompFunctionCall(ctxt);
10358     }
10359     SKIP_BLANKS;
10360 }
10361 
10362 /**
10363  * xmlXPathCompFilterExpr:
10364  * @ctxt:  the XPath Parser context
10365  *
10366  *  [20]   FilterExpr ::=   PrimaryExpr
10367  *               | FilterExpr Predicate
10368  *
10369  * Compile a filter expression.
10370  * Square brackets are used to filter expressions in the same way that
10371  * they are used in location paths. It is an error if the expression to
10372  * be filtered does not evaluate to a node-set. The context node list
10373  * used for evaluating the expression in square brackets is the node-set
10374  * to be filtered listed in document order.
10375  */
10376 
10377 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10378 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10379     xmlXPathCompPrimaryExpr(ctxt);
10380     CHECK_ERROR;
10381     SKIP_BLANKS;
10382 
10383     while (CUR == '[') {
10384 	xmlXPathCompPredicate(ctxt, 1);
10385 	SKIP_BLANKS;
10386     }
10387 
10388 
10389 }
10390 
10391 /**
10392  * xmlXPathScanName:
10393  * @ctxt:  the XPath Parser context
10394  *
10395  * Trickery: parse an XML name but without consuming the input flow
10396  * Needed to avoid insanity in the parser state.
10397  *
10398  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10399  *                  CombiningChar | Extender
10400  *
10401  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10402  *
10403  * [6] Names ::= Name (S Name)*
10404  *
10405  * Returns the Name parsed or NULL
10406  */
10407 
10408 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10409 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10410     int len = 0, l;
10411     int c;
10412     const xmlChar *cur;
10413     xmlChar *ret;
10414 
10415     cur = ctxt->cur;
10416 
10417     c = CUR_CHAR(l);
10418     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10419 	(!IS_LETTER(c) && (c != '_') &&
10420          (c != ':'))) {
10421 	return(NULL);
10422     }
10423 
10424     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10425 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10426             (c == '.') || (c == '-') ||
10427 	    (c == '_') || (c == ':') ||
10428 	    (IS_COMBINING(c)) ||
10429 	    (IS_EXTENDER(c)))) {
10430 	len += l;
10431 	NEXTL(l);
10432 	c = CUR_CHAR(l);
10433     }
10434     ret = xmlStrndup(cur, ctxt->cur - cur);
10435     ctxt->cur = cur;
10436     return(ret);
10437 }
10438 
10439 /**
10440  * xmlXPathCompPathExpr:
10441  * @ctxt:  the XPath Parser context
10442  *
10443  *  [19]   PathExpr ::=   LocationPath
10444  *               | FilterExpr
10445  *               | FilterExpr '/' RelativeLocationPath
10446  *               | FilterExpr '//' RelativeLocationPath
10447  *
10448  * Compile a path expression.
10449  * The / operator and // operators combine an arbitrary expression
10450  * and a relative location path. It is an error if the expression
10451  * does not evaluate to a node-set.
10452  * The / operator does composition in the same way as when / is
10453  * used in a location path. As in location paths, // is short for
10454  * /descendant-or-self::node()/.
10455  */
10456 
10457 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10458 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10459     int lc = 1;           /* Should we branch to LocationPath ?         */
10460     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10461 
10462     SKIP_BLANKS;
10463     if ((CUR == '$') || (CUR == '(') ||
10464     	(IS_ASCII_DIGIT(CUR)) ||
10465         (CUR == '\'') || (CUR == '"') ||
10466 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10467 	lc = 0;
10468     } else if (CUR == '*') {
10469 	/* relative or absolute location path */
10470 	lc = 1;
10471     } else if (CUR == '/') {
10472 	/* relative or absolute location path */
10473 	lc = 1;
10474     } else if (CUR == '@') {
10475 	/* relative abbreviated attribute location path */
10476 	lc = 1;
10477     } else if (CUR == '.') {
10478 	/* relative abbreviated attribute location path */
10479 	lc = 1;
10480     } else {
10481 	/*
10482 	 * Problem is finding if we have a name here whether it's:
10483 	 *   - a nodetype
10484 	 *   - a function call in which case it's followed by '('
10485 	 *   - an axis in which case it's followed by ':'
10486 	 *   - a element name
10487 	 * We do an a priori analysis here rather than having to
10488 	 * maintain parsed token content through the recursive function
10489 	 * calls. This looks uglier but makes the code easier to
10490 	 * read/write/debug.
10491 	 */
10492 	SKIP_BLANKS;
10493 	name = xmlXPathScanName(ctxt);
10494 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10495 #ifdef DEBUG_STEP
10496 	    xmlGenericError(xmlGenericErrorContext,
10497 		    "PathExpr: Axis\n");
10498 #endif
10499 	    lc = 1;
10500 	    xmlFree(name);
10501 	} else if (name != NULL) {
10502 	    int len =xmlStrlen(name);
10503 
10504 
10505 	    while (NXT(len) != 0) {
10506 		if (NXT(len) == '/') {
10507 		    /* element name */
10508 #ifdef DEBUG_STEP
10509 		    xmlGenericError(xmlGenericErrorContext,
10510 			    "PathExpr: AbbrRelLocation\n");
10511 #endif
10512 		    lc = 1;
10513 		    break;
10514 		} else if (IS_BLANK_CH(NXT(len))) {
10515 		    /* ignore blanks */
10516 		    ;
10517 		} else if (NXT(len) == ':') {
10518 #ifdef DEBUG_STEP
10519 		    xmlGenericError(xmlGenericErrorContext,
10520 			    "PathExpr: AbbrRelLocation\n");
10521 #endif
10522 		    lc = 1;
10523 		    break;
10524 		} else if ((NXT(len) == '(')) {
10525 		    /* Note Type or Function */
10526 		    if (xmlXPathIsNodeType(name)) {
10527 #ifdef DEBUG_STEP
10528 		        xmlGenericError(xmlGenericErrorContext,
10529 				"PathExpr: Type search\n");
10530 #endif
10531 			lc = 1;
10532 		    } else {
10533 #ifdef DEBUG_STEP
10534 		        xmlGenericError(xmlGenericErrorContext,
10535 				"PathExpr: function call\n");
10536 #endif
10537 			lc = 0;
10538 		    }
10539                     break;
10540 		} else if ((NXT(len) == '[')) {
10541 		    /* element name */
10542 #ifdef DEBUG_STEP
10543 		    xmlGenericError(xmlGenericErrorContext,
10544 			    "PathExpr: AbbrRelLocation\n");
10545 #endif
10546 		    lc = 1;
10547 		    break;
10548 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10549 			   (NXT(len) == '=')) {
10550 		    lc = 1;
10551 		    break;
10552 		} else {
10553 		    lc = 1;
10554 		    break;
10555 		}
10556 		len++;
10557 	    }
10558 	    if (NXT(len) == 0) {
10559 #ifdef DEBUG_STEP
10560 		xmlGenericError(xmlGenericErrorContext,
10561 			"PathExpr: AbbrRelLocation\n");
10562 #endif
10563 		/* element name */
10564 		lc = 1;
10565 	    }
10566 	    xmlFree(name);
10567 	} else {
10568 	    /* make sure all cases are covered explicitly */
10569 	    XP_ERROR(XPATH_EXPR_ERROR);
10570 	}
10571     }
10572 
10573     if (lc) {
10574 	if (CUR == '/') {
10575 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10576 	} else {
10577 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10578 	}
10579 	xmlXPathCompLocationPath(ctxt);
10580     } else {
10581 	xmlXPathCompFilterExpr(ctxt);
10582 	CHECK_ERROR;
10583 	if ((CUR == '/') && (NXT(1) == '/')) {
10584 	    SKIP(2);
10585 	    SKIP_BLANKS;
10586 
10587 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10588 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10589 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10590 
10591 	    xmlXPathCompRelativeLocationPath(ctxt);
10592 	} else if (CUR == '/') {
10593 	    xmlXPathCompRelativeLocationPath(ctxt);
10594 	}
10595     }
10596     SKIP_BLANKS;
10597 }
10598 
10599 /**
10600  * xmlXPathCompUnionExpr:
10601  * @ctxt:  the XPath Parser context
10602  *
10603  *  [18]   UnionExpr ::=   PathExpr
10604  *               | UnionExpr '|' PathExpr
10605  *
10606  * Compile an union expression.
10607  */
10608 
10609 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10610 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10611     xmlXPathCompPathExpr(ctxt);
10612     CHECK_ERROR;
10613     SKIP_BLANKS;
10614     while (CUR == '|') {
10615 	int op1 = ctxt->comp->last;
10616 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10617 
10618 	NEXT;
10619 	SKIP_BLANKS;
10620 	xmlXPathCompPathExpr(ctxt);
10621 
10622 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10623 
10624 	SKIP_BLANKS;
10625     }
10626 }
10627 
10628 /**
10629  * xmlXPathCompUnaryExpr:
10630  * @ctxt:  the XPath Parser context
10631  *
10632  *  [27]   UnaryExpr ::=   UnionExpr
10633  *                   | '-' UnaryExpr
10634  *
10635  * Compile an unary expression.
10636  */
10637 
10638 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10639 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10640     int minus = 0;
10641     int found = 0;
10642 
10643     SKIP_BLANKS;
10644     while (CUR == '-') {
10645         minus = 1 - minus;
10646 	found = 1;
10647 	NEXT;
10648 	SKIP_BLANKS;
10649     }
10650 
10651     xmlXPathCompUnionExpr(ctxt);
10652     CHECK_ERROR;
10653     if (found) {
10654 	if (minus)
10655 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10656 	else
10657 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10658     }
10659 }
10660 
10661 /**
10662  * xmlXPathCompMultiplicativeExpr:
10663  * @ctxt:  the XPath Parser context
10664  *
10665  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10666  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10667  *                   | MultiplicativeExpr 'div' UnaryExpr
10668  *                   | MultiplicativeExpr 'mod' UnaryExpr
10669  *  [34]   MultiplyOperator ::=   '*'
10670  *
10671  * Compile an Additive expression.
10672  */
10673 
10674 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10675 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10676     xmlXPathCompUnaryExpr(ctxt);
10677     CHECK_ERROR;
10678     SKIP_BLANKS;
10679     while ((CUR == '*') ||
10680            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10681            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10682 	int op = -1;
10683 	int op1 = ctxt->comp->last;
10684 
10685         if (CUR == '*') {
10686 	    op = 0;
10687 	    NEXT;
10688 	} else if (CUR == 'd') {
10689 	    op = 1;
10690 	    SKIP(3);
10691 	} else if (CUR == 'm') {
10692 	    op = 2;
10693 	    SKIP(3);
10694 	}
10695 	SKIP_BLANKS;
10696         xmlXPathCompUnaryExpr(ctxt);
10697 	CHECK_ERROR;
10698 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10699 	SKIP_BLANKS;
10700     }
10701 }
10702 
10703 /**
10704  * xmlXPathCompAdditiveExpr:
10705  * @ctxt:  the XPath Parser context
10706  *
10707  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10708  *                   | AdditiveExpr '+' MultiplicativeExpr
10709  *                   | AdditiveExpr '-' MultiplicativeExpr
10710  *
10711  * Compile an Additive expression.
10712  */
10713 
10714 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10715 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10716 
10717     xmlXPathCompMultiplicativeExpr(ctxt);
10718     CHECK_ERROR;
10719     SKIP_BLANKS;
10720     while ((CUR == '+') || (CUR == '-')) {
10721 	int plus;
10722 	int op1 = ctxt->comp->last;
10723 
10724         if (CUR == '+') plus = 1;
10725 	else plus = 0;
10726 	NEXT;
10727 	SKIP_BLANKS;
10728         xmlXPathCompMultiplicativeExpr(ctxt);
10729 	CHECK_ERROR;
10730 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10731 	SKIP_BLANKS;
10732     }
10733 }
10734 
10735 /**
10736  * xmlXPathCompRelationalExpr:
10737  * @ctxt:  the XPath Parser context
10738  *
10739  *  [24]   RelationalExpr ::=   AdditiveExpr
10740  *                 | RelationalExpr '<' AdditiveExpr
10741  *                 | RelationalExpr '>' AdditiveExpr
10742  *                 | RelationalExpr '<=' AdditiveExpr
10743  *                 | RelationalExpr '>=' AdditiveExpr
10744  *
10745  *  A <= B > C is allowed ? Answer from James, yes with
10746  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10747  *  which is basically what got implemented.
10748  *
10749  * Compile a Relational expression, then push the result
10750  * on the stack
10751  */
10752 
10753 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10754 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10755     xmlXPathCompAdditiveExpr(ctxt);
10756     CHECK_ERROR;
10757     SKIP_BLANKS;
10758     while ((CUR == '<') ||
10759            (CUR == '>') ||
10760            ((CUR == '<') && (NXT(1) == '=')) ||
10761            ((CUR == '>') && (NXT(1) == '='))) {
10762 	int inf, strict;
10763 	int op1 = ctxt->comp->last;
10764 
10765         if (CUR == '<') inf = 1;
10766 	else inf = 0;
10767 	if (NXT(1) == '=') strict = 0;
10768 	else strict = 1;
10769 	NEXT;
10770 	if (!strict) NEXT;
10771 	SKIP_BLANKS;
10772         xmlXPathCompAdditiveExpr(ctxt);
10773 	CHECK_ERROR;
10774 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10775 	SKIP_BLANKS;
10776     }
10777 }
10778 
10779 /**
10780  * xmlXPathCompEqualityExpr:
10781  * @ctxt:  the XPath Parser context
10782  *
10783  *  [23]   EqualityExpr ::=   RelationalExpr
10784  *                 | EqualityExpr '=' RelationalExpr
10785  *                 | EqualityExpr '!=' RelationalExpr
10786  *
10787  *  A != B != C is allowed ? Answer from James, yes with
10788  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10789  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10790  *  which is basically what got implemented.
10791  *
10792  * Compile an Equality expression.
10793  *
10794  */
10795 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10796 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10797     xmlXPathCompRelationalExpr(ctxt);
10798     CHECK_ERROR;
10799     SKIP_BLANKS;
10800     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10801 	int eq;
10802 	int op1 = ctxt->comp->last;
10803 
10804         if (CUR == '=') eq = 1;
10805 	else eq = 0;
10806 	NEXT;
10807 	if (!eq) NEXT;
10808 	SKIP_BLANKS;
10809         xmlXPathCompRelationalExpr(ctxt);
10810 	CHECK_ERROR;
10811 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10812 	SKIP_BLANKS;
10813     }
10814 }
10815 
10816 /**
10817  * xmlXPathCompAndExpr:
10818  * @ctxt:  the XPath Parser context
10819  *
10820  *  [22]   AndExpr ::=   EqualityExpr
10821  *                 | AndExpr 'and' EqualityExpr
10822  *
10823  * Compile an AND expression.
10824  *
10825  */
10826 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10827 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10828     xmlXPathCompEqualityExpr(ctxt);
10829     CHECK_ERROR;
10830     SKIP_BLANKS;
10831     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10832 	int op1 = ctxt->comp->last;
10833         SKIP(3);
10834 	SKIP_BLANKS;
10835         xmlXPathCompEqualityExpr(ctxt);
10836 	CHECK_ERROR;
10837 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10838 	SKIP_BLANKS;
10839     }
10840 }
10841 
10842 /**
10843  * xmlXPathCompileExpr:
10844  * @ctxt:  the XPath Parser context
10845  *
10846  *  [14]   Expr ::=   OrExpr
10847  *  [21]   OrExpr ::=   AndExpr
10848  *                 | OrExpr 'or' AndExpr
10849  *
10850  * Parse and compile an expression
10851  */
10852 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10853 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10854     xmlXPathCompAndExpr(ctxt);
10855     CHECK_ERROR;
10856     SKIP_BLANKS;
10857     while ((CUR == 'o') && (NXT(1) == 'r')) {
10858 	int op1 = ctxt->comp->last;
10859         SKIP(2);
10860 	SKIP_BLANKS;
10861         xmlXPathCompAndExpr(ctxt);
10862 	CHECK_ERROR;
10863 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10864 	op1 = ctxt->comp->nbStep;
10865 	SKIP_BLANKS;
10866     }
10867     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10868 	/* more ops could be optimized too */
10869 	/*
10870 	* This is the main place to eliminate sorting for
10871 	* operations which don't require a sorted node-set.
10872 	* E.g. count().
10873 	*/
10874 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10875     }
10876 }
10877 
10878 /**
10879  * xmlXPathCompPredicate:
10880  * @ctxt:  the XPath Parser context
10881  * @filter:  act as a filter
10882  *
10883  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10884  *  [9]   PredicateExpr ::=   Expr
10885  *
10886  * Compile a predicate expression
10887  */
10888 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10889 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10890     int op1 = ctxt->comp->last;
10891 
10892     SKIP_BLANKS;
10893     if (CUR != '[') {
10894 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10895     }
10896     NEXT;
10897     SKIP_BLANKS;
10898 
10899     ctxt->comp->last = -1;
10900     /*
10901     * This call to xmlXPathCompileExpr() will deactivate sorting
10902     * of the predicate result.
10903     * TODO: Sorting is still activated for filters, since I'm not
10904     *  sure if needed. Normally sorting should not be needed, since
10905     *  a filter can only diminish the number of items in a sequence,
10906     *  but won't change its order; so if the initial sequence is sorted,
10907     *  subsequent sorting is not needed.
10908     */
10909     if (! filter)
10910 	xmlXPathCompileExpr(ctxt, 0);
10911     else
10912 	xmlXPathCompileExpr(ctxt, 1);
10913     CHECK_ERROR;
10914 
10915     if (CUR != ']') {
10916 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10917     }
10918 
10919     if (filter)
10920 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10921     else
10922 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10923 
10924     NEXT;
10925     SKIP_BLANKS;
10926 }
10927 
10928 /**
10929  * xmlXPathCompNodeTest:
10930  * @ctxt:  the XPath Parser context
10931  * @test:  pointer to a xmlXPathTestVal
10932  * @type:  pointer to a xmlXPathTypeVal
10933  * @prefix:  placeholder for a possible name prefix
10934  *
10935  * [7] NodeTest ::=   NameTest
10936  *		    | NodeType '(' ')'
10937  *		    | 'processing-instruction' '(' Literal ')'
10938  *
10939  * [37] NameTest ::=  '*'
10940  *		    | NCName ':' '*'
10941  *		    | QName
10942  * [38] NodeType ::= 'comment'
10943  *		   | 'text'
10944  *		   | 'processing-instruction'
10945  *		   | 'node'
10946  *
10947  * Returns the name found and updates @test, @type and @prefix appropriately
10948  */
10949 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)10950 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10951 	             xmlXPathTypeVal *type, const xmlChar **prefix,
10952 		     xmlChar *name) {
10953     int blanks;
10954 
10955     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10956 	STRANGE;
10957 	return(NULL);
10958     }
10959     *type = (xmlXPathTypeVal) 0;
10960     *test = (xmlXPathTestVal) 0;
10961     *prefix = NULL;
10962     SKIP_BLANKS;
10963 
10964     if ((name == NULL) && (CUR == '*')) {
10965 	/*
10966 	 * All elements
10967 	 */
10968 	NEXT;
10969 	*test = NODE_TEST_ALL;
10970 	return(NULL);
10971     }
10972 
10973     if (name == NULL)
10974 	name = xmlXPathParseNCName(ctxt);
10975     if (name == NULL) {
10976 	XP_ERRORNULL(XPATH_EXPR_ERROR);
10977     }
10978 
10979     blanks = IS_BLANK_CH(CUR);
10980     SKIP_BLANKS;
10981     if (CUR == '(') {
10982 	NEXT;
10983 	/*
10984 	 * NodeType or PI search
10985 	 */
10986 	if (xmlStrEqual(name, BAD_CAST "comment"))
10987 	    *type = NODE_TYPE_COMMENT;
10988 	else if (xmlStrEqual(name, BAD_CAST "node"))
10989 	    *type = NODE_TYPE_NODE;
10990 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10991 	    *type = NODE_TYPE_PI;
10992 	else if (xmlStrEqual(name, BAD_CAST "text"))
10993 	    *type = NODE_TYPE_TEXT;
10994 	else {
10995 	    if (name != NULL)
10996 		xmlFree(name);
10997 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10998 	}
10999 
11000 	*test = NODE_TEST_TYPE;
11001 
11002 	SKIP_BLANKS;
11003 	if (*type == NODE_TYPE_PI) {
11004 	    /*
11005 	     * Specific case: search a PI by name.
11006 	     */
11007 	    if (name != NULL)
11008 		xmlFree(name);
11009 	    name = NULL;
11010 	    if (CUR != ')') {
11011 		name = xmlXPathParseLiteral(ctxt);
11012 		CHECK_ERROR NULL;
11013 		*test = NODE_TEST_PI;
11014 		SKIP_BLANKS;
11015 	    }
11016 	}
11017 	if (CUR != ')') {
11018 	    if (name != NULL)
11019 		xmlFree(name);
11020 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11021 	}
11022 	NEXT;
11023 	return(name);
11024     }
11025     *test = NODE_TEST_NAME;
11026     if ((!blanks) && (CUR == ':')) {
11027 	NEXT;
11028 
11029 	/*
11030 	 * Since currently the parser context don't have a
11031 	 * namespace list associated:
11032 	 * The namespace name for this prefix can be computed
11033 	 * only at evaluation time. The compilation is done
11034 	 * outside of any context.
11035 	 */
11036 #if 0
11037 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11038 	if (name != NULL)
11039 	    xmlFree(name);
11040 	if (*prefix == NULL) {
11041 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11042 	}
11043 #else
11044 	*prefix = name;
11045 #endif
11046 
11047 	if (CUR == '*') {
11048 	    /*
11049 	     * All elements
11050 	     */
11051 	    NEXT;
11052 	    *test = NODE_TEST_ALL;
11053 	    return(NULL);
11054 	}
11055 
11056 	name = xmlXPathParseNCName(ctxt);
11057 	if (name == NULL) {
11058 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11059 	}
11060     }
11061     return(name);
11062 }
11063 
11064 /**
11065  * xmlXPathIsAxisName:
11066  * @name:  a preparsed name token
11067  *
11068  * [6] AxisName ::=   'ancestor'
11069  *                  | 'ancestor-or-self'
11070  *                  | 'attribute'
11071  *                  | 'child'
11072  *                  | 'descendant'
11073  *                  | 'descendant-or-self'
11074  *                  | 'following'
11075  *                  | 'following-sibling'
11076  *                  | 'namespace'
11077  *                  | 'parent'
11078  *                  | 'preceding'
11079  *                  | 'preceding-sibling'
11080  *                  | 'self'
11081  *
11082  * Returns the axis or 0
11083  */
11084 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11085 xmlXPathIsAxisName(const xmlChar *name) {
11086     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11087     switch (name[0]) {
11088 	case 'a':
11089 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11090 		ret = AXIS_ANCESTOR;
11091 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11092 		ret = AXIS_ANCESTOR_OR_SELF;
11093 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11094 		ret = AXIS_ATTRIBUTE;
11095 	    break;
11096 	case 'c':
11097 	    if (xmlStrEqual(name, BAD_CAST "child"))
11098 		ret = AXIS_CHILD;
11099 	    break;
11100 	case 'd':
11101 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11102 		ret = AXIS_DESCENDANT;
11103 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11104 		ret = AXIS_DESCENDANT_OR_SELF;
11105 	    break;
11106 	case 'f':
11107 	    if (xmlStrEqual(name, BAD_CAST "following"))
11108 		ret = AXIS_FOLLOWING;
11109 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11110 		ret = AXIS_FOLLOWING_SIBLING;
11111 	    break;
11112 	case 'n':
11113 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11114 		ret = AXIS_NAMESPACE;
11115 	    break;
11116 	case 'p':
11117 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11118 		ret = AXIS_PARENT;
11119 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11120 		ret = AXIS_PRECEDING;
11121 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11122 		ret = AXIS_PRECEDING_SIBLING;
11123 	    break;
11124 	case 's':
11125 	    if (xmlStrEqual(name, BAD_CAST "self"))
11126 		ret = AXIS_SELF;
11127 	    break;
11128     }
11129     return(ret);
11130 }
11131 
11132 /**
11133  * xmlXPathCompStep:
11134  * @ctxt:  the XPath Parser context
11135  *
11136  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11137  *                  | AbbreviatedStep
11138  *
11139  * [12] AbbreviatedStep ::=   '.' | '..'
11140  *
11141  * [5] AxisSpecifier ::= AxisName '::'
11142  *                  | AbbreviatedAxisSpecifier
11143  *
11144  * [13] AbbreviatedAxisSpecifier ::= '@'?
11145  *
11146  * Modified for XPtr range support as:
11147  *
11148  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11149  *                     | AbbreviatedStep
11150  *                     | 'range-to' '(' Expr ')' Predicate*
11151  *
11152  * Compile one step in a Location Path
11153  * A location step of . is short for self::node(). This is
11154  * particularly useful in conjunction with //. For example, the
11155  * location path .//para is short for
11156  * self::node()/descendant-or-self::node()/child::para
11157  * and so will select all para descendant elements of the context
11158  * node.
11159  * Similarly, a location step of .. is short for parent::node().
11160  * For example, ../title is short for parent::node()/child::title
11161  * and so will select the title children of the parent of the context
11162  * node.
11163  */
11164 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11165 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11166 #ifdef LIBXML_XPTR_ENABLED
11167     int rangeto = 0;
11168     int op2 = -1;
11169 #endif
11170 
11171     SKIP_BLANKS;
11172     if ((CUR == '.') && (NXT(1) == '.')) {
11173 	SKIP(2);
11174 	SKIP_BLANKS;
11175 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11176 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11177     } else if (CUR == '.') {
11178 	NEXT;
11179 	SKIP_BLANKS;
11180     } else {
11181 	xmlChar *name = NULL;
11182 	const xmlChar *prefix = NULL;
11183 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11184 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11185 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11186 	int op1;
11187 
11188 	/*
11189 	 * The modification needed for XPointer change to the production
11190 	 */
11191 #ifdef LIBXML_XPTR_ENABLED
11192 	if (ctxt->xptr) {
11193 	    name = xmlXPathParseNCName(ctxt);
11194 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11195                 op2 = ctxt->comp->last;
11196 		xmlFree(name);
11197 		SKIP_BLANKS;
11198 		if (CUR != '(') {
11199 		    XP_ERROR(XPATH_EXPR_ERROR);
11200 		}
11201 		NEXT;
11202 		SKIP_BLANKS;
11203 
11204 		xmlXPathCompileExpr(ctxt, 1);
11205 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11206 		CHECK_ERROR;
11207 
11208 		SKIP_BLANKS;
11209 		if (CUR != ')') {
11210 		    XP_ERROR(XPATH_EXPR_ERROR);
11211 		}
11212 		NEXT;
11213 		rangeto = 1;
11214 		goto eval_predicates;
11215 	    }
11216 	}
11217 #endif
11218 	if (CUR == '*') {
11219 	    axis = AXIS_CHILD;
11220 	} else {
11221 	    if (name == NULL)
11222 		name = xmlXPathParseNCName(ctxt);
11223 	    if (name != NULL) {
11224 		axis = xmlXPathIsAxisName(name);
11225 		if (axis != 0) {
11226 		    SKIP_BLANKS;
11227 		    if ((CUR == ':') && (NXT(1) == ':')) {
11228 			SKIP(2);
11229 			xmlFree(name);
11230 			name = NULL;
11231 		    } else {
11232 			/* an element name can conflict with an axis one :-\ */
11233 			axis = AXIS_CHILD;
11234 		    }
11235 		} else {
11236 		    axis = AXIS_CHILD;
11237 		}
11238 	    } else if (CUR == '@') {
11239 		NEXT;
11240 		axis = AXIS_ATTRIBUTE;
11241 	    } else {
11242 		axis = AXIS_CHILD;
11243 	    }
11244 	}
11245 
11246 	CHECK_ERROR;
11247 
11248 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11249 	if (test == 0)
11250 	    return;
11251 
11252         if ((prefix != NULL) && (ctxt->context != NULL) &&
11253 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11254 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11255 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11256 	    }
11257 	}
11258 #ifdef DEBUG_STEP
11259 	xmlGenericError(xmlGenericErrorContext,
11260 		"Basis : computing new set\n");
11261 #endif
11262 
11263 #ifdef DEBUG_STEP
11264 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11265 	if (ctxt->value == NULL)
11266 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11267 	else if (ctxt->value->nodesetval == NULL)
11268 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11269 	else
11270 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11271 #endif
11272 
11273 #ifdef LIBXML_XPTR_ENABLED
11274 eval_predicates:
11275 #endif
11276 	op1 = ctxt->comp->last;
11277 	ctxt->comp->last = -1;
11278 
11279 	SKIP_BLANKS;
11280 	while (CUR == '[') {
11281 	    xmlXPathCompPredicate(ctxt, 0);
11282 	}
11283 
11284 #ifdef LIBXML_XPTR_ENABLED
11285 	if (rangeto) {
11286 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11287 	} else
11288 #endif
11289 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11290 			   test, type, (void *)prefix, (void *)name);
11291 
11292     }
11293 #ifdef DEBUG_STEP
11294     xmlGenericError(xmlGenericErrorContext, "Step : ");
11295     if (ctxt->value == NULL)
11296 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11297     else if (ctxt->value->nodesetval == NULL)
11298 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11299     else
11300 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11301 		ctxt->value->nodesetval);
11302 #endif
11303 }
11304 
11305 /**
11306  * xmlXPathCompRelativeLocationPath:
11307  * @ctxt:  the XPath Parser context
11308  *
11309  *  [3]   RelativeLocationPath ::=   Step
11310  *                     | RelativeLocationPath '/' Step
11311  *                     | AbbreviatedRelativeLocationPath
11312  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11313  *
11314  * Compile a relative location path.
11315  */
11316 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11317 xmlXPathCompRelativeLocationPath
11318 (xmlXPathParserContextPtr ctxt) {
11319     SKIP_BLANKS;
11320     if ((CUR == '/') && (NXT(1) == '/')) {
11321 	SKIP(2);
11322 	SKIP_BLANKS;
11323 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11324 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11325     } else if (CUR == '/') {
11326 	    NEXT;
11327 	SKIP_BLANKS;
11328     }
11329     xmlXPathCompStep(ctxt);
11330     SKIP_BLANKS;
11331     while (CUR == '/') {
11332 	if ((CUR == '/') && (NXT(1) == '/')) {
11333 	    SKIP(2);
11334 	    SKIP_BLANKS;
11335 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11336 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11337 	    xmlXPathCompStep(ctxt);
11338 	} else if (CUR == '/') {
11339 	    NEXT;
11340 	    SKIP_BLANKS;
11341 	    xmlXPathCompStep(ctxt);
11342 	}
11343 	SKIP_BLANKS;
11344     }
11345 }
11346 
11347 /**
11348  * xmlXPathCompLocationPath:
11349  * @ctxt:  the XPath Parser context
11350  *
11351  *  [1]   LocationPath ::=   RelativeLocationPath
11352  *                     | AbsoluteLocationPath
11353  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11354  *                     | AbbreviatedAbsoluteLocationPath
11355  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11356  *                           '//' RelativeLocationPath
11357  *
11358  * Compile a location path
11359  *
11360  * // is short for /descendant-or-self::node()/. For example,
11361  * //para is short for /descendant-or-self::node()/child::para and
11362  * so will select any para element in the document (even a para element
11363  * that is a document element will be selected by //para since the
11364  * document element node is a child of the root node); div//para is
11365  * short for div/descendant-or-self::node()/child::para and so will
11366  * select all para descendants of div children.
11367  */
11368 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11369 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11370     SKIP_BLANKS;
11371     if (CUR != '/') {
11372         xmlXPathCompRelativeLocationPath(ctxt);
11373     } else {
11374 	while (CUR == '/') {
11375 	    if ((CUR == '/') && (NXT(1) == '/')) {
11376 		SKIP(2);
11377 		SKIP_BLANKS;
11378 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11379 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11380 		xmlXPathCompRelativeLocationPath(ctxt);
11381 	    } else if (CUR == '/') {
11382 		NEXT;
11383 		SKIP_BLANKS;
11384 		if ((CUR != 0 ) &&
11385 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11386 		     (CUR == '@') || (CUR == '*')))
11387 		    xmlXPathCompRelativeLocationPath(ctxt);
11388 	    }
11389 	}
11390     }
11391 }
11392 
11393 /************************************************************************
11394  *									*
11395  * 		XPath precompiled expression evaluation			*
11396  *									*
11397  ************************************************************************/
11398 
11399 static int
11400 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11401 
11402 #ifdef DEBUG_STEP
11403 static void
xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,xmlXPathTestVal test,int nbNodes)11404 xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11405 			  xmlXPathTestVal test,
11406 			  int nbNodes)
11407 {
11408     xmlGenericError(xmlGenericErrorContext, "new step : ");
11409     switch (axis) {
11410         case AXIS_ANCESTOR:
11411             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11412             break;
11413         case AXIS_ANCESTOR_OR_SELF:
11414             xmlGenericError(xmlGenericErrorContext,
11415                             "axis 'ancestors-or-self' ");
11416             break;
11417         case AXIS_ATTRIBUTE:
11418             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11419             break;
11420         case AXIS_CHILD:
11421             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11422             break;
11423         case AXIS_DESCENDANT:
11424             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11425             break;
11426         case AXIS_DESCENDANT_OR_SELF:
11427             xmlGenericError(xmlGenericErrorContext,
11428                             "axis 'descendant-or-self' ");
11429             break;
11430         case AXIS_FOLLOWING:
11431             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11432             break;
11433         case AXIS_FOLLOWING_SIBLING:
11434             xmlGenericError(xmlGenericErrorContext,
11435                             "axis 'following-siblings' ");
11436             break;
11437         case AXIS_NAMESPACE:
11438             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11439             break;
11440         case AXIS_PARENT:
11441             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11442             break;
11443         case AXIS_PRECEDING:
11444             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11445             break;
11446         case AXIS_PRECEDING_SIBLING:
11447             xmlGenericError(xmlGenericErrorContext,
11448                             "axis 'preceding-sibling' ");
11449             break;
11450         case AXIS_SELF:
11451             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11452             break;
11453     }
11454     xmlGenericError(xmlGenericErrorContext,
11455 	" context contains %d nodes\n", nbNodes);
11456     switch (test) {
11457         case NODE_TEST_NONE:
11458             xmlGenericError(xmlGenericErrorContext,
11459                             "           searching for none !!!\n");
11460             break;
11461         case NODE_TEST_TYPE:
11462             xmlGenericError(xmlGenericErrorContext,
11463                             "           searching for type %d\n", type);
11464             break;
11465         case NODE_TEST_PI:
11466             xmlGenericError(xmlGenericErrorContext,
11467                             "           searching for PI !!!\n");
11468             break;
11469         case NODE_TEST_ALL:
11470             xmlGenericError(xmlGenericErrorContext,
11471                             "           searching for *\n");
11472             break;
11473         case NODE_TEST_NS:
11474             xmlGenericError(xmlGenericErrorContext,
11475                             "           searching for namespace %s\n",
11476                             prefix);
11477             break;
11478         case NODE_TEST_NAME:
11479             xmlGenericError(xmlGenericErrorContext,
11480                             "           searching for name %s\n", name);
11481             if (prefix != NULL)
11482                 xmlGenericError(xmlGenericErrorContext,
11483                                 "           with namespace %s\n", prefix);
11484             break;
11485     }
11486     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11487 }
11488 #endif /* DEBUG_STEP */
11489 
11490 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11491 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11492 			    xmlXPathStepOpPtr op,
11493 			    xmlNodeSetPtr set,
11494 			    int contextSize,
11495 			    int hasNsNodes)
11496 {
11497     if (op->ch1 != -1) {
11498 	xmlXPathCompExprPtr comp = ctxt->comp;
11499 	/*
11500 	* Process inner predicates first.
11501 	*/
11502 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11503 	    /*
11504 	    * TODO: raise an internal error.
11505 	    */
11506 	}
11507 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11508 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11509 	CHECK_ERROR0;
11510 	if (contextSize <= 0)
11511 	    return(0);
11512     }
11513     if (op->ch2 != -1) {
11514 	xmlXPathContextPtr xpctxt = ctxt->context;
11515 	xmlNodePtr contextNode, oldContextNode;
11516 	xmlDocPtr oldContextDoc;
11517 	int i, res, contextPos = 0, newContextSize;
11518 	xmlXPathStepOpPtr exprOp;
11519 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11520 
11521 #ifdef LIBXML_XPTR_ENABLED
11522 	/*
11523 	* URGENT TODO: Check the following:
11524 	*  We don't expect location sets if evaluating prediates, right?
11525 	*  Only filters should expect location sets, right?
11526 	*/
11527 #endif
11528 	/*
11529 	* SPEC XPath 1.0:
11530 	*  "For each node in the node-set to be filtered, the
11531 	*  PredicateExpr is evaluated with that node as the
11532 	*  context node, with the number of nodes in the
11533 	*  node-set as the context size, and with the proximity
11534 	*  position of the node in the node-set with respect to
11535 	*  the axis as the context position;"
11536 	* @oldset is the node-set" to be filtered.
11537 	*
11538 	* SPEC XPath 1.0:
11539 	*  "only predicates change the context position and
11540 	*  context size (see [2.4 Predicates])."
11541 	* Example:
11542 	*   node-set  context pos
11543 	*    nA         1
11544 	*    nB         2
11545 	*    nC         3
11546 	*   After applying predicate [position() > 1] :
11547 	*   node-set  context pos
11548 	*    nB         1
11549 	*    nC         2
11550 	*/
11551 	oldContextNode = xpctxt->node;
11552 	oldContextDoc = xpctxt->doc;
11553 	/*
11554 	* Get the expression of this predicate.
11555 	*/
11556 	exprOp = &ctxt->comp->steps[op->ch2];
11557 	newContextSize = 0;
11558 	for (i = 0; i < set->nodeNr; i++) {
11559 	    if (set->nodeTab[i] == NULL)
11560 		continue;
11561 
11562 	    contextNode = set->nodeTab[i];
11563 	    xpctxt->node = contextNode;
11564 	    xpctxt->contextSize = contextSize;
11565 	    xpctxt->proximityPosition = ++contextPos;
11566 
11567 	    /*
11568 	    * Also set the xpath document in case things like
11569 	    * key() are evaluated in the predicate.
11570 	    */
11571 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11572 		(contextNode->doc != NULL))
11573 		xpctxt->doc = contextNode->doc;
11574 	    /*
11575 	    * Evaluate the predicate expression with 1 context node
11576 	    * at a time; this node is packaged into a node set; this
11577 	    * node set is handed over to the evaluation mechanism.
11578 	    */
11579 	    if (contextObj == NULL)
11580 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11581 	    else
11582 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11583 		    contextNode);
11584 
11585 	    valuePush(ctxt, contextObj);
11586 
11587 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11588 
11589 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11590 		xmlXPathNodeSetClear(set, hasNsNodes);
11591 		newContextSize = 0;
11592 		goto evaluation_exit;
11593 	    }
11594 
11595 	    if (res != 0) {
11596 		newContextSize++;
11597 	    } else {
11598 		/*
11599 		* Remove the entry from the initial node set.
11600 		*/
11601 		set->nodeTab[i] = NULL;
11602 		if (contextNode->type == XML_NAMESPACE_DECL)
11603 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11604 	    }
11605 	    if (ctxt->value == contextObj) {
11606 		/*
11607 		* Don't free the temporary XPath object holding the
11608 		* context node, in order to avoid massive recreation
11609 		* inside this loop.
11610 		*/
11611 		valuePop(ctxt);
11612 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11613 	    } else {
11614 		/*
11615 		* TODO: The object was lost in the evaluation machinery.
11616 		*  Can this happen? Maybe in internal-error cases.
11617 		*/
11618 		contextObj = NULL;
11619 	    }
11620 	}
11621 
11622 	if (contextObj != NULL) {
11623 	    if (ctxt->value == contextObj)
11624 		valuePop(ctxt);
11625 	    xmlXPathReleaseObject(xpctxt, contextObj);
11626 	}
11627 evaluation_exit:
11628 	if (exprRes != NULL)
11629 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11630 	/*
11631 	* Reset/invalidate the context.
11632 	*/
11633 	xpctxt->node = oldContextNode;
11634 	xpctxt->doc = oldContextDoc;
11635 	xpctxt->contextSize = -1;
11636 	xpctxt->proximityPosition = -1;
11637 	return(newContextSize);
11638     }
11639     return(contextSize);
11640 }
11641 
11642 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11643 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11644 				      xmlXPathStepOpPtr op,
11645 				      xmlNodeSetPtr set,
11646 				      int contextSize,
11647 				      int minPos,
11648 				      int maxPos,
11649 				      int hasNsNodes)
11650 {
11651     if (op->ch1 != -1) {
11652 	xmlXPathCompExprPtr comp = ctxt->comp;
11653 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11654 	    /*
11655 	    * TODO: raise an internal error.
11656 	    */
11657 	}
11658 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11659 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11660 	CHECK_ERROR0;
11661 	if (contextSize <= 0)
11662 	    return(0);
11663     }
11664     /*
11665     * Check if the node set contains a sufficient number of nodes for
11666     * the requested range.
11667     */
11668     if (contextSize < minPos) {
11669 	xmlXPathNodeSetClear(set, hasNsNodes);
11670 	return(0);
11671     }
11672     if (op->ch2 == -1) {
11673 	/*
11674 	* TODO: Can this ever happen?
11675 	*/
11676 	return (contextSize);
11677     } else {
11678 	xmlDocPtr oldContextDoc;
11679 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11680 	xmlXPathStepOpPtr exprOp;
11681 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11682 	xmlNodePtr oldContextNode, contextNode = NULL;
11683 	xmlXPathContextPtr xpctxt = ctxt->context;
11684 
11685 #ifdef LIBXML_XPTR_ENABLED
11686 	    /*
11687 	    * URGENT TODO: Check the following:
11688 	    *  We don't expect location sets if evaluating prediates, right?
11689 	    *  Only filters should expect location sets, right?
11690 	*/
11691 #endif /* LIBXML_XPTR_ENABLED */
11692 
11693 	/*
11694 	* Save old context.
11695 	*/
11696 	oldContextNode = xpctxt->node;
11697 	oldContextDoc = xpctxt->doc;
11698 	/*
11699 	* Get the expression of this predicate.
11700 	*/
11701 	exprOp = &ctxt->comp->steps[op->ch2];
11702 	for (i = 0; i < set->nodeNr; i++) {
11703 	    if (set->nodeTab[i] == NULL)
11704 		continue;
11705 
11706 	    contextNode = set->nodeTab[i];
11707 	    xpctxt->node = contextNode;
11708 	    xpctxt->contextSize = contextSize;
11709 	    xpctxt->proximityPosition = ++contextPos;
11710 
11711 	    /*
11712 	    * Initialize the new set.
11713 	    * Also set the xpath document in case things like
11714 	    * key() evaluation are attempted on the predicate
11715 	    */
11716 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11717 		(contextNode->doc != NULL))
11718 		xpctxt->doc = contextNode->doc;
11719 	    /*
11720 	    * Evaluate the predicate expression with 1 context node
11721 	    * at a time; this node is packaged into a node set; this
11722 	    * node set is handed over to the evaluation mechanism.
11723 	    */
11724 	    if (contextObj == NULL)
11725 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11726 	    else
11727 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11728 		    contextNode);
11729 
11730 	    valuePush(ctxt, contextObj);
11731 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11732 
11733 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11734 	        xmlXPathObjectPtr tmp;
11735 		/* pop the result */
11736 		tmp = valuePop(ctxt);
11737 		xmlXPathReleaseObject(xpctxt, tmp);
11738 		/* then pop off contextObj, which will be freed later */
11739 		valuePop(ctxt);
11740 		goto evaluation_error;
11741 	    }
11742 
11743 	    if (res)
11744 		pos++;
11745 
11746 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11747 		/*
11748 		* Fits in the requested range.
11749 		*/
11750 		newContextSize++;
11751 		if (minPos == maxPos) {
11752 		    /*
11753 		    * Only 1 node was requested.
11754 		    */
11755 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11756 			/*
11757 			* As always: take care of those nasty
11758 			* namespace nodes.
11759 			*/
11760 			set->nodeTab[i] = NULL;
11761 		    }
11762 		    xmlXPathNodeSetClear(set, hasNsNodes);
11763 		    set->nodeNr = 1;
11764 		    set->nodeTab[0] = contextNode;
11765 		    goto evaluation_exit;
11766 		}
11767 		if (pos == maxPos) {
11768 		    /*
11769 		    * We are done.
11770 		    */
11771 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11772 		    goto evaluation_exit;
11773 		}
11774 	    } else {
11775 		/*
11776 		* Remove the entry from the initial node set.
11777 		*/
11778 		set->nodeTab[i] = NULL;
11779 		if (contextNode->type == XML_NAMESPACE_DECL)
11780 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11781 	    }
11782 	    if (exprRes != NULL) {
11783 		xmlXPathReleaseObject(ctxt->context, exprRes);
11784 		exprRes = NULL;
11785 	    }
11786 	    if (ctxt->value == contextObj) {
11787 		/*
11788 		* Don't free the temporary XPath object holding the
11789 		* context node, in order to avoid massive recreation
11790 		* inside this loop.
11791 		*/
11792 		valuePop(ctxt);
11793 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11794 	    } else {
11795 		/*
11796 		* The object was lost in the evaluation machinery.
11797 		* Can this happen? Maybe in case of internal-errors.
11798 		*/
11799 		contextObj = NULL;
11800 	    }
11801 	}
11802 	goto evaluation_exit;
11803 
11804 evaluation_error:
11805 	xmlXPathNodeSetClear(set, hasNsNodes);
11806 	newContextSize = 0;
11807 
11808 evaluation_exit:
11809 	if (contextObj != NULL) {
11810 	    if (ctxt->value == contextObj)
11811 		valuePop(ctxt);
11812 	    xmlXPathReleaseObject(xpctxt, contextObj);
11813 	}
11814 	if (exprRes != NULL)
11815 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11816 	/*
11817 	* Reset/invalidate the context.
11818 	*/
11819 	xpctxt->node = oldContextNode;
11820 	xpctxt->doc = oldContextDoc;
11821 	xpctxt->contextSize = -1;
11822 	xpctxt->proximityPosition = -1;
11823 	return(newContextSize);
11824     }
11825     return(contextSize);
11826 }
11827 
11828 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11829 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11830 			    xmlXPathStepOpPtr op,
11831 			    int *maxPos)
11832 {
11833 
11834     xmlXPathStepOpPtr exprOp;
11835 
11836     /*
11837     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11838     */
11839 
11840     /*
11841     * If not -1, then ch1 will point to:
11842     * 1) For predicates (XPATH_OP_PREDICATE):
11843     *    - an inner predicate operator
11844     * 2) For filters (XPATH_OP_FILTER):
11845     *    - an inner filter operater OR
11846     *    - an expression selecting the node set.
11847     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11848     */
11849     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11850 	return(0);
11851 
11852     if (op->ch2 != -1) {
11853 	exprOp = &ctxt->comp->steps[op->ch2];
11854     } else
11855 	return(0);
11856 
11857     if ((exprOp != NULL) &&
11858 	(exprOp->op == XPATH_OP_VALUE) &&
11859 	(exprOp->value4 != NULL) &&
11860 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11861     {
11862 	/*
11863 	* We have a "[n]" predicate here.
11864 	* TODO: Unfortunately this simplistic test here is not
11865 	* able to detect a position() predicate in compound
11866 	* expressions like "[@attr = 'a" and position() = 1],
11867 	* and even not the usage of position() in
11868 	* "[position() = 1]"; thus - obviously - a position-range,
11869 	* like it "[position() < 5]", is also not detected.
11870 	* Maybe we could rewrite the AST to ease the optimization.
11871 	*/
11872 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11873 
11874 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11875 	    (float) *maxPos)
11876 	{
11877 	    return(1);
11878 	}
11879     }
11880     return(0);
11881 }
11882 
11883 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11884 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11885                            xmlXPathStepOpPtr op,
11886 			   xmlNodePtr * first, xmlNodePtr * last,
11887 			   int toBool)
11888 {
11889 
11890 #define XP_TEST_HIT \
11891     if (hasAxisRange != 0) { \
11892 	if (++pos == maxPos) { \
11893 	    addNode(seq, cur); \
11894 	goto axis_range_end; } \
11895     } else { \
11896 	addNode(seq, cur); \
11897 	if (breakOnFirstHit) goto first_hit; }
11898 
11899 #define XP_TEST_HIT_NS \
11900     if (hasAxisRange != 0) { \
11901 	if (++pos == maxPos) { \
11902 	    hasNsNodes = 1; \
11903 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11904 	goto axis_range_end; } \
11905     } else { \
11906 	hasNsNodes = 1; \
11907 	xmlXPathNodeSetAddNs(seq, \
11908 	xpctxt->node, (xmlNsPtr) cur); \
11909 	if (breakOnFirstHit) goto first_hit; }
11910 
11911     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11912     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11913     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11914     const xmlChar *prefix = op->value4;
11915     const xmlChar *name = op->value5;
11916     const xmlChar *URI = NULL;
11917 
11918 #ifdef DEBUG_STEP
11919     int nbMatches = 0, prevMatches = 0;
11920 #endif
11921     int total = 0, hasNsNodes = 0;
11922     /* The popped object holding the context nodes */
11923     xmlXPathObjectPtr obj;
11924     /* The set of context nodes for the node tests */
11925     xmlNodeSetPtr contextSeq;
11926     int contextIdx;
11927     xmlNodePtr contextNode;
11928     /* The context node for a compound traversal */
11929     xmlNodePtr outerContextNode;
11930     /* The final resulting node set wrt to all context nodes */
11931     xmlNodeSetPtr outSeq;
11932     /*
11933     * The temporary resulting node set wrt 1 context node.
11934     * Used to feed predicate evaluation.
11935     */
11936     xmlNodeSetPtr seq;
11937     xmlNodePtr cur;
11938     /* First predicate operator */
11939     xmlXPathStepOpPtr predOp;
11940     int maxPos; /* The requested position() (when a "[n]" predicate) */
11941     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11942     int breakOnFirstHit;
11943 
11944     xmlXPathTraversalFunction next = NULL;
11945     /* compound axis traversal */
11946     xmlXPathTraversalFunctionExt outerNext = NULL;
11947     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11948     xmlXPathNodeSetMergeFunction mergeAndClear;
11949     xmlNodePtr oldContextNode;
11950     xmlXPathContextPtr xpctxt = ctxt->context;
11951 
11952 
11953     CHECK_TYPE0(XPATH_NODESET);
11954     obj = valuePop(ctxt);
11955     /*
11956     * Setup namespaces.
11957     */
11958     if (prefix != NULL) {
11959         URI = xmlXPathNsLookup(xpctxt, prefix);
11960         if (URI == NULL) {
11961 	    xmlXPathReleaseObject(xpctxt, obj);
11962             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11963 	}
11964     }
11965     /*
11966     * Setup axis.
11967     *
11968     * MAYBE FUTURE TODO: merging optimizations:
11969     * - If the nodes to be traversed wrt to the initial nodes and
11970     *   the current axis cannot overlap, then we could avoid searching
11971     *   for duplicates during the merge.
11972     *   But the question is how/when to evaluate if they cannot overlap.
11973     *   Example: if we know that for two initial nodes, the one is
11974     *   not in the ancestor-or-self axis of the other, then we could safely
11975     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11976     *   the descendant-or-self axis.
11977     */
11978     addNode = xmlXPathNodeSetAdd;
11979     mergeAndClear = xmlXPathNodeSetMergeAndClear;
11980     switch (axis) {
11981         case AXIS_ANCESTOR:
11982             first = NULL;
11983             next = xmlXPathNextAncestor;
11984             break;
11985         case AXIS_ANCESTOR_OR_SELF:
11986             first = NULL;
11987             next = xmlXPathNextAncestorOrSelf;
11988             break;
11989         case AXIS_ATTRIBUTE:
11990             first = NULL;
11991 	    last = NULL;
11992             next = xmlXPathNextAttribute;
11993 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11994             break;
11995         case AXIS_CHILD:
11996 	    last = NULL;
11997 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11998 		/*
11999 		* This iterator will give us only nodes which can
12000 		* hold element nodes.
12001 		*/
12002 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12003 	    }
12004 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12005 		(type == NODE_TYPE_NODE))
12006 	    {
12007 		/*
12008 		* Optimization if an element node type is 'element'.
12009 		*/
12010 		next = xmlXPathNextChildElement;
12011 	    } else
12012 		next = xmlXPathNextChild;
12013 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12014             break;
12015         case AXIS_DESCENDANT:
12016 	    last = NULL;
12017             next = xmlXPathNextDescendant;
12018             break;
12019         case AXIS_DESCENDANT_OR_SELF:
12020 	    last = NULL;
12021             next = xmlXPathNextDescendantOrSelf;
12022             break;
12023         case AXIS_FOLLOWING:
12024 	    last = NULL;
12025             next = xmlXPathNextFollowing;
12026             break;
12027         case AXIS_FOLLOWING_SIBLING:
12028 	    last = NULL;
12029             next = xmlXPathNextFollowingSibling;
12030             break;
12031         case AXIS_NAMESPACE:
12032             first = NULL;
12033 	    last = NULL;
12034             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12035 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12036             break;
12037         case AXIS_PARENT:
12038             first = NULL;
12039             next = xmlXPathNextParent;
12040             break;
12041         case AXIS_PRECEDING:
12042             first = NULL;
12043             next = xmlXPathNextPrecedingInternal;
12044             break;
12045         case AXIS_PRECEDING_SIBLING:
12046             first = NULL;
12047             next = xmlXPathNextPrecedingSibling;
12048             break;
12049         case AXIS_SELF:
12050             first = NULL;
12051 	    last = NULL;
12052             next = xmlXPathNextSelf;
12053 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12054             break;
12055     }
12056 
12057 #ifdef DEBUG_STEP
12058     xmlXPathDebugDumpStepAxis(axis, test,
12059 	(obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12060 #endif
12061 
12062     if (next == NULL) {
12063 	xmlXPathReleaseObject(xpctxt, obj);
12064         return(0);
12065     }
12066     contextSeq = obj->nodesetval;
12067     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12068 	xmlXPathReleaseObject(xpctxt, obj);
12069         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12070         return(0);
12071     }
12072     /*
12073     * Predicate optimization ---------------------------------------------
12074     * If this step has a last predicate, which contains a position(),
12075     * then we'll optimize (although not exactly "position()", but only
12076     * the  short-hand form, i.e., "[n]".
12077     *
12078     * Example - expression "/foo[parent::bar][1]":
12079     *
12080     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12081     *   ROOT                               -- op->ch1
12082     *   PREDICATE                          -- op->ch2 (predOp)
12083     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12084     *       SORT
12085     *         COLLECT  'parent' 'name' 'node' bar
12086     *           NODE
12087     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12088     *
12089     */
12090     maxPos = 0;
12091     predOp = NULL;
12092     hasPredicateRange = 0;
12093     hasAxisRange = 0;
12094     if (op->ch2 != -1) {
12095 	/*
12096 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12097 	*/
12098 	predOp = &ctxt->comp->steps[op->ch2];
12099 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12100 	    if (predOp->ch1 != -1) {
12101 		/*
12102 		* Use the next inner predicate operator.
12103 		*/
12104 		predOp = &ctxt->comp->steps[predOp->ch1];
12105 		hasPredicateRange = 1;
12106 	    } else {
12107 		/*
12108 		* There's no other predicate than the [n] predicate.
12109 		*/
12110 		predOp = NULL;
12111 		hasAxisRange = 1;
12112 	    }
12113 	}
12114     }
12115     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12116     /*
12117     * Axis traversal -----------------------------------------------------
12118     */
12119     /*
12120      * 2.3 Node Tests
12121      *  - For the attribute axis, the principal node type is attribute.
12122      *  - For the namespace axis, the principal node type is namespace.
12123      *  - For other axes, the principal node type is element.
12124      *
12125      * A node test * is true for any node of the
12126      * principal node type. For example, child::* will
12127      * select all element children of the context node
12128      */
12129     oldContextNode = xpctxt->node;
12130     addNode = xmlXPathNodeSetAddUnique;
12131     outSeq = NULL;
12132     seq = NULL;
12133     outerContextNode = NULL;
12134     contextNode = NULL;
12135     contextIdx = 0;
12136 
12137 
12138     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12139 	if (outerNext != NULL) {
12140 	    /*
12141 	    * This is a compound traversal.
12142 	    */
12143 	    if (contextNode == NULL) {
12144 		/*
12145 		* Set the context for the outer traversal.
12146 		*/
12147 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12148 		contextNode = outerNext(NULL, outerContextNode);
12149 	    } else
12150 		contextNode = outerNext(contextNode, outerContextNode);
12151 	    if (contextNode == NULL)
12152 		continue;
12153 	    /*
12154 	    * Set the context for the main traversal.
12155 	    */
12156 	    xpctxt->node = contextNode;
12157 	} else
12158 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12159 
12160 	if (seq == NULL) {
12161 	    seq = xmlXPathNodeSetCreate(NULL);
12162 	    if (seq == NULL) {
12163 		total = 0;
12164 		goto error;
12165 	    }
12166 	}
12167 	/*
12168 	* Traverse the axis and test the nodes.
12169 	*/
12170 	pos = 0;
12171 	cur = NULL;
12172 	hasNsNodes = 0;
12173         do {
12174             cur = next(ctxt, cur);
12175             if (cur == NULL)
12176                 break;
12177 
12178 	    /*
12179 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12180 	    */
12181             if ((first != NULL) && (*first != NULL)) {
12182 		if (*first == cur)
12183 		    break;
12184 		if (((total % 256) == 0) &&
12185 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12186 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12187 #else
12188 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12189 #endif
12190 		{
12191 		    break;
12192 		}
12193 	    }
12194 	    if ((last != NULL) && (*last != NULL)) {
12195 		if (*last == cur)
12196 		    break;
12197 		if (((total % 256) == 0) &&
12198 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12199 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12200 #else
12201 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12202 #endif
12203 		{
12204 		    break;
12205 		}
12206 	    }
12207 
12208             total++;
12209 
12210 #ifdef DEBUG_STEP
12211             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12212 #endif
12213 
12214 	    switch (test) {
12215                 case NODE_TEST_NONE:
12216 		    total = 0;
12217                     STRANGE
12218 		    goto error;
12219                 case NODE_TEST_TYPE:
12220 		    /*
12221 		    * TODO: Don't we need to use
12222 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12223 		    *  Surprisingly, some c14n tests fail, if we do this.
12224 		    */
12225 		    if (type == NODE_TYPE_NODE) {
12226 			switch (cur->type) {
12227 			    case XML_DOCUMENT_NODE:
12228 			    case XML_HTML_DOCUMENT_NODE:
12229 #ifdef LIBXML_DOCB_ENABLED
12230 			    case XML_DOCB_DOCUMENT_NODE:
12231 #endif
12232 			    case XML_ELEMENT_NODE:
12233 			    case XML_ATTRIBUTE_NODE:
12234 			    case XML_PI_NODE:
12235 			    case XML_COMMENT_NODE:
12236 			    case XML_CDATA_SECTION_NODE:
12237 			    case XML_TEXT_NODE:
12238 			    case XML_NAMESPACE_DECL:
12239 				XP_TEST_HIT
12240 				break;
12241 			    default:
12242 				break;
12243 			}
12244 		    } else if (cur->type == type) {
12245 			if (type == XML_NAMESPACE_DECL)
12246 			    XP_TEST_HIT_NS
12247 			else
12248 			    XP_TEST_HIT
12249 		    } else if ((type == NODE_TYPE_TEXT) &&
12250 			 (cur->type == XML_CDATA_SECTION_NODE))
12251 		    {
12252 			XP_TEST_HIT
12253 		    }
12254 		    break;
12255                 case NODE_TEST_PI:
12256                     if ((cur->type == XML_PI_NODE) &&
12257                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12258 		    {
12259 			XP_TEST_HIT
12260                     }
12261                     break;
12262                 case NODE_TEST_ALL:
12263                     if (axis == AXIS_ATTRIBUTE) {
12264                         if (cur->type == XML_ATTRIBUTE_NODE)
12265 			{
12266 			    XP_TEST_HIT
12267                         }
12268                     } else if (axis == AXIS_NAMESPACE) {
12269                         if (cur->type == XML_NAMESPACE_DECL)
12270 			{
12271 			    XP_TEST_HIT_NS
12272                         }
12273                     } else {
12274                         if (cur->type == XML_ELEMENT_NODE) {
12275                             if (prefix == NULL)
12276 			    {
12277 				XP_TEST_HIT
12278 
12279                             } else if ((cur->ns != NULL) &&
12280 				(xmlStrEqual(URI, cur->ns->href)))
12281 			    {
12282 				XP_TEST_HIT
12283                             }
12284                         }
12285                     }
12286                     break;
12287                 case NODE_TEST_NS:{
12288                         TODO;
12289                         break;
12290                     }
12291                 case NODE_TEST_NAME:
12292                     if (axis == AXIS_ATTRIBUTE) {
12293                         if (cur->type != XML_ATTRIBUTE_NODE)
12294 			    break;
12295 		    } else if (axis == AXIS_NAMESPACE) {
12296                         if (cur->type != XML_NAMESPACE_DECL)
12297 			    break;
12298 		    } else {
12299 		        if (cur->type != XML_ELEMENT_NODE)
12300 			    break;
12301 		    }
12302                     switch (cur->type) {
12303                         case XML_ELEMENT_NODE:
12304                             if (xmlStrEqual(name, cur->name)) {
12305                                 if (prefix == NULL) {
12306                                     if (cur->ns == NULL)
12307 				    {
12308 					XP_TEST_HIT
12309                                     }
12310                                 } else {
12311                                     if ((cur->ns != NULL) &&
12312                                         (xmlStrEqual(URI, cur->ns->href)))
12313 				    {
12314 					XP_TEST_HIT
12315                                     }
12316                                 }
12317                             }
12318                             break;
12319                         case XML_ATTRIBUTE_NODE:{
12320                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12321 
12322                                 if (xmlStrEqual(name, attr->name)) {
12323                                     if (prefix == NULL) {
12324                                         if ((attr->ns == NULL) ||
12325                                             (attr->ns->prefix == NULL))
12326 					{
12327 					    XP_TEST_HIT
12328                                         }
12329                                     } else {
12330                                         if ((attr->ns != NULL) &&
12331                                             (xmlStrEqual(URI,
12332 					      attr->ns->href)))
12333 					{
12334 					    XP_TEST_HIT
12335                                         }
12336                                     }
12337                                 }
12338                                 break;
12339                             }
12340                         case XML_NAMESPACE_DECL:
12341                             if (cur->type == XML_NAMESPACE_DECL) {
12342                                 xmlNsPtr ns = (xmlNsPtr) cur;
12343 
12344                                 if ((ns->prefix != NULL) && (name != NULL)
12345                                     && (xmlStrEqual(ns->prefix, name)))
12346 				{
12347 				    XP_TEST_HIT_NS
12348                                 }
12349                             }
12350                             break;
12351                         default:
12352                             break;
12353                     }
12354                     break;
12355 	    } /* switch(test) */
12356         } while (cur != NULL);
12357 
12358 	goto apply_predicates;
12359 
12360 axis_range_end: /* ----------------------------------------------------- */
12361 	/*
12362 	* We have a "/foo[n]", and position() = n was reached.
12363 	* Note that we can have as well "/foo/::parent::foo[1]", so
12364 	* a duplicate-aware merge is still needed.
12365 	* Merge with the result.
12366 	*/
12367 	if (outSeq == NULL) {
12368 	    outSeq = seq;
12369 	    seq = NULL;
12370 	} else
12371 	    outSeq = mergeAndClear(outSeq, seq, 0);
12372 	/*
12373 	* Break if only a true/false result was requested.
12374 	*/
12375 	if (toBool)
12376 	    break;
12377 	continue;
12378 
12379 first_hit: /* ---------------------------------------------------------- */
12380 	/*
12381 	* Break if only a true/false result was requested and
12382 	* no predicates existed and a node test succeeded.
12383 	*/
12384 	if (outSeq == NULL) {
12385 	    outSeq = seq;
12386 	    seq = NULL;
12387 	} else
12388 	    outSeq = mergeAndClear(outSeq, seq, 0);
12389 	break;
12390 
12391 #ifdef DEBUG_STEP
12392 	if (seq != NULL)
12393 	    nbMatches += seq->nodeNr;
12394 #endif
12395 
12396 apply_predicates: /* --------------------------------------------------- */
12397         /*
12398 	* Apply predicates.
12399 	*/
12400         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12401 	    /*
12402 	    * E.g. when we have a "/foo[some expression][n]".
12403 	    */
12404 	    /*
12405 	    * QUESTION TODO: The old predicate evaluation took into
12406 	    *  account location-sets.
12407 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12408 	    *  Do we expect such a set here?
12409 	    *  All what I learned now from the evaluation semantics
12410 	    *  does not indicate that a location-set will be processed
12411 	    *  here, so this looks OK.
12412 	    */
12413 	    /*
12414 	    * Iterate over all predicates, starting with the outermost
12415 	    * predicate.
12416 	    * TODO: Problem: we cannot execute the inner predicates first
12417 	    *  since we cannot go back *up* the operator tree!
12418 	    *  Options we have:
12419 	    *  1) Use of recursive functions (like is it currently done
12420 	    *     via xmlXPathCompOpEval())
12421 	    *  2) Add a predicate evaluation information stack to the
12422 	    *     context struct
12423 	    *  3) Change the way the operators are linked; we need a
12424 	    *     "parent" field on xmlXPathStepOp
12425 	    *
12426 	    * For the moment, I'll try to solve this with a recursive
12427 	    * function: xmlXPathCompOpEvalPredicate().
12428 	    */
12429 	    size = seq->nodeNr;
12430 	    if (hasPredicateRange != 0)
12431 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12432 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12433 	    else
12434 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12435 		    predOp, seq, size, hasNsNodes);
12436 
12437 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12438 		total = 0;
12439 		goto error;
12440 	    }
12441 	    /*
12442 	    * Add the filtered set of nodes to the result node set.
12443 	    */
12444 	    if (newSize == 0) {
12445 		/*
12446 		* The predicates filtered all nodes out.
12447 		*/
12448 		xmlXPathNodeSetClear(seq, hasNsNodes);
12449 	    } else if (seq->nodeNr > 0) {
12450 		/*
12451 		* Add to result set.
12452 		*/
12453 		if (outSeq == NULL) {
12454 		    if (size != newSize) {
12455 			/*
12456 			* We need to merge and clear here, since
12457 			* the sequence will contained NULLed entries.
12458 			*/
12459 			outSeq = mergeAndClear(NULL, seq, 1);
12460 		    } else {
12461 			outSeq = seq;
12462 			seq = NULL;
12463 		    }
12464 		} else
12465 		    outSeq = mergeAndClear(outSeq, seq,
12466 			(size != newSize) ? 1: 0);
12467 		/*
12468 		* Break if only a true/false result was requested.
12469 		*/
12470 		if (toBool)
12471 		    break;
12472 	    }
12473         } else if (seq->nodeNr > 0) {
12474 	    /*
12475 	    * Add to result set.
12476 	    */
12477 	    if (outSeq == NULL) {
12478 		outSeq = seq;
12479 		seq = NULL;
12480 	    } else {
12481 		outSeq = mergeAndClear(outSeq, seq, 0);
12482 	    }
12483 	}
12484     }
12485 
12486 error:
12487     if ((obj->boolval) && (obj->user != NULL)) {
12488 	/*
12489 	* QUESTION TODO: What does this do and why?
12490 	* TODO: Do we have to do this also for the "error"
12491 	* cleanup further down?
12492 	*/
12493 	ctxt->value->boolval = 1;
12494 	ctxt->value->user = obj->user;
12495 	obj->user = NULL;
12496 	obj->boolval = 0;
12497     }
12498     xmlXPathReleaseObject(xpctxt, obj);
12499 
12500     /*
12501     * Ensure we return at least an emtpy set.
12502     */
12503     if (outSeq == NULL) {
12504 	if ((seq != NULL) && (seq->nodeNr == 0))
12505 	    outSeq = seq;
12506 	else
12507 	    outSeq = xmlXPathNodeSetCreate(NULL);
12508         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12509     }
12510     if ((seq != NULL) && (seq != outSeq)) {
12511 	 xmlXPathFreeNodeSet(seq);
12512     }
12513     /*
12514     * Hand over the result. Better to push the set also in
12515     * case of errors.
12516     */
12517     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12518     /*
12519     * Reset the context node.
12520     */
12521     xpctxt->node = oldContextNode;
12522 
12523 #ifdef DEBUG_STEP
12524     xmlGenericError(xmlGenericErrorContext,
12525 	"\nExamined %d nodes, found %d nodes at that step\n",
12526 	total, nbMatches);
12527 #endif
12528 
12529     return(total);
12530 }
12531 
12532 static int
12533 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12534 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12535 
12536 /**
12537  * xmlXPathCompOpEvalFirst:
12538  * @ctxt:  the XPath parser context with the compiled expression
12539  * @op:  an XPath compiled operation
12540  * @first:  the first elem found so far
12541  *
12542  * Evaluate the Precompiled XPath operation searching only the first
12543  * element in document order
12544  *
12545  * Returns the number of examined objects.
12546  */
12547 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12548 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12549                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12550 {
12551     int total = 0, cur;
12552     xmlXPathCompExprPtr comp;
12553     xmlXPathObjectPtr arg1, arg2;
12554 
12555     CHECK_ERROR0;
12556     comp = ctxt->comp;
12557     switch (op->op) {
12558         case XPATH_OP_END:
12559             return (0);
12560         case XPATH_OP_UNION:
12561             total =
12562                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12563                                         first);
12564 	    CHECK_ERROR0;
12565             if ((ctxt->value != NULL)
12566                 && (ctxt->value->type == XPATH_NODESET)
12567                 && (ctxt->value->nodesetval != NULL)
12568                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12569                 /*
12570                  * limit tree traversing to first node in the result
12571                  */
12572 		/*
12573 		* OPTIMIZE TODO: This implicitely sorts
12574 		*  the result, even if not needed. E.g. if the argument
12575 		*  of the count() function, no sorting is needed.
12576 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12577 		*  aready sorted?
12578 		*/
12579 		if (ctxt->value->nodesetval->nodeNr > 1)
12580 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12581                 *first = ctxt->value->nodesetval->nodeTab[0];
12582             }
12583             cur =
12584                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12585                                         first);
12586 	    CHECK_ERROR0;
12587             CHECK_TYPE0(XPATH_NODESET);
12588             arg2 = valuePop(ctxt);
12589 
12590             CHECK_TYPE0(XPATH_NODESET);
12591             arg1 = valuePop(ctxt);
12592 
12593             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12594                                                     arg2->nodesetval);
12595             valuePush(ctxt, arg1);
12596 	    xmlXPathReleaseObject(ctxt->context, arg2);
12597             /* optimizer */
12598 	    if (total > cur)
12599 		xmlXPathCompSwap(op);
12600             return (total + cur);
12601         case XPATH_OP_ROOT:
12602             xmlXPathRoot(ctxt);
12603             return (0);
12604         case XPATH_OP_NODE:
12605             if (op->ch1 != -1)
12606                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12607 	    CHECK_ERROR0;
12608             if (op->ch2 != -1)
12609                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12610 	    CHECK_ERROR0;
12611 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12612 		ctxt->context->node));
12613             return (total);
12614         case XPATH_OP_RESET:
12615             if (op->ch1 != -1)
12616                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12617 	    CHECK_ERROR0;
12618             if (op->ch2 != -1)
12619                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12620 	    CHECK_ERROR0;
12621             ctxt->context->node = NULL;
12622             return (total);
12623         case XPATH_OP_COLLECT:{
12624                 if (op->ch1 == -1)
12625                     return (total);
12626 
12627                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12628 		CHECK_ERROR0;
12629 
12630                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12631                 return (total);
12632             }
12633         case XPATH_OP_VALUE:
12634             valuePush(ctxt,
12635                       xmlXPathCacheObjectCopy(ctxt->context,
12636 			(xmlXPathObjectPtr) op->value4));
12637             return (0);
12638         case XPATH_OP_SORT:
12639             if (op->ch1 != -1)
12640                 total +=
12641                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12642                                             first);
12643 	    CHECK_ERROR0;
12644             if ((ctxt->value != NULL)
12645                 && (ctxt->value->type == XPATH_NODESET)
12646                 && (ctxt->value->nodesetval != NULL)
12647 		&& (ctxt->value->nodesetval->nodeNr > 1))
12648                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12649             return (total);
12650 #ifdef XP_OPTIMIZED_FILTER_FIRST
12651 	case XPATH_OP_FILTER:
12652                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12653             return (total);
12654 #endif
12655         default:
12656             return (xmlXPathCompOpEval(ctxt, op));
12657     }
12658 }
12659 
12660 /**
12661  * xmlXPathCompOpEvalLast:
12662  * @ctxt:  the XPath parser context with the compiled expression
12663  * @op:  an XPath compiled operation
12664  * @last:  the last elem found so far
12665  *
12666  * Evaluate the Precompiled XPath operation searching only the last
12667  * element in document order
12668  *
12669  * Returns the number of nodes traversed
12670  */
12671 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12672 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12673                        xmlNodePtr * last)
12674 {
12675     int total = 0, cur;
12676     xmlXPathCompExprPtr comp;
12677     xmlXPathObjectPtr arg1, arg2;
12678     xmlNodePtr bak;
12679     xmlDocPtr bakd;
12680     int pp;
12681     int cs;
12682 
12683     CHECK_ERROR0;
12684     comp = ctxt->comp;
12685     switch (op->op) {
12686         case XPATH_OP_END:
12687             return (0);
12688         case XPATH_OP_UNION:
12689 	    bakd = ctxt->context->doc;
12690 	    bak = ctxt->context->node;
12691 	    pp = ctxt->context->proximityPosition;
12692 	    cs = ctxt->context->contextSize;
12693             total =
12694                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12695 	    CHECK_ERROR0;
12696             if ((ctxt->value != NULL)
12697                 && (ctxt->value->type == XPATH_NODESET)
12698                 && (ctxt->value->nodesetval != NULL)
12699                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12700                 /*
12701                  * limit tree traversing to first node in the result
12702                  */
12703 		if (ctxt->value->nodesetval->nodeNr > 1)
12704 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12705                 *last =
12706                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12707                                                      nodesetval->nodeNr -
12708                                                      1];
12709             }
12710 	    ctxt->context->doc = bakd;
12711 	    ctxt->context->node = bak;
12712 	    ctxt->context->proximityPosition = pp;
12713 	    ctxt->context->contextSize = cs;
12714             cur =
12715                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12716 	    CHECK_ERROR0;
12717             if ((ctxt->value != NULL)
12718                 && (ctxt->value->type == XPATH_NODESET)
12719                 && (ctxt->value->nodesetval != NULL)
12720                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12721             }
12722             CHECK_TYPE0(XPATH_NODESET);
12723             arg2 = valuePop(ctxt);
12724 
12725             CHECK_TYPE0(XPATH_NODESET);
12726             arg1 = valuePop(ctxt);
12727 
12728             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12729                                                     arg2->nodesetval);
12730             valuePush(ctxt, arg1);
12731 	    xmlXPathReleaseObject(ctxt->context, arg2);
12732             /* optimizer */
12733 	    if (total > cur)
12734 		xmlXPathCompSwap(op);
12735             return (total + cur);
12736         case XPATH_OP_ROOT:
12737             xmlXPathRoot(ctxt);
12738             return (0);
12739         case XPATH_OP_NODE:
12740             if (op->ch1 != -1)
12741                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12742 	    CHECK_ERROR0;
12743             if (op->ch2 != -1)
12744                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12745 	    CHECK_ERROR0;
12746 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12747 		ctxt->context->node));
12748             return (total);
12749         case XPATH_OP_RESET:
12750             if (op->ch1 != -1)
12751                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12752 	    CHECK_ERROR0;
12753             if (op->ch2 != -1)
12754                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12755 	    CHECK_ERROR0;
12756             ctxt->context->node = NULL;
12757             return (total);
12758         case XPATH_OP_COLLECT:{
12759                 if (op->ch1 == -1)
12760                     return (0);
12761 
12762                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12763 		CHECK_ERROR0;
12764 
12765                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12766                 return (total);
12767             }
12768         case XPATH_OP_VALUE:
12769             valuePush(ctxt,
12770                       xmlXPathCacheObjectCopy(ctxt->context,
12771 			(xmlXPathObjectPtr) op->value4));
12772             return (0);
12773         case XPATH_OP_SORT:
12774             if (op->ch1 != -1)
12775                 total +=
12776                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12777                                            last);
12778 	    CHECK_ERROR0;
12779             if ((ctxt->value != NULL)
12780                 && (ctxt->value->type == XPATH_NODESET)
12781                 && (ctxt->value->nodesetval != NULL)
12782 		&& (ctxt->value->nodesetval->nodeNr > 1))
12783                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12784             return (total);
12785         default:
12786             return (xmlXPathCompOpEval(ctxt, op));
12787     }
12788 }
12789 
12790 #ifdef XP_OPTIMIZED_FILTER_FIRST
12791 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12792 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12793 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12794 {
12795     int total = 0;
12796     xmlXPathCompExprPtr comp;
12797     xmlXPathObjectPtr res;
12798     xmlXPathObjectPtr obj;
12799     xmlNodeSetPtr oldset;
12800     xmlNodePtr oldnode;
12801     xmlDocPtr oldDoc;
12802     int i;
12803 
12804     CHECK_ERROR0;
12805     comp = ctxt->comp;
12806     /*
12807     * Optimization for ()[last()] selection i.e. the last elem
12808     */
12809     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12810 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12811 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12812 	int f = comp->steps[op->ch2].ch1;
12813 
12814 	if ((f != -1) &&
12815 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12816 	    (comp->steps[f].value5 == NULL) &&
12817 	    (comp->steps[f].value == 0) &&
12818 	    (comp->steps[f].value4 != NULL) &&
12819 	    (xmlStrEqual
12820 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12821 	    xmlNodePtr last = NULL;
12822 
12823 	    total +=
12824 		xmlXPathCompOpEvalLast(ctxt,
12825 		    &comp->steps[op->ch1],
12826 		    &last);
12827 	    CHECK_ERROR0;
12828 	    /*
12829 	    * The nodeset should be in document order,
12830 	    * Keep only the last value
12831 	    */
12832 	    if ((ctxt->value != NULL) &&
12833 		(ctxt->value->type == XPATH_NODESET) &&
12834 		(ctxt->value->nodesetval != NULL) &&
12835 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12836 		(ctxt->value->nodesetval->nodeNr > 1)) {
12837 		ctxt->value->nodesetval->nodeTab[0] =
12838 		    ctxt->value->nodesetval->nodeTab[ctxt->
12839 		    value->
12840 		    nodesetval->
12841 		    nodeNr -
12842 		    1];
12843 		ctxt->value->nodesetval->nodeNr = 1;
12844 		*first = *(ctxt->value->nodesetval->nodeTab);
12845 	    }
12846 	    return (total);
12847 	}
12848     }
12849 
12850     if (op->ch1 != -1)
12851 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12852     CHECK_ERROR0;
12853     if (op->ch2 == -1)
12854 	return (total);
12855     if (ctxt->value == NULL)
12856 	return (total);
12857 
12858 #ifdef LIBXML_XPTR_ENABLED
12859     oldnode = ctxt->context->node;
12860     /*
12861     * Hum are we filtering the result of an XPointer expression
12862     */
12863     if (ctxt->value->type == XPATH_LOCATIONSET) {
12864 	xmlXPathObjectPtr tmp = NULL;
12865 	xmlLocationSetPtr newlocset = NULL;
12866 	xmlLocationSetPtr oldlocset;
12867 
12868 	/*
12869 	* Extract the old locset, and then evaluate the result of the
12870 	* expression for all the element in the locset. use it to grow
12871 	* up a new locset.
12872 	*/
12873 	CHECK_TYPE0(XPATH_LOCATIONSET);
12874 	obj = valuePop(ctxt);
12875 	oldlocset = obj->user;
12876 	ctxt->context->node = NULL;
12877 
12878 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12879 	    ctxt->context->contextSize = 0;
12880 	    ctxt->context->proximityPosition = 0;
12881 	    if (op->ch2 != -1)
12882 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12883 	    res = valuePop(ctxt);
12884 	    if (res != NULL) {
12885 		xmlXPathReleaseObject(ctxt->context, res);
12886 	    }
12887 	    valuePush(ctxt, obj);
12888 	    CHECK_ERROR0;
12889 	    return (total);
12890 	}
12891 	newlocset = xmlXPtrLocationSetCreate(NULL);
12892 
12893 	for (i = 0; i < oldlocset->locNr; i++) {
12894 	    /*
12895 	    * Run the evaluation with a node list made of a
12896 	    * single item in the nodelocset.
12897 	    */
12898 	    ctxt->context->node = oldlocset->locTab[i]->user;
12899 	    ctxt->context->contextSize = oldlocset->locNr;
12900 	    ctxt->context->proximityPosition = i + 1;
12901 	    if (tmp == NULL) {
12902 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12903 		    ctxt->context->node);
12904 	    } else {
12905 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12906 		    ctxt->context->node);
12907 	    }
12908 	    valuePush(ctxt, tmp);
12909 	    if (op->ch2 != -1)
12910 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12911 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12912 		xmlXPathFreeObject(obj);
12913 		return(0);
12914 	    }
12915 	    /*
12916 	    * The result of the evaluation need to be tested to
12917 	    * decided whether the filter succeeded or not
12918 	    */
12919 	    res = valuePop(ctxt);
12920 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12921 		xmlXPtrLocationSetAdd(newlocset,
12922 		    xmlXPathCacheObjectCopy(ctxt->context,
12923 			oldlocset->locTab[i]));
12924 	    }
12925 	    /*
12926 	    * Cleanup
12927 	    */
12928 	    if (res != NULL) {
12929 		xmlXPathReleaseObject(ctxt->context, res);
12930 	    }
12931 	    if (ctxt->value == tmp) {
12932 		valuePop(ctxt);
12933 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12934 		/*
12935 		* REVISIT TODO: Don't create a temporary nodeset
12936 		* for everly iteration.
12937 		*/
12938 		/* OLD: xmlXPathFreeObject(res); */
12939 	    } else
12940 		tmp = NULL;
12941 	    ctxt->context->node = NULL;
12942 	    /*
12943 	    * Only put the first node in the result, then leave.
12944 	    */
12945 	    if (newlocset->locNr > 0) {
12946 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12947 		break;
12948 	    }
12949 	}
12950 	if (tmp != NULL) {
12951 	    xmlXPathReleaseObject(ctxt->context, tmp);
12952 	}
12953 	/*
12954 	* The result is used as the new evaluation locset.
12955 	*/
12956 	xmlXPathReleaseObject(ctxt->context, obj);
12957 	ctxt->context->node = NULL;
12958 	ctxt->context->contextSize = -1;
12959 	ctxt->context->proximityPosition = -1;
12960 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12961 	ctxt->context->node = oldnode;
12962 	return (total);
12963     }
12964 #endif /* LIBXML_XPTR_ENABLED */
12965 
12966     /*
12967     * Extract the old set, and then evaluate the result of the
12968     * expression for all the element in the set. use it to grow
12969     * up a new set.
12970     */
12971     CHECK_TYPE0(XPATH_NODESET);
12972     obj = valuePop(ctxt);
12973     oldset = obj->nodesetval;
12974 
12975     oldnode = ctxt->context->node;
12976     oldDoc = ctxt->context->doc;
12977     ctxt->context->node = NULL;
12978 
12979     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12980 	ctxt->context->contextSize = 0;
12981 	ctxt->context->proximityPosition = 0;
12982 	/* QUESTION TODO: Why was this code commented out?
12983 	    if (op->ch2 != -1)
12984 		total +=
12985 		    xmlXPathCompOpEval(ctxt,
12986 			&comp->steps[op->ch2]);
12987 	    CHECK_ERROR0;
12988 	    res = valuePop(ctxt);
12989 	    if (res != NULL)
12990 		xmlXPathFreeObject(res);
12991 	*/
12992 	valuePush(ctxt, obj);
12993 	ctxt->context->node = oldnode;
12994 	CHECK_ERROR0;
12995     } else {
12996 	xmlNodeSetPtr newset;
12997 	xmlXPathObjectPtr tmp = NULL;
12998 	/*
12999 	* Initialize the new set.
13000 	* Also set the xpath document in case things like
13001 	* key() evaluation are attempted on the predicate
13002 	*/
13003 	newset = xmlXPathNodeSetCreate(NULL);
13004         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13005 
13006 	for (i = 0; i < oldset->nodeNr; i++) {
13007 	    /*
13008 	    * Run the evaluation with a node list made of
13009 	    * a single item in the nodeset.
13010 	    */
13011 	    ctxt->context->node = oldset->nodeTab[i];
13012 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13013 		(oldset->nodeTab[i]->doc != NULL))
13014 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13015 	    if (tmp == NULL) {
13016 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13017 		    ctxt->context->node);
13018 	    } else {
13019 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13020 		    ctxt->context->node);
13021 	    }
13022 	    valuePush(ctxt, tmp);
13023 	    ctxt->context->contextSize = oldset->nodeNr;
13024 	    ctxt->context->proximityPosition = i + 1;
13025 	    if (op->ch2 != -1)
13026 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13027 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13028 		xmlXPathFreeNodeSet(newset);
13029 		xmlXPathFreeObject(obj);
13030 		return(0);
13031 	    }
13032 	    /*
13033 	    * The result of the evaluation needs to be tested to
13034 	    * decide whether the filter succeeded or not
13035 	    */
13036 	    res = valuePop(ctxt);
13037 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13038 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13039 	    }
13040 	    /*
13041 	    * Cleanup
13042 	    */
13043 	    if (res != NULL) {
13044 		xmlXPathReleaseObject(ctxt->context, res);
13045 	    }
13046 	    if (ctxt->value == tmp) {
13047 		valuePop(ctxt);
13048 		/*
13049 		* Don't free the temporary nodeset
13050 		* in order to avoid massive recreation inside this
13051 		* loop.
13052 		*/
13053 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13054 	    } else
13055 		tmp = NULL;
13056 	    ctxt->context->node = NULL;
13057 	    /*
13058 	    * Only put the first node in the result, then leave.
13059 	    */
13060 	    if (newset->nodeNr > 0) {
13061 		*first = *(newset->nodeTab);
13062 		break;
13063 	    }
13064 	}
13065 	if (tmp != NULL) {
13066 	    xmlXPathReleaseObject(ctxt->context, tmp);
13067 	}
13068 	/*
13069 	* The result is used as the new evaluation set.
13070 	*/
13071 	xmlXPathReleaseObject(ctxt->context, obj);
13072 	ctxt->context->node = NULL;
13073 	ctxt->context->contextSize = -1;
13074 	ctxt->context->proximityPosition = -1;
13075 	/* may want to move this past the '}' later */
13076 	ctxt->context->doc = oldDoc;
13077 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13078     }
13079     ctxt->context->node = oldnode;
13080     return(total);
13081 }
13082 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13083 
13084 /**
13085  * xmlXPathCompOpEval:
13086  * @ctxt:  the XPath parser context with the compiled expression
13087  * @op:  an XPath compiled operation
13088  *
13089  * Evaluate the Precompiled XPath operation
13090  * Returns the number of nodes traversed
13091  */
13092 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13093 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13094 {
13095     int total = 0;
13096     int equal, ret;
13097     xmlXPathCompExprPtr comp;
13098     xmlXPathObjectPtr arg1, arg2;
13099     xmlNodePtr bak;
13100     xmlDocPtr bakd;
13101     int pp;
13102     int cs;
13103 
13104     CHECK_ERROR0;
13105     comp = ctxt->comp;
13106     switch (op->op) {
13107         case XPATH_OP_END:
13108             return (0);
13109         case XPATH_OP_AND:
13110 	    bakd = ctxt->context->doc;
13111 	    bak = ctxt->context->node;
13112 	    pp = ctxt->context->proximityPosition;
13113 	    cs = ctxt->context->contextSize;
13114             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13115 	    CHECK_ERROR0;
13116             xmlXPathBooleanFunction(ctxt, 1);
13117             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13118                 return (total);
13119             arg2 = valuePop(ctxt);
13120 	    ctxt->context->doc = bakd;
13121 	    ctxt->context->node = bak;
13122 	    ctxt->context->proximityPosition = pp;
13123 	    ctxt->context->contextSize = cs;
13124             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13125 	    if (ctxt->error) {
13126 		xmlXPathFreeObject(arg2);
13127 		return(0);
13128 	    }
13129             xmlXPathBooleanFunction(ctxt, 1);
13130             arg1 = valuePop(ctxt);
13131             arg1->boolval &= arg2->boolval;
13132             valuePush(ctxt, arg1);
13133 	    xmlXPathReleaseObject(ctxt->context, arg2);
13134             return (total);
13135         case XPATH_OP_OR:
13136 	    bakd = ctxt->context->doc;
13137 	    bak = ctxt->context->node;
13138 	    pp = ctxt->context->proximityPosition;
13139 	    cs = ctxt->context->contextSize;
13140             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13141 	    CHECK_ERROR0;
13142             xmlXPathBooleanFunction(ctxt, 1);
13143             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13144                 return (total);
13145             arg2 = valuePop(ctxt);
13146 	    ctxt->context->doc = bakd;
13147 	    ctxt->context->node = bak;
13148 	    ctxt->context->proximityPosition = pp;
13149 	    ctxt->context->contextSize = cs;
13150             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13151 	    if (ctxt->error) {
13152 		xmlXPathFreeObject(arg2);
13153 		return(0);
13154 	    }
13155             xmlXPathBooleanFunction(ctxt, 1);
13156             arg1 = valuePop(ctxt);
13157             arg1->boolval |= arg2->boolval;
13158             valuePush(ctxt, arg1);
13159 	    xmlXPathReleaseObject(ctxt->context, arg2);
13160             return (total);
13161         case XPATH_OP_EQUAL:
13162 	    bakd = ctxt->context->doc;
13163 	    bak = ctxt->context->node;
13164 	    pp = ctxt->context->proximityPosition;
13165 	    cs = ctxt->context->contextSize;
13166             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13167 	    CHECK_ERROR0;
13168 	    ctxt->context->doc = bakd;
13169 	    ctxt->context->node = bak;
13170 	    ctxt->context->proximityPosition = pp;
13171 	    ctxt->context->contextSize = cs;
13172             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13173 	    CHECK_ERROR0;
13174 	    if (op->value)
13175         	equal = xmlXPathEqualValues(ctxt);
13176 	    else
13177 		equal = xmlXPathNotEqualValues(ctxt);
13178 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13179             return (total);
13180         case XPATH_OP_CMP:
13181 	    bakd = ctxt->context->doc;
13182 	    bak = ctxt->context->node;
13183 	    pp = ctxt->context->proximityPosition;
13184 	    cs = ctxt->context->contextSize;
13185             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13186 	    CHECK_ERROR0;
13187 	    ctxt->context->doc = bakd;
13188 	    ctxt->context->node = bak;
13189 	    ctxt->context->proximityPosition = pp;
13190 	    ctxt->context->contextSize = cs;
13191             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13192 	    CHECK_ERROR0;
13193             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13194 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13195             return (total);
13196         case XPATH_OP_PLUS:
13197 	    bakd = ctxt->context->doc;
13198 	    bak = ctxt->context->node;
13199 	    pp = ctxt->context->proximityPosition;
13200 	    cs = ctxt->context->contextSize;
13201             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13202 	    CHECK_ERROR0;
13203             if (op->ch2 != -1) {
13204 		ctxt->context->doc = bakd;
13205 		ctxt->context->node = bak;
13206 		ctxt->context->proximityPosition = pp;
13207 		ctxt->context->contextSize = cs;
13208                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209 	    }
13210 	    CHECK_ERROR0;
13211             if (op->value == 0)
13212                 xmlXPathSubValues(ctxt);
13213             else if (op->value == 1)
13214                 xmlXPathAddValues(ctxt);
13215             else if (op->value == 2)
13216                 xmlXPathValueFlipSign(ctxt);
13217             else if (op->value == 3) {
13218                 CAST_TO_NUMBER;
13219                 CHECK_TYPE0(XPATH_NUMBER);
13220             }
13221             return (total);
13222         case XPATH_OP_MULT:
13223 	    bakd = ctxt->context->doc;
13224 	    bak = ctxt->context->node;
13225 	    pp = ctxt->context->proximityPosition;
13226 	    cs = ctxt->context->contextSize;
13227             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13228 	    CHECK_ERROR0;
13229 	    ctxt->context->doc = bakd;
13230 	    ctxt->context->node = bak;
13231 	    ctxt->context->proximityPosition = pp;
13232 	    ctxt->context->contextSize = cs;
13233             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13234 	    CHECK_ERROR0;
13235             if (op->value == 0)
13236                 xmlXPathMultValues(ctxt);
13237             else if (op->value == 1)
13238                 xmlXPathDivValues(ctxt);
13239             else if (op->value == 2)
13240                 xmlXPathModValues(ctxt);
13241             return (total);
13242         case XPATH_OP_UNION:
13243 	    bakd = ctxt->context->doc;
13244 	    bak = ctxt->context->node;
13245 	    pp = ctxt->context->proximityPosition;
13246 	    cs = ctxt->context->contextSize;
13247             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13248 	    CHECK_ERROR0;
13249 	    ctxt->context->doc = bakd;
13250 	    ctxt->context->node = bak;
13251 	    ctxt->context->proximityPosition = pp;
13252 	    ctxt->context->contextSize = cs;
13253             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13254 	    CHECK_ERROR0;
13255             CHECK_TYPE0(XPATH_NODESET);
13256             arg2 = valuePop(ctxt);
13257 
13258             CHECK_TYPE0(XPATH_NODESET);
13259             arg1 = valuePop(ctxt);
13260 
13261 	    if ((arg1->nodesetval == NULL) ||
13262 		((arg2->nodesetval != NULL) &&
13263 		 (arg2->nodesetval->nodeNr != 0)))
13264 	    {
13265 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13266 							arg2->nodesetval);
13267 	    }
13268 
13269             valuePush(ctxt, arg1);
13270 	    xmlXPathReleaseObject(ctxt->context, arg2);
13271             return (total);
13272         case XPATH_OP_ROOT:
13273             xmlXPathRoot(ctxt);
13274             return (total);
13275         case XPATH_OP_NODE:
13276             if (op->ch1 != -1)
13277                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13278 	    CHECK_ERROR0;
13279             if (op->ch2 != -1)
13280                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13281 	    CHECK_ERROR0;
13282 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13283 		ctxt->context->node));
13284             return (total);
13285         case XPATH_OP_RESET:
13286             if (op->ch1 != -1)
13287                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288 	    CHECK_ERROR0;
13289             if (op->ch2 != -1)
13290                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13291 	    CHECK_ERROR0;
13292             ctxt->context->node = NULL;
13293             return (total);
13294         case XPATH_OP_COLLECT:{
13295                 if (op->ch1 == -1)
13296                     return (total);
13297 
13298                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13299 		CHECK_ERROR0;
13300 
13301                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13302                 return (total);
13303             }
13304         case XPATH_OP_VALUE:
13305             valuePush(ctxt,
13306                       xmlXPathCacheObjectCopy(ctxt->context,
13307 			(xmlXPathObjectPtr) op->value4));
13308             return (total);
13309         case XPATH_OP_VARIABLE:{
13310 		xmlXPathObjectPtr val;
13311 
13312                 if (op->ch1 != -1)
13313                     total +=
13314                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13315                 if (op->value5 == NULL) {
13316 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13317 		    if (val == NULL) {
13318 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13319 			return(0);
13320 		    }
13321                     valuePush(ctxt, val);
13322 		} else {
13323                     const xmlChar *URI;
13324 
13325                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13326                     if (URI == NULL) {
13327                         xmlGenericError(xmlGenericErrorContext,
13328                                         "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13329                                         op->value4, op->value5);
13330                         return (total);
13331                     }
13332 		    val = xmlXPathVariableLookupNS(ctxt->context,
13333                                                        op->value4, URI);
13334 		    if (val == NULL) {
13335 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13336 			return(0);
13337 		    }
13338                     valuePush(ctxt, val);
13339                 }
13340                 return (total);
13341             }
13342         case XPATH_OP_FUNCTION:{
13343                 xmlXPathFunction func;
13344                 const xmlChar *oldFunc, *oldFuncURI;
13345 		int i;
13346 
13347                 if (op->ch1 != -1)
13348                     total +=
13349                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13350 		if (ctxt->valueNr < op->value) {
13351 		    xmlGenericError(xmlGenericErrorContext,
13352 			    "xmlXPathCompOpEval: parameter error\n");
13353 		    ctxt->error = XPATH_INVALID_OPERAND;
13354 		    return (total);
13355 		}
13356 		for (i = 0; i < op->value; i++)
13357 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13358 			xmlGenericError(xmlGenericErrorContext,
13359 				"xmlXPathCompOpEval: parameter error\n");
13360 			ctxt->error = XPATH_INVALID_OPERAND;
13361 			return (total);
13362 		    }
13363                 if (op->cache != NULL)
13364                     XML_CAST_FPTR(func) = op->cache;
13365                 else {
13366                     const xmlChar *URI = NULL;
13367 
13368                     if (op->value5 == NULL)
13369                         func =
13370                             xmlXPathFunctionLookup(ctxt->context,
13371                                                    op->value4);
13372                     else {
13373                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13374                         if (URI == NULL) {
13375                             xmlGenericError(xmlGenericErrorContext,
13376                                             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13377                                             op->value4, op->value5);
13378                             return (total);
13379                         }
13380                         func = xmlXPathFunctionLookupNS(ctxt->context,
13381                                                         op->value4, URI);
13382                     }
13383                     if (func == NULL) {
13384                         xmlGenericError(xmlGenericErrorContext,
13385                                         "xmlXPathCompOpEval: function %s not found\n",
13386                                         op->value4);
13387                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13388                     }
13389                     op->cache = XML_CAST_FPTR(func);
13390                     op->cacheURI = (void *) URI;
13391                 }
13392                 oldFunc = ctxt->context->function;
13393                 oldFuncURI = ctxt->context->functionURI;
13394                 ctxt->context->function = op->value4;
13395                 ctxt->context->functionURI = op->cacheURI;
13396                 func(ctxt, op->value);
13397                 ctxt->context->function = oldFunc;
13398                 ctxt->context->functionURI = oldFuncURI;
13399                 return (total);
13400             }
13401         case XPATH_OP_ARG:
13402 	    bakd = ctxt->context->doc;
13403 	    bak = ctxt->context->node;
13404 	    pp = ctxt->context->proximityPosition;
13405 	    cs = ctxt->context->contextSize;
13406             if (op->ch1 != -1)
13407                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13408 	    ctxt->context->contextSize = cs;
13409 	    ctxt->context->proximityPosition = pp;
13410 	    ctxt->context->node = bak;
13411 	    ctxt->context->doc = bakd;
13412 	    CHECK_ERROR0;
13413             if (op->ch2 != -1) {
13414                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13415 	        ctxt->context->doc = bakd;
13416 	        ctxt->context->node = bak;
13417 	        CHECK_ERROR0;
13418 	    }
13419             return (total);
13420         case XPATH_OP_PREDICATE:
13421         case XPATH_OP_FILTER:{
13422                 xmlXPathObjectPtr res;
13423                 xmlXPathObjectPtr obj, tmp;
13424                 xmlNodeSetPtr newset = NULL;
13425                 xmlNodeSetPtr oldset;
13426                 xmlNodePtr oldnode;
13427 		xmlDocPtr oldDoc;
13428                 int i;
13429 
13430                 /*
13431                  * Optimization for ()[1] selection i.e. the first elem
13432                  */
13433                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13434 #ifdef XP_OPTIMIZED_FILTER_FIRST
13435 		    /*
13436 		    * FILTER TODO: Can we assume that the inner processing
13437 		    *  will result in an ordered list if we have an
13438 		    *  XPATH_OP_FILTER?
13439 		    *  What about an additional field or flag on
13440 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13441 		    *  to assume anything, so it would be more robust and
13442 		    *  easier to optimize.
13443 		    */
13444                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13445 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13446 #else
13447 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13448 #endif
13449                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13450                     xmlXPathObjectPtr val;
13451 
13452                     val = comp->steps[op->ch2].value4;
13453                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13454                         (val->floatval == 1.0)) {
13455                         xmlNodePtr first = NULL;
13456 
13457                         total +=
13458                             xmlXPathCompOpEvalFirst(ctxt,
13459                                                     &comp->steps[op->ch1],
13460                                                     &first);
13461 			CHECK_ERROR0;
13462                         /*
13463                          * The nodeset should be in document order,
13464                          * Keep only the first value
13465                          */
13466                         if ((ctxt->value != NULL) &&
13467                             (ctxt->value->type == XPATH_NODESET) &&
13468                             (ctxt->value->nodesetval != NULL) &&
13469                             (ctxt->value->nodesetval->nodeNr > 1))
13470                             ctxt->value->nodesetval->nodeNr = 1;
13471                         return (total);
13472                     }
13473                 }
13474                 /*
13475                  * Optimization for ()[last()] selection i.e. the last elem
13476                  */
13477                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13478                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13479                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13480                     int f = comp->steps[op->ch2].ch1;
13481 
13482                     if ((f != -1) &&
13483                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13484                         (comp->steps[f].value5 == NULL) &&
13485                         (comp->steps[f].value == 0) &&
13486                         (comp->steps[f].value4 != NULL) &&
13487                         (xmlStrEqual
13488                          (comp->steps[f].value4, BAD_CAST "last"))) {
13489                         xmlNodePtr last = NULL;
13490 
13491                         total +=
13492                             xmlXPathCompOpEvalLast(ctxt,
13493                                                    &comp->steps[op->ch1],
13494                                                    &last);
13495 			CHECK_ERROR0;
13496                         /*
13497                          * The nodeset should be in document order,
13498                          * Keep only the last value
13499                          */
13500                         if ((ctxt->value != NULL) &&
13501                             (ctxt->value->type == XPATH_NODESET) &&
13502                             (ctxt->value->nodesetval != NULL) &&
13503                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13504                             (ctxt->value->nodesetval->nodeNr > 1)) {
13505                             ctxt->value->nodesetval->nodeTab[0] =
13506                                 ctxt->value->nodesetval->nodeTab[ctxt->
13507                                                                  value->
13508                                                                  nodesetval->
13509                                                                  nodeNr -
13510                                                                  1];
13511                             ctxt->value->nodesetval->nodeNr = 1;
13512                         }
13513                         return (total);
13514                     }
13515                 }
13516 		/*
13517 		* Process inner predicates first.
13518 		* Example "index[parent::book][1]":
13519 		* ...
13520 		*   PREDICATE   <-- we are here "[1]"
13521 		*     PREDICATE <-- process "[parent::book]" first
13522 		*       SORT
13523 		*         COLLECT  'parent' 'name' 'node' book
13524 		*           NODE
13525 		*     ELEM Object is a number : 1
13526 		*/
13527                 if (op->ch1 != -1)
13528                     total +=
13529                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13530 		CHECK_ERROR0;
13531                 if (op->ch2 == -1)
13532                     return (total);
13533                 if (ctxt->value == NULL)
13534                     return (total);
13535 
13536                 oldnode = ctxt->context->node;
13537 
13538 #ifdef LIBXML_XPTR_ENABLED
13539                 /*
13540                  * Hum are we filtering the result of an XPointer expression
13541                  */
13542                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13543                     xmlLocationSetPtr newlocset = NULL;
13544                     xmlLocationSetPtr oldlocset;
13545 
13546                     /*
13547                      * Extract the old locset, and then evaluate the result of the
13548                      * expression for all the element in the locset. use it to grow
13549                      * up a new locset.
13550                      */
13551                     CHECK_TYPE0(XPATH_LOCATIONSET);
13552                     obj = valuePop(ctxt);
13553                     oldlocset = obj->user;
13554                     ctxt->context->node = NULL;
13555 
13556                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13557                         ctxt->context->contextSize = 0;
13558                         ctxt->context->proximityPosition = 0;
13559                         if (op->ch2 != -1)
13560                             total +=
13561                                 xmlXPathCompOpEval(ctxt,
13562                                                    &comp->steps[op->ch2]);
13563                         res = valuePop(ctxt);
13564                         if (res != NULL) {
13565 			    xmlXPathReleaseObject(ctxt->context, res);
13566 			}
13567                         valuePush(ctxt, obj);
13568                         CHECK_ERROR0;
13569                         return (total);
13570                     }
13571                     newlocset = xmlXPtrLocationSetCreate(NULL);
13572 
13573                     for (i = 0; i < oldlocset->locNr; i++) {
13574                         /*
13575                          * Run the evaluation with a node list made of a
13576                          * single item in the nodelocset.
13577                          */
13578                         ctxt->context->node = oldlocset->locTab[i]->user;
13579                         ctxt->context->contextSize = oldlocset->locNr;
13580                         ctxt->context->proximityPosition = i + 1;
13581 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13582 			    ctxt->context->node);
13583                         valuePush(ctxt, tmp);
13584 
13585                         if (op->ch2 != -1)
13586                             total +=
13587                                 xmlXPathCompOpEval(ctxt,
13588                                                    &comp->steps[op->ch2]);
13589 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13590 			    xmlXPathFreeObject(obj);
13591 			    return(0);
13592 			}
13593 
13594                         /*
13595                          * The result of the evaluation need to be tested to
13596                          * decided whether the filter succeeded or not
13597                          */
13598                         res = valuePop(ctxt);
13599                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13600                             xmlXPtrLocationSetAdd(newlocset,
13601                                                   xmlXPathObjectCopy
13602                                                   (oldlocset->locTab[i]));
13603                         }
13604 
13605                         /*
13606                          * Cleanup
13607                          */
13608                         if (res != NULL) {
13609 			    xmlXPathReleaseObject(ctxt->context, res);
13610 			}
13611                         if (ctxt->value == tmp) {
13612                             res = valuePop(ctxt);
13613 			    xmlXPathReleaseObject(ctxt->context, res);
13614                         }
13615 
13616                         ctxt->context->node = NULL;
13617                     }
13618 
13619                     /*
13620                      * The result is used as the new evaluation locset.
13621                      */
13622 		    xmlXPathReleaseObject(ctxt->context, obj);
13623                     ctxt->context->node = NULL;
13624                     ctxt->context->contextSize = -1;
13625                     ctxt->context->proximityPosition = -1;
13626                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13627                     ctxt->context->node = oldnode;
13628                     return (total);
13629                 }
13630 #endif /* LIBXML_XPTR_ENABLED */
13631 
13632                 /*
13633                  * Extract the old set, and then evaluate the result of the
13634                  * expression for all the element in the set. use it to grow
13635                  * up a new set.
13636                  */
13637                 CHECK_TYPE0(XPATH_NODESET);
13638                 obj = valuePop(ctxt);
13639                 oldset = obj->nodesetval;
13640 
13641                 oldnode = ctxt->context->node;
13642 		oldDoc = ctxt->context->doc;
13643                 ctxt->context->node = NULL;
13644 
13645                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13646                     ctxt->context->contextSize = 0;
13647                     ctxt->context->proximityPosition = 0;
13648 /*
13649                     if (op->ch2 != -1)
13650                         total +=
13651                             xmlXPathCompOpEval(ctxt,
13652                                                &comp->steps[op->ch2]);
13653 		    CHECK_ERROR0;
13654                     res = valuePop(ctxt);
13655                     if (res != NULL)
13656                         xmlXPathFreeObject(res);
13657 */
13658                     valuePush(ctxt, obj);
13659                     ctxt->context->node = oldnode;
13660                     CHECK_ERROR0;
13661                 } else {
13662 		    tmp = NULL;
13663                     /*
13664                      * Initialize the new set.
13665 		     * Also set the xpath document in case things like
13666 		     * key() evaluation are attempted on the predicate
13667                      */
13668                     newset = xmlXPathNodeSetCreate(NULL);
13669 		    /*
13670 		    * SPEC XPath 1.0:
13671 		    *  "For each node in the node-set to be filtered, the
13672 		    *  PredicateExpr is evaluated with that node as the
13673 		    *  context node, with the number of nodes in the
13674 		    *  node-set as the context size, and with the proximity
13675 		    *  position of the node in the node-set with respect to
13676 		    *  the axis as the context position;"
13677 		    * @oldset is the node-set" to be filtered.
13678 		    *
13679 		    * SPEC XPath 1.0:
13680 		    *  "only predicates change the context position and
13681 		    *  context size (see [2.4 Predicates])."
13682 		    * Example:
13683 		    *   node-set  context pos
13684 		    *    nA         1
13685 		    *    nB         2
13686 		    *    nC         3
13687 		    *   After applying predicate [position() > 1] :
13688 		    *   node-set  context pos
13689 		    *    nB         1
13690 		    *    nC         2
13691 		    *
13692 		    * removed the first node in the node-set, then
13693 		    * the context position of the
13694 		    */
13695                     for (i = 0; i < oldset->nodeNr; i++) {
13696                         /*
13697                          * Run the evaluation with a node list made of
13698                          * a single item in the nodeset.
13699                          */
13700                         ctxt->context->node = oldset->nodeTab[i];
13701 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13702 			    (oldset->nodeTab[i]->doc != NULL))
13703 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13704 			if (tmp == NULL) {
13705 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13706 				ctxt->context->node);
13707 			} else {
13708 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13709 				ctxt->context->node);
13710 			}
13711                         valuePush(ctxt, tmp);
13712                         ctxt->context->contextSize = oldset->nodeNr;
13713                         ctxt->context->proximityPosition = i + 1;
13714 			/*
13715 			* Evaluate the predicate against the context node.
13716 			* Can/should we optimize position() predicates
13717 			* here (e.g. "[1]")?
13718 			*/
13719                         if (op->ch2 != -1)
13720                             total +=
13721                                 xmlXPathCompOpEval(ctxt,
13722                                                    &comp->steps[op->ch2]);
13723 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13724 			    xmlXPathFreeNodeSet(newset);
13725 			    xmlXPathFreeObject(obj);
13726 			    return(0);
13727 			}
13728 
13729                         /*
13730                          * The result of the evaluation needs to be tested to
13731                          * decide whether the filter succeeded or not
13732                          */
13733 			/*
13734 			* OPTIMIZE TODO: Can we use
13735 			* xmlXPathNodeSetAdd*Unique()* instead?
13736 			*/
13737                         res = valuePop(ctxt);
13738                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13739                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13740                         }
13741 
13742                         /*
13743                          * Cleanup
13744                          */
13745                         if (res != NULL) {
13746 			    xmlXPathReleaseObject(ctxt->context, res);
13747 			}
13748                         if (ctxt->value == tmp) {
13749                             valuePop(ctxt);
13750 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13751 			    /*
13752 			    * Don't free the temporary nodeset
13753 			    * in order to avoid massive recreation inside this
13754 			    * loop.
13755 			    */
13756                         } else
13757 			    tmp = NULL;
13758                         ctxt->context->node = NULL;
13759                     }
13760 		    if (tmp != NULL)
13761 			xmlXPathReleaseObject(ctxt->context, tmp);
13762                     /*
13763                      * The result is used as the new evaluation set.
13764                      */
13765 		    xmlXPathReleaseObject(ctxt->context, obj);
13766                     ctxt->context->node = NULL;
13767                     ctxt->context->contextSize = -1;
13768                     ctxt->context->proximityPosition = -1;
13769 		    /* may want to move this past the '}' later */
13770 		    ctxt->context->doc = oldDoc;
13771 		    valuePush(ctxt,
13772 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13773                 }
13774                 ctxt->context->node = oldnode;
13775                 return (total);
13776             }
13777         case XPATH_OP_SORT:
13778             if (op->ch1 != -1)
13779                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13780 	    CHECK_ERROR0;
13781             if ((ctxt->value != NULL) &&
13782                 (ctxt->value->type == XPATH_NODESET) &&
13783                 (ctxt->value->nodesetval != NULL) &&
13784 		(ctxt->value->nodesetval->nodeNr > 1))
13785 	    {
13786                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13787 	    }
13788             return (total);
13789 #ifdef LIBXML_XPTR_ENABLED
13790         case XPATH_OP_RANGETO:{
13791                 xmlXPathObjectPtr range;
13792                 xmlXPathObjectPtr res, obj;
13793                 xmlXPathObjectPtr tmp;
13794                 xmlLocationSetPtr newlocset = NULL;
13795 		    xmlLocationSetPtr oldlocset;
13796                 xmlNodeSetPtr oldset;
13797                 int i, j;
13798 
13799                 if (op->ch1 != -1)
13800                     total +=
13801                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13802                 if (op->ch2 == -1)
13803                     return (total);
13804 
13805                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13806                     /*
13807                      * Extract the old locset, and then evaluate the result of the
13808                      * expression for all the element in the locset. use it to grow
13809                      * up a new locset.
13810                      */
13811                     CHECK_TYPE0(XPATH_LOCATIONSET);
13812                     obj = valuePop(ctxt);
13813                     oldlocset = obj->user;
13814 
13815                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13816 		        ctxt->context->node = NULL;
13817                         ctxt->context->contextSize = 0;
13818                         ctxt->context->proximityPosition = 0;
13819                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13820                         res = valuePop(ctxt);
13821                         if (res != NULL) {
13822 			    xmlXPathReleaseObject(ctxt->context, res);
13823 			}
13824                         valuePush(ctxt, obj);
13825                         CHECK_ERROR0;
13826                         return (total);
13827                     }
13828                     newlocset = xmlXPtrLocationSetCreate(NULL);
13829 
13830                     for (i = 0; i < oldlocset->locNr; i++) {
13831                         /*
13832                          * Run the evaluation with a node list made of a
13833                          * single item in the nodelocset.
13834                          */
13835                         ctxt->context->node = oldlocset->locTab[i]->user;
13836                         ctxt->context->contextSize = oldlocset->locNr;
13837                         ctxt->context->proximityPosition = i + 1;
13838 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13839 			    ctxt->context->node);
13840                         valuePush(ctxt, tmp);
13841 
13842                         if (op->ch2 != -1)
13843                             total +=
13844                                 xmlXPathCompOpEval(ctxt,
13845                                                    &comp->steps[op->ch2]);
13846 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13847 			    xmlXPathFreeObject(obj);
13848 			    return(0);
13849 			}
13850 
13851                         res = valuePop(ctxt);
13852 			if (res->type == XPATH_LOCATIONSET) {
13853 			    xmlLocationSetPtr rloc =
13854 			        (xmlLocationSetPtr)res->user;
13855 			    for (j=0; j<rloc->locNr; j++) {
13856 			        range = xmlXPtrNewRange(
13857 				  oldlocset->locTab[i]->user,
13858 				  oldlocset->locTab[i]->index,
13859 				  rloc->locTab[j]->user2,
13860 				  rloc->locTab[j]->index2);
13861 				if (range != NULL) {
13862 				    xmlXPtrLocationSetAdd(newlocset, range);
13863 				}
13864 			    }
13865 			} else {
13866 			    range = xmlXPtrNewRangeNodeObject(
13867 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13868                             if (range != NULL) {
13869                                 xmlXPtrLocationSetAdd(newlocset,range);
13870 			    }
13871                         }
13872 
13873                         /*
13874                          * Cleanup
13875                          */
13876                         if (res != NULL) {
13877 			    xmlXPathReleaseObject(ctxt->context, res);
13878 			}
13879                         if (ctxt->value == tmp) {
13880                             res = valuePop(ctxt);
13881 			    xmlXPathReleaseObject(ctxt->context, res);
13882                         }
13883 
13884                         ctxt->context->node = NULL;
13885                     }
13886 		} else {	/* Not a location set */
13887                     CHECK_TYPE0(XPATH_NODESET);
13888                     obj = valuePop(ctxt);
13889                     oldset = obj->nodesetval;
13890                     ctxt->context->node = NULL;
13891 
13892                     newlocset = xmlXPtrLocationSetCreate(NULL);
13893 
13894                     if (oldset != NULL) {
13895                         for (i = 0; i < oldset->nodeNr; i++) {
13896                             /*
13897                              * Run the evaluation with a node list made of a single item
13898                              * in the nodeset.
13899                              */
13900                             ctxt->context->node = oldset->nodeTab[i];
13901 			    /*
13902 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13903 			    */
13904 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13905 				ctxt->context->node);
13906                             valuePush(ctxt, tmp);
13907 
13908                             if (op->ch2 != -1)
13909                                 total +=
13910                                     xmlXPathCompOpEval(ctxt,
13911                                                    &comp->steps[op->ch2]);
13912 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13913 				xmlXPathFreeObject(obj);
13914 				return(0);
13915 			    }
13916 
13917                             res = valuePop(ctxt);
13918                             range =
13919                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13920                                                       res);
13921                             if (range != NULL) {
13922                                 xmlXPtrLocationSetAdd(newlocset, range);
13923                             }
13924 
13925                             /*
13926                              * Cleanup
13927                              */
13928                             if (res != NULL) {
13929 				xmlXPathReleaseObject(ctxt->context, res);
13930 			    }
13931                             if (ctxt->value == tmp) {
13932                                 res = valuePop(ctxt);
13933 				xmlXPathReleaseObject(ctxt->context, res);
13934                             }
13935 
13936                             ctxt->context->node = NULL;
13937                         }
13938                     }
13939                 }
13940 
13941                 /*
13942                  * The result is used as the new evaluation set.
13943                  */
13944 		xmlXPathReleaseObject(ctxt->context, obj);
13945                 ctxt->context->node = NULL;
13946                 ctxt->context->contextSize = -1;
13947                 ctxt->context->proximityPosition = -1;
13948                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13949                 return (total);
13950             }
13951 #endif /* LIBXML_XPTR_ENABLED */
13952     }
13953     xmlGenericError(xmlGenericErrorContext,
13954                     "XPath: unknown precompiled operation %d\n", op->op);
13955     return (total);
13956 }
13957 
13958 /**
13959  * xmlXPathCompOpEvalToBoolean:
13960  * @ctxt:  the XPath parser context
13961  *
13962  * Evaluates if the expression evaluates to true.
13963  *
13964  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13965  */
13966 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13967 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13968 			    xmlXPathStepOpPtr op,
13969 			    int isPredicate)
13970 {
13971     xmlXPathObjectPtr resObj = NULL;
13972 
13973 start:
13974     /* comp = ctxt->comp; */
13975     switch (op->op) {
13976         case XPATH_OP_END:
13977             return (0);
13978 	case XPATH_OP_VALUE:
13979 	    resObj = (xmlXPathObjectPtr) op->value4;
13980 	    if (isPredicate)
13981 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13982 	    return(xmlXPathCastToBoolean(resObj));
13983 	case XPATH_OP_SORT:
13984 	    /*
13985 	    * We don't need sorting for boolean results. Skip this one.
13986 	    */
13987             if (op->ch1 != -1) {
13988 		op = &ctxt->comp->steps[op->ch1];
13989 		goto start;
13990 	    }
13991 	    return(0);
13992 	case XPATH_OP_COLLECT:
13993 	    if (op->ch1 == -1)
13994 		return(0);
13995 
13996             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13997 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13998 		return(-1);
13999 
14000             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14001 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14002 		return(-1);
14003 
14004 	    resObj = valuePop(ctxt);
14005 	    if (resObj == NULL)
14006 		return(-1);
14007 	    break;
14008 	default:
14009 	    /*
14010 	    * Fallback to call xmlXPathCompOpEval().
14011 	    */
14012 	    xmlXPathCompOpEval(ctxt, op);
14013 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14014 		return(-1);
14015 
14016 	    resObj = valuePop(ctxt);
14017 	    if (resObj == NULL)
14018 		return(-1);
14019 	    break;
14020     }
14021 
14022     if (resObj) {
14023 	int res;
14024 
14025 	if (resObj->type == XPATH_BOOLEAN) {
14026 	    res = resObj->boolval;
14027 	} else if (isPredicate) {
14028 	    /*
14029 	    * For predicates a result of type "number" is handled
14030 	    * differently:
14031 	    * SPEC XPath 1.0:
14032 	    * "If the result is a number, the result will be converted
14033 	    *  to true if the number is equal to the context position
14034 	    *  and will be converted to false otherwise;"
14035 	    */
14036 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14037 	} else {
14038 	    res = xmlXPathCastToBoolean(resObj);
14039 	}
14040 	xmlXPathReleaseObject(ctxt->context, resObj);
14041 	return(res);
14042     }
14043 
14044     return(0);
14045 }
14046 
14047 #ifdef XPATH_STREAMING
14048 /**
14049  * xmlXPathRunStreamEval:
14050  * @ctxt:  the XPath parser context with the compiled expression
14051  *
14052  * Evaluate the Precompiled Streamable XPath expression in the given context.
14053  */
14054 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14055 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14056 		      xmlXPathObjectPtr *resultSeq, int toBool)
14057 {
14058     int max_depth, min_depth;
14059     int from_root;
14060     int ret, depth;
14061     int eval_all_nodes;
14062     xmlNodePtr cur = NULL, limit = NULL;
14063     xmlStreamCtxtPtr patstream = NULL;
14064 
14065     int nb_nodes = 0;
14066 
14067     if ((ctxt == NULL) || (comp == NULL))
14068         return(-1);
14069     max_depth = xmlPatternMaxDepth(comp);
14070     if (max_depth == -1)
14071         return(-1);
14072     if (max_depth == -2)
14073         max_depth = 10000;
14074     min_depth = xmlPatternMinDepth(comp);
14075     if (min_depth == -1)
14076         return(-1);
14077     from_root = xmlPatternFromRoot(comp);
14078     if (from_root < 0)
14079         return(-1);
14080 #if 0
14081     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14082 #endif
14083 
14084     if (! toBool) {
14085 	if (resultSeq == NULL)
14086 	    return(-1);
14087 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14088 	if (*resultSeq == NULL)
14089 	    return(-1);
14090     }
14091 
14092     /*
14093      * handle the special cases of "/" amd "." being matched
14094      */
14095     if (min_depth == 0) {
14096 	if (from_root) {
14097 	    /* Select "/" */
14098 	    if (toBool)
14099 		return(1);
14100 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14101 		(xmlNodePtr) ctxt->doc);
14102 	} else {
14103 	    /* Select "self::node()" */
14104 	    if (toBool)
14105 		return(1);
14106 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14107 	}
14108     }
14109     if (max_depth == 0) {
14110 	return(0);
14111     }
14112 
14113     if (from_root) {
14114         cur = (xmlNodePtr)ctxt->doc;
14115     } else if (ctxt->node != NULL) {
14116         switch (ctxt->node->type) {
14117             case XML_ELEMENT_NODE:
14118             case XML_DOCUMENT_NODE:
14119             case XML_DOCUMENT_FRAG_NODE:
14120             case XML_HTML_DOCUMENT_NODE:
14121 #ifdef LIBXML_DOCB_ENABLED
14122             case XML_DOCB_DOCUMENT_NODE:
14123 #endif
14124 	        cur = ctxt->node;
14125 		break;
14126             case XML_ATTRIBUTE_NODE:
14127             case XML_TEXT_NODE:
14128             case XML_CDATA_SECTION_NODE:
14129             case XML_ENTITY_REF_NODE:
14130             case XML_ENTITY_NODE:
14131             case XML_PI_NODE:
14132             case XML_COMMENT_NODE:
14133             case XML_NOTATION_NODE:
14134             case XML_DTD_NODE:
14135             case XML_DOCUMENT_TYPE_NODE:
14136             case XML_ELEMENT_DECL:
14137             case XML_ATTRIBUTE_DECL:
14138             case XML_ENTITY_DECL:
14139             case XML_NAMESPACE_DECL:
14140             case XML_XINCLUDE_START:
14141             case XML_XINCLUDE_END:
14142 		break;
14143 	}
14144 	limit = cur;
14145     }
14146     if (cur == NULL) {
14147         return(0);
14148     }
14149 
14150     patstream = xmlPatternGetStreamCtxt(comp);
14151     if (patstream == NULL) {
14152 	/*
14153 	* QUESTION TODO: Is this an error?
14154 	*/
14155 	return(0);
14156     }
14157 
14158     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14159 
14160     if (from_root) {
14161 	ret = xmlStreamPush(patstream, NULL, NULL);
14162 	if (ret < 0) {
14163 	} else if (ret == 1) {
14164 	    if (toBool)
14165 		goto return_1;
14166 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14167 	}
14168     }
14169     depth = 0;
14170     goto scan_children;
14171 next_node:
14172     do {
14173         nb_nodes++;
14174 
14175 	switch (cur->type) {
14176 	    case XML_ELEMENT_NODE:
14177 	    case XML_TEXT_NODE:
14178 	    case XML_CDATA_SECTION_NODE:
14179 	    case XML_COMMENT_NODE:
14180 	    case XML_PI_NODE:
14181 		if (cur->type == XML_ELEMENT_NODE) {
14182 		    ret = xmlStreamPush(patstream, cur->name,
14183 				(cur->ns ? cur->ns->href : NULL));
14184 		} else if (eval_all_nodes)
14185 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14186 		else
14187 		    break;
14188 
14189 		if (ret < 0) {
14190 		    /* NOP. */
14191 		} else if (ret == 1) {
14192 		    if (toBool)
14193 			goto return_1;
14194 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14195 		}
14196 		if ((cur->children == NULL) || (depth >= max_depth)) {
14197 		    ret = xmlStreamPop(patstream);
14198 		    while (cur->next != NULL) {
14199 			cur = cur->next;
14200 			if ((cur->type != XML_ENTITY_DECL) &&
14201 			    (cur->type != XML_DTD_NODE))
14202 			    goto next_node;
14203 		    }
14204 		}
14205 	    default:
14206 		break;
14207 	}
14208 
14209 scan_children:
14210 	if ((cur->children != NULL) && (depth < max_depth)) {
14211 	    /*
14212 	     * Do not descend on entities declarations
14213 	     */
14214 	    if (cur->children->type != XML_ENTITY_DECL) {
14215 		cur = cur->children;
14216 		depth++;
14217 		/*
14218 		 * Skip DTDs
14219 		 */
14220 		if (cur->type != XML_DTD_NODE)
14221 		    continue;
14222 	    }
14223 	}
14224 
14225 	if (cur == limit)
14226 	    break;
14227 
14228 	while (cur->next != NULL) {
14229 	    cur = cur->next;
14230 	    if ((cur->type != XML_ENTITY_DECL) &&
14231 		(cur->type != XML_DTD_NODE))
14232 		goto next_node;
14233 	}
14234 
14235 	do {
14236 	    cur = cur->parent;
14237 	    depth--;
14238 	    if ((cur == NULL) || (cur == limit))
14239 	        goto done;
14240 	    if (cur->type == XML_ELEMENT_NODE) {
14241 		ret = xmlStreamPop(patstream);
14242 	    } else if ((eval_all_nodes) &&
14243 		((cur->type == XML_TEXT_NODE) ||
14244 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14245 		 (cur->type == XML_COMMENT_NODE) ||
14246 		 (cur->type == XML_PI_NODE)))
14247 	    {
14248 		ret = xmlStreamPop(patstream);
14249 	    }
14250 	    if (cur->next != NULL) {
14251 		cur = cur->next;
14252 		break;
14253 	    }
14254 	} while (cur != NULL);
14255 
14256     } while ((cur != NULL) && (depth >= 0));
14257 
14258 done:
14259 
14260 #if 0
14261     printf("stream eval: checked %d nodes selected %d\n",
14262            nb_nodes, retObj->nodesetval->nodeNr);
14263 #endif
14264 
14265     if (patstream)
14266 	xmlFreeStreamCtxt(patstream);
14267     return(0);
14268 
14269 return_1:
14270     if (patstream)
14271 	xmlFreeStreamCtxt(patstream);
14272     return(1);
14273 }
14274 #endif /* XPATH_STREAMING */
14275 
14276 /**
14277  * xmlXPathRunEval:
14278  * @ctxt:  the XPath parser context with the compiled expression
14279  * @toBool:  evaluate to a boolean result
14280  *
14281  * Evaluate the Precompiled XPath expression in the given context.
14282  */
14283 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14284 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14285 {
14286     xmlXPathCompExprPtr comp;
14287 
14288     if ((ctxt == NULL) || (ctxt->comp == NULL))
14289 	return(-1);
14290 
14291     if (ctxt->valueTab == NULL) {
14292 	/* Allocate the value stack */
14293 	ctxt->valueTab = (xmlXPathObjectPtr *)
14294 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14295 	if (ctxt->valueTab == NULL) {
14296 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14297 	    xmlFree(ctxt);
14298 	}
14299 	ctxt->valueNr = 0;
14300 	ctxt->valueMax = 10;
14301 	ctxt->value = NULL;
14302     }
14303 #ifdef XPATH_STREAMING
14304     if (ctxt->comp->stream) {
14305 	int res;
14306 
14307 	if (toBool) {
14308 	    /*
14309 	    * Evaluation to boolean result.
14310 	    */
14311 	    res = xmlXPathRunStreamEval(ctxt->context,
14312 		ctxt->comp->stream, NULL, 1);
14313 	    if (res != -1)
14314 		return(res);
14315 	} else {
14316 	    xmlXPathObjectPtr resObj = NULL;
14317 
14318 	    /*
14319 	    * Evaluation to a sequence.
14320 	    */
14321 	    res = xmlXPathRunStreamEval(ctxt->context,
14322 		ctxt->comp->stream, &resObj, 0);
14323 
14324 	    if ((res != -1) && (resObj != NULL)) {
14325 		valuePush(ctxt, resObj);
14326 		return(0);
14327 	    }
14328 	    if (resObj != NULL)
14329 		xmlXPathReleaseObject(ctxt->context, resObj);
14330 	}
14331 	/*
14332 	* QUESTION TODO: This falls back to normal XPath evaluation
14333 	* if res == -1. Is this intended?
14334 	*/
14335     }
14336 #endif
14337     comp = ctxt->comp;
14338     if (comp->last < 0) {
14339 	xmlGenericError(xmlGenericErrorContext,
14340 	    "xmlXPathRunEval: last is less than zero\n");
14341 	return(-1);
14342     }
14343     if (toBool)
14344 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14345 	    &comp->steps[comp->last], 0));
14346     else
14347 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14348 
14349     return(0);
14350 }
14351 
14352 /************************************************************************
14353  *									*
14354  * 			Public interfaces				*
14355  *									*
14356  ************************************************************************/
14357 
14358 /**
14359  * xmlXPathEvalPredicate:
14360  * @ctxt:  the XPath context
14361  * @res:  the Predicate Expression evaluation result
14362  *
14363  * Evaluate a predicate result for the current node.
14364  * A PredicateExpr is evaluated by evaluating the Expr and converting
14365  * the result to a boolean. If the result is a number, the result will
14366  * be converted to true if the number is equal to the position of the
14367  * context node in the context node list (as returned by the position
14368  * function) and will be converted to false otherwise; if the result
14369  * is not a number, then the result will be converted as if by a call
14370  * to the boolean function.
14371  *
14372  * Returns 1 if predicate is true, 0 otherwise
14373  */
14374 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14375 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14376     if ((ctxt == NULL) || (res == NULL)) return(0);
14377     switch (res->type) {
14378         case XPATH_BOOLEAN:
14379 	    return(res->boolval);
14380         case XPATH_NUMBER:
14381 	    return(res->floatval == ctxt->proximityPosition);
14382         case XPATH_NODESET:
14383         case XPATH_XSLT_TREE:
14384 	    if (res->nodesetval == NULL)
14385 		return(0);
14386 	    return(res->nodesetval->nodeNr != 0);
14387         case XPATH_STRING:
14388 	    return((res->stringval != NULL) &&
14389 	           (xmlStrlen(res->stringval) != 0));
14390         default:
14391 	    STRANGE
14392     }
14393     return(0);
14394 }
14395 
14396 /**
14397  * xmlXPathEvaluatePredicateResult:
14398  * @ctxt:  the XPath Parser context
14399  * @res:  the Predicate Expression evaluation result
14400  *
14401  * Evaluate a predicate result for the current node.
14402  * A PredicateExpr is evaluated by evaluating the Expr and converting
14403  * the result to a boolean. If the result is a number, the result will
14404  * be converted to true if the number is equal to the position of the
14405  * context node in the context node list (as returned by the position
14406  * function) and will be converted to false otherwise; if the result
14407  * is not a number, then the result will be converted as if by a call
14408  * to the boolean function.
14409  *
14410  * Returns 1 if predicate is true, 0 otherwise
14411  */
14412 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14413 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14414                                 xmlXPathObjectPtr res) {
14415     if ((ctxt == NULL) || (res == NULL)) return(0);
14416     switch (res->type) {
14417         case XPATH_BOOLEAN:
14418 	    return(res->boolval);
14419         case XPATH_NUMBER:
14420 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14421 	    return((res->floatval == ctxt->context->proximityPosition) &&
14422 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14423 #else
14424 	    return(res->floatval == ctxt->context->proximityPosition);
14425 #endif
14426         case XPATH_NODESET:
14427         case XPATH_XSLT_TREE:
14428 	    if (res->nodesetval == NULL)
14429 		return(0);
14430 	    return(res->nodesetval->nodeNr != 0);
14431         case XPATH_STRING:
14432 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14433 #ifdef LIBXML_XPTR_ENABLED
14434 	case XPATH_LOCATIONSET:{
14435 	    xmlLocationSetPtr ptr = res->user;
14436 	    if (ptr == NULL)
14437 	        return(0);
14438 	    return (ptr->locNr != 0);
14439 	    }
14440 #endif
14441         default:
14442 	    STRANGE
14443     }
14444     return(0);
14445 }
14446 
14447 #ifdef XPATH_STREAMING
14448 /**
14449  * xmlXPathTryStreamCompile:
14450  * @ctxt: an XPath context
14451  * @str:  the XPath expression
14452  *
14453  * Try to compile the XPath expression as a streamable subset.
14454  *
14455  * Returns the compiled expression or NULL if failed to compile.
14456  */
14457 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14458 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14459     /*
14460      * Optimization: use streaming patterns when the XPath expression can
14461      * be compiled to a stream lookup
14462      */
14463     xmlPatternPtr stream;
14464     xmlXPathCompExprPtr comp;
14465     xmlDictPtr dict = NULL;
14466     const xmlChar **namespaces = NULL;
14467     xmlNsPtr ns;
14468     int i, j;
14469 
14470     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14471         (!xmlStrchr(str, '@'))) {
14472 	const xmlChar *tmp;
14473 
14474 	/*
14475 	 * We don't try to handle expressions using the verbose axis
14476 	 * specifiers ("::"), just the simplied form at this point.
14477 	 * Additionally, if there is no list of namespaces available and
14478 	 *  there's a ":" in the expression, indicating a prefixed QName,
14479 	 *  then we won't try to compile either. xmlPatterncompile() needs
14480 	 *  to have a list of namespaces at compilation time in order to
14481 	 *  compile prefixed name tests.
14482 	 */
14483 	tmp = xmlStrchr(str, ':');
14484 	if ((tmp != NULL) &&
14485 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14486 	    return(NULL);
14487 
14488 	if (ctxt != NULL) {
14489 	    dict = ctxt->dict;
14490 	    if (ctxt->nsNr > 0) {
14491 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14492 		if (namespaces == NULL) {
14493 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14494 		    return(NULL);
14495 		}
14496 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14497 		    ns = ctxt->namespaces[j];
14498 		    namespaces[i++] = ns->href;
14499 		    namespaces[i++] = ns->prefix;
14500 		}
14501 		namespaces[i++] = NULL;
14502 		namespaces[i++] = NULL;
14503 	    }
14504 	}
14505 
14506 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14507 			&namespaces[0]);
14508 	if (namespaces != NULL) {
14509 	    xmlFree((xmlChar **)namespaces);
14510  	}
14511 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14512 	    comp = xmlXPathNewCompExpr();
14513 	    if (comp == NULL) {
14514 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14515 		return(NULL);
14516 	    }
14517 	    comp->stream = stream;
14518 	    comp->dict = dict;
14519 	    if (comp->dict)
14520 		xmlDictReference(comp->dict);
14521 	    return(comp);
14522 	}
14523 	xmlFreePattern(stream);
14524     }
14525     return(NULL);
14526 }
14527 #endif /* XPATH_STREAMING */
14528 
14529 static int
xmlXPathCanRewriteDosExpression(xmlChar * expr)14530 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14531 {
14532     if (expr == NULL)
14533 	return(0);
14534     do {
14535         if ((*expr == '/') && (*(++expr) == '/'))
14536 	    return(1);
14537     } while (*expr++);
14538     return(0);
14539 }
14540 static void
xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14541 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14542 {
14543     /*
14544     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14545     * internal representation.
14546     */
14547     if (op->ch1 != -1) {
14548 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14549 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14550 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14551 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14552 	{
14553 	    /*
14554 	    * This is a "child::foo"
14555 	    */
14556 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14557 
14558 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14559 		(prevop->ch1 != -1) &&
14560 		((xmlXPathAxisVal) prevop->value ==
14561 		    AXIS_DESCENDANT_OR_SELF) &&
14562 		(prevop->ch2 == -1) &&
14563 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14564 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14565 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14566 	    {
14567 		/*
14568 		* This is a "/descendant-or-self::node()" without predicates.
14569 		* Eliminate it.
14570 		*/
14571 		op->ch1 = prevop->ch1;
14572 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14573 	    }
14574 	}
14575 	if (op->ch1 != -1)
14576 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14577     }
14578     if (op->ch2 != -1)
14579 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14580 }
14581 
14582 /**
14583  * xmlXPathCtxtCompile:
14584  * @ctxt: an XPath context
14585  * @str:  the XPath expression
14586  *
14587  * Compile an XPath expression
14588  *
14589  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14590  *         the caller has to free the object.
14591  */
14592 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14593 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14594     xmlXPathParserContextPtr pctxt;
14595     xmlXPathCompExprPtr comp;
14596 
14597 #ifdef XPATH_STREAMING
14598     comp = xmlXPathTryStreamCompile(ctxt, str);
14599     if (comp != NULL)
14600         return(comp);
14601 #endif
14602 
14603     xmlXPathInit();
14604 
14605     pctxt = xmlXPathNewParserContext(str, ctxt);
14606     if (pctxt == NULL)
14607         return NULL;
14608     xmlXPathCompileExpr(pctxt, 1);
14609 
14610     if( pctxt->error != XPATH_EXPRESSION_OK )
14611     {
14612         xmlXPathFreeParserContext(pctxt);
14613         return(NULL);
14614     }
14615 
14616     if (*pctxt->cur != 0) {
14617 	/*
14618 	 * aleksey: in some cases this line prints *second* error message
14619 	 * (see bug #78858) and probably this should be fixed.
14620 	 * However, we are not sure that all error messages are printed
14621 	 * out in other places. It's not critical so we leave it as-is for now
14622 	 */
14623 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14624 	comp = NULL;
14625     } else {
14626 	comp = pctxt->comp;
14627 	pctxt->comp = NULL;
14628     }
14629     xmlXPathFreeParserContext(pctxt);
14630 
14631     if (comp != NULL) {
14632 	comp->expr = xmlStrdup(str);
14633 #ifdef DEBUG_EVAL_COUNTS
14634 	comp->string = xmlStrdup(str);
14635 	comp->nb = 0;
14636 #endif
14637 	if ((comp->expr != NULL) &&
14638 	    (comp->nbStep > 2) &&
14639 	    (comp->last >= 0) &&
14640 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14641 	{
14642 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14643 	}
14644     }
14645     return(comp);
14646 }
14647 
14648 /**
14649  * xmlXPathCompile:
14650  * @str:  the XPath expression
14651  *
14652  * Compile an XPath expression
14653  *
14654  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14655  *         the caller has to free the object.
14656  */
14657 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14658 xmlXPathCompile(const xmlChar *str) {
14659     return(xmlXPathCtxtCompile(NULL, str));
14660 }
14661 
14662 /**
14663  * xmlXPathCompiledEvalInternal:
14664  * @comp:  the compiled XPath expression
14665  * @ctxt:  the XPath context
14666  * @resObj: the resulting XPath object or NULL
14667  * @toBool: 1 if only a boolean result is requested
14668  *
14669  * Evaluate the Precompiled XPath expression in the given context.
14670  * The caller has to free @resObj.
14671  *
14672  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14673  *         the caller has to free the object.
14674  */
14675 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObj,int toBool)14676 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14677 			     xmlXPathContextPtr ctxt,
14678 			     xmlXPathObjectPtr *resObj,
14679 			     int toBool)
14680 {
14681     xmlXPathParserContextPtr pctxt;
14682 #ifndef LIBXML_THREAD_ENABLED
14683     static int reentance = 0;
14684 #endif
14685     int res;
14686 
14687     CHECK_CTXT_NEG(ctxt)
14688 
14689     if (comp == NULL)
14690 	return(-1);
14691     xmlXPathInit();
14692 
14693 #ifndef LIBXML_THREAD_ENABLED
14694     reentance++;
14695     if (reentance > 1)
14696 	xmlXPathDisableOptimizer = 1;
14697 #endif
14698 
14699 #ifdef DEBUG_EVAL_COUNTS
14700     comp->nb++;
14701     if ((comp->string != NULL) && (comp->nb > 100)) {
14702 	fprintf(stderr, "100 x %s\n", comp->string);
14703 	comp->nb = 0;
14704     }
14705 #endif
14706     pctxt = xmlXPathCompParserContext(comp, ctxt);
14707     res = xmlXPathRunEval(pctxt, toBool);
14708 
14709     if (resObj) {
14710 	if (pctxt->value == NULL) {
14711 	    xmlGenericError(xmlGenericErrorContext,
14712 		"xmlXPathCompiledEval: evaluation failed\n");
14713 	    *resObj = NULL;
14714 	} else {
14715 	    *resObj = valuePop(pctxt);
14716 	}
14717     }
14718 
14719     /*
14720     * Pop all remaining objects from the stack.
14721     */
14722     if (pctxt->valueNr > 0) {
14723 	xmlXPathObjectPtr tmp;
14724 	int stack = 0;
14725 
14726 	do {
14727 	    tmp = valuePop(pctxt);
14728 	    if (tmp != NULL) {
14729 		stack++;
14730 		xmlXPathReleaseObject(ctxt, tmp);
14731 	    }
14732 	} while (tmp != NULL);
14733 	if ((stack != 0) &&
14734 	    ((toBool) || ((resObj) && (*resObj))))
14735 	{
14736 	    xmlGenericError(xmlGenericErrorContext,
14737 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14738 		stack);
14739 	}
14740     }
14741 
14742     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14743 	xmlXPathFreeObject(*resObj);
14744 	*resObj = NULL;
14745     }
14746     pctxt->comp = NULL;
14747     xmlXPathFreeParserContext(pctxt);
14748 #ifndef LIBXML_THREAD_ENABLED
14749     reentance--;
14750 #endif
14751 
14752     return(res);
14753 }
14754 
14755 /**
14756  * xmlXPathCompiledEval:
14757  * @comp:  the compiled XPath expression
14758  * @ctx:  the XPath context
14759  *
14760  * Evaluate the Precompiled XPath expression in the given context.
14761  *
14762  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14763  *         the caller has to free the object.
14764  */
14765 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14766 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14767 {
14768     xmlXPathObjectPtr res = NULL;
14769 
14770     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14771     return(res);
14772 }
14773 
14774 /**
14775  * xmlXPathCompiledEvalToBoolean:
14776  * @comp:  the compiled XPath expression
14777  * @ctxt:  the XPath context
14778  *
14779  * Applies the XPath boolean() function on the result of the given
14780  * compiled expression.
14781  *
14782  * Returns 1 if the expression evaluated to true, 0 if to false and
14783  *         -1 in API and internal errors.
14784  */
14785 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14786 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14787 			      xmlXPathContextPtr ctxt)
14788 {
14789     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14790 }
14791 
14792 /**
14793  * xmlXPathEvalExpr:
14794  * @ctxt:  the XPath Parser context
14795  *
14796  * Parse and evaluate an XPath expression in the given context,
14797  * then push the result on the context stack
14798  */
14799 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14800 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14801 #ifdef XPATH_STREAMING
14802     xmlXPathCompExprPtr comp;
14803 #endif
14804 
14805     if (ctxt == NULL) return;
14806 
14807 #ifdef XPATH_STREAMING
14808     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14809     if (comp != NULL) {
14810         if (ctxt->comp != NULL)
14811 	    xmlXPathFreeCompExpr(ctxt->comp);
14812         ctxt->comp = comp;
14813 	if (ctxt->cur != NULL)
14814 	    while (*ctxt->cur != 0) ctxt->cur++;
14815     } else
14816 #endif
14817     {
14818 	xmlXPathCompileExpr(ctxt, 1);
14819 	/*
14820 	* In this scenario the expression string will sit in ctxt->base.
14821 	*/
14822 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14823 	    (ctxt->comp != NULL) &&
14824 	    (ctxt->base != NULL) &&
14825 	    (ctxt->comp->nbStep > 2) &&
14826 	    (ctxt->comp->last >= 0) &&
14827 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14828 	{
14829 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14830 		&ctxt->comp->steps[ctxt->comp->last]);
14831 	}
14832     }
14833     CHECK_ERROR;
14834     xmlXPathRunEval(ctxt, 0);
14835 }
14836 
14837 /**
14838  * xmlXPathEval:
14839  * @str:  the XPath expression
14840  * @ctx:  the XPath context
14841  *
14842  * Evaluate the XPath Location Path in the given context.
14843  *
14844  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14845  *         the caller has to free the object.
14846  */
14847 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14848 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14849     xmlXPathParserContextPtr ctxt;
14850     xmlXPathObjectPtr res, tmp, init = NULL;
14851     int stack = 0;
14852 
14853     CHECK_CTXT(ctx)
14854 
14855     xmlXPathInit();
14856 
14857     ctxt = xmlXPathNewParserContext(str, ctx);
14858     if (ctxt == NULL)
14859         return NULL;
14860     xmlXPathEvalExpr(ctxt);
14861 
14862     if (ctxt->value == NULL) {
14863 	xmlGenericError(xmlGenericErrorContext,
14864 		"xmlXPathEval: evaluation failed\n");
14865 	res = NULL;
14866     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14867 #ifdef XPATH_STREAMING
14868             && (ctxt->comp->stream == NULL)
14869 #endif
14870 	      ) {
14871 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14872 	res = NULL;
14873     } else {
14874 	res = valuePop(ctxt);
14875     }
14876 
14877     do {
14878         tmp = valuePop(ctxt);
14879 	if (tmp != NULL) {
14880 	    if (tmp != init)
14881 		stack++;
14882 	    xmlXPathReleaseObject(ctx, tmp);
14883         }
14884     } while (tmp != NULL);
14885     if ((stack != 0) && (res != NULL)) {
14886 	xmlGenericError(xmlGenericErrorContext,
14887 		"xmlXPathEval: %d object left on the stack\n",
14888 	        stack);
14889     }
14890     if (ctxt->error != XPATH_EXPRESSION_OK) {
14891 	xmlXPathFreeObject(res);
14892 	res = NULL;
14893     }
14894 
14895     xmlXPathFreeParserContext(ctxt);
14896     return(res);
14897 }
14898 
14899 /**
14900  * xmlXPathEvalExpression:
14901  * @str:  the XPath expression
14902  * @ctxt:  the XPath context
14903  *
14904  * Evaluate the XPath expression in the given context.
14905  *
14906  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14907  *         the caller has to free the object.
14908  */
14909 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14910 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14911     xmlXPathParserContextPtr pctxt;
14912     xmlXPathObjectPtr res, tmp;
14913     int stack = 0;
14914 
14915     CHECK_CTXT(ctxt)
14916 
14917     xmlXPathInit();
14918 
14919     pctxt = xmlXPathNewParserContext(str, ctxt);
14920     if (pctxt == NULL)
14921         return NULL;
14922     xmlXPathEvalExpr(pctxt);
14923 
14924     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14925 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14926 	res = NULL;
14927     } else {
14928 	res = valuePop(pctxt);
14929     }
14930     do {
14931         tmp = valuePop(pctxt);
14932 	if (tmp != NULL) {
14933 	    xmlXPathReleaseObject(ctxt, tmp);
14934 	    stack++;
14935 	}
14936     } while (tmp != NULL);
14937     if ((stack != 0) && (res != NULL)) {
14938 	xmlGenericError(xmlGenericErrorContext,
14939 		"xmlXPathEvalExpression: %d object left on the stack\n",
14940 	        stack);
14941     }
14942     xmlXPathFreeParserContext(pctxt);
14943     return(res);
14944 }
14945 
14946 /************************************************************************
14947  *									*
14948  *	Extra functions not pertaining to the XPath spec		*
14949  *									*
14950  ************************************************************************/
14951 /**
14952  * xmlXPathEscapeUriFunction:
14953  * @ctxt:  the XPath Parser context
14954  * @nargs:  the number of arguments
14955  *
14956  * Implement the escape-uri() XPath function
14957  *    string escape-uri(string $str, bool $escape-reserved)
14958  *
14959  * This function applies the URI escaping rules defined in section 2 of [RFC
14960  * 2396] to the string supplied as $uri-part, which typically represents all
14961  * or part of a URI. The effect of the function is to replace any special
14962  * character in the string by an escape sequence of the form %xx%yy...,
14963  * where xxyy... is the hexadecimal representation of the octets used to
14964  * represent the character in UTF-8.
14965  *
14966  * The set of characters that are escaped depends on the setting of the
14967  * boolean argument $escape-reserved.
14968  *
14969  * If $escape-reserved is true, all characters are escaped other than lower
14970  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14971  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14972  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14973  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14974  * A-F).
14975  *
14976  * If $escape-reserved is false, the behavior differs in that characters
14977  * referred to in [RFC 2396] as reserved characters are not escaped. These
14978  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14979  *
14980  * [RFC 2396] does not define whether escaped URIs should use lower case or
14981  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14982  * compared using string comparison functions, this function must always use
14983  * the upper-case letters A-F.
14984  *
14985  * Generally, $escape-reserved should be set to true when escaping a string
14986  * that is to form a single part of a URI, and to false when escaping an
14987  * entire URI or URI reference.
14988  *
14989  * In the case of non-ascii characters, the string is encoded according to
14990  * utf-8 and then converted according to RFC 2396.
14991  *
14992  * Examples
14993  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14994  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14995  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14996  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14997  *
14998  */
14999 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15000 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15001     xmlXPathObjectPtr str;
15002     int escape_reserved;
15003     xmlBufferPtr target;
15004     xmlChar *cptr;
15005     xmlChar escape[4];
15006 
15007     CHECK_ARITY(2);
15008 
15009     escape_reserved = xmlXPathPopBoolean(ctxt);
15010 
15011     CAST_TO_STRING;
15012     str = valuePop(ctxt);
15013 
15014     target = xmlBufferCreate();
15015 
15016     escape[0] = '%';
15017     escape[3] = 0;
15018 
15019     if (target) {
15020 	for (cptr = str->stringval; *cptr; cptr++) {
15021 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15022 		(*cptr >= 'a' && *cptr <= 'z') ||
15023 		(*cptr >= '0' && *cptr <= '9') ||
15024 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15025 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15026 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15027 		(*cptr == '%' &&
15028 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15029 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15030 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15031 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15032 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15033 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15034 		(!escape_reserved &&
15035 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15036 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15037 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15038 		  *cptr == ','))) {
15039 		xmlBufferAdd(target, cptr, 1);
15040 	    } else {
15041 		if ((*cptr >> 4) < 10)
15042 		    escape[1] = '0' + (*cptr >> 4);
15043 		else
15044 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15045 		if ((*cptr & 0xF) < 10)
15046 		    escape[2] = '0' + (*cptr & 0xF);
15047 		else
15048 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15049 
15050 		xmlBufferAdd(target, &escape[0], 3);
15051 	    }
15052 	}
15053     }
15054     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15055 	xmlBufferContent(target)));
15056     xmlBufferFree(target);
15057     xmlXPathReleaseObject(ctxt->context, str);
15058 }
15059 
15060 /**
15061  * xmlXPathRegisterAllFunctions:
15062  * @ctxt:  the XPath context
15063  *
15064  * Registers all default XPath functions in this context
15065  */
15066 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15067 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15068 {
15069     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15070                          xmlXPathBooleanFunction);
15071     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15072                          xmlXPathCeilingFunction);
15073     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15074                          xmlXPathCountFunction);
15075     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15076                          xmlXPathConcatFunction);
15077     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15078                          xmlXPathContainsFunction);
15079     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15080                          xmlXPathIdFunction);
15081     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15082                          xmlXPathFalseFunction);
15083     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15084                          xmlXPathFloorFunction);
15085     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15086                          xmlXPathLastFunction);
15087     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15088                          xmlXPathLangFunction);
15089     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15090                          xmlXPathLocalNameFunction);
15091     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15092                          xmlXPathNotFunction);
15093     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15094                          xmlXPathNameFunction);
15095     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15096                          xmlXPathNamespaceURIFunction);
15097     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15098                          xmlXPathNormalizeFunction);
15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15100                          xmlXPathNumberFunction);
15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15102                          xmlXPathPositionFunction);
15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15104                          xmlXPathRoundFunction);
15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15106                          xmlXPathStringFunction);
15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15108                          xmlXPathStringLengthFunction);
15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15110                          xmlXPathStartsWithFunction);
15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15112                          xmlXPathSubstringFunction);
15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15114                          xmlXPathSubstringBeforeFunction);
15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15116                          xmlXPathSubstringAfterFunction);
15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15118                          xmlXPathSumFunction);
15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15120                          xmlXPathTrueFunction);
15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15122                          xmlXPathTranslateFunction);
15123 
15124     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15125 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15126                          xmlXPathEscapeUriFunction);
15127 }
15128 
15129 #endif /* LIBXML_XPATH_ENABLED */
15130 #define bottom_xpath
15131 #include "elfgcchack.h"
15132