• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 #define IN_LIBXML
18 #include "libxml.h"
19 
20 #include <string.h>
21 
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37 
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57 
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61 
62 #define TODO 								\
63     xmlGenericError(xmlGenericErrorContext,				\
64 	    "Unimplemented block at %s:%d\n",				\
65             __FILE__, __LINE__);
66 
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77 
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84 
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91 
92 /*
93  * TODO:
94  * There are a few spots where some tests are done which depend upon ascii
95  * data.  These should be enhanced for full UTF8 support (see particularly
96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97  */
98 
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100 
101 /************************************************************************
102  * 									*
103  * 			Floating point stuff				*
104  * 									*
105  ************************************************************************/
106 
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111 
112 /*
113  * The lack of portability of this section of the libc is annoying !
114  */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120 
121 /**
122  * xmlXPathInit:
123  *
124  * Initialize the XPath environment
125  */
126 void
xmlXPathInit(void)127 xmlXPathInit(void) {
128     if (xmlXPathInitialized) return;
129 
130     xmlXPathPINF = trio_pinf();
131     xmlXPathNINF = trio_ninf();
132     xmlXPathNAN = trio_nan();
133     xmlXPathNZERO = trio_nzero();
134 
135     xmlXPathInitialized = 1;
136 }
137 
138 /**
139  * xmlXPathIsNaN:
140  * @val:  a double value
141  *
142  * Provides a portable isnan() function to detect whether a double
143  * is a NotaNumber. Based on trio code
144  * http://sourceforge.net/projects/ctrio/
145  *
146  * Returns 1 if the value is a NaN, 0 otherwise
147  */
148 int
xmlXPathIsNaN(double val)149 xmlXPathIsNaN(double val) {
150     return(trio_isnan(val));
151 }
152 
153 /**
154  * xmlXPathIsInf:
155  * @val:  a double value
156  *
157  * Provides a portable isinf() function to detect whether a double
158  * is a +Infinite or -Infinite. Based on trio code
159  * http://sourceforge.net/projects/ctrio/
160  *
161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162  */
163 int
xmlXPathIsInf(double val)164 xmlXPathIsInf(double val) {
165     return(trio_isinf(val));
166 }
167 
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171  * xmlXPathGetSign:
172  * @val:  a double value
173  *
174  * Provides a portable function to detect the sign of a double
175  * Modified from trio code
176  * http://sourceforge.net/projects/ctrio/
177  *
178  * Returns 1 if the value is Negative, 0 if positive
179  */
180 static int
xmlXPathGetSign(double val)181 xmlXPathGetSign(double val) {
182     return(trio_signbit(val));
183 }
184 
185 
186 /*
187  * TODO: when compatibility allows remove all "fake node libxslt" strings
188  *       the test should just be name[0] = ' '
189  */
190 /* #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 0
3667 	/*
3668 	* TODO: The optimization won't work in every case, since
3669 	*  those nasty namespace nodes need to be added with
3670 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3671 	*  memcpy is not possible.
3672 	*  If there was a flag on the nodesetval, indicating that
3673 	*  some temporary nodes are in, that would be helpfull.
3674 	*/
3675 	/*
3676 	* Optimization: Create an equally sized node-set
3677 	* and memcpy the content.
3678 	*/
3679 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3680 	if (val1 == NULL)
3681 	    return(NULL);
3682 	if (val2->nodeNr != 0) {
3683 	    if (val2->nodeNr == 1)
3684 		*(val1->nodeTab) = *(val2->nodeTab);
3685 	    else {
3686 		memcpy(val1->nodeTab, val2->nodeTab,
3687 		    val2->nodeNr * sizeof(xmlNodePtr));
3688 	    }
3689 	    val1->nodeNr = val2->nodeNr;
3690 	}
3691 	return(val1);
3692 #endif
3693     }
3694 
3695     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3696     initNr = val1->nodeNr;
3697 
3698     for (i = 0;i < val2->nodeNr;i++) {
3699 	n2 = val2->nodeTab[i];
3700 	/*
3701 	 * check against duplicates
3702 	 */
3703 	skip = 0;
3704 	for (j = 0; j < initNr; j++) {
3705 	    n1 = val1->nodeTab[j];
3706 	    if (n1 == n2) {
3707 		skip = 1;
3708 		break;
3709 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3710 		       (n2->type == XML_NAMESPACE_DECL)) {
3711 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3712 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3713 			((xmlNsPtr) n2)->prefix)))
3714 		{
3715 		    skip = 1;
3716 		    break;
3717 		}
3718 	    }
3719 	}
3720 	if (skip)
3721 	    continue;
3722 
3723 	/*
3724 	 * grow the nodeTab if needed
3725 	 */
3726 	if (val1->nodeMax == 0) {
3727 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3728 						    sizeof(xmlNodePtr));
3729 	    if (val1->nodeTab == NULL) {
3730 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3731 		return(NULL);
3732 	    }
3733 	    memset(val1->nodeTab, 0 ,
3734 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3735 	    val1->nodeMax = XML_NODESET_DEFAULT;
3736 	} else if (val1->nodeNr == val1->nodeMax) {
3737 	    xmlNodePtr *temp;
3738 
3739 	    val1->nodeMax *= 2;
3740 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3741 					     sizeof(xmlNodePtr));
3742 	    if (temp == NULL) {
3743 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3744 		return(NULL);
3745 	    }
3746 	    val1->nodeTab = temp;
3747 	}
3748 	if (n2->type == XML_NAMESPACE_DECL) {
3749 	    xmlNsPtr ns = (xmlNsPtr) n2;
3750 
3751 	    val1->nodeTab[val1->nodeNr++] =
3752 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3753 	} else
3754 	    val1->nodeTab[val1->nodeNr++] = n2;
3755     }
3756 
3757     return(val1);
3758 }
3759 
3760 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3761 /**
3762  * xmlXPathNodeSetMergeUnique:
3763  * @val1:  the first NodeSet or NULL
3764  * @val2:  the second NodeSet
3765  *
3766  * Merges two nodesets, all nodes from @val2 are added to @val1
3767  * if @val1 is NULL, a new set is created and copied from @val2
3768  *
3769  * Returns @val1 once extended or NULL in case of error.
3770  */
3771 static xmlNodeSetPtr
3772 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3773     int i;
3774 
3775     if (val2 == NULL) return(val1);
3776     if (val1 == NULL) {
3777 	val1 = xmlXPathNodeSetCreate(NULL);
3778     }
3779 
3780     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781 
3782     for (i = 0;i < val2->nodeNr;i++) {
3783 	/*
3784 	 * grow the nodeTab if needed
3785 	 */
3786 	if (val1->nodeMax == 0) {
3787 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788 						    sizeof(xmlNodePtr));
3789 	    if (val1->nodeTab == NULL) {
3790 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3791 		return(NULL);
3792 	    }
3793 	    memset(val1->nodeTab, 0 ,
3794 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795 	    val1->nodeMax = XML_NODESET_DEFAULT;
3796 	} else if (val1->nodeNr == val1->nodeMax) {
3797 	    xmlNodePtr *temp;
3798 
3799 	    val1->nodeMax *= 2;
3800 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3801 					     sizeof(xmlNodePtr));
3802 	    if (temp == NULL) {
3803 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3804 		return(NULL);
3805 	    }
3806 	    val1->nodeTab = temp;
3807 	}
3808 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3809 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3810 
3811 	    val1->nodeTab[val1->nodeNr++] =
3812 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3813 	} else
3814 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3815     }
3816 
3817     return(val1);
3818 }
3819 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3820 
3821 /**
3822  * xmlXPathNodeSetMergeAndClear:
3823  * @set1:  the first NodeSet or NULL
3824  * @set2:  the second NodeSet
3825  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3826  *
3827  * Merges two nodesets, all nodes from @set2 are added to @set1
3828  * if @set1 is NULL, a new set is created and copied from @set2.
3829  * Checks for duplicate nodes. Clears set2.
3830  *
3831  * Returns @set1 once extended or NULL in case of error.
3832  */
3833 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3834 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3835 			     int hasNullEntries)
3836 {
3837     if ((set1 == NULL) && (hasNullEntries == 0)) {
3838 	/*
3839 	* Note that doing a memcpy of the list, namespace nodes are
3840 	* just assigned to set1, since set2 is cleared anyway.
3841 	*/
3842 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3843 	if (set1 == NULL)
3844 	    return(NULL);
3845 	if (set2->nodeNr != 0) {
3846 	    memcpy(set1->nodeTab, set2->nodeTab,
3847 		set2->nodeNr * sizeof(xmlNodePtr));
3848 	    set1->nodeNr = set2->nodeNr;
3849 	}
3850     } else {
3851 	int i, j, initNbSet1;
3852 	xmlNodePtr n1, n2;
3853 
3854 	if (set1 == NULL)
3855 	    	set1 = xmlXPathNodeSetCreate(NULL);
3856 
3857 	initNbSet1 = set1->nodeNr;
3858 	for (i = 0;i < set2->nodeNr;i++) {
3859 	    n2 = set2->nodeTab[i];
3860 	    /*
3861 	    * Skip NULLed entries.
3862 	    */
3863 	    if (n2 == NULL)
3864 		continue;
3865 	    /*
3866 	    * Skip duplicates.
3867 	    */
3868 	    for (j = 0; j < initNbSet1; j++) {
3869 		n1 = set1->nodeTab[j];
3870 		if (n1 == n2) {
3871 		    goto skip_node;
3872 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3873 		    (n2->type == XML_NAMESPACE_DECL))
3874 		{
3875 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3876 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3877 			((xmlNsPtr) n2)->prefix)))
3878 		    {
3879 			/*
3880 			* Free the namespace node.
3881 			*/
3882 			set2->nodeTab[i] = NULL;
3883 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3884 			goto skip_node;
3885 		    }
3886 		}
3887 	    }
3888 	    /*
3889 	    * grow the nodeTab if needed
3890 	    */
3891 	    if (set1->nodeMax == 0) {
3892 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3893 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3894 		if (set1->nodeTab == NULL) {
3895 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3896 		    return(NULL);
3897 		}
3898 		memset(set1->nodeTab, 0,
3899 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3900 		set1->nodeMax = XML_NODESET_DEFAULT;
3901 	    } else if (set1->nodeNr >= set1->nodeMax) {
3902 		xmlNodePtr *temp;
3903 
3904 		set1->nodeMax *= 2;
3905 		temp = (xmlNodePtr *) xmlRealloc(
3906 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3907 		if (temp == NULL) {
3908 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 		    return(NULL);
3910 		}
3911 		set1->nodeTab = temp;
3912 	    }
3913 	    if (n2->type == XML_NAMESPACE_DECL) {
3914 		xmlNsPtr ns = (xmlNsPtr) n2;
3915 
3916 		set1->nodeTab[set1->nodeNr++] =
3917 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918 	    } else
3919 		set1->nodeTab[set1->nodeNr++] = n2;
3920 skip_node:
3921 	    {}
3922 	}
3923     }
3924     set2->nodeNr = 0;
3925     return(set1);
3926 }
3927 
3928 /**
3929  * xmlXPathNodeSetMergeAndClearNoDupls:
3930  * @set1:  the first NodeSet or NULL
3931  * @set2:  the second NodeSet
3932  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3933  *
3934  * Merges two nodesets, all nodes from @set2 are added to @set1
3935  * if @set1 is NULL, a new set is created and copied from @set2.
3936  * Doesn't chack for duplicate nodes. Clears set2.
3937  *
3938  * Returns @set1 once extended or NULL in case of error.
3939  */
3940 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3941 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3942 				    int hasNullEntries)
3943 {
3944     if (set2 == NULL)
3945 	return(set1);
3946     if ((set1 == NULL) && (hasNullEntries == 0)) {
3947 	/*
3948 	* Note that doing a memcpy of the list, namespace nodes are
3949 	* just assigned to set1, since set2 is cleared anyway.
3950 	*/
3951 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3952 	if (set1 == NULL)
3953 	    return(NULL);
3954 	if (set2->nodeNr != 0) {
3955 	    memcpy(set1->nodeTab, set2->nodeTab,
3956 		set2->nodeNr * sizeof(xmlNodePtr));
3957 	    set1->nodeNr = set2->nodeNr;
3958 	}
3959     } else {
3960 	int i;
3961 	xmlNodePtr n2;
3962 
3963 	if (set1 == NULL)
3964 	    set1 = xmlXPathNodeSetCreate(NULL);
3965 
3966 	for (i = 0;i < set2->nodeNr;i++) {
3967 	    n2 = set2->nodeTab[i];
3968 	    /*
3969 	    * Skip NULLed entries.
3970 	    */
3971 	    if (n2 == NULL)
3972 		continue;
3973 	    if (set1->nodeMax == 0) {
3974 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3975 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3976 		if (set1->nodeTab == NULL) {
3977 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3978 		    return(NULL);
3979 		}
3980 		memset(set1->nodeTab, 0,
3981 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3982 		set1->nodeMax = XML_NODESET_DEFAULT;
3983 	    } else if (set1->nodeNr >= set1->nodeMax) {
3984 		xmlNodePtr *temp;
3985 
3986 		set1->nodeMax *= 2;
3987 		temp = (xmlNodePtr *) xmlRealloc(
3988 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3989 		if (temp == NULL) {
3990 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3991 		    return(NULL);
3992 		}
3993 		set1->nodeTab = temp;
3994 	    }
3995 	    set1->nodeTab[set1->nodeNr++] = n2;
3996 	}
3997     }
3998     set2->nodeNr = 0;
3999     return(set1);
4000 }
4001 
4002 /**
4003  * xmlXPathNodeSetDel:
4004  * @cur:  the initial node set
4005  * @val:  an xmlNodePtr
4006  *
4007  * Removes an xmlNodePtr from an existing NodeSet
4008  */
4009 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4010 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4011     int i;
4012 
4013     if (cur == NULL) return;
4014     if (val == NULL) return;
4015 
4016     /*
4017      * find node in nodeTab
4018      */
4019     for (i = 0;i < cur->nodeNr;i++)
4020         if (cur->nodeTab[i] == val) break;
4021 
4022     if (i >= cur->nodeNr) {	/* not found */
4023 #ifdef DEBUG
4024         xmlGenericError(xmlGenericErrorContext,
4025 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4026 		val->name);
4027 #endif
4028         return;
4029     }
4030     if ((cur->nodeTab[i] != NULL) &&
4031 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4032 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4033     cur->nodeNr--;
4034     for (;i < cur->nodeNr;i++)
4035         cur->nodeTab[i] = cur->nodeTab[i + 1];
4036     cur->nodeTab[cur->nodeNr] = NULL;
4037 }
4038 
4039 /**
4040  * xmlXPathNodeSetRemove:
4041  * @cur:  the initial node set
4042  * @val:  the index to remove
4043  *
4044  * Removes an entry from an existing NodeSet list.
4045  */
4046 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4047 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4048     if (cur == NULL) return;
4049     if (val >= cur->nodeNr) return;
4050     if ((cur->nodeTab[val] != NULL) &&
4051 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4052 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4053     cur->nodeNr--;
4054     for (;val < cur->nodeNr;val++)
4055         cur->nodeTab[val] = cur->nodeTab[val + 1];
4056     cur->nodeTab[cur->nodeNr] = NULL;
4057 }
4058 
4059 /**
4060  * xmlXPathFreeNodeSet:
4061  * @obj:  the xmlNodeSetPtr to free
4062  *
4063  * Free the NodeSet compound (not the actual nodes !).
4064  */
4065 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4066 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4067     if (obj == NULL) return;
4068     if (obj->nodeTab != NULL) {
4069 	int i;
4070 
4071 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4072 	for (i = 0;i < obj->nodeNr;i++)
4073 	    if ((obj->nodeTab[i] != NULL) &&
4074 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4075 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4076 	xmlFree(obj->nodeTab);
4077     }
4078     xmlFree(obj);
4079 }
4080 
4081 /**
4082  * xmlXPathNodeSetClear:
4083  * @set:  the node set to clear
4084  *
4085  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4086  * are feed), but does *not* free the list itself. Sets the length of the
4087  * list to 0.
4088  */
4089 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4090 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4091 {
4092     if ((set == NULL) || (set->nodeNr <= 0))
4093 	return;
4094     else if (hasNsNodes) {
4095 	int i;
4096 	xmlNodePtr node;
4097 
4098 	for (i = 0; i < set->nodeNr; i++) {
4099 	    node = set->nodeTab[i];
4100 	    if ((node != NULL) &&
4101 		(node->type == XML_NAMESPACE_DECL))
4102 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4103 	}
4104     }
4105     set->nodeNr = 0;
4106 }
4107 
4108 /**
4109  * xmlXPathNodeSetClearFromPos:
4110  * @set: the node set to be cleared
4111  * @pos: the start position to clear from
4112  *
4113  * Clears the list from temporary XPath objects (e.g. namespace nodes
4114  * are feed) starting with the entry at @pos, but does *not* free the list
4115  * itself. Sets the length of the list to @pos.
4116  */
4117 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4118 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4119 {
4120     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4121 	return;
4122     else if ((hasNsNodes)) {
4123 	int i;
4124 	xmlNodePtr node;
4125 
4126 	for (i = pos; i < set->nodeNr; i++) {
4127 	    node = set->nodeTab[i];
4128 	    if ((node != NULL) &&
4129 		(node->type == XML_NAMESPACE_DECL))
4130 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4131 	}
4132     }
4133     set->nodeNr = pos;
4134 }
4135 
4136 /**
4137  * xmlXPathFreeValueTree:
4138  * @obj:  the xmlNodeSetPtr to free
4139  *
4140  * Free the NodeSet compound and the actual tree, this is different
4141  * from xmlXPathFreeNodeSet()
4142  */
4143 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4144 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4145     int i;
4146 
4147     if (obj == NULL) return;
4148 
4149     if (obj->nodeTab != NULL) {
4150 	for (i = 0;i < obj->nodeNr;i++) {
4151 	    if (obj->nodeTab[i] != NULL) {
4152 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4153 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 		} else {
4155 		    xmlFreeNodeList(obj->nodeTab[i]);
4156 		}
4157 	    }
4158 	}
4159 	xmlFree(obj->nodeTab);
4160     }
4161     xmlFree(obj);
4162 }
4163 
4164 #if defined(DEBUG) || defined(DEBUG_STEP)
4165 /**
4166  * xmlGenericErrorContextNodeSet:
4167  * @output:  a FILE * for the output
4168  * @obj:  the xmlNodeSetPtr to display
4169  *
4170  * Quick display of a NodeSet
4171  */
4172 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4173 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4174     int i;
4175 
4176     if (output == NULL) output = xmlGenericErrorContext;
4177     if (obj == NULL)  {
4178         fprintf(output, "NodeSet == NULL !\n");
4179 	return;
4180     }
4181     if (obj->nodeNr == 0) {
4182         fprintf(output, "NodeSet is empty\n");
4183 	return;
4184     }
4185     if (obj->nodeTab == NULL) {
4186 	fprintf(output, " nodeTab == NULL !\n");
4187 	return;
4188     }
4189     for (i = 0; i < obj->nodeNr; i++) {
4190         if (obj->nodeTab[i] == NULL) {
4191 	    fprintf(output, " NULL !\n");
4192 	    return;
4193         }
4194 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4195 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4196 	    fprintf(output, " /");
4197 	else if (obj->nodeTab[i]->name == NULL)
4198 	    fprintf(output, " noname!");
4199 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4200     }
4201     fprintf(output, "\n");
4202 }
4203 #endif
4204 
4205 /**
4206  * xmlXPathNewNodeSet:
4207  * @val:  the NodePtr value
4208  *
4209  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4210  * it with the single Node @val
4211  *
4212  * Returns the newly created object.
4213  */
4214 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4215 xmlXPathNewNodeSet(xmlNodePtr val) {
4216     xmlXPathObjectPtr ret;
4217 
4218     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4219     if (ret == NULL) {
4220         xmlXPathErrMemory(NULL, "creating nodeset\n");
4221 	return(NULL);
4222     }
4223     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4224     ret->type = XPATH_NODESET;
4225     ret->boolval = 0;
4226     ret->nodesetval = xmlXPathNodeSetCreate(val);
4227     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4228 #ifdef XP_DEBUG_OBJ_USAGE
4229     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4230 #endif
4231     return(ret);
4232 }
4233 
4234 /**
4235  * xmlXPathNewValueTree:
4236  * @val:  the NodePtr value
4237  *
4238  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4239  * it with the tree root @val
4240  *
4241  * Returns the newly created object.
4242  */
4243 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4244 xmlXPathNewValueTree(xmlNodePtr val) {
4245     xmlXPathObjectPtr ret;
4246 
4247     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4248     if (ret == NULL) {
4249         xmlXPathErrMemory(NULL, "creating result value tree\n");
4250 	return(NULL);
4251     }
4252     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4253     ret->type = XPATH_XSLT_TREE;
4254     ret->boolval = 1;
4255     ret->user = (void *) val;
4256     ret->nodesetval = xmlXPathNodeSetCreate(val);
4257 #ifdef XP_DEBUG_OBJ_USAGE
4258     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4259 #endif
4260     return(ret);
4261 }
4262 
4263 /**
4264  * xmlXPathNewNodeSetList:
4265  * @val:  an existing NodeSet
4266  *
4267  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4268  * it with the Nodeset @val
4269  *
4270  * Returns the newly created object.
4271  */
4272 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4273 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4274 {
4275     xmlXPathObjectPtr ret;
4276     int i;
4277 
4278     if (val == NULL)
4279         ret = NULL;
4280     else if (val->nodeTab == NULL)
4281         ret = xmlXPathNewNodeSet(NULL);
4282     else {
4283         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4284         for (i = 1; i < val->nodeNr; ++i)
4285             xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4286     }
4287 
4288     return (ret);
4289 }
4290 
4291 /**
4292  * xmlXPathWrapNodeSet:
4293  * @val:  the NodePtr value
4294  *
4295  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4296  *
4297  * Returns the newly created object.
4298  */
4299 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4300 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4301     xmlXPathObjectPtr ret;
4302 
4303     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304     if (ret == NULL) {
4305         xmlXPathErrMemory(NULL, "creating node set object\n");
4306 	return(NULL);
4307     }
4308     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309     ret->type = XPATH_NODESET;
4310     ret->nodesetval = val;
4311 #ifdef XP_DEBUG_OBJ_USAGE
4312     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4313 #endif
4314     return(ret);
4315 }
4316 
4317 /**
4318  * xmlXPathFreeNodeSetList:
4319  * @obj:  an existing NodeSetList object
4320  *
4321  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4322  * the list contrary to xmlXPathFreeObject().
4323  */
4324 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4325 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4326     if (obj == NULL) return;
4327 #ifdef XP_DEBUG_OBJ_USAGE
4328     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4329 #endif
4330     xmlFree(obj);
4331 }
4332 
4333 /**
4334  * xmlXPathDifference:
4335  * @nodes1:  a node-set
4336  * @nodes2:  a node-set
4337  *
4338  * Implements the EXSLT - Sets difference() function:
4339  *    node-set set:difference (node-set, node-set)
4340  *
4341  * Returns the difference between the two node sets, or nodes1 if
4342  *         nodes2 is empty
4343  */
4344 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4345 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4346     xmlNodeSetPtr ret;
4347     int i, l1;
4348     xmlNodePtr cur;
4349 
4350     if (xmlXPathNodeSetIsEmpty(nodes2))
4351 	return(nodes1);
4352 
4353     ret = xmlXPathNodeSetCreate(NULL);
4354     if (xmlXPathNodeSetIsEmpty(nodes1))
4355 	return(ret);
4356 
4357     l1 = xmlXPathNodeSetGetLength(nodes1);
4358 
4359     for (i = 0; i < l1; i++) {
4360 	cur = xmlXPathNodeSetItem(nodes1, i);
4361 	if (!xmlXPathNodeSetContains(nodes2, cur))
4362 	    xmlXPathNodeSetAddUnique(ret, cur);
4363     }
4364     return(ret);
4365 }
4366 
4367 /**
4368  * xmlXPathIntersection:
4369  * @nodes1:  a node-set
4370  * @nodes2:  a node-set
4371  *
4372  * Implements the EXSLT - Sets intersection() function:
4373  *    node-set set:intersection (node-set, node-set)
4374  *
4375  * Returns a node set comprising the nodes that are within both the
4376  *         node sets passed as arguments
4377  */
4378 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4379 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4380     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4381     int i, l1;
4382     xmlNodePtr cur;
4383 
4384     if (xmlXPathNodeSetIsEmpty(nodes1))
4385 	return(ret);
4386     if (xmlXPathNodeSetIsEmpty(nodes2))
4387 	return(ret);
4388 
4389     l1 = xmlXPathNodeSetGetLength(nodes1);
4390 
4391     for (i = 0; i < l1; i++) {
4392 	cur = xmlXPathNodeSetItem(nodes1, i);
4393 	if (xmlXPathNodeSetContains(nodes2, cur))
4394 	    xmlXPathNodeSetAddUnique(ret, cur);
4395     }
4396     return(ret);
4397 }
4398 
4399 /**
4400  * xmlXPathDistinctSorted:
4401  * @nodes:  a node-set, sorted by document order
4402  *
4403  * Implements the EXSLT - Sets distinct() function:
4404  *    node-set set:distinct (node-set)
4405  *
4406  * Returns a subset of the nodes contained in @nodes, or @nodes if
4407  *         it is empty
4408  */
4409 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4410 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4411     xmlNodeSetPtr ret;
4412     xmlHashTablePtr hash;
4413     int i, l;
4414     xmlChar * strval;
4415     xmlNodePtr cur;
4416 
4417     if (xmlXPathNodeSetIsEmpty(nodes))
4418 	return(nodes);
4419 
4420     ret = xmlXPathNodeSetCreate(NULL);
4421     l = xmlXPathNodeSetGetLength(nodes);
4422     hash = xmlHashCreate (l);
4423     for (i = 0; i < l; i++) {
4424 	cur = xmlXPathNodeSetItem(nodes, i);
4425 	strval = xmlXPathCastNodeToString(cur);
4426 	if (xmlHashLookup(hash, strval) == NULL) {
4427 	    xmlHashAddEntry(hash, strval, strval);
4428 	    xmlXPathNodeSetAddUnique(ret, cur);
4429 	} else {
4430 	    xmlFree(strval);
4431 	}
4432     }
4433     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4434     return(ret);
4435 }
4436 
4437 /**
4438  * xmlXPathDistinct:
4439  * @nodes:  a node-set
4440  *
4441  * Implements the EXSLT - Sets distinct() function:
4442  *    node-set set:distinct (node-set)
4443  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4444  * is called with the sorted node-set
4445  *
4446  * Returns a subset of the nodes contained in @nodes, or @nodes if
4447  *         it is empty
4448  */
4449 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4450 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4451     if (xmlXPathNodeSetIsEmpty(nodes))
4452 	return(nodes);
4453 
4454     xmlXPathNodeSetSort(nodes);
4455     return(xmlXPathDistinctSorted(nodes));
4456 }
4457 
4458 /**
4459  * xmlXPathHasSameNodes:
4460  * @nodes1:  a node-set
4461  * @nodes2:  a node-set
4462  *
4463  * Implements the EXSLT - Sets has-same-nodes function:
4464  *    boolean set:has-same-node(node-set, node-set)
4465  *
4466  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4467  *         otherwise
4468  */
4469 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4470 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4471     int i, l;
4472     xmlNodePtr cur;
4473 
4474     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4475 	xmlXPathNodeSetIsEmpty(nodes2))
4476 	return(0);
4477 
4478     l = xmlXPathNodeSetGetLength(nodes1);
4479     for (i = 0; i < l; i++) {
4480 	cur = xmlXPathNodeSetItem(nodes1, i);
4481 	if (xmlXPathNodeSetContains(nodes2, cur))
4482 	    return(1);
4483     }
4484     return(0);
4485 }
4486 
4487 /**
4488  * xmlXPathNodeLeadingSorted:
4489  * @nodes: a node-set, sorted by document order
4490  * @node: a node
4491  *
4492  * Implements the EXSLT - Sets leading() function:
4493  *    node-set set:leading (node-set, node-set)
4494  *
4495  * Returns the nodes in @nodes that precede @node in document order,
4496  *         @nodes if @node is NULL or an empty node-set if @nodes
4497  *         doesn't contain @node
4498  */
4499 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4500 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4501     int i, l;
4502     xmlNodePtr cur;
4503     xmlNodeSetPtr ret;
4504 
4505     if (node == NULL)
4506 	return(nodes);
4507 
4508     ret = xmlXPathNodeSetCreate(NULL);
4509     if (xmlXPathNodeSetIsEmpty(nodes) ||
4510 	(!xmlXPathNodeSetContains(nodes, node)))
4511 	return(ret);
4512 
4513     l = xmlXPathNodeSetGetLength(nodes);
4514     for (i = 0; i < l; i++) {
4515 	cur = xmlXPathNodeSetItem(nodes, i);
4516 	if (cur == node)
4517 	    break;
4518 	xmlXPathNodeSetAddUnique(ret, cur);
4519     }
4520     return(ret);
4521 }
4522 
4523 /**
4524  * xmlXPathNodeLeading:
4525  * @nodes:  a node-set
4526  * @node:  a node
4527  *
4528  * Implements the EXSLT - Sets leading() function:
4529  *    node-set set:leading (node-set, node-set)
4530  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4531  * is called.
4532  *
4533  * Returns the nodes in @nodes that precede @node in document order,
4534  *         @nodes if @node is NULL or an empty node-set if @nodes
4535  *         doesn't contain @node
4536  */
4537 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4538 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4539     xmlXPathNodeSetSort(nodes);
4540     return(xmlXPathNodeLeadingSorted(nodes, node));
4541 }
4542 
4543 /**
4544  * xmlXPathLeadingSorted:
4545  * @nodes1:  a node-set, sorted by document order
4546  * @nodes2:  a node-set, sorted by document order
4547  *
4548  * Implements the EXSLT - Sets leading() function:
4549  *    node-set set:leading (node-set, node-set)
4550  *
4551  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4552  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4553  *         an empty node-set if @nodes1 doesn't contain @nodes2
4554  */
4555 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4556 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4557     if (xmlXPathNodeSetIsEmpty(nodes2))
4558 	return(nodes1);
4559     return(xmlXPathNodeLeadingSorted(nodes1,
4560 				     xmlXPathNodeSetItem(nodes2, 1)));
4561 }
4562 
4563 /**
4564  * xmlXPathLeading:
4565  * @nodes1:  a node-set
4566  * @nodes2:  a node-set
4567  *
4568  * Implements the EXSLT - Sets leading() function:
4569  *    node-set set:leading (node-set, node-set)
4570  * @nodes1 and @nodes2 are sorted by document order, then
4571  * #exslSetsLeadingSorted is called.
4572  *
4573  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4574  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4575  *         an empty node-set if @nodes1 doesn't contain @nodes2
4576  */
4577 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4578 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4579     if (xmlXPathNodeSetIsEmpty(nodes2))
4580 	return(nodes1);
4581     if (xmlXPathNodeSetIsEmpty(nodes1))
4582 	return(xmlXPathNodeSetCreate(NULL));
4583     xmlXPathNodeSetSort(nodes1);
4584     xmlXPathNodeSetSort(nodes2);
4585     return(xmlXPathNodeLeadingSorted(nodes1,
4586 				     xmlXPathNodeSetItem(nodes2, 1)));
4587 }
4588 
4589 /**
4590  * xmlXPathNodeTrailingSorted:
4591  * @nodes: a node-set, sorted by document order
4592  * @node: a node
4593  *
4594  * Implements the EXSLT - Sets trailing() function:
4595  *    node-set set:trailing (node-set, node-set)
4596  *
4597  * Returns the nodes in @nodes that follow @node in document order,
4598  *         @nodes if @node is NULL or an empty node-set if @nodes
4599  *         doesn't contain @node
4600  */
4601 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4602 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4603     int i, l;
4604     xmlNodePtr cur;
4605     xmlNodeSetPtr ret;
4606 
4607     if (node == NULL)
4608 	return(nodes);
4609 
4610     ret = xmlXPathNodeSetCreate(NULL);
4611     if (xmlXPathNodeSetIsEmpty(nodes) ||
4612 	(!xmlXPathNodeSetContains(nodes, node)))
4613 	return(ret);
4614 
4615     l = xmlXPathNodeSetGetLength(nodes);
4616     for (i = l - 1; i >= 0; i--) {
4617 	cur = xmlXPathNodeSetItem(nodes, i);
4618 	if (cur == node)
4619 	    break;
4620 	xmlXPathNodeSetAddUnique(ret, cur);
4621     }
4622     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4623     return(ret);
4624 }
4625 
4626 /**
4627  * xmlXPathNodeTrailing:
4628  * @nodes:  a node-set
4629  * @node:  a node
4630  *
4631  * Implements the EXSLT - Sets trailing() function:
4632  *    node-set set:trailing (node-set, node-set)
4633  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4634  * is called.
4635  *
4636  * Returns the nodes in @nodes that follow @node in document order,
4637  *         @nodes if @node is NULL or an empty node-set if @nodes
4638  *         doesn't contain @node
4639  */
4640 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4641 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4642     xmlXPathNodeSetSort(nodes);
4643     return(xmlXPathNodeTrailingSorted(nodes, node));
4644 }
4645 
4646 /**
4647  * xmlXPathTrailingSorted:
4648  * @nodes1:  a node-set, sorted by document order
4649  * @nodes2:  a node-set, sorted by document order
4650  *
4651  * Implements the EXSLT - Sets trailing() function:
4652  *    node-set set:trailing (node-set, node-set)
4653  *
4654  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4655  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4656  *         an empty node-set if @nodes1 doesn't contain @nodes2
4657  */
4658 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4659 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4660     if (xmlXPathNodeSetIsEmpty(nodes2))
4661 	return(nodes1);
4662     return(xmlXPathNodeTrailingSorted(nodes1,
4663 				      xmlXPathNodeSetItem(nodes2, 0)));
4664 }
4665 
4666 /**
4667  * xmlXPathTrailing:
4668  * @nodes1:  a node-set
4669  * @nodes2:  a node-set
4670  *
4671  * Implements the EXSLT - Sets trailing() function:
4672  *    node-set set:trailing (node-set, node-set)
4673  * @nodes1 and @nodes2 are sorted by document order, then
4674  * #xmlXPathTrailingSorted is called.
4675  *
4676  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4677  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4678  *         an empty node-set if @nodes1 doesn't contain @nodes2
4679  */
4680 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4681 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4682     if (xmlXPathNodeSetIsEmpty(nodes2))
4683 	return(nodes1);
4684     if (xmlXPathNodeSetIsEmpty(nodes1))
4685 	return(xmlXPathNodeSetCreate(NULL));
4686     xmlXPathNodeSetSort(nodes1);
4687     xmlXPathNodeSetSort(nodes2);
4688     return(xmlXPathNodeTrailingSorted(nodes1,
4689 				      xmlXPathNodeSetItem(nodes2, 0)));
4690 }
4691 
4692 /************************************************************************
4693  *									*
4694  *		Routines to handle extra functions			*
4695  *									*
4696  ************************************************************************/
4697 
4698 /**
4699  * xmlXPathRegisterFunc:
4700  * @ctxt:  the XPath context
4701  * @name:  the function name
4702  * @f:  the function implementation or NULL
4703  *
4704  * Register a new function. If @f is NULL it unregisters the function
4705  *
4706  * Returns 0 in case of success, -1 in case of error
4707  */
4708 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4709 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4710 		     xmlXPathFunction f) {
4711     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4712 }
4713 
4714 /**
4715  * xmlXPathRegisterFuncNS:
4716  * @ctxt:  the XPath context
4717  * @name:  the function name
4718  * @ns_uri:  the function namespace URI
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
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4726 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4728     if (ctxt == NULL)
4729 	return(-1);
4730     if (name == NULL)
4731 	return(-1);
4732 
4733     if (ctxt->funcHash == NULL)
4734 	ctxt->funcHash = xmlHashCreate(0);
4735     if (ctxt->funcHash == NULL)
4736 	return(-1);
4737     if (f == NULL)
4738         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4739     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4740 }
4741 
4742 /**
4743  * xmlXPathRegisterFuncLookup:
4744  * @ctxt:  the XPath context
4745  * @f:  the lookup function
4746  * @funcCtxt:  the lookup data
4747  *
4748  * Registers an external mechanism to do function lookup.
4749  */
4750 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4751 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4752 			    xmlXPathFuncLookupFunc f,
4753 			    void *funcCtxt) {
4754     if (ctxt == NULL)
4755 	return;
4756     ctxt->funcLookupFunc = f;
4757     ctxt->funcLookupData = funcCtxt;
4758 }
4759 
4760 /**
4761  * xmlXPathFunctionLookup:
4762  * @ctxt:  the XPath context
4763  * @name:  the function name
4764  *
4765  * Search in the Function array of the context for the given
4766  * function.
4767  *
4768  * Returns the xmlXPathFunction or NULL if not found
4769  */
4770 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4771 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4772     if (ctxt == NULL)
4773 	return (NULL);
4774 
4775     if (ctxt->funcLookupFunc != NULL) {
4776 	xmlXPathFunction ret;
4777 	xmlXPathFuncLookupFunc f;
4778 
4779 	f = ctxt->funcLookupFunc;
4780 	ret = f(ctxt->funcLookupData, name, NULL);
4781 	if (ret != NULL)
4782 	    return(ret);
4783     }
4784     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4785 }
4786 
4787 /**
4788  * xmlXPathFunctionLookupNS:
4789  * @ctxt:  the XPath context
4790  * @name:  the function name
4791  * @ns_uri:  the function namespace URI
4792  *
4793  * Search in the Function array of the context for the given
4794  * function.
4795  *
4796  * Returns the xmlXPathFunction or NULL if not found
4797  */
4798 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4799 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4800 			 const xmlChar *ns_uri) {
4801     xmlXPathFunction ret;
4802 
4803     if (ctxt == NULL)
4804 	return(NULL);
4805     if (name == NULL)
4806 	return(NULL);
4807 
4808     if (ctxt->funcLookupFunc != NULL) {
4809 	xmlXPathFuncLookupFunc f;
4810 
4811 	f = ctxt->funcLookupFunc;
4812 	ret = f(ctxt->funcLookupData, name, ns_uri);
4813 	if (ret != NULL)
4814 	    return(ret);
4815     }
4816 
4817     if (ctxt->funcHash == NULL)
4818 	return(NULL);
4819 
4820     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4821     return(ret);
4822 }
4823 
4824 /**
4825  * xmlXPathRegisteredFuncsCleanup:
4826  * @ctxt:  the XPath context
4827  *
4828  * Cleanup the XPath context data associated to registered functions
4829  */
4830 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4831 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4832     if (ctxt == NULL)
4833 	return;
4834 
4835     xmlHashFree(ctxt->funcHash, NULL);
4836     ctxt->funcHash = NULL;
4837 }
4838 
4839 /************************************************************************
4840  *									*
4841  *			Routines to handle Variables			*
4842  *									*
4843  ************************************************************************/
4844 
4845 /**
4846  * xmlXPathRegisterVariable:
4847  * @ctxt:  the XPath context
4848  * @name:  the variable name
4849  * @value:  the variable value or NULL
4850  *
4851  * Register a new variable value. If @value is NULL it unregisters
4852  * the variable
4853  *
4854  * Returns 0 in case of success, -1 in case of error
4855  */
4856 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4857 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4858 			 xmlXPathObjectPtr value) {
4859     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4860 }
4861 
4862 /**
4863  * xmlXPathRegisterVariableNS:
4864  * @ctxt:  the XPath context
4865  * @name:  the variable name
4866  * @ns_uri:  the variable namespace URI
4867  * @value:  the variable value or NULL
4868  *
4869  * Register a new variable value. If @value is NULL it unregisters
4870  * the variable
4871  *
4872  * Returns 0 in case of success, -1 in case of error
4873  */
4874 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4875 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4876 			   const xmlChar *ns_uri,
4877 			   xmlXPathObjectPtr value) {
4878     if (ctxt == NULL)
4879 	return(-1);
4880     if (name == NULL)
4881 	return(-1);
4882 
4883     if (ctxt->varHash == NULL)
4884 	ctxt->varHash = xmlHashCreate(0);
4885     if (ctxt->varHash == NULL)
4886 	return(-1);
4887     if (value == NULL)
4888         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4889 	                           (xmlHashDeallocator)xmlXPathFreeObject));
4890     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4891 			       (void *) value,
4892 			       (xmlHashDeallocator)xmlXPathFreeObject));
4893 }
4894 
4895 /**
4896  * xmlXPathRegisterVariableLookup:
4897  * @ctxt:  the XPath context
4898  * @f:  the lookup function
4899  * @data:  the lookup data
4900  *
4901  * register an external mechanism to do variable lookup
4902  */
4903 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4904 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4905 	 xmlXPathVariableLookupFunc f, void *data) {
4906     if (ctxt == NULL)
4907 	return;
4908     ctxt->varLookupFunc = f;
4909     ctxt->varLookupData = data;
4910 }
4911 
4912 /**
4913  * xmlXPathVariableLookup:
4914  * @ctxt:  the XPath context
4915  * @name:  the variable name
4916  *
4917  * Search in the Variable array of the context for the given
4918  * variable value.
4919  *
4920  * Returns a copy of the value or NULL if not found
4921  */
4922 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4923 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4924     if (ctxt == NULL)
4925 	return(NULL);
4926 
4927     if (ctxt->varLookupFunc != NULL) {
4928 	xmlXPathObjectPtr ret;
4929 
4930 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4931 	        (ctxt->varLookupData, name, NULL);
4932 	return(ret);
4933     }
4934     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4935 }
4936 
4937 /**
4938  * xmlXPathVariableLookupNS:
4939  * @ctxt:  the XPath context
4940  * @name:  the variable name
4941  * @ns_uri:  the variable namespace URI
4942  *
4943  * Search in the Variable array of the context for the given
4944  * variable value.
4945  *
4946  * Returns the a copy of the value or NULL if not found
4947  */
4948 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4949 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4950 			 const xmlChar *ns_uri) {
4951     if (ctxt == NULL)
4952 	return(NULL);
4953 
4954     if (ctxt->varLookupFunc != NULL) {
4955 	xmlXPathObjectPtr ret;
4956 
4957 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4958 	        (ctxt->varLookupData, name, ns_uri);
4959 	if (ret != NULL) return(ret);
4960     }
4961 
4962     if (ctxt->varHash == NULL)
4963 	return(NULL);
4964     if (name == NULL)
4965 	return(NULL);
4966 
4967     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4968 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4969 }
4970 
4971 /**
4972  * xmlXPathRegisteredVariablesCleanup:
4973  * @ctxt:  the XPath context
4974  *
4975  * Cleanup the XPath context data associated to registered variables
4976  */
4977 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4978 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4979     if (ctxt == NULL)
4980 	return;
4981 
4982     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4983     ctxt->varHash = NULL;
4984 }
4985 
4986 /**
4987  * xmlXPathRegisterNs:
4988  * @ctxt:  the XPath context
4989  * @prefix:  the namespace prefix
4990  * @ns_uri:  the namespace name
4991  *
4992  * Register a new namespace. If @ns_uri is NULL it unregisters
4993  * the namespace
4994  *
4995  * Returns 0 in case of success, -1 in case of error
4996  */
4997 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4998 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4999 			   const xmlChar *ns_uri) {
5000     if (ctxt == NULL)
5001 	return(-1);
5002     if (prefix == NULL)
5003 	return(-1);
5004 
5005     if (ctxt->nsHash == NULL)
5006 	ctxt->nsHash = xmlHashCreate(10);
5007     if (ctxt->nsHash == NULL)
5008 	return(-1);
5009     if (ns_uri == NULL)
5010         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5011 	                          (xmlHashDeallocator)xmlFree));
5012     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5013 			      (xmlHashDeallocator)xmlFree));
5014 }
5015 
5016 /**
5017  * xmlXPathNsLookup:
5018  * @ctxt:  the XPath context
5019  * @prefix:  the namespace prefix value
5020  *
5021  * Search in the namespace declaration array of the context for the given
5022  * namespace name associated to the given prefix
5023  *
5024  * Returns the value or NULL if not found
5025  */
5026 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5027 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5028     if (ctxt == NULL)
5029 	return(NULL);
5030     if (prefix == NULL)
5031 	return(NULL);
5032 
5033 #ifdef XML_XML_NAMESPACE
5034     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5035 	return(XML_XML_NAMESPACE);
5036 #endif
5037 
5038     if (ctxt->namespaces != NULL) {
5039 	int i;
5040 
5041 	for (i = 0;i < ctxt->nsNr;i++) {
5042 	    if ((ctxt->namespaces[i] != NULL) &&
5043 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5044 		return(ctxt->namespaces[i]->href);
5045 	}
5046     }
5047 
5048     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5049 }
5050 
5051 /**
5052  * xmlXPathRegisteredNsCleanup:
5053  * @ctxt:  the XPath context
5054  *
5055  * Cleanup the XPath context data associated to registered variables
5056  */
5057 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5058 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5059     if (ctxt == NULL)
5060 	return;
5061 
5062     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5063     ctxt->nsHash = NULL;
5064 }
5065 
5066 /************************************************************************
5067  *									*
5068  *			Routines to handle Values			*
5069  *									*
5070  ************************************************************************/
5071 
5072 /* Allocations are terrible, one needs to optimize all this !!! */
5073 
5074 /**
5075  * xmlXPathNewFloat:
5076  * @val:  the double value
5077  *
5078  * Create a new xmlXPathObjectPtr of type double and of value @val
5079  *
5080  * Returns the newly created object.
5081  */
5082 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5083 xmlXPathNewFloat(double val) {
5084     xmlXPathObjectPtr ret;
5085 
5086     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5087     if (ret == NULL) {
5088         xmlXPathErrMemory(NULL, "creating float object\n");
5089 	return(NULL);
5090     }
5091     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5092     ret->type = XPATH_NUMBER;
5093     ret->floatval = val;
5094 #ifdef XP_DEBUG_OBJ_USAGE
5095     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5096 #endif
5097     return(ret);
5098 }
5099 
5100 /**
5101  * xmlXPathNewBoolean:
5102  * @val:  the boolean value
5103  *
5104  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5105  *
5106  * Returns the newly created object.
5107  */
5108 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5109 xmlXPathNewBoolean(int val) {
5110     xmlXPathObjectPtr ret;
5111 
5112     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5113     if (ret == NULL) {
5114         xmlXPathErrMemory(NULL, "creating boolean object\n");
5115 	return(NULL);
5116     }
5117     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5118     ret->type = XPATH_BOOLEAN;
5119     ret->boolval = (val != 0);
5120 #ifdef XP_DEBUG_OBJ_USAGE
5121     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5122 #endif
5123     return(ret);
5124 }
5125 
5126 /**
5127  * xmlXPathNewString:
5128  * @val:  the xmlChar * value
5129  *
5130  * Create a new xmlXPathObjectPtr of type string and of value @val
5131  *
5132  * Returns the newly created object.
5133  */
5134 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5135 xmlXPathNewString(const xmlChar *val) {
5136     xmlXPathObjectPtr ret;
5137 
5138     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5139     if (ret == NULL) {
5140         xmlXPathErrMemory(NULL, "creating string object\n");
5141 	return(NULL);
5142     }
5143     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5144     ret->type = XPATH_STRING;
5145     if (val != NULL)
5146 	ret->stringval = xmlStrdup(val);
5147     else
5148 	ret->stringval = xmlStrdup((const xmlChar *)"");
5149 #ifdef XP_DEBUG_OBJ_USAGE
5150     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5151 #endif
5152     return(ret);
5153 }
5154 
5155 /**
5156  * xmlXPathWrapString:
5157  * @val:  the xmlChar * value
5158  *
5159  * Wraps the @val string into an XPath object.
5160  *
5161  * Returns the newly created object.
5162  */
5163 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5164 xmlXPathWrapString (xmlChar *val) {
5165     xmlXPathObjectPtr ret;
5166 
5167     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5168     if (ret == NULL) {
5169         xmlXPathErrMemory(NULL, "creating string object\n");
5170 	return(NULL);
5171     }
5172     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5173     ret->type = XPATH_STRING;
5174     ret->stringval = val;
5175 #ifdef XP_DEBUG_OBJ_USAGE
5176     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5177 #endif
5178     return(ret);
5179 }
5180 
5181 /**
5182  * xmlXPathNewCString:
5183  * @val:  the char * value
5184  *
5185  * Create a new xmlXPathObjectPtr of type string and of value @val
5186  *
5187  * Returns the newly created object.
5188  */
5189 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5190 xmlXPathNewCString(const char *val) {
5191     xmlXPathObjectPtr ret;
5192 
5193     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5194     if (ret == NULL) {
5195         xmlXPathErrMemory(NULL, "creating string object\n");
5196 	return(NULL);
5197     }
5198     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5199     ret->type = XPATH_STRING;
5200     ret->stringval = xmlStrdup(BAD_CAST val);
5201 #ifdef XP_DEBUG_OBJ_USAGE
5202     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5203 #endif
5204     return(ret);
5205 }
5206 
5207 /**
5208  * xmlXPathWrapCString:
5209  * @val:  the char * value
5210  *
5211  * Wraps a string into an XPath object.
5212  *
5213  * Returns the newly created object.
5214  */
5215 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5216 xmlXPathWrapCString (char * val) {
5217     return(xmlXPathWrapString((xmlChar *)(val)));
5218 }
5219 
5220 /**
5221  * xmlXPathWrapExternal:
5222  * @val:  the user data
5223  *
5224  * Wraps the @val data into an XPath object.
5225  *
5226  * Returns the newly created object.
5227  */
5228 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5229 xmlXPathWrapExternal (void *val) {
5230     xmlXPathObjectPtr ret;
5231 
5232     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5233     if (ret == NULL) {
5234         xmlXPathErrMemory(NULL, "creating user object\n");
5235 	return(NULL);
5236     }
5237     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5238     ret->type = XPATH_USERS;
5239     ret->user = val;
5240 #ifdef XP_DEBUG_OBJ_USAGE
5241     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5242 #endif
5243     return(ret);
5244 }
5245 
5246 /**
5247  * xmlXPathObjectCopy:
5248  * @val:  the original object
5249  *
5250  * allocate a new copy of a given object
5251  *
5252  * Returns the newly created object.
5253  */
5254 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5255 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5256     xmlXPathObjectPtr ret;
5257 
5258     if (val == NULL)
5259 	return(NULL);
5260 
5261     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262     if (ret == NULL) {
5263         xmlXPathErrMemory(NULL, "copying object\n");
5264 	return(NULL);
5265     }
5266     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5267 #ifdef XP_DEBUG_OBJ_USAGE
5268     xmlXPathDebugObjUsageRequested(NULL, val->type);
5269 #endif
5270     switch (val->type) {
5271 	case XPATH_BOOLEAN:
5272 	case XPATH_NUMBER:
5273 	case XPATH_POINT:
5274 	case XPATH_RANGE:
5275 	    break;
5276 	case XPATH_STRING:
5277 	    ret->stringval = xmlStrdup(val->stringval);
5278 	    break;
5279 	case XPATH_XSLT_TREE:
5280 #if 0
5281 /*
5282   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5283   this previous handling is no longer correct, and can cause some serious
5284   problems (ref. bug 145547)
5285 */
5286 	    if ((val->nodesetval != NULL) &&
5287 		(val->nodesetval->nodeTab != NULL)) {
5288 		xmlNodePtr cur, tmp;
5289 		xmlDocPtr top;
5290 
5291 		ret->boolval = 1;
5292 		top =  xmlNewDoc(NULL);
5293 		top->name = (char *)
5294 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5295 		ret->user = top;
5296 		if (top != NULL) {
5297 		    top->doc = top;
5298 		    cur = val->nodesetval->nodeTab[0]->children;
5299 		    while (cur != NULL) {
5300 			tmp = xmlDocCopyNode(cur, top, 1);
5301 			xmlAddChild((xmlNodePtr) top, tmp);
5302 			cur = cur->next;
5303 		    }
5304 		}
5305 
5306 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5307 	    } else
5308 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5309 	    /* Deallocate the copied tree value */
5310 	    break;
5311 #endif
5312 	case XPATH_NODESET:
5313 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5314 	    /* Do not deallocate the copied tree value */
5315 	    ret->boolval = 0;
5316 	    break;
5317 	case XPATH_LOCATIONSET:
5318 #ifdef LIBXML_XPTR_ENABLED
5319 	{
5320 	    xmlLocationSetPtr loc = val->user;
5321 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5322 	    break;
5323 	}
5324 #endif
5325         case XPATH_USERS:
5326 	    ret->user = val->user;
5327 	    break;
5328         case XPATH_UNDEFINED:
5329 	    xmlGenericError(xmlGenericErrorContext,
5330 		    "xmlXPathObjectCopy: unsupported type %d\n",
5331 		    val->type);
5332 	    break;
5333     }
5334     return(ret);
5335 }
5336 
5337 /**
5338  * xmlXPathFreeObject:
5339  * @obj:  the object to free
5340  *
5341  * Free up an xmlXPathObjectPtr object.
5342  */
5343 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5344 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5345     if (obj == NULL) return;
5346     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5347 	if (obj->boolval) {
5348 #if 0
5349 	    if (obj->user != NULL) {
5350                 xmlXPathFreeNodeSet(obj->nodesetval);
5351 		xmlFreeNodeList((xmlNodePtr) obj->user);
5352 	    } else
5353 #endif
5354 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5355 	    if (obj->nodesetval != NULL)
5356 		xmlXPathFreeValueTree(obj->nodesetval);
5357 	} else {
5358 	    if (obj->nodesetval != NULL)
5359 		xmlXPathFreeNodeSet(obj->nodesetval);
5360 	}
5361 #ifdef LIBXML_XPTR_ENABLED
5362     } else if (obj->type == XPATH_LOCATIONSET) {
5363 	if (obj->user != NULL)
5364 	    xmlXPtrFreeLocationSet(obj->user);
5365 #endif
5366     } else if (obj->type == XPATH_STRING) {
5367 	if (obj->stringval != NULL)
5368 	    xmlFree(obj->stringval);
5369     }
5370 #ifdef XP_DEBUG_OBJ_USAGE
5371     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5372 #endif
5373     xmlFree(obj);
5374 }
5375 
5376 /**
5377  * xmlXPathReleaseObject:
5378  * @obj:  the xmlXPathObjectPtr to free or to cache
5379  *
5380  * Depending on the state of the cache this frees the given
5381  * XPath object or stores it in the cache.
5382  */
5383 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5384 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5385 {
5386 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5387 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5388     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5389 
5390 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5391 
5392     if (obj == NULL)
5393 	return;
5394     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5395 	 xmlXPathFreeObject(obj);
5396     } else {
5397 	xmlXPathContextCachePtr cache =
5398 	    (xmlXPathContextCachePtr) ctxt->cache;
5399 
5400 	switch (obj->type) {
5401 	    case XPATH_NODESET:
5402 	    case XPATH_XSLT_TREE:
5403 		if (obj->nodesetval != NULL) {
5404 		    if (obj->boolval) {
5405 		    	/*
5406 			* It looks like the @boolval is used for
5407 			* evaluation if this an XSLT Result Tree Fragment.
5408 			* TODO: Check if this assumption is correct.
5409 			*/
5410 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5411 			xmlXPathFreeValueTree(obj->nodesetval);
5412 			obj->nodesetval = NULL;
5413 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5414 			(XP_CACHE_WANTS(cache->nodesetObjs,
5415 					cache->maxNodeset)))
5416 		    {
5417 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5418 			goto obj_cached;
5419 		    } else {
5420 			xmlXPathFreeNodeSet(obj->nodesetval);
5421 			obj->nodesetval = NULL;
5422 		    }
5423 		}
5424 		break;
5425 	    case XPATH_STRING:
5426 		if (obj->stringval != NULL)
5427 		    xmlFree(obj->stringval);
5428 
5429 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5430 		    XP_CACHE_ADD(cache->stringObjs, obj);
5431 		    goto obj_cached;
5432 		}
5433 		break;
5434 	    case XPATH_BOOLEAN:
5435 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5436 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5437 		    goto obj_cached;
5438 		}
5439 		break;
5440 	    case XPATH_NUMBER:
5441 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5442 		    XP_CACHE_ADD(cache->numberObjs, obj);
5443 		    goto obj_cached;
5444 		}
5445 		break;
5446 #ifdef LIBXML_XPTR_ENABLED
5447 	    case XPATH_LOCATIONSET:
5448 		if (obj->user != NULL) {
5449 		    xmlXPtrFreeLocationSet(obj->user);
5450 		}
5451 		goto free_obj;
5452 #endif
5453 	    default:
5454 		goto free_obj;
5455 	}
5456 
5457 	/*
5458 	* Fallback to adding to the misc-objects slot.
5459 	*/
5460 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5461 	    XP_CACHE_ADD(cache->miscObjs, obj);
5462 	} else
5463 	    goto free_obj;
5464 
5465 obj_cached:
5466 
5467 #ifdef XP_DEBUG_OBJ_USAGE
5468 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5469 #endif
5470 
5471 	if (obj->nodesetval != NULL) {
5472 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5473 
5474 	    /*
5475 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5476 	    *  the list and free the ns-nodes.
5477 	    * URGENT TODO: Check if it's actually slowing things down.
5478 	    *  Maybe we shouldn't try to preserve the list.
5479 	    */
5480 	    if (tmpset->nodeNr > 1) {
5481 		int i;
5482 		xmlNodePtr node;
5483 
5484 		for (i = 0; i < tmpset->nodeNr; i++) {
5485 		    node = tmpset->nodeTab[i];
5486 		    if ((node != NULL) &&
5487 			(node->type == XML_NAMESPACE_DECL))
5488 		    {
5489 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5490 		    }
5491 		}
5492 	    } else if (tmpset->nodeNr == 1) {
5493 		if ((tmpset->nodeTab[0] != NULL) &&
5494 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5495 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5496 	    }
5497 	    tmpset->nodeNr = 0;
5498 	    memset(obj, 0, sizeof(xmlXPathObject));
5499 	    obj->nodesetval = tmpset;
5500 	} else
5501 	    memset(obj, 0, sizeof(xmlXPathObject));
5502 
5503 	return;
5504 
5505 free_obj:
5506 	/*
5507 	* Cache is full; free the object.
5508 	*/
5509 	if (obj->nodesetval != NULL)
5510 	    xmlXPathFreeNodeSet(obj->nodesetval);
5511 #ifdef XP_DEBUG_OBJ_USAGE
5512 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5513 #endif
5514 	xmlFree(obj);
5515     }
5516     return;
5517 }
5518 
5519 
5520 /************************************************************************
5521  *									*
5522  *			Type Casting Routines				*
5523  *									*
5524  ************************************************************************/
5525 
5526 /**
5527  * xmlXPathCastBooleanToString:
5528  * @val:  a boolean
5529  *
5530  * Converts a boolean to its string value.
5531  *
5532  * Returns a newly allocated string.
5533  */
5534 xmlChar *
xmlXPathCastBooleanToString(int val)5535 xmlXPathCastBooleanToString (int val) {
5536     xmlChar *ret;
5537     if (val)
5538 	ret = xmlStrdup((const xmlChar *) "true");
5539     else
5540 	ret = xmlStrdup((const xmlChar *) "false");
5541     return(ret);
5542 }
5543 
5544 /**
5545  * xmlXPathCastNumberToString:
5546  * @val:  a number
5547  *
5548  * Converts a number to its string value.
5549  *
5550  * Returns a newly allocated string.
5551  */
5552 xmlChar *
xmlXPathCastNumberToString(double val)5553 xmlXPathCastNumberToString (double val) {
5554     xmlChar *ret;
5555     switch (xmlXPathIsInf(val)) {
5556     case 1:
5557 	ret = xmlStrdup((const xmlChar *) "Infinity");
5558 	break;
5559     case -1:
5560 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5561 	break;
5562     default:
5563 	if (xmlXPathIsNaN(val)) {
5564 	    ret = xmlStrdup((const xmlChar *) "NaN");
5565 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5566 	    ret = xmlStrdup((const xmlChar *) "0");
5567 	} else {
5568 	    /* could be improved */
5569 	    char buf[100];
5570 	    xmlXPathFormatNumber(val, buf, 99);
5571 	    buf[99] = 0;
5572 	    ret = xmlStrdup((const xmlChar *) buf);
5573 	}
5574     }
5575     return(ret);
5576 }
5577 
5578 /**
5579  * xmlXPathCastNodeToString:
5580  * @node:  a node
5581  *
5582  * Converts a node to its string value.
5583  *
5584  * Returns a newly allocated string.
5585  */
5586 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5587 xmlXPathCastNodeToString (xmlNodePtr node) {
5588 xmlChar *ret;
5589     if ((ret = xmlNodeGetContent(node)) == NULL)
5590 	ret = xmlStrdup((const xmlChar *) "");
5591     return(ret);
5592 }
5593 
5594 /**
5595  * xmlXPathCastNodeSetToString:
5596  * @ns:  a node-set
5597  *
5598  * Converts a node-set to its string value.
5599  *
5600  * Returns a newly allocated string.
5601  */
5602 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5603 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5604     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5605 	return(xmlStrdup((const xmlChar *) ""));
5606 
5607     if (ns->nodeNr > 1)
5608 	xmlXPathNodeSetSort(ns);
5609     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5610 }
5611 
5612 /**
5613  * xmlXPathCastToString:
5614  * @val:  an XPath object
5615  *
5616  * Converts an existing object to its string() equivalent
5617  *
5618  * Returns the allocated string value of the object, NULL in case of error.
5619  *         It's up to the caller to free the string memory with xmlFree().
5620  */
5621 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5622 xmlXPathCastToString(xmlXPathObjectPtr val) {
5623     xmlChar *ret = NULL;
5624 
5625     if (val == NULL)
5626 	return(xmlStrdup((const xmlChar *) ""));
5627     switch (val->type) {
5628 	case XPATH_UNDEFINED:
5629 #ifdef DEBUG_EXPR
5630 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5631 #endif
5632 	    ret = xmlStrdup((const xmlChar *) "");
5633 	    break;
5634         case XPATH_NODESET:
5635         case XPATH_XSLT_TREE:
5636 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5637 	    break;
5638 	case XPATH_STRING:
5639 	    return(xmlStrdup(val->stringval));
5640         case XPATH_BOOLEAN:
5641 	    ret = xmlXPathCastBooleanToString(val->boolval);
5642 	    break;
5643 	case XPATH_NUMBER: {
5644 	    ret = xmlXPathCastNumberToString(val->floatval);
5645 	    break;
5646 	}
5647 	case XPATH_USERS:
5648 	case XPATH_POINT:
5649 	case XPATH_RANGE:
5650 	case XPATH_LOCATIONSET:
5651 	    TODO
5652 	    ret = xmlStrdup((const xmlChar *) "");
5653 	    break;
5654     }
5655     return(ret);
5656 }
5657 
5658 /**
5659  * xmlXPathConvertString:
5660  * @val:  an XPath object
5661  *
5662  * Converts an existing object to its string() equivalent
5663  *
5664  * Returns the new object, the old one is freed (or the operation
5665  *         is done directly on @val)
5666  */
5667 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5668 xmlXPathConvertString(xmlXPathObjectPtr val) {
5669     xmlChar *res = NULL;
5670 
5671     if (val == NULL)
5672 	return(xmlXPathNewCString(""));
5673 
5674     switch (val->type) {
5675     case XPATH_UNDEFINED:
5676 #ifdef DEBUG_EXPR
5677 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5678 #endif
5679 	break;
5680     case XPATH_NODESET:
5681     case XPATH_XSLT_TREE:
5682 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5683 	break;
5684     case XPATH_STRING:
5685 	return(val);
5686     case XPATH_BOOLEAN:
5687 	res = xmlXPathCastBooleanToString(val->boolval);
5688 	break;
5689     case XPATH_NUMBER:
5690 	res = xmlXPathCastNumberToString(val->floatval);
5691 	break;
5692     case XPATH_USERS:
5693     case XPATH_POINT:
5694     case XPATH_RANGE:
5695     case XPATH_LOCATIONSET:
5696 	TODO;
5697 	break;
5698     }
5699     xmlXPathFreeObject(val);
5700     if (res == NULL)
5701 	return(xmlXPathNewCString(""));
5702     return(xmlXPathWrapString(res));
5703 }
5704 
5705 /**
5706  * xmlXPathCastBooleanToNumber:
5707  * @val:  a boolean
5708  *
5709  * Converts a boolean to its number value
5710  *
5711  * Returns the number value
5712  */
5713 double
xmlXPathCastBooleanToNumber(int val)5714 xmlXPathCastBooleanToNumber(int val) {
5715     if (val)
5716 	return(1.0);
5717     return(0.0);
5718 }
5719 
5720 /**
5721  * xmlXPathCastStringToNumber:
5722  * @val:  a string
5723  *
5724  * Converts a string to its number value
5725  *
5726  * Returns the number value
5727  */
5728 double
xmlXPathCastStringToNumber(const xmlChar * val)5729 xmlXPathCastStringToNumber(const xmlChar * val) {
5730     return(xmlXPathStringEvalNumber(val));
5731 }
5732 
5733 /**
5734  * xmlXPathCastNodeToNumber:
5735  * @node:  a node
5736  *
5737  * Converts a node to its number value
5738  *
5739  * Returns the number value
5740  */
5741 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5742 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5743     xmlChar *strval;
5744     double ret;
5745 
5746     if (node == NULL)
5747 	return(xmlXPathNAN);
5748     strval = xmlXPathCastNodeToString(node);
5749     if (strval == NULL)
5750 	return(xmlXPathNAN);
5751     ret = xmlXPathCastStringToNumber(strval);
5752     xmlFree(strval);
5753 
5754     return(ret);
5755 }
5756 
5757 /**
5758  * xmlXPathCastNodeSetToNumber:
5759  * @ns:  a node-set
5760  *
5761  * Converts a node-set to its number value
5762  *
5763  * Returns the number value
5764  */
5765 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5766 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5767     xmlChar *str;
5768     double ret;
5769 
5770     if (ns == NULL)
5771 	return(xmlXPathNAN);
5772     str = xmlXPathCastNodeSetToString(ns);
5773     ret = xmlXPathCastStringToNumber(str);
5774     xmlFree(str);
5775     return(ret);
5776 }
5777 
5778 /**
5779  * xmlXPathCastToNumber:
5780  * @val:  an XPath object
5781  *
5782  * Converts an XPath object to its number value
5783  *
5784  * Returns the number value
5785  */
5786 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5787 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5788     double ret = 0.0;
5789 
5790     if (val == NULL)
5791 	return(xmlXPathNAN);
5792     switch (val->type) {
5793     case XPATH_UNDEFINED:
5794 #ifdef DEGUB_EXPR
5795 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5796 #endif
5797 	ret = xmlXPathNAN;
5798 	break;
5799     case XPATH_NODESET:
5800     case XPATH_XSLT_TREE:
5801 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5802 	break;
5803     case XPATH_STRING:
5804 	ret = xmlXPathCastStringToNumber(val->stringval);
5805 	break;
5806     case XPATH_NUMBER:
5807 	ret = val->floatval;
5808 	break;
5809     case XPATH_BOOLEAN:
5810 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5811 	break;
5812     case XPATH_USERS:
5813     case XPATH_POINT:
5814     case XPATH_RANGE:
5815     case XPATH_LOCATIONSET:
5816 	TODO;
5817 	ret = xmlXPathNAN;
5818 	break;
5819     }
5820     return(ret);
5821 }
5822 
5823 /**
5824  * xmlXPathConvertNumber:
5825  * @val:  an XPath object
5826  *
5827  * Converts an existing object to its number() equivalent
5828  *
5829  * Returns the new object, the old one is freed (or the operation
5830  *         is done directly on @val)
5831  */
5832 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5833 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5834     xmlXPathObjectPtr ret;
5835 
5836     if (val == NULL)
5837 	return(xmlXPathNewFloat(0.0));
5838     if (val->type == XPATH_NUMBER)
5839 	return(val);
5840     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5841     xmlXPathFreeObject(val);
5842     return(ret);
5843 }
5844 
5845 /**
5846  * xmlXPathCastNumberToBoolean:
5847  * @val:  a number
5848  *
5849  * Converts a number to its boolean value
5850  *
5851  * Returns the boolean value
5852  */
5853 int
xmlXPathCastNumberToBoolean(double val)5854 xmlXPathCastNumberToBoolean (double val) {
5855      if (xmlXPathIsNaN(val) || (val == 0.0))
5856 	 return(0);
5857      return(1);
5858 }
5859 
5860 /**
5861  * xmlXPathCastStringToBoolean:
5862  * @val:  a string
5863  *
5864  * Converts a string to its boolean value
5865  *
5866  * Returns the boolean value
5867  */
5868 int
xmlXPathCastStringToBoolean(const xmlChar * val)5869 xmlXPathCastStringToBoolean (const xmlChar *val) {
5870     if ((val == NULL) || (xmlStrlen(val) == 0))
5871 	return(0);
5872     return(1);
5873 }
5874 
5875 /**
5876  * xmlXPathCastNodeSetToBoolean:
5877  * @ns:  a node-set
5878  *
5879  * Converts a node-set to its boolean value
5880  *
5881  * Returns the boolean value
5882  */
5883 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5884 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5885     if ((ns == NULL) || (ns->nodeNr == 0))
5886 	return(0);
5887     return(1);
5888 }
5889 
5890 /**
5891  * xmlXPathCastToBoolean:
5892  * @val:  an XPath object
5893  *
5894  * Converts an XPath object to its boolean value
5895  *
5896  * Returns the boolean value
5897  */
5898 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5899 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5900     int ret = 0;
5901 
5902     if (val == NULL)
5903 	return(0);
5904     switch (val->type) {
5905     case XPATH_UNDEFINED:
5906 #ifdef DEBUG_EXPR
5907 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5908 #endif
5909 	ret = 0;
5910 	break;
5911     case XPATH_NODESET:
5912     case XPATH_XSLT_TREE:
5913 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5914 	break;
5915     case XPATH_STRING:
5916 	ret = xmlXPathCastStringToBoolean(val->stringval);
5917 	break;
5918     case XPATH_NUMBER:
5919 	ret = xmlXPathCastNumberToBoolean(val->floatval);
5920 	break;
5921     case XPATH_BOOLEAN:
5922 	ret = val->boolval;
5923 	break;
5924     case XPATH_USERS:
5925     case XPATH_POINT:
5926     case XPATH_RANGE:
5927     case XPATH_LOCATIONSET:
5928 	TODO;
5929 	ret = 0;
5930 	break;
5931     }
5932     return(ret);
5933 }
5934 
5935 
5936 /**
5937  * xmlXPathConvertBoolean:
5938  * @val:  an XPath object
5939  *
5940  * Converts an existing object to its boolean() equivalent
5941  *
5942  * Returns the new object, the old one is freed (or the operation
5943  *         is done directly on @val)
5944  */
5945 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)5946 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5947     xmlXPathObjectPtr ret;
5948 
5949     if (val == NULL)
5950 	return(xmlXPathNewBoolean(0));
5951     if (val->type == XPATH_BOOLEAN)
5952 	return(val);
5953     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5954     xmlXPathFreeObject(val);
5955     return(ret);
5956 }
5957 
5958 /************************************************************************
5959  *									*
5960  *		Routines to handle XPath contexts			*
5961  *									*
5962  ************************************************************************/
5963 
5964 /**
5965  * xmlXPathNewContext:
5966  * @doc:  the XML document
5967  *
5968  * Create a new xmlXPathContext
5969  *
5970  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5971  */
5972 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)5973 xmlXPathNewContext(xmlDocPtr doc) {
5974     xmlXPathContextPtr ret;
5975 
5976     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5977     if (ret == NULL) {
5978         xmlXPathErrMemory(NULL, "creating context\n");
5979 	return(NULL);
5980     }
5981     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5982     ret->doc = doc;
5983     ret->node = NULL;
5984 
5985     ret->varHash = NULL;
5986 
5987     ret->nb_types = 0;
5988     ret->max_types = 0;
5989     ret->types = NULL;
5990 
5991     ret->funcHash = xmlHashCreate(0);
5992 
5993     ret->nb_axis = 0;
5994     ret->max_axis = 0;
5995     ret->axis = NULL;
5996 
5997     ret->nsHash = NULL;
5998     ret->user = NULL;
5999 
6000     ret->contextSize = -1;
6001     ret->proximityPosition = -1;
6002 
6003 #ifdef XP_DEFAULT_CACHE_ON
6004     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6005 	xmlXPathFreeContext(ret);
6006 	return(NULL);
6007     }
6008 #endif
6009 
6010     xmlXPathRegisterAllFunctions(ret);
6011 
6012     return(ret);
6013 }
6014 
6015 /**
6016  * xmlXPathFreeContext:
6017  * @ctxt:  the context to free
6018  *
6019  * Free up an xmlXPathContext
6020  */
6021 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6022 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6023     if (ctxt == NULL) return;
6024 
6025     if (ctxt->cache != NULL)
6026 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6027     xmlXPathRegisteredNsCleanup(ctxt);
6028     xmlXPathRegisteredFuncsCleanup(ctxt);
6029     xmlXPathRegisteredVariablesCleanup(ctxt);
6030     xmlResetError(&ctxt->lastError);
6031     xmlFree(ctxt);
6032 }
6033 
6034 /************************************************************************
6035  *									*
6036  *		Routines to handle XPath parser contexts		*
6037  *									*
6038  ************************************************************************/
6039 
6040 #define CHECK_CTXT(ctxt)						\
6041     if (ctxt == NULL) { 						\
6042 	__xmlRaiseError(NULL, NULL, NULL,				\
6043 		NULL, NULL, XML_FROM_XPATH,				\
6044 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6045 		__FILE__, __LINE__,					\
6046 		NULL, NULL, NULL, 0, 0,					\
6047 		"NULL context pointer\n");				\
6048 	return(NULL);							\
6049     }									\
6050 
6051 #define CHECK_CTXT_NEG(ctxt)						\
6052     if (ctxt == NULL) { 						\
6053 	__xmlRaiseError(NULL, NULL, NULL,				\
6054 		NULL, NULL, XML_FROM_XPATH,				\
6055 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6056 		__FILE__, __LINE__,					\
6057 		NULL, NULL, NULL, 0, 0,					\
6058 		"NULL context pointer\n");				\
6059 	return(-1);							\
6060     }									\
6061 
6062 
6063 #define CHECK_CONTEXT(ctxt)						\
6064     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6065         (ctxt->doc->children == NULL)) { 				\
6066 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6067 	return(NULL);							\
6068     }
6069 
6070 
6071 /**
6072  * xmlXPathNewParserContext:
6073  * @str:  the XPath expression
6074  * @ctxt:  the XPath context
6075  *
6076  * Create a new xmlXPathParserContext
6077  *
6078  * Returns the xmlXPathParserContext just allocated.
6079  */
6080 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6081 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6082     xmlXPathParserContextPtr ret;
6083 
6084     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6085     if (ret == NULL) {
6086         xmlXPathErrMemory(ctxt, "creating parser context\n");
6087 	return(NULL);
6088     }
6089     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6090     ret->cur = ret->base = str;
6091     ret->context = ctxt;
6092 
6093     ret->comp = xmlXPathNewCompExpr();
6094     if (ret->comp == NULL) {
6095 	xmlFree(ret->valueTab);
6096 	xmlFree(ret);
6097 	return(NULL);
6098     }
6099     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6100         ret->comp->dict = ctxt->dict;
6101 	xmlDictReference(ret->comp->dict);
6102     }
6103 
6104     return(ret);
6105 }
6106 
6107 /**
6108  * xmlXPathCompParserContext:
6109  * @comp:  the XPath compiled expression
6110  * @ctxt:  the XPath context
6111  *
6112  * Create a new xmlXPathParserContext when processing a compiled expression
6113  *
6114  * Returns the xmlXPathParserContext just allocated.
6115  */
6116 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6117 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6118     xmlXPathParserContextPtr ret;
6119 
6120     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6121     if (ret == NULL) {
6122         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6123 	return(NULL);
6124     }
6125     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6126 
6127     /* Allocate the value stack */
6128     ret->valueTab = (xmlXPathObjectPtr *)
6129                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6130     if (ret->valueTab == NULL) {
6131 	xmlFree(ret);
6132 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6133 	return(NULL);
6134     }
6135     ret->valueNr = 0;
6136     ret->valueMax = 10;
6137     ret->value = NULL;
6138 
6139     ret->context = ctxt;
6140     ret->comp = comp;
6141 
6142     return(ret);
6143 }
6144 
6145 /**
6146  * xmlXPathFreeParserContext:
6147  * @ctxt:  the context to free
6148  *
6149  * Free up an xmlXPathParserContext
6150  */
6151 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6152 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6153     if (ctxt->valueTab != NULL) {
6154         xmlFree(ctxt->valueTab);
6155     }
6156     if (ctxt->comp != NULL) {
6157 #ifdef XPATH_STREAMING
6158 	if (ctxt->comp->stream != NULL) {
6159 	    xmlFreePatternList(ctxt->comp->stream);
6160 	    ctxt->comp->stream = NULL;
6161 	}
6162 #endif
6163 	xmlXPathFreeCompExpr(ctxt->comp);
6164     }
6165     xmlFree(ctxt);
6166 }
6167 
6168 /************************************************************************
6169  *									*
6170  *		The implicit core function library			*
6171  *									*
6172  ************************************************************************/
6173 
6174 /**
6175  * xmlXPathNodeValHash:
6176  * @node:  a node pointer
6177  *
6178  * Function computing the beginning of the string value of the node,
6179  * used to speed up comparisons
6180  *
6181  * Returns an int usable as a hash
6182  */
6183 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6184 xmlXPathNodeValHash(xmlNodePtr node) {
6185     int len = 2;
6186     const xmlChar * string = NULL;
6187     xmlNodePtr tmp = NULL;
6188     unsigned int ret = 0;
6189 
6190     if (node == NULL)
6191 	return(0);
6192 
6193     if (node->type == XML_DOCUMENT_NODE) {
6194 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6195 	if (tmp == NULL)
6196 	    node = node->children;
6197 	else
6198 	    node = tmp;
6199 
6200 	if (node == NULL)
6201 	    return(0);
6202     }
6203 
6204     switch (node->type) {
6205 	case XML_COMMENT_NODE:
6206 	case XML_PI_NODE:
6207 	case XML_CDATA_SECTION_NODE:
6208 	case XML_TEXT_NODE:
6209 	    string = node->content;
6210 	    if (string == NULL)
6211 		return(0);
6212 	    if (string[0] == 0)
6213 		return(0);
6214 	    return(((unsigned int) string[0]) +
6215 		   (((unsigned int) string[1]) << 8));
6216 	case XML_NAMESPACE_DECL:
6217 	    string = ((xmlNsPtr)node)->href;
6218 	    if (string == NULL)
6219 		return(0);
6220 	    if (string[0] == 0)
6221 		return(0);
6222 	    return(((unsigned int) string[0]) +
6223 		   (((unsigned int) string[1]) << 8));
6224 	case XML_ATTRIBUTE_NODE:
6225 	    tmp = ((xmlAttrPtr) node)->children;
6226 	    break;
6227 	case XML_ELEMENT_NODE:
6228 	    tmp = node->children;
6229 	    break;
6230 	default:
6231 	    return(0);
6232     }
6233     while (tmp != NULL) {
6234 	switch (tmp->type) {
6235 	    case XML_COMMENT_NODE:
6236 	    case XML_PI_NODE:
6237 	    case XML_CDATA_SECTION_NODE:
6238 	    case XML_TEXT_NODE:
6239 		string = tmp->content;
6240 		break;
6241 	    case XML_NAMESPACE_DECL:
6242 		string = ((xmlNsPtr)tmp)->href;
6243 		break;
6244 	    default:
6245 		break;
6246 	}
6247 	if ((string != NULL) && (string[0] != 0)) {
6248 	    if (len == 1) {
6249 		return(ret + (((unsigned int) string[0]) << 8));
6250 	    }
6251 	    if (string[1] == 0) {
6252 		len = 1;
6253 		ret = (unsigned int) string[0];
6254 	    } else {
6255 		return(((unsigned int) string[0]) +
6256 		       (((unsigned int) string[1]) << 8));
6257 	    }
6258 	}
6259 	/*
6260 	 * Skip to next node
6261 	 */
6262 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6263 	    if (tmp->children->type != XML_ENTITY_DECL) {
6264 		tmp = tmp->children;
6265 		continue;
6266 	    }
6267 	}
6268 	if (tmp == node)
6269 	    break;
6270 
6271 	if (tmp->next != NULL) {
6272 	    tmp = tmp->next;
6273 	    continue;
6274 	}
6275 
6276 	do {
6277 	    tmp = tmp->parent;
6278 	    if (tmp == NULL)
6279 		break;
6280 	    if (tmp == node) {
6281 		tmp = NULL;
6282 		break;
6283 	    }
6284 	    if (tmp->next != NULL) {
6285 		tmp = tmp->next;
6286 		break;
6287 	    }
6288 	} while (tmp != NULL);
6289     }
6290     return(ret);
6291 }
6292 
6293 /**
6294  * xmlXPathStringHash:
6295  * @string:  a string
6296  *
6297  * Function computing the beginning of the string value of the node,
6298  * used to speed up comparisons
6299  *
6300  * Returns an int usable as a hash
6301  */
6302 static unsigned int
xmlXPathStringHash(const xmlChar * string)6303 xmlXPathStringHash(const xmlChar * string) {
6304     if (string == NULL)
6305 	return((unsigned int) 0);
6306     if (string[0] == 0)
6307 	return(0);
6308     return(((unsigned int) string[0]) +
6309 	   (((unsigned int) string[1]) << 8));
6310 }
6311 
6312 /**
6313  * xmlXPathCompareNodeSetFloat:
6314  * @ctxt:  the XPath Parser context
6315  * @inf:  less than (1) or greater than (0)
6316  * @strict:  is the comparison strict
6317  * @arg:  the node set
6318  * @f:  the value
6319  *
6320  * Implement the compare operation between a nodeset and a number
6321  *     @ns < @val    (1, 1, ...
6322  *     @ns <= @val   (1, 0, ...
6323  *     @ns > @val    (0, 1, ...
6324  *     @ns >= @val   (0, 0, ...
6325  *
6326  * If one object to be compared is a node-set and the other is a number,
6327  * then the comparison will be true if and only if there is a node in the
6328  * node-set such that the result of performing the comparison on the number
6329  * to be compared and on the result of converting the string-value of that
6330  * node to a number using the number function is true.
6331  *
6332  * Returns 0 or 1 depending on the results of the test.
6333  */
6334 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6335 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6336 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6337     int i, ret = 0;
6338     xmlNodeSetPtr ns;
6339     xmlChar *str2;
6340 
6341     if ((f == NULL) || (arg == NULL) ||
6342 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6343 	xmlXPathReleaseObject(ctxt->context, arg);
6344 	xmlXPathReleaseObject(ctxt->context, f);
6345         return(0);
6346     }
6347     ns = arg->nodesetval;
6348     if (ns != NULL) {
6349 	for (i = 0;i < ns->nodeNr;i++) {
6350 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6351 	     if (str2 != NULL) {
6352 		 valuePush(ctxt,
6353 			   xmlXPathCacheNewString(ctxt->context, str2));
6354 		 xmlFree(str2);
6355 		 xmlXPathNumberFunction(ctxt, 1);
6356 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6357 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6358 		 if (ret)
6359 		     break;
6360 	     }
6361 	}
6362     }
6363     xmlXPathReleaseObject(ctxt->context, arg);
6364     xmlXPathReleaseObject(ctxt->context, f);
6365     return(ret);
6366 }
6367 
6368 /**
6369  * xmlXPathCompareNodeSetString:
6370  * @ctxt:  the XPath Parser context
6371  * @inf:  less than (1) or greater than (0)
6372  * @strict:  is the comparison strict
6373  * @arg:  the node set
6374  * @s:  the value
6375  *
6376  * Implement the compare operation between a nodeset and a string
6377  *     @ns < @val    (1, 1, ...
6378  *     @ns <= @val   (1, 0, ...
6379  *     @ns > @val    (0, 1, ...
6380  *     @ns >= @val   (0, 0, ...
6381  *
6382  * If one object to be compared is a node-set and the other is a string,
6383  * then the comparison will be true if and only if there is a node in
6384  * the node-set such that the result of performing the comparison on the
6385  * string-value of the node and the other string is true.
6386  *
6387  * Returns 0 or 1 depending on the results of the test.
6388  */
6389 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6390 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6391 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6392     int i, ret = 0;
6393     xmlNodeSetPtr ns;
6394     xmlChar *str2;
6395 
6396     if ((s == NULL) || (arg == NULL) ||
6397 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6398 	xmlXPathReleaseObject(ctxt->context, arg);
6399 	xmlXPathReleaseObject(ctxt->context, s);
6400         return(0);
6401     }
6402     ns = arg->nodesetval;
6403     if (ns != NULL) {
6404 	for (i = 0;i < ns->nodeNr;i++) {
6405 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6406 	     if (str2 != NULL) {
6407 		 valuePush(ctxt,
6408 			   xmlXPathCacheNewString(ctxt->context, str2));
6409 		 xmlFree(str2);
6410 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6411 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6412 		 if (ret)
6413 		     break;
6414 	     }
6415 	}
6416     }
6417     xmlXPathReleaseObject(ctxt->context, arg);
6418     xmlXPathReleaseObject(ctxt->context, s);
6419     return(ret);
6420 }
6421 
6422 /**
6423  * xmlXPathCompareNodeSets:
6424  * @inf:  less than (1) or greater than (0)
6425  * @strict:  is the comparison strict
6426  * @arg1:  the first node set object
6427  * @arg2:  the second node set object
6428  *
6429  * Implement the compare operation on nodesets:
6430  *
6431  * If both objects to be compared are node-sets, then the comparison
6432  * will be true if and only if there is a node in the first node-set
6433  * and a node in the second node-set such that the result of performing
6434  * the comparison on the string-values of the two nodes is true.
6435  * ....
6436  * When neither object to be compared is a node-set and the operator
6437  * is <=, <, >= or >, then the objects are compared by converting both
6438  * objects to numbers and comparing the numbers according to IEEE 754.
6439  * ....
6440  * The number function converts its argument to a number as follows:
6441  *  - a string that consists of optional whitespace followed by an
6442  *    optional minus sign followed by a Number followed by whitespace
6443  *    is converted to the IEEE 754 number that is nearest (according
6444  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6445  *    represented by the string; any other string is converted to NaN
6446  *
6447  * Conclusion all nodes need to be converted first to their string value
6448  * and then the comparison must be done when possible
6449  */
6450 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6451 xmlXPathCompareNodeSets(int inf, int strict,
6452 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6453     int i, j, init = 0;
6454     double val1;
6455     double *values2;
6456     int ret = 0;
6457     xmlNodeSetPtr ns1;
6458     xmlNodeSetPtr ns2;
6459 
6460     if ((arg1 == NULL) ||
6461 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6462 	xmlXPathFreeObject(arg2);
6463         return(0);
6464     }
6465     if ((arg2 == NULL) ||
6466 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6467 	xmlXPathFreeObject(arg1);
6468 	xmlXPathFreeObject(arg2);
6469         return(0);
6470     }
6471 
6472     ns1 = arg1->nodesetval;
6473     ns2 = arg2->nodesetval;
6474 
6475     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6476 	xmlXPathFreeObject(arg1);
6477 	xmlXPathFreeObject(arg2);
6478 	return(0);
6479     }
6480     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6481 	xmlXPathFreeObject(arg1);
6482 	xmlXPathFreeObject(arg2);
6483 	return(0);
6484     }
6485 
6486     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6487     if (values2 == NULL) {
6488         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6489 	xmlXPathFreeObject(arg1);
6490 	xmlXPathFreeObject(arg2);
6491 	return(0);
6492     }
6493     for (i = 0;i < ns1->nodeNr;i++) {
6494 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6495 	if (xmlXPathIsNaN(val1))
6496 	    continue;
6497 	for (j = 0;j < ns2->nodeNr;j++) {
6498 	    if (init == 0) {
6499 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6500 	    }
6501 	    if (xmlXPathIsNaN(values2[j]))
6502 		continue;
6503 	    if (inf && strict)
6504 		ret = (val1 < values2[j]);
6505 	    else if (inf && !strict)
6506 		ret = (val1 <= values2[j]);
6507 	    else if (!inf && strict)
6508 		ret = (val1 > values2[j]);
6509 	    else if (!inf && !strict)
6510 		ret = (val1 >= values2[j]);
6511 	    if (ret)
6512 		break;
6513 	}
6514 	if (ret)
6515 	    break;
6516 	init = 1;
6517     }
6518     xmlFree(values2);
6519     xmlXPathFreeObject(arg1);
6520     xmlXPathFreeObject(arg2);
6521     return(ret);
6522 }
6523 
6524 /**
6525  * xmlXPathCompareNodeSetValue:
6526  * @ctxt:  the XPath Parser context
6527  * @inf:  less than (1) or greater than (0)
6528  * @strict:  is the comparison strict
6529  * @arg:  the node set
6530  * @val:  the value
6531  *
6532  * Implement the compare operation between a nodeset and a value
6533  *     @ns < @val    (1, 1, ...
6534  *     @ns <= @val   (1, 0, ...
6535  *     @ns > @val    (0, 1, ...
6536  *     @ns >= @val   (0, 0, ...
6537  *
6538  * If one object to be compared is a node-set and the other is a boolean,
6539  * then the comparison will be true if and only if the result of performing
6540  * the comparison on the boolean and on the result of converting
6541  * the node-set to a boolean using the boolean function is true.
6542  *
6543  * Returns 0 or 1 depending on the results of the test.
6544  */
6545 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6546 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6547 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6548     if ((val == NULL) || (arg == NULL) ||
6549 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6550         return(0);
6551 
6552     switch(val->type) {
6553         case XPATH_NUMBER:
6554 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6555         case XPATH_NODESET:
6556         case XPATH_XSLT_TREE:
6557 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6558         case XPATH_STRING:
6559 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6560         case XPATH_BOOLEAN:
6561 	    valuePush(ctxt, arg);
6562 	    xmlXPathBooleanFunction(ctxt, 1);
6563 	    valuePush(ctxt, val);
6564 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6565 	default:
6566 	    TODO
6567     }
6568     return(0);
6569 }
6570 
6571 /**
6572  * xmlXPathEqualNodeSetString:
6573  * @arg:  the nodeset object argument
6574  * @str:  the string to compare to.
6575  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6576  *
6577  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6578  * If one object to be compared is a node-set and the other is a string,
6579  * then the comparison will be true if and only if there is a node in
6580  * the node-set such that the result of performing the comparison on the
6581  * string-value of the node and the other string is true.
6582  *
6583  * Returns 0 or 1 depending on the results of the test.
6584  */
6585 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6586 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6587 {
6588     int i;
6589     xmlNodeSetPtr ns;
6590     xmlChar *str2;
6591     unsigned int hash;
6592 
6593     if ((str == NULL) || (arg == NULL) ||
6594         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6595         return (0);
6596     ns = arg->nodesetval;
6597     /*
6598      * A NULL nodeset compared with a string is always false
6599      * (since there is no node equal, and no node not equal)
6600      */
6601     if ((ns == NULL) || (ns->nodeNr <= 0) )
6602         return (0);
6603     hash = xmlXPathStringHash(str);
6604     for (i = 0; i < ns->nodeNr; i++) {
6605         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6606             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6607             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6608                 xmlFree(str2);
6609 		if (neq)
6610 		    continue;
6611                 return (1);
6612 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6613 		if (neq)
6614 		    continue;
6615                 return (1);
6616             } else if (neq) {
6617 		if (str2 != NULL)
6618 		    xmlFree(str2);
6619 		return (1);
6620 	    }
6621             if (str2 != NULL)
6622                 xmlFree(str2);
6623         } else if (neq)
6624 	    return (1);
6625     }
6626     return (0);
6627 }
6628 
6629 /**
6630  * xmlXPathEqualNodeSetFloat:
6631  * @arg:  the nodeset object argument
6632  * @f:  the float to compare to
6633  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6634  *
6635  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6636  * If one object to be compared is a node-set and the other is a number,
6637  * then the comparison will be true if and only if there is a node in
6638  * the node-set such that the result of performing the comparison on the
6639  * number to be compared and on the result of converting the string-value
6640  * of that node to a number using the number function is true.
6641  *
6642  * Returns 0 or 1 depending on the results of the test.
6643  */
6644 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6645 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6646     xmlXPathObjectPtr arg, double f, int neq) {
6647   int i, ret=0;
6648   xmlNodeSetPtr ns;
6649   xmlChar *str2;
6650   xmlXPathObjectPtr val;
6651   double v;
6652 
6653     if ((arg == NULL) ||
6654 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6655         return(0);
6656 
6657     ns = arg->nodesetval;
6658     if (ns != NULL) {
6659 	for (i=0;i<ns->nodeNr;i++) {
6660 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6661 	    if (str2 != NULL) {
6662 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6663 		xmlFree(str2);
6664 		xmlXPathNumberFunction(ctxt, 1);
6665 		val = valuePop(ctxt);
6666 		v = val->floatval;
6667 		xmlXPathReleaseObject(ctxt->context, val);
6668 		if (!xmlXPathIsNaN(v)) {
6669 		    if ((!neq) && (v==f)) {
6670 			ret = 1;
6671 			break;
6672 		    } else if ((neq) && (v!=f)) {
6673 			ret = 1;
6674 			break;
6675 		    }
6676 		} else {	/* NaN is unequal to any value */
6677 		    if (neq)
6678 			ret = 1;
6679 		}
6680 	    }
6681 	}
6682     }
6683 
6684     return(ret);
6685 }
6686 
6687 
6688 /**
6689  * xmlXPathEqualNodeSets:
6690  * @arg1:  first nodeset object argument
6691  * @arg2:  second nodeset object argument
6692  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6693  *
6694  * Implement the equal / not equal operation on XPath nodesets:
6695  * @arg1 == @arg2  or  @arg1 != @arg2
6696  * If both objects to be compared are node-sets, then the comparison
6697  * will be true if and only if there is a node in the first node-set and
6698  * a node in the second node-set such that the result of performing the
6699  * comparison on the string-values of the two nodes is true.
6700  *
6701  * (needless to say, this is a costly operation)
6702  *
6703  * Returns 0 or 1 depending on the results of the test.
6704  */
6705 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6706 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6707     int i, j;
6708     unsigned int *hashs1;
6709     unsigned int *hashs2;
6710     xmlChar **values1;
6711     xmlChar **values2;
6712     int ret = 0;
6713     xmlNodeSetPtr ns1;
6714     xmlNodeSetPtr ns2;
6715 
6716     if ((arg1 == NULL) ||
6717 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6718         return(0);
6719     if ((arg2 == NULL) ||
6720 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6721         return(0);
6722 
6723     ns1 = arg1->nodesetval;
6724     ns2 = arg2->nodesetval;
6725 
6726     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6727 	return(0);
6728     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6729 	return(0);
6730 
6731     /*
6732      * for equal, check if there is a node pertaining to both sets
6733      */
6734     if (neq == 0)
6735 	for (i = 0;i < ns1->nodeNr;i++)
6736 	    for (j = 0;j < ns2->nodeNr;j++)
6737 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6738 		    return(1);
6739 
6740     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6741     if (values1 == NULL) {
6742         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6743 	return(0);
6744     }
6745     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6746     if (hashs1 == NULL) {
6747         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6748 	xmlFree(values1);
6749 	return(0);
6750     }
6751     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6752     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6753     if (values2 == NULL) {
6754         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6755 	xmlFree(hashs1);
6756 	xmlFree(values1);
6757 	return(0);
6758     }
6759     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6760     if (hashs2 == NULL) {
6761         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6762 	xmlFree(hashs1);
6763 	xmlFree(values1);
6764 	xmlFree(values2);
6765 	return(0);
6766     }
6767     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6768     for (i = 0;i < ns1->nodeNr;i++) {
6769 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6770 	for (j = 0;j < ns2->nodeNr;j++) {
6771 	    if (i == 0)
6772 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6773 	    if (hashs1[i] != hashs2[j]) {
6774 		if (neq) {
6775 		    ret = 1;
6776 		    break;
6777 		}
6778 	    }
6779 	    else {
6780 		if (values1[i] == NULL)
6781 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6782 		if (values2[j] == NULL)
6783 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6784 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6785 		if (ret)
6786 		    break;
6787 	    }
6788 	}
6789 	if (ret)
6790 	    break;
6791     }
6792     for (i = 0;i < ns1->nodeNr;i++)
6793 	if (values1[i] != NULL)
6794 	    xmlFree(values1[i]);
6795     for (j = 0;j < ns2->nodeNr;j++)
6796 	if (values2[j] != NULL)
6797 	    xmlFree(values2[j]);
6798     xmlFree(values1);
6799     xmlFree(values2);
6800     xmlFree(hashs1);
6801     xmlFree(hashs2);
6802     return(ret);
6803 }
6804 
6805 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6806 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6807   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6808     int ret = 0;
6809     /*
6810      *At this point we are assured neither arg1 nor arg2
6811      *is a nodeset, so we can just pick the appropriate routine.
6812      */
6813     switch (arg1->type) {
6814         case XPATH_UNDEFINED:
6815 #ifdef DEBUG_EXPR
6816 	    xmlGenericError(xmlGenericErrorContext,
6817 		    "Equal: undefined\n");
6818 #endif
6819 	    break;
6820         case XPATH_BOOLEAN:
6821 	    switch (arg2->type) {
6822 	        case XPATH_UNDEFINED:
6823 #ifdef DEBUG_EXPR
6824 		    xmlGenericError(xmlGenericErrorContext,
6825 			    "Equal: undefined\n");
6826 #endif
6827 		    break;
6828 		case XPATH_BOOLEAN:
6829 #ifdef DEBUG_EXPR
6830 		    xmlGenericError(xmlGenericErrorContext,
6831 			    "Equal: %d boolean %d \n",
6832 			    arg1->boolval, arg2->boolval);
6833 #endif
6834 		    ret = (arg1->boolval == arg2->boolval);
6835 		    break;
6836 		case XPATH_NUMBER:
6837 		    ret = (arg1->boolval ==
6838 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6839 		    break;
6840 		case XPATH_STRING:
6841 		    if ((arg2->stringval == NULL) ||
6842 			(arg2->stringval[0] == 0)) ret = 0;
6843 		    else
6844 			ret = 1;
6845 		    ret = (arg1->boolval == ret);
6846 		    break;
6847 		case XPATH_USERS:
6848 		case XPATH_POINT:
6849 		case XPATH_RANGE:
6850 		case XPATH_LOCATIONSET:
6851 		    TODO
6852 		    break;
6853 		case XPATH_NODESET:
6854 		case XPATH_XSLT_TREE:
6855 		    break;
6856 	    }
6857 	    break;
6858         case XPATH_NUMBER:
6859 	    switch (arg2->type) {
6860 	        case XPATH_UNDEFINED:
6861 #ifdef DEBUG_EXPR
6862 		    xmlGenericError(xmlGenericErrorContext,
6863 			    "Equal: undefined\n");
6864 #endif
6865 		    break;
6866 		case XPATH_BOOLEAN:
6867 		    ret = (arg2->boolval==
6868 			   xmlXPathCastNumberToBoolean(arg1->floatval));
6869 		    break;
6870 		case XPATH_STRING:
6871 		    valuePush(ctxt, arg2);
6872 		    xmlXPathNumberFunction(ctxt, 1);
6873 		    arg2 = valuePop(ctxt);
6874 		    /* no break on purpose */
6875 		case XPATH_NUMBER:
6876 		    /* Hand check NaN and Infinity equalities */
6877 		    if (xmlXPathIsNaN(arg1->floatval) ||
6878 		    	    xmlXPathIsNaN(arg2->floatval)) {
6879 		        ret = 0;
6880 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6881 		        if (xmlXPathIsInf(arg2->floatval) == 1)
6882 			    ret = 1;
6883 			else
6884 			    ret = 0;
6885 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6886 			if (xmlXPathIsInf(arg2->floatval) == -1)
6887 			    ret = 1;
6888 			else
6889 			    ret = 0;
6890 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6891 			if (xmlXPathIsInf(arg1->floatval) == 1)
6892 			    ret = 1;
6893 			else
6894 			    ret = 0;
6895 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6896 			if (xmlXPathIsInf(arg1->floatval) == -1)
6897 			    ret = 1;
6898 			else
6899 			    ret = 0;
6900 		    } else {
6901 		        ret = (arg1->floatval == arg2->floatval);
6902 		    }
6903 		    break;
6904 		case XPATH_USERS:
6905 		case XPATH_POINT:
6906 		case XPATH_RANGE:
6907 		case XPATH_LOCATIONSET:
6908 		    TODO
6909 		    break;
6910 		case XPATH_NODESET:
6911 		case XPATH_XSLT_TREE:
6912 		    break;
6913 	    }
6914 	    break;
6915         case XPATH_STRING:
6916 	    switch (arg2->type) {
6917 	        case XPATH_UNDEFINED:
6918 #ifdef DEBUG_EXPR
6919 		    xmlGenericError(xmlGenericErrorContext,
6920 			    "Equal: undefined\n");
6921 #endif
6922 		    break;
6923 		case XPATH_BOOLEAN:
6924 		    if ((arg1->stringval == NULL) ||
6925 			(arg1->stringval[0] == 0)) ret = 0;
6926 		    else
6927 			ret = 1;
6928 		    ret = (arg2->boolval == ret);
6929 		    break;
6930 		case XPATH_STRING:
6931 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6932 		    break;
6933 		case XPATH_NUMBER:
6934 		    valuePush(ctxt, arg1);
6935 		    xmlXPathNumberFunction(ctxt, 1);
6936 		    arg1 = valuePop(ctxt);
6937 		    /* Hand check NaN and Infinity equalities */
6938 		    if (xmlXPathIsNaN(arg1->floatval) ||
6939 		    	    xmlXPathIsNaN(arg2->floatval)) {
6940 		        ret = 0;
6941 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6942 			if (xmlXPathIsInf(arg2->floatval) == 1)
6943 			    ret = 1;
6944 			else
6945 			    ret = 0;
6946 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6947 			if (xmlXPathIsInf(arg2->floatval) == -1)
6948 			    ret = 1;
6949 			else
6950 			    ret = 0;
6951 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6952 			if (xmlXPathIsInf(arg1->floatval) == 1)
6953 			    ret = 1;
6954 			else
6955 			    ret = 0;
6956 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6957 			if (xmlXPathIsInf(arg1->floatval) == -1)
6958 			    ret = 1;
6959 			else
6960 			    ret = 0;
6961 		    } else {
6962 		        ret = (arg1->floatval == arg2->floatval);
6963 		    }
6964 		    break;
6965 		case XPATH_USERS:
6966 		case XPATH_POINT:
6967 		case XPATH_RANGE:
6968 		case XPATH_LOCATIONSET:
6969 		    TODO
6970 		    break;
6971 		case XPATH_NODESET:
6972 		case XPATH_XSLT_TREE:
6973 		    break;
6974 	    }
6975 	    break;
6976         case XPATH_USERS:
6977 	case XPATH_POINT:
6978 	case XPATH_RANGE:
6979 	case XPATH_LOCATIONSET:
6980 	    TODO
6981 	    break;
6982 	case XPATH_NODESET:
6983 	case XPATH_XSLT_TREE:
6984 	    break;
6985     }
6986     xmlXPathReleaseObject(ctxt->context, arg1);
6987     xmlXPathReleaseObject(ctxt->context, arg2);
6988     return(ret);
6989 }
6990 
6991 /**
6992  * xmlXPathEqualValues:
6993  * @ctxt:  the XPath Parser context
6994  *
6995  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6996  *
6997  * Returns 0 or 1 depending on the results of the test.
6998  */
6999 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7000 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7001     xmlXPathObjectPtr arg1, arg2, argtmp;
7002     int ret = 0;
7003 
7004     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7005     arg2 = valuePop(ctxt);
7006     arg1 = valuePop(ctxt);
7007     if ((arg1 == NULL) || (arg2 == NULL)) {
7008 	if (arg1 != NULL)
7009 	    xmlXPathReleaseObject(ctxt->context, arg1);
7010 	else
7011 	    xmlXPathReleaseObject(ctxt->context, arg2);
7012 	XP_ERROR0(XPATH_INVALID_OPERAND);
7013     }
7014 
7015     if (arg1 == arg2) {
7016 #ifdef DEBUG_EXPR
7017         xmlGenericError(xmlGenericErrorContext,
7018 		"Equal: by pointer\n");
7019 #endif
7020 	xmlXPathFreeObject(arg1);
7021         return(1);
7022     }
7023 
7024     /*
7025      *If either argument is a nodeset, it's a 'special case'
7026      */
7027     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7028       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7029 	/*
7030 	 *Hack it to assure arg1 is the nodeset
7031 	 */
7032 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7033 		argtmp = arg2;
7034 		arg2 = arg1;
7035 		arg1 = argtmp;
7036 	}
7037 	switch (arg2->type) {
7038 	    case XPATH_UNDEFINED:
7039 #ifdef DEBUG_EXPR
7040 		xmlGenericError(xmlGenericErrorContext,
7041 			"Equal: undefined\n");
7042 #endif
7043 		break;
7044 	    case XPATH_NODESET:
7045 	    case XPATH_XSLT_TREE:
7046 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7047 		break;
7048 	    case XPATH_BOOLEAN:
7049 		if ((arg1->nodesetval == NULL) ||
7050 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7051 		else
7052 		    ret = 1;
7053 		ret = (ret == arg2->boolval);
7054 		break;
7055 	    case XPATH_NUMBER:
7056 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7057 		break;
7058 	    case XPATH_STRING:
7059 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7060 		break;
7061 	    case XPATH_USERS:
7062 	    case XPATH_POINT:
7063 	    case XPATH_RANGE:
7064 	    case XPATH_LOCATIONSET:
7065 		TODO
7066 		break;
7067 	}
7068 	xmlXPathReleaseObject(ctxt->context, arg1);
7069 	xmlXPathReleaseObject(ctxt->context, arg2);
7070 	return(ret);
7071     }
7072 
7073     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7074 }
7075 
7076 /**
7077  * xmlXPathNotEqualValues:
7078  * @ctxt:  the XPath Parser context
7079  *
7080  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7081  *
7082  * Returns 0 or 1 depending on the results of the test.
7083  */
7084 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7085 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7086     xmlXPathObjectPtr arg1, arg2, argtmp;
7087     int ret = 0;
7088 
7089     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7090     arg2 = valuePop(ctxt);
7091     arg1 = valuePop(ctxt);
7092     if ((arg1 == NULL) || (arg2 == NULL)) {
7093 	if (arg1 != NULL)
7094 	    xmlXPathReleaseObject(ctxt->context, arg1);
7095 	else
7096 	    xmlXPathReleaseObject(ctxt->context, arg2);
7097 	XP_ERROR0(XPATH_INVALID_OPERAND);
7098     }
7099 
7100     if (arg1 == arg2) {
7101 #ifdef DEBUG_EXPR
7102         xmlGenericError(xmlGenericErrorContext,
7103 		"NotEqual: by pointer\n");
7104 #endif
7105 	xmlXPathReleaseObject(ctxt->context, arg1);
7106         return(0);
7107     }
7108 
7109     /*
7110      *If either argument is a nodeset, it's a 'special case'
7111      */
7112     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7113       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7114 	/*
7115 	 *Hack it to assure arg1 is the nodeset
7116 	 */
7117 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7118 		argtmp = arg2;
7119 		arg2 = arg1;
7120 		arg1 = argtmp;
7121 	}
7122 	switch (arg2->type) {
7123 	    case XPATH_UNDEFINED:
7124 #ifdef DEBUG_EXPR
7125 		xmlGenericError(xmlGenericErrorContext,
7126 			"NotEqual: undefined\n");
7127 #endif
7128 		break;
7129 	    case XPATH_NODESET:
7130 	    case XPATH_XSLT_TREE:
7131 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7132 		break;
7133 	    case XPATH_BOOLEAN:
7134 		if ((arg1->nodesetval == NULL) ||
7135 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7136 		else
7137 		    ret = 1;
7138 		ret = (ret != arg2->boolval);
7139 		break;
7140 	    case XPATH_NUMBER:
7141 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7142 		break;
7143 	    case XPATH_STRING:
7144 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7145 		break;
7146 	    case XPATH_USERS:
7147 	    case XPATH_POINT:
7148 	    case XPATH_RANGE:
7149 	    case XPATH_LOCATIONSET:
7150 		TODO
7151 		break;
7152 	}
7153 	xmlXPathReleaseObject(ctxt->context, arg1);
7154 	xmlXPathReleaseObject(ctxt->context, arg2);
7155 	return(ret);
7156     }
7157 
7158     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7159 }
7160 
7161 /**
7162  * xmlXPathCompareValues:
7163  * @ctxt:  the XPath Parser context
7164  * @inf:  less than (1) or greater than (0)
7165  * @strict:  is the comparison strict
7166  *
7167  * Implement the compare operation on XPath objects:
7168  *     @arg1 < @arg2    (1, 1, ...
7169  *     @arg1 <= @arg2   (1, 0, ...
7170  *     @arg1 > @arg2    (0, 1, ...
7171  *     @arg1 >= @arg2   (0, 0, ...
7172  *
7173  * When neither object to be compared is a node-set and the operator is
7174  * <=, <, >=, >, then the objects are compared by converted both objects
7175  * to numbers and comparing the numbers according to IEEE 754. The <
7176  * comparison will be true if and only if the first number is less than the
7177  * second number. The <= comparison will be true if and only if the first
7178  * number is less than or equal to the second number. The > comparison
7179  * will be true if and only if the first number is greater than the second
7180  * number. The >= comparison will be true if and only if the first number
7181  * is greater than or equal to the second number.
7182  *
7183  * Returns 1 if the comparison succeeded, 0 if it failed
7184  */
7185 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7186 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7187     int ret = 0, arg1i = 0, arg2i = 0;
7188     xmlXPathObjectPtr arg1, arg2;
7189 
7190     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7191     arg2 = valuePop(ctxt);
7192     arg1 = valuePop(ctxt);
7193     if ((arg1 == NULL) || (arg2 == NULL)) {
7194 	if (arg1 != NULL)
7195 	    xmlXPathReleaseObject(ctxt->context, arg1);
7196 	else
7197 	    xmlXPathReleaseObject(ctxt->context, arg2);
7198 	XP_ERROR0(XPATH_INVALID_OPERAND);
7199     }
7200 
7201     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7202       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7203 	/*
7204 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7205 	 * are not freed from within this routine; they will be freed from the
7206 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7207 	 */
7208 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7209 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7210 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7211 	} else {
7212 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7213 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7214 			                          arg1, arg2);
7215 	    } else {
7216 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7217 			                          arg2, arg1);
7218 	    }
7219 	}
7220 	return(ret);
7221     }
7222 
7223     if (arg1->type != XPATH_NUMBER) {
7224 	valuePush(ctxt, arg1);
7225 	xmlXPathNumberFunction(ctxt, 1);
7226 	arg1 = valuePop(ctxt);
7227     }
7228     if (arg1->type != XPATH_NUMBER) {
7229 	xmlXPathFreeObject(arg1);
7230 	xmlXPathFreeObject(arg2);
7231 	XP_ERROR0(XPATH_INVALID_OPERAND);
7232     }
7233     if (arg2->type != XPATH_NUMBER) {
7234 	valuePush(ctxt, arg2);
7235 	xmlXPathNumberFunction(ctxt, 1);
7236 	arg2 = valuePop(ctxt);
7237     }
7238     if (arg2->type != XPATH_NUMBER) {
7239 	xmlXPathReleaseObject(ctxt->context, arg1);
7240 	xmlXPathReleaseObject(ctxt->context, arg2);
7241 	XP_ERROR0(XPATH_INVALID_OPERAND);
7242     }
7243     /*
7244      * Add tests for infinity and nan
7245      * => feedback on 3.4 for Inf and NaN
7246      */
7247     /* Hand check NaN and Infinity comparisons */
7248     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7249 	ret=0;
7250     } else {
7251 	arg1i=xmlXPathIsInf(arg1->floatval);
7252 	arg2i=xmlXPathIsInf(arg2->floatval);
7253 	if (inf && strict) {
7254 	    if ((arg1i == -1 && arg2i != -1) ||
7255 		(arg2i == 1 && arg1i != 1)) {
7256 		ret = 1;
7257 	    } else if (arg1i == 0 && arg2i == 0) {
7258 		ret = (arg1->floatval < arg2->floatval);
7259 	    } else {
7260 		ret = 0;
7261 	    }
7262 	}
7263 	else if (inf && !strict) {
7264 	    if (arg1i == -1 || arg2i == 1) {
7265 		ret = 1;
7266 	    } else if (arg1i == 0 && arg2i == 0) {
7267 		ret = (arg1->floatval <= arg2->floatval);
7268 	    } else {
7269 		ret = 0;
7270 	    }
7271 	}
7272 	else if (!inf && strict) {
7273 	    if ((arg1i == 1 && arg2i != 1) ||
7274 		(arg2i == -1 && arg1i != -1)) {
7275 		ret = 1;
7276 	    } else if (arg1i == 0 && arg2i == 0) {
7277 		ret = (arg1->floatval > arg2->floatval);
7278 	    } else {
7279 		ret = 0;
7280 	    }
7281 	}
7282 	else if (!inf && !strict) {
7283 	    if (arg1i == 1 || arg2i == -1) {
7284 		ret = 1;
7285 	    } else if (arg1i == 0 && arg2i == 0) {
7286 		ret = (arg1->floatval >= arg2->floatval);
7287 	    } else {
7288 		ret = 0;
7289 	    }
7290 	}
7291     }
7292     xmlXPathReleaseObject(ctxt->context, arg1);
7293     xmlXPathReleaseObject(ctxt->context, arg2);
7294     return(ret);
7295 }
7296 
7297 /**
7298  * xmlXPathValueFlipSign:
7299  * @ctxt:  the XPath Parser context
7300  *
7301  * Implement the unary - operation on an XPath object
7302  * The numeric operators convert their operands to numbers as if
7303  * by calling the number function.
7304  */
7305 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7306 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7307     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7308     CAST_TO_NUMBER;
7309     CHECK_TYPE(XPATH_NUMBER);
7310     if (xmlXPathIsNaN(ctxt->value->floatval))
7311         ctxt->value->floatval=xmlXPathNAN;
7312     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7313         ctxt->value->floatval=xmlXPathNINF;
7314     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7315         ctxt->value->floatval=xmlXPathPINF;
7316     else if (ctxt->value->floatval == 0) {
7317         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7318 	    ctxt->value->floatval = xmlXPathNZERO;
7319 	else
7320 	    ctxt->value->floatval = 0;
7321     }
7322     else
7323         ctxt->value->floatval = - ctxt->value->floatval;
7324 }
7325 
7326 /**
7327  * xmlXPathAddValues:
7328  * @ctxt:  the XPath Parser context
7329  *
7330  * Implement the add operation on XPath objects:
7331  * The numeric operators convert their operands to numbers as if
7332  * by calling the number function.
7333  */
7334 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7335 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7336     xmlXPathObjectPtr arg;
7337     double val;
7338 
7339     arg = valuePop(ctxt);
7340     if (arg == NULL)
7341 	XP_ERROR(XPATH_INVALID_OPERAND);
7342     val = xmlXPathCastToNumber(arg);
7343     xmlXPathReleaseObject(ctxt->context, arg);
7344     CAST_TO_NUMBER;
7345     CHECK_TYPE(XPATH_NUMBER);
7346     ctxt->value->floatval += val;
7347 }
7348 
7349 /**
7350  * xmlXPathSubValues:
7351  * @ctxt:  the XPath Parser context
7352  *
7353  * Implement the subtraction operation on XPath objects:
7354  * The numeric operators convert their operands to numbers as if
7355  * by calling the number function.
7356  */
7357 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7358 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7359     xmlXPathObjectPtr arg;
7360     double val;
7361 
7362     arg = valuePop(ctxt);
7363     if (arg == NULL)
7364 	XP_ERROR(XPATH_INVALID_OPERAND);
7365     val = xmlXPathCastToNumber(arg);
7366     xmlXPathReleaseObject(ctxt->context, arg);
7367     CAST_TO_NUMBER;
7368     CHECK_TYPE(XPATH_NUMBER);
7369     ctxt->value->floatval -= val;
7370 }
7371 
7372 /**
7373  * xmlXPathMultValues:
7374  * @ctxt:  the XPath Parser context
7375  *
7376  * Implement the multiply operation on XPath objects:
7377  * The numeric operators convert their operands to numbers as if
7378  * by calling the number function.
7379  */
7380 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7381 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7382     xmlXPathObjectPtr arg;
7383     double val;
7384 
7385     arg = valuePop(ctxt);
7386     if (arg == NULL)
7387 	XP_ERROR(XPATH_INVALID_OPERAND);
7388     val = xmlXPathCastToNumber(arg);
7389     xmlXPathReleaseObject(ctxt->context, arg);
7390     CAST_TO_NUMBER;
7391     CHECK_TYPE(XPATH_NUMBER);
7392     ctxt->value->floatval *= val;
7393 }
7394 
7395 /**
7396  * xmlXPathDivValues:
7397  * @ctxt:  the XPath Parser context
7398  *
7399  * Implement the div operation on XPath objects @arg1 / @arg2:
7400  * The numeric operators convert their operands to numbers as if
7401  * by calling the number function.
7402  */
7403 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7404 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7405     xmlXPathObjectPtr arg;
7406     double val;
7407 
7408     arg = valuePop(ctxt);
7409     if (arg == NULL)
7410 	XP_ERROR(XPATH_INVALID_OPERAND);
7411     val = xmlXPathCastToNumber(arg);
7412     xmlXPathReleaseObject(ctxt->context, arg);
7413     CAST_TO_NUMBER;
7414     CHECK_TYPE(XPATH_NUMBER);
7415     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7416 	ctxt->value->floatval = xmlXPathNAN;
7417     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7418 	if (ctxt->value->floatval == 0)
7419 	    ctxt->value->floatval = xmlXPathNAN;
7420 	else if (ctxt->value->floatval > 0)
7421 	    ctxt->value->floatval = xmlXPathNINF;
7422 	else if (ctxt->value->floatval < 0)
7423 	    ctxt->value->floatval = xmlXPathPINF;
7424     }
7425     else if (val == 0) {
7426 	if (ctxt->value->floatval == 0)
7427 	    ctxt->value->floatval = xmlXPathNAN;
7428 	else if (ctxt->value->floatval > 0)
7429 	    ctxt->value->floatval = xmlXPathPINF;
7430 	else if (ctxt->value->floatval < 0)
7431 	    ctxt->value->floatval = xmlXPathNINF;
7432     } else
7433 	ctxt->value->floatval /= val;
7434 }
7435 
7436 /**
7437  * xmlXPathModValues:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the mod operation on XPath objects: @arg1 / @arg2
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7445 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7446     xmlXPathObjectPtr arg;
7447     double arg1, arg2;
7448 
7449     arg = valuePop(ctxt);
7450     if (arg == NULL)
7451 	XP_ERROR(XPATH_INVALID_OPERAND);
7452     arg2 = xmlXPathCastToNumber(arg);
7453     xmlXPathReleaseObject(ctxt->context, arg);
7454     CAST_TO_NUMBER;
7455     CHECK_TYPE(XPATH_NUMBER);
7456     arg1 = ctxt->value->floatval;
7457     if (arg2 == 0)
7458 	ctxt->value->floatval = xmlXPathNAN;
7459     else {
7460 	ctxt->value->floatval = fmod(arg1, arg2);
7461     }
7462 }
7463 
7464 /************************************************************************
7465  *									*
7466  *		The traversal functions					*
7467  *									*
7468  ************************************************************************/
7469 
7470 /*
7471  * A traversal function enumerates nodes along an axis.
7472  * Initially it must be called with NULL, and it indicates
7473  * termination on the axis by returning NULL.
7474  */
7475 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7476                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7477 
7478 /*
7479  * xmlXPathTraversalFunctionExt:
7480  * A traversal function enumerates nodes along an axis.
7481  * Initially it must be called with NULL, and it indicates
7482  * termination on the axis by returning NULL.
7483  * The context node of the traversal is specified via @contextNode.
7484  */
7485 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7486                     (xmlNodePtr cur, xmlNodePtr contextNode);
7487 
7488 /*
7489  * xmlXPathNodeSetMergeFunction:
7490  * Used for merging node sets in xmlXPathCollectAndTest().
7491  */
7492 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7493 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7494 
7495 
7496 /**
7497  * xmlXPathNextSelf:
7498  * @ctxt:  the XPath Parser context
7499  * @cur:  the current node in the traversal
7500  *
7501  * Traversal function for the "self" direction
7502  * The self axis contains just the context node itself
7503  *
7504  * Returns the next element following that axis
7505  */
7506 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7507 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7508     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7509     if (cur == NULL)
7510         return(ctxt->context->node);
7511     return(NULL);
7512 }
7513 
7514 /**
7515  * xmlXPathNextChild:
7516  * @ctxt:  the XPath Parser context
7517  * @cur:  the current node in the traversal
7518  *
7519  * Traversal function for the "child" direction
7520  * The child axis contains the children of the context node in document order.
7521  *
7522  * Returns the next element following that axis
7523  */
7524 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7525 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7526     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7527     if (cur == NULL) {
7528 	if (ctxt->context->node == NULL) return(NULL);
7529 	switch (ctxt->context->node->type) {
7530             case XML_ELEMENT_NODE:
7531             case XML_TEXT_NODE:
7532             case XML_CDATA_SECTION_NODE:
7533             case XML_ENTITY_REF_NODE:
7534             case XML_ENTITY_NODE:
7535             case XML_PI_NODE:
7536             case XML_COMMENT_NODE:
7537             case XML_NOTATION_NODE:
7538             case XML_DTD_NODE:
7539 		return(ctxt->context->node->children);
7540             case XML_DOCUMENT_NODE:
7541             case XML_DOCUMENT_TYPE_NODE:
7542             case XML_DOCUMENT_FRAG_NODE:
7543             case XML_HTML_DOCUMENT_NODE:
7544 #ifdef LIBXML_DOCB_ENABLED
7545 	    case XML_DOCB_DOCUMENT_NODE:
7546 #endif
7547 		return(((xmlDocPtr) ctxt->context->node)->children);
7548 	    case XML_ELEMENT_DECL:
7549 	    case XML_ATTRIBUTE_DECL:
7550 	    case XML_ENTITY_DECL:
7551             case XML_ATTRIBUTE_NODE:
7552 	    case XML_NAMESPACE_DECL:
7553 	    case XML_XINCLUDE_START:
7554 	    case XML_XINCLUDE_END:
7555 		return(NULL);
7556 	}
7557 	return(NULL);
7558     }
7559     if ((cur->type == XML_DOCUMENT_NODE) ||
7560         (cur->type == XML_HTML_DOCUMENT_NODE))
7561 	return(NULL);
7562     return(cur->next);
7563 }
7564 
7565 /**
7566  * xmlXPathNextChildElement:
7567  * @ctxt:  the XPath Parser context
7568  * @cur:  the current node in the traversal
7569  *
7570  * Traversal function for the "child" direction and nodes of type element.
7571  * The child axis contains the children of the context node in document order.
7572  *
7573  * Returns the next element following that axis
7574  */
7575 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7576 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7577     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7578     if (cur == NULL) {
7579 	cur = ctxt->context->node;
7580 	if (cur == NULL) return(NULL);
7581 	/*
7582 	* Get the first element child.
7583 	*/
7584 	switch (cur->type) {
7585             case XML_ELEMENT_NODE:
7586 	    case XML_DOCUMENT_FRAG_NODE:
7587 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7588             case XML_ENTITY_NODE:
7589 		cur = cur->children;
7590 		if (cur != NULL) {
7591 		    if (cur->type == XML_ELEMENT_NODE)
7592 			return(cur);
7593 		    do {
7594 			cur = cur->next;
7595 		    } while ((cur != NULL) &&
7596 			(cur->type != XML_ELEMENT_NODE));
7597 		    return(cur);
7598 		}
7599 		return(NULL);
7600             case XML_DOCUMENT_NODE:
7601             case XML_HTML_DOCUMENT_NODE:
7602 #ifdef LIBXML_DOCB_ENABLED
7603 	    case XML_DOCB_DOCUMENT_NODE:
7604 #endif
7605 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7606 	    default:
7607 		return(NULL);
7608 	}
7609 	return(NULL);
7610     }
7611     /*
7612     * Get the next sibling element node.
7613     */
7614     switch (cur->type) {
7615 	case XML_ELEMENT_NODE:
7616 	case XML_TEXT_NODE:
7617 	case XML_ENTITY_REF_NODE:
7618 	case XML_ENTITY_NODE:
7619 	case XML_CDATA_SECTION_NODE:
7620 	case XML_PI_NODE:
7621 	case XML_COMMENT_NODE:
7622 	case XML_XINCLUDE_END:
7623 	    break;
7624 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7625 	default:
7626 	    return(NULL);
7627     }
7628     if (cur->next != NULL) {
7629 	if (cur->next->type == XML_ELEMENT_NODE)
7630 	    return(cur->next);
7631 	cur = cur->next;
7632 	do {
7633 	    cur = cur->next;
7634 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7635 	return(cur);
7636     }
7637     return(NULL);
7638 }
7639 
7640 /**
7641  * xmlXPathNextDescendantOrSelfElemParent:
7642  * @ctxt:  the XPath Parser context
7643  * @cur:  the current node in the traversal
7644  *
7645  * Traversal function for the "descendant-or-self" axis.
7646  * Additionally it returns only nodes which can be parents of
7647  * element nodes.
7648  *
7649  *
7650  * Returns the next element following that axis
7651  */
7652 static xmlNodePtr
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,xmlNodePtr contextNode)7653 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7654 				       xmlNodePtr contextNode)
7655 {
7656     if (cur == NULL) {
7657 	if (contextNode == NULL)
7658 	    return(NULL);
7659 	switch (contextNode->type) {
7660 	    case XML_ELEMENT_NODE:
7661 	    case XML_XINCLUDE_START:
7662 	    case XML_DOCUMENT_FRAG_NODE:
7663 	    case XML_DOCUMENT_NODE:
7664 #ifdef LIBXML_DOCB_ENABLED
7665 	    case XML_DOCB_DOCUMENT_NODE:
7666 #endif
7667 	    case XML_HTML_DOCUMENT_NODE:
7668 		return(contextNode);
7669 	    default:
7670 		return(NULL);
7671 	}
7672 	return(NULL);
7673     } else {
7674 	xmlNodePtr start = cur;
7675 
7676 	while (cur != NULL) {
7677 	    switch (cur->type) {
7678 		case XML_ELEMENT_NODE:
7679 		/* TODO: OK to have XInclude here? */
7680 		case XML_XINCLUDE_START:
7681 		case XML_DOCUMENT_FRAG_NODE:
7682 		    if (cur != start)
7683 			return(cur);
7684 		    if (cur->children != NULL) {
7685 			cur = cur->children;
7686 			continue;
7687 		    }
7688 		    break;
7689 		/* Not sure if we need those here. */
7690 		case XML_DOCUMENT_NODE:
7691 #ifdef LIBXML_DOCB_ENABLED
7692 		case XML_DOCB_DOCUMENT_NODE:
7693 #endif
7694 		case XML_HTML_DOCUMENT_NODE:
7695 		    if (cur != start)
7696 			return(cur);
7697 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7698 		default:
7699 		    break;
7700 	    }
7701 
7702 next_sibling:
7703 	    if ((cur == NULL) || (cur == contextNode))
7704 		return(NULL);
7705 	    if (cur->next != NULL) {
7706 		cur = cur->next;
7707 	    } else {
7708 		cur = cur->parent;
7709 		goto next_sibling;
7710 	    }
7711 	}
7712     }
7713     return(NULL);
7714 }
7715 
7716 /**
7717  * xmlXPathNextDescendant:
7718  * @ctxt:  the XPath Parser context
7719  * @cur:  the current node in the traversal
7720  *
7721  * Traversal function for the "descendant" direction
7722  * the descendant axis contains the descendants of the context node in document
7723  * order; a descendant is a child or a child of a child and so on.
7724  *
7725  * Returns the next element following that axis
7726  */
7727 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7728 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7729     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7730     if (cur == NULL) {
7731 	if (ctxt->context->node == NULL)
7732 	    return(NULL);
7733 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7734 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7735 	    return(NULL);
7736 
7737         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7738 	    return(ctxt->context->doc->children);
7739         return(ctxt->context->node->children);
7740     }
7741 
7742     if (cur->children != NULL) {
7743 	/*
7744 	 * Do not descend on entities declarations
7745 	 */
7746     	if (cur->children->type != XML_ENTITY_DECL) {
7747 	    cur = cur->children;
7748 	    /*
7749 	     * Skip DTDs
7750 	     */
7751 	    if (cur->type != XML_DTD_NODE)
7752 		return(cur);
7753 	}
7754     }
7755 
7756     if (cur == ctxt->context->node) return(NULL);
7757 
7758     while (cur->next != NULL) {
7759 	cur = cur->next;
7760 	if ((cur->type != XML_ENTITY_DECL) &&
7761 	    (cur->type != XML_DTD_NODE))
7762 	    return(cur);
7763     }
7764 
7765     do {
7766         cur = cur->parent;
7767 	if (cur == NULL) break;
7768 	if (cur == ctxt->context->node) return(NULL);
7769 	if (cur->next != NULL) {
7770 	    cur = cur->next;
7771 	    return(cur);
7772 	}
7773     } while (cur != NULL);
7774     return(cur);
7775 }
7776 
7777 /**
7778  * xmlXPathNextDescendantOrSelf:
7779  * @ctxt:  the XPath Parser context
7780  * @cur:  the current node in the traversal
7781  *
7782  * Traversal function for the "descendant-or-self" direction
7783  * the descendant-or-self axis contains the context node and the descendants
7784  * of the context node in document order; thus the context node is the first
7785  * node on the axis, and the first child of the context node is the second node
7786  * on the axis
7787  *
7788  * Returns the next element following that axis
7789  */
7790 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7791 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7792     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7793     if (cur == NULL) {
7794 	if (ctxt->context->node == NULL)
7795 	    return(NULL);
7796 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7797 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7798 	    return(NULL);
7799         return(ctxt->context->node);
7800     }
7801 
7802     return(xmlXPathNextDescendant(ctxt, cur));
7803 }
7804 
7805 /**
7806  * xmlXPathNextParent:
7807  * @ctxt:  the XPath Parser context
7808  * @cur:  the current node in the traversal
7809  *
7810  * Traversal function for the "parent" direction
7811  * The parent axis contains the parent of the context node, if there is one.
7812  *
7813  * Returns the next element following that axis
7814  */
7815 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7816 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7817     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7818     /*
7819      * the parent of an attribute or namespace node is the element
7820      * to which the attribute or namespace node is attached
7821      * Namespace handling !!!
7822      */
7823     if (cur == NULL) {
7824 	if (ctxt->context->node == NULL) return(NULL);
7825 	switch (ctxt->context->node->type) {
7826             case XML_ELEMENT_NODE:
7827             case XML_TEXT_NODE:
7828             case XML_CDATA_SECTION_NODE:
7829             case XML_ENTITY_REF_NODE:
7830             case XML_ENTITY_NODE:
7831             case XML_PI_NODE:
7832             case XML_COMMENT_NODE:
7833             case XML_NOTATION_NODE:
7834             case XML_DTD_NODE:
7835 	    case XML_ELEMENT_DECL:
7836 	    case XML_ATTRIBUTE_DECL:
7837 	    case XML_XINCLUDE_START:
7838 	    case XML_XINCLUDE_END:
7839 	    case XML_ENTITY_DECL:
7840 		if (ctxt->context->node->parent == NULL)
7841 		    return((xmlNodePtr) ctxt->context->doc);
7842 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7843 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7844 		     (xmlStrEqual(ctxt->context->node->parent->name,
7845 				 BAD_CAST "fake node libxslt"))))
7846 		    return(NULL);
7847 		return(ctxt->context->node->parent);
7848             case XML_ATTRIBUTE_NODE: {
7849 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7850 
7851 		return(att->parent);
7852 	    }
7853             case XML_DOCUMENT_NODE:
7854             case XML_DOCUMENT_TYPE_NODE:
7855             case XML_DOCUMENT_FRAG_NODE:
7856             case XML_HTML_DOCUMENT_NODE:
7857 #ifdef LIBXML_DOCB_ENABLED
7858 	    case XML_DOCB_DOCUMENT_NODE:
7859 #endif
7860                 return(NULL);
7861 	    case XML_NAMESPACE_DECL: {
7862 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7863 
7864 		if ((ns->next != NULL) &&
7865 		    (ns->next->type != XML_NAMESPACE_DECL))
7866 		    return((xmlNodePtr) ns->next);
7867                 return(NULL);
7868 	    }
7869 	}
7870     }
7871     return(NULL);
7872 }
7873 
7874 /**
7875  * xmlXPathNextAncestor:
7876  * @ctxt:  the XPath Parser context
7877  * @cur:  the current node in the traversal
7878  *
7879  * Traversal function for the "ancestor" direction
7880  * the ancestor axis contains the ancestors of the context node; the ancestors
7881  * of the context node consist of the parent of context node and the parent's
7882  * parent and so on; the nodes are ordered in reverse document order; thus the
7883  * parent is the first node on the axis, and the parent's parent is the second
7884  * node on the axis
7885  *
7886  * Returns the next element following that axis
7887  */
7888 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7889 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7890     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7891     /*
7892      * the parent of an attribute or namespace node is the element
7893      * to which the attribute or namespace node is attached
7894      * !!!!!!!!!!!!!
7895      */
7896     if (cur == NULL) {
7897 	if (ctxt->context->node == NULL) return(NULL);
7898 	switch (ctxt->context->node->type) {
7899             case XML_ELEMENT_NODE:
7900             case XML_TEXT_NODE:
7901             case XML_CDATA_SECTION_NODE:
7902             case XML_ENTITY_REF_NODE:
7903             case XML_ENTITY_NODE:
7904             case XML_PI_NODE:
7905             case XML_COMMENT_NODE:
7906 	    case XML_DTD_NODE:
7907 	    case XML_ELEMENT_DECL:
7908 	    case XML_ATTRIBUTE_DECL:
7909 	    case XML_ENTITY_DECL:
7910             case XML_NOTATION_NODE:
7911 	    case XML_XINCLUDE_START:
7912 	    case XML_XINCLUDE_END:
7913 		if (ctxt->context->node->parent == NULL)
7914 		    return((xmlNodePtr) ctxt->context->doc);
7915 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7916 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7917 		     (xmlStrEqual(ctxt->context->node->parent->name,
7918 				 BAD_CAST "fake node libxslt"))))
7919 		    return(NULL);
7920 		return(ctxt->context->node->parent);
7921             case XML_ATTRIBUTE_NODE: {
7922 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7923 
7924 		return(tmp->parent);
7925 	    }
7926             case XML_DOCUMENT_NODE:
7927             case XML_DOCUMENT_TYPE_NODE:
7928             case XML_DOCUMENT_FRAG_NODE:
7929             case XML_HTML_DOCUMENT_NODE:
7930 #ifdef LIBXML_DOCB_ENABLED
7931 	    case XML_DOCB_DOCUMENT_NODE:
7932 #endif
7933                 return(NULL);
7934 	    case XML_NAMESPACE_DECL: {
7935 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7936 
7937 		if ((ns->next != NULL) &&
7938 		    (ns->next->type != XML_NAMESPACE_DECL))
7939 		    return((xmlNodePtr) ns->next);
7940 		/* Bad, how did that namespace end up here ? */
7941                 return(NULL);
7942 	    }
7943 	}
7944 	return(NULL);
7945     }
7946     if (cur == ctxt->context->doc->children)
7947 	return((xmlNodePtr) ctxt->context->doc);
7948     if (cur == (xmlNodePtr) ctxt->context->doc)
7949 	return(NULL);
7950     switch (cur->type) {
7951 	case XML_ELEMENT_NODE:
7952 	case XML_TEXT_NODE:
7953 	case XML_CDATA_SECTION_NODE:
7954 	case XML_ENTITY_REF_NODE:
7955 	case XML_ENTITY_NODE:
7956 	case XML_PI_NODE:
7957 	case XML_COMMENT_NODE:
7958 	case XML_NOTATION_NODE:
7959 	case XML_DTD_NODE:
7960         case XML_ELEMENT_DECL:
7961         case XML_ATTRIBUTE_DECL:
7962         case XML_ENTITY_DECL:
7963 	case XML_XINCLUDE_START:
7964 	case XML_XINCLUDE_END:
7965 	    if (cur->parent == NULL)
7966 		return(NULL);
7967 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7968 		((cur->parent->name[0] == ' ') ||
7969 		 (xmlStrEqual(cur->parent->name,
7970 			      BAD_CAST "fake node libxslt"))))
7971 		return(NULL);
7972 	    return(cur->parent);
7973 	case XML_ATTRIBUTE_NODE: {
7974 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7975 
7976 	    return(att->parent);
7977 	}
7978 	case XML_NAMESPACE_DECL: {
7979 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7980 
7981 	    if ((ns->next != NULL) &&
7982 	        (ns->next->type != XML_NAMESPACE_DECL))
7983 	        return((xmlNodePtr) ns->next);
7984 	    /* Bad, how did that namespace end up here ? */
7985             return(NULL);
7986 	}
7987 	case XML_DOCUMENT_NODE:
7988 	case XML_DOCUMENT_TYPE_NODE:
7989 	case XML_DOCUMENT_FRAG_NODE:
7990 	case XML_HTML_DOCUMENT_NODE:
7991 #ifdef LIBXML_DOCB_ENABLED
7992 	case XML_DOCB_DOCUMENT_NODE:
7993 #endif
7994 	    return(NULL);
7995     }
7996     return(NULL);
7997 }
7998 
7999 /**
8000  * xmlXPathNextAncestorOrSelf:
8001  * @ctxt:  the XPath Parser context
8002  * @cur:  the current node in the traversal
8003  *
8004  * Traversal function for the "ancestor-or-self" direction
8005  * he ancestor-or-self axis contains the context node and ancestors of
8006  * the context node in reverse document order; thus the context node is
8007  * the first node on the axis, and the context node's parent the second;
8008  * parent here is defined the same as with the parent axis.
8009  *
8010  * Returns the next element following that axis
8011  */
8012 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8013 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8014     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8015     if (cur == NULL)
8016         return(ctxt->context->node);
8017     return(xmlXPathNextAncestor(ctxt, cur));
8018 }
8019 
8020 /**
8021  * xmlXPathNextFollowingSibling:
8022  * @ctxt:  the XPath Parser context
8023  * @cur:  the current node in the traversal
8024  *
8025  * Traversal function for the "following-sibling" direction
8026  * The following-sibling axis contains the following siblings of the context
8027  * node in document order.
8028  *
8029  * Returns the next element following that axis
8030  */
8031 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8032 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8035 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8036 	return(NULL);
8037     if (cur == (xmlNodePtr) ctxt->context->doc)
8038         return(NULL);
8039     if (cur == NULL)
8040         return(ctxt->context->node->next);
8041     return(cur->next);
8042 }
8043 
8044 /**
8045  * xmlXPathNextPrecedingSibling:
8046  * @ctxt:  the XPath Parser context
8047  * @cur:  the current node in the traversal
8048  *
8049  * Traversal function for the "preceding-sibling" direction
8050  * The preceding-sibling axis contains the preceding siblings of the context
8051  * node in reverse document order; the first preceding sibling is first on the
8052  * axis; the sibling preceding that node is the second on the axis and so on.
8053  *
8054  * Returns the next element following that axis
8055  */
8056 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8057 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8058     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8059     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8060 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8061 	return(NULL);
8062     if (cur == (xmlNodePtr) ctxt->context->doc)
8063         return(NULL);
8064     if (cur == NULL)
8065         return(ctxt->context->node->prev);
8066     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8067 	cur = cur->prev;
8068 	if (cur == NULL)
8069 	    return(ctxt->context->node->prev);
8070     }
8071     return(cur->prev);
8072 }
8073 
8074 /**
8075  * xmlXPathNextFollowing:
8076  * @ctxt:  the XPath Parser context
8077  * @cur:  the current node in the traversal
8078  *
8079  * Traversal function for the "following" direction
8080  * The following axis contains all nodes in the same document as the context
8081  * node that are after the context node in document order, excluding any
8082  * descendants and excluding attribute nodes and namespace nodes; the nodes
8083  * are ordered in document order
8084  *
8085  * Returns the next element following that axis
8086  */
8087 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8088 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8089     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8090     if (cur != NULL && cur->children != NULL)
8091         return cur->children ;
8092     if (cur == NULL) cur = ctxt->context->node;
8093     if (cur == NULL) return(NULL) ; /* ERROR */
8094     if (cur->next != NULL) return(cur->next) ;
8095     do {
8096         cur = cur->parent;
8097         if (cur == NULL) break;
8098         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8099         if (cur->next != NULL) return(cur->next);
8100     } while (cur != NULL);
8101     return(cur);
8102 }
8103 
8104 /*
8105  * xmlXPathIsAncestor:
8106  * @ancestor:  the ancestor node
8107  * @node:  the current node
8108  *
8109  * Check that @ancestor is a @node's ancestor
8110  *
8111  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8112  */
8113 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8114 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8115     if ((ancestor == NULL) || (node == NULL)) return(0);
8116     /* nodes need to be in the same document */
8117     if (ancestor->doc != node->doc) return(0);
8118     /* avoid searching if ancestor or node is the root node */
8119     if (ancestor == (xmlNodePtr) node->doc) return(1);
8120     if (node == (xmlNodePtr) ancestor->doc) return(0);
8121     while (node->parent != NULL) {
8122         if (node->parent == ancestor)
8123             return(1);
8124 	node = node->parent;
8125     }
8126     return(0);
8127 }
8128 
8129 /**
8130  * xmlXPathNextPreceding:
8131  * @ctxt:  the XPath Parser context
8132  * @cur:  the current node in the traversal
8133  *
8134  * Traversal function for the "preceding" direction
8135  * the preceding axis contains all nodes in the same document as the context
8136  * node that are before the context node in document order, excluding any
8137  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8138  * ordered in reverse document order
8139  *
8140  * Returns the next element following that axis
8141  */
8142 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8143 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8144 {
8145     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8146     if (cur == NULL)
8147         cur = ctxt->context->node;
8148     if (cur == NULL)
8149 	return (NULL);
8150     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8151 	cur = cur->prev;
8152     do {
8153         if (cur->prev != NULL) {
8154             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8155             return (cur);
8156         }
8157 
8158         cur = cur->parent;
8159         if (cur == NULL)
8160             return (NULL);
8161         if (cur == ctxt->context->doc->children)
8162             return (NULL);
8163     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8164     return (cur);
8165 }
8166 
8167 /**
8168  * xmlXPathNextPrecedingInternal:
8169  * @ctxt:  the XPath Parser context
8170  * @cur:  the current node in the traversal
8171  *
8172  * Traversal function for the "preceding" direction
8173  * the preceding axis contains all nodes in the same document as the context
8174  * node that are before the context node in document order, excluding any
8175  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8176  * ordered in reverse document order
8177  * This is a faster implementation but internal only since it requires a
8178  * state kept in the parser context: ctxt->ancestor.
8179  *
8180  * Returns the next element following that axis
8181  */
8182 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8183 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8184                               xmlNodePtr cur)
8185 {
8186     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8187     if (cur == NULL) {
8188         cur = ctxt->context->node;
8189         if (cur == NULL)
8190             return (NULL);
8191 	if (cur->type == XML_NAMESPACE_DECL)
8192 	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8193         ctxt->ancestor = cur->parent;
8194     }
8195     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8196 	cur = cur->prev;
8197     while (cur->prev == NULL) {
8198         cur = cur->parent;
8199         if (cur == NULL)
8200             return (NULL);
8201         if (cur == ctxt->context->doc->children)
8202             return (NULL);
8203         if (cur != ctxt->ancestor)
8204             return (cur);
8205         ctxt->ancestor = cur->parent;
8206     }
8207     cur = cur->prev;
8208     while (cur->last != NULL)
8209         cur = cur->last;
8210     return (cur);
8211 }
8212 
8213 /**
8214  * xmlXPathNextNamespace:
8215  * @ctxt:  the XPath Parser context
8216  * @cur:  the current attribute in the traversal
8217  *
8218  * Traversal function for the "namespace" direction
8219  * the namespace axis contains the namespace nodes of the context node;
8220  * the order of nodes on this axis is implementation-defined; the axis will
8221  * be empty unless the context node is an element
8222  *
8223  * We keep the XML namespace node at the end of the list.
8224  *
8225  * Returns the next element following that axis
8226  */
8227 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8228 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8229     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8230     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8231     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8232         if (ctxt->context->tmpNsList != NULL)
8233 	    xmlFree(ctxt->context->tmpNsList);
8234 	ctxt->context->tmpNsList =
8235 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8236 	ctxt->context->tmpNsNr = 0;
8237 	if (ctxt->context->tmpNsList != NULL) {
8238 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8239 		ctxt->context->tmpNsNr++;
8240 	    }
8241 	}
8242 	return((xmlNodePtr) xmlXPathXMLNamespace);
8243     }
8244     if (ctxt->context->tmpNsNr > 0) {
8245 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8246     } else {
8247 	if (ctxt->context->tmpNsList != NULL)
8248 	    xmlFree(ctxt->context->tmpNsList);
8249 	ctxt->context->tmpNsList = NULL;
8250 	return(NULL);
8251     }
8252 }
8253 
8254 /**
8255  * xmlXPathNextAttribute:
8256  * @ctxt:  the XPath Parser context
8257  * @cur:  the current attribute in the traversal
8258  *
8259  * Traversal function for the "attribute" direction
8260  * TODO: support DTD inherited default attributes
8261  *
8262  * Returns the next element following that axis
8263  */
8264 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8265 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8266     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8267     if (ctxt->context->node == NULL)
8268 	return(NULL);
8269     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8270 	return(NULL);
8271     if (cur == NULL) {
8272         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8273 	    return(NULL);
8274         return((xmlNodePtr)ctxt->context->node->properties);
8275     }
8276     return((xmlNodePtr)cur->next);
8277 }
8278 
8279 /************************************************************************
8280  *									*
8281  *		NodeTest Functions					*
8282  *									*
8283  ************************************************************************/
8284 
8285 #define IS_FUNCTION			200
8286 
8287 
8288 /************************************************************************
8289  *									*
8290  *		Implicit tree core function library			*
8291  *									*
8292  ************************************************************************/
8293 
8294 /**
8295  * xmlXPathRoot:
8296  * @ctxt:  the XPath Parser context
8297  *
8298  * Initialize the context to the root of the document
8299  */
8300 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8301 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8302     if ((ctxt == NULL) || (ctxt->context == NULL))
8303 	return;
8304     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8305     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8306 	ctxt->context->node));
8307 }
8308 
8309 /************************************************************************
8310  *									*
8311  *		The explicit core function library			*
8312  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8313  *									*
8314  ************************************************************************/
8315 
8316 
8317 /**
8318  * xmlXPathLastFunction:
8319  * @ctxt:  the XPath Parser context
8320  * @nargs:  the number of arguments
8321  *
8322  * Implement the last() XPath function
8323  *    number last()
8324  * The last function returns the number of nodes in the context node list.
8325  */
8326 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8327 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8328     CHECK_ARITY(0);
8329     if (ctxt->context->contextSize >= 0) {
8330 	valuePush(ctxt,
8331 	    xmlXPathCacheNewFloat(ctxt->context,
8332 		(double) ctxt->context->contextSize));
8333 #ifdef DEBUG_EXPR
8334 	xmlGenericError(xmlGenericErrorContext,
8335 		"last() : %d\n", ctxt->context->contextSize);
8336 #endif
8337     } else {
8338 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8339     }
8340 }
8341 
8342 /**
8343  * xmlXPathPositionFunction:
8344  * @ctxt:  the XPath Parser context
8345  * @nargs:  the number of arguments
8346  *
8347  * Implement the position() XPath function
8348  *    number position()
8349  * The position function returns the position of the context node in the
8350  * context node list. The first position is 1, and so the last position
8351  * will be equal to last().
8352  */
8353 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8354 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8355     CHECK_ARITY(0);
8356     if (ctxt->context->proximityPosition >= 0) {
8357 	valuePush(ctxt,
8358 	      xmlXPathCacheNewFloat(ctxt->context,
8359 		(double) ctxt->context->proximityPosition));
8360 #ifdef DEBUG_EXPR
8361 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8362 		ctxt->context->proximityPosition);
8363 #endif
8364     } else {
8365 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8366     }
8367 }
8368 
8369 /**
8370  * xmlXPathCountFunction:
8371  * @ctxt:  the XPath Parser context
8372  * @nargs:  the number of arguments
8373  *
8374  * Implement the count() XPath function
8375  *    number count(node-set)
8376  */
8377 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8378 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8379     xmlXPathObjectPtr cur;
8380 
8381     CHECK_ARITY(1);
8382     if ((ctxt->value == NULL) ||
8383 	((ctxt->value->type != XPATH_NODESET) &&
8384 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8385 	XP_ERROR(XPATH_INVALID_TYPE);
8386     cur = valuePop(ctxt);
8387 
8388     if ((cur == NULL) || (cur->nodesetval == NULL))
8389 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8390     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8391 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8392 	    (double) cur->nodesetval->nodeNr));
8393     } else {
8394 	if ((cur->nodesetval->nodeNr != 1) ||
8395 	    (cur->nodesetval->nodeTab == NULL)) {
8396 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8397 	} else {
8398 	    xmlNodePtr tmp;
8399 	    int i = 0;
8400 
8401 	    tmp = cur->nodesetval->nodeTab[0];
8402 	    if (tmp != NULL) {
8403 		tmp = tmp->children;
8404 		while (tmp != NULL) {
8405 		    tmp = tmp->next;
8406 		    i++;
8407 		}
8408 	    }
8409 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8410 	}
8411     }
8412     xmlXPathReleaseObject(ctxt->context, cur);
8413 }
8414 
8415 /**
8416  * xmlXPathGetElementsByIds:
8417  * @doc:  the document
8418  * @ids:  a whitespace separated list of IDs
8419  *
8420  * Selects elements by their unique ID.
8421  *
8422  * Returns a node-set of selected elements.
8423  */
8424 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8425 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8426     xmlNodeSetPtr ret;
8427     const xmlChar *cur = ids;
8428     xmlChar *ID;
8429     xmlAttrPtr attr;
8430     xmlNodePtr elem = NULL;
8431 
8432     if (ids == NULL) return(NULL);
8433 
8434     ret = xmlXPathNodeSetCreate(NULL);
8435 
8436     while (IS_BLANK_CH(*cur)) cur++;
8437     while (*cur != 0) {
8438 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8439 	    cur++;
8440 
8441         ID = xmlStrndup(ids, cur - ids);
8442 	if (ID != NULL) {
8443 	    /*
8444 	     * We used to check the fact that the value passed
8445 	     * was an NCName, but this generated much troubles for
8446 	     * me and Aleksey Sanin, people blatantly violated that
8447 	     * constaint, like Visa3D spec.
8448 	     * if (xmlValidateNCName(ID, 1) == 0)
8449 	     */
8450 	    attr = xmlGetID(doc, ID);
8451 	    if (attr != NULL) {
8452 		if (attr->type == XML_ATTRIBUTE_NODE)
8453 		    elem = attr->parent;
8454 		else if (attr->type == XML_ELEMENT_NODE)
8455 		    elem = (xmlNodePtr) attr;
8456 		else
8457 		    elem = NULL;
8458 		if (elem != NULL)
8459 		    xmlXPathNodeSetAdd(ret, elem);
8460 	    }
8461 	    xmlFree(ID);
8462 	}
8463 
8464 	while (IS_BLANK_CH(*cur)) cur++;
8465 	ids = cur;
8466     }
8467     return(ret);
8468 }
8469 
8470 /**
8471  * xmlXPathIdFunction:
8472  * @ctxt:  the XPath Parser context
8473  * @nargs:  the number of arguments
8474  *
8475  * Implement the id() XPath function
8476  *    node-set id(object)
8477  * The id function selects elements by their unique ID
8478  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8479  * then the result is the union of the result of applying id to the
8480  * string value of each of the nodes in the argument node-set. When the
8481  * argument to id is of any other type, the argument is converted to a
8482  * string as if by a call to the string function; the string is split
8483  * into a whitespace-separated list of tokens (whitespace is any sequence
8484  * of characters matching the production S); the result is a node-set
8485  * containing the elements in the same document as the context node that
8486  * have a unique ID equal to any of the tokens in the list.
8487  */
8488 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8489 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490     xmlChar *tokens;
8491     xmlNodeSetPtr ret;
8492     xmlXPathObjectPtr obj;
8493 
8494     CHECK_ARITY(1);
8495     obj = valuePop(ctxt);
8496     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8497     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8498 	xmlNodeSetPtr ns;
8499 	int i;
8500 
8501 	ret = xmlXPathNodeSetCreate(NULL);
8502 
8503 	if (obj->nodesetval != NULL) {
8504 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8505 		tokens =
8506 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8507 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8508 		ret = xmlXPathNodeSetMerge(ret, ns);
8509 		xmlXPathFreeNodeSet(ns);
8510 		if (tokens != NULL)
8511 		    xmlFree(tokens);
8512 	    }
8513 	}
8514 	xmlXPathReleaseObject(ctxt->context, obj);
8515 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8516 	return;
8517     }
8518     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8519     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8520     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8521     xmlXPathReleaseObject(ctxt->context, obj);
8522     return;
8523 }
8524 
8525 /**
8526  * xmlXPathLocalNameFunction:
8527  * @ctxt:  the XPath Parser context
8528  * @nargs:  the number of arguments
8529  *
8530  * Implement the local-name() XPath function
8531  *    string local-name(node-set?)
8532  * The local-name function returns a string containing the local part
8533  * of the name of the node in the argument node-set that is first in
8534  * document order. If the node-set is empty or the first node has no
8535  * name, an empty string is returned. If the argument is omitted it
8536  * defaults to the context node.
8537  */
8538 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8539 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8540     xmlXPathObjectPtr cur;
8541 
8542     if (ctxt == NULL) return;
8543 
8544     if (nargs == 0) {
8545 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8546 	    ctxt->context->node));
8547 	nargs = 1;
8548     }
8549 
8550     CHECK_ARITY(1);
8551     if ((ctxt->value == NULL) ||
8552 	((ctxt->value->type != XPATH_NODESET) &&
8553 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8554 	XP_ERROR(XPATH_INVALID_TYPE);
8555     cur = valuePop(ctxt);
8556 
8557     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8558 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8559     } else {
8560 	int i = 0; /* Should be first in document order !!!!! */
8561 	switch (cur->nodesetval->nodeTab[i]->type) {
8562 	case XML_ELEMENT_NODE:
8563 	case XML_ATTRIBUTE_NODE:
8564 	case XML_PI_NODE:
8565 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8566 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8567 	    else
8568 		valuePush(ctxt,
8569 		      xmlXPathCacheNewString(ctxt->context,
8570 			cur->nodesetval->nodeTab[i]->name));
8571 	    break;
8572 	case XML_NAMESPACE_DECL:
8573 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8574 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8575 	    break;
8576 	default:
8577 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8578 	}
8579     }
8580     xmlXPathReleaseObject(ctxt->context, cur);
8581 }
8582 
8583 /**
8584  * xmlXPathNamespaceURIFunction:
8585  * @ctxt:  the XPath Parser context
8586  * @nargs:  the number of arguments
8587  *
8588  * Implement the namespace-uri() XPath function
8589  *    string namespace-uri(node-set?)
8590  * The namespace-uri function returns a string containing the
8591  * namespace URI of the expanded name of the node in the argument
8592  * node-set that is first in document order. If the node-set is empty,
8593  * the first node has no name, or the expanded name has no namespace
8594  * URI, an empty string is returned. If the argument is omitted it
8595  * defaults to the context node.
8596  */
8597 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8598 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8599     xmlXPathObjectPtr cur;
8600 
8601     if (ctxt == NULL) return;
8602 
8603     if (nargs == 0) {
8604 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8605 	    ctxt->context->node));
8606 	nargs = 1;
8607     }
8608     CHECK_ARITY(1);
8609     if ((ctxt->value == NULL) ||
8610 	((ctxt->value->type != XPATH_NODESET) &&
8611 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8612 	XP_ERROR(XPATH_INVALID_TYPE);
8613     cur = valuePop(ctxt);
8614 
8615     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8616 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8617     } else {
8618 	int i = 0; /* Should be first in document order !!!!! */
8619 	switch (cur->nodesetval->nodeTab[i]->type) {
8620 	case XML_ELEMENT_NODE:
8621 	case XML_ATTRIBUTE_NODE:
8622 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8623 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8624 	    else
8625 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8626 			  cur->nodesetval->nodeTab[i]->ns->href));
8627 	    break;
8628 	default:
8629 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8630 	}
8631     }
8632     xmlXPathReleaseObject(ctxt->context, cur);
8633 }
8634 
8635 /**
8636  * xmlXPathNameFunction:
8637  * @ctxt:  the XPath Parser context
8638  * @nargs:  the number of arguments
8639  *
8640  * Implement the name() XPath function
8641  *    string name(node-set?)
8642  * The name function returns a string containing a QName representing
8643  * the name of the node in the argument node-set that is first in document
8644  * order. The QName must represent the name with respect to the namespace
8645  * declarations in effect on the node whose name is being represented.
8646  * Typically, this will be the form in which the name occurred in the XML
8647  * source. This need not be the case if there are namespace declarations
8648  * in effect on the node that associate multiple prefixes with the same
8649  * namespace. However, an implementation may include information about
8650  * the original prefix in its representation of nodes; in this case, an
8651  * implementation can ensure that the returned string is always the same
8652  * as the QName used in the XML source. If the argument it omitted it
8653  * defaults to the context node.
8654  * Libxml keep the original prefix so the "real qualified name" used is
8655  * returned.
8656  */
8657 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8658 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8659 {
8660     xmlXPathObjectPtr cur;
8661 
8662     if (nargs == 0) {
8663 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8664 	    ctxt->context->node));
8665         nargs = 1;
8666     }
8667 
8668     CHECK_ARITY(1);
8669     if ((ctxt->value == NULL) ||
8670         ((ctxt->value->type != XPATH_NODESET) &&
8671          (ctxt->value->type != XPATH_XSLT_TREE)))
8672         XP_ERROR(XPATH_INVALID_TYPE);
8673     cur = valuePop(ctxt);
8674 
8675     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8676         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8677     } else {
8678         int i = 0;              /* Should be first in document order !!!!! */
8679 
8680         switch (cur->nodesetval->nodeTab[i]->type) {
8681             case XML_ELEMENT_NODE:
8682             case XML_ATTRIBUTE_NODE:
8683 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8684 		    valuePush(ctxt,
8685 			xmlXPathCacheNewCString(ctxt->context, ""));
8686 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8687                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8688 		    valuePush(ctxt,
8689 		        xmlXPathCacheNewString(ctxt->context,
8690 			    cur->nodesetval->nodeTab[i]->name));
8691 		} else {
8692 		    xmlChar *fullname;
8693 
8694 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8695 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8696 				     NULL, 0);
8697 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8698 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8699 		    if (fullname == NULL) {
8700 			XP_ERROR(XPATH_MEMORY_ERROR);
8701 		    }
8702 		    valuePush(ctxt, xmlXPathCacheWrapString(
8703 			ctxt->context, fullname));
8704                 }
8705                 break;
8706             default:
8707 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8708 		    cur->nodesetval->nodeTab[i]));
8709                 xmlXPathLocalNameFunction(ctxt, 1);
8710         }
8711     }
8712     xmlXPathReleaseObject(ctxt->context, cur);
8713 }
8714 
8715 
8716 /**
8717  * xmlXPathStringFunction:
8718  * @ctxt:  the XPath Parser context
8719  * @nargs:  the number of arguments
8720  *
8721  * Implement the string() XPath function
8722  *    string string(object?)
8723  * The string function converts an object to a string as follows:
8724  *    - A node-set is converted to a string by returning the value of
8725  *      the node in the node-set that is first in document order.
8726  *      If the node-set is empty, an empty string is returned.
8727  *    - A number is converted to a string as follows
8728  *      + NaN is converted to the string NaN
8729  *      + positive zero is converted to the string 0
8730  *      + negative zero is converted to the string 0
8731  *      + positive infinity is converted to the string Infinity
8732  *      + negative infinity is converted to the string -Infinity
8733  *      + if the number is an integer, the number is represented in
8734  *        decimal form as a Number with no decimal point and no leading
8735  *        zeros, preceded by a minus sign (-) if the number is negative
8736  *      + otherwise, the number is represented in decimal form as a
8737  *        Number including a decimal point with at least one digit
8738  *        before the decimal point and at least one digit after the
8739  *        decimal point, preceded by a minus sign (-) if the number
8740  *        is negative; there must be no leading zeros before the decimal
8741  *        point apart possibly from the one required digit immediately
8742  *        before the decimal point; beyond the one required digit
8743  *        after the decimal point there must be as many, but only as
8744  *        many, more digits as are needed to uniquely distinguish the
8745  *        number from all other IEEE 754 numeric values.
8746  *    - The boolean false value is converted to the string false.
8747  *      The boolean true value is converted to the string true.
8748  *
8749  * If the argument is omitted, it defaults to a node-set with the
8750  * context node as its only member.
8751  */
8752 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8753 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8754     xmlXPathObjectPtr cur;
8755 
8756     if (ctxt == NULL) return;
8757     if (nargs == 0) {
8758     valuePush(ctxt,
8759 	xmlXPathCacheWrapString(ctxt->context,
8760 	    xmlXPathCastNodeToString(ctxt->context->node)));
8761 	return;
8762     }
8763 
8764     CHECK_ARITY(1);
8765     cur = valuePop(ctxt);
8766     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8767     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8768 }
8769 
8770 /**
8771  * xmlXPathStringLengthFunction:
8772  * @ctxt:  the XPath Parser context
8773  * @nargs:  the number of arguments
8774  *
8775  * Implement the string-length() XPath function
8776  *    number string-length(string?)
8777  * The string-length returns the number of characters in the string
8778  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8779  * the context node converted to a string, in other words the value
8780  * of the context node.
8781  */
8782 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8783 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8784     xmlXPathObjectPtr cur;
8785 
8786     if (nargs == 0) {
8787         if ((ctxt == NULL) || (ctxt->context == NULL))
8788 	    return;
8789 	if (ctxt->context->node == NULL) {
8790 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8791 	} else {
8792 	    xmlChar *content;
8793 
8794 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8795 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8796 		xmlUTF8Strlen(content)));
8797 	    xmlFree(content);
8798 	}
8799 	return;
8800     }
8801     CHECK_ARITY(1);
8802     CAST_TO_STRING;
8803     CHECK_TYPE(XPATH_STRING);
8804     cur = valuePop(ctxt);
8805     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8806 	xmlUTF8Strlen(cur->stringval)));
8807     xmlXPathReleaseObject(ctxt->context, cur);
8808 }
8809 
8810 /**
8811  * xmlXPathConcatFunction:
8812  * @ctxt:  the XPath Parser context
8813  * @nargs:  the number of arguments
8814  *
8815  * Implement the concat() XPath function
8816  *    string concat(string, string, string*)
8817  * The concat function returns the concatenation of its arguments.
8818  */
8819 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8820 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8821     xmlXPathObjectPtr cur, newobj;
8822     xmlChar *tmp;
8823 
8824     if (ctxt == NULL) return;
8825     if (nargs < 2) {
8826 	CHECK_ARITY(2);
8827     }
8828 
8829     CAST_TO_STRING;
8830     cur = valuePop(ctxt);
8831     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8832 	xmlXPathReleaseObject(ctxt->context, cur);
8833 	return;
8834     }
8835     nargs--;
8836 
8837     while (nargs > 0) {
8838 	CAST_TO_STRING;
8839 	newobj = valuePop(ctxt);
8840 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8841 	    xmlXPathReleaseObject(ctxt->context, newobj);
8842 	    xmlXPathReleaseObject(ctxt->context, cur);
8843 	    XP_ERROR(XPATH_INVALID_TYPE);
8844 	}
8845 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8846 	newobj->stringval = cur->stringval;
8847 	cur->stringval = tmp;
8848 	xmlXPathReleaseObject(ctxt->context, newobj);
8849 	nargs--;
8850     }
8851     valuePush(ctxt, cur);
8852 }
8853 
8854 /**
8855  * xmlXPathContainsFunction:
8856  * @ctxt:  the XPath Parser context
8857  * @nargs:  the number of arguments
8858  *
8859  * Implement the contains() XPath function
8860  *    boolean contains(string, string)
8861  * The contains function returns true if the first argument string
8862  * contains the second argument string, and otherwise returns false.
8863  */
8864 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)8865 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8866     xmlXPathObjectPtr hay, needle;
8867 
8868     CHECK_ARITY(2);
8869     CAST_TO_STRING;
8870     CHECK_TYPE(XPATH_STRING);
8871     needle = valuePop(ctxt);
8872     CAST_TO_STRING;
8873     hay = valuePop(ctxt);
8874 
8875     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8876 	xmlXPathReleaseObject(ctxt->context, hay);
8877 	xmlXPathReleaseObject(ctxt->context, needle);
8878 	XP_ERROR(XPATH_INVALID_TYPE);
8879     }
8880     if (xmlStrstr(hay->stringval, needle->stringval))
8881 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8882     else
8883 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8884     xmlXPathReleaseObject(ctxt->context, hay);
8885     xmlXPathReleaseObject(ctxt->context, needle);
8886 }
8887 
8888 /**
8889  * xmlXPathStartsWithFunction:
8890  * @ctxt:  the XPath Parser context
8891  * @nargs:  the number of arguments
8892  *
8893  * Implement the starts-with() XPath function
8894  *    boolean starts-with(string, string)
8895  * The starts-with function returns true if the first argument string
8896  * starts with the second argument string, and otherwise returns false.
8897  */
8898 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8899 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900     xmlXPathObjectPtr hay, needle;
8901     int n;
8902 
8903     CHECK_ARITY(2);
8904     CAST_TO_STRING;
8905     CHECK_TYPE(XPATH_STRING);
8906     needle = valuePop(ctxt);
8907     CAST_TO_STRING;
8908     hay = valuePop(ctxt);
8909 
8910     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8911 	xmlXPathReleaseObject(ctxt->context, hay);
8912 	xmlXPathReleaseObject(ctxt->context, needle);
8913 	XP_ERROR(XPATH_INVALID_TYPE);
8914     }
8915     n = xmlStrlen(needle->stringval);
8916     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8917         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8918     else
8919         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8920     xmlXPathReleaseObject(ctxt->context, hay);
8921     xmlXPathReleaseObject(ctxt->context, needle);
8922 }
8923 
8924 /**
8925  * xmlXPathSubstringFunction:
8926  * @ctxt:  the XPath Parser context
8927  * @nargs:  the number of arguments
8928  *
8929  * Implement the substring() XPath function
8930  *    string substring(string, number, number?)
8931  * The substring function returns the substring of the first argument
8932  * starting at the position specified in the second argument with
8933  * length specified in the third argument. For example,
8934  * substring("12345",2,3) returns "234". If the third argument is not
8935  * specified, it returns the substring starting at the position specified
8936  * in the second argument and continuing to the end of the string. For
8937  * example, substring("12345",2) returns "2345".  More precisely, each
8938  * character in the string (see [3.6 Strings]) is considered to have a
8939  * numeric position: the position of the first character is 1, the position
8940  * of the second character is 2 and so on. The returned substring contains
8941  * those characters for which the position of the character is greater than
8942  * or equal to the second argument and, if the third argument is specified,
8943  * less than the sum of the second and third arguments; the comparisons
8944  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8945  *  - substring("12345", 1.5, 2.6) returns "234"
8946  *  - substring("12345", 0, 3) returns "12"
8947  *  - substring("12345", 0 div 0, 3) returns ""
8948  *  - substring("12345", 1, 0 div 0) returns ""
8949  *  - substring("12345", -42, 1 div 0) returns "12345"
8950  *  - substring("12345", -1 div 0, 1 div 0) returns ""
8951  */
8952 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)8953 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8954     xmlXPathObjectPtr str, start, len;
8955     double le=0, in;
8956     int i, l, m;
8957     xmlChar *ret;
8958 
8959     if (nargs < 2) {
8960 	CHECK_ARITY(2);
8961     }
8962     if (nargs > 3) {
8963 	CHECK_ARITY(3);
8964     }
8965     /*
8966      * take care of possible last (position) argument
8967     */
8968     if (nargs == 3) {
8969 	CAST_TO_NUMBER;
8970 	CHECK_TYPE(XPATH_NUMBER);
8971 	len = valuePop(ctxt);
8972 	le = len->floatval;
8973 	xmlXPathReleaseObject(ctxt->context, len);
8974     }
8975 
8976     CAST_TO_NUMBER;
8977     CHECK_TYPE(XPATH_NUMBER);
8978     start = valuePop(ctxt);
8979     in = start->floatval;
8980     xmlXPathReleaseObject(ctxt->context, start);
8981     CAST_TO_STRING;
8982     CHECK_TYPE(XPATH_STRING);
8983     str = valuePop(ctxt);
8984     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8985 
8986     /*
8987      * If last pos not present, calculate last position
8988     */
8989     if (nargs != 3) {
8990 	le = (double)m;
8991 	if (in < 1.0)
8992 	    in = 1.0;
8993     }
8994 
8995     /* Need to check for the special cases where either
8996      * the index is NaN, the length is NaN, or both
8997      * arguments are infinity (relying on Inf + -Inf = NaN)
8998      */
8999     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
9000         /*
9001          * To meet the requirements of the spec, the arguments
9002 	 * must be converted to integer format before
9003 	 * initial index calculations are done
9004          *
9005          * First we go to integer form, rounding up
9006 	 * and checking for special cases
9007          */
9008         i = (int) in;
9009         if (((double)i)+0.5 <= in) i++;
9010 
9011 	if (xmlXPathIsInf(le) == 1) {
9012 	    l = m;
9013 	    if (i < 1)
9014 		i = 1;
9015 	}
9016 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9017 	    l = 0;
9018 	else {
9019 	    l = (int) le;
9020 	    if (((double)l)+0.5 <= le) l++;
9021 	}
9022 
9023 	/* Now we normalize inidices */
9024         i -= 1;
9025         l += i;
9026         if (i < 0)
9027             i = 0;
9028         if (l > m)
9029             l = m;
9030 
9031         /* number of chars to copy */
9032         l -= i;
9033 
9034         ret = xmlUTF8Strsub(str->stringval, i, l);
9035     }
9036     else {
9037         ret = NULL;
9038     }
9039     if (ret == NULL)
9040 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9041     else {
9042 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9043 	xmlFree(ret);
9044     }
9045     xmlXPathReleaseObject(ctxt->context, str);
9046 }
9047 
9048 /**
9049  * xmlXPathSubstringBeforeFunction:
9050  * @ctxt:  the XPath Parser context
9051  * @nargs:  the number of arguments
9052  *
9053  * Implement the substring-before() XPath function
9054  *    string substring-before(string, string)
9055  * The substring-before function returns the substring of the first
9056  * argument string that precedes the first occurrence of the second
9057  * argument string in the first argument string, or the empty string
9058  * if the first argument string does not contain the second argument
9059  * string. For example, substring-before("1999/04/01","/") returns 1999.
9060  */
9061 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9062 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9063   xmlXPathObjectPtr str;
9064   xmlXPathObjectPtr find;
9065   xmlBufferPtr target;
9066   const xmlChar *point;
9067   int offset;
9068 
9069   CHECK_ARITY(2);
9070   CAST_TO_STRING;
9071   find = valuePop(ctxt);
9072   CAST_TO_STRING;
9073   str = valuePop(ctxt);
9074 
9075   target = xmlBufferCreate();
9076   if (target) {
9077     point = xmlStrstr(str->stringval, find->stringval);
9078     if (point) {
9079       offset = (int)(point - str->stringval);
9080       xmlBufferAdd(target, str->stringval, offset);
9081     }
9082     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9083 	xmlBufferContent(target)));
9084     xmlBufferFree(target);
9085   }
9086   xmlXPathReleaseObject(ctxt->context, str);
9087   xmlXPathReleaseObject(ctxt->context, find);
9088 }
9089 
9090 /**
9091  * xmlXPathSubstringAfterFunction:
9092  * @ctxt:  the XPath Parser context
9093  * @nargs:  the number of arguments
9094  *
9095  * Implement the substring-after() XPath function
9096  *    string substring-after(string, string)
9097  * The substring-after function returns the substring of the first
9098  * argument string that follows the first occurrence of the second
9099  * argument string in the first argument string, or the empty stringi
9100  * if the first argument string does not contain the second argument
9101  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9102  * and substring-after("1999/04/01","19") returns 99/04/01.
9103  */
9104 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9105 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9106   xmlXPathObjectPtr str;
9107   xmlXPathObjectPtr find;
9108   xmlBufferPtr target;
9109   const xmlChar *point;
9110   int offset;
9111 
9112   CHECK_ARITY(2);
9113   CAST_TO_STRING;
9114   find = valuePop(ctxt);
9115   CAST_TO_STRING;
9116   str = valuePop(ctxt);
9117 
9118   target = xmlBufferCreate();
9119   if (target) {
9120     point = xmlStrstr(str->stringval, find->stringval);
9121     if (point) {
9122       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9123       xmlBufferAdd(target, &str->stringval[offset],
9124 		   xmlStrlen(str->stringval) - offset);
9125     }
9126     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9127 	xmlBufferContent(target)));
9128     xmlBufferFree(target);
9129   }
9130   xmlXPathReleaseObject(ctxt->context, str);
9131   xmlXPathReleaseObject(ctxt->context, find);
9132 }
9133 
9134 /**
9135  * xmlXPathNormalizeFunction:
9136  * @ctxt:  the XPath Parser context
9137  * @nargs:  the number of arguments
9138  *
9139  * Implement the normalize-space() XPath function
9140  *    string normalize-space(string?)
9141  * The normalize-space function returns the argument string with white
9142  * space normalized by stripping leading and trailing whitespace
9143  * and replacing sequences of whitespace characters by a single
9144  * space. Whitespace characters are the same allowed by the S production
9145  * in XML. If the argument is omitted, it defaults to the context
9146  * node converted to a string, in other words the value of the context node.
9147  */
9148 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9149 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9150   xmlXPathObjectPtr obj = NULL;
9151   xmlChar *source = NULL;
9152   xmlBufferPtr target;
9153   xmlChar blank;
9154 
9155   if (ctxt == NULL) return;
9156   if (nargs == 0) {
9157     /* Use current context node */
9158       valuePush(ctxt,
9159 	  xmlXPathCacheWrapString(ctxt->context,
9160 	    xmlXPathCastNodeToString(ctxt->context->node)));
9161     nargs = 1;
9162   }
9163 
9164   CHECK_ARITY(1);
9165   CAST_TO_STRING;
9166   CHECK_TYPE(XPATH_STRING);
9167   obj = valuePop(ctxt);
9168   source = obj->stringval;
9169 
9170   target = xmlBufferCreate();
9171   if (target && source) {
9172 
9173     /* Skip leading whitespaces */
9174     while (IS_BLANK_CH(*source))
9175       source++;
9176 
9177     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9178     blank = 0;
9179     while (*source) {
9180       if (IS_BLANK_CH(*source)) {
9181 	blank = 0x20;
9182       } else {
9183 	if (blank) {
9184 	  xmlBufferAdd(target, &blank, 1);
9185 	  blank = 0;
9186 	}
9187 	xmlBufferAdd(target, source, 1);
9188       }
9189       source++;
9190     }
9191     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9192 	xmlBufferContent(target)));
9193     xmlBufferFree(target);
9194   }
9195   xmlXPathReleaseObject(ctxt->context, obj);
9196 }
9197 
9198 /**
9199  * xmlXPathTranslateFunction:
9200  * @ctxt:  the XPath Parser context
9201  * @nargs:  the number of arguments
9202  *
9203  * Implement the translate() XPath function
9204  *    string translate(string, string, string)
9205  * The translate function returns the first argument string with
9206  * occurrences of characters in the second argument string replaced
9207  * by the character at the corresponding position in the third argument
9208  * string. For example, translate("bar","abc","ABC") returns the string
9209  * BAr. If there is a character in the second argument string with no
9210  * character at a corresponding position in the third argument string
9211  * (because the second argument string is longer than the third argument
9212  * string), then occurrences of that character in the first argument
9213  * string are removed. For example, translate("--aaa--","abc-","ABC")
9214  * returns "AAA". If a character occurs more than once in second
9215  * argument string, then the first occurrence determines the replacement
9216  * character. If the third argument string is longer than the second
9217  * argument string, then excess characters are ignored.
9218  */
9219 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9220 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9221     xmlXPathObjectPtr str;
9222     xmlXPathObjectPtr from;
9223     xmlXPathObjectPtr to;
9224     xmlBufferPtr target;
9225     int offset, max;
9226     xmlChar ch;
9227     const xmlChar *point;
9228     xmlChar *cptr;
9229 
9230     CHECK_ARITY(3);
9231 
9232     CAST_TO_STRING;
9233     to = valuePop(ctxt);
9234     CAST_TO_STRING;
9235     from = valuePop(ctxt);
9236     CAST_TO_STRING;
9237     str = valuePop(ctxt);
9238 
9239     target = xmlBufferCreate();
9240     if (target) {
9241 	max = xmlUTF8Strlen(to->stringval);
9242 	for (cptr = str->stringval; (ch=*cptr); ) {
9243 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9244 	    if (offset >= 0) {
9245 		if (offset < max) {
9246 		    point = xmlUTF8Strpos(to->stringval, offset);
9247 		    if (point)
9248 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9249 		}
9250 	    } else
9251 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9252 
9253 	    /* Step to next character in input */
9254 	    cptr++;
9255 	    if ( ch & 0x80 ) {
9256 		/* if not simple ascii, verify proper format */
9257 		if ( (ch & 0xc0) != 0xc0 ) {
9258 		    xmlGenericError(xmlGenericErrorContext,
9259 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9260 		    break;
9261 		}
9262 		/* then skip over remaining bytes for this char */
9263 		while ( (ch <<= 1) & 0x80 )
9264 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9265 			xmlGenericError(xmlGenericErrorContext,
9266 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9267 			break;
9268 		    }
9269 		if (ch & 0x80) /* must have had error encountered */
9270 		    break;
9271 	    }
9272 	}
9273     }
9274     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9275 	xmlBufferContent(target)));
9276     xmlBufferFree(target);
9277     xmlXPathReleaseObject(ctxt->context, str);
9278     xmlXPathReleaseObject(ctxt->context, from);
9279     xmlXPathReleaseObject(ctxt->context, to);
9280 }
9281 
9282 /**
9283  * xmlXPathBooleanFunction:
9284  * @ctxt:  the XPath Parser context
9285  * @nargs:  the number of arguments
9286  *
9287  * Implement the boolean() XPath function
9288  *    boolean boolean(object)
9289  * The boolean function converts its argument to a boolean as follows:
9290  *    - a number is true if and only if it is neither positive or
9291  *      negative zero nor NaN
9292  *    - a node-set is true if and only if it is non-empty
9293  *    - a string is true if and only if its length is non-zero
9294  */
9295 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9296 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9297     xmlXPathObjectPtr cur;
9298 
9299     CHECK_ARITY(1);
9300     cur = valuePop(ctxt);
9301     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9302     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9303     valuePush(ctxt, cur);
9304 }
9305 
9306 /**
9307  * xmlXPathNotFunction:
9308  * @ctxt:  the XPath Parser context
9309  * @nargs:  the number of arguments
9310  *
9311  * Implement the not() XPath function
9312  *    boolean not(boolean)
9313  * The not function returns true if its argument is false,
9314  * and false otherwise.
9315  */
9316 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9317 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9318     CHECK_ARITY(1);
9319     CAST_TO_BOOLEAN;
9320     CHECK_TYPE(XPATH_BOOLEAN);
9321     ctxt->value->boolval = ! ctxt->value->boolval;
9322 }
9323 
9324 /**
9325  * xmlXPathTrueFunction:
9326  * @ctxt:  the XPath Parser context
9327  * @nargs:  the number of arguments
9328  *
9329  * Implement the true() XPath function
9330  *    boolean true()
9331  */
9332 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9333 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334     CHECK_ARITY(0);
9335     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9336 }
9337 
9338 /**
9339  * xmlXPathFalseFunction:
9340  * @ctxt:  the XPath Parser context
9341  * @nargs:  the number of arguments
9342  *
9343  * Implement the false() XPath function
9344  *    boolean false()
9345  */
9346 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9347 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9348     CHECK_ARITY(0);
9349     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9350 }
9351 
9352 /**
9353  * xmlXPathLangFunction:
9354  * @ctxt:  the XPath Parser context
9355  * @nargs:  the number of arguments
9356  *
9357  * Implement the lang() XPath function
9358  *    boolean lang(string)
9359  * The lang function returns true or false depending on whether the
9360  * language of the context node as specified by xml:lang attributes
9361  * is the same as or is a sublanguage of the language specified by
9362  * the argument string. The language of the context node is determined
9363  * by the value of the xml:lang attribute on the context node, or, if
9364  * the context node has no xml:lang attribute, by the value of the
9365  * xml:lang attribute on the nearest ancestor of the context node that
9366  * has an xml:lang attribute. If there is no such attribute, then lang
9367  * returns false. If there is such an attribute, then lang returns
9368  * true if the attribute value is equal to the argument ignoring case,
9369  * or if there is some suffix starting with - such that the attribute
9370  * value is equal to the argument ignoring that suffix of the attribute
9371  * value and ignoring case.
9372  */
9373 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9374 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9375     xmlXPathObjectPtr val = NULL;
9376     const xmlChar *theLang = NULL;
9377     const xmlChar *lang;
9378     int ret = 0;
9379     int i;
9380 
9381     CHECK_ARITY(1);
9382     CAST_TO_STRING;
9383     CHECK_TYPE(XPATH_STRING);
9384     val = valuePop(ctxt);
9385     lang = val->stringval;
9386     theLang = xmlNodeGetLang(ctxt->context->node);
9387     if ((theLang != NULL) && (lang != NULL)) {
9388         for (i = 0;lang[i] != 0;i++)
9389 	    if (toupper(lang[i]) != toupper(theLang[i]))
9390 	        goto not_equal;
9391 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9392 	    ret = 1;
9393     }
9394 not_equal:
9395     if (theLang != NULL)
9396 	xmlFree((void *)theLang);
9397 
9398     xmlXPathReleaseObject(ctxt->context, val);
9399     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9400 }
9401 
9402 /**
9403  * xmlXPathNumberFunction:
9404  * @ctxt:  the XPath Parser context
9405  * @nargs:  the number of arguments
9406  *
9407  * Implement the number() XPath function
9408  *    number number(object?)
9409  */
9410 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9411 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412     xmlXPathObjectPtr cur;
9413     double res;
9414 
9415     if (ctxt == NULL) return;
9416     if (nargs == 0) {
9417 	if (ctxt->context->node == NULL) {
9418 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9419 	} else {
9420 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9421 
9422 	    res = xmlXPathStringEvalNumber(content);
9423 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9424 	    xmlFree(content);
9425 	}
9426 	return;
9427     }
9428 
9429     CHECK_ARITY(1);
9430     cur = valuePop(ctxt);
9431     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9432 }
9433 
9434 /**
9435  * xmlXPathSumFunction:
9436  * @ctxt:  the XPath Parser context
9437  * @nargs:  the number of arguments
9438  *
9439  * Implement the sum() XPath function
9440  *    number sum(node-set)
9441  * The sum function returns the sum of the values of the nodes in
9442  * the argument node-set.
9443  */
9444 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9445 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9446     xmlXPathObjectPtr cur;
9447     int i;
9448     double res = 0.0;
9449 
9450     CHECK_ARITY(1);
9451     if ((ctxt->value == NULL) ||
9452 	((ctxt->value->type != XPATH_NODESET) &&
9453 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9454 	XP_ERROR(XPATH_INVALID_TYPE);
9455     cur = valuePop(ctxt);
9456 
9457     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9458 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9459 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9460 	}
9461     }
9462     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9463     xmlXPathReleaseObject(ctxt->context, cur);
9464 }
9465 
9466 /*
9467  * To assure working code on multiple platforms, we want to only depend
9468  * upon the characteristic truncation of converting a floating point value
9469  * to an integer.  Unfortunately, because of the different storage sizes
9470  * of our internal floating point value (double) and integer (int), we
9471  * can't directly convert (see bug 301162).  This macro is a messy
9472  * 'workaround'
9473  */
9474 #define XTRUNC(f, v)            \
9475     f = fmod((v), INT_MAX);     \
9476     f = (v) - (f) + (double)((int)(f));
9477 
9478 /**
9479  * xmlXPathFloorFunction:
9480  * @ctxt:  the XPath Parser context
9481  * @nargs:  the number of arguments
9482  *
9483  * Implement the floor() XPath function
9484  *    number floor(number)
9485  * The floor function returns the largest (closest to positive infinity)
9486  * number that is not greater than the argument and that is an integer.
9487  */
9488 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9489 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490     double f;
9491 
9492     CHECK_ARITY(1);
9493     CAST_TO_NUMBER;
9494     CHECK_TYPE(XPATH_NUMBER);
9495 
9496     XTRUNC(f, ctxt->value->floatval);
9497     if (f != ctxt->value->floatval) {
9498 	if (ctxt->value->floatval > 0)
9499 	    ctxt->value->floatval = f;
9500 	else
9501 	    ctxt->value->floatval = f - 1;
9502     }
9503 }
9504 
9505 /**
9506  * xmlXPathCeilingFunction:
9507  * @ctxt:  the XPath Parser context
9508  * @nargs:  the number of arguments
9509  *
9510  * Implement the ceiling() XPath function
9511  *    number ceiling(number)
9512  * The ceiling function returns the smallest (closest to negative infinity)
9513  * number that is not less than the argument and that is an integer.
9514  */
9515 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9516 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9517     double f;
9518 
9519     CHECK_ARITY(1);
9520     CAST_TO_NUMBER;
9521     CHECK_TYPE(XPATH_NUMBER);
9522 
9523 #if 0
9524     ctxt->value->floatval = ceil(ctxt->value->floatval);
9525 #else
9526     XTRUNC(f, ctxt->value->floatval);
9527     if (f != ctxt->value->floatval) {
9528 	if (ctxt->value->floatval > 0)
9529 	    ctxt->value->floatval = f + 1;
9530 	else {
9531 	    if (ctxt->value->floatval < 0 && f == 0)
9532 	        ctxt->value->floatval = xmlXPathNZERO;
9533 	    else
9534 	        ctxt->value->floatval = f;
9535 	}
9536 
9537     }
9538 #endif
9539 }
9540 
9541 /**
9542  * xmlXPathRoundFunction:
9543  * @ctxt:  the XPath Parser context
9544  * @nargs:  the number of arguments
9545  *
9546  * Implement the round() XPath function
9547  *    number round(number)
9548  * The round function returns the number that is closest to the
9549  * argument and that is an integer. If there are two such numbers,
9550  * then the one that is even is returned.
9551  */
9552 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9553 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9554     double f;
9555 
9556     CHECK_ARITY(1);
9557     CAST_TO_NUMBER;
9558     CHECK_TYPE(XPATH_NUMBER);
9559 
9560     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9561 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9562 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9563 	(ctxt->value->floatval == 0.0))
9564 	return;
9565 
9566     XTRUNC(f, ctxt->value->floatval);
9567     if (ctxt->value->floatval < 0) {
9568 	if (ctxt->value->floatval < f - 0.5)
9569 	    ctxt->value->floatval = f - 1;
9570 	else
9571 	    ctxt->value->floatval = f;
9572 	if (ctxt->value->floatval == 0)
9573 	    ctxt->value->floatval = xmlXPathNZERO;
9574     } else {
9575 	if (ctxt->value->floatval < f + 0.5)
9576 	    ctxt->value->floatval = f;
9577 	else
9578 	    ctxt->value->floatval = f + 1;
9579     }
9580 }
9581 
9582 /************************************************************************
9583  *									*
9584  *			The Parser					*
9585  *									*
9586  ************************************************************************/
9587 
9588 /*
9589  * a few forward declarations since we use a recursive call based
9590  * implementation.
9591  */
9592 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9593 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9594 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9595 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9596 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9597 	                                  int qualified);
9598 
9599 /**
9600  * xmlXPathCurrentChar:
9601  * @ctxt:  the XPath parser context
9602  * @cur:  pointer to the beginning of the char
9603  * @len:  pointer to the length of the char read
9604  *
9605  * The current char value, if using UTF-8 this may actually span multiple
9606  * bytes in the input buffer.
9607  *
9608  * Returns the current char value and its length
9609  */
9610 
9611 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9612 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9613     unsigned char c;
9614     unsigned int val;
9615     const xmlChar *cur;
9616 
9617     if (ctxt == NULL)
9618 	return(0);
9619     cur = ctxt->cur;
9620 
9621     /*
9622      * We are supposed to handle UTF8, check it's valid
9623      * From rfc2044: encoding of the Unicode values on UTF-8:
9624      *
9625      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9626      * 0000 0000-0000 007F   0xxxxxxx
9627      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9628      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9629      *
9630      * Check for the 0x110000 limit too
9631      */
9632     c = *cur;
9633     if (c & 0x80) {
9634 	if ((cur[1] & 0xc0) != 0x80)
9635 	    goto encoding_error;
9636 	if ((c & 0xe0) == 0xe0) {
9637 
9638 	    if ((cur[2] & 0xc0) != 0x80)
9639 		goto encoding_error;
9640 	    if ((c & 0xf0) == 0xf0) {
9641 		if (((c & 0xf8) != 0xf0) ||
9642 		    ((cur[3] & 0xc0) != 0x80))
9643 		    goto encoding_error;
9644 		/* 4-byte code */
9645 		*len = 4;
9646 		val = (cur[0] & 0x7) << 18;
9647 		val |= (cur[1] & 0x3f) << 12;
9648 		val |= (cur[2] & 0x3f) << 6;
9649 		val |= cur[3] & 0x3f;
9650 	    } else {
9651 	      /* 3-byte code */
9652 		*len = 3;
9653 		val = (cur[0] & 0xf) << 12;
9654 		val |= (cur[1] & 0x3f) << 6;
9655 		val |= cur[2] & 0x3f;
9656 	    }
9657 	} else {
9658 	  /* 2-byte code */
9659 	    *len = 2;
9660 	    val = (cur[0] & 0x1f) << 6;
9661 	    val |= cur[1] & 0x3f;
9662 	}
9663 	if (!IS_CHAR(val)) {
9664 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9665 	}
9666 	return(val);
9667     } else {
9668 	/* 1-byte code */
9669 	*len = 1;
9670 	return((int) *cur);
9671     }
9672 encoding_error:
9673     /*
9674      * If we detect an UTF8 error that probably means that the
9675      * input encoding didn't get properly advertised in the
9676      * declaration header. Report the error and switch the encoding
9677      * to ISO-Latin-1 (if you don't like this policy, just declare the
9678      * encoding !)
9679      */
9680     *len = 0;
9681     XP_ERROR0(XPATH_ENCODING_ERROR);
9682 }
9683 
9684 /**
9685  * xmlXPathParseNCName:
9686  * @ctxt:  the XPath Parser context
9687  *
9688  * parse an XML namespace non qualified name.
9689  *
9690  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9691  *
9692  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9693  *                       CombiningChar | Extender
9694  *
9695  * Returns the namespace name or NULL
9696  */
9697 
9698 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9699 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9700     const xmlChar *in;
9701     xmlChar *ret;
9702     int count = 0;
9703 
9704     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9705     /*
9706      * Accelerator for simple ASCII names
9707      */
9708     in = ctxt->cur;
9709     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9710 	((*in >= 0x41) && (*in <= 0x5A)) ||
9711 	(*in == '_')) {
9712 	in++;
9713 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9714 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9715 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9716 	       (*in == '_') || (*in == '.') ||
9717 	       (*in == '-'))
9718 	    in++;
9719 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9720             (*in == '[') || (*in == ']') || (*in == ':') ||
9721             (*in == '@') || (*in == '*')) {
9722 	    count = in - ctxt->cur;
9723 	    if (count == 0)
9724 		return(NULL);
9725 	    ret = xmlStrndup(ctxt->cur, count);
9726 	    ctxt->cur = in;
9727 	    return(ret);
9728 	}
9729     }
9730     return(xmlXPathParseNameComplex(ctxt, 0));
9731 }
9732 
9733 
9734 /**
9735  * xmlXPathParseQName:
9736  * @ctxt:  the XPath Parser context
9737  * @prefix:  a xmlChar **
9738  *
9739  * parse an XML qualified name
9740  *
9741  * [NS 5] QName ::= (Prefix ':')? LocalPart
9742  *
9743  * [NS 6] Prefix ::= NCName
9744  *
9745  * [NS 7] LocalPart ::= NCName
9746  *
9747  * Returns the function returns the local part, and prefix is updated
9748  *   to get the Prefix if any.
9749  */
9750 
9751 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9752 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9753     xmlChar *ret = NULL;
9754 
9755     *prefix = NULL;
9756     ret = xmlXPathParseNCName(ctxt);
9757     if (CUR == ':') {
9758         *prefix = ret;
9759 	NEXT;
9760 	ret = xmlXPathParseNCName(ctxt);
9761     }
9762     return(ret);
9763 }
9764 
9765 /**
9766  * xmlXPathParseName:
9767  * @ctxt:  the XPath Parser context
9768  *
9769  * parse an XML name
9770  *
9771  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9772  *                  CombiningChar | Extender
9773  *
9774  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9775  *
9776  * Returns the namespace name or NULL
9777  */
9778 
9779 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9780 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9781     const xmlChar *in;
9782     xmlChar *ret;
9783     int count = 0;
9784 
9785     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9786     /*
9787      * Accelerator for simple ASCII names
9788      */
9789     in = ctxt->cur;
9790     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9791 	((*in >= 0x41) && (*in <= 0x5A)) ||
9792 	(*in == '_') || (*in == ':')) {
9793 	in++;
9794 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9795 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9796 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9797 	       (*in == '_') || (*in == '-') ||
9798 	       (*in == ':') || (*in == '.'))
9799 	    in++;
9800 	if ((*in > 0) && (*in < 0x80)) {
9801 	    count = in - ctxt->cur;
9802 	    ret = xmlStrndup(ctxt->cur, count);
9803 	    ctxt->cur = in;
9804 	    return(ret);
9805 	}
9806     }
9807     return(xmlXPathParseNameComplex(ctxt, 1));
9808 }
9809 
9810 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9811 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9812     xmlChar buf[XML_MAX_NAMELEN + 5];
9813     int len = 0, l;
9814     int c;
9815 
9816     /*
9817      * Handler for more complex cases
9818      */
9819     c = CUR_CHAR(l);
9820     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9821         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9822         (c == '*') || /* accelerators */
9823 	(!IS_LETTER(c) && (c != '_') &&
9824          ((qualified) && (c != ':')))) {
9825 	return(NULL);
9826     }
9827 
9828     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9829 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9830             (c == '.') || (c == '-') ||
9831 	    (c == '_') || ((qualified) && (c == ':')) ||
9832 	    (IS_COMBINING(c)) ||
9833 	    (IS_EXTENDER(c)))) {
9834 	COPY_BUF(l,buf,len,c);
9835 	NEXTL(l);
9836 	c = CUR_CHAR(l);
9837 	if (len >= XML_MAX_NAMELEN) {
9838 	    /*
9839 	     * Okay someone managed to make a huge name, so he's ready to pay
9840 	     * for the processing speed.
9841 	     */
9842 	    xmlChar *buffer;
9843 	    int max = len * 2;
9844 
9845 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9846 	    if (buffer == NULL) {
9847 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9848 	    }
9849 	    memcpy(buffer, buf, len);
9850 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9851 		   (c == '.') || (c == '-') ||
9852 		   (c == '_') || ((qualified) && (c == ':')) ||
9853 		   (IS_COMBINING(c)) ||
9854 		   (IS_EXTENDER(c))) {
9855 		if (len + 10 > max) {
9856 		    max *= 2;
9857 		    buffer = (xmlChar *) xmlRealloc(buffer,
9858 			                            max * sizeof(xmlChar));
9859 		    if (buffer == NULL) {
9860 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9861 		    }
9862 		}
9863 		COPY_BUF(l,buffer,len,c);
9864 		NEXTL(l);
9865 		c = CUR_CHAR(l);
9866 	    }
9867 	    buffer[len] = 0;
9868 	    return(buffer);
9869 	}
9870     }
9871     if (len == 0)
9872 	return(NULL);
9873     return(xmlStrndup(buf, len));
9874 }
9875 
9876 #define MAX_FRAC 20
9877 
9878 /*
9879  * These are used as divisors for the fractional part of a number.
9880  * Since the table includes 1.0 (representing '0' fractional digits),
9881  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9882  */
9883 static double my_pow10[MAX_FRAC+1] = {
9884     1.0, 10.0, 100.0, 1000.0, 10000.0,
9885     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9886     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9887     100000000000000.0,
9888     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9889     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9890 };
9891 
9892 /**
9893  * xmlXPathStringEvalNumber:
9894  * @str:  A string to scan
9895  *
9896  *  [30a]  Float  ::= Number ('e' Digits?)?
9897  *
9898  *  [30]   Number ::=   Digits ('.' Digits?)?
9899  *                    | '.' Digits
9900  *  [31]   Digits ::=   [0-9]+
9901  *
9902  * Compile a Number in the string
9903  * In complement of the Number expression, this function also handles
9904  * negative values : '-' Number.
9905  *
9906  * Returns the double value.
9907  */
9908 double
xmlXPathStringEvalNumber(const xmlChar * str)9909 xmlXPathStringEvalNumber(const xmlChar *str) {
9910     const xmlChar *cur = str;
9911     double ret;
9912     int ok = 0;
9913     int isneg = 0;
9914     int exponent = 0;
9915     int is_exponent_negative = 0;
9916 #ifdef __GNUC__
9917     unsigned long tmp = 0;
9918     double temp;
9919 #endif
9920     if (cur == NULL) return(0);
9921     while (IS_BLANK_CH(*cur)) cur++;
9922     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9923         return(xmlXPathNAN);
9924     }
9925     if (*cur == '-') {
9926 	isneg = 1;
9927 	cur++;
9928     }
9929 
9930 #ifdef __GNUC__
9931     /*
9932      * tmp/temp is a workaround against a gcc compiler bug
9933      * http://veillard.com/gcc.bug
9934      */
9935     ret = 0;
9936     while ((*cur >= '0') && (*cur <= '9')) {
9937 	ret = ret * 10;
9938 	tmp = (*cur - '0');
9939 	ok = 1;
9940 	cur++;
9941 	temp = (double) tmp;
9942 	ret = ret + temp;
9943     }
9944 #else
9945     ret = 0;
9946     while ((*cur >= '0') && (*cur <= '9')) {
9947 	ret = ret * 10 + (*cur - '0');
9948 	ok = 1;
9949 	cur++;
9950     }
9951 #endif
9952 
9953     if (*cur == '.') {
9954 	int v, frac = 0;
9955 	double fraction = 0;
9956 
9957         cur++;
9958 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9959 	    return(xmlXPathNAN);
9960 	}
9961 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9962 	    v = (*cur - '0');
9963 	    fraction = fraction * 10 + v;
9964 	    frac = frac + 1;
9965 	    cur++;
9966 	}
9967 	fraction /= my_pow10[frac];
9968 	ret = ret + fraction;
9969 	while ((*cur >= '0') && (*cur <= '9'))
9970 	    cur++;
9971     }
9972     if ((*cur == 'e') || (*cur == 'E')) {
9973       cur++;
9974       if (*cur == '-') {
9975 	is_exponent_negative = 1;
9976 	cur++;
9977       } else if (*cur == '+') {
9978         cur++;
9979       }
9980       while ((*cur >= '0') && (*cur <= '9')) {
9981 	exponent = exponent * 10 + (*cur - '0');
9982 	cur++;
9983       }
9984     }
9985     while (IS_BLANK_CH(*cur)) cur++;
9986     if (*cur != 0) return(xmlXPathNAN);
9987     if (isneg) ret = -ret;
9988     if (is_exponent_negative) exponent = -exponent;
9989     ret *= pow(10.0, (double)exponent);
9990     return(ret);
9991 }
9992 
9993 /**
9994  * xmlXPathCompNumber:
9995  * @ctxt:  the XPath Parser context
9996  *
9997  *  [30]   Number ::=   Digits ('.' Digits?)?
9998  *                    | '.' Digits
9999  *  [31]   Digits ::=   [0-9]+
10000  *
10001  * Compile a Number, then push it on the stack
10002  *
10003  */
10004 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10005 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10006 {
10007     double ret = 0.0;
10008     double mult = 1;
10009     int ok = 0;
10010     int exponent = 0;
10011     int is_exponent_negative = 0;
10012 #ifdef __GNUC__
10013     unsigned long tmp = 0;
10014     double temp;
10015 #endif
10016 
10017     CHECK_ERROR;
10018     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10019         XP_ERROR(XPATH_NUMBER_ERROR);
10020     }
10021 #ifdef __GNUC__
10022     /*
10023      * tmp/temp is a workaround against a gcc compiler bug
10024      * http://veillard.com/gcc.bug
10025      */
10026     ret = 0;
10027     while ((CUR >= '0') && (CUR <= '9')) {
10028 	ret = ret * 10;
10029 	tmp = (CUR - '0');
10030         ok = 1;
10031         NEXT;
10032 	temp = (double) tmp;
10033 	ret = ret + temp;
10034     }
10035 #else
10036     ret = 0;
10037     while ((CUR >= '0') && (CUR <= '9')) {
10038 	ret = ret * 10 + (CUR - '0');
10039 	ok = 1;
10040 	NEXT;
10041     }
10042 #endif
10043     if (CUR == '.') {
10044         NEXT;
10045         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10046             XP_ERROR(XPATH_NUMBER_ERROR);
10047         }
10048         while ((CUR >= '0') && (CUR <= '9')) {
10049             mult /= 10;
10050             ret = ret + (CUR - '0') * mult;
10051             NEXT;
10052         }
10053     }
10054     if ((CUR == 'e') || (CUR == 'E')) {
10055         NEXT;
10056         if (CUR == '-') {
10057             is_exponent_negative = 1;
10058             NEXT;
10059         } else if (CUR == '+') {
10060 	    NEXT;
10061 	}
10062         while ((CUR >= '0') && (CUR <= '9')) {
10063             exponent = exponent * 10 + (CUR - '0');
10064             NEXT;
10065         }
10066         if (is_exponent_negative)
10067             exponent = -exponent;
10068         ret *= pow(10.0, (double) exponent);
10069     }
10070     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10071                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10072 }
10073 
10074 /**
10075  * xmlXPathParseLiteral:
10076  * @ctxt:  the XPath Parser context
10077  *
10078  * Parse a Literal
10079  *
10080  *  [29]   Literal ::=   '"' [^"]* '"'
10081  *                    | "'" [^']* "'"
10082  *
10083  * Returns the value found or NULL in case of error
10084  */
10085 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10086 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10087     const xmlChar *q;
10088     xmlChar *ret = NULL;
10089 
10090     if (CUR == '"') {
10091         NEXT;
10092 	q = CUR_PTR;
10093 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10094 	    NEXT;
10095 	if (!IS_CHAR_CH(CUR)) {
10096 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10097 	} else {
10098 	    ret = xmlStrndup(q, CUR_PTR - q);
10099 	    NEXT;
10100         }
10101     } else if (CUR == '\'') {
10102         NEXT;
10103 	q = CUR_PTR;
10104 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10105 	    NEXT;
10106 	if (!IS_CHAR_CH(CUR)) {
10107 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10108 	} else {
10109 	    ret = xmlStrndup(q, CUR_PTR - q);
10110 	    NEXT;
10111         }
10112     } else {
10113 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10114     }
10115     return(ret);
10116 }
10117 
10118 /**
10119  * xmlXPathCompLiteral:
10120  * @ctxt:  the XPath Parser context
10121  *
10122  * Parse a Literal and push it on the stack.
10123  *
10124  *  [29]   Literal ::=   '"' [^"]* '"'
10125  *                    | "'" [^']* "'"
10126  *
10127  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10128  */
10129 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10130 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10131     const xmlChar *q;
10132     xmlChar *ret = NULL;
10133 
10134     if (CUR == '"') {
10135         NEXT;
10136 	q = CUR_PTR;
10137 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10138 	    NEXT;
10139 	if (!IS_CHAR_CH(CUR)) {
10140 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10141 	} else {
10142 	    ret = xmlStrndup(q, CUR_PTR - q);
10143 	    NEXT;
10144         }
10145     } else if (CUR == '\'') {
10146         NEXT;
10147 	q = CUR_PTR;
10148 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10149 	    NEXT;
10150 	if (!IS_CHAR_CH(CUR)) {
10151 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10152 	} else {
10153 	    ret = xmlStrndup(q, CUR_PTR - q);
10154 	    NEXT;
10155         }
10156     } else {
10157 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10158     }
10159     if (ret == NULL) return;
10160     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10161 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10162     xmlFree(ret);
10163 }
10164 
10165 /**
10166  * xmlXPathCompVariableReference:
10167  * @ctxt:  the XPath Parser context
10168  *
10169  * Parse a VariableReference, evaluate it and push it on the stack.
10170  *
10171  * The variable bindings consist of a mapping from variable names
10172  * to variable values. The value of a variable is an object, which can be
10173  * of any of the types that are possible for the value of an expression,
10174  * and may also be of additional types not specified here.
10175  *
10176  * Early evaluation is possible since:
10177  * The variable bindings [...] used to evaluate a subexpression are
10178  * always the same as those used to evaluate the containing expression.
10179  *
10180  *  [36]   VariableReference ::=   '$' QName
10181  */
10182 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10183 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10184     xmlChar *name;
10185     xmlChar *prefix;
10186 
10187     SKIP_BLANKS;
10188     if (CUR != '$') {
10189 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10190     }
10191     NEXT;
10192     name = xmlXPathParseQName(ctxt, &prefix);
10193     if (name == NULL) {
10194 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10195     }
10196     ctxt->comp->last = -1;
10197     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10198 	           name, prefix);
10199     SKIP_BLANKS;
10200     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10201 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10202     }
10203 }
10204 
10205 /**
10206  * xmlXPathIsNodeType:
10207  * @name:  a name string
10208  *
10209  * Is the name given a NodeType one.
10210  *
10211  *  [38]   NodeType ::=   'comment'
10212  *                    | 'text'
10213  *                    | 'processing-instruction'
10214  *                    | 'node'
10215  *
10216  * Returns 1 if true 0 otherwise
10217  */
10218 int
xmlXPathIsNodeType(const xmlChar * name)10219 xmlXPathIsNodeType(const xmlChar *name) {
10220     if (name == NULL)
10221 	return(0);
10222 
10223     if (xmlStrEqual(name, BAD_CAST "node"))
10224 	return(1);
10225     if (xmlStrEqual(name, BAD_CAST "text"))
10226 	return(1);
10227     if (xmlStrEqual(name, BAD_CAST "comment"))
10228 	return(1);
10229     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10230 	return(1);
10231     return(0);
10232 }
10233 
10234 /**
10235  * xmlXPathCompFunctionCall:
10236  * @ctxt:  the XPath Parser context
10237  *
10238  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10239  *  [17]   Argument ::=   Expr
10240  *
10241  * Compile a function call, the evaluation of all arguments are
10242  * pushed on the stack
10243  */
10244 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10245 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10246     xmlChar *name;
10247     xmlChar *prefix;
10248     int nbargs = 0;
10249     int sort = 1;
10250 
10251     name = xmlXPathParseQName(ctxt, &prefix);
10252     if (name == NULL) {
10253 	XP_ERROR(XPATH_EXPR_ERROR);
10254     }
10255     SKIP_BLANKS;
10256 #ifdef DEBUG_EXPR
10257     if (prefix == NULL)
10258 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10259 			name);
10260     else
10261 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10262 			prefix, name);
10263 #endif
10264 
10265     if (CUR != '(') {
10266 	XP_ERROR(XPATH_EXPR_ERROR);
10267     }
10268     NEXT;
10269     SKIP_BLANKS;
10270 
10271     /*
10272     * Optimization for count(): we don't need the node-set to be sorted.
10273     */
10274     if ((prefix == NULL) && (name[0] == 'c') &&
10275 	xmlStrEqual(name, BAD_CAST "count"))
10276     {
10277 	sort = 0;
10278     }
10279     ctxt->comp->last = -1;
10280     if (CUR != ')') {
10281 	while (CUR != 0) {
10282 	    int op1 = ctxt->comp->last;
10283 	    ctxt->comp->last = -1;
10284 	    xmlXPathCompileExpr(ctxt, sort);
10285 	    CHECK_ERROR;
10286 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10287 	    nbargs++;
10288 	    if (CUR == ')') break;
10289 	    if (CUR != ',') {
10290 		XP_ERROR(XPATH_EXPR_ERROR);
10291 	    }
10292 	    NEXT;
10293 	    SKIP_BLANKS;
10294 	}
10295     }
10296     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10297 	           name, prefix);
10298     NEXT;
10299     SKIP_BLANKS;
10300 }
10301 
10302 /**
10303  * xmlXPathCompPrimaryExpr:
10304  * @ctxt:  the XPath Parser context
10305  *
10306  *  [15]   PrimaryExpr ::=   VariableReference
10307  *                | '(' Expr ')'
10308  *                | Literal
10309  *                | Number
10310  *                | FunctionCall
10311  *
10312  * Compile a primary expression.
10313  */
10314 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10315 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10316     SKIP_BLANKS;
10317     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10318     else if (CUR == '(') {
10319 	NEXT;
10320 	SKIP_BLANKS;
10321 	xmlXPathCompileExpr(ctxt, 1);
10322 	CHECK_ERROR;
10323 	if (CUR != ')') {
10324 	    XP_ERROR(XPATH_EXPR_ERROR);
10325 	}
10326 	NEXT;
10327 	SKIP_BLANKS;
10328     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10329 	xmlXPathCompNumber(ctxt);
10330     } else if ((CUR == '\'') || (CUR == '"')) {
10331 	xmlXPathCompLiteral(ctxt);
10332     } else {
10333 	xmlXPathCompFunctionCall(ctxt);
10334     }
10335     SKIP_BLANKS;
10336 }
10337 
10338 /**
10339  * xmlXPathCompFilterExpr:
10340  * @ctxt:  the XPath Parser context
10341  *
10342  *  [20]   FilterExpr ::=   PrimaryExpr
10343  *               | FilterExpr Predicate
10344  *
10345  * Compile a filter expression.
10346  * Square brackets are used to filter expressions in the same way that
10347  * they are used in location paths. It is an error if the expression to
10348  * be filtered does not evaluate to a node-set. The context node list
10349  * used for evaluating the expression in square brackets is the node-set
10350  * to be filtered listed in document order.
10351  */
10352 
10353 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10354 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10355     xmlXPathCompPrimaryExpr(ctxt);
10356     CHECK_ERROR;
10357     SKIP_BLANKS;
10358 
10359     while (CUR == '[') {
10360 	xmlXPathCompPredicate(ctxt, 1);
10361 	SKIP_BLANKS;
10362     }
10363 
10364 
10365 }
10366 
10367 /**
10368  * xmlXPathScanName:
10369  * @ctxt:  the XPath Parser context
10370  *
10371  * Trickery: parse an XML name but without consuming the input flow
10372  * Needed to avoid insanity in the parser state.
10373  *
10374  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10375  *                  CombiningChar | Extender
10376  *
10377  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10378  *
10379  * [6] Names ::= Name (S Name)*
10380  *
10381  * Returns the Name parsed or NULL
10382  */
10383 
10384 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10385 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10386     int len = 0, l;
10387     int c;
10388     const xmlChar *cur;
10389     xmlChar *ret;
10390 
10391     cur = ctxt->cur;
10392 
10393     c = CUR_CHAR(l);
10394     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10395 	(!IS_LETTER(c) && (c != '_') &&
10396          (c != ':'))) {
10397 	return(NULL);
10398     }
10399 
10400     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10401 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10402             (c == '.') || (c == '-') ||
10403 	    (c == '_') || (c == ':') ||
10404 	    (IS_COMBINING(c)) ||
10405 	    (IS_EXTENDER(c)))) {
10406 	len += l;
10407 	NEXTL(l);
10408 	c = CUR_CHAR(l);
10409     }
10410     ret = xmlStrndup(cur, ctxt->cur - cur);
10411     ctxt->cur = cur;
10412     return(ret);
10413 }
10414 
10415 /**
10416  * xmlXPathCompPathExpr:
10417  * @ctxt:  the XPath Parser context
10418  *
10419  *  [19]   PathExpr ::=   LocationPath
10420  *               | FilterExpr
10421  *               | FilterExpr '/' RelativeLocationPath
10422  *               | FilterExpr '//' RelativeLocationPath
10423  *
10424  * Compile a path expression.
10425  * The / operator and // operators combine an arbitrary expression
10426  * and a relative location path. It is an error if the expression
10427  * does not evaluate to a node-set.
10428  * The / operator does composition in the same way as when / is
10429  * used in a location path. As in location paths, // is short for
10430  * /descendant-or-self::node()/.
10431  */
10432 
10433 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10434 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10435     int lc = 1;           /* Should we branch to LocationPath ?         */
10436     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10437 
10438     SKIP_BLANKS;
10439     if ((CUR == '$') || (CUR == '(') ||
10440     	(IS_ASCII_DIGIT(CUR)) ||
10441         (CUR == '\'') || (CUR == '"') ||
10442 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10443 	lc = 0;
10444     } else if (CUR == '*') {
10445 	/* relative or absolute location path */
10446 	lc = 1;
10447     } else if (CUR == '/') {
10448 	/* relative or absolute location path */
10449 	lc = 1;
10450     } else if (CUR == '@') {
10451 	/* relative abbreviated attribute location path */
10452 	lc = 1;
10453     } else if (CUR == '.') {
10454 	/* relative abbreviated attribute location path */
10455 	lc = 1;
10456     } else {
10457 	/*
10458 	 * Problem is finding if we have a name here whether it's:
10459 	 *   - a nodetype
10460 	 *   - a function call in which case it's followed by '('
10461 	 *   - an axis in which case it's followed by ':'
10462 	 *   - a element name
10463 	 * We do an a priori analysis here rather than having to
10464 	 * maintain parsed token content through the recursive function
10465 	 * calls. This looks uglier but makes the code easier to
10466 	 * read/write/debug.
10467 	 */
10468 	SKIP_BLANKS;
10469 	name = xmlXPathScanName(ctxt);
10470 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10471 #ifdef DEBUG_STEP
10472 	    xmlGenericError(xmlGenericErrorContext,
10473 		    "PathExpr: Axis\n");
10474 #endif
10475 	    lc = 1;
10476 	    xmlFree(name);
10477 	} else if (name != NULL) {
10478 	    int len =xmlStrlen(name);
10479 
10480 
10481 	    while (NXT(len) != 0) {
10482 		if (NXT(len) == '/') {
10483 		    /* element name */
10484 #ifdef DEBUG_STEP
10485 		    xmlGenericError(xmlGenericErrorContext,
10486 			    "PathExpr: AbbrRelLocation\n");
10487 #endif
10488 		    lc = 1;
10489 		    break;
10490 		} else if (IS_BLANK_CH(NXT(len))) {
10491 		    /* ignore blanks */
10492 		    ;
10493 		} else if (NXT(len) == ':') {
10494 #ifdef DEBUG_STEP
10495 		    xmlGenericError(xmlGenericErrorContext,
10496 			    "PathExpr: AbbrRelLocation\n");
10497 #endif
10498 		    lc = 1;
10499 		    break;
10500 		} else if ((NXT(len) == '(')) {
10501 		    /* Note Type or Function */
10502 		    if (xmlXPathIsNodeType(name)) {
10503 #ifdef DEBUG_STEP
10504 		        xmlGenericError(xmlGenericErrorContext,
10505 				"PathExpr: Type search\n");
10506 #endif
10507 			lc = 1;
10508 		    } else {
10509 #ifdef DEBUG_STEP
10510 		        xmlGenericError(xmlGenericErrorContext,
10511 				"PathExpr: function call\n");
10512 #endif
10513 			lc = 0;
10514 		    }
10515                     break;
10516 		} else if ((NXT(len) == '[')) {
10517 		    /* element name */
10518 #ifdef DEBUG_STEP
10519 		    xmlGenericError(xmlGenericErrorContext,
10520 			    "PathExpr: AbbrRelLocation\n");
10521 #endif
10522 		    lc = 1;
10523 		    break;
10524 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10525 			   (NXT(len) == '=')) {
10526 		    lc = 1;
10527 		    break;
10528 		} else {
10529 		    lc = 1;
10530 		    break;
10531 		}
10532 		len++;
10533 	    }
10534 	    if (NXT(len) == 0) {
10535 #ifdef DEBUG_STEP
10536 		xmlGenericError(xmlGenericErrorContext,
10537 			"PathExpr: AbbrRelLocation\n");
10538 #endif
10539 		/* element name */
10540 		lc = 1;
10541 	    }
10542 	    xmlFree(name);
10543 	} else {
10544 	    /* make sure all cases are covered explicitly */
10545 	    XP_ERROR(XPATH_EXPR_ERROR);
10546 	}
10547     }
10548 
10549     if (lc) {
10550 	if (CUR == '/') {
10551 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10552 	} else {
10553 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10554 	}
10555 	xmlXPathCompLocationPath(ctxt);
10556     } else {
10557 	xmlXPathCompFilterExpr(ctxt);
10558 	CHECK_ERROR;
10559 	if ((CUR == '/') && (NXT(1) == '/')) {
10560 	    SKIP(2);
10561 	    SKIP_BLANKS;
10562 
10563 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10564 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10565 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10566 
10567 	    xmlXPathCompRelativeLocationPath(ctxt);
10568 	} else if (CUR == '/') {
10569 	    xmlXPathCompRelativeLocationPath(ctxt);
10570 	}
10571     }
10572     SKIP_BLANKS;
10573 }
10574 
10575 /**
10576  * xmlXPathCompUnionExpr:
10577  * @ctxt:  the XPath Parser context
10578  *
10579  *  [18]   UnionExpr ::=   PathExpr
10580  *               | UnionExpr '|' PathExpr
10581  *
10582  * Compile an union expression.
10583  */
10584 
10585 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10586 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10587     xmlXPathCompPathExpr(ctxt);
10588     CHECK_ERROR;
10589     SKIP_BLANKS;
10590     while (CUR == '|') {
10591 	int op1 = ctxt->comp->last;
10592 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10593 
10594 	NEXT;
10595 	SKIP_BLANKS;
10596 	xmlXPathCompPathExpr(ctxt);
10597 
10598 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10599 
10600 	SKIP_BLANKS;
10601     }
10602 }
10603 
10604 /**
10605  * xmlXPathCompUnaryExpr:
10606  * @ctxt:  the XPath Parser context
10607  *
10608  *  [27]   UnaryExpr ::=   UnionExpr
10609  *                   | '-' UnaryExpr
10610  *
10611  * Compile an unary expression.
10612  */
10613 
10614 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10615 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10616     int minus = 0;
10617     int found = 0;
10618 
10619     SKIP_BLANKS;
10620     while (CUR == '-') {
10621         minus = 1 - minus;
10622 	found = 1;
10623 	NEXT;
10624 	SKIP_BLANKS;
10625     }
10626 
10627     xmlXPathCompUnionExpr(ctxt);
10628     CHECK_ERROR;
10629     if (found) {
10630 	if (minus)
10631 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10632 	else
10633 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10634     }
10635 }
10636 
10637 /**
10638  * xmlXPathCompMultiplicativeExpr:
10639  * @ctxt:  the XPath Parser context
10640  *
10641  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10642  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10643  *                   | MultiplicativeExpr 'div' UnaryExpr
10644  *                   | MultiplicativeExpr 'mod' UnaryExpr
10645  *  [34]   MultiplyOperator ::=   '*'
10646  *
10647  * Compile an Additive expression.
10648  */
10649 
10650 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10651 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10652     xmlXPathCompUnaryExpr(ctxt);
10653     CHECK_ERROR;
10654     SKIP_BLANKS;
10655     while ((CUR == '*') ||
10656            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10657            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10658 	int op = -1;
10659 	int op1 = ctxt->comp->last;
10660 
10661         if (CUR == '*') {
10662 	    op = 0;
10663 	    NEXT;
10664 	} else if (CUR == 'd') {
10665 	    op = 1;
10666 	    SKIP(3);
10667 	} else if (CUR == 'm') {
10668 	    op = 2;
10669 	    SKIP(3);
10670 	}
10671 	SKIP_BLANKS;
10672         xmlXPathCompUnaryExpr(ctxt);
10673 	CHECK_ERROR;
10674 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10675 	SKIP_BLANKS;
10676     }
10677 }
10678 
10679 /**
10680  * xmlXPathCompAdditiveExpr:
10681  * @ctxt:  the XPath Parser context
10682  *
10683  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10684  *                   | AdditiveExpr '+' MultiplicativeExpr
10685  *                   | AdditiveExpr '-' MultiplicativeExpr
10686  *
10687  * Compile an Additive expression.
10688  */
10689 
10690 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10691 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10692 
10693     xmlXPathCompMultiplicativeExpr(ctxt);
10694     CHECK_ERROR;
10695     SKIP_BLANKS;
10696     while ((CUR == '+') || (CUR == '-')) {
10697 	int plus;
10698 	int op1 = ctxt->comp->last;
10699 
10700         if (CUR == '+') plus = 1;
10701 	else plus = 0;
10702 	NEXT;
10703 	SKIP_BLANKS;
10704         xmlXPathCompMultiplicativeExpr(ctxt);
10705 	CHECK_ERROR;
10706 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10707 	SKIP_BLANKS;
10708     }
10709 }
10710 
10711 /**
10712  * xmlXPathCompRelationalExpr:
10713  * @ctxt:  the XPath Parser context
10714  *
10715  *  [24]   RelationalExpr ::=   AdditiveExpr
10716  *                 | RelationalExpr '<' AdditiveExpr
10717  *                 | RelationalExpr '>' AdditiveExpr
10718  *                 | RelationalExpr '<=' AdditiveExpr
10719  *                 | RelationalExpr '>=' AdditiveExpr
10720  *
10721  *  A <= B > C is allowed ? Answer from James, yes with
10722  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10723  *  which is basically what got implemented.
10724  *
10725  * Compile a Relational expression, then push the result
10726  * on the stack
10727  */
10728 
10729 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10730 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10731     xmlXPathCompAdditiveExpr(ctxt);
10732     CHECK_ERROR;
10733     SKIP_BLANKS;
10734     while ((CUR == '<') ||
10735            (CUR == '>') ||
10736            ((CUR == '<') && (NXT(1) == '=')) ||
10737            ((CUR == '>') && (NXT(1) == '='))) {
10738 	int inf, strict;
10739 	int op1 = ctxt->comp->last;
10740 
10741         if (CUR == '<') inf = 1;
10742 	else inf = 0;
10743 	if (NXT(1) == '=') strict = 0;
10744 	else strict = 1;
10745 	NEXT;
10746 	if (!strict) NEXT;
10747 	SKIP_BLANKS;
10748         xmlXPathCompAdditiveExpr(ctxt);
10749 	CHECK_ERROR;
10750 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10751 	SKIP_BLANKS;
10752     }
10753 }
10754 
10755 /**
10756  * xmlXPathCompEqualityExpr:
10757  * @ctxt:  the XPath Parser context
10758  *
10759  *  [23]   EqualityExpr ::=   RelationalExpr
10760  *                 | EqualityExpr '=' RelationalExpr
10761  *                 | EqualityExpr '!=' RelationalExpr
10762  *
10763  *  A != B != C is allowed ? Answer from James, yes with
10764  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10765  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10766  *  which is basically what got implemented.
10767  *
10768  * Compile an Equality expression.
10769  *
10770  */
10771 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10772 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10773     xmlXPathCompRelationalExpr(ctxt);
10774     CHECK_ERROR;
10775     SKIP_BLANKS;
10776     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10777 	int eq;
10778 	int op1 = ctxt->comp->last;
10779 
10780         if (CUR == '=') eq = 1;
10781 	else eq = 0;
10782 	NEXT;
10783 	if (!eq) NEXT;
10784 	SKIP_BLANKS;
10785         xmlXPathCompRelationalExpr(ctxt);
10786 	CHECK_ERROR;
10787 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10788 	SKIP_BLANKS;
10789     }
10790 }
10791 
10792 /**
10793  * xmlXPathCompAndExpr:
10794  * @ctxt:  the XPath Parser context
10795  *
10796  *  [22]   AndExpr ::=   EqualityExpr
10797  *                 | AndExpr 'and' EqualityExpr
10798  *
10799  * Compile an AND expression.
10800  *
10801  */
10802 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10803 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10804     xmlXPathCompEqualityExpr(ctxt);
10805     CHECK_ERROR;
10806     SKIP_BLANKS;
10807     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10808 	int op1 = ctxt->comp->last;
10809         SKIP(3);
10810 	SKIP_BLANKS;
10811         xmlXPathCompEqualityExpr(ctxt);
10812 	CHECK_ERROR;
10813 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10814 	SKIP_BLANKS;
10815     }
10816 }
10817 
10818 /**
10819  * xmlXPathCompileExpr:
10820  * @ctxt:  the XPath Parser context
10821  *
10822  *  [14]   Expr ::=   OrExpr
10823  *  [21]   OrExpr ::=   AndExpr
10824  *                 | OrExpr 'or' AndExpr
10825  *
10826  * Parse and compile an expression
10827  */
10828 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10829 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10830     xmlXPathCompAndExpr(ctxt);
10831     CHECK_ERROR;
10832     SKIP_BLANKS;
10833     while ((CUR == 'o') && (NXT(1) == 'r')) {
10834 	int op1 = ctxt->comp->last;
10835         SKIP(2);
10836 	SKIP_BLANKS;
10837         xmlXPathCompAndExpr(ctxt);
10838 	CHECK_ERROR;
10839 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10840 	op1 = ctxt->comp->nbStep;
10841 	SKIP_BLANKS;
10842     }
10843     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10844 	/* more ops could be optimized too */
10845 	/*
10846 	* This is the main place to eliminate sorting for
10847 	* operations which don't require a sorted node-set.
10848 	* E.g. count().
10849 	*/
10850 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10851     }
10852 }
10853 
10854 /**
10855  * xmlXPathCompPredicate:
10856  * @ctxt:  the XPath Parser context
10857  * @filter:  act as a filter
10858  *
10859  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10860  *  [9]   PredicateExpr ::=   Expr
10861  *
10862  * Compile a predicate expression
10863  */
10864 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10865 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10866     int op1 = ctxt->comp->last;
10867 
10868     SKIP_BLANKS;
10869     if (CUR != '[') {
10870 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10871     }
10872     NEXT;
10873     SKIP_BLANKS;
10874 
10875     ctxt->comp->last = -1;
10876     /*
10877     * This call to xmlXPathCompileExpr() will deactivate sorting
10878     * of the predicate result.
10879     * TODO: Sorting is still activated for filters, since I'm not
10880     *  sure if needed. Normally sorting should not be needed, since
10881     *  a filter can only diminish the number of items in a sequence,
10882     *  but won't change its order; so if the initial sequence is sorted,
10883     *  subsequent sorting is not needed.
10884     */
10885     if (! filter)
10886 	xmlXPathCompileExpr(ctxt, 0);
10887     else
10888 	xmlXPathCompileExpr(ctxt, 1);
10889     CHECK_ERROR;
10890 
10891     if (CUR != ']') {
10892 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10893     }
10894 
10895     if (filter)
10896 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10897     else
10898 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10899 
10900     NEXT;
10901     SKIP_BLANKS;
10902 }
10903 
10904 /**
10905  * xmlXPathCompNodeTest:
10906  * @ctxt:  the XPath Parser context
10907  * @test:  pointer to a xmlXPathTestVal
10908  * @type:  pointer to a xmlXPathTypeVal
10909  * @prefix:  placeholder for a possible name prefix
10910  *
10911  * [7] NodeTest ::=   NameTest
10912  *		    | NodeType '(' ')'
10913  *		    | 'processing-instruction' '(' Literal ')'
10914  *
10915  * [37] NameTest ::=  '*'
10916  *		    | NCName ':' '*'
10917  *		    | QName
10918  * [38] NodeType ::= 'comment'
10919  *		   | 'text'
10920  *		   | 'processing-instruction'
10921  *		   | 'node'
10922  *
10923  * Returns the name found and updates @test, @type and @prefix appropriately
10924  */
10925 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)10926 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10927 	             xmlXPathTypeVal *type, const xmlChar **prefix,
10928 		     xmlChar *name) {
10929     int blanks;
10930 
10931     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10932 	STRANGE;
10933 	return(NULL);
10934     }
10935     *type = (xmlXPathTypeVal) 0;
10936     *test = (xmlXPathTestVal) 0;
10937     *prefix = NULL;
10938     SKIP_BLANKS;
10939 
10940     if ((name == NULL) && (CUR == '*')) {
10941 	/*
10942 	 * All elements
10943 	 */
10944 	NEXT;
10945 	*test = NODE_TEST_ALL;
10946 	return(NULL);
10947     }
10948 
10949     if (name == NULL)
10950 	name = xmlXPathParseNCName(ctxt);
10951     if (name == NULL) {
10952 	XP_ERRORNULL(XPATH_EXPR_ERROR);
10953     }
10954 
10955     blanks = IS_BLANK_CH(CUR);
10956     SKIP_BLANKS;
10957     if (CUR == '(') {
10958 	NEXT;
10959 	/*
10960 	 * NodeType or PI search
10961 	 */
10962 	if (xmlStrEqual(name, BAD_CAST "comment"))
10963 	    *type = NODE_TYPE_COMMENT;
10964 	else if (xmlStrEqual(name, BAD_CAST "node"))
10965 	    *type = NODE_TYPE_NODE;
10966 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10967 	    *type = NODE_TYPE_PI;
10968 	else if (xmlStrEqual(name, BAD_CAST "text"))
10969 	    *type = NODE_TYPE_TEXT;
10970 	else {
10971 	    if (name != NULL)
10972 		xmlFree(name);
10973 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10974 	}
10975 
10976 	*test = NODE_TEST_TYPE;
10977 
10978 	SKIP_BLANKS;
10979 	if (*type == NODE_TYPE_PI) {
10980 	    /*
10981 	     * Specific case: search a PI by name.
10982 	     */
10983 	    if (name != NULL)
10984 		xmlFree(name);
10985 	    name = NULL;
10986 	    if (CUR != ')') {
10987 		name = xmlXPathParseLiteral(ctxt);
10988 		CHECK_ERROR NULL;
10989 		*test = NODE_TEST_PI;
10990 		SKIP_BLANKS;
10991 	    }
10992 	}
10993 	if (CUR != ')') {
10994 	    if (name != NULL)
10995 		xmlFree(name);
10996 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10997 	}
10998 	NEXT;
10999 	return(name);
11000     }
11001     *test = NODE_TEST_NAME;
11002     if ((!blanks) && (CUR == ':')) {
11003 	NEXT;
11004 
11005 	/*
11006 	 * Since currently the parser context don't have a
11007 	 * namespace list associated:
11008 	 * The namespace name for this prefix can be computed
11009 	 * only at evaluation time. The compilation is done
11010 	 * outside of any context.
11011 	 */
11012 #if 0
11013 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11014 	if (name != NULL)
11015 	    xmlFree(name);
11016 	if (*prefix == NULL) {
11017 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11018 	}
11019 #else
11020 	*prefix = name;
11021 #endif
11022 
11023 	if (CUR == '*') {
11024 	    /*
11025 	     * All elements
11026 	     */
11027 	    NEXT;
11028 	    *test = NODE_TEST_ALL;
11029 	    return(NULL);
11030 	}
11031 
11032 	name = xmlXPathParseNCName(ctxt);
11033 	if (name == NULL) {
11034 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11035 	}
11036     }
11037     return(name);
11038 }
11039 
11040 /**
11041  * xmlXPathIsAxisName:
11042  * @name:  a preparsed name token
11043  *
11044  * [6] AxisName ::=   'ancestor'
11045  *                  | 'ancestor-or-self'
11046  *                  | 'attribute'
11047  *                  | 'child'
11048  *                  | 'descendant'
11049  *                  | 'descendant-or-self'
11050  *                  | 'following'
11051  *                  | 'following-sibling'
11052  *                  | 'namespace'
11053  *                  | 'parent'
11054  *                  | 'preceding'
11055  *                  | 'preceding-sibling'
11056  *                  | 'self'
11057  *
11058  * Returns the axis or 0
11059  */
11060 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11061 xmlXPathIsAxisName(const xmlChar *name) {
11062     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11063     switch (name[0]) {
11064 	case 'a':
11065 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11066 		ret = AXIS_ANCESTOR;
11067 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11068 		ret = AXIS_ANCESTOR_OR_SELF;
11069 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11070 		ret = AXIS_ATTRIBUTE;
11071 	    break;
11072 	case 'c':
11073 	    if (xmlStrEqual(name, BAD_CAST "child"))
11074 		ret = AXIS_CHILD;
11075 	    break;
11076 	case 'd':
11077 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11078 		ret = AXIS_DESCENDANT;
11079 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11080 		ret = AXIS_DESCENDANT_OR_SELF;
11081 	    break;
11082 	case 'f':
11083 	    if (xmlStrEqual(name, BAD_CAST "following"))
11084 		ret = AXIS_FOLLOWING;
11085 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11086 		ret = AXIS_FOLLOWING_SIBLING;
11087 	    break;
11088 	case 'n':
11089 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11090 		ret = AXIS_NAMESPACE;
11091 	    break;
11092 	case 'p':
11093 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11094 		ret = AXIS_PARENT;
11095 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11096 		ret = AXIS_PRECEDING;
11097 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11098 		ret = AXIS_PRECEDING_SIBLING;
11099 	    break;
11100 	case 's':
11101 	    if (xmlStrEqual(name, BAD_CAST "self"))
11102 		ret = AXIS_SELF;
11103 	    break;
11104     }
11105     return(ret);
11106 }
11107 
11108 /**
11109  * xmlXPathCompStep:
11110  * @ctxt:  the XPath Parser context
11111  *
11112  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11113  *                  | AbbreviatedStep
11114  *
11115  * [12] AbbreviatedStep ::=   '.' | '..'
11116  *
11117  * [5] AxisSpecifier ::= AxisName '::'
11118  *                  | AbbreviatedAxisSpecifier
11119  *
11120  * [13] AbbreviatedAxisSpecifier ::= '@'?
11121  *
11122  * Modified for XPtr range support as:
11123  *
11124  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11125  *                     | AbbreviatedStep
11126  *                     | 'range-to' '(' Expr ')' Predicate*
11127  *
11128  * Compile one step in a Location Path
11129  * A location step of . is short for self::node(). This is
11130  * particularly useful in conjunction with //. For example, the
11131  * location path .//para is short for
11132  * self::node()/descendant-or-self::node()/child::para
11133  * and so will select all para descendant elements of the context
11134  * node.
11135  * Similarly, a location step of .. is short for parent::node().
11136  * For example, ../title is short for parent::node()/child::title
11137  * and so will select the title children of the parent of the context
11138  * node.
11139  */
11140 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11141 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11142 #ifdef LIBXML_XPTR_ENABLED
11143     int rangeto = 0;
11144     int op2 = -1;
11145 #endif
11146 
11147     SKIP_BLANKS;
11148     if ((CUR == '.') && (NXT(1) == '.')) {
11149 	SKIP(2);
11150 	SKIP_BLANKS;
11151 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11152 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11153     } else if (CUR == '.') {
11154 	NEXT;
11155 	SKIP_BLANKS;
11156     } else {
11157 	xmlChar *name = NULL;
11158 	const xmlChar *prefix = NULL;
11159 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11160 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11161 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11162 	int op1;
11163 
11164 	/*
11165 	 * The modification needed for XPointer change to the production
11166 	 */
11167 #ifdef LIBXML_XPTR_ENABLED
11168 	if (ctxt->xptr) {
11169 	    name = xmlXPathParseNCName(ctxt);
11170 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11171                 op2 = ctxt->comp->last;
11172 		xmlFree(name);
11173 		SKIP_BLANKS;
11174 		if (CUR != '(') {
11175 		    XP_ERROR(XPATH_EXPR_ERROR);
11176 		}
11177 		NEXT;
11178 		SKIP_BLANKS;
11179 
11180 		xmlXPathCompileExpr(ctxt, 1);
11181 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11182 		CHECK_ERROR;
11183 
11184 		SKIP_BLANKS;
11185 		if (CUR != ')') {
11186 		    XP_ERROR(XPATH_EXPR_ERROR);
11187 		}
11188 		NEXT;
11189 		rangeto = 1;
11190 		goto eval_predicates;
11191 	    }
11192 	}
11193 #endif
11194 	if (CUR == '*') {
11195 	    axis = AXIS_CHILD;
11196 	} else {
11197 	    if (name == NULL)
11198 		name = xmlXPathParseNCName(ctxt);
11199 	    if (name != NULL) {
11200 		axis = xmlXPathIsAxisName(name);
11201 		if (axis != 0) {
11202 		    SKIP_BLANKS;
11203 		    if ((CUR == ':') && (NXT(1) == ':')) {
11204 			SKIP(2);
11205 			xmlFree(name);
11206 			name = NULL;
11207 		    } else {
11208 			/* an element name can conflict with an axis one :-\ */
11209 			axis = AXIS_CHILD;
11210 		    }
11211 		} else {
11212 		    axis = AXIS_CHILD;
11213 		}
11214 	    } else if (CUR == '@') {
11215 		NEXT;
11216 		axis = AXIS_ATTRIBUTE;
11217 	    } else {
11218 		axis = AXIS_CHILD;
11219 	    }
11220 	}
11221 
11222 	CHECK_ERROR;
11223 
11224 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11225 	if (test == 0)
11226 	    return;
11227 
11228         if ((prefix != NULL) && (ctxt->context != NULL) &&
11229 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11230 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11231 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11232 	    }
11233 	}
11234 #ifdef DEBUG_STEP
11235 	xmlGenericError(xmlGenericErrorContext,
11236 		"Basis : computing new set\n");
11237 #endif
11238 
11239 #ifdef DEBUG_STEP
11240 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11241 	if (ctxt->value == NULL)
11242 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11243 	else if (ctxt->value->nodesetval == NULL)
11244 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11245 	else
11246 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11247 #endif
11248 
11249 #ifdef LIBXML_XPTR_ENABLED
11250 eval_predicates:
11251 #endif
11252 	op1 = ctxt->comp->last;
11253 	ctxt->comp->last = -1;
11254 
11255 	SKIP_BLANKS;
11256 	while (CUR == '[') {
11257 	    xmlXPathCompPredicate(ctxt, 0);
11258 	}
11259 
11260 #ifdef LIBXML_XPTR_ENABLED
11261 	if (rangeto) {
11262 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11263 	} else
11264 #endif
11265 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11266 			   test, type, (void *)prefix, (void *)name);
11267 
11268     }
11269 #ifdef DEBUG_STEP
11270     xmlGenericError(xmlGenericErrorContext, "Step : ");
11271     if (ctxt->value == NULL)
11272 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11273     else if (ctxt->value->nodesetval == NULL)
11274 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11275     else
11276 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11277 		ctxt->value->nodesetval);
11278 #endif
11279 }
11280 
11281 /**
11282  * xmlXPathCompRelativeLocationPath:
11283  * @ctxt:  the XPath Parser context
11284  *
11285  *  [3]   RelativeLocationPath ::=   Step
11286  *                     | RelativeLocationPath '/' Step
11287  *                     | AbbreviatedRelativeLocationPath
11288  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11289  *
11290  * Compile a relative location path.
11291  */
11292 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11293 xmlXPathCompRelativeLocationPath
11294 (xmlXPathParserContextPtr ctxt) {
11295     SKIP_BLANKS;
11296     if ((CUR == '/') && (NXT(1) == '/')) {
11297 	SKIP(2);
11298 	SKIP_BLANKS;
11299 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11300 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11301     } else if (CUR == '/') {
11302 	    NEXT;
11303 	SKIP_BLANKS;
11304     }
11305     xmlXPathCompStep(ctxt);
11306     SKIP_BLANKS;
11307     while (CUR == '/') {
11308 	if ((CUR == '/') && (NXT(1) == '/')) {
11309 	    SKIP(2);
11310 	    SKIP_BLANKS;
11311 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11312 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11313 	    xmlXPathCompStep(ctxt);
11314 	} else if (CUR == '/') {
11315 	    NEXT;
11316 	    SKIP_BLANKS;
11317 	    xmlXPathCompStep(ctxt);
11318 	}
11319 	SKIP_BLANKS;
11320     }
11321 }
11322 
11323 /**
11324  * xmlXPathCompLocationPath:
11325  * @ctxt:  the XPath Parser context
11326  *
11327  *  [1]   LocationPath ::=   RelativeLocationPath
11328  *                     | AbsoluteLocationPath
11329  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11330  *                     | AbbreviatedAbsoluteLocationPath
11331  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11332  *                           '//' RelativeLocationPath
11333  *
11334  * Compile a location path
11335  *
11336  * // is short for /descendant-or-self::node()/. For example,
11337  * //para is short for /descendant-or-self::node()/child::para and
11338  * so will select any para element in the document (even a para element
11339  * that is a document element will be selected by //para since the
11340  * document element node is a child of the root node); div//para is
11341  * short for div/descendant-or-self::node()/child::para and so will
11342  * select all para descendants of div children.
11343  */
11344 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11345 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11346     SKIP_BLANKS;
11347     if (CUR != '/') {
11348         xmlXPathCompRelativeLocationPath(ctxt);
11349     } else {
11350 	while (CUR == '/') {
11351 	    if ((CUR == '/') && (NXT(1) == '/')) {
11352 		SKIP(2);
11353 		SKIP_BLANKS;
11354 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11355 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11356 		xmlXPathCompRelativeLocationPath(ctxt);
11357 	    } else if (CUR == '/') {
11358 		NEXT;
11359 		SKIP_BLANKS;
11360 		if ((CUR != 0 ) &&
11361 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11362 		     (CUR == '@') || (CUR == '*')))
11363 		    xmlXPathCompRelativeLocationPath(ctxt);
11364 	    }
11365 	}
11366     }
11367 }
11368 
11369 /************************************************************************
11370  *									*
11371  * 		XPath precompiled expression evaluation			*
11372  *									*
11373  ************************************************************************/
11374 
11375 static int
11376 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11377 
11378 #ifdef DEBUG_STEP
11379 static void
xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,xmlXPathTestVal test,int nbNodes)11380 xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11381 			  xmlXPathTestVal test,
11382 			  int nbNodes)
11383 {
11384     xmlGenericError(xmlGenericErrorContext, "new step : ");
11385     switch (axis) {
11386         case AXIS_ANCESTOR:
11387             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11388             break;
11389         case AXIS_ANCESTOR_OR_SELF:
11390             xmlGenericError(xmlGenericErrorContext,
11391                             "axis 'ancestors-or-self' ");
11392             break;
11393         case AXIS_ATTRIBUTE:
11394             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11395             break;
11396         case AXIS_CHILD:
11397             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11398             break;
11399         case AXIS_DESCENDANT:
11400             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11401             break;
11402         case AXIS_DESCENDANT_OR_SELF:
11403             xmlGenericError(xmlGenericErrorContext,
11404                             "axis 'descendant-or-self' ");
11405             break;
11406         case AXIS_FOLLOWING:
11407             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11408             break;
11409         case AXIS_FOLLOWING_SIBLING:
11410             xmlGenericError(xmlGenericErrorContext,
11411                             "axis 'following-siblings' ");
11412             break;
11413         case AXIS_NAMESPACE:
11414             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11415             break;
11416         case AXIS_PARENT:
11417             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11418             break;
11419         case AXIS_PRECEDING:
11420             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11421             break;
11422         case AXIS_PRECEDING_SIBLING:
11423             xmlGenericError(xmlGenericErrorContext,
11424                             "axis 'preceding-sibling' ");
11425             break;
11426         case AXIS_SELF:
11427             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11428             break;
11429     }
11430     xmlGenericError(xmlGenericErrorContext,
11431 	" context contains %d nodes\n", nbNodes);
11432     switch (test) {
11433         case NODE_TEST_NONE:
11434             xmlGenericError(xmlGenericErrorContext,
11435                             "           searching for none !!!\n");
11436             break;
11437         case NODE_TEST_TYPE:
11438             xmlGenericError(xmlGenericErrorContext,
11439                             "           searching for type %d\n", type);
11440             break;
11441         case NODE_TEST_PI:
11442             xmlGenericError(xmlGenericErrorContext,
11443                             "           searching for PI !!!\n");
11444             break;
11445         case NODE_TEST_ALL:
11446             xmlGenericError(xmlGenericErrorContext,
11447                             "           searching for *\n");
11448             break;
11449         case NODE_TEST_NS:
11450             xmlGenericError(xmlGenericErrorContext,
11451                             "           searching for namespace %s\n",
11452                             prefix);
11453             break;
11454         case NODE_TEST_NAME:
11455             xmlGenericError(xmlGenericErrorContext,
11456                             "           searching for name %s\n", name);
11457             if (prefix != NULL)
11458                 xmlGenericError(xmlGenericErrorContext,
11459                                 "           with namespace %s\n", prefix);
11460             break;
11461     }
11462     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11463 }
11464 #endif /* DEBUG_STEP */
11465 
11466 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11467 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11468 			    xmlXPathStepOpPtr op,
11469 			    xmlNodeSetPtr set,
11470 			    int contextSize,
11471 			    int hasNsNodes)
11472 {
11473     if (op->ch1 != -1) {
11474 	xmlXPathCompExprPtr comp = ctxt->comp;
11475 	/*
11476 	* Process inner predicates first.
11477 	*/
11478 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11479 	    /*
11480 	    * TODO: raise an internal error.
11481 	    */
11482 	}
11483 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11484 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11485 	CHECK_ERROR0;
11486 	if (contextSize <= 0)
11487 	    return(0);
11488     }
11489     if (op->ch2 != -1) {
11490 	xmlXPathContextPtr xpctxt = ctxt->context;
11491 	xmlNodePtr contextNode, oldContextNode;
11492 	xmlDocPtr oldContextDoc;
11493 	int i, res, contextPos = 0, newContextSize;
11494 	xmlXPathStepOpPtr exprOp;
11495 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11496 
11497 #ifdef LIBXML_XPTR_ENABLED
11498 	/*
11499 	* URGENT TODO: Check the following:
11500 	*  We don't expect location sets if evaluating prediates, right?
11501 	*  Only filters should expect location sets, right?
11502 	*/
11503 #endif
11504 	/*
11505 	* SPEC XPath 1.0:
11506 	*  "For each node in the node-set to be filtered, the
11507 	*  PredicateExpr is evaluated with that node as the
11508 	*  context node, with the number of nodes in the
11509 	*  node-set as the context size, and with the proximity
11510 	*  position of the node in the node-set with respect to
11511 	*  the axis as the context position;"
11512 	* @oldset is the node-set" to be filtered.
11513 	*
11514 	* SPEC XPath 1.0:
11515 	*  "only predicates change the context position and
11516 	*  context size (see [2.4 Predicates])."
11517 	* Example:
11518 	*   node-set  context pos
11519 	*    nA         1
11520 	*    nB         2
11521 	*    nC         3
11522 	*   After applying predicate [position() > 1] :
11523 	*   node-set  context pos
11524 	*    nB         1
11525 	*    nC         2
11526 	*/
11527 	oldContextNode = xpctxt->node;
11528 	oldContextDoc = xpctxt->doc;
11529 	/*
11530 	* Get the expression of this predicate.
11531 	*/
11532 	exprOp = &ctxt->comp->steps[op->ch2];
11533 	newContextSize = 0;
11534 	for (i = 0; i < set->nodeNr; i++) {
11535 	    if (set->nodeTab[i] == NULL)
11536 		continue;
11537 
11538 	    contextNode = set->nodeTab[i];
11539 	    xpctxt->node = contextNode;
11540 	    xpctxt->contextSize = contextSize;
11541 	    xpctxt->proximityPosition = ++contextPos;
11542 
11543 	    /*
11544 	    * Also set the xpath document in case things like
11545 	    * key() are evaluated in the predicate.
11546 	    */
11547 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11548 		(contextNode->doc != NULL))
11549 		xpctxt->doc = contextNode->doc;
11550 	    /*
11551 	    * Evaluate the predicate expression with 1 context node
11552 	    * at a time; this node is packaged into a node set; this
11553 	    * node set is handed over to the evaluation mechanism.
11554 	    */
11555 	    if (contextObj == NULL)
11556 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11557 	    else
11558 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11559 		    contextNode);
11560 
11561 	    valuePush(ctxt, contextObj);
11562 
11563 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11564 
11565 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11566 		xmlXPathNodeSetClear(set, hasNsNodes);
11567 		newContextSize = 0;
11568 		goto evaluation_exit;
11569 	    }
11570 
11571 	    if (res != 0) {
11572 		newContextSize++;
11573 	    } else {
11574 		/*
11575 		* Remove the entry from the initial node set.
11576 		*/
11577 		set->nodeTab[i] = NULL;
11578 		if (contextNode->type == XML_NAMESPACE_DECL)
11579 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11580 	    }
11581 	    if (ctxt->value == contextObj) {
11582 		/*
11583 		* Don't free the temporary XPath object holding the
11584 		* context node, in order to avoid massive recreation
11585 		* inside this loop.
11586 		*/
11587 		valuePop(ctxt);
11588 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11589 	    } else {
11590 		/*
11591 		* TODO: The object was lost in the evaluation machinery.
11592 		*  Can this happen? Maybe in internal-error cases.
11593 		*/
11594 		contextObj = NULL;
11595 	    }
11596 	}
11597 
11598 	if (contextObj != NULL) {
11599 	    if (ctxt->value == contextObj)
11600 		valuePop(ctxt);
11601 	    xmlXPathReleaseObject(xpctxt, contextObj);
11602 	}
11603 evaluation_exit:
11604 	if (exprRes != NULL)
11605 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11606 	/*
11607 	* Reset/invalidate the context.
11608 	*/
11609 	xpctxt->node = oldContextNode;
11610 	xpctxt->doc = oldContextDoc;
11611 	xpctxt->contextSize = -1;
11612 	xpctxt->proximityPosition = -1;
11613 	return(newContextSize);
11614     }
11615     return(contextSize);
11616 }
11617 
11618 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11619 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11620 				      xmlXPathStepOpPtr op,
11621 				      xmlNodeSetPtr set,
11622 				      int contextSize,
11623 				      int minPos,
11624 				      int maxPos,
11625 				      int hasNsNodes)
11626 {
11627     if (op->ch1 != -1) {
11628 	xmlXPathCompExprPtr comp = ctxt->comp;
11629 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11630 	    /*
11631 	    * TODO: raise an internal error.
11632 	    */
11633 	}
11634 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11635 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11636 	CHECK_ERROR0;
11637 	if (contextSize <= 0)
11638 	    return(0);
11639     }
11640     /*
11641     * Check if the node set contains a sufficient number of nodes for
11642     * the requested range.
11643     */
11644     if (contextSize < minPos) {
11645 	xmlXPathNodeSetClear(set, hasNsNodes);
11646 	return(0);
11647     }
11648     if (op->ch2 == -1) {
11649 	/*
11650 	* TODO: Can this ever happen?
11651 	*/
11652 	return (contextSize);
11653     } else {
11654 	xmlDocPtr oldContextDoc;
11655 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11656 	xmlXPathStepOpPtr exprOp;
11657 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11658 	xmlNodePtr oldContextNode, contextNode = NULL;
11659 	xmlXPathContextPtr xpctxt = ctxt->context;
11660 
11661 #ifdef LIBXML_XPTR_ENABLED
11662 	    /*
11663 	    * URGENT TODO: Check the following:
11664 	    *  We don't expect location sets if evaluating prediates, right?
11665 	    *  Only filters should expect location sets, right?
11666 	*/
11667 #endif /* LIBXML_XPTR_ENABLED */
11668 
11669 	/*
11670 	* Save old context.
11671 	*/
11672 	oldContextNode = xpctxt->node;
11673 	oldContextDoc = xpctxt->doc;
11674 	/*
11675 	* Get the expression of this predicate.
11676 	*/
11677 	exprOp = &ctxt->comp->steps[op->ch2];
11678 	for (i = 0; i < set->nodeNr; i++) {
11679 	    if (set->nodeTab[i] == NULL)
11680 		continue;
11681 
11682 	    contextNode = set->nodeTab[i];
11683 	    xpctxt->node = contextNode;
11684 	    xpctxt->contextSize = contextSize;
11685 	    xpctxt->proximityPosition = ++contextPos;
11686 
11687 	    /*
11688 	    * Initialize the new set.
11689 	    * Also set the xpath document in case things like
11690 	    * key() evaluation are attempted on the predicate
11691 	    */
11692 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11693 		(contextNode->doc != NULL))
11694 		xpctxt->doc = contextNode->doc;
11695 	    /*
11696 	    * Evaluate the predicate expression with 1 context node
11697 	    * at a time; this node is packaged into a node set; this
11698 	    * node set is handed over to the evaluation mechanism.
11699 	    */
11700 	    if (contextObj == NULL)
11701 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11702 	    else
11703 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11704 		    contextNode);
11705 
11706 	    valuePush(ctxt, contextObj);
11707 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11708 
11709 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11710 	        xmlXPathObjectPtr tmp;
11711 		/* pop the result */
11712 		tmp = valuePop(ctxt);
11713 		xmlXPathReleaseObject(xpctxt, tmp);
11714 		/* then pop off contextObj, which will be freed later */
11715 		valuePop(ctxt);
11716 		goto evaluation_error;
11717 	    }
11718 
11719 	    if (res)
11720 		pos++;
11721 
11722 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11723 		/*
11724 		* Fits in the requested range.
11725 		*/
11726 		newContextSize++;
11727 		if (minPos == maxPos) {
11728 		    /*
11729 		    * Only 1 node was requested.
11730 		    */
11731 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11732 			/*
11733 			* As always: take care of those nasty
11734 			* namespace nodes.
11735 			*/
11736 			set->nodeTab[i] = NULL;
11737 		    }
11738 		    xmlXPathNodeSetClear(set, hasNsNodes);
11739 		    set->nodeNr = 1;
11740 		    set->nodeTab[0] = contextNode;
11741 		    goto evaluation_exit;
11742 		}
11743 		if (pos == maxPos) {
11744 		    /*
11745 		    * We are done.
11746 		    */
11747 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11748 		    goto evaluation_exit;
11749 		}
11750 	    } else {
11751 		/*
11752 		* Remove the entry from the initial node set.
11753 		*/
11754 		set->nodeTab[i] = NULL;
11755 		if (contextNode->type == XML_NAMESPACE_DECL)
11756 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11757 	    }
11758 	    if (exprRes != NULL) {
11759 		xmlXPathReleaseObject(ctxt->context, exprRes);
11760 		exprRes = NULL;
11761 	    }
11762 	    if (ctxt->value == contextObj) {
11763 		/*
11764 		* Don't free the temporary XPath object holding the
11765 		* context node, in order to avoid massive recreation
11766 		* inside this loop.
11767 		*/
11768 		valuePop(ctxt);
11769 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11770 	    } else {
11771 		/*
11772 		* The object was lost in the evaluation machinery.
11773 		* Can this happen? Maybe in case of internal-errors.
11774 		*/
11775 		contextObj = NULL;
11776 	    }
11777 	}
11778 	goto evaluation_exit;
11779 
11780 evaluation_error:
11781 	xmlXPathNodeSetClear(set, hasNsNodes);
11782 	newContextSize = 0;
11783 
11784 evaluation_exit:
11785 	if (contextObj != NULL) {
11786 	    if (ctxt->value == contextObj)
11787 		valuePop(ctxt);
11788 	    xmlXPathReleaseObject(xpctxt, contextObj);
11789 	}
11790 	if (exprRes != NULL)
11791 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11792 	/*
11793 	* Reset/invalidate the context.
11794 	*/
11795 	xpctxt->node = oldContextNode;
11796 	xpctxt->doc = oldContextDoc;
11797 	xpctxt->contextSize = -1;
11798 	xpctxt->proximityPosition = -1;
11799 	return(newContextSize);
11800     }
11801     return(contextSize);
11802 }
11803 
11804 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11805 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11806 			    xmlXPathStepOpPtr op,
11807 			    int *maxPos)
11808 {
11809 
11810     xmlXPathStepOpPtr exprOp;
11811 
11812     /*
11813     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11814     */
11815 
11816     /*
11817     * If not -1, then ch1 will point to:
11818     * 1) For predicates (XPATH_OP_PREDICATE):
11819     *    - an inner predicate operator
11820     * 2) For filters (XPATH_OP_FILTER):
11821     *    - an inner filter operater OR
11822     *    - an expression selecting the node set.
11823     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11824     */
11825     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11826 	return(0);
11827 
11828     if (op->ch2 != -1) {
11829 	exprOp = &ctxt->comp->steps[op->ch2];
11830     } else
11831 	return(0);
11832 
11833     if ((exprOp != NULL) &&
11834 	(exprOp->op == XPATH_OP_VALUE) &&
11835 	(exprOp->value4 != NULL) &&
11836 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11837     {
11838 	/*
11839 	* We have a "[n]" predicate here.
11840 	* TODO: Unfortunately this simplistic test here is not
11841 	* able to detect a position() predicate in compound
11842 	* expressions like "[@attr = 'a" and position() = 1],
11843 	* and even not the usage of position() in
11844 	* "[position() = 1]"; thus - obviously - a position-range,
11845 	* like it "[position() < 5]", is also not detected.
11846 	* Maybe we could rewrite the AST to ease the optimization.
11847 	*/
11848 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11849 
11850 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11851 	    (float) *maxPos)
11852 	{
11853 	    return(1);
11854 	}
11855     }
11856     return(0);
11857 }
11858 
11859 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11860 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11861                            xmlXPathStepOpPtr op,
11862 			   xmlNodePtr * first, xmlNodePtr * last,
11863 			   int toBool)
11864 {
11865 
11866 #define XP_TEST_HIT \
11867     if (hasAxisRange != 0) { \
11868 	if (++pos == maxPos) { \
11869 	    addNode(seq, cur); \
11870 	goto axis_range_end; } \
11871     } else { \
11872 	addNode(seq, cur); \
11873 	if (breakOnFirstHit) goto first_hit; }
11874 
11875 #define XP_TEST_HIT_NS \
11876     if (hasAxisRange != 0) { \
11877 	if (++pos == maxPos) { \
11878 	    hasNsNodes = 1; \
11879 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11880 	goto axis_range_end; } \
11881     } else { \
11882 	hasNsNodes = 1; \
11883 	xmlXPathNodeSetAddNs(seq, \
11884 	xpctxt->node, (xmlNsPtr) cur); \
11885 	if (breakOnFirstHit) goto first_hit; }
11886 
11887     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11888     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11889     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11890     const xmlChar *prefix = op->value4;
11891     const xmlChar *name = op->value5;
11892     const xmlChar *URI = NULL;
11893 
11894 #ifdef DEBUG_STEP
11895     int nbMatches = 0, prevMatches = 0;
11896 #endif
11897     int total = 0, hasNsNodes = 0;
11898     /* The popped object holding the context nodes */
11899     xmlXPathObjectPtr obj;
11900     /* The set of context nodes for the node tests */
11901     xmlNodeSetPtr contextSeq;
11902     int contextIdx;
11903     xmlNodePtr contextNode;
11904     /* The context node for a compound traversal */
11905     xmlNodePtr outerContextNode;
11906     /* The final resulting node set wrt to all context nodes */
11907     xmlNodeSetPtr outSeq;
11908     /*
11909     * The temporary resulting node set wrt 1 context node.
11910     * Used to feed predicate evaluation.
11911     */
11912     xmlNodeSetPtr seq;
11913     xmlNodePtr cur;
11914     /* First predicate operator */
11915     xmlXPathStepOpPtr predOp;
11916     int maxPos; /* The requested position() (when a "[n]" predicate) */
11917     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11918     int breakOnFirstHit;
11919 
11920     xmlXPathTraversalFunction next = NULL;
11921     /* compound axis traversal */
11922     xmlXPathTraversalFunctionExt outerNext = NULL;
11923     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11924     xmlXPathNodeSetMergeFunction mergeAndClear;
11925     xmlNodePtr oldContextNode;
11926     xmlXPathContextPtr xpctxt = ctxt->context;
11927 
11928 
11929     CHECK_TYPE0(XPATH_NODESET);
11930     obj = valuePop(ctxt);
11931     /*
11932     * Setup namespaces.
11933     */
11934     if (prefix != NULL) {
11935         URI = xmlXPathNsLookup(xpctxt, prefix);
11936         if (URI == NULL) {
11937 	    xmlXPathReleaseObject(xpctxt, obj);
11938             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11939 	}
11940     }
11941     /*
11942     * Setup axis.
11943     *
11944     * MAYBE FUTURE TODO: merging optimizations:
11945     * - If the nodes to be traversed wrt to the initial nodes and
11946     *   the current axis cannot overlap, then we could avoid searching
11947     *   for duplicates during the merge.
11948     *   But the question is how/when to evaluate if they cannot overlap.
11949     *   Example: if we know that for two initial nodes, the one is
11950     *   not in the ancestor-or-self axis of the other, then we could safely
11951     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11952     *   the descendant-or-self axis.
11953     */
11954     addNode = xmlXPathNodeSetAdd;
11955     mergeAndClear = xmlXPathNodeSetMergeAndClear;
11956     switch (axis) {
11957         case AXIS_ANCESTOR:
11958             first = NULL;
11959             next = xmlXPathNextAncestor;
11960             break;
11961         case AXIS_ANCESTOR_OR_SELF:
11962             first = NULL;
11963             next = xmlXPathNextAncestorOrSelf;
11964             break;
11965         case AXIS_ATTRIBUTE:
11966             first = NULL;
11967 	    last = NULL;
11968             next = xmlXPathNextAttribute;
11969 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11970             break;
11971         case AXIS_CHILD:
11972 	    last = NULL;
11973 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11974 		/*
11975 		* This iterator will give us only nodes which can
11976 		* hold element nodes.
11977 		*/
11978 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
11979 	    }
11980 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11981 		(type == NODE_TYPE_NODE))
11982 	    {
11983 		/*
11984 		* Optimization if an element node type is 'element'.
11985 		*/
11986 		next = xmlXPathNextChildElement;
11987 	    } else
11988 		next = xmlXPathNextChild;
11989 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11990             break;
11991         case AXIS_DESCENDANT:
11992 	    last = NULL;
11993             next = xmlXPathNextDescendant;
11994             break;
11995         case AXIS_DESCENDANT_OR_SELF:
11996 	    last = NULL;
11997             next = xmlXPathNextDescendantOrSelf;
11998             break;
11999         case AXIS_FOLLOWING:
12000 	    last = NULL;
12001             next = xmlXPathNextFollowing;
12002             break;
12003         case AXIS_FOLLOWING_SIBLING:
12004 	    last = NULL;
12005             next = xmlXPathNextFollowingSibling;
12006             break;
12007         case AXIS_NAMESPACE:
12008             first = NULL;
12009 	    last = NULL;
12010             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12011 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12012             break;
12013         case AXIS_PARENT:
12014             first = NULL;
12015             next = xmlXPathNextParent;
12016             break;
12017         case AXIS_PRECEDING:
12018             first = NULL;
12019             next = xmlXPathNextPrecedingInternal;
12020             break;
12021         case AXIS_PRECEDING_SIBLING:
12022             first = NULL;
12023             next = xmlXPathNextPrecedingSibling;
12024             break;
12025         case AXIS_SELF:
12026             first = NULL;
12027 	    last = NULL;
12028             next = xmlXPathNextSelf;
12029 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12030             break;
12031     }
12032 
12033 #ifdef DEBUG_STEP
12034     xmlXPathDebugDumpStepAxis(axis, test,
12035 	(obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12036 #endif
12037 
12038     if (next == NULL) {
12039 	xmlXPathReleaseObject(xpctxt, obj);
12040         return(0);
12041     }
12042     contextSeq = obj->nodesetval;
12043     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12044 	xmlXPathReleaseObject(xpctxt, obj);
12045         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12046         return(0);
12047     }
12048     /*
12049     * Predicate optimization ---------------------------------------------
12050     * If this step has a last predicate, which contains a position(),
12051     * then we'll optimize (although not exactly "position()", but only
12052     * the  short-hand form, i.e., "[n]".
12053     *
12054     * Example - expression "/foo[parent::bar][1]":
12055     *
12056     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12057     *   ROOT                               -- op->ch1
12058     *   PREDICATE                          -- op->ch2 (predOp)
12059     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12060     *       SORT
12061     *         COLLECT  'parent' 'name' 'node' bar
12062     *           NODE
12063     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12064     *
12065     */
12066     maxPos = 0;
12067     predOp = NULL;
12068     hasPredicateRange = 0;
12069     hasAxisRange = 0;
12070     if (op->ch2 != -1) {
12071 	/*
12072 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12073 	*/
12074 	predOp = &ctxt->comp->steps[op->ch2];
12075 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12076 	    if (predOp->ch1 != -1) {
12077 		/*
12078 		* Use the next inner predicate operator.
12079 		*/
12080 		predOp = &ctxt->comp->steps[predOp->ch1];
12081 		hasPredicateRange = 1;
12082 	    } else {
12083 		/*
12084 		* There's no other predicate than the [n] predicate.
12085 		*/
12086 		predOp = NULL;
12087 		hasAxisRange = 1;
12088 	    }
12089 	}
12090     }
12091     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12092     /*
12093     * Axis traversal -----------------------------------------------------
12094     */
12095     /*
12096      * 2.3 Node Tests
12097      *  - For the attribute axis, the principal node type is attribute.
12098      *  - For the namespace axis, the principal node type is namespace.
12099      *  - For other axes, the principal node type is element.
12100      *
12101      * A node test * is true for any node of the
12102      * principal node type. For example, child::* will
12103      * select all element children of the context node
12104      */
12105     oldContextNode = xpctxt->node;
12106     addNode = xmlXPathNodeSetAddUnique;
12107     outSeq = NULL;
12108     seq = NULL;
12109     outerContextNode = NULL;
12110     contextNode = NULL;
12111     contextIdx = 0;
12112 
12113 
12114     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12115 	if (outerNext != NULL) {
12116 	    /*
12117 	    * This is a compound traversal.
12118 	    */
12119 	    if (contextNode == NULL) {
12120 		/*
12121 		* Set the context for the outer traversal.
12122 		*/
12123 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12124 		contextNode = outerNext(NULL, outerContextNode);
12125 	    } else
12126 		contextNode = outerNext(contextNode, outerContextNode);
12127 	    if (contextNode == NULL)
12128 		continue;
12129 	    /*
12130 	    * Set the context for the main traversal.
12131 	    */
12132 	    xpctxt->node = contextNode;
12133 	} else
12134 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12135 
12136 	if (seq == NULL) {
12137 	    seq = xmlXPathNodeSetCreate(NULL);
12138 	    if (seq == NULL) {
12139 		total = 0;
12140 		goto error;
12141 	    }
12142 	}
12143 	/*
12144 	* Traverse the axis and test the nodes.
12145 	*/
12146 	pos = 0;
12147 	cur = NULL;
12148 	hasNsNodes = 0;
12149         do {
12150             cur = next(ctxt, cur);
12151             if (cur == NULL)
12152                 break;
12153 
12154 	    /*
12155 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12156 	    */
12157             if ((first != NULL) && (*first != NULL)) {
12158 		if (*first == cur)
12159 		    break;
12160 		if (((total % 256) == 0) &&
12161 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12162 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12163 #else
12164 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12165 #endif
12166 		{
12167 		    break;
12168 		}
12169 	    }
12170 	    if ((last != NULL) && (*last != NULL)) {
12171 		if (*last == cur)
12172 		    break;
12173 		if (((total % 256) == 0) &&
12174 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12175 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12176 #else
12177 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12178 #endif
12179 		{
12180 		    break;
12181 		}
12182 	    }
12183 
12184             total++;
12185 
12186 #ifdef DEBUG_STEP
12187             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12188 #endif
12189 
12190 	    switch (test) {
12191                 case NODE_TEST_NONE:
12192 		    total = 0;
12193                     STRANGE
12194 		    goto error;
12195                 case NODE_TEST_TYPE:
12196 		    /*
12197 		    * TODO: Don't we need to use
12198 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12199 		    *  Surprisingly, some c14n tests fail, if we do this.
12200 		    */
12201 		    if (type == NODE_TYPE_NODE) {
12202 			switch (cur->type) {
12203 			    case XML_DOCUMENT_NODE:
12204 			    case XML_HTML_DOCUMENT_NODE:
12205 #ifdef LIBXML_DOCB_ENABLED
12206 			    case XML_DOCB_DOCUMENT_NODE:
12207 #endif
12208 			    case XML_ELEMENT_NODE:
12209 			    case XML_ATTRIBUTE_NODE:
12210 			    case XML_PI_NODE:
12211 			    case XML_COMMENT_NODE:
12212 			    case XML_CDATA_SECTION_NODE:
12213 			    case XML_TEXT_NODE:
12214 			    case XML_NAMESPACE_DECL:
12215 				XP_TEST_HIT
12216 				break;
12217 			    default:
12218 				break;
12219 			}
12220 		    } else if (cur->type == type) {
12221 			if (type == XML_NAMESPACE_DECL)
12222 			    XP_TEST_HIT_NS
12223 			else
12224 			    XP_TEST_HIT
12225 		    } else if ((type == NODE_TYPE_TEXT) &&
12226 			 (cur->type == XML_CDATA_SECTION_NODE))
12227 		    {
12228 			XP_TEST_HIT
12229 		    }
12230 		    break;
12231                 case NODE_TEST_PI:
12232                     if ((cur->type == XML_PI_NODE) &&
12233                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12234 		    {
12235 			XP_TEST_HIT
12236                     }
12237                     break;
12238                 case NODE_TEST_ALL:
12239                     if (axis == AXIS_ATTRIBUTE) {
12240                         if (cur->type == XML_ATTRIBUTE_NODE)
12241 			{
12242 			    XP_TEST_HIT
12243                         }
12244                     } else if (axis == AXIS_NAMESPACE) {
12245                         if (cur->type == XML_NAMESPACE_DECL)
12246 			{
12247 			    XP_TEST_HIT_NS
12248                         }
12249                     } else {
12250                         if (cur->type == XML_ELEMENT_NODE) {
12251                             if (prefix == NULL)
12252 			    {
12253 				XP_TEST_HIT
12254 
12255                             } else if ((cur->ns != NULL) &&
12256 				(xmlStrEqual(URI, cur->ns->href)))
12257 			    {
12258 				XP_TEST_HIT
12259                             }
12260                         }
12261                     }
12262                     break;
12263                 case NODE_TEST_NS:{
12264                         TODO;
12265                         break;
12266                     }
12267                 case NODE_TEST_NAME:
12268                     if (axis == AXIS_ATTRIBUTE) {
12269                         if (cur->type != XML_ATTRIBUTE_NODE)
12270 			    break;
12271 		    } else if (axis == AXIS_NAMESPACE) {
12272                         if (cur->type != XML_NAMESPACE_DECL)
12273 			    break;
12274 		    } else {
12275 		        if (cur->type != XML_ELEMENT_NODE)
12276 			    break;
12277 		    }
12278                     switch (cur->type) {
12279                         case XML_ELEMENT_NODE:
12280                             if (xmlStrEqual(name, cur->name)) {
12281                                 if (prefix == NULL) {
12282                                     if (cur->ns == NULL)
12283 				    {
12284 					XP_TEST_HIT
12285                                     }
12286                                 } else {
12287                                     if ((cur->ns != NULL) &&
12288                                         (xmlStrEqual(URI, cur->ns->href)))
12289 				    {
12290 					XP_TEST_HIT
12291                                     }
12292                                 }
12293                             }
12294                             break;
12295                         case XML_ATTRIBUTE_NODE:{
12296                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12297 
12298                                 if (xmlStrEqual(name, attr->name)) {
12299                                     if (prefix == NULL) {
12300                                         if ((attr->ns == NULL) ||
12301                                             (attr->ns->prefix == NULL))
12302 					{
12303 					    XP_TEST_HIT
12304                                         }
12305                                     } else {
12306                                         if ((attr->ns != NULL) &&
12307                                             (xmlStrEqual(URI,
12308 					      attr->ns->href)))
12309 					{
12310 					    XP_TEST_HIT
12311                                         }
12312                                     }
12313                                 }
12314                                 break;
12315                             }
12316                         case XML_NAMESPACE_DECL:
12317                             if (cur->type == XML_NAMESPACE_DECL) {
12318                                 xmlNsPtr ns = (xmlNsPtr) cur;
12319 
12320                                 if ((ns->prefix != NULL) && (name != NULL)
12321                                     && (xmlStrEqual(ns->prefix, name)))
12322 				{
12323 				    XP_TEST_HIT_NS
12324                                 }
12325                             }
12326                             break;
12327                         default:
12328                             break;
12329                     }
12330                     break;
12331 	    } /* switch(test) */
12332         } while (cur != NULL);
12333 
12334 	goto apply_predicates;
12335 
12336 axis_range_end: /* ----------------------------------------------------- */
12337 	/*
12338 	* We have a "/foo[n]", and position() = n was reached.
12339 	* Note that we can have as well "/foo/::parent::foo[1]", so
12340 	* a duplicate-aware merge is still needed.
12341 	* Merge with the result.
12342 	*/
12343 	if (outSeq == NULL) {
12344 	    outSeq = seq;
12345 	    seq = NULL;
12346 	} else
12347 	    outSeq = mergeAndClear(outSeq, seq, 0);
12348 	/*
12349 	* Break if only a true/false result was requested.
12350 	*/
12351 	if (toBool)
12352 	    break;
12353 	continue;
12354 
12355 first_hit: /* ---------------------------------------------------------- */
12356 	/*
12357 	* Break if only a true/false result was requested and
12358 	* no predicates existed and a node test succeeded.
12359 	*/
12360 	if (outSeq == NULL) {
12361 	    outSeq = seq;
12362 	    seq = NULL;
12363 	} else
12364 	    outSeq = mergeAndClear(outSeq, seq, 0);
12365 	break;
12366 
12367 #ifdef DEBUG_STEP
12368 	if (seq != NULL)
12369 	    nbMatches += seq->nodeNr;
12370 #endif
12371 
12372 apply_predicates: /* --------------------------------------------------- */
12373         /*
12374 	* Apply predicates.
12375 	*/
12376         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12377 	    /*
12378 	    * E.g. when we have a "/foo[some expression][n]".
12379 	    */
12380 	    /*
12381 	    * QUESTION TODO: The old predicate evaluation took into
12382 	    *  account location-sets.
12383 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12384 	    *  Do we expect such a set here?
12385 	    *  All what I learned now from the evaluation semantics
12386 	    *  does not indicate that a location-set will be processed
12387 	    *  here, so this looks OK.
12388 	    */
12389 	    /*
12390 	    * Iterate over all predicates, starting with the outermost
12391 	    * predicate.
12392 	    * TODO: Problem: we cannot execute the inner predicates first
12393 	    *  since we cannot go back *up* the operator tree!
12394 	    *  Options we have:
12395 	    *  1) Use of recursive functions (like is it currently done
12396 	    *     via xmlXPathCompOpEval())
12397 	    *  2) Add a predicate evaluation information stack to the
12398 	    *     context struct
12399 	    *  3) Change the way the operators are linked; we need a
12400 	    *     "parent" field on xmlXPathStepOp
12401 	    *
12402 	    * For the moment, I'll try to solve this with a recursive
12403 	    * function: xmlXPathCompOpEvalPredicate().
12404 	    */
12405 	    size = seq->nodeNr;
12406 	    if (hasPredicateRange != 0)
12407 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12408 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12409 	    else
12410 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12411 		    predOp, seq, size, hasNsNodes);
12412 
12413 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12414 		total = 0;
12415 		goto error;
12416 	    }
12417 	    /*
12418 	    * Add the filtered set of nodes to the result node set.
12419 	    */
12420 	    if (newSize == 0) {
12421 		/*
12422 		* The predicates filtered all nodes out.
12423 		*/
12424 		xmlXPathNodeSetClear(seq, hasNsNodes);
12425 	    } else if (seq->nodeNr > 0) {
12426 		/*
12427 		* Add to result set.
12428 		*/
12429 		if (outSeq == NULL) {
12430 		    if (size != newSize) {
12431 			/*
12432 			* We need to merge and clear here, since
12433 			* the sequence will contained NULLed entries.
12434 			*/
12435 			outSeq = mergeAndClear(NULL, seq, 1);
12436 		    } else {
12437 			outSeq = seq;
12438 			seq = NULL;
12439 		    }
12440 		} else
12441 		    outSeq = mergeAndClear(outSeq, seq,
12442 			(size != newSize) ? 1: 0);
12443 		/*
12444 		* Break if only a true/false result was requested.
12445 		*/
12446 		if (toBool)
12447 		    break;
12448 	    }
12449         } else if (seq->nodeNr > 0) {
12450 	    /*
12451 	    * Add to result set.
12452 	    */
12453 	    if (outSeq == NULL) {
12454 		outSeq = seq;
12455 		seq = NULL;
12456 	    } else {
12457 		outSeq = mergeAndClear(outSeq, seq, 0);
12458 	    }
12459 	}
12460     }
12461 
12462 error:
12463     if ((obj->boolval) && (obj->user != NULL)) {
12464 	/*
12465 	* QUESTION TODO: What does this do and why?
12466 	* TODO: Do we have to do this also for the "error"
12467 	* cleanup further down?
12468 	*/
12469 	ctxt->value->boolval = 1;
12470 	ctxt->value->user = obj->user;
12471 	obj->user = NULL;
12472 	obj->boolval = 0;
12473     }
12474     xmlXPathReleaseObject(xpctxt, obj);
12475 
12476     /*
12477     * Ensure we return at least an emtpy set.
12478     */
12479     if (outSeq == NULL) {
12480 	if ((seq != NULL) && (seq->nodeNr == 0))
12481 	    outSeq = seq;
12482 	else
12483 	    outSeq = xmlXPathNodeSetCreate(NULL);
12484     }
12485     if ((seq != NULL) && (seq != outSeq)) {
12486 	 xmlXPathFreeNodeSet(seq);
12487     }
12488     /*
12489     * Hand over the result. Better to push the set also in
12490     * case of errors.
12491     */
12492     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12493     /*
12494     * Reset the context node.
12495     */
12496     xpctxt->node = oldContextNode;
12497 
12498 #ifdef DEBUG_STEP
12499     xmlGenericError(xmlGenericErrorContext,
12500 	"\nExamined %d nodes, found %d nodes at that step\n",
12501 	total, nbMatches);
12502 #endif
12503 
12504     return(total);
12505 }
12506 
12507 static int
12508 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12509 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12510 
12511 /**
12512  * xmlXPathCompOpEvalFirst:
12513  * @ctxt:  the XPath parser context with the compiled expression
12514  * @op:  an XPath compiled operation
12515  * @first:  the first elem found so far
12516  *
12517  * Evaluate the Precompiled XPath operation searching only the first
12518  * element in document order
12519  *
12520  * Returns the number of examined objects.
12521  */
12522 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12523 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12524                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12525 {
12526     int total = 0, cur;
12527     xmlXPathCompExprPtr comp;
12528     xmlXPathObjectPtr arg1, arg2;
12529 
12530     CHECK_ERROR0;
12531     comp = ctxt->comp;
12532     switch (op->op) {
12533         case XPATH_OP_END:
12534             return (0);
12535         case XPATH_OP_UNION:
12536             total =
12537                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12538                                         first);
12539 	    CHECK_ERROR0;
12540             if ((ctxt->value != NULL)
12541                 && (ctxt->value->type == XPATH_NODESET)
12542                 && (ctxt->value->nodesetval != NULL)
12543                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12544                 /*
12545                  * limit tree traversing to first node in the result
12546                  */
12547 		/*
12548 		* OPTIMIZE TODO: This implicitely sorts
12549 		*  the result, even if not needed. E.g. if the argument
12550 		*  of the count() function, no sorting is needed.
12551 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12552 		*  aready sorted?
12553 		*/
12554 		if (ctxt->value->nodesetval->nodeNr > 1)
12555 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12556                 *first = ctxt->value->nodesetval->nodeTab[0];
12557             }
12558             cur =
12559                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12560                                         first);
12561 	    CHECK_ERROR0;
12562             CHECK_TYPE0(XPATH_NODESET);
12563             arg2 = valuePop(ctxt);
12564 
12565             CHECK_TYPE0(XPATH_NODESET);
12566             arg1 = valuePop(ctxt);
12567 
12568             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12569                                                     arg2->nodesetval);
12570             valuePush(ctxt, arg1);
12571 	    xmlXPathReleaseObject(ctxt->context, arg2);
12572             /* optimizer */
12573 	    if (total > cur)
12574 		xmlXPathCompSwap(op);
12575             return (total + cur);
12576         case XPATH_OP_ROOT:
12577             xmlXPathRoot(ctxt);
12578             return (0);
12579         case XPATH_OP_NODE:
12580             if (op->ch1 != -1)
12581                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12582 	    CHECK_ERROR0;
12583             if (op->ch2 != -1)
12584                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12585 	    CHECK_ERROR0;
12586 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12587 		ctxt->context->node));
12588             return (total);
12589         case XPATH_OP_RESET:
12590             if (op->ch1 != -1)
12591                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12592 	    CHECK_ERROR0;
12593             if (op->ch2 != -1)
12594                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12595 	    CHECK_ERROR0;
12596             ctxt->context->node = NULL;
12597             return (total);
12598         case XPATH_OP_COLLECT:{
12599                 if (op->ch1 == -1)
12600                     return (total);
12601 
12602                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12603 		CHECK_ERROR0;
12604 
12605                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12606                 return (total);
12607             }
12608         case XPATH_OP_VALUE:
12609             valuePush(ctxt,
12610                       xmlXPathCacheObjectCopy(ctxt->context,
12611 			(xmlXPathObjectPtr) op->value4));
12612             return (0);
12613         case XPATH_OP_SORT:
12614             if (op->ch1 != -1)
12615                 total +=
12616                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12617                                             first);
12618 	    CHECK_ERROR0;
12619             if ((ctxt->value != NULL)
12620                 && (ctxt->value->type == XPATH_NODESET)
12621                 && (ctxt->value->nodesetval != NULL)
12622 		&& (ctxt->value->nodesetval->nodeNr > 1))
12623                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12624             return (total);
12625 #ifdef XP_OPTIMIZED_FILTER_FIRST
12626 	case XPATH_OP_FILTER:
12627                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12628             return (total);
12629 #endif
12630         default:
12631             return (xmlXPathCompOpEval(ctxt, op));
12632     }
12633 }
12634 
12635 /**
12636  * xmlXPathCompOpEvalLast:
12637  * @ctxt:  the XPath parser context with the compiled expression
12638  * @op:  an XPath compiled operation
12639  * @last:  the last elem found so far
12640  *
12641  * Evaluate the Precompiled XPath operation searching only the last
12642  * element in document order
12643  *
12644  * Returns the number of nodes traversed
12645  */
12646 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12647 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12648                        xmlNodePtr * last)
12649 {
12650     int total = 0, cur;
12651     xmlXPathCompExprPtr comp;
12652     xmlXPathObjectPtr arg1, arg2;
12653     xmlNodePtr bak;
12654     xmlDocPtr bakd;
12655     int pp;
12656     int cs;
12657 
12658     CHECK_ERROR0;
12659     comp = ctxt->comp;
12660     switch (op->op) {
12661         case XPATH_OP_END:
12662             return (0);
12663         case XPATH_OP_UNION:
12664 	    bakd = ctxt->context->doc;
12665 	    bak = ctxt->context->node;
12666 	    pp = ctxt->context->proximityPosition;
12667 	    cs = ctxt->context->contextSize;
12668             total =
12669                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12670 	    CHECK_ERROR0;
12671             if ((ctxt->value != NULL)
12672                 && (ctxt->value->type == XPATH_NODESET)
12673                 && (ctxt->value->nodesetval != NULL)
12674                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12675                 /*
12676                  * limit tree traversing to first node in the result
12677                  */
12678 		if (ctxt->value->nodesetval->nodeNr > 1)
12679 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12680                 *last =
12681                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12682                                                      nodesetval->nodeNr -
12683                                                      1];
12684             }
12685 	    ctxt->context->doc = bakd;
12686 	    ctxt->context->node = bak;
12687 	    ctxt->context->proximityPosition = pp;
12688 	    ctxt->context->contextSize = cs;
12689             cur =
12690                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12691 	    CHECK_ERROR0;
12692             if ((ctxt->value != NULL)
12693                 && (ctxt->value->type == XPATH_NODESET)
12694                 && (ctxt->value->nodesetval != NULL)
12695                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12696             }
12697             CHECK_TYPE0(XPATH_NODESET);
12698             arg2 = valuePop(ctxt);
12699 
12700             CHECK_TYPE0(XPATH_NODESET);
12701             arg1 = valuePop(ctxt);
12702 
12703             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12704                                                     arg2->nodesetval);
12705             valuePush(ctxt, arg1);
12706 	    xmlXPathReleaseObject(ctxt->context, arg2);
12707             /* optimizer */
12708 	    if (total > cur)
12709 		xmlXPathCompSwap(op);
12710             return (total + cur);
12711         case XPATH_OP_ROOT:
12712             xmlXPathRoot(ctxt);
12713             return (0);
12714         case XPATH_OP_NODE:
12715             if (op->ch1 != -1)
12716                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12717 	    CHECK_ERROR0;
12718             if (op->ch2 != -1)
12719                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12720 	    CHECK_ERROR0;
12721 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12722 		ctxt->context->node));
12723             return (total);
12724         case XPATH_OP_RESET:
12725             if (op->ch1 != -1)
12726                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12727 	    CHECK_ERROR0;
12728             if (op->ch2 != -1)
12729                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12730 	    CHECK_ERROR0;
12731             ctxt->context->node = NULL;
12732             return (total);
12733         case XPATH_OP_COLLECT:{
12734                 if (op->ch1 == -1)
12735                     return (0);
12736 
12737                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12738 		CHECK_ERROR0;
12739 
12740                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12741                 return (total);
12742             }
12743         case XPATH_OP_VALUE:
12744             valuePush(ctxt,
12745                       xmlXPathCacheObjectCopy(ctxt->context,
12746 			(xmlXPathObjectPtr) op->value4));
12747             return (0);
12748         case XPATH_OP_SORT:
12749             if (op->ch1 != -1)
12750                 total +=
12751                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12752                                            last);
12753 	    CHECK_ERROR0;
12754             if ((ctxt->value != NULL)
12755                 && (ctxt->value->type == XPATH_NODESET)
12756                 && (ctxt->value->nodesetval != NULL)
12757 		&& (ctxt->value->nodesetval->nodeNr > 1))
12758                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12759             return (total);
12760         default:
12761             return (xmlXPathCompOpEval(ctxt, op));
12762     }
12763 }
12764 
12765 #ifdef XP_OPTIMIZED_FILTER_FIRST
12766 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12767 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12768 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12769 {
12770     int total = 0;
12771     xmlXPathCompExprPtr comp;
12772     xmlXPathObjectPtr res;
12773     xmlXPathObjectPtr obj;
12774     xmlNodeSetPtr oldset;
12775     xmlNodePtr oldnode;
12776     xmlDocPtr oldDoc;
12777     int i;
12778 
12779     CHECK_ERROR0;
12780     comp = ctxt->comp;
12781     /*
12782     * Optimization for ()[last()] selection i.e. the last elem
12783     */
12784     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12785 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12786 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12787 	int f = comp->steps[op->ch2].ch1;
12788 
12789 	if ((f != -1) &&
12790 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12791 	    (comp->steps[f].value5 == NULL) &&
12792 	    (comp->steps[f].value == 0) &&
12793 	    (comp->steps[f].value4 != NULL) &&
12794 	    (xmlStrEqual
12795 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12796 	    xmlNodePtr last = NULL;
12797 
12798 	    total +=
12799 		xmlXPathCompOpEvalLast(ctxt,
12800 		    &comp->steps[op->ch1],
12801 		    &last);
12802 	    CHECK_ERROR0;
12803 	    /*
12804 	    * The nodeset should be in document order,
12805 	    * Keep only the last value
12806 	    */
12807 	    if ((ctxt->value != NULL) &&
12808 		(ctxt->value->type == XPATH_NODESET) &&
12809 		(ctxt->value->nodesetval != NULL) &&
12810 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12811 		(ctxt->value->nodesetval->nodeNr > 1)) {
12812 		ctxt->value->nodesetval->nodeTab[0] =
12813 		    ctxt->value->nodesetval->nodeTab[ctxt->
12814 		    value->
12815 		    nodesetval->
12816 		    nodeNr -
12817 		    1];
12818 		ctxt->value->nodesetval->nodeNr = 1;
12819 		*first = *(ctxt->value->nodesetval->nodeTab);
12820 	    }
12821 	    return (total);
12822 	}
12823     }
12824 
12825     if (op->ch1 != -1)
12826 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827     CHECK_ERROR0;
12828     if (op->ch2 == -1)
12829 	return (total);
12830     if (ctxt->value == NULL)
12831 	return (total);
12832 
12833 #ifdef LIBXML_XPTR_ENABLED
12834     oldnode = ctxt->context->node;
12835     /*
12836     * Hum are we filtering the result of an XPointer expression
12837     */
12838     if (ctxt->value->type == XPATH_LOCATIONSET) {
12839 	xmlXPathObjectPtr tmp = NULL;
12840 	xmlLocationSetPtr newlocset = NULL;
12841 	xmlLocationSetPtr oldlocset;
12842 
12843 	/*
12844 	* Extract the old locset, and then evaluate the result of the
12845 	* expression for all the element in the locset. use it to grow
12846 	* up a new locset.
12847 	*/
12848 	CHECK_TYPE0(XPATH_LOCATIONSET);
12849 	obj = valuePop(ctxt);
12850 	oldlocset = obj->user;
12851 	ctxt->context->node = NULL;
12852 
12853 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12854 	    ctxt->context->contextSize = 0;
12855 	    ctxt->context->proximityPosition = 0;
12856 	    if (op->ch2 != -1)
12857 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12858 	    res = valuePop(ctxt);
12859 	    if (res != NULL) {
12860 		xmlXPathReleaseObject(ctxt->context, res);
12861 	    }
12862 	    valuePush(ctxt, obj);
12863 	    CHECK_ERROR0;
12864 	    return (total);
12865 	}
12866 	newlocset = xmlXPtrLocationSetCreate(NULL);
12867 
12868 	for (i = 0; i < oldlocset->locNr; i++) {
12869 	    /*
12870 	    * Run the evaluation with a node list made of a
12871 	    * single item in the nodelocset.
12872 	    */
12873 	    ctxt->context->node = oldlocset->locTab[i]->user;
12874 	    ctxt->context->contextSize = oldlocset->locNr;
12875 	    ctxt->context->proximityPosition = i + 1;
12876 	    if (tmp == NULL) {
12877 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12878 		    ctxt->context->node);
12879 	    } else {
12880 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12881 		    ctxt->context->node);
12882 	    }
12883 	    valuePush(ctxt, tmp);
12884 	    if (op->ch2 != -1)
12885 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12886 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12887 		xmlXPathFreeObject(obj);
12888 		return(0);
12889 	    }
12890 	    /*
12891 	    * The result of the evaluation need to be tested to
12892 	    * decided whether the filter succeeded or not
12893 	    */
12894 	    res = valuePop(ctxt);
12895 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12896 		xmlXPtrLocationSetAdd(newlocset,
12897 		    xmlXPathCacheObjectCopy(ctxt->context,
12898 			oldlocset->locTab[i]));
12899 	    }
12900 	    /*
12901 	    * Cleanup
12902 	    */
12903 	    if (res != NULL) {
12904 		xmlXPathReleaseObject(ctxt->context, res);
12905 	    }
12906 	    if (ctxt->value == tmp) {
12907 		valuePop(ctxt);
12908 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12909 		/*
12910 		* REVISIT TODO: Don't create a temporary nodeset
12911 		* for everly iteration.
12912 		*/
12913 		/* OLD: xmlXPathFreeObject(res); */
12914 	    } else
12915 		tmp = NULL;
12916 	    ctxt->context->node = NULL;
12917 	    /*
12918 	    * Only put the first node in the result, then leave.
12919 	    */
12920 	    if (newlocset->locNr > 0) {
12921 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12922 		break;
12923 	    }
12924 	}
12925 	if (tmp != NULL) {
12926 	    xmlXPathReleaseObject(ctxt->context, tmp);
12927 	}
12928 	/*
12929 	* The result is used as the new evaluation locset.
12930 	*/
12931 	xmlXPathReleaseObject(ctxt->context, obj);
12932 	ctxt->context->node = NULL;
12933 	ctxt->context->contextSize = -1;
12934 	ctxt->context->proximityPosition = -1;
12935 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12936 	ctxt->context->node = oldnode;
12937 	return (total);
12938     }
12939 #endif /* LIBXML_XPTR_ENABLED */
12940 
12941     /*
12942     * Extract the old set, and then evaluate the result of the
12943     * expression for all the element in the set. use it to grow
12944     * up a new set.
12945     */
12946     CHECK_TYPE0(XPATH_NODESET);
12947     obj = valuePop(ctxt);
12948     oldset = obj->nodesetval;
12949 
12950     oldnode = ctxt->context->node;
12951     oldDoc = ctxt->context->doc;
12952     ctxt->context->node = NULL;
12953 
12954     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12955 	ctxt->context->contextSize = 0;
12956 	ctxt->context->proximityPosition = 0;
12957 	/* QUESTION TODO: Why was this code commented out?
12958 	    if (op->ch2 != -1)
12959 		total +=
12960 		    xmlXPathCompOpEval(ctxt,
12961 			&comp->steps[op->ch2]);
12962 	    CHECK_ERROR0;
12963 	    res = valuePop(ctxt);
12964 	    if (res != NULL)
12965 		xmlXPathFreeObject(res);
12966 	*/
12967 	valuePush(ctxt, obj);
12968 	ctxt->context->node = oldnode;
12969 	CHECK_ERROR0;
12970     } else {
12971 	xmlNodeSetPtr newset;
12972 	xmlXPathObjectPtr tmp = NULL;
12973 	/*
12974 	* Initialize the new set.
12975 	* Also set the xpath document in case things like
12976 	* key() evaluation are attempted on the predicate
12977 	*/
12978 	newset = xmlXPathNodeSetCreate(NULL);
12979 
12980 	for (i = 0; i < oldset->nodeNr; i++) {
12981 	    /*
12982 	    * Run the evaluation with a node list made of
12983 	    * a single item in the nodeset.
12984 	    */
12985 	    ctxt->context->node = oldset->nodeTab[i];
12986 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12987 		(oldset->nodeTab[i]->doc != NULL))
12988 		ctxt->context->doc = oldset->nodeTab[i]->doc;
12989 	    if (tmp == NULL) {
12990 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12991 		    ctxt->context->node);
12992 	    } else {
12993 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12994 		    ctxt->context->node);
12995 	    }
12996 	    valuePush(ctxt, tmp);
12997 	    ctxt->context->contextSize = oldset->nodeNr;
12998 	    ctxt->context->proximityPosition = i + 1;
12999 	    if (op->ch2 != -1)
13000 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13001 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13002 		xmlXPathFreeNodeSet(newset);
13003 		xmlXPathFreeObject(obj);
13004 		return(0);
13005 	    }
13006 	    /*
13007 	    * The result of the evaluation needs to be tested to
13008 	    * decide whether the filter succeeded or not
13009 	    */
13010 	    res = valuePop(ctxt);
13011 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13012 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13013 	    }
13014 	    /*
13015 	    * Cleanup
13016 	    */
13017 	    if (res != NULL) {
13018 		xmlXPathReleaseObject(ctxt->context, res);
13019 	    }
13020 	    if (ctxt->value == tmp) {
13021 		valuePop(ctxt);
13022 		/*
13023 		* Don't free the temporary nodeset
13024 		* in order to avoid massive recreation inside this
13025 		* loop.
13026 		*/
13027 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13028 	    } else
13029 		tmp = NULL;
13030 	    ctxt->context->node = NULL;
13031 	    /*
13032 	    * Only put the first node in the result, then leave.
13033 	    */
13034 	    if (newset->nodeNr > 0) {
13035 		*first = *(newset->nodeTab);
13036 		break;
13037 	    }
13038 	}
13039 	if (tmp != NULL) {
13040 	    xmlXPathReleaseObject(ctxt->context, tmp);
13041 	}
13042 	/*
13043 	* The result is used as the new evaluation set.
13044 	*/
13045 	xmlXPathReleaseObject(ctxt->context, obj);
13046 	ctxt->context->node = NULL;
13047 	ctxt->context->contextSize = -1;
13048 	ctxt->context->proximityPosition = -1;
13049 	/* may want to move this past the '}' later */
13050 	ctxt->context->doc = oldDoc;
13051 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13052     }
13053     ctxt->context->node = oldnode;
13054     return(total);
13055 }
13056 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13057 
13058 /**
13059  * xmlXPathCompOpEval:
13060  * @ctxt:  the XPath parser context with the compiled expression
13061  * @op:  an XPath compiled operation
13062  *
13063  * Evaluate the Precompiled XPath operation
13064  * Returns the number of nodes traversed
13065  */
13066 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13067 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13068 {
13069     int total = 0;
13070     int equal, ret;
13071     xmlXPathCompExprPtr comp;
13072     xmlXPathObjectPtr arg1, arg2;
13073     xmlNodePtr bak;
13074     xmlDocPtr bakd;
13075     int pp;
13076     int cs;
13077 
13078     CHECK_ERROR0;
13079     comp = ctxt->comp;
13080     switch (op->op) {
13081         case XPATH_OP_END:
13082             return (0);
13083         case XPATH_OP_AND:
13084 	    bakd = ctxt->context->doc;
13085 	    bak = ctxt->context->node;
13086 	    pp = ctxt->context->proximityPosition;
13087 	    cs = ctxt->context->contextSize;
13088             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13089 	    CHECK_ERROR0;
13090             xmlXPathBooleanFunction(ctxt, 1);
13091             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13092                 return (total);
13093             arg2 = valuePop(ctxt);
13094 	    ctxt->context->doc = bakd;
13095 	    ctxt->context->node = bak;
13096 	    ctxt->context->proximityPosition = pp;
13097 	    ctxt->context->contextSize = cs;
13098             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13099 	    if (ctxt->error) {
13100 		xmlXPathFreeObject(arg2);
13101 		return(0);
13102 	    }
13103             xmlXPathBooleanFunction(ctxt, 1);
13104             arg1 = valuePop(ctxt);
13105             arg1->boolval &= arg2->boolval;
13106             valuePush(ctxt, arg1);
13107 	    xmlXPathReleaseObject(ctxt->context, arg2);
13108             return (total);
13109         case XPATH_OP_OR:
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 == 1))
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_EQUAL:
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 	    ctxt->context->doc = bakd;
13143 	    ctxt->context->node = bak;
13144 	    ctxt->context->proximityPosition = pp;
13145 	    ctxt->context->contextSize = cs;
13146             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13147 	    CHECK_ERROR0;
13148 	    if (op->value)
13149         	equal = xmlXPathEqualValues(ctxt);
13150 	    else
13151 		equal = xmlXPathNotEqualValues(ctxt);
13152 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13153             return (total);
13154         case XPATH_OP_CMP:
13155 	    bakd = ctxt->context->doc;
13156 	    bak = ctxt->context->node;
13157 	    pp = ctxt->context->proximityPosition;
13158 	    cs = ctxt->context->contextSize;
13159             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13160 	    CHECK_ERROR0;
13161 	    ctxt->context->doc = bakd;
13162 	    ctxt->context->node = bak;
13163 	    ctxt->context->proximityPosition = pp;
13164 	    ctxt->context->contextSize = cs;
13165             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13166 	    CHECK_ERROR0;
13167             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13168 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13169             return (total);
13170         case XPATH_OP_PLUS:
13171 	    bakd = ctxt->context->doc;
13172 	    bak = ctxt->context->node;
13173 	    pp = ctxt->context->proximityPosition;
13174 	    cs = ctxt->context->contextSize;
13175             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13176 	    CHECK_ERROR0;
13177             if (op->ch2 != -1) {
13178 		ctxt->context->doc = bakd;
13179 		ctxt->context->node = bak;
13180 		ctxt->context->proximityPosition = pp;
13181 		ctxt->context->contextSize = cs;
13182                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13183 	    }
13184 	    CHECK_ERROR0;
13185             if (op->value == 0)
13186                 xmlXPathSubValues(ctxt);
13187             else if (op->value == 1)
13188                 xmlXPathAddValues(ctxt);
13189             else if (op->value == 2)
13190                 xmlXPathValueFlipSign(ctxt);
13191             else if (op->value == 3) {
13192                 CAST_TO_NUMBER;
13193                 CHECK_TYPE0(XPATH_NUMBER);
13194             }
13195             return (total);
13196         case XPATH_OP_MULT:
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 	    ctxt->context->doc = bakd;
13204 	    ctxt->context->node = bak;
13205 	    ctxt->context->proximityPosition = pp;
13206 	    ctxt->context->contextSize = cs;
13207             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13208 	    CHECK_ERROR0;
13209             if (op->value == 0)
13210                 xmlXPathMultValues(ctxt);
13211             else if (op->value == 1)
13212                 xmlXPathDivValues(ctxt);
13213             else if (op->value == 2)
13214                 xmlXPathModValues(ctxt);
13215             return (total);
13216         case XPATH_OP_UNION:
13217 	    bakd = ctxt->context->doc;
13218 	    bak = ctxt->context->node;
13219 	    pp = ctxt->context->proximityPosition;
13220 	    cs = ctxt->context->contextSize;
13221             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13222 	    CHECK_ERROR0;
13223 	    ctxt->context->doc = bakd;
13224 	    ctxt->context->node = bak;
13225 	    ctxt->context->proximityPosition = pp;
13226 	    ctxt->context->contextSize = cs;
13227             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13228 	    CHECK_ERROR0;
13229             CHECK_TYPE0(XPATH_NODESET);
13230             arg2 = valuePop(ctxt);
13231 
13232             CHECK_TYPE0(XPATH_NODESET);
13233             arg1 = valuePop(ctxt);
13234 
13235 	    if ((arg1->nodesetval == NULL) ||
13236 		((arg2->nodesetval != NULL) &&
13237 		 (arg2->nodesetval->nodeNr != 0)))
13238 	    {
13239 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13240 							arg2->nodesetval);
13241 	    }
13242 
13243             valuePush(ctxt, arg1);
13244 	    xmlXPathReleaseObject(ctxt->context, arg2);
13245             return (total);
13246         case XPATH_OP_ROOT:
13247             xmlXPathRoot(ctxt);
13248             return (total);
13249         case XPATH_OP_NODE:
13250             if (op->ch1 != -1)
13251                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13252 	    CHECK_ERROR0;
13253             if (op->ch2 != -1)
13254                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13255 	    CHECK_ERROR0;
13256 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13257 		ctxt->context->node));
13258             return (total);
13259         case XPATH_OP_RESET:
13260             if (op->ch1 != -1)
13261                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13262 	    CHECK_ERROR0;
13263             if (op->ch2 != -1)
13264                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13265 	    CHECK_ERROR0;
13266             ctxt->context->node = NULL;
13267             return (total);
13268         case XPATH_OP_COLLECT:{
13269                 if (op->ch1 == -1)
13270                     return (total);
13271 
13272                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13273 		CHECK_ERROR0;
13274 
13275                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13276                 return (total);
13277             }
13278         case XPATH_OP_VALUE:
13279             valuePush(ctxt,
13280                       xmlXPathCacheObjectCopy(ctxt->context,
13281 			(xmlXPathObjectPtr) op->value4));
13282             return (total);
13283         case XPATH_OP_VARIABLE:{
13284 		xmlXPathObjectPtr val;
13285 
13286                 if (op->ch1 != -1)
13287                     total +=
13288                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13289                 if (op->value5 == NULL) {
13290 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13291 		    if (val == NULL) {
13292 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13293 			return(0);
13294 		    }
13295                     valuePush(ctxt, val);
13296 		} else {
13297                     const xmlChar *URI;
13298 
13299                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13300                     if (URI == NULL) {
13301                         xmlGenericError(xmlGenericErrorContext,
13302                                         "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13303                                         op->value4, op->value5);
13304                         return (total);
13305                     }
13306 		    val = xmlXPathVariableLookupNS(ctxt->context,
13307                                                        op->value4, URI);
13308 		    if (val == NULL) {
13309 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13310 			return(0);
13311 		    }
13312                     valuePush(ctxt, val);
13313                 }
13314                 return (total);
13315             }
13316         case XPATH_OP_FUNCTION:{
13317                 xmlXPathFunction func;
13318                 const xmlChar *oldFunc, *oldFuncURI;
13319 		int i;
13320 
13321                 if (op->ch1 != -1)
13322                     total +=
13323                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13324 		if (ctxt->valueNr < op->value) {
13325 		    xmlGenericError(xmlGenericErrorContext,
13326 			    "xmlXPathCompOpEval: parameter error\n");
13327 		    ctxt->error = XPATH_INVALID_OPERAND;
13328 		    return (total);
13329 		}
13330 		for (i = 0; i < op->value; i++)
13331 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13332 			xmlGenericError(xmlGenericErrorContext,
13333 				"xmlXPathCompOpEval: parameter error\n");
13334 			ctxt->error = XPATH_INVALID_OPERAND;
13335 			return (total);
13336 		    }
13337                 if (op->cache != NULL)
13338                     XML_CAST_FPTR(func) = op->cache;
13339                 else {
13340                     const xmlChar *URI = NULL;
13341 
13342                     if (op->value5 == NULL)
13343                         func =
13344                             xmlXPathFunctionLookup(ctxt->context,
13345                                                    op->value4);
13346                     else {
13347                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13348                         if (URI == NULL) {
13349                             xmlGenericError(xmlGenericErrorContext,
13350                                             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13351                                             op->value4, op->value5);
13352                             return (total);
13353                         }
13354                         func = xmlXPathFunctionLookupNS(ctxt->context,
13355                                                         op->value4, URI);
13356                     }
13357                     if (func == NULL) {
13358                         xmlGenericError(xmlGenericErrorContext,
13359                                         "xmlXPathCompOpEval: function %s not found\n",
13360                                         op->value4);
13361                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13362                     }
13363                     op->cache = XML_CAST_FPTR(func);
13364                     op->cacheURI = (void *) URI;
13365                 }
13366                 oldFunc = ctxt->context->function;
13367                 oldFuncURI = ctxt->context->functionURI;
13368                 ctxt->context->function = op->value4;
13369                 ctxt->context->functionURI = op->cacheURI;
13370                 func(ctxt, op->value);
13371                 ctxt->context->function = oldFunc;
13372                 ctxt->context->functionURI = oldFuncURI;
13373                 return (total);
13374             }
13375         case XPATH_OP_ARG:
13376 	    bakd = ctxt->context->doc;
13377 	    bak = ctxt->context->node;
13378 	    pp = ctxt->context->proximityPosition;
13379 	    cs = ctxt->context->contextSize;
13380             if (op->ch1 != -1)
13381                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13382 	    ctxt->context->contextSize = cs;
13383 	    ctxt->context->proximityPosition = pp;
13384 	    ctxt->context->node = bak;
13385 	    ctxt->context->doc = bakd;
13386 	    CHECK_ERROR0;
13387             if (op->ch2 != -1) {
13388                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13389 	        ctxt->context->doc = bakd;
13390 	        ctxt->context->node = bak;
13391 	        CHECK_ERROR0;
13392 	    }
13393             return (total);
13394         case XPATH_OP_PREDICATE:
13395         case XPATH_OP_FILTER:{
13396                 xmlXPathObjectPtr res;
13397                 xmlXPathObjectPtr obj, tmp;
13398                 xmlNodeSetPtr newset = NULL;
13399                 xmlNodeSetPtr oldset;
13400                 xmlNodePtr oldnode;
13401 		xmlDocPtr oldDoc;
13402                 int i;
13403 
13404                 /*
13405                  * Optimization for ()[1] selection i.e. the first elem
13406                  */
13407                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13408 #ifdef XP_OPTIMIZED_FILTER_FIRST
13409 		    /*
13410 		    * FILTER TODO: Can we assume that the inner processing
13411 		    *  will result in an ordered list if we have an
13412 		    *  XPATH_OP_FILTER?
13413 		    *  What about an additional field or flag on
13414 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13415 		    *  to assume anything, so it would be more robust and
13416 		    *  easier to optimize.
13417 		    */
13418                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13419 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13420 #else
13421 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13422 #endif
13423                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13424                     xmlXPathObjectPtr val;
13425 
13426                     val = comp->steps[op->ch2].value4;
13427                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13428                         (val->floatval == 1.0)) {
13429                         xmlNodePtr first = NULL;
13430 
13431                         total +=
13432                             xmlXPathCompOpEvalFirst(ctxt,
13433                                                     &comp->steps[op->ch1],
13434                                                     &first);
13435 			CHECK_ERROR0;
13436                         /*
13437                          * The nodeset should be in document order,
13438                          * Keep only the first value
13439                          */
13440                         if ((ctxt->value != NULL) &&
13441                             (ctxt->value->type == XPATH_NODESET) &&
13442                             (ctxt->value->nodesetval != NULL) &&
13443                             (ctxt->value->nodesetval->nodeNr > 1))
13444                             ctxt->value->nodesetval->nodeNr = 1;
13445                         return (total);
13446                     }
13447                 }
13448                 /*
13449                  * Optimization for ()[last()] selection i.e. the last elem
13450                  */
13451                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13452                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13453                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13454                     int f = comp->steps[op->ch2].ch1;
13455 
13456                     if ((f != -1) &&
13457                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13458                         (comp->steps[f].value5 == NULL) &&
13459                         (comp->steps[f].value == 0) &&
13460                         (comp->steps[f].value4 != NULL) &&
13461                         (xmlStrEqual
13462                          (comp->steps[f].value4, BAD_CAST "last"))) {
13463                         xmlNodePtr last = NULL;
13464 
13465                         total +=
13466                             xmlXPathCompOpEvalLast(ctxt,
13467                                                    &comp->steps[op->ch1],
13468                                                    &last);
13469 			CHECK_ERROR0;
13470                         /*
13471                          * The nodeset should be in document order,
13472                          * Keep only the last value
13473                          */
13474                         if ((ctxt->value != NULL) &&
13475                             (ctxt->value->type == XPATH_NODESET) &&
13476                             (ctxt->value->nodesetval != NULL) &&
13477                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13478                             (ctxt->value->nodesetval->nodeNr > 1)) {
13479                             ctxt->value->nodesetval->nodeTab[0] =
13480                                 ctxt->value->nodesetval->nodeTab[ctxt->
13481                                                                  value->
13482                                                                  nodesetval->
13483                                                                  nodeNr -
13484                                                                  1];
13485                             ctxt->value->nodesetval->nodeNr = 1;
13486                         }
13487                         return (total);
13488                     }
13489                 }
13490 		/*
13491 		* Process inner predicates first.
13492 		* Example "index[parent::book][1]":
13493 		* ...
13494 		*   PREDICATE   <-- we are here "[1]"
13495 		*     PREDICATE <-- process "[parent::book]" first
13496 		*       SORT
13497 		*         COLLECT  'parent' 'name' 'node' book
13498 		*           NODE
13499 		*     ELEM Object is a number : 1
13500 		*/
13501                 if (op->ch1 != -1)
13502                     total +=
13503                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13504 		CHECK_ERROR0;
13505                 if (op->ch2 == -1)
13506                     return (total);
13507                 if (ctxt->value == NULL)
13508                     return (total);
13509 
13510                 oldnode = ctxt->context->node;
13511 
13512 #ifdef LIBXML_XPTR_ENABLED
13513                 /*
13514                  * Hum are we filtering the result of an XPointer expression
13515                  */
13516                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13517                     xmlLocationSetPtr newlocset = NULL;
13518                     xmlLocationSetPtr oldlocset;
13519 
13520                     /*
13521                      * Extract the old locset, and then evaluate the result of the
13522                      * expression for all the element in the locset. use it to grow
13523                      * up a new locset.
13524                      */
13525                     CHECK_TYPE0(XPATH_LOCATIONSET);
13526                     obj = valuePop(ctxt);
13527                     oldlocset = obj->user;
13528                     ctxt->context->node = NULL;
13529 
13530                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13531                         ctxt->context->contextSize = 0;
13532                         ctxt->context->proximityPosition = 0;
13533                         if (op->ch2 != -1)
13534                             total +=
13535                                 xmlXPathCompOpEval(ctxt,
13536                                                    &comp->steps[op->ch2]);
13537                         res = valuePop(ctxt);
13538                         if (res != NULL) {
13539 			    xmlXPathReleaseObject(ctxt->context, res);
13540 			}
13541                         valuePush(ctxt, obj);
13542                         CHECK_ERROR0;
13543                         return (total);
13544                     }
13545                     newlocset = xmlXPtrLocationSetCreate(NULL);
13546 
13547                     for (i = 0; i < oldlocset->locNr; i++) {
13548                         /*
13549                          * Run the evaluation with a node list made of a
13550                          * single item in the nodelocset.
13551                          */
13552                         ctxt->context->node = oldlocset->locTab[i]->user;
13553                         ctxt->context->contextSize = oldlocset->locNr;
13554                         ctxt->context->proximityPosition = i + 1;
13555 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13556 			    ctxt->context->node);
13557                         valuePush(ctxt, tmp);
13558 
13559                         if (op->ch2 != -1)
13560                             total +=
13561                                 xmlXPathCompOpEval(ctxt,
13562                                                    &comp->steps[op->ch2]);
13563 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13564 			    xmlXPathFreeObject(obj);
13565 			    return(0);
13566 			}
13567 
13568                         /*
13569                          * The result of the evaluation need to be tested to
13570                          * decided whether the filter succeeded or not
13571                          */
13572                         res = valuePop(ctxt);
13573                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13574                             xmlXPtrLocationSetAdd(newlocset,
13575                                                   xmlXPathObjectCopy
13576                                                   (oldlocset->locTab[i]));
13577                         }
13578 
13579                         /*
13580                          * Cleanup
13581                          */
13582                         if (res != NULL) {
13583 			    xmlXPathReleaseObject(ctxt->context, res);
13584 			}
13585                         if (ctxt->value == tmp) {
13586                             res = valuePop(ctxt);
13587 			    xmlXPathReleaseObject(ctxt->context, res);
13588                         }
13589 
13590                         ctxt->context->node = NULL;
13591                     }
13592 
13593                     /*
13594                      * The result is used as the new evaluation locset.
13595                      */
13596 		    xmlXPathReleaseObject(ctxt->context, obj);
13597                     ctxt->context->node = NULL;
13598                     ctxt->context->contextSize = -1;
13599                     ctxt->context->proximityPosition = -1;
13600                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13601                     ctxt->context->node = oldnode;
13602                     return (total);
13603                 }
13604 #endif /* LIBXML_XPTR_ENABLED */
13605 
13606                 /*
13607                  * Extract the old set, and then evaluate the result of the
13608                  * expression for all the element in the set. use it to grow
13609                  * up a new set.
13610                  */
13611                 CHECK_TYPE0(XPATH_NODESET);
13612                 obj = valuePop(ctxt);
13613                 oldset = obj->nodesetval;
13614 
13615                 oldnode = ctxt->context->node;
13616 		oldDoc = ctxt->context->doc;
13617                 ctxt->context->node = NULL;
13618 
13619                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13620                     ctxt->context->contextSize = 0;
13621                     ctxt->context->proximityPosition = 0;
13622 /*
13623                     if (op->ch2 != -1)
13624                         total +=
13625                             xmlXPathCompOpEval(ctxt,
13626                                                &comp->steps[op->ch2]);
13627 		    CHECK_ERROR0;
13628                     res = valuePop(ctxt);
13629                     if (res != NULL)
13630                         xmlXPathFreeObject(res);
13631 */
13632                     valuePush(ctxt, obj);
13633                     ctxt->context->node = oldnode;
13634                     CHECK_ERROR0;
13635                 } else {
13636 		    tmp = NULL;
13637                     /*
13638                      * Initialize the new set.
13639 		     * Also set the xpath document in case things like
13640 		     * key() evaluation are attempted on the predicate
13641                      */
13642                     newset = xmlXPathNodeSetCreate(NULL);
13643 		    /*
13644 		    * SPEC XPath 1.0:
13645 		    *  "For each node in the node-set to be filtered, the
13646 		    *  PredicateExpr is evaluated with that node as the
13647 		    *  context node, with the number of nodes in the
13648 		    *  node-set as the context size, and with the proximity
13649 		    *  position of the node in the node-set with respect to
13650 		    *  the axis as the context position;"
13651 		    * @oldset is the node-set" to be filtered.
13652 		    *
13653 		    * SPEC XPath 1.0:
13654 		    *  "only predicates change the context position and
13655 		    *  context size (see [2.4 Predicates])."
13656 		    * Example:
13657 		    *   node-set  context pos
13658 		    *    nA         1
13659 		    *    nB         2
13660 		    *    nC         3
13661 		    *   After applying predicate [position() > 1] :
13662 		    *   node-set  context pos
13663 		    *    nB         1
13664 		    *    nC         2
13665 		    *
13666 		    * removed the first node in the node-set, then
13667 		    * the context position of the
13668 		    */
13669                     for (i = 0; i < oldset->nodeNr; i++) {
13670                         /*
13671                          * Run the evaluation with a node list made of
13672                          * a single item in the nodeset.
13673                          */
13674                         ctxt->context->node = oldset->nodeTab[i];
13675 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13676 			    (oldset->nodeTab[i]->doc != NULL))
13677 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13678 			if (tmp == NULL) {
13679 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13680 				ctxt->context->node);
13681 			} else {
13682 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13683 				ctxt->context->node);
13684 			}
13685                         valuePush(ctxt, tmp);
13686                         ctxt->context->contextSize = oldset->nodeNr;
13687                         ctxt->context->proximityPosition = i + 1;
13688 			/*
13689 			* Evaluate the predicate against the context node.
13690 			* Can/should we optimize position() predicates
13691 			* here (e.g. "[1]")?
13692 			*/
13693                         if (op->ch2 != -1)
13694                             total +=
13695                                 xmlXPathCompOpEval(ctxt,
13696                                                    &comp->steps[op->ch2]);
13697 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13698 			    xmlXPathFreeNodeSet(newset);
13699 			    xmlXPathFreeObject(obj);
13700 			    return(0);
13701 			}
13702 
13703                         /*
13704                          * The result of the evaluation needs to be tested to
13705                          * decide whether the filter succeeded or not
13706                          */
13707 			/*
13708 			* OPTIMIZE TODO: Can we use
13709 			* xmlXPathNodeSetAdd*Unique()* instead?
13710 			*/
13711                         res = valuePop(ctxt);
13712                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13713                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13714                         }
13715 
13716                         /*
13717                          * Cleanup
13718                          */
13719                         if (res != NULL) {
13720 			    xmlXPathReleaseObject(ctxt->context, res);
13721 			}
13722                         if (ctxt->value == tmp) {
13723                             valuePop(ctxt);
13724 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13725 			    /*
13726 			    * Don't free the temporary nodeset
13727 			    * in order to avoid massive recreation inside this
13728 			    * loop.
13729 			    */
13730                         } else
13731 			    tmp = NULL;
13732                         ctxt->context->node = NULL;
13733                     }
13734 		    if (tmp != NULL)
13735 			xmlXPathReleaseObject(ctxt->context, tmp);
13736                     /*
13737                      * The result is used as the new evaluation set.
13738                      */
13739 		    xmlXPathReleaseObject(ctxt->context, obj);
13740                     ctxt->context->node = NULL;
13741                     ctxt->context->contextSize = -1;
13742                     ctxt->context->proximityPosition = -1;
13743 		    /* may want to move this past the '}' later */
13744 		    ctxt->context->doc = oldDoc;
13745 		    valuePush(ctxt,
13746 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13747                 }
13748                 ctxt->context->node = oldnode;
13749                 return (total);
13750             }
13751         case XPATH_OP_SORT:
13752             if (op->ch1 != -1)
13753                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13754 	    CHECK_ERROR0;
13755             if ((ctxt->value != NULL) &&
13756                 (ctxt->value->type == XPATH_NODESET) &&
13757                 (ctxt->value->nodesetval != NULL) &&
13758 		(ctxt->value->nodesetval->nodeNr > 1))
13759 	    {
13760                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13761 	    }
13762             return (total);
13763 #ifdef LIBXML_XPTR_ENABLED
13764         case XPATH_OP_RANGETO:{
13765                 xmlXPathObjectPtr range;
13766                 xmlXPathObjectPtr res, obj;
13767                 xmlXPathObjectPtr tmp;
13768                 xmlLocationSetPtr newlocset = NULL;
13769 		    xmlLocationSetPtr oldlocset;
13770                 xmlNodeSetPtr oldset;
13771                 int i, j;
13772 
13773                 if (op->ch1 != -1)
13774                     total +=
13775                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13776                 if (op->ch2 == -1)
13777                     return (total);
13778 
13779                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13780                     /*
13781                      * Extract the old locset, and then evaluate the result of the
13782                      * expression for all the element in the locset. use it to grow
13783                      * up a new locset.
13784                      */
13785                     CHECK_TYPE0(XPATH_LOCATIONSET);
13786                     obj = valuePop(ctxt);
13787                     oldlocset = obj->user;
13788 
13789                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13790 		        ctxt->context->node = NULL;
13791                         ctxt->context->contextSize = 0;
13792                         ctxt->context->proximityPosition = 0;
13793                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13794                         res = valuePop(ctxt);
13795                         if (res != NULL) {
13796 			    xmlXPathReleaseObject(ctxt->context, res);
13797 			}
13798                         valuePush(ctxt, obj);
13799                         CHECK_ERROR0;
13800                         return (total);
13801                     }
13802                     newlocset = xmlXPtrLocationSetCreate(NULL);
13803 
13804                     for (i = 0; i < oldlocset->locNr; i++) {
13805                         /*
13806                          * Run the evaluation with a node list made of a
13807                          * single item in the nodelocset.
13808                          */
13809                         ctxt->context->node = oldlocset->locTab[i]->user;
13810                         ctxt->context->contextSize = oldlocset->locNr;
13811                         ctxt->context->proximityPosition = i + 1;
13812 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13813 			    ctxt->context->node);
13814                         valuePush(ctxt, tmp);
13815 
13816                         if (op->ch2 != -1)
13817                             total +=
13818                                 xmlXPathCompOpEval(ctxt,
13819                                                    &comp->steps[op->ch2]);
13820 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13821 			    xmlXPathFreeObject(obj);
13822 			    return(0);
13823 			}
13824 
13825                         res = valuePop(ctxt);
13826 			if (res->type == XPATH_LOCATIONSET) {
13827 			    xmlLocationSetPtr rloc =
13828 			        (xmlLocationSetPtr)res->user;
13829 			    for (j=0; j<rloc->locNr; j++) {
13830 			        range = xmlXPtrNewRange(
13831 				  oldlocset->locTab[i]->user,
13832 				  oldlocset->locTab[i]->index,
13833 				  rloc->locTab[j]->user2,
13834 				  rloc->locTab[j]->index2);
13835 				if (range != NULL) {
13836 				    xmlXPtrLocationSetAdd(newlocset, range);
13837 				}
13838 			    }
13839 			} else {
13840 			    range = xmlXPtrNewRangeNodeObject(
13841 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13842                             if (range != NULL) {
13843                                 xmlXPtrLocationSetAdd(newlocset,range);
13844 			    }
13845                         }
13846 
13847                         /*
13848                          * Cleanup
13849                          */
13850                         if (res != NULL) {
13851 			    xmlXPathReleaseObject(ctxt->context, res);
13852 			}
13853                         if (ctxt->value == tmp) {
13854                             res = valuePop(ctxt);
13855 			    xmlXPathReleaseObject(ctxt->context, res);
13856                         }
13857 
13858                         ctxt->context->node = NULL;
13859                     }
13860 		} else {	/* Not a location set */
13861                     CHECK_TYPE0(XPATH_NODESET);
13862                     obj = valuePop(ctxt);
13863                     oldset = obj->nodesetval;
13864                     ctxt->context->node = NULL;
13865 
13866                     newlocset = xmlXPtrLocationSetCreate(NULL);
13867 
13868                     if (oldset != NULL) {
13869                         for (i = 0; i < oldset->nodeNr; i++) {
13870                             /*
13871                              * Run the evaluation with a node list made of a single item
13872                              * in the nodeset.
13873                              */
13874                             ctxt->context->node = oldset->nodeTab[i];
13875 			    /*
13876 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13877 			    */
13878 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13879 				ctxt->context->node);
13880                             valuePush(ctxt, tmp);
13881 
13882                             if (op->ch2 != -1)
13883                                 total +=
13884                                     xmlXPathCompOpEval(ctxt,
13885                                                    &comp->steps[op->ch2]);
13886 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13887 				xmlXPathFreeObject(obj);
13888 				return(0);
13889 			    }
13890 
13891                             res = valuePop(ctxt);
13892                             range =
13893                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13894                                                       res);
13895                             if (range != NULL) {
13896                                 xmlXPtrLocationSetAdd(newlocset, range);
13897                             }
13898 
13899                             /*
13900                              * Cleanup
13901                              */
13902                             if (res != NULL) {
13903 				xmlXPathReleaseObject(ctxt->context, res);
13904 			    }
13905                             if (ctxt->value == tmp) {
13906                                 res = valuePop(ctxt);
13907 				xmlXPathReleaseObject(ctxt->context, res);
13908                             }
13909 
13910                             ctxt->context->node = NULL;
13911                         }
13912                     }
13913                 }
13914 
13915                 /*
13916                  * The result is used as the new evaluation set.
13917                  */
13918 		xmlXPathReleaseObject(ctxt->context, obj);
13919                 ctxt->context->node = NULL;
13920                 ctxt->context->contextSize = -1;
13921                 ctxt->context->proximityPosition = -1;
13922                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13923                 return (total);
13924             }
13925 #endif /* LIBXML_XPTR_ENABLED */
13926     }
13927     xmlGenericError(xmlGenericErrorContext,
13928                     "XPath: unknown precompiled operation %d\n", op->op);
13929     return (total);
13930 }
13931 
13932 /**
13933  * xmlXPathCompOpEvalToBoolean:
13934  * @ctxt:  the XPath parser context
13935  *
13936  * Evaluates if the expression evaluates to true.
13937  *
13938  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13939  */
13940 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13941 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13942 			    xmlXPathStepOpPtr op,
13943 			    int isPredicate)
13944 {
13945     xmlXPathObjectPtr resObj = NULL;
13946 
13947 start:
13948     /* comp = ctxt->comp; */
13949     switch (op->op) {
13950         case XPATH_OP_END:
13951             return (0);
13952 	case XPATH_OP_VALUE:
13953 	    resObj = (xmlXPathObjectPtr) op->value4;
13954 	    if (isPredicate)
13955 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13956 	    return(xmlXPathCastToBoolean(resObj));
13957 	case XPATH_OP_SORT:
13958 	    /*
13959 	    * We don't need sorting for boolean results. Skip this one.
13960 	    */
13961             if (op->ch1 != -1) {
13962 		op = &ctxt->comp->steps[op->ch1];
13963 		goto start;
13964 	    }
13965 	    return(0);
13966 	case XPATH_OP_COLLECT:
13967 	    if (op->ch1 == -1)
13968 		return(0);
13969 
13970             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13971 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13972 		return(-1);
13973 
13974             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13975 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13976 		return(-1);
13977 
13978 	    resObj = valuePop(ctxt);
13979 	    if (resObj == NULL)
13980 		return(-1);
13981 	    break;
13982 	default:
13983 	    /*
13984 	    * Fallback to call xmlXPathCompOpEval().
13985 	    */
13986 	    xmlXPathCompOpEval(ctxt, op);
13987 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13988 		return(-1);
13989 
13990 	    resObj = valuePop(ctxt);
13991 	    if (resObj == NULL)
13992 		return(-1);
13993 	    break;
13994     }
13995 
13996     if (resObj) {
13997 	int res;
13998 
13999 	if (resObj->type == XPATH_BOOLEAN) {
14000 	    res = resObj->boolval;
14001 	} else if (isPredicate) {
14002 	    /*
14003 	    * For predicates a result of type "number" is handled
14004 	    * differently:
14005 	    * SPEC XPath 1.0:
14006 	    * "If the result is a number, the result will be converted
14007 	    *  to true if the number is equal to the context position
14008 	    *  and will be converted to false otherwise;"
14009 	    */
14010 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14011 	} else {
14012 	    res = xmlXPathCastToBoolean(resObj);
14013 	}
14014 	xmlXPathReleaseObject(ctxt->context, resObj);
14015 	return(res);
14016     }
14017 
14018     return(0);
14019 }
14020 
14021 #ifdef XPATH_STREAMING
14022 /**
14023  * xmlXPathRunStreamEval:
14024  * @ctxt:  the XPath parser context with the compiled expression
14025  *
14026  * Evaluate the Precompiled Streamable XPath expression in the given context.
14027  */
14028 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14029 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14030 		      xmlXPathObjectPtr *resultSeq, int toBool)
14031 {
14032     int max_depth, min_depth;
14033     int from_root;
14034     int ret, depth;
14035     int eval_all_nodes;
14036     xmlNodePtr cur = NULL, limit = NULL;
14037     xmlStreamCtxtPtr patstream = NULL;
14038 
14039     int nb_nodes = 0;
14040 
14041     if ((ctxt == NULL) || (comp == NULL))
14042         return(-1);
14043     max_depth = xmlPatternMaxDepth(comp);
14044     if (max_depth == -1)
14045         return(-1);
14046     if (max_depth == -2)
14047         max_depth = 10000;
14048     min_depth = xmlPatternMinDepth(comp);
14049     if (min_depth == -1)
14050         return(-1);
14051     from_root = xmlPatternFromRoot(comp);
14052     if (from_root < 0)
14053         return(-1);
14054 #if 0
14055     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14056 #endif
14057 
14058     if (! toBool) {
14059 	if (resultSeq == NULL)
14060 	    return(-1);
14061 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14062 	if (*resultSeq == NULL)
14063 	    return(-1);
14064     }
14065 
14066     /*
14067      * handle the special cases of "/" amd "." being matched
14068      */
14069     if (min_depth == 0) {
14070 	if (from_root) {
14071 	    /* Select "/" */
14072 	    if (toBool)
14073 		return(1);
14074 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14075 		(xmlNodePtr) ctxt->doc);
14076 	} else {
14077 	    /* Select "self::node()" */
14078 	    if (toBool)
14079 		return(1);
14080 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14081 	}
14082     }
14083     if (max_depth == 0) {
14084 	return(0);
14085     }
14086 
14087     if (from_root) {
14088         cur = (xmlNodePtr)ctxt->doc;
14089     } else if (ctxt->node != NULL) {
14090         switch (ctxt->node->type) {
14091             case XML_ELEMENT_NODE:
14092             case XML_DOCUMENT_NODE:
14093             case XML_DOCUMENT_FRAG_NODE:
14094             case XML_HTML_DOCUMENT_NODE:
14095 #ifdef LIBXML_DOCB_ENABLED
14096             case XML_DOCB_DOCUMENT_NODE:
14097 #endif
14098 	        cur = ctxt->node;
14099 		break;
14100             case XML_ATTRIBUTE_NODE:
14101             case XML_TEXT_NODE:
14102             case XML_CDATA_SECTION_NODE:
14103             case XML_ENTITY_REF_NODE:
14104             case XML_ENTITY_NODE:
14105             case XML_PI_NODE:
14106             case XML_COMMENT_NODE:
14107             case XML_NOTATION_NODE:
14108             case XML_DTD_NODE:
14109             case XML_DOCUMENT_TYPE_NODE:
14110             case XML_ELEMENT_DECL:
14111             case XML_ATTRIBUTE_DECL:
14112             case XML_ENTITY_DECL:
14113             case XML_NAMESPACE_DECL:
14114             case XML_XINCLUDE_START:
14115             case XML_XINCLUDE_END:
14116 		break;
14117 	}
14118 	limit = cur;
14119     }
14120     if (cur == NULL) {
14121         return(0);
14122     }
14123 
14124     patstream = xmlPatternGetStreamCtxt(comp);
14125     if (patstream == NULL) {
14126 	/*
14127 	* QUESTION TODO: Is this an error?
14128 	*/
14129 	return(0);
14130     }
14131 
14132     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14133 
14134     if (from_root) {
14135 	ret = xmlStreamPush(patstream, NULL, NULL);
14136 	if (ret < 0) {
14137 	} else if (ret == 1) {
14138 	    if (toBool)
14139 		goto return_1;
14140 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14141 	}
14142     }
14143     depth = 0;
14144     goto scan_children;
14145 next_node:
14146     do {
14147         nb_nodes++;
14148 
14149 	switch (cur->type) {
14150 	    case XML_ELEMENT_NODE:
14151 	    case XML_TEXT_NODE:
14152 	    case XML_CDATA_SECTION_NODE:
14153 	    case XML_COMMENT_NODE:
14154 	    case XML_PI_NODE:
14155 		if (cur->type == XML_ELEMENT_NODE) {
14156 		    ret = xmlStreamPush(patstream, cur->name,
14157 				(cur->ns ? cur->ns->href : NULL));
14158 		} else if (eval_all_nodes)
14159 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14160 		else
14161 		    break;
14162 
14163 		if (ret < 0) {
14164 		    /* NOP. */
14165 		} else if (ret == 1) {
14166 		    if (toBool)
14167 			goto return_1;
14168 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14169 		}
14170 		if ((cur->children == NULL) || (depth >= max_depth)) {
14171 		    ret = xmlStreamPop(patstream);
14172 		    while (cur->next != NULL) {
14173 			cur = cur->next;
14174 			if ((cur->type != XML_ENTITY_DECL) &&
14175 			    (cur->type != XML_DTD_NODE))
14176 			    goto next_node;
14177 		    }
14178 		}
14179 	    default:
14180 		break;
14181 	}
14182 
14183 scan_children:
14184 	if ((cur->children != NULL) && (depth < max_depth)) {
14185 	    /*
14186 	     * Do not descend on entities declarations
14187 	     */
14188 	    if (cur->children->type != XML_ENTITY_DECL) {
14189 		cur = cur->children;
14190 		depth++;
14191 		/*
14192 		 * Skip DTDs
14193 		 */
14194 		if (cur->type != XML_DTD_NODE)
14195 		    continue;
14196 	    }
14197 	}
14198 
14199 	if (cur == limit)
14200 	    break;
14201 
14202 	while (cur->next != NULL) {
14203 	    cur = cur->next;
14204 	    if ((cur->type != XML_ENTITY_DECL) &&
14205 		(cur->type != XML_DTD_NODE))
14206 		goto next_node;
14207 	}
14208 
14209 	do {
14210 	    cur = cur->parent;
14211 	    depth--;
14212 	    if ((cur == NULL) || (cur == limit))
14213 	        goto done;
14214 	    if (cur->type == XML_ELEMENT_NODE) {
14215 		ret = xmlStreamPop(patstream);
14216 	    } else if ((eval_all_nodes) &&
14217 		((cur->type == XML_TEXT_NODE) ||
14218 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14219 		 (cur->type == XML_COMMENT_NODE) ||
14220 		 (cur->type == XML_PI_NODE)))
14221 	    {
14222 		ret = xmlStreamPop(patstream);
14223 	    }
14224 	    if (cur->next != NULL) {
14225 		cur = cur->next;
14226 		break;
14227 	    }
14228 	} while (cur != NULL);
14229 
14230     } while ((cur != NULL) && (depth >= 0));
14231 
14232 done:
14233 
14234 #if 0
14235     printf("stream eval: checked %d nodes selected %d\n",
14236            nb_nodes, retObj->nodesetval->nodeNr);
14237 #endif
14238 
14239     if (patstream)
14240 	xmlFreeStreamCtxt(patstream);
14241     return(0);
14242 
14243 return_1:
14244     if (patstream)
14245 	xmlFreeStreamCtxt(patstream);
14246     return(1);
14247 }
14248 #endif /* XPATH_STREAMING */
14249 
14250 /**
14251  * xmlXPathRunEval:
14252  * @ctxt:  the XPath parser context with the compiled expression
14253  * @toBool:  evaluate to a boolean result
14254  *
14255  * Evaluate the Precompiled XPath expression in the given context.
14256  */
14257 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14258 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14259 {
14260     xmlXPathCompExprPtr comp;
14261 
14262     if ((ctxt == NULL) || (ctxt->comp == NULL))
14263 	return(-1);
14264 
14265     if (ctxt->valueTab == NULL) {
14266 	/* Allocate the value stack */
14267 	ctxt->valueTab = (xmlXPathObjectPtr *)
14268 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14269 	if (ctxt->valueTab == NULL) {
14270 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14271 	    xmlFree(ctxt);
14272 	}
14273 	ctxt->valueNr = 0;
14274 	ctxt->valueMax = 10;
14275 	ctxt->value = NULL;
14276     }
14277 #ifdef XPATH_STREAMING
14278     if (ctxt->comp->stream) {
14279 	int res;
14280 
14281 	if (toBool) {
14282 	    /*
14283 	    * Evaluation to boolean result.
14284 	    */
14285 	    res = xmlXPathRunStreamEval(ctxt->context,
14286 		ctxt->comp->stream, NULL, 1);
14287 	    if (res != -1)
14288 		return(res);
14289 	} else {
14290 	    xmlXPathObjectPtr resObj = NULL;
14291 
14292 	    /*
14293 	    * Evaluation to a sequence.
14294 	    */
14295 	    res = xmlXPathRunStreamEval(ctxt->context,
14296 		ctxt->comp->stream, &resObj, 0);
14297 
14298 	    if ((res != -1) && (resObj != NULL)) {
14299 		valuePush(ctxt, resObj);
14300 		return(0);
14301 	    }
14302 	    if (resObj != NULL)
14303 		xmlXPathReleaseObject(ctxt->context, resObj);
14304 	}
14305 	/*
14306 	* QUESTION TODO: This falls back to normal XPath evaluation
14307 	* if res == -1. Is this intended?
14308 	*/
14309     }
14310 #endif
14311     comp = ctxt->comp;
14312     if (comp->last < 0) {
14313 	xmlGenericError(xmlGenericErrorContext,
14314 	    "xmlXPathRunEval: last is less than zero\n");
14315 	return(-1);
14316     }
14317     if (toBool)
14318 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14319 	    &comp->steps[comp->last], 0));
14320     else
14321 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14322 
14323     return(0);
14324 }
14325 
14326 /************************************************************************
14327  *									*
14328  * 			Public interfaces				*
14329  *									*
14330  ************************************************************************/
14331 
14332 /**
14333  * xmlXPathEvalPredicate:
14334  * @ctxt:  the XPath context
14335  * @res:  the Predicate Expression evaluation result
14336  *
14337  * Evaluate a predicate result for the current node.
14338  * A PredicateExpr is evaluated by evaluating the Expr and converting
14339  * the result to a boolean. If the result is a number, the result will
14340  * be converted to true if the number is equal to the position of the
14341  * context node in the context node list (as returned by the position
14342  * function) and will be converted to false otherwise; if the result
14343  * is not a number, then the result will be converted as if by a call
14344  * to the boolean function.
14345  *
14346  * Returns 1 if predicate is true, 0 otherwise
14347  */
14348 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14349 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14350     if ((ctxt == NULL) || (res == NULL)) return(0);
14351     switch (res->type) {
14352         case XPATH_BOOLEAN:
14353 	    return(res->boolval);
14354         case XPATH_NUMBER:
14355 	    return(res->floatval == ctxt->proximityPosition);
14356         case XPATH_NODESET:
14357         case XPATH_XSLT_TREE:
14358 	    if (res->nodesetval == NULL)
14359 		return(0);
14360 	    return(res->nodesetval->nodeNr != 0);
14361         case XPATH_STRING:
14362 	    return((res->stringval != NULL) &&
14363 	           (xmlStrlen(res->stringval) != 0));
14364         default:
14365 	    STRANGE
14366     }
14367     return(0);
14368 }
14369 
14370 /**
14371  * xmlXPathEvaluatePredicateResult:
14372  * @ctxt:  the XPath Parser context
14373  * @res:  the Predicate Expression evaluation result
14374  *
14375  * Evaluate a predicate result for the current node.
14376  * A PredicateExpr is evaluated by evaluating the Expr and converting
14377  * the result to a boolean. If the result is a number, the result will
14378  * be converted to true if the number is equal to the position of the
14379  * context node in the context node list (as returned by the position
14380  * function) and will be converted to false otherwise; if the result
14381  * is not a number, then the result will be converted as if by a call
14382  * to the boolean function.
14383  *
14384  * Returns 1 if predicate is true, 0 otherwise
14385  */
14386 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14387 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14388                                 xmlXPathObjectPtr res) {
14389     if ((ctxt == NULL) || (res == NULL)) return(0);
14390     switch (res->type) {
14391         case XPATH_BOOLEAN:
14392 	    return(res->boolval);
14393         case XPATH_NUMBER:
14394 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14395 	    return((res->floatval == ctxt->context->proximityPosition) &&
14396 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14397 #else
14398 	    return(res->floatval == ctxt->context->proximityPosition);
14399 #endif
14400         case XPATH_NODESET:
14401         case XPATH_XSLT_TREE:
14402 	    if (res->nodesetval == NULL)
14403 		return(0);
14404 	    return(res->nodesetval->nodeNr != 0);
14405         case XPATH_STRING:
14406 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14407 #ifdef LIBXML_XPTR_ENABLED
14408 	case XPATH_LOCATIONSET:{
14409 	    xmlLocationSetPtr ptr = res->user;
14410 	    if (ptr == NULL)
14411 	        return(0);
14412 	    return (ptr->locNr != 0);
14413 	    }
14414 #endif
14415         default:
14416 	    STRANGE
14417     }
14418     return(0);
14419 }
14420 
14421 #ifdef XPATH_STREAMING
14422 /**
14423  * xmlXPathTryStreamCompile:
14424  * @ctxt: an XPath context
14425  * @str:  the XPath expression
14426  *
14427  * Try to compile the XPath expression as a streamable subset.
14428  *
14429  * Returns the compiled expression or NULL if failed to compile.
14430  */
14431 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14432 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14433     /*
14434      * Optimization: use streaming patterns when the XPath expression can
14435      * be compiled to a stream lookup
14436      */
14437     xmlPatternPtr stream;
14438     xmlXPathCompExprPtr comp;
14439     xmlDictPtr dict = NULL;
14440     const xmlChar **namespaces = NULL;
14441     xmlNsPtr ns;
14442     int i, j;
14443 
14444     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14445         (!xmlStrchr(str, '@'))) {
14446 	const xmlChar *tmp;
14447 
14448 	/*
14449 	 * We don't try to handle expressions using the verbose axis
14450 	 * specifiers ("::"), just the simplied form at this point.
14451 	 * Additionally, if there is no list of namespaces available and
14452 	 *  there's a ":" in the expression, indicating a prefixed QName,
14453 	 *  then we won't try to compile either. xmlPatterncompile() needs
14454 	 *  to have a list of namespaces at compilation time in order to
14455 	 *  compile prefixed name tests.
14456 	 */
14457 	tmp = xmlStrchr(str, ':');
14458 	if ((tmp != NULL) &&
14459 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14460 	    return(NULL);
14461 
14462 	if (ctxt != NULL) {
14463 	    dict = ctxt->dict;
14464 	    if (ctxt->nsNr > 0) {
14465 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14466 		if (namespaces == NULL) {
14467 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14468 		    return(NULL);
14469 		}
14470 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14471 		    ns = ctxt->namespaces[j];
14472 		    namespaces[i++] = ns->href;
14473 		    namespaces[i++] = ns->prefix;
14474 		}
14475 		namespaces[i++] = NULL;
14476 		namespaces[i++] = NULL;
14477 	    }
14478 	}
14479 
14480 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14481 			&namespaces[0]);
14482 	if (namespaces != NULL) {
14483 	    xmlFree((xmlChar **)namespaces);
14484  	}
14485 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14486 	    comp = xmlXPathNewCompExpr();
14487 	    if (comp == NULL) {
14488 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14489 		return(NULL);
14490 	    }
14491 	    comp->stream = stream;
14492 	    comp->dict = dict;
14493 	    if (comp->dict)
14494 		xmlDictReference(comp->dict);
14495 	    return(comp);
14496 	}
14497 	xmlFreePattern(stream);
14498     }
14499     return(NULL);
14500 }
14501 #endif /* XPATH_STREAMING */
14502 
14503 static int
xmlXPathCanRewriteDosExpression(xmlChar * expr)14504 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14505 {
14506     if (expr == NULL)
14507 	return(0);
14508     do {
14509         if ((*expr == '/') && (*(++expr) == '/'))
14510 	    return(1);
14511     } while (*expr++);
14512     return(0);
14513 }
14514 static void
xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14515 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14516 {
14517     /*
14518     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14519     * internal representation.
14520     */
14521     if (op->ch1 != -1) {
14522 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14523 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14524 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14525 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14526 	{
14527 	    /*
14528 	    * This is a "child::foo"
14529 	    */
14530 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14531 
14532 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14533 		(prevop->ch1 != -1) &&
14534 		((xmlXPathAxisVal) prevop->value ==
14535 		    AXIS_DESCENDANT_OR_SELF) &&
14536 		(prevop->ch2 == -1) &&
14537 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14538 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14539 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14540 	    {
14541 		/*
14542 		* This is a "/descendant-or-self::node()" without predicates.
14543 		* Eliminate it.
14544 		*/
14545 		op->ch1 = prevop->ch1;
14546 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14547 	    }
14548 	}
14549 	if (op->ch1 != -1)
14550 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14551     }
14552     if (op->ch2 != -1)
14553 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14554 }
14555 
14556 /**
14557  * xmlXPathCtxtCompile:
14558  * @ctxt: an XPath context
14559  * @str:  the XPath expression
14560  *
14561  * Compile an XPath expression
14562  *
14563  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14564  *         the caller has to free the object.
14565  */
14566 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14567 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14568     xmlXPathParserContextPtr pctxt;
14569     xmlXPathCompExprPtr comp;
14570 
14571 #ifdef XPATH_STREAMING
14572     comp = xmlXPathTryStreamCompile(ctxt, str);
14573     if (comp != NULL)
14574         return(comp);
14575 #endif
14576 
14577     xmlXPathInit();
14578 
14579     pctxt = xmlXPathNewParserContext(str, ctxt);
14580     if (pctxt == NULL)
14581         return NULL;
14582     xmlXPathCompileExpr(pctxt, 1);
14583 
14584     if( pctxt->error != XPATH_EXPRESSION_OK )
14585     {
14586         xmlXPathFreeParserContext(pctxt);
14587         return(NULL);
14588     }
14589 
14590     if (*pctxt->cur != 0) {
14591 	/*
14592 	 * aleksey: in some cases this line prints *second* error message
14593 	 * (see bug #78858) and probably this should be fixed.
14594 	 * However, we are not sure that all error messages are printed
14595 	 * out in other places. It's not critical so we leave it as-is for now
14596 	 */
14597 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14598 	comp = NULL;
14599     } else {
14600 	comp = pctxt->comp;
14601 	pctxt->comp = NULL;
14602     }
14603     xmlXPathFreeParserContext(pctxt);
14604 
14605     if (comp != NULL) {
14606 	comp->expr = xmlStrdup(str);
14607 #ifdef DEBUG_EVAL_COUNTS
14608 	comp->string = xmlStrdup(str);
14609 	comp->nb = 0;
14610 #endif
14611 	if ((comp->expr != NULL) &&
14612 	    (comp->nbStep > 2) &&
14613 	    (comp->last >= 0) &&
14614 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14615 	{
14616 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14617 	}
14618     }
14619     return(comp);
14620 }
14621 
14622 /**
14623  * xmlXPathCompile:
14624  * @str:  the XPath expression
14625  *
14626  * Compile an XPath expression
14627  *
14628  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14629  *         the caller has to free the object.
14630  */
14631 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14632 xmlXPathCompile(const xmlChar *str) {
14633     return(xmlXPathCtxtCompile(NULL, str));
14634 }
14635 
14636 /**
14637  * xmlXPathCompiledEvalInternal:
14638  * @comp:  the compiled XPath expression
14639  * @ctxt:  the XPath context
14640  * @resObj: the resulting XPath object or NULL
14641  * @toBool: 1 if only a boolean result is requested
14642  *
14643  * Evaluate the Precompiled XPath expression in the given context.
14644  * The caller has to free @resObj.
14645  *
14646  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14647  *         the caller has to free the object.
14648  */
14649 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObj,int toBool)14650 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14651 			     xmlXPathContextPtr ctxt,
14652 			     xmlXPathObjectPtr *resObj,
14653 			     int toBool)
14654 {
14655     xmlXPathParserContextPtr pctxt;
14656 #ifndef LIBXML_THREAD_ENABLED
14657     static int reentance = 0;
14658 #endif
14659     int res;
14660 
14661     CHECK_CTXT_NEG(ctxt)
14662 
14663     if (comp == NULL)
14664 	return(-1);
14665     xmlXPathInit();
14666 
14667 #ifndef LIBXML_THREAD_ENABLED
14668     reentance++;
14669     if (reentance > 1)
14670 	xmlXPathDisableOptimizer = 1;
14671 #endif
14672 
14673 #ifdef DEBUG_EVAL_COUNTS
14674     comp->nb++;
14675     if ((comp->string != NULL) && (comp->nb > 100)) {
14676 	fprintf(stderr, "100 x %s\n", comp->string);
14677 	comp->nb = 0;
14678     }
14679 #endif
14680     pctxt = xmlXPathCompParserContext(comp, ctxt);
14681     res = xmlXPathRunEval(pctxt, toBool);
14682 
14683     if (resObj) {
14684 	if (pctxt->value == NULL) {
14685 	    xmlGenericError(xmlGenericErrorContext,
14686 		"xmlXPathCompiledEval: evaluation failed\n");
14687 	    *resObj = NULL;
14688 	} else {
14689 	    *resObj = valuePop(pctxt);
14690 	}
14691     }
14692 
14693     /*
14694     * Pop all remaining objects from the stack.
14695     */
14696     if (pctxt->valueNr > 0) {
14697 	xmlXPathObjectPtr tmp;
14698 	int stack = 0;
14699 
14700 	do {
14701 	    tmp = valuePop(pctxt);
14702 	    if (tmp != NULL) {
14703 		stack++;
14704 		xmlXPathReleaseObject(ctxt, tmp);
14705 	    }
14706 	} while (tmp != NULL);
14707 	if ((stack != 0) &&
14708 	    ((toBool) || ((resObj) && (*resObj))))
14709 	{
14710 	    xmlGenericError(xmlGenericErrorContext,
14711 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14712 		stack);
14713 	}
14714     }
14715 
14716     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14717 	xmlXPathFreeObject(*resObj);
14718 	*resObj = NULL;
14719     }
14720     pctxt->comp = NULL;
14721     xmlXPathFreeParserContext(pctxt);
14722 #ifndef LIBXML_THREAD_ENABLED
14723     reentance--;
14724 #endif
14725 
14726     return(res);
14727 }
14728 
14729 /**
14730  * xmlXPathCompiledEval:
14731  * @comp:  the compiled XPath expression
14732  * @ctx:  the XPath context
14733  *
14734  * Evaluate the Precompiled XPath expression in the given context.
14735  *
14736  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14737  *         the caller has to free the object.
14738  */
14739 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14740 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14741 {
14742     xmlXPathObjectPtr res = NULL;
14743 
14744     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14745     return(res);
14746 }
14747 
14748 /**
14749  * xmlXPathCompiledEvalToBoolean:
14750  * @comp:  the compiled XPath expression
14751  * @ctxt:  the XPath context
14752  *
14753  * Applies the XPath boolean() function on the result of the given
14754  * compiled expression.
14755  *
14756  * Returns 1 if the expression evaluated to true, 0 if to false and
14757  *         -1 in API and internal errors.
14758  */
14759 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14760 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14761 			      xmlXPathContextPtr ctxt)
14762 {
14763     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14764 }
14765 
14766 /**
14767  * xmlXPathEvalExpr:
14768  * @ctxt:  the XPath Parser context
14769  *
14770  * Parse and evaluate an XPath expression in the given context,
14771  * then push the result on the context stack
14772  */
14773 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14774 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14775 #ifdef XPATH_STREAMING
14776     xmlXPathCompExprPtr comp;
14777 #endif
14778 
14779     if (ctxt == NULL) return;
14780 
14781 #ifdef XPATH_STREAMING
14782     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14783     if (comp != NULL) {
14784         if (ctxt->comp != NULL)
14785 	    xmlXPathFreeCompExpr(ctxt->comp);
14786         ctxt->comp = comp;
14787 	if (ctxt->cur != NULL)
14788 	    while (*ctxt->cur != 0) ctxt->cur++;
14789     } else
14790 #endif
14791     {
14792 	xmlXPathCompileExpr(ctxt, 1);
14793 	/*
14794 	* In this scenario the expression string will sit in ctxt->base.
14795 	*/
14796 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14797 	    (ctxt->comp != NULL) &&
14798 	    (ctxt->base != NULL) &&
14799 	    (ctxt->comp->nbStep > 2) &&
14800 	    (ctxt->comp->last >= 0) &&
14801 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14802 	{
14803 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14804 		&ctxt->comp->steps[ctxt->comp->last]);
14805 	}
14806     }
14807     CHECK_ERROR;
14808     xmlXPathRunEval(ctxt, 0);
14809 }
14810 
14811 /**
14812  * xmlXPathEval:
14813  * @str:  the XPath expression
14814  * @ctx:  the XPath context
14815  *
14816  * Evaluate the XPath Location Path in the given context.
14817  *
14818  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14819  *         the caller has to free the object.
14820  */
14821 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14822 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14823     xmlXPathParserContextPtr ctxt;
14824     xmlXPathObjectPtr res, tmp, init = NULL;
14825     int stack = 0;
14826 
14827     CHECK_CTXT(ctx)
14828 
14829     xmlXPathInit();
14830 
14831     ctxt = xmlXPathNewParserContext(str, ctx);
14832     if (ctxt == NULL)
14833         return NULL;
14834     xmlXPathEvalExpr(ctxt);
14835 
14836     if (ctxt->value == NULL) {
14837 	xmlGenericError(xmlGenericErrorContext,
14838 		"xmlXPathEval: evaluation failed\n");
14839 	res = NULL;
14840     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14841 #ifdef XPATH_STREAMING
14842             && (ctxt->comp->stream == NULL)
14843 #endif
14844 	      ) {
14845 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14846 	res = NULL;
14847     } else {
14848 	res = valuePop(ctxt);
14849     }
14850 
14851     do {
14852         tmp = valuePop(ctxt);
14853 	if (tmp != NULL) {
14854 	    if (tmp != init)
14855 		stack++;
14856 	    xmlXPathReleaseObject(ctx, tmp);
14857         }
14858     } while (tmp != NULL);
14859     if ((stack != 0) && (res != NULL)) {
14860 	xmlGenericError(xmlGenericErrorContext,
14861 		"xmlXPathEval: %d object left on the stack\n",
14862 	        stack);
14863     }
14864     if (ctxt->error != XPATH_EXPRESSION_OK) {
14865 	xmlXPathFreeObject(res);
14866 	res = NULL;
14867     }
14868 
14869     xmlXPathFreeParserContext(ctxt);
14870     return(res);
14871 }
14872 
14873 /**
14874  * xmlXPathEvalExpression:
14875  * @str:  the XPath expression
14876  * @ctxt:  the XPath context
14877  *
14878  * Evaluate the XPath expression in the given context.
14879  *
14880  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14881  *         the caller has to free the object.
14882  */
14883 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14884 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14885     xmlXPathParserContextPtr pctxt;
14886     xmlXPathObjectPtr res, tmp;
14887     int stack = 0;
14888 
14889     CHECK_CTXT(ctxt)
14890 
14891     xmlXPathInit();
14892 
14893     pctxt = xmlXPathNewParserContext(str, ctxt);
14894     if (pctxt == NULL)
14895         return NULL;
14896     xmlXPathEvalExpr(pctxt);
14897 
14898     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14899 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14900 	res = NULL;
14901     } else {
14902 	res = valuePop(pctxt);
14903     }
14904     do {
14905         tmp = valuePop(pctxt);
14906 	if (tmp != NULL) {
14907 	    xmlXPathReleaseObject(ctxt, tmp);
14908 	    stack++;
14909 	}
14910     } while (tmp != NULL);
14911     if ((stack != 0) && (res != NULL)) {
14912 	xmlGenericError(xmlGenericErrorContext,
14913 		"xmlXPathEvalExpression: %d object left on the stack\n",
14914 	        stack);
14915     }
14916     xmlXPathFreeParserContext(pctxt);
14917     return(res);
14918 }
14919 
14920 /************************************************************************
14921  *									*
14922  *	Extra functions not pertaining to the XPath spec		*
14923  *									*
14924  ************************************************************************/
14925 /**
14926  * xmlXPathEscapeUriFunction:
14927  * @ctxt:  the XPath Parser context
14928  * @nargs:  the number of arguments
14929  *
14930  * Implement the escape-uri() XPath function
14931  *    string escape-uri(string $str, bool $escape-reserved)
14932  *
14933  * This function applies the URI escaping rules defined in section 2 of [RFC
14934  * 2396] to the string supplied as $uri-part, which typically represents all
14935  * or part of a URI. The effect of the function is to replace any special
14936  * character in the string by an escape sequence of the form %xx%yy...,
14937  * where xxyy... is the hexadecimal representation of the octets used to
14938  * represent the character in UTF-8.
14939  *
14940  * The set of characters that are escaped depends on the setting of the
14941  * boolean argument $escape-reserved.
14942  *
14943  * If $escape-reserved is true, all characters are escaped other than lower
14944  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14945  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14946  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14947  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14948  * A-F).
14949  *
14950  * If $escape-reserved is false, the behavior differs in that characters
14951  * referred to in [RFC 2396] as reserved characters are not escaped. These
14952  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14953  *
14954  * [RFC 2396] does not define whether escaped URIs should use lower case or
14955  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14956  * compared using string comparison functions, this function must always use
14957  * the upper-case letters A-F.
14958  *
14959  * Generally, $escape-reserved should be set to true when escaping a string
14960  * that is to form a single part of a URI, and to false when escaping an
14961  * entire URI or URI reference.
14962  *
14963  * In the case of non-ascii characters, the string is encoded according to
14964  * utf-8 and then converted according to RFC 2396.
14965  *
14966  * Examples
14967  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14968  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14969  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14970  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14971  *
14972  */
14973 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14974 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14975     xmlXPathObjectPtr str;
14976     int escape_reserved;
14977     xmlBufferPtr target;
14978     xmlChar *cptr;
14979     xmlChar escape[4];
14980 
14981     CHECK_ARITY(2);
14982 
14983     escape_reserved = xmlXPathPopBoolean(ctxt);
14984 
14985     CAST_TO_STRING;
14986     str = valuePop(ctxt);
14987 
14988     target = xmlBufferCreate();
14989 
14990     escape[0] = '%';
14991     escape[3] = 0;
14992 
14993     if (target) {
14994 	for (cptr = str->stringval; *cptr; cptr++) {
14995 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14996 		(*cptr >= 'a' && *cptr <= 'z') ||
14997 		(*cptr >= '0' && *cptr <= '9') ||
14998 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14999 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15000 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15001 		(*cptr == '%' &&
15002 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15003 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15004 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15005 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15006 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15007 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15008 		(!escape_reserved &&
15009 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15010 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15011 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15012 		  *cptr == ','))) {
15013 		xmlBufferAdd(target, cptr, 1);
15014 	    } else {
15015 		if ((*cptr >> 4) < 10)
15016 		    escape[1] = '0' + (*cptr >> 4);
15017 		else
15018 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15019 		if ((*cptr & 0xF) < 10)
15020 		    escape[2] = '0' + (*cptr & 0xF);
15021 		else
15022 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15023 
15024 		xmlBufferAdd(target, &escape[0], 3);
15025 	    }
15026 	}
15027     }
15028     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15029 	xmlBufferContent(target)));
15030     xmlBufferFree(target);
15031     xmlXPathReleaseObject(ctxt->context, str);
15032 }
15033 
15034 /**
15035  * xmlXPathRegisterAllFunctions:
15036  * @ctxt:  the XPath context
15037  *
15038  * Registers all default XPath functions in this context
15039  */
15040 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15041 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15042 {
15043     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15044                          xmlXPathBooleanFunction);
15045     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15046                          xmlXPathCeilingFunction);
15047     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15048                          xmlXPathCountFunction);
15049     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15050                          xmlXPathConcatFunction);
15051     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15052                          xmlXPathContainsFunction);
15053     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15054                          xmlXPathIdFunction);
15055     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15056                          xmlXPathFalseFunction);
15057     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15058                          xmlXPathFloorFunction);
15059     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15060                          xmlXPathLastFunction);
15061     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15062                          xmlXPathLangFunction);
15063     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15064                          xmlXPathLocalNameFunction);
15065     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15066                          xmlXPathNotFunction);
15067     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15068                          xmlXPathNameFunction);
15069     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15070                          xmlXPathNamespaceURIFunction);
15071     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15072                          xmlXPathNormalizeFunction);
15073     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15074                          xmlXPathNumberFunction);
15075     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15076                          xmlXPathPositionFunction);
15077     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15078                          xmlXPathRoundFunction);
15079     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15080                          xmlXPathStringFunction);
15081     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15082                          xmlXPathStringLengthFunction);
15083     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15084                          xmlXPathStartsWithFunction);
15085     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15086                          xmlXPathSubstringFunction);
15087     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15088                          xmlXPathSubstringBeforeFunction);
15089     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15090                          xmlXPathSubstringAfterFunction);
15091     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15092                          xmlXPathSumFunction);
15093     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15094                          xmlXPathTrueFunction);
15095     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15096                          xmlXPathTranslateFunction);
15097 
15098     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15099 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15100                          xmlXPathEscapeUriFunction);
15101 }
15102 
15103 #endif /* LIBXML_XPATH_ENABLED */
15104 #define bottom_xpath
15105 #include "elfgcchack.h"
15106