• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 #define IN_LIBXML
18 #include "libxml.h"
19 
20 #include <string.h>
21 
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37 
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57 
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61 
62 #define TODO								\
63     xmlGenericError(xmlGenericErrorContext,				\
64 	    "Unimplemented block at %s:%d\n",				\
65             __FILE__, __LINE__);
66 
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77 
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84 
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91 
92 /*
93  * TODO:
94  * There are a few spots where some tests are done which depend upon ascii
95  * data.  These should be enhanced for full UTF8 support (see particularly
96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97  */
98 
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100 
101 /************************************************************************
102  *									*
103  *			Floating point stuff				*
104  *									*
105  ************************************************************************/
106 
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111 
112 /*
113  * The lack of portability of this section of the libc is annoying !
114  */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120 
121 /**
122  * xmlXPathInit:
123  *
124  * Initialize the XPath environment
125  */
126 void
xmlXPathInit(void)127 xmlXPathInit(void) {
128     if (xmlXPathInitialized) return;
129 
130     xmlXPathPINF = trio_pinf();
131     xmlXPathNINF = trio_ninf();
132     xmlXPathNAN = trio_nan();
133     xmlXPathNZERO = trio_nzero();
134 
135     xmlXPathInitialized = 1;
136 }
137 
138 /**
139  * xmlXPathIsNaN:
140  * @val:  a double value
141  *
142  * Provides a portable isnan() function to detect whether a double
143  * is a NotaNumber. Based on trio code
144  * http://sourceforge.net/projects/ctrio/
145  *
146  * Returns 1 if the value is a NaN, 0 otherwise
147  */
148 int
xmlXPathIsNaN(double val)149 xmlXPathIsNaN(double val) {
150     return(trio_isnan(val));
151 }
152 
153 /**
154  * xmlXPathIsInf:
155  * @val:  a double value
156  *
157  * Provides a portable isinf() function to detect whether a double
158  * is a +Infinite or -Infinite. Based on trio code
159  * http://sourceforge.net/projects/ctrio/
160  *
161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162  */
163 int
xmlXPathIsInf(double val)164 xmlXPathIsInf(double val) {
165     return(trio_isinf(val));
166 }
167 
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171  * xmlXPathGetSign:
172  * @val:  a double value
173  *
174  * Provides a portable function to detect the sign of a double
175  * Modified from trio code
176  * http://sourceforge.net/projects/ctrio/
177  *
178  * Returns 1 if the value is Negative, 0 if positive
179  */
180 static int
xmlXPathGetSign(double val)181 xmlXPathGetSign(double val) {
182     return(trio_signbit(val));
183 }
184 
185 
186 /*
187  * TODO: when compatibility allows remove all "fake node libxslt" strings
188  *       the test should just be name[0] = ' '
189  */
190 #ifdef DEBUG_XPATH_EXPRESSION
191 #define DEBUG_STEP
192 #define DEBUG_EXPR
193 #define DEBUG_EVAL_COUNTS
194 #endif
195 
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197     NULL,
198     XML_NAMESPACE_DECL,
199     XML_XML_NAMESPACE,
200     BAD_CAST "xml",
201     NULL,
202     NULL
203 };
204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205 #ifndef LIBXML_THREAD_ENABLED
206 /*
207  * Optimizer is disabled only when threaded apps are detected while
208  * the library ain't compiled for thread safety.
209  */
210 static int xmlXPathDisableOptimizer = 0;
211 #endif
212 
213 /************************************************************************
214  *									*
215  *			Error handling routines				*
216  *									*
217  ************************************************************************/
218 
219 /**
220  * XP_ERRORNULL:
221  * @X:  the error code
222  *
223  * Macro to raise an XPath error and return NULL.
224  */
225 #define XP_ERRORNULL(X)							\
226     { xmlXPathErr(ctxt, X); return(NULL); }
227 
228 /*
229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230  */
231 static const char *xmlXPathErrorMessages[] = {
232     "Ok\n",
233     "Number encoding\n",
234     "Unfinished literal\n",
235     "Start of literal\n",
236     "Expected $ for variable reference\n",
237     "Undefined variable\n",
238     "Invalid predicate\n",
239     "Invalid expression\n",
240     "Missing closing curly brace\n",
241     "Unregistered function\n",
242     "Invalid operand\n",
243     "Invalid type\n",
244     "Invalid number of arguments\n",
245     "Invalid context size\n",
246     "Invalid context position\n",
247     "Memory allocation error\n",
248     "Syntax error\n",
249     "Resource error\n",
250     "Sub resource error\n",
251     "Undefined namespace prefix\n",
252     "Encoding error\n",
253     "Char out of XML range\n",
254     "Invalid or incomplete context\n",
255     "Stack usage errror\n",
256     "?? Unknown error ??\n"	/* Must be last in the list! */
257 };
258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
259 		   sizeof(xmlXPathErrorMessages[0])) - 1)
260 /**
261  * xmlXPathErrMemory:
262  * @ctxt:  an XPath context
263  * @extra:  extra informations
264  *
265  * Handle a redefinition of attribute error
266  */
267 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
269 {
270     if (ctxt != NULL) {
271         if (extra) {
272             xmlChar buf[200];
273 
274             xmlStrPrintf(buf, 200,
275                          BAD_CAST "Memory allocation failed : %s\n",
276                          extra);
277             ctxt->lastError.message = (char *) xmlStrdup(buf);
278         } else {
279             ctxt->lastError.message = (char *)
280 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
281         }
282         ctxt->lastError.domain = XML_FROM_XPATH;
283         ctxt->lastError.code = XML_ERR_NO_MEMORY;
284 	if (ctxt->error != NULL)
285 	    ctxt->error(ctxt->userData, &ctxt->lastError);
286     } else {
287         if (extra)
288             __xmlRaiseError(NULL, NULL, NULL,
289                             NULL, NULL, XML_FROM_XPATH,
290                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291                             extra, NULL, NULL, 0, 0,
292                             "Memory allocation failed : %s\n", extra);
293         else
294             __xmlRaiseError(NULL, NULL, NULL,
295                             NULL, NULL, XML_FROM_XPATH,
296                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297                             NULL, NULL, NULL, 0, 0,
298                             "Memory allocation failed\n");
299     }
300 }
301 
302 /**
303  * xmlXPathPErrMemory:
304  * @ctxt:  an XPath parser context
305  * @extra:  extra informations
306  *
307  * Handle a redefinition of attribute error
308  */
309 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311 {
312     if (ctxt == NULL)
313 	xmlXPathErrMemory(NULL, extra);
314     else {
315 	ctxt->error = XPATH_MEMORY_ERROR;
316 	xmlXPathErrMemory(ctxt->context, extra);
317     }
318 }
319 
320 /**
321  * xmlXPathErr:
322  * @ctxt:  a XPath parser context
323  * @error:  the error code
324  *
325  * Handle an XPath error
326  */
327 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329 {
330     if ((error < 0) || (error > MAXERRNO))
331 	error = MAXERRNO;
332     if (ctxt == NULL) {
333 	__xmlRaiseError(NULL, NULL, NULL,
334 			NULL, NULL, XML_FROM_XPATH,
335 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336 			XML_ERR_ERROR, NULL, 0,
337 			NULL, NULL, NULL, 0, 0,
338 			"%s", xmlXPathErrorMessages[error]);
339 	return;
340     }
341     ctxt->error = error;
342     if (ctxt->context == NULL) {
343 	__xmlRaiseError(NULL, NULL, NULL,
344 			NULL, NULL, XML_FROM_XPATH,
345 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346 			XML_ERR_ERROR, NULL, 0,
347 			(const char *) ctxt->base, NULL, NULL,
348 			ctxt->cur - ctxt->base, 0,
349 			"%s", xmlXPathErrorMessages[error]);
350 	return;
351     }
352 
353     /* cleanup current last error */
354     xmlResetError(&ctxt->context->lastError);
355 
356     ctxt->context->lastError.domain = XML_FROM_XPATH;
357     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358                            XPATH_EXPRESSION_OK;
359     ctxt->context->lastError.level = XML_ERR_ERROR;
360     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362     ctxt->context->lastError.node = ctxt->context->debugNode;
363     if (ctxt->context->error != NULL) {
364 	ctxt->context->error(ctxt->context->userData,
365 	                     &ctxt->context->lastError);
366     } else {
367 	__xmlRaiseError(NULL, NULL, NULL,
368 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370 			XML_ERR_ERROR, NULL, 0,
371 			(const char *) ctxt->base, NULL, NULL,
372 			ctxt->cur - ctxt->base, 0,
373 			"%s", xmlXPathErrorMessages[error]);
374     }
375 
376 }
377 
378 /**
379  * xmlXPatherror:
380  * @ctxt:  the XPath Parser context
381  * @file:  the file name
382  * @line:  the line number
383  * @no:  the error number
384  *
385  * Formats an error message.
386  */
387 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389               int line ATTRIBUTE_UNUSED, int no) {
390     xmlXPathErr(ctxt, no);
391 }
392 
393 /************************************************************************
394  *									*
395  *			Utilities					*
396  *									*
397  ************************************************************************/
398 
399 /**
400  * xsltPointerList:
401  *
402  * Pointer-list for various purposes.
403  */
404 typedef struct _xmlPointerList xmlPointerList;
405 typedef xmlPointerList *xmlPointerListPtr;
406 struct _xmlPointerList {
407     void **items;
408     int number;
409     int size;
410 };
411 /*
412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413 * and here, we should make the functions public.
414 */
415 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)416 xmlPointerListAddSize(xmlPointerListPtr list,
417 		       void *item,
418 		       int initialSize)
419 {
420     if (list->items == NULL) {
421 	if (initialSize <= 0)
422 	    initialSize = 1;
423 	list->items = (void **) xmlMalloc(
424 	    initialSize * sizeof(void *));
425 	if (list->items == NULL) {
426 	    xmlXPathErrMemory(NULL,
427 		"xmlPointerListCreate: allocating item\n");
428 	    return(-1);
429 	}
430 	list->number = 0;
431 	list->size = initialSize;
432     } else if (list->size <= list->number) {
433 	list->size *= 2;
434 	list->items = (void **) xmlRealloc(list->items,
435 	    list->size * sizeof(void *));
436 	if (list->items == NULL) {
437 	    xmlXPathErrMemory(NULL,
438 		"xmlPointerListCreate: re-allocating item\n");
439 	    list->size = 0;
440 	    return(-1);
441 	}
442     }
443     list->items[list->number++] = item;
444     return(0);
445 }
446 
447 /**
448  * xsltPointerListCreate:
449  *
450  * Creates an xsltPointerList structure.
451  *
452  * Returns a xsltPointerList structure or NULL in case of an error.
453  */
454 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)455 xmlPointerListCreate(int initialSize)
456 {
457     xmlPointerListPtr ret;
458 
459     ret = xmlMalloc(sizeof(xmlPointerList));
460     if (ret == NULL) {
461 	xmlXPathErrMemory(NULL,
462 	    "xmlPointerListCreate: allocating item\n");
463 	return (NULL);
464     }
465     memset(ret, 0, sizeof(xmlPointerList));
466     if (initialSize > 0) {
467 	xmlPointerListAddSize(ret, NULL, initialSize);
468 	ret->number = 0;
469     }
470     return (ret);
471 }
472 
473 /**
474  * xsltPointerListFree:
475  *
476  * Frees the xsltPointerList structure. This does not free
477  * the content of the list.
478  */
479 static void
xmlPointerListFree(xmlPointerListPtr list)480 xmlPointerListFree(xmlPointerListPtr list)
481 {
482     if (list == NULL)
483 	return;
484     if (list->items != NULL)
485 	xmlFree(list->items);
486     xmlFree(list);
487 }
488 
489 /************************************************************************
490  *									*
491  *			Parser Types					*
492  *									*
493  ************************************************************************/
494 
495 /*
496  * Types are private:
497  */
498 
499 typedef enum {
500     XPATH_OP_END=0,
501     XPATH_OP_AND,
502     XPATH_OP_OR,
503     XPATH_OP_EQUAL,
504     XPATH_OP_CMP,
505     XPATH_OP_PLUS,
506     XPATH_OP_MULT,
507     XPATH_OP_UNION,
508     XPATH_OP_ROOT,
509     XPATH_OP_NODE,
510     XPATH_OP_RESET, /* 10 */
511     XPATH_OP_COLLECT,
512     XPATH_OP_VALUE, /* 12 */
513     XPATH_OP_VARIABLE,
514     XPATH_OP_FUNCTION,
515     XPATH_OP_ARG,
516     XPATH_OP_PREDICATE,
517     XPATH_OP_FILTER, /* 17 */
518     XPATH_OP_SORT /* 18 */
519 #ifdef LIBXML_XPTR_ENABLED
520     ,XPATH_OP_RANGETO
521 #endif
522 } xmlXPathOp;
523 
524 typedef enum {
525     AXIS_ANCESTOR = 1,
526     AXIS_ANCESTOR_OR_SELF,
527     AXIS_ATTRIBUTE,
528     AXIS_CHILD,
529     AXIS_DESCENDANT,
530     AXIS_DESCENDANT_OR_SELF,
531     AXIS_FOLLOWING,
532     AXIS_FOLLOWING_SIBLING,
533     AXIS_NAMESPACE,
534     AXIS_PARENT,
535     AXIS_PRECEDING,
536     AXIS_PRECEDING_SIBLING,
537     AXIS_SELF
538 } xmlXPathAxisVal;
539 
540 typedef enum {
541     NODE_TEST_NONE = 0,
542     NODE_TEST_TYPE = 1,
543     NODE_TEST_PI = 2,
544     NODE_TEST_ALL = 3,
545     NODE_TEST_NS = 4,
546     NODE_TEST_NAME = 5
547 } xmlXPathTestVal;
548 
549 typedef enum {
550     NODE_TYPE_NODE = 0,
551     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552     NODE_TYPE_TEXT = XML_TEXT_NODE,
553     NODE_TYPE_PI = XML_PI_NODE
554 } xmlXPathTypeVal;
555 
556 #define XP_REWRITE_DOS_CHILD_ELEM 1
557 
558 typedef struct _xmlXPathStepOp xmlXPathStepOp;
559 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560 struct _xmlXPathStepOp {
561     xmlXPathOp op;		/* The identifier of the operation */
562     int ch1;			/* First child */
563     int ch2;			/* Second child */
564     int value;
565     int value2;
566     int value3;
567     void *value4;
568     void *value5;
569     void *cache;
570     void *cacheURI;
571     int rewriteType;
572 };
573 
574 struct _xmlXPathCompExpr {
575     int nbStep;			/* Number of steps in this expression */
576     int maxStep;		/* Maximum number of steps allocated */
577     xmlXPathStepOp *steps;	/* ops for computation of this expression */
578     int last;			/* index of last step in expression */
579     xmlChar *expr;		/* the expression being computed */
580     xmlDictPtr dict;		/* the dictionnary to use if any */
581 #ifdef DEBUG_EVAL_COUNTS
582     int nb;
583     xmlChar *string;
584 #endif
585 #ifdef XPATH_STREAMING
586     xmlPatternPtr stream;
587 #endif
588 };
589 
590 /************************************************************************
591  *									*
592  *			Forward declarations				*
593  *									*
594  ************************************************************************/
595 static void
596 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597 static void
598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599 static int
600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601                         xmlXPathStepOpPtr op, xmlNodePtr *first);
602 static int
603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
604 			    xmlXPathStepOpPtr op,
605 			    int isPredicate);
606 
607 /************************************************************************
608  *									*
609  *			Parser Type functions				*
610  *									*
611  ************************************************************************/
612 
613 /**
614  * xmlXPathNewCompExpr:
615  *
616  * Create a new Xpath component
617  *
618  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619  */
620 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)621 xmlXPathNewCompExpr(void) {
622     xmlXPathCompExprPtr cur;
623 
624     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625     if (cur == NULL) {
626         xmlXPathErrMemory(NULL, "allocating component\n");
627 	return(NULL);
628     }
629     memset(cur, 0, sizeof(xmlXPathCompExpr));
630     cur->maxStep = 10;
631     cur->nbStep = 0;
632     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633 	                                   sizeof(xmlXPathStepOp));
634     if (cur->steps == NULL) {
635         xmlXPathErrMemory(NULL, "allocating steps\n");
636 	xmlFree(cur);
637 	return(NULL);
638     }
639     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640     cur->last = -1;
641 #ifdef DEBUG_EVAL_COUNTS
642     cur->nb = 0;
643 #endif
644     return(cur);
645 }
646 
647 /**
648  * xmlXPathFreeCompExpr:
649  * @comp:  an XPATH comp
650  *
651  * Free up the memory allocated by @comp
652  */
653 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655 {
656     xmlXPathStepOpPtr op;
657     int i;
658 
659     if (comp == NULL)
660         return;
661     if (comp->dict == NULL) {
662 	for (i = 0; i < comp->nbStep; i++) {
663 	    op = &comp->steps[i];
664 	    if (op->value4 != NULL) {
665 		if (op->op == XPATH_OP_VALUE)
666 		    xmlXPathFreeObject(op->value4);
667 		else
668 		    xmlFree(op->value4);
669 	    }
670 	    if (op->value5 != NULL)
671 		xmlFree(op->value5);
672 	}
673     } else {
674 	for (i = 0; i < comp->nbStep; i++) {
675 	    op = &comp->steps[i];
676 	    if (op->value4 != NULL) {
677 		if (op->op == XPATH_OP_VALUE)
678 		    xmlXPathFreeObject(op->value4);
679 	    }
680 	}
681         xmlDictFree(comp->dict);
682     }
683     if (comp->steps != NULL) {
684         xmlFree(comp->steps);
685     }
686 #ifdef DEBUG_EVAL_COUNTS
687     if (comp->string != NULL) {
688         xmlFree(comp->string);
689     }
690 #endif
691 #ifdef XPATH_STREAMING
692     if (comp->stream != NULL) {
693         xmlFreePatternList(comp->stream);
694     }
695 #endif
696     if (comp->expr != NULL) {
697         xmlFree(comp->expr);
698     }
699 
700     xmlFree(comp);
701 }
702 
703 /**
704  * xmlXPathCompExprAdd:
705  * @comp:  the compiled expression
706  * @ch1: first child index
707  * @ch2: second child index
708  * @op:  an op
709  * @value:  the first int value
710  * @value2:  the second int value
711  * @value3:  the third int value
712  * @value4:  the first string value
713  * @value5:  the second string value
714  *
715  * Add a step to an XPath Compiled Expression
716  *
717  * Returns -1 in case of failure, the index otherwise
718  */
719 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721    xmlXPathOp op, int value,
722    int value2, int value3, void *value4, void *value5) {
723     if (comp->nbStep >= comp->maxStep) {
724 	xmlXPathStepOp *real;
725 
726 	comp->maxStep *= 2;
727 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728 		                      comp->maxStep * sizeof(xmlXPathStepOp));
729 	if (real == NULL) {
730 	    comp->maxStep /= 2;
731 	    xmlXPathErrMemory(NULL, "adding step\n");
732 	    return(-1);
733 	}
734 	comp->steps = real;
735     }
736     comp->last = comp->nbStep;
737     comp->steps[comp->nbStep].rewriteType = 0;
738     comp->steps[comp->nbStep].ch1 = ch1;
739     comp->steps[comp->nbStep].ch2 = ch2;
740     comp->steps[comp->nbStep].op = op;
741     comp->steps[comp->nbStep].value = value;
742     comp->steps[comp->nbStep].value2 = value2;
743     comp->steps[comp->nbStep].value3 = value3;
744     if ((comp->dict != NULL) &&
745         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746 	 (op == XPATH_OP_COLLECT))) {
747         if (value4 != NULL) {
748 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
749 	        (void *)xmlDictLookup(comp->dict, value4, -1);
750 	    xmlFree(value4);
751 	} else
752 	    comp->steps[comp->nbStep].value4 = NULL;
753         if (value5 != NULL) {
754 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
755 	        (void *)xmlDictLookup(comp->dict, value5, -1);
756 	    xmlFree(value5);
757 	} else
758 	    comp->steps[comp->nbStep].value5 = NULL;
759     } else {
760 	comp->steps[comp->nbStep].value4 = value4;
761 	comp->steps[comp->nbStep].value5 = value5;
762     }
763     comp->steps[comp->nbStep].cache = NULL;
764     return(comp->nbStep++);
765 }
766 
767 /**
768  * xmlXPathCompSwap:
769  * @comp:  the compiled expression
770  * @op: operation index
771  *
772  * Swaps 2 operations in the compiled expression
773  */
774 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)775 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776     int tmp;
777 
778 #ifndef LIBXML_THREAD_ENABLED
779     /*
780      * Since this manipulates possibly shared variables, this is
781      * disabled if one detects that the library is used in a multithreaded
782      * application
783      */
784     if (xmlXPathDisableOptimizer)
785 	return;
786 #endif
787 
788     tmp = op->ch1;
789     op->ch1 = op->ch2;
790     op->ch2 = tmp;
791 }
792 
793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
794     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
795 	                (op), (val), (val2), (val3), (val4), (val5))
796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
797     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
798 	                (op), (val), (val2), (val3), (val4), (val5))
799 
800 #define PUSH_LEAVE_EXPR(op, val, val2)					\
801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802 
803 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805 
806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
808 			(val), (val2), 0 ,NULL ,NULL)
809 
810 /************************************************************************
811  *									*
812  *		XPath object cache structures				*
813  *									*
814  ************************************************************************/
815 
816 /* #define XP_DEFAULT_CACHE_ON */
817 
818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
819 
820 typedef struct _xmlXPathContextCache xmlXPathContextCache;
821 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822 struct _xmlXPathContextCache {
823     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
824     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
825     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
826     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
827     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
828     int maxNodeset;
829     int maxString;
830     int maxBoolean;
831     int maxNumber;
832     int maxMisc;
833 #ifdef XP_DEBUG_OBJ_USAGE
834     int dbgCachedAll;
835     int dbgCachedNodeset;
836     int dbgCachedString;
837     int dbgCachedBool;
838     int dbgCachedNumber;
839     int dbgCachedPoint;
840     int dbgCachedRange;
841     int dbgCachedLocset;
842     int dbgCachedUsers;
843     int dbgCachedXSLTTree;
844     int dbgCachedUndefined;
845 
846 
847     int dbgReusedAll;
848     int dbgReusedNodeset;
849     int dbgReusedString;
850     int dbgReusedBool;
851     int dbgReusedNumber;
852     int dbgReusedPoint;
853     int dbgReusedRange;
854     int dbgReusedLocset;
855     int dbgReusedUsers;
856     int dbgReusedXSLTTree;
857     int dbgReusedUndefined;
858 
859 #endif
860 };
861 
862 /************************************************************************
863  *									*
864  *		Debugging related functions				*
865  *									*
866  ************************************************************************/
867 
868 #define STRANGE							\
869     xmlGenericError(xmlGenericErrorContext,				\
870 	    "Internal error at %s:%d\n",				\
871             __FILE__, __LINE__);
872 
873 #ifdef LIBXML_DEBUG_ENABLED
874 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
876     int i;
877     char shift[100];
878 
879     for (i = 0;((i < depth) && (i < 25));i++)
880         shift[2 * i] = shift[2 * i + 1] = ' ';
881     shift[2 * i] = shift[2 * i + 1] = 0;
882     if (cur == NULL) {
883 	fprintf(output, "%s", shift);
884 	fprintf(output, "Node is NULL !\n");
885 	return;
886 
887     }
888 
889     if ((cur->type == XML_DOCUMENT_NODE) ||
890 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
891 	fprintf(output, "%s", shift);
892 	fprintf(output, " /\n");
893     } else if (cur->type == XML_ATTRIBUTE_NODE)
894 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895     else
896 	xmlDebugDumpOneNode(output, cur, depth);
897 }
898 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
900     xmlNodePtr tmp;
901     int i;
902     char shift[100];
903 
904     for (i = 0;((i < depth) && (i < 25));i++)
905         shift[2 * i] = shift[2 * i + 1] = ' ';
906     shift[2 * i] = shift[2 * i + 1] = 0;
907     if (cur == NULL) {
908 	fprintf(output, "%s", shift);
909 	fprintf(output, "Node is NULL !\n");
910 	return;
911 
912     }
913 
914     while (cur != NULL) {
915 	tmp = cur;
916 	cur = cur->next;
917 	xmlDebugDumpOneNode(output, tmp, depth);
918     }
919 }
920 
921 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
923     int i;
924     char shift[100];
925 
926     for (i = 0;((i < depth) && (i < 25));i++)
927         shift[2 * i] = shift[2 * i + 1] = ' ';
928     shift[2 * i] = shift[2 * i + 1] = 0;
929 
930     if (cur == NULL) {
931 	fprintf(output, "%s", shift);
932 	fprintf(output, "NodeSet is NULL !\n");
933 	return;
934 
935     }
936 
937     if (cur != NULL) {
938 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939 	for (i = 0;i < cur->nodeNr;i++) {
940 	    fprintf(output, "%s", shift);
941 	    fprintf(output, "%d", i + 1);
942 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943 	}
944     }
945 }
946 
947 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
949     int i;
950     char shift[100];
951 
952     for (i = 0;((i < depth) && (i < 25));i++)
953         shift[2 * i] = shift[2 * i + 1] = ' ';
954     shift[2 * i] = shift[2 * i + 1] = 0;
955 
956     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
957 	fprintf(output, "%s", shift);
958 	fprintf(output, "Value Tree is NULL !\n");
959 	return;
960 
961     }
962 
963     fprintf(output, "%s", shift);
964     fprintf(output, "%d", i + 1);
965     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966 }
967 #if defined(LIBXML_XPTR_ENABLED)
968 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
970     int i;
971     char shift[100];
972 
973     for (i = 0;((i < depth) && (i < 25));i++)
974         shift[2 * i] = shift[2 * i + 1] = ' ';
975     shift[2 * i] = shift[2 * i + 1] = 0;
976 
977     if (cur == NULL) {
978 	fprintf(output, "%s", shift);
979 	fprintf(output, "LocationSet is NULL !\n");
980 	return;
981 
982     }
983 
984     for (i = 0;i < cur->locNr;i++) {
985 	fprintf(output, "%s", shift);
986         fprintf(output, "%d : ", i + 1);
987 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988     }
989 }
990 #endif /* LIBXML_XPTR_ENABLED */
991 
992 /**
993  * xmlXPathDebugDumpObject:
994  * @output:  the FILE * to dump the output
995  * @cur:  the object to inspect
996  * @depth:  indentation level
997  *
998  * Dump the content of the object for debugging purposes
999  */
1000 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1002     int i;
1003     char shift[100];
1004 
1005     if (output == NULL) return;
1006 
1007     for (i = 0;((i < depth) && (i < 25));i++)
1008         shift[2 * i] = shift[2 * i + 1] = ' ';
1009     shift[2 * i] = shift[2 * i + 1] = 0;
1010 
1011 
1012     fprintf(output, "%s", shift);
1013 
1014     if (cur == NULL) {
1015         fprintf(output, "Object is empty (NULL)\n");
1016 	return;
1017     }
1018     switch(cur->type) {
1019         case XPATH_UNDEFINED:
1020 	    fprintf(output, "Object is uninitialized\n");
1021 	    break;
1022         case XPATH_NODESET:
1023 	    fprintf(output, "Object is a Node Set :\n");
1024 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025 	    break;
1026 	case XPATH_XSLT_TREE:
1027 	    fprintf(output, "Object is an XSLT value tree :\n");
1028 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1029 	    break;
1030         case XPATH_BOOLEAN:
1031 	    fprintf(output, "Object is a Boolean : ");
1032 	    if (cur->boolval) fprintf(output, "true\n");
1033 	    else fprintf(output, "false\n");
1034 	    break;
1035         case XPATH_NUMBER:
1036 	    switch (xmlXPathIsInf(cur->floatval)) {
1037 	    case 1:
1038 		fprintf(output, "Object is a number : Infinity\n");
1039 		break;
1040 	    case -1:
1041 		fprintf(output, "Object is a number : -Infinity\n");
1042 		break;
1043 	    default:
1044 		if (xmlXPathIsNaN(cur->floatval)) {
1045 		    fprintf(output, "Object is a number : NaN\n");
1046 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047 		    fprintf(output, "Object is a number : 0\n");
1048 		} else {
1049 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1050 		}
1051 	    }
1052 	    break;
1053         case XPATH_STRING:
1054 	    fprintf(output, "Object is a string : ");
1055 	    xmlDebugDumpString(output, cur->stringval);
1056 	    fprintf(output, "\n");
1057 	    break;
1058 	case XPATH_POINT:
1059 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1060 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061 	    fprintf(output, "\n");
1062 	    break;
1063 	case XPATH_RANGE:
1064 	    if ((cur->user2 == NULL) ||
1065 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066 		fprintf(output, "Object is a collapsed range :\n");
1067 		fprintf(output, "%s", shift);
1068 		if (cur->index >= 0)
1069 		    fprintf(output, "index %d in ", cur->index);
1070 		fprintf(output, "node\n");
1071 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072 			              depth + 1);
1073 	    } else  {
1074 		fprintf(output, "Object is a range :\n");
1075 		fprintf(output, "%s", shift);
1076 		fprintf(output, "From ");
1077 		if (cur->index >= 0)
1078 		    fprintf(output, "index %d in ", cur->index);
1079 		fprintf(output, "node\n");
1080 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081 			              depth + 1);
1082 		fprintf(output, "%s", shift);
1083 		fprintf(output, "To ");
1084 		if (cur->index2 >= 0)
1085 		    fprintf(output, "index %d in ", cur->index2);
1086 		fprintf(output, "node\n");
1087 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088 			              depth + 1);
1089 		fprintf(output, "\n");
1090 	    }
1091 	    break;
1092 	case XPATH_LOCATIONSET:
1093 #if defined(LIBXML_XPTR_ENABLED)
1094 	    fprintf(output, "Object is a Location Set:\n");
1095 	    xmlXPathDebugDumpLocationSet(output,
1096 		    (xmlLocationSetPtr) cur->user, depth);
1097 #endif
1098 	    break;
1099 	case XPATH_USERS:
1100 	    fprintf(output, "Object is user defined\n");
1101 	    break;
1102     }
1103 }
1104 
1105 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1107 	                     xmlXPathStepOpPtr op, int depth) {
1108     int i;
1109     char shift[100];
1110 
1111     for (i = 0;((i < depth) && (i < 25));i++)
1112         shift[2 * i] = shift[2 * i + 1] = ' ';
1113     shift[2 * i] = shift[2 * i + 1] = 0;
1114 
1115     fprintf(output, "%s", shift);
1116     if (op == NULL) {
1117 	fprintf(output, "Step is NULL\n");
1118 	return;
1119     }
1120     switch (op->op) {
1121         case XPATH_OP_END:
1122 	    fprintf(output, "END"); break;
1123         case XPATH_OP_AND:
1124 	    fprintf(output, "AND"); break;
1125         case XPATH_OP_OR:
1126 	    fprintf(output, "OR"); break;
1127         case XPATH_OP_EQUAL:
1128 	     if (op->value)
1129 		 fprintf(output, "EQUAL =");
1130 	     else
1131 		 fprintf(output, "EQUAL !=");
1132 	     break;
1133         case XPATH_OP_CMP:
1134 	     if (op->value)
1135 		 fprintf(output, "CMP <");
1136 	     else
1137 		 fprintf(output, "CMP >");
1138 	     if (!op->value2)
1139 		 fprintf(output, "=");
1140 	     break;
1141         case XPATH_OP_PLUS:
1142 	     if (op->value == 0)
1143 		 fprintf(output, "PLUS -");
1144 	     else if (op->value == 1)
1145 		 fprintf(output, "PLUS +");
1146 	     else if (op->value == 2)
1147 		 fprintf(output, "PLUS unary -");
1148 	     else if (op->value == 3)
1149 		 fprintf(output, "PLUS unary - -");
1150 	     break;
1151         case XPATH_OP_MULT:
1152 	     if (op->value == 0)
1153 		 fprintf(output, "MULT *");
1154 	     else if (op->value == 1)
1155 		 fprintf(output, "MULT div");
1156 	     else
1157 		 fprintf(output, "MULT mod");
1158 	     break;
1159         case XPATH_OP_UNION:
1160 	     fprintf(output, "UNION"); break;
1161         case XPATH_OP_ROOT:
1162 	     fprintf(output, "ROOT"); break;
1163         case XPATH_OP_NODE:
1164 	     fprintf(output, "NODE"); break;
1165         case XPATH_OP_RESET:
1166 	     fprintf(output, "RESET"); break;
1167         case XPATH_OP_SORT:
1168 	     fprintf(output, "SORT"); break;
1169         case XPATH_OP_COLLECT: {
1170 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1173 	    const xmlChar *prefix = op->value4;
1174 	    const xmlChar *name = op->value5;
1175 
1176 	    fprintf(output, "COLLECT ");
1177 	    switch (axis) {
1178 		case AXIS_ANCESTOR:
1179 		    fprintf(output, " 'ancestors' "); break;
1180 		case AXIS_ANCESTOR_OR_SELF:
1181 		    fprintf(output, " 'ancestors-or-self' "); break;
1182 		case AXIS_ATTRIBUTE:
1183 		    fprintf(output, " 'attributes' "); break;
1184 		case AXIS_CHILD:
1185 		    fprintf(output, " 'child' "); break;
1186 		case AXIS_DESCENDANT:
1187 		    fprintf(output, " 'descendant' "); break;
1188 		case AXIS_DESCENDANT_OR_SELF:
1189 		    fprintf(output, " 'descendant-or-self' "); break;
1190 		case AXIS_FOLLOWING:
1191 		    fprintf(output, " 'following' "); break;
1192 		case AXIS_FOLLOWING_SIBLING:
1193 		    fprintf(output, " 'following-siblings' "); break;
1194 		case AXIS_NAMESPACE:
1195 		    fprintf(output, " 'namespace' "); break;
1196 		case AXIS_PARENT:
1197 		    fprintf(output, " 'parent' "); break;
1198 		case AXIS_PRECEDING:
1199 		    fprintf(output, " 'preceding' "); break;
1200 		case AXIS_PRECEDING_SIBLING:
1201 		    fprintf(output, " 'preceding-sibling' "); break;
1202 		case AXIS_SELF:
1203 		    fprintf(output, " 'self' "); break;
1204 	    }
1205 	    switch (test) {
1206                 case NODE_TEST_NONE:
1207 		    fprintf(output, "'none' "); break;
1208                 case NODE_TEST_TYPE:
1209 		    fprintf(output, "'type' "); break;
1210                 case NODE_TEST_PI:
1211 		    fprintf(output, "'PI' "); break;
1212                 case NODE_TEST_ALL:
1213 		    fprintf(output, "'all' "); break;
1214                 case NODE_TEST_NS:
1215 		    fprintf(output, "'namespace' "); break;
1216                 case NODE_TEST_NAME:
1217 		    fprintf(output, "'name' "); break;
1218 	    }
1219 	    switch (type) {
1220                 case NODE_TYPE_NODE:
1221 		    fprintf(output, "'node' "); break;
1222                 case NODE_TYPE_COMMENT:
1223 		    fprintf(output, "'comment' "); break;
1224                 case NODE_TYPE_TEXT:
1225 		    fprintf(output, "'text' "); break;
1226                 case NODE_TYPE_PI:
1227 		    fprintf(output, "'PI' "); break;
1228 	    }
1229 	    if (prefix != NULL)
1230 		fprintf(output, "%s:", prefix);
1231 	    if (name != NULL)
1232 		fprintf(output, "%s", (const char *) name);
1233 	    break;
1234 
1235         }
1236 	case XPATH_OP_VALUE: {
1237 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238 
1239 	    fprintf(output, "ELEM ");
1240 	    xmlXPathDebugDumpObject(output, object, 0);
1241 	    goto finish;
1242 	}
1243 	case XPATH_OP_VARIABLE: {
1244 	    const xmlChar *prefix = op->value5;
1245 	    const xmlChar *name = op->value4;
1246 
1247 	    if (prefix != NULL)
1248 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1249 	    else
1250 		fprintf(output, "VARIABLE %s", name);
1251 	    break;
1252 	}
1253 	case XPATH_OP_FUNCTION: {
1254 	    int nbargs = op->value;
1255 	    const xmlChar *prefix = op->value5;
1256 	    const xmlChar *name = op->value4;
1257 
1258 	    if (prefix != NULL)
1259 		fprintf(output, "FUNCTION %s:%s(%d args)",
1260 			prefix, name, nbargs);
1261 	    else
1262 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263 	    break;
1264 	}
1265         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1267         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1268 #ifdef LIBXML_XPTR_ENABLED
1269         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270 #endif
1271 	default:
1272         fprintf(output, "UNKNOWN %d\n", op->op); return;
1273     }
1274     fprintf(output, "\n");
1275 finish:
1276     if (op->ch1 >= 0)
1277 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278     if (op->ch2 >= 0)
1279 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1280 }
1281 
1282 /**
1283  * xmlXPathDebugDumpCompExpr:
1284  * @output:  the FILE * for the output
1285  * @comp:  the precompiled XPath expression
1286  * @depth:  the indentation level.
1287  *
1288  * Dumps the tree of the compiled XPath expression.
1289  */
1290 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1292 	                  int depth) {
1293     int i;
1294     char shift[100];
1295 
1296     if ((output == NULL) || (comp == NULL)) return;
1297 
1298     for (i = 0;((i < depth) && (i < 25));i++)
1299         shift[2 * i] = shift[2 * i + 1] = ' ';
1300     shift[2 * i] = shift[2 * i + 1] = 0;
1301 
1302     fprintf(output, "%s", shift);
1303 
1304     fprintf(output, "Compiled Expression : %d elements\n",
1305 	    comp->nbStep);
1306     i = comp->last;
1307     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308 }
1309 
1310 #ifdef XP_DEBUG_OBJ_USAGE
1311 
1312 /*
1313 * XPath object usage related debugging variables.
1314 */
1315 static int xmlXPathDebugObjCounterUndefined = 0;
1316 static int xmlXPathDebugObjCounterNodeset = 0;
1317 static int xmlXPathDebugObjCounterBool = 0;
1318 static int xmlXPathDebugObjCounterNumber = 0;
1319 static int xmlXPathDebugObjCounterString = 0;
1320 static int xmlXPathDebugObjCounterPoint = 0;
1321 static int xmlXPathDebugObjCounterRange = 0;
1322 static int xmlXPathDebugObjCounterLocset = 0;
1323 static int xmlXPathDebugObjCounterUsers = 0;
1324 static int xmlXPathDebugObjCounterXSLTTree = 0;
1325 static int xmlXPathDebugObjCounterAll = 0;
1326 
1327 static int xmlXPathDebugObjTotalUndefined = 0;
1328 static int xmlXPathDebugObjTotalNodeset = 0;
1329 static int xmlXPathDebugObjTotalBool = 0;
1330 static int xmlXPathDebugObjTotalNumber = 0;
1331 static int xmlXPathDebugObjTotalString = 0;
1332 static int xmlXPathDebugObjTotalPoint = 0;
1333 static int xmlXPathDebugObjTotalRange = 0;
1334 static int xmlXPathDebugObjTotalLocset = 0;
1335 static int xmlXPathDebugObjTotalUsers = 0;
1336 static int xmlXPathDebugObjTotalXSLTTree = 0;
1337 static int xmlXPathDebugObjTotalAll = 0;
1338 
1339 static int xmlXPathDebugObjMaxUndefined = 0;
1340 static int xmlXPathDebugObjMaxNodeset = 0;
1341 static int xmlXPathDebugObjMaxBool = 0;
1342 static int xmlXPathDebugObjMaxNumber = 0;
1343 static int xmlXPathDebugObjMaxString = 0;
1344 static int xmlXPathDebugObjMaxPoint = 0;
1345 static int xmlXPathDebugObjMaxRange = 0;
1346 static int xmlXPathDebugObjMaxLocset = 0;
1347 static int xmlXPathDebugObjMaxUsers = 0;
1348 static int xmlXPathDebugObjMaxXSLTTree = 0;
1349 static int xmlXPathDebugObjMaxAll = 0;
1350 
1351 /* REVISIT TODO: Make this static when committing */
1352 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354 {
1355     if (ctxt != NULL) {
1356 	if (ctxt->cache != NULL) {
1357 	    xmlXPathContextCachePtr cache =
1358 		(xmlXPathContextCachePtr) ctxt->cache;
1359 
1360 	    cache->dbgCachedAll = 0;
1361 	    cache->dbgCachedNodeset = 0;
1362 	    cache->dbgCachedString = 0;
1363 	    cache->dbgCachedBool = 0;
1364 	    cache->dbgCachedNumber = 0;
1365 	    cache->dbgCachedPoint = 0;
1366 	    cache->dbgCachedRange = 0;
1367 	    cache->dbgCachedLocset = 0;
1368 	    cache->dbgCachedUsers = 0;
1369 	    cache->dbgCachedXSLTTree = 0;
1370 	    cache->dbgCachedUndefined = 0;
1371 
1372 	    cache->dbgReusedAll = 0;
1373 	    cache->dbgReusedNodeset = 0;
1374 	    cache->dbgReusedString = 0;
1375 	    cache->dbgReusedBool = 0;
1376 	    cache->dbgReusedNumber = 0;
1377 	    cache->dbgReusedPoint = 0;
1378 	    cache->dbgReusedRange = 0;
1379 	    cache->dbgReusedLocset = 0;
1380 	    cache->dbgReusedUsers = 0;
1381 	    cache->dbgReusedXSLTTree = 0;
1382 	    cache->dbgReusedUndefined = 0;
1383 	}
1384     }
1385 
1386     xmlXPathDebugObjCounterUndefined = 0;
1387     xmlXPathDebugObjCounterNodeset = 0;
1388     xmlXPathDebugObjCounterBool = 0;
1389     xmlXPathDebugObjCounterNumber = 0;
1390     xmlXPathDebugObjCounterString = 0;
1391     xmlXPathDebugObjCounterPoint = 0;
1392     xmlXPathDebugObjCounterRange = 0;
1393     xmlXPathDebugObjCounterLocset = 0;
1394     xmlXPathDebugObjCounterUsers = 0;
1395     xmlXPathDebugObjCounterXSLTTree = 0;
1396     xmlXPathDebugObjCounterAll = 0;
1397 
1398     xmlXPathDebugObjTotalUndefined = 0;
1399     xmlXPathDebugObjTotalNodeset = 0;
1400     xmlXPathDebugObjTotalBool = 0;
1401     xmlXPathDebugObjTotalNumber = 0;
1402     xmlXPathDebugObjTotalString = 0;
1403     xmlXPathDebugObjTotalPoint = 0;
1404     xmlXPathDebugObjTotalRange = 0;
1405     xmlXPathDebugObjTotalLocset = 0;
1406     xmlXPathDebugObjTotalUsers = 0;
1407     xmlXPathDebugObjTotalXSLTTree = 0;
1408     xmlXPathDebugObjTotalAll = 0;
1409 
1410     xmlXPathDebugObjMaxUndefined = 0;
1411     xmlXPathDebugObjMaxNodeset = 0;
1412     xmlXPathDebugObjMaxBool = 0;
1413     xmlXPathDebugObjMaxNumber = 0;
1414     xmlXPathDebugObjMaxString = 0;
1415     xmlXPathDebugObjMaxPoint = 0;
1416     xmlXPathDebugObjMaxRange = 0;
1417     xmlXPathDebugObjMaxLocset = 0;
1418     xmlXPathDebugObjMaxUsers = 0;
1419     xmlXPathDebugObjMaxXSLTTree = 0;
1420     xmlXPathDebugObjMaxAll = 0;
1421 
1422 }
1423 
1424 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426 			      xmlXPathObjectType objType)
1427 {
1428     int isCached = 0;
1429 
1430     if (ctxt != NULL) {
1431 	if (ctxt->cache != NULL) {
1432 	    xmlXPathContextCachePtr cache =
1433 		(xmlXPathContextCachePtr) ctxt->cache;
1434 
1435 	    isCached = 1;
1436 
1437 	    cache->dbgReusedAll++;
1438 	    switch (objType) {
1439 		case XPATH_UNDEFINED:
1440 		    cache->dbgReusedUndefined++;
1441 		    break;
1442 		case XPATH_NODESET:
1443 		    cache->dbgReusedNodeset++;
1444 		    break;
1445 		case XPATH_BOOLEAN:
1446 		    cache->dbgReusedBool++;
1447 		    break;
1448 		case XPATH_NUMBER:
1449 		    cache->dbgReusedNumber++;
1450 		    break;
1451 		case XPATH_STRING:
1452 		    cache->dbgReusedString++;
1453 		    break;
1454 		case XPATH_POINT:
1455 		    cache->dbgReusedPoint++;
1456 		    break;
1457 		case XPATH_RANGE:
1458 		    cache->dbgReusedRange++;
1459 		    break;
1460 		case XPATH_LOCATIONSET:
1461 		    cache->dbgReusedLocset++;
1462 		    break;
1463 		case XPATH_USERS:
1464 		    cache->dbgReusedUsers++;
1465 		    break;
1466 		case XPATH_XSLT_TREE:
1467 		    cache->dbgReusedXSLTTree++;
1468 		    break;
1469 		default:
1470 		    break;
1471 	    }
1472 	}
1473     }
1474 
1475     switch (objType) {
1476 	case XPATH_UNDEFINED:
1477 	    if (! isCached)
1478 		xmlXPathDebugObjTotalUndefined++;
1479 	    xmlXPathDebugObjCounterUndefined++;
1480 	    if (xmlXPathDebugObjCounterUndefined >
1481 		xmlXPathDebugObjMaxUndefined)
1482 		xmlXPathDebugObjMaxUndefined =
1483 		    xmlXPathDebugObjCounterUndefined;
1484 	    break;
1485 	case XPATH_NODESET:
1486 	    if (! isCached)
1487 		xmlXPathDebugObjTotalNodeset++;
1488 	    xmlXPathDebugObjCounterNodeset++;
1489 	    if (xmlXPathDebugObjCounterNodeset >
1490 		xmlXPathDebugObjMaxNodeset)
1491 		xmlXPathDebugObjMaxNodeset =
1492 		    xmlXPathDebugObjCounterNodeset;
1493 	    break;
1494 	case XPATH_BOOLEAN:
1495 	    if (! isCached)
1496 		xmlXPathDebugObjTotalBool++;
1497 	    xmlXPathDebugObjCounterBool++;
1498 	    if (xmlXPathDebugObjCounterBool >
1499 		xmlXPathDebugObjMaxBool)
1500 		xmlXPathDebugObjMaxBool =
1501 		    xmlXPathDebugObjCounterBool;
1502 	    break;
1503 	case XPATH_NUMBER:
1504 	    if (! isCached)
1505 		xmlXPathDebugObjTotalNumber++;
1506 	    xmlXPathDebugObjCounterNumber++;
1507 	    if (xmlXPathDebugObjCounterNumber >
1508 		xmlXPathDebugObjMaxNumber)
1509 		xmlXPathDebugObjMaxNumber =
1510 		    xmlXPathDebugObjCounterNumber;
1511 	    break;
1512 	case XPATH_STRING:
1513 	    if (! isCached)
1514 		xmlXPathDebugObjTotalString++;
1515 	    xmlXPathDebugObjCounterString++;
1516 	    if (xmlXPathDebugObjCounterString >
1517 		xmlXPathDebugObjMaxString)
1518 		xmlXPathDebugObjMaxString =
1519 		    xmlXPathDebugObjCounterString;
1520 	    break;
1521 	case XPATH_POINT:
1522 	    if (! isCached)
1523 		xmlXPathDebugObjTotalPoint++;
1524 	    xmlXPathDebugObjCounterPoint++;
1525 	    if (xmlXPathDebugObjCounterPoint >
1526 		xmlXPathDebugObjMaxPoint)
1527 		xmlXPathDebugObjMaxPoint =
1528 		    xmlXPathDebugObjCounterPoint;
1529 	    break;
1530 	case XPATH_RANGE:
1531 	    if (! isCached)
1532 		xmlXPathDebugObjTotalRange++;
1533 	    xmlXPathDebugObjCounterRange++;
1534 	    if (xmlXPathDebugObjCounterRange >
1535 		xmlXPathDebugObjMaxRange)
1536 		xmlXPathDebugObjMaxRange =
1537 		    xmlXPathDebugObjCounterRange;
1538 	    break;
1539 	case XPATH_LOCATIONSET:
1540 	    if (! isCached)
1541 		xmlXPathDebugObjTotalLocset++;
1542 	    xmlXPathDebugObjCounterLocset++;
1543 	    if (xmlXPathDebugObjCounterLocset >
1544 		xmlXPathDebugObjMaxLocset)
1545 		xmlXPathDebugObjMaxLocset =
1546 		    xmlXPathDebugObjCounterLocset;
1547 	    break;
1548 	case XPATH_USERS:
1549 	    if (! isCached)
1550 		xmlXPathDebugObjTotalUsers++;
1551 	    xmlXPathDebugObjCounterUsers++;
1552 	    if (xmlXPathDebugObjCounterUsers >
1553 		xmlXPathDebugObjMaxUsers)
1554 		xmlXPathDebugObjMaxUsers =
1555 		    xmlXPathDebugObjCounterUsers;
1556 	    break;
1557 	case XPATH_XSLT_TREE:
1558 	    if (! isCached)
1559 		xmlXPathDebugObjTotalXSLTTree++;
1560 	    xmlXPathDebugObjCounterXSLTTree++;
1561 	    if (xmlXPathDebugObjCounterXSLTTree >
1562 		xmlXPathDebugObjMaxXSLTTree)
1563 		xmlXPathDebugObjMaxXSLTTree =
1564 		    xmlXPathDebugObjCounterXSLTTree;
1565 	    break;
1566 	default:
1567 	    break;
1568     }
1569     if (! isCached)
1570 	xmlXPathDebugObjTotalAll++;
1571     xmlXPathDebugObjCounterAll++;
1572     if (xmlXPathDebugObjCounterAll >
1573 	xmlXPathDebugObjMaxAll)
1574 	xmlXPathDebugObjMaxAll =
1575 	    xmlXPathDebugObjCounterAll;
1576 }
1577 
1578 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580 			      xmlXPathObjectType objType)
1581 {
1582     int isCached = 0;
1583 
1584     if (ctxt != NULL) {
1585 	if (ctxt->cache != NULL) {
1586 	    xmlXPathContextCachePtr cache =
1587 		(xmlXPathContextCachePtr) ctxt->cache;
1588 
1589 	    isCached = 1;
1590 
1591 	    cache->dbgCachedAll++;
1592 	    switch (objType) {
1593 		case XPATH_UNDEFINED:
1594 		    cache->dbgCachedUndefined++;
1595 		    break;
1596 		case XPATH_NODESET:
1597 		    cache->dbgCachedNodeset++;
1598 		    break;
1599 		case XPATH_BOOLEAN:
1600 		    cache->dbgCachedBool++;
1601 		    break;
1602 		case XPATH_NUMBER:
1603 		    cache->dbgCachedNumber++;
1604 		    break;
1605 		case XPATH_STRING:
1606 		    cache->dbgCachedString++;
1607 		    break;
1608 		case XPATH_POINT:
1609 		    cache->dbgCachedPoint++;
1610 		    break;
1611 		case XPATH_RANGE:
1612 		    cache->dbgCachedRange++;
1613 		    break;
1614 		case XPATH_LOCATIONSET:
1615 		    cache->dbgCachedLocset++;
1616 		    break;
1617 		case XPATH_USERS:
1618 		    cache->dbgCachedUsers++;
1619 		    break;
1620 		case XPATH_XSLT_TREE:
1621 		    cache->dbgCachedXSLTTree++;
1622 		    break;
1623 		default:
1624 		    break;
1625 	    }
1626 
1627 	}
1628     }
1629     switch (objType) {
1630 	case XPATH_UNDEFINED:
1631 	    xmlXPathDebugObjCounterUndefined--;
1632 	    break;
1633 	case XPATH_NODESET:
1634 	    xmlXPathDebugObjCounterNodeset--;
1635 	    break;
1636 	case XPATH_BOOLEAN:
1637 	    xmlXPathDebugObjCounterBool--;
1638 	    break;
1639 	case XPATH_NUMBER:
1640 	    xmlXPathDebugObjCounterNumber--;
1641 	    break;
1642 	case XPATH_STRING:
1643 	    xmlXPathDebugObjCounterString--;
1644 	    break;
1645 	case XPATH_POINT:
1646 	    xmlXPathDebugObjCounterPoint--;
1647 	    break;
1648 	case XPATH_RANGE:
1649 	    xmlXPathDebugObjCounterRange--;
1650 	    break;
1651 	case XPATH_LOCATIONSET:
1652 	    xmlXPathDebugObjCounterLocset--;
1653 	    break;
1654 	case XPATH_USERS:
1655 	    xmlXPathDebugObjCounterUsers--;
1656 	    break;
1657 	case XPATH_XSLT_TREE:
1658 	    xmlXPathDebugObjCounterXSLTTree--;
1659 	    break;
1660 	default:
1661 	    break;
1662     }
1663     xmlXPathDebugObjCounterAll--;
1664 }
1665 
1666 /* REVISIT TODO: Make this static when committing */
1667 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669 {
1670     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671 	reqXSLTTree, reqUndefined;
1672     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676     int leftObjs = xmlXPathDebugObjCounterAll;
1677 
1678     reqAll = xmlXPathDebugObjTotalAll;
1679     reqNodeset = xmlXPathDebugObjTotalNodeset;
1680     reqString = xmlXPathDebugObjTotalString;
1681     reqBool = xmlXPathDebugObjTotalBool;
1682     reqNumber = xmlXPathDebugObjTotalNumber;
1683     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684     reqUndefined = xmlXPathDebugObjTotalUndefined;
1685 
1686     printf("# XPath object usage:\n");
1687 
1688     if (ctxt != NULL) {
1689 	if (ctxt->cache != NULL) {
1690 	    xmlXPathContextCachePtr cache =
1691 		(xmlXPathContextCachePtr) ctxt->cache;
1692 
1693 	    reAll = cache->dbgReusedAll;
1694 	    reqAll += reAll;
1695 	    reNodeset = cache->dbgReusedNodeset;
1696 	    reqNodeset += reNodeset;
1697 	    reString = cache->dbgReusedString;
1698 	    reqString += reString;
1699 	    reBool = cache->dbgReusedBool;
1700 	    reqBool += reBool;
1701 	    reNumber = cache->dbgReusedNumber;
1702 	    reqNumber += reNumber;
1703 	    reXSLTTree = cache->dbgReusedXSLTTree;
1704 	    reqXSLTTree += reXSLTTree;
1705 	    reUndefined = cache->dbgReusedUndefined;
1706 	    reqUndefined += reUndefined;
1707 
1708 	    caAll = cache->dbgCachedAll;
1709 	    caBool = cache->dbgCachedBool;
1710 	    caNodeset = cache->dbgCachedNodeset;
1711 	    caString = cache->dbgCachedString;
1712 	    caNumber = cache->dbgCachedNumber;
1713 	    caXSLTTree = cache->dbgCachedXSLTTree;
1714 	    caUndefined = cache->dbgCachedUndefined;
1715 
1716 	    if (cache->nodesetObjs)
1717 		leftObjs -= cache->nodesetObjs->number;
1718 	    if (cache->stringObjs)
1719 		leftObjs -= cache->stringObjs->number;
1720 	    if (cache->booleanObjs)
1721 		leftObjs -= cache->booleanObjs->number;
1722 	    if (cache->numberObjs)
1723 		leftObjs -= cache->numberObjs->number;
1724 	    if (cache->miscObjs)
1725 		leftObjs -= cache->miscObjs->number;
1726 	}
1727     }
1728 
1729     printf("# all\n");
1730     printf("#   total  : %d\n", reqAll);
1731     printf("#   left  : %d\n", leftObjs);
1732     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1733     printf("#   reused : %d\n", reAll);
1734     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1735 
1736     printf("# node-sets\n");
1737     printf("#   total  : %d\n", reqNodeset);
1738     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1739     printf("#   reused : %d\n", reNodeset);
1740     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1741 
1742     printf("# strings\n");
1743     printf("#   total  : %d\n", reqString);
1744     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1745     printf("#   reused : %d\n", reString);
1746     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1747 
1748     printf("# booleans\n");
1749     printf("#   total  : %d\n", reqBool);
1750     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1751     printf("#   reused : %d\n", reBool);
1752     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1753 
1754     printf("# numbers\n");
1755     printf("#   total  : %d\n", reqNumber);
1756     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1757     printf("#   reused : %d\n", reNumber);
1758     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1759 
1760     printf("# XSLT result tree fragments\n");
1761     printf("#   total  : %d\n", reqXSLTTree);
1762     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763     printf("#   reused : %d\n", reXSLTTree);
1764     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765 
1766     printf("# undefined\n");
1767     printf("#   total  : %d\n", reqUndefined);
1768     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1769     printf("#   reused : %d\n", reUndefined);
1770     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1771 
1772 }
1773 
1774 #endif /* XP_DEBUG_OBJ_USAGE */
1775 
1776 #endif /* LIBXML_DEBUG_ENABLED */
1777 
1778 /************************************************************************
1779  *									*
1780  *			XPath object caching				*
1781  *									*
1782  ************************************************************************/
1783 
1784 /**
1785  * xmlXPathNewCache:
1786  *
1787  * Create a new object cache
1788  *
1789  * Returns the xmlXPathCache just allocated.
1790  */
1791 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1792 xmlXPathNewCache(void)
1793 {
1794     xmlXPathContextCachePtr ret;
1795 
1796     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1797     if (ret == NULL) {
1798         xmlXPathErrMemory(NULL, "creating object cache\n");
1799 	return(NULL);
1800     }
1801     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1802     ret->maxNodeset = 100;
1803     ret->maxString = 100;
1804     ret->maxBoolean = 100;
1805     ret->maxNumber = 100;
1806     ret->maxMisc = 100;
1807     return(ret);
1808 }
1809 
1810 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1812 {
1813     int i;
1814     xmlXPathObjectPtr obj;
1815 
1816     if (list == NULL)
1817 	return;
1818 
1819     for (i = 0; i < list->number; i++) {
1820 	obj = list->items[i];
1821 	/*
1822 	* Note that it is already assured that we don't need to
1823 	* look out for namespace nodes in the node-set.
1824 	*/
1825 	if (obj->nodesetval != NULL) {
1826 	    if (obj->nodesetval->nodeTab != NULL)
1827 		xmlFree(obj->nodesetval->nodeTab);
1828 	    xmlFree(obj->nodesetval);
1829 	}
1830 	xmlFree(obj);
1831 #ifdef XP_DEBUG_OBJ_USAGE
1832 	xmlXPathDebugObjCounterAll--;
1833 #endif
1834     }
1835     xmlPointerListFree(list);
1836 }
1837 
1838 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1840 {
1841     if (cache == NULL)
1842 	return;
1843     if (cache->nodesetObjs)
1844 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1845     if (cache->stringObjs)
1846 	xmlXPathCacheFreeObjectList(cache->stringObjs);
1847     if (cache->booleanObjs)
1848 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1849     if (cache->numberObjs)
1850 	xmlXPathCacheFreeObjectList(cache->numberObjs);
1851     if (cache->miscObjs)
1852 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1853     xmlFree(cache);
1854 }
1855 
1856 /**
1857  * xmlXPathContextSetCache:
1858  *
1859  * @ctxt:  the XPath context
1860  * @active: enables/disables (creates/frees) the cache
1861  * @value: a value with semantics dependant on @options
1862  * @options: options (currently only the value 0 is used)
1863  *
1864  * Creates/frees an object cache on the XPath context.
1865  * If activates XPath objects (xmlXPathObject) will be cached internally
1866  * to be reused.
1867  * @options:
1868  *   0: This will set the XPath object caching:
1869  *      @value:
1870  *        This will set the maximum number of XPath objects
1871  *        to be cached per slot
1872  *        There are 5 slots for: node-set, string, number, boolean, and
1873  *        misc objects. Use <0 for the default number (100).
1874  *   Other values for @options have currently no effect.
1875  *
1876  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877  */
1878 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1880 			int active,
1881 			int value,
1882 			int options)
1883 {
1884     if (ctxt == NULL)
1885 	return(-1);
1886     if (active) {
1887 	xmlXPathContextCachePtr cache;
1888 
1889 	if (ctxt->cache == NULL) {
1890 	    ctxt->cache = xmlXPathNewCache();
1891 	    if (ctxt->cache == NULL)
1892 		return(-1);
1893 	}
1894 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1895 	if (options == 0) {
1896 	    if (value < 0)
1897 		value = 100;
1898 	    cache->maxNodeset = value;
1899 	    cache->maxString = value;
1900 	    cache->maxNumber = value;
1901 	    cache->maxBoolean = value;
1902 	    cache->maxMisc = value;
1903 	}
1904     } else if (ctxt->cache != NULL) {
1905 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1906 	ctxt->cache = NULL;
1907     }
1908     return(0);
1909 }
1910 
1911 /**
1912  * xmlXPathCacheWrapNodeSet:
1913  * @ctxt: the XPath context
1914  * @val:  the NodePtr value
1915  *
1916  * This is the cached version of xmlXPathWrapNodeSet().
1917  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918  *
1919  * Returns the created or reused object.
1920  */
1921 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1923 {
1924     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925 	xmlXPathContextCachePtr cache =
1926 	    (xmlXPathContextCachePtr) ctxt->cache;
1927 
1928 	if ((cache->miscObjs != NULL) &&
1929 	    (cache->miscObjs->number != 0))
1930 	{
1931 	    xmlXPathObjectPtr ret;
1932 
1933 	    ret = (xmlXPathObjectPtr)
1934 		cache->miscObjs->items[--cache->miscObjs->number];
1935 	    ret->type = XPATH_NODESET;
1936 	    ret->nodesetval = val;
1937 #ifdef XP_DEBUG_OBJ_USAGE
1938 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1939 #endif
1940 	    return(ret);
1941 	}
1942     }
1943 
1944     return(xmlXPathWrapNodeSet(val));
1945 
1946 }
1947 
1948 /**
1949  * xmlXPathCacheWrapString:
1950  * @ctxt: the XPath context
1951  * @val:  the xmlChar * value
1952  *
1953  * This is the cached version of xmlXPathWrapString().
1954  * Wraps the @val string into an XPath object.
1955  *
1956  * Returns the created or reused object.
1957  */
1958 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1960 {
1961     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1963 
1964 	if ((cache->stringObjs != NULL) &&
1965 	    (cache->stringObjs->number != 0))
1966 	{
1967 
1968 	    xmlXPathObjectPtr ret;
1969 
1970 	    ret = (xmlXPathObjectPtr)
1971 		cache->stringObjs->items[--cache->stringObjs->number];
1972 	    ret->type = XPATH_STRING;
1973 	    ret->stringval = val;
1974 #ifdef XP_DEBUG_OBJ_USAGE
1975 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976 #endif
1977 	    return(ret);
1978 	} else if ((cache->miscObjs != NULL) &&
1979 	    (cache->miscObjs->number != 0))
1980 	{
1981 	    xmlXPathObjectPtr ret;
1982 	    /*
1983 	    * Fallback to misc-cache.
1984 	    */
1985 	    ret = (xmlXPathObjectPtr)
1986 		cache->miscObjs->items[--cache->miscObjs->number];
1987 
1988 	    ret->type = XPATH_STRING;
1989 	    ret->stringval = val;
1990 #ifdef XP_DEBUG_OBJ_USAGE
1991 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1992 #endif
1993 	    return(ret);
1994 	}
1995     }
1996     return(xmlXPathWrapString(val));
1997 }
1998 
1999 /**
2000  * xmlXPathCacheNewNodeSet:
2001  * @ctxt: the XPath context
2002  * @val:  the NodePtr value
2003  *
2004  * This is the cached version of xmlXPathNewNodeSet().
2005  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006  * it with the single Node @val
2007  *
2008  * Returns the created or reused object.
2009  */
2010 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012 {
2013     if ((ctxt != NULL) && (ctxt->cache)) {
2014 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2015 
2016 	if ((cache->nodesetObjs != NULL) &&
2017 	    (cache->nodesetObjs->number != 0))
2018 	{
2019 	    xmlXPathObjectPtr ret;
2020 	    /*
2021 	    * Use the nodset-cache.
2022 	    */
2023 	    ret = (xmlXPathObjectPtr)
2024 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025 	    ret->type = XPATH_NODESET;
2026 	    ret->boolval = 0;
2027 	    if (val) {
2028 		if ((ret->nodesetval->nodeMax == 0) ||
2029 		    (val->type == XML_NAMESPACE_DECL))
2030 		{
2031 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2032 		} else {
2033 		    ret->nodesetval->nodeTab[0] = val;
2034 		    ret->nodesetval->nodeNr = 1;
2035 		}
2036 	    }
2037 #ifdef XP_DEBUG_OBJ_USAGE
2038 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039 #endif
2040 	    return(ret);
2041 	} else if ((cache->miscObjs != NULL) &&
2042 	    (cache->miscObjs->number != 0))
2043 	{
2044 	    xmlXPathObjectPtr ret;
2045 	    /*
2046 	    * Fallback to misc-cache.
2047 	    */
2048 
2049 	    ret = (xmlXPathObjectPtr)
2050 		cache->miscObjs->items[--cache->miscObjs->number];
2051 
2052 	    ret->type = XPATH_NODESET;
2053 	    ret->boolval = 0;
2054 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2055 #ifdef XP_DEBUG_OBJ_USAGE
2056 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2057 #endif
2058 	    return(ret);
2059 	}
2060     }
2061     return(xmlXPathNewNodeSet(val));
2062 }
2063 
2064 /**
2065  * xmlXPathCacheNewCString:
2066  * @ctxt: the XPath context
2067  * @val:  the char * value
2068  *
2069  * This is the cached version of xmlXPathNewCString().
2070  * Acquire an xmlXPathObjectPtr of type string and of value @val
2071  *
2072  * Returns the created or reused object.
2073  */
2074 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2076 {
2077     if ((ctxt != NULL) && (ctxt->cache)) {
2078 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2079 
2080 	if ((cache->stringObjs != NULL) &&
2081 	    (cache->stringObjs->number != 0))
2082 	{
2083 	    xmlXPathObjectPtr ret;
2084 
2085 	    ret = (xmlXPathObjectPtr)
2086 		cache->stringObjs->items[--cache->stringObjs->number];
2087 
2088 	    ret->type = XPATH_STRING;
2089 	    ret->stringval = xmlStrdup(BAD_CAST val);
2090 #ifdef XP_DEBUG_OBJ_USAGE
2091 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092 #endif
2093 	    return(ret);
2094 	} else if ((cache->miscObjs != NULL) &&
2095 	    (cache->miscObjs->number != 0))
2096 	{
2097 	    xmlXPathObjectPtr ret;
2098 
2099 	    ret = (xmlXPathObjectPtr)
2100 		cache->miscObjs->items[--cache->miscObjs->number];
2101 
2102 	    ret->type = XPATH_STRING;
2103 	    ret->stringval = xmlStrdup(BAD_CAST val);
2104 #ifdef XP_DEBUG_OBJ_USAGE
2105 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2106 #endif
2107 	    return(ret);
2108 	}
2109     }
2110     return(xmlXPathNewCString(val));
2111 }
2112 
2113 /**
2114  * xmlXPathCacheNewString:
2115  * @ctxt: the XPath context
2116  * @val:  the xmlChar * value
2117  *
2118  * This is the cached version of xmlXPathNewString().
2119  * Acquire an xmlXPathObjectPtr of type string and of value @val
2120  *
2121  * Returns the created or reused object.
2122  */
2123 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2125 {
2126     if ((ctxt != NULL) && (ctxt->cache)) {
2127 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2128 
2129 	if ((cache->stringObjs != NULL) &&
2130 	    (cache->stringObjs->number != 0))
2131 	{
2132 	    xmlXPathObjectPtr ret;
2133 
2134 	    ret = (xmlXPathObjectPtr)
2135 		cache->stringObjs->items[--cache->stringObjs->number];
2136 	    ret->type = XPATH_STRING;
2137 	    if (val != NULL)
2138 		ret->stringval = xmlStrdup(val);
2139 	    else
2140 		ret->stringval = xmlStrdup((const xmlChar *)"");
2141 #ifdef XP_DEBUG_OBJ_USAGE
2142 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143 #endif
2144 	    return(ret);
2145 	} else if ((cache->miscObjs != NULL) &&
2146 	    (cache->miscObjs->number != 0))
2147 	{
2148 	    xmlXPathObjectPtr ret;
2149 
2150 	    ret = (xmlXPathObjectPtr)
2151 		cache->miscObjs->items[--cache->miscObjs->number];
2152 
2153 	    ret->type = XPATH_STRING;
2154 	    if (val != NULL)
2155 		ret->stringval = xmlStrdup(val);
2156 	    else
2157 		ret->stringval = xmlStrdup((const xmlChar *)"");
2158 #ifdef XP_DEBUG_OBJ_USAGE
2159 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2160 #endif
2161 	    return(ret);
2162 	}
2163     }
2164     return(xmlXPathNewString(val));
2165 }
2166 
2167 /**
2168  * xmlXPathCacheNewBoolean:
2169  * @ctxt: the XPath context
2170  * @val:  the boolean value
2171  *
2172  * This is the cached version of xmlXPathNewBoolean().
2173  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174  *
2175  * Returns the created or reused object.
2176  */
2177 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2179 {
2180     if ((ctxt != NULL) && (ctxt->cache)) {
2181 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2182 
2183 	if ((cache->booleanObjs != NULL) &&
2184 	    (cache->booleanObjs->number != 0))
2185 	{
2186 	    xmlXPathObjectPtr ret;
2187 
2188 	    ret = (xmlXPathObjectPtr)
2189 		cache->booleanObjs->items[--cache->booleanObjs->number];
2190 	    ret->type = XPATH_BOOLEAN;
2191 	    ret->boolval = (val != 0);
2192 #ifdef XP_DEBUG_OBJ_USAGE
2193 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194 #endif
2195 	    return(ret);
2196 	} else if ((cache->miscObjs != NULL) &&
2197 	    (cache->miscObjs->number != 0))
2198 	{
2199 	    xmlXPathObjectPtr ret;
2200 
2201 	    ret = (xmlXPathObjectPtr)
2202 		cache->miscObjs->items[--cache->miscObjs->number];
2203 
2204 	    ret->type = XPATH_BOOLEAN;
2205 	    ret->boolval = (val != 0);
2206 #ifdef XP_DEBUG_OBJ_USAGE
2207 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2208 #endif
2209 	    return(ret);
2210 	}
2211     }
2212     return(xmlXPathNewBoolean(val));
2213 }
2214 
2215 /**
2216  * xmlXPathCacheNewFloat:
2217  * @ctxt: the XPath context
2218  * @val:  the double value
2219  *
2220  * This is the cached version of xmlXPathNewFloat().
2221  * Acquires an xmlXPathObjectPtr of type double and of value @val
2222  *
2223  * Returns the created or reused object.
2224  */
2225 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227 {
2228      if ((ctxt != NULL) && (ctxt->cache)) {
2229 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2230 
2231 	if ((cache->numberObjs != NULL) &&
2232 	    (cache->numberObjs->number != 0))
2233 	{
2234 	    xmlXPathObjectPtr ret;
2235 
2236 	    ret = (xmlXPathObjectPtr)
2237 		cache->numberObjs->items[--cache->numberObjs->number];
2238 	    ret->type = XPATH_NUMBER;
2239 	    ret->floatval = val;
2240 #ifdef XP_DEBUG_OBJ_USAGE
2241 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242 #endif
2243 	    return(ret);
2244 	} else if ((cache->miscObjs != NULL) &&
2245 	    (cache->miscObjs->number != 0))
2246 	{
2247 	    xmlXPathObjectPtr ret;
2248 
2249 	    ret = (xmlXPathObjectPtr)
2250 		cache->miscObjs->items[--cache->miscObjs->number];
2251 
2252 	    ret->type = XPATH_NUMBER;
2253 	    ret->floatval = val;
2254 #ifdef XP_DEBUG_OBJ_USAGE
2255 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2256 #endif
2257 	    return(ret);
2258 	}
2259     }
2260     return(xmlXPathNewFloat(val));
2261 }
2262 
2263 /**
2264  * xmlXPathCacheConvertString:
2265  * @ctxt: the XPath context
2266  * @val:  an XPath object
2267  *
2268  * This is the cached version of xmlXPathConvertString().
2269  * Converts an existing object to its string() equivalent
2270  *
2271  * Returns a created or reused object, the old one is freed (cached)
2272  *         (or the operation is done directly on @val)
2273  */
2274 
2275 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2277     xmlChar *res = NULL;
2278 
2279     if (val == NULL)
2280 	return(xmlXPathCacheNewCString(ctxt, ""));
2281 
2282     switch (val->type) {
2283     case XPATH_UNDEFINED:
2284 #ifdef DEBUG_EXPR
2285 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2286 #endif
2287 	break;
2288     case XPATH_NODESET:
2289     case XPATH_XSLT_TREE:
2290 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2291 	break;
2292     case XPATH_STRING:
2293 	return(val);
2294     case XPATH_BOOLEAN:
2295 	res = xmlXPathCastBooleanToString(val->boolval);
2296 	break;
2297     case XPATH_NUMBER:
2298 	res = xmlXPathCastNumberToString(val->floatval);
2299 	break;
2300     case XPATH_USERS:
2301     case XPATH_POINT:
2302     case XPATH_RANGE:
2303     case XPATH_LOCATIONSET:
2304 	TODO;
2305 	break;
2306     }
2307     xmlXPathReleaseObject(ctxt, val);
2308     if (res == NULL)
2309 	return(xmlXPathCacheNewCString(ctxt, ""));
2310     return(xmlXPathCacheWrapString(ctxt, res));
2311 }
2312 
2313 /**
2314  * xmlXPathCacheObjectCopy:
2315  * @ctxt: the XPath context
2316  * @val:  the original object
2317  *
2318  * This is the cached version of xmlXPathObjectCopy().
2319  * Acquire a copy of a given object
2320  *
2321  * Returns a created or reused created object.
2322  */
2323 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2325 {
2326     if (val == NULL)
2327 	return(NULL);
2328 
2329     if (XP_HAS_CACHE(ctxt)) {
2330 	switch (val->type) {
2331 	    case XPATH_NODESET:
2332 		return(xmlXPathCacheWrapNodeSet(ctxt,
2333 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2334 	    case XPATH_STRING:
2335 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2336 	    case XPATH_BOOLEAN:
2337 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2338 	    case XPATH_NUMBER:
2339 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340 	    default:
2341 		break;
2342 	}
2343     }
2344     return(xmlXPathObjectCopy(val));
2345 }
2346 
2347 /**
2348  * xmlXPathCacheConvertBoolean:
2349  * @ctxt: the XPath context
2350  * @val:  an XPath object
2351  *
2352  * This is the cached version of xmlXPathConvertBoolean().
2353  * Converts an existing object to its boolean() equivalent
2354  *
2355  * Returns a created or reused object, the old one is freed (or the operation
2356  *         is done directly on @val)
2357  */
2358 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360     xmlXPathObjectPtr ret;
2361 
2362     if (val == NULL)
2363 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2364     if (val->type == XPATH_BOOLEAN)
2365 	return(val);
2366     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367     xmlXPathReleaseObject(ctxt, val);
2368     return(ret);
2369 }
2370 
2371 /**
2372  * xmlXPathCacheConvertNumber:
2373  * @ctxt: the XPath context
2374  * @val:  an XPath object
2375  *
2376  * This is the cached version of xmlXPathConvertNumber().
2377  * Converts an existing object to its number() equivalent
2378  *
2379  * Returns a created or reused object, the old one is freed (or the operation
2380  *         is done directly on @val)
2381  */
2382 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384     xmlXPathObjectPtr ret;
2385 
2386     if (val == NULL)
2387 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388     if (val->type == XPATH_NUMBER)
2389 	return(val);
2390     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391     xmlXPathReleaseObject(ctxt, val);
2392     return(ret);
2393 }
2394 
2395 /************************************************************************
2396  *									*
2397  *		Parser stacks related functions and macros		*
2398  *									*
2399  ************************************************************************/
2400 
2401 /**
2402  * xmlXPathSetFrame:
2403  * @ctxt: an XPath parser context
2404  *
2405  * Set the callee evaluation frame
2406  *
2407  * Returns the previous frame value to be restored once done
2408  */
2409 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2411     int ret;
2412 
2413     if (ctxt == NULL)
2414         return(0);
2415     ret = ctxt->valueFrame;
2416     ctxt->valueFrame = ctxt->valueNr;
2417     return(ret);
2418 }
2419 
2420 /**
2421  * xmlXPathPopFrame:
2422  * @ctxt: an XPath parser context
2423  * @frame: the previous frame value
2424  *
2425  * Remove the callee evaluation frame
2426  */
2427 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2429     if (ctxt == NULL)
2430         return;
2431     if (ctxt->valueNr < ctxt->valueFrame) {
2432         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2433     }
2434     ctxt->valueFrame = frame;
2435 }
2436 
2437 /**
2438  * valuePop:
2439  * @ctxt: an XPath evaluation context
2440  *
2441  * Pops the top XPath object from the value stack
2442  *
2443  * Returns the XPath object just removed
2444  */
2445 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2446 valuePop(xmlXPathParserContextPtr ctxt)
2447 {
2448     xmlXPathObjectPtr ret;
2449 
2450     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2451         return (NULL);
2452 
2453     if (ctxt->valueNr <= ctxt->valueFrame) {
2454         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2455         return (NULL);
2456     }
2457 
2458     ctxt->valueNr--;
2459     if (ctxt->valueNr > 0)
2460         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2461     else
2462         ctxt->value = NULL;
2463     ret = ctxt->valueTab[ctxt->valueNr];
2464     ctxt->valueTab[ctxt->valueNr] = NULL;
2465     return (ret);
2466 }
2467 /**
2468  * valuePush:
2469  * @ctxt:  an XPath evaluation context
2470  * @value:  the XPath object
2471  *
2472  * Pushes a new XPath object on top of the value stack
2473  *
2474  * returns the number of items on the value stack
2475  */
2476 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2478 {
2479     if ((ctxt == NULL) || (value == NULL)) return(-1);
2480     if (ctxt->valueNr >= ctxt->valueMax) {
2481         xmlXPathObjectPtr *tmp;
2482 
2483         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484                                              2 * ctxt->valueMax *
2485                                              sizeof(ctxt->valueTab[0]));
2486         if (tmp == NULL) {
2487             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2488             ctxt->error = XPATH_MEMORY_ERROR;
2489             return (0);
2490         }
2491         ctxt->valueMax *= 2;
2492 	ctxt->valueTab = tmp;
2493     }
2494     ctxt->valueTab[ctxt->valueNr] = value;
2495     ctxt->value = value;
2496     return (ctxt->valueNr++);
2497 }
2498 
2499 /**
2500  * xmlXPathPopBoolean:
2501  * @ctxt:  an XPath parser context
2502  *
2503  * Pops a boolean from the stack, handling conversion if needed.
2504  * Check error with #xmlXPathCheckError.
2505  *
2506  * Returns the boolean
2507  */
2508 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510     xmlXPathObjectPtr obj;
2511     int ret;
2512 
2513     obj = valuePop(ctxt);
2514     if (obj == NULL) {
2515 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2516 	return(0);
2517     }
2518     if (obj->type != XPATH_BOOLEAN)
2519 	ret = xmlXPathCastToBoolean(obj);
2520     else
2521         ret = obj->boolval;
2522     xmlXPathReleaseObject(ctxt->context, obj);
2523     return(ret);
2524 }
2525 
2526 /**
2527  * xmlXPathPopNumber:
2528  * @ctxt:  an XPath parser context
2529  *
2530  * Pops a number from the stack, handling conversion if needed.
2531  * Check error with #xmlXPathCheckError.
2532  *
2533  * Returns the number
2534  */
2535 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537     xmlXPathObjectPtr obj;
2538     double ret;
2539 
2540     obj = valuePop(ctxt);
2541     if (obj == NULL) {
2542 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2543 	return(0);
2544     }
2545     if (obj->type != XPATH_NUMBER)
2546 	ret = xmlXPathCastToNumber(obj);
2547     else
2548         ret = obj->floatval;
2549     xmlXPathReleaseObject(ctxt->context, obj);
2550     return(ret);
2551 }
2552 
2553 /**
2554  * xmlXPathPopString:
2555  * @ctxt:  an XPath parser context
2556  *
2557  * Pops a string from the stack, handling conversion if needed.
2558  * Check error with #xmlXPathCheckError.
2559  *
2560  * Returns the string
2561  */
2562 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564     xmlXPathObjectPtr obj;
2565     xmlChar * ret;
2566 
2567     obj = valuePop(ctxt);
2568     if (obj == NULL) {
2569 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2570 	return(NULL);
2571     }
2572     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2573     /* TODO: needs refactoring somewhere else */
2574     if (obj->stringval == ret)
2575 	obj->stringval = NULL;
2576     xmlXPathReleaseObject(ctxt->context, obj);
2577     return(ret);
2578 }
2579 
2580 /**
2581  * xmlXPathPopNodeSet:
2582  * @ctxt:  an XPath parser context
2583  *
2584  * Pops a node-set from the stack, handling conversion if needed.
2585  * Check error with #xmlXPathCheckError.
2586  *
2587  * Returns the node-set
2588  */
2589 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591     xmlXPathObjectPtr obj;
2592     xmlNodeSetPtr ret;
2593 
2594     if (ctxt == NULL) return(NULL);
2595     if (ctxt->value == NULL) {
2596 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2597 	return(NULL);
2598     }
2599     if (!xmlXPathStackIsNodeSet(ctxt)) {
2600 	xmlXPathSetTypeError(ctxt);
2601 	return(NULL);
2602     }
2603     obj = valuePop(ctxt);
2604     ret = obj->nodesetval;
2605 #if 0
2606     /* to fix memory leak of not clearing obj->user */
2607     if (obj->boolval && obj->user != NULL)
2608         xmlFreeNodeList((xmlNodePtr) obj->user);
2609 #endif
2610     obj->nodesetval = NULL;
2611     xmlXPathReleaseObject(ctxt->context, obj);
2612     return(ret);
2613 }
2614 
2615 /**
2616  * xmlXPathPopExternal:
2617  * @ctxt:  an XPath parser context
2618  *
2619  * Pops an external object from the stack, handling conversion if needed.
2620  * Check error with #xmlXPathCheckError.
2621  *
2622  * Returns the object
2623  */
2624 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626     xmlXPathObjectPtr obj;
2627     void * ret;
2628 
2629     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2630 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2631 	return(NULL);
2632     }
2633     if (ctxt->value->type != XPATH_USERS) {
2634 	xmlXPathSetTypeError(ctxt);
2635 	return(NULL);
2636     }
2637     obj = valuePop(ctxt);
2638     ret = obj->user;
2639     obj->user = NULL;
2640     xmlXPathReleaseObject(ctxt->context, obj);
2641     return(ret);
2642 }
2643 
2644 /*
2645  * Macros for accessing the content. Those should be used only by the parser,
2646  * and not exported.
2647  *
2648  * Dirty macros, i.e. one need to make assumption on the context to use them
2649  *
2650  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2651  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2652  *           in ISO-Latin or UTF-8.
2653  *           This should be used internally by the parser
2654  *           only to compare to ASCII values otherwise it would break when
2655  *           running with UTF-8 encoding.
2656  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2657  *           to compare on ASCII based substring.
2658  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659  *           strings within the parser.
2660  *   CURRENT Returns the current char value, with the full decoding of
2661  *           UTF-8 if we are using this mode. It returns an int.
2662  *   NEXT    Skip to the next character, this does the proper decoding
2663  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664  *           It returns the pointer to the current xmlChar.
2665  */
2666 
2667 #define CUR (*ctxt->cur)
2668 #define SKIP(val) ctxt->cur += (val)
2669 #define NXT(val) ctxt->cur[(val)]
2670 #define CUR_PTR ctxt->cur
2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2672 
2673 #define COPY_BUF(l,b,i,v)                                              \
2674     if (l == 1) b[i++] = (xmlChar) v;                                  \
2675     else i += xmlCopyChar(l,&b[i],v)
2676 
2677 #define NEXTL(l)  ctxt->cur += l
2678 
2679 #define SKIP_BLANKS							\
2680     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2681 
2682 #define CURRENT (*ctxt->cur)
2683 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2684 
2685 
2686 #ifndef DBL_DIG
2687 #define DBL_DIG 16
2688 #endif
2689 #ifndef DBL_EPSILON
2690 #define DBL_EPSILON 1E-9
2691 #endif
2692 
2693 #define UPPER_DOUBLE 1E9
2694 #define LOWER_DOUBLE 1E-5
2695 #define	LOWER_DOUBLE_EXP 5
2696 
2697 #define INTEGER_DIGITS DBL_DIG
2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2699 #define EXPONENT_DIGITS (3 + 2)
2700 
2701 /**
2702  * xmlXPathFormatNumber:
2703  * @number:     number to format
2704  * @buffer:     output buffer
2705  * @buffersize: size of output buffer
2706  *
2707  * Convert the number into a string representation.
2708  */
2709 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2711 {
2712     switch (xmlXPathIsInf(number)) {
2713     case 1:
2714 	if (buffersize > (int)sizeof("Infinity"))
2715 	    snprintf(buffer, buffersize, "Infinity");
2716 	break;
2717     case -1:
2718 	if (buffersize > (int)sizeof("-Infinity"))
2719 	    snprintf(buffer, buffersize, "-Infinity");
2720 	break;
2721     default:
2722 	if (xmlXPathIsNaN(number)) {
2723 	    if (buffersize > (int)sizeof("NaN"))
2724 		snprintf(buffer, buffersize, "NaN");
2725 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2726 	    snprintf(buffer, buffersize, "0");
2727 	} else if (number == ((int) number)) {
2728 	    char work[30];
2729 	    char *ptr, *cur;
2730 	    int value = (int) number;
2731 
2732             ptr = &buffer[0];
2733 	    if (value == 0) {
2734 		*ptr++ = '0';
2735 	    } else {
2736 		snprintf(work, 29, "%d", value);
2737 		cur = &work[0];
2738 		while ((*cur) && (ptr - buffer < buffersize)) {
2739 		    *ptr++ = *cur++;
2740 		}
2741 	    }
2742 	    if (ptr - buffer < buffersize) {
2743 		*ptr = 0;
2744 	    } else if (buffersize > 0) {
2745 		ptr--;
2746 		*ptr = 0;
2747 	    }
2748 	} else {
2749 	    /*
2750 	      For the dimension of work,
2751 	          DBL_DIG is number of significant digits
2752 		  EXPONENT is only needed for "scientific notation"
2753 	          3 is sign, decimal point, and terminating zero
2754 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755 	      Note that this dimension is slightly (a few characters)
2756 	      larger than actually necessary.
2757 	    */
2758 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2759 	    int integer_place, fraction_place;
2760 	    char *ptr;
2761 	    char *after_fraction;
2762 	    double absolute_value;
2763 	    int size;
2764 
2765 	    absolute_value = fabs(number);
2766 
2767 	    /*
2768 	     * First choose format - scientific or regular floating point.
2769 	     * In either case, result is in work, and after_fraction points
2770 	     * just past the fractional part.
2771 	    */
2772 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2773 		  (absolute_value < LOWER_DOUBLE)) &&
2774 		 (absolute_value != 0.0) ) {
2775 		/* Use scientific notation */
2776 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777 		fraction_place = DBL_DIG - 1;
2778 		size = snprintf(work, sizeof(work),"%*.*e",
2779 			 integer_place, fraction_place, number);
2780 		while ((size > 0) && (work[size] != 'e')) size--;
2781 
2782 	    }
2783 	    else {
2784 		/* Use regular notation */
2785 		if (absolute_value > 0.0) {
2786 		    integer_place = (int)log10(absolute_value);
2787 		    if (integer_place > 0)
2788 		        fraction_place = DBL_DIG - integer_place - 1;
2789 		    else
2790 		        fraction_place = DBL_DIG - integer_place;
2791 		} else {
2792 		    fraction_place = 1;
2793 		}
2794 		size = snprintf(work, sizeof(work), "%0.*f",
2795 				fraction_place, number);
2796 	    }
2797 
2798 	    /* Remove fractional trailing zeroes */
2799 	    after_fraction = work + size;
2800 	    ptr = after_fraction;
2801 	    while (*(--ptr) == '0')
2802 		;
2803 	    if (*ptr != '.')
2804 	        ptr++;
2805 	    while ((*ptr++ = *after_fraction++) != 0);
2806 
2807 	    /* Finally copy result back to caller */
2808 	    size = strlen(work) + 1;
2809 	    if (size > buffersize && buffersize <= (int)sizeof(work)) {
2810 		work[buffersize - 1] = 0;
2811 		size = buffersize;
2812 	    }
2813 	    memmove(buffer, work, size);
2814 	}
2815 	break;
2816     }
2817 }
2818 
2819 
2820 /************************************************************************
2821  *									*
2822  *			Routines to handle NodeSets			*
2823  *									*
2824  ************************************************************************/
2825 
2826 /**
2827  * xmlXPathOrderDocElems:
2828  * @doc:  an input document
2829  *
2830  * Call this routine to speed up XPath computation on static documents.
2831  * This stamps all the element nodes with the document order
2832  * Like for line information, the order is kept in the element->content
2833  * field, the value stored is actually - the node number (starting at -1)
2834  * to be able to differentiate from line numbers.
2835  *
2836  * Returns the number of elements found in the document or -1 in case
2837  *    of error.
2838  */
2839 long
xmlXPathOrderDocElems(xmlDocPtr doc)2840 xmlXPathOrderDocElems(xmlDocPtr doc) {
2841     long count = 0;
2842     xmlNodePtr cur;
2843 
2844     if (doc == NULL)
2845 	return(-1);
2846     cur = doc->children;
2847     while (cur != NULL) {
2848 	if (cur->type == XML_ELEMENT_NODE) {
2849 	    cur->content = (void *) (-(++count));
2850 	    if (cur->children != NULL) {
2851 		cur = cur->children;
2852 		continue;
2853 	    }
2854 	}
2855 	if (cur->next != NULL) {
2856 	    cur = cur->next;
2857 	    continue;
2858 	}
2859 	do {
2860 	    cur = cur->parent;
2861 	    if (cur == NULL)
2862 		break;
2863 	    if (cur == (xmlNodePtr) doc) {
2864 		cur = NULL;
2865 		break;
2866 	    }
2867 	    if (cur->next != NULL) {
2868 		cur = cur->next;
2869 		break;
2870 	    }
2871 	} while (cur != NULL);
2872     }
2873     return(count);
2874 }
2875 
2876 /**
2877  * xmlXPathCmpNodes:
2878  * @node1:  the first node
2879  * @node2:  the second node
2880  *
2881  * Compare two nodes w.r.t document order
2882  *
2883  * Returns -2 in case of error 1 if first point < second point, 0 if
2884  *         it's the same node, -1 otherwise
2885  */
2886 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2888     int depth1, depth2;
2889     int attr1 = 0, attr2 = 0;
2890     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2891     xmlNodePtr cur, root;
2892 
2893     if ((node1 == NULL) || (node2 == NULL))
2894 	return(-2);
2895     /*
2896      * a couple of optimizations which will avoid computations in most cases
2897      */
2898     if (node1 == node2)		/* trivial case */
2899 	return(0);
2900     if (node1->type == XML_ATTRIBUTE_NODE) {
2901 	attr1 = 1;
2902 	attrNode1 = node1;
2903 	node1 = node1->parent;
2904     }
2905     if (node2->type == XML_ATTRIBUTE_NODE) {
2906 	attr2 = 1;
2907 	attrNode2 = node2;
2908 	node2 = node2->parent;
2909     }
2910     if (node1 == node2) {
2911 	if (attr1 == attr2) {
2912 	    /* not required, but we keep attributes in order */
2913 	    if (attr1 != 0) {
2914 	        cur = attrNode2->prev;
2915 		while (cur != NULL) {
2916 		    if (cur == attrNode1)
2917 		        return (1);
2918 		    cur = cur->prev;
2919 		}
2920 		return (-1);
2921 	    }
2922 	    return(0);
2923 	}
2924 	if (attr2 == 1)
2925 	    return(1);
2926 	return(-1);
2927     }
2928     if ((node1->type == XML_NAMESPACE_DECL) ||
2929         (node2->type == XML_NAMESPACE_DECL))
2930 	return(1);
2931     if (node1 == node2->prev)
2932 	return(1);
2933     if (node1 == node2->next)
2934 	return(-1);
2935 
2936     /*
2937      * Speedup using document order if availble.
2938      */
2939     if ((node1->type == XML_ELEMENT_NODE) &&
2940 	(node2->type == XML_ELEMENT_NODE) &&
2941 	(0 > (long) node1->content) &&
2942 	(0 > (long) node2->content) &&
2943 	(node1->doc == node2->doc)) {
2944 	long l1, l2;
2945 
2946 	l1 = -((long) node1->content);
2947 	l2 = -((long) node2->content);
2948 	if (l1 < l2)
2949 	    return(1);
2950 	if (l1 > l2)
2951 	    return(-1);
2952     }
2953 
2954     /*
2955      * compute depth to root
2956      */
2957     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2958 	if (cur == node1)
2959 	    return(1);
2960 	depth2++;
2961     }
2962     root = cur;
2963     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2964 	if (cur == node2)
2965 	    return(-1);
2966 	depth1++;
2967     }
2968     /*
2969      * Distinct document (or distinct entities :-( ) case.
2970      */
2971     if (root != cur) {
2972 	return(-2);
2973     }
2974     /*
2975      * get the nearest common ancestor.
2976      */
2977     while (depth1 > depth2) {
2978 	depth1--;
2979 	node1 = node1->parent;
2980     }
2981     while (depth2 > depth1) {
2982 	depth2--;
2983 	node2 = node2->parent;
2984     }
2985     while (node1->parent != node2->parent) {
2986 	node1 = node1->parent;
2987 	node2 = node2->parent;
2988 	/* should not happen but just in case ... */
2989 	if ((node1 == NULL) || (node2 == NULL))
2990 	    return(-2);
2991     }
2992     /*
2993      * Find who's first.
2994      */
2995     if (node1 == node2->prev)
2996 	return(1);
2997     if (node1 == node2->next)
2998 	return(-1);
2999     /*
3000      * Speedup using document order if availble.
3001      */
3002     if ((node1->type == XML_ELEMENT_NODE) &&
3003 	(node2->type == XML_ELEMENT_NODE) &&
3004 	(0 > (long) node1->content) &&
3005 	(0 > (long) node2->content) &&
3006 	(node1->doc == node2->doc)) {
3007 	long l1, l2;
3008 
3009 	l1 = -((long) node1->content);
3010 	l2 = -((long) node2->content);
3011 	if (l1 < l2)
3012 	    return(1);
3013 	if (l1 > l2)
3014 	    return(-1);
3015     }
3016 
3017     for (cur = node1->next;cur != NULL;cur = cur->next)
3018 	if (cur == node2)
3019 	    return(1);
3020     return(-1); /* assume there is no sibling list corruption */
3021 }
3022 
3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3024 /**
3025  * xmlXPathCmpNodesExt:
3026  * @node1:  the first node
3027  * @node2:  the second node
3028  *
3029  * Compare two nodes w.r.t document order.
3030  * This one is optimized for handling of non-element nodes.
3031  *
3032  * Returns -2 in case of error 1 if first point < second point, 0 if
3033  *         it's the same node, -1 otherwise
3034  */
3035 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3037     int depth1, depth2;
3038     int misc = 0, precedence1 = 0, precedence2 = 0;
3039     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040     xmlNodePtr cur, root;
3041     long l1, l2;
3042 
3043     if ((node1 == NULL) || (node2 == NULL))
3044 	return(-2);
3045 
3046     if (node1 == node2)
3047 	return(0);
3048 
3049     /*
3050      * a couple of optimizations which will avoid computations in most cases
3051      */
3052     switch (node1->type) {
3053 	case XML_ELEMENT_NODE:
3054 	    if (node2->type == XML_ELEMENT_NODE) {
3055 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056 		    (0 > (long) node2->content) &&
3057 		    (node1->doc == node2->doc))
3058 		{
3059 		    l1 = -((long) node1->content);
3060 		    l2 = -((long) node2->content);
3061 		    if (l1 < l2)
3062 			return(1);
3063 		    if (l1 > l2)
3064 			return(-1);
3065 		} else
3066 		    goto turtle_comparison;
3067 	    }
3068 	    break;
3069 	case XML_ATTRIBUTE_NODE:
3070 	    precedence1 = 1; /* element is owner */
3071 	    miscNode1 = node1;
3072 	    node1 = node1->parent;
3073 	    misc = 1;
3074 	    break;
3075 	case XML_TEXT_NODE:
3076 	case XML_CDATA_SECTION_NODE:
3077 	case XML_COMMENT_NODE:
3078 	case XML_PI_NODE: {
3079 	    miscNode1 = node1;
3080 	    /*
3081 	    * Find nearest element node.
3082 	    */
3083 	    if (node1->prev != NULL) {
3084 		do {
3085 		    node1 = node1->prev;
3086 		    if (node1->type == XML_ELEMENT_NODE) {
3087 			precedence1 = 3; /* element in prev-sibl axis */
3088 			break;
3089 		    }
3090 		    if (node1->prev == NULL) {
3091 			precedence1 = 2; /* element is parent */
3092 			/*
3093 			* URGENT TODO: Are there any cases, where the
3094 			* parent of such a node is not an element node?
3095 			*/
3096 			node1 = node1->parent;
3097 			break;
3098 		    }
3099 		} while (1);
3100 	    } else {
3101 		precedence1 = 2; /* element is parent */
3102 		node1 = node1->parent;
3103 	    }
3104 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105 		(0 <= (long) node1->content)) {
3106 		/*
3107 		* Fallback for whatever case.
3108 		*/
3109 		node1 = miscNode1;
3110 		precedence1 = 0;
3111 	    } else
3112 		misc = 1;
3113 	}
3114 	    break;
3115 	case XML_NAMESPACE_DECL:
3116 	    /*
3117 	    * TODO: why do we return 1 for namespace nodes?
3118 	    */
3119 	    return(1);
3120 	default:
3121 	    break;
3122     }
3123     switch (node2->type) {
3124 	case XML_ELEMENT_NODE:
3125 	    break;
3126 	case XML_ATTRIBUTE_NODE:
3127 	    precedence2 = 1; /* element is owner */
3128 	    miscNode2 = node2;
3129 	    node2 = node2->parent;
3130 	    misc = 1;
3131 	    break;
3132 	case XML_TEXT_NODE:
3133 	case XML_CDATA_SECTION_NODE:
3134 	case XML_COMMENT_NODE:
3135 	case XML_PI_NODE: {
3136 	    miscNode2 = node2;
3137 	    if (node2->prev != NULL) {
3138 		do {
3139 		    node2 = node2->prev;
3140 		    if (node2->type == XML_ELEMENT_NODE) {
3141 			precedence2 = 3; /* element in prev-sibl axis */
3142 			break;
3143 		    }
3144 		    if (node2->prev == NULL) {
3145 			precedence2 = 2; /* element is parent */
3146 			node2 = node2->parent;
3147 			break;
3148 		    }
3149 		} while (1);
3150 	    } else {
3151 		precedence2 = 2; /* element is parent */
3152 		node2 = node2->parent;
3153 	    }
3154 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155 		(0 <= (long) node1->content))
3156 	    {
3157 		node2 = miscNode2;
3158 		precedence2 = 0;
3159 	    } else
3160 		misc = 1;
3161 	}
3162 	    break;
3163 	case XML_NAMESPACE_DECL:
3164 	    return(1);
3165 	default:
3166 	    break;
3167     }
3168     if (misc) {
3169 	if (node1 == node2) {
3170 	    if (precedence1 == precedence2) {
3171 		/*
3172 		* The ugly case; but normally there aren't many
3173 		* adjacent non-element nodes around.
3174 		*/
3175 		cur = miscNode2->prev;
3176 		while (cur != NULL) {
3177 		    if (cur == miscNode1)
3178 			return(1);
3179 		    if (cur->type == XML_ELEMENT_NODE)
3180 			return(-1);
3181 		    cur = cur->prev;
3182 		}
3183 		return (-1);
3184 	    } else {
3185 		/*
3186 		* Evaluate based on higher precedence wrt to the element.
3187 		* TODO: This assumes attributes are sorted before content.
3188 		*   Is this 100% correct?
3189 		*/
3190 		if (precedence1 < precedence2)
3191 		    return(1);
3192 		else
3193 		    return(-1);
3194 	    }
3195 	}
3196 	/*
3197 	* Special case: One of the helper-elements is contained by the other.
3198 	* <foo>
3199 	*   <node2>
3200 	*     <node1>Text-1(precedence1 == 2)</node1>
3201 	*   </node2>
3202 	*   Text-6(precedence2 == 3)
3203 	* </foo>
3204 	*/
3205 	if ((precedence2 == 3) && (precedence1 > 1)) {
3206 	    cur = node1->parent;
3207 	    while (cur) {
3208 		if (cur == node2)
3209 		    return(1);
3210 		cur = cur->parent;
3211 	    }
3212 	}
3213 	if ((precedence1 == 3) && (precedence2 > 1)) {
3214 	    cur = node2->parent;
3215 	    while (cur) {
3216 		if (cur == node1)
3217 		    return(-1);
3218 		cur = cur->parent;
3219 	    }
3220 	}
3221     }
3222 
3223     /*
3224      * Speedup using document order if availble.
3225      */
3226     if ((node1->type == XML_ELEMENT_NODE) &&
3227 	(node2->type == XML_ELEMENT_NODE) &&
3228 	(0 > (long) node1->content) &&
3229 	(0 > (long) node2->content) &&
3230 	(node1->doc == node2->doc)) {
3231 
3232 	l1 = -((long) node1->content);
3233 	l2 = -((long) node2->content);
3234 	if (l1 < l2)
3235 	    return(1);
3236 	if (l1 > l2)
3237 	    return(-1);
3238     }
3239 
3240 turtle_comparison:
3241 
3242     if (node1 == node2->prev)
3243 	return(1);
3244     if (node1 == node2->next)
3245 	return(-1);
3246     /*
3247      * compute depth to root
3248      */
3249     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3250 	if (cur == node1)
3251 	    return(1);
3252 	depth2++;
3253     }
3254     root = cur;
3255     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3256 	if (cur == node2)
3257 	    return(-1);
3258 	depth1++;
3259     }
3260     /*
3261      * Distinct document (or distinct entities :-( ) case.
3262      */
3263     if (root != cur) {
3264 	return(-2);
3265     }
3266     /*
3267      * get the nearest common ancestor.
3268      */
3269     while (depth1 > depth2) {
3270 	depth1--;
3271 	node1 = node1->parent;
3272     }
3273     while (depth2 > depth1) {
3274 	depth2--;
3275 	node2 = node2->parent;
3276     }
3277     while (node1->parent != node2->parent) {
3278 	node1 = node1->parent;
3279 	node2 = node2->parent;
3280 	/* should not happen but just in case ... */
3281 	if ((node1 == NULL) || (node2 == NULL))
3282 	    return(-2);
3283     }
3284     /*
3285      * Find who's first.
3286      */
3287     if (node1 == node2->prev)
3288 	return(1);
3289     if (node1 == node2->next)
3290 	return(-1);
3291     /*
3292      * Speedup using document order if availble.
3293      */
3294     if ((node1->type == XML_ELEMENT_NODE) &&
3295 	(node2->type == XML_ELEMENT_NODE) &&
3296 	(0 > (long) node1->content) &&
3297 	(0 > (long) node2->content) &&
3298 	(node1->doc == node2->doc)) {
3299 
3300 	l1 = -((long) node1->content);
3301 	l2 = -((long) node2->content);
3302 	if (l1 < l2)
3303 	    return(1);
3304 	if (l1 > l2)
3305 	    return(-1);
3306     }
3307 
3308     for (cur = node1->next;cur != NULL;cur = cur->next)
3309 	if (cur == node2)
3310 	    return(1);
3311     return(-1); /* assume there is no sibling list corruption */
3312 }
3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3314 
3315 /**
3316  * xmlXPathNodeSetSort:
3317  * @set:  the node set
3318  *
3319  * Sort the node set in document order
3320  */
3321 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3323     int i, j, incr, len;
3324     xmlNodePtr tmp;
3325 
3326     if (set == NULL)
3327 	return;
3328 
3329     /* Use Shell's sort to sort the node-set */
3330     len = set->nodeNr;
3331     for (incr = len / 2; incr > 0; incr /= 2) {
3332 	for (i = incr; i < len; i++) {
3333 	    j = i - incr;
3334 	    while (j >= 0) {
3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3336 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337 			set->nodeTab[j + incr]) == -1)
3338 #else
3339 		if (xmlXPathCmpNodes(set->nodeTab[j],
3340 			set->nodeTab[j + incr]) == -1)
3341 #endif
3342 		{
3343 		    tmp = set->nodeTab[j];
3344 		    set->nodeTab[j] = set->nodeTab[j + incr];
3345 		    set->nodeTab[j + incr] = tmp;
3346 		    j -= incr;
3347 		} else
3348 		    break;
3349 	    }
3350 	}
3351     }
3352 }
3353 
3354 #define XML_NODESET_DEFAULT	10
3355 /**
3356  * xmlXPathNodeSetDupNs:
3357  * @node:  the parent node of the namespace XPath node
3358  * @ns:  the libxml namespace declaration node.
3359  *
3360  * Namespace node in libxml don't match the XPath semantic. In a node set
3361  * the namespace nodes are duplicated and the next pointer is set to the
3362  * parent node in the XPath semantic.
3363  *
3364  * Returns the newly created object.
3365  */
3366 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3368     xmlNsPtr cur;
3369 
3370     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3371 	return(NULL);
3372     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373 	return((xmlNodePtr) ns);
3374 
3375     /*
3376      * Allocate a new Namespace and fill the fields.
3377      */
3378     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3379     if (cur == NULL) {
3380         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3381 	return(NULL);
3382     }
3383     memset(cur, 0, sizeof(xmlNs));
3384     cur->type = XML_NAMESPACE_DECL;
3385     if (ns->href != NULL)
3386 	cur->href = xmlStrdup(ns->href);
3387     if (ns->prefix != NULL)
3388 	cur->prefix = xmlStrdup(ns->prefix);
3389     cur->next = (xmlNsPtr) node;
3390     return((xmlNodePtr) cur);
3391 }
3392 
3393 /**
3394  * xmlXPathNodeSetFreeNs:
3395  * @ns:  the XPath namespace node found in a nodeset.
3396  *
3397  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3398  * the namespace nodes are duplicated and the next pointer is set to the
3399  * parent node in the XPath semantic. Check if such a node needs to be freed
3400  */
3401 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3404 	return;
3405 
3406     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407 	if (ns->href != NULL)
3408 	    xmlFree((xmlChar *)ns->href);
3409 	if (ns->prefix != NULL)
3410 	    xmlFree((xmlChar *)ns->prefix);
3411 	xmlFree(ns);
3412     }
3413 }
3414 
3415 /**
3416  * xmlXPathNodeSetCreate:
3417  * @val:  an initial xmlNodePtr, or NULL
3418  *
3419  * Create a new xmlNodeSetPtr of type double and of value @val
3420  *
3421  * Returns the newly created object.
3422  */
3423 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3424 xmlXPathNodeSetCreate(xmlNodePtr val) {
3425     xmlNodeSetPtr ret;
3426 
3427     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428     if (ret == NULL) {
3429         xmlXPathErrMemory(NULL, "creating nodeset\n");
3430 	return(NULL);
3431     }
3432     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433     if (val != NULL) {
3434         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435 					     sizeof(xmlNodePtr));
3436 	if (ret->nodeTab == NULL) {
3437 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3438 	    xmlFree(ret);
3439 	    return(NULL);
3440 	}
3441 	memset(ret->nodeTab, 0 ,
3442 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443         ret->nodeMax = XML_NODESET_DEFAULT;
3444 	if (val->type == XML_NAMESPACE_DECL) {
3445 	    xmlNsPtr ns = (xmlNsPtr) val;
3446 
3447 	    ret->nodeTab[ret->nodeNr++] =
3448 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3449 	} else
3450 	    ret->nodeTab[ret->nodeNr++] = val;
3451     }
3452     return(ret);
3453 }
3454 
3455 /**
3456  * xmlXPathNodeSetCreateSize:
3457  * @size:  the initial size of the set
3458  *
3459  * Create a new xmlNodeSetPtr of type double and of value @val
3460  *
3461  * Returns the newly created object.
3462  */
3463 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3464 xmlXPathNodeSetCreateSize(int size) {
3465     xmlNodeSetPtr ret;
3466 
3467     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3468     if (ret == NULL) {
3469         xmlXPathErrMemory(NULL, "creating nodeset\n");
3470 	return(NULL);
3471     }
3472     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473     if (size < XML_NODESET_DEFAULT)
3474 	size = XML_NODESET_DEFAULT;
3475     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476     if (ret->nodeTab == NULL) {
3477 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3478 	xmlFree(ret);
3479 	return(NULL);
3480     }
3481     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3482     ret->nodeMax = size;
3483     return(ret);
3484 }
3485 
3486 /**
3487  * xmlXPathNodeSetContains:
3488  * @cur:  the node-set
3489  * @val:  the node
3490  *
3491  * checks whether @cur contains @val
3492  *
3493  * Returns true (1) if @cur contains @val, false (0) otherwise
3494  */
3495 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3497     int i;
3498 
3499     if ((cur == NULL) || (val == NULL)) return(0);
3500     if (val->type == XML_NAMESPACE_DECL) {
3501 	for (i = 0; i < cur->nodeNr; i++) {
3502 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3503 		xmlNsPtr ns1, ns2;
3504 
3505 		ns1 = (xmlNsPtr) val;
3506 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3507 		if (ns1 == ns2)
3508 		    return(1);
3509 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3511 		    return(1);
3512 	    }
3513 	}
3514     } else {
3515 	for (i = 0; i < cur->nodeNr; i++) {
3516 	    if (cur->nodeTab[i] == val)
3517 		return(1);
3518 	}
3519     }
3520     return(0);
3521 }
3522 
3523 /**
3524  * xmlXPathNodeSetAddNs:
3525  * @cur:  the initial node set
3526  * @node:  the hosting node
3527  * @ns:  a the namespace node
3528  *
3529  * add a new namespace node to an existing NodeSet
3530  */
3531 void
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3533     int i;
3534 
3535 
3536     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537         (ns->type != XML_NAMESPACE_DECL) ||
3538 	(node->type != XML_ELEMENT_NODE))
3539 	return;
3540 
3541     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542     /*
3543      * prevent duplicates
3544      */
3545     for (i = 0;i < cur->nodeNr;i++) {
3546         if ((cur->nodeTab[i] != NULL) &&
3547 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3548 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3549 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3550 	    return;
3551     }
3552 
3553     /*
3554      * grow the nodeTab if needed
3555      */
3556     if (cur->nodeMax == 0) {
3557         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558 					     sizeof(xmlNodePtr));
3559 	if (cur->nodeTab == NULL) {
3560 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3561 	    return;
3562 	}
3563 	memset(cur->nodeTab, 0 ,
3564 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565         cur->nodeMax = XML_NODESET_DEFAULT;
3566     } else if (cur->nodeNr == cur->nodeMax) {
3567         xmlNodePtr *temp;
3568 
3569 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3570 				      sizeof(xmlNodePtr));
3571 	if (temp == NULL) {
3572 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3573 	    return;
3574 	}
3575         cur->nodeMax *= 2;
3576 	cur->nodeTab = temp;
3577     }
3578     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3579 }
3580 
3581 /**
3582  * xmlXPathNodeSetAdd:
3583  * @cur:  the initial node set
3584  * @val:  a new xmlNodePtr
3585  *
3586  * add a new xmlNodePtr to an existing NodeSet
3587  */
3588 void
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3590     int i;
3591 
3592     if ((cur == NULL) || (val == NULL)) return;
3593 
3594 #if 0
3595     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 	return;	/* an XSLT fake node */
3597 #endif
3598 
3599     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600     /*
3601      * prevent duplcates
3602      */
3603     for (i = 0;i < cur->nodeNr;i++)
3604         if (cur->nodeTab[i] == val) return;
3605 
3606     /*
3607      * grow the nodeTab if needed
3608      */
3609     if (cur->nodeMax == 0) {
3610         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611 					     sizeof(xmlNodePtr));
3612 	if (cur->nodeTab == NULL) {
3613 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3614 	    return;
3615 	}
3616 	memset(cur->nodeTab, 0 ,
3617 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618         cur->nodeMax = XML_NODESET_DEFAULT;
3619     } else if (cur->nodeNr == cur->nodeMax) {
3620         xmlNodePtr *temp;
3621 
3622 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3623 				      sizeof(xmlNodePtr));
3624 	if (temp == NULL) {
3625 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3626 	    return;
3627 	}
3628         cur->nodeMax *= 2;
3629 	cur->nodeTab = temp;
3630     }
3631     if (val->type == XML_NAMESPACE_DECL) {
3632 	xmlNsPtr ns = (xmlNsPtr) val;
3633 
3634 	cur->nodeTab[cur->nodeNr++] =
3635 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3636     } else
3637 	cur->nodeTab[cur->nodeNr++] = val;
3638 }
3639 
3640 /**
3641  * xmlXPathNodeSetAddUnique:
3642  * @cur:  the initial node set
3643  * @val:  a new xmlNodePtr
3644  *
3645  * add a new xmlNodePtr to an existing NodeSet, optimized version
3646  * when we are sure the node is not already in the set.
3647  */
3648 void
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3650     if ((cur == NULL) || (val == NULL)) return;
3651 
3652 #if 0
3653     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654 	return;	/* an XSLT fake node */
3655 #endif
3656 
3657     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3658     /*
3659      * grow the nodeTab if needed
3660      */
3661     if (cur->nodeMax == 0) {
3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 					     sizeof(xmlNodePtr));
3664 	if (cur->nodeTab == NULL) {
3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3666 	    return;
3667 	}
3668 	memset(cur->nodeTab, 0 ,
3669 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670         cur->nodeMax = XML_NODESET_DEFAULT;
3671     } else if (cur->nodeNr == cur->nodeMax) {
3672         xmlNodePtr *temp;
3673 
3674 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675 				      sizeof(xmlNodePtr));
3676 	if (temp == NULL) {
3677 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3678 	    return;
3679 	}
3680 	cur->nodeTab = temp;
3681         cur->nodeMax *= 2;
3682     }
3683     if (val->type == XML_NAMESPACE_DECL) {
3684 	xmlNsPtr ns = (xmlNsPtr) val;
3685 
3686 	cur->nodeTab[cur->nodeNr++] =
3687 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3688     } else
3689 	cur->nodeTab[cur->nodeNr++] = val;
3690 }
3691 
3692 /**
3693  * xmlXPathNodeSetMerge:
3694  * @val1:  the first NodeSet or NULL
3695  * @val2:  the second NodeSet
3696  *
3697  * Merges two nodesets, all nodes from @val2 are added to @val1
3698  * if @val1 is NULL, a new set is created and copied from @val2
3699  *
3700  * Returns @val1 once extended or NULL in case of error.
3701  */
3702 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3704     int i, j, initNr, skip;
3705     xmlNodePtr n1, n2;
3706 
3707     if (val2 == NULL) return(val1);
3708     if (val1 == NULL) {
3709 	val1 = xmlXPathNodeSetCreate(NULL);
3710     if (val1 == NULL)
3711         return (NULL);
3712 #if 0
3713 	/*
3714 	* TODO: The optimization won't work in every case, since
3715 	*  those nasty namespace nodes need to be added with
3716 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3717 	*  memcpy is not possible.
3718 	*  If there was a flag on the nodesetval, indicating that
3719 	*  some temporary nodes are in, that would be helpfull.
3720 	*/
3721 	/*
3722 	* Optimization: Create an equally sized node-set
3723 	* and memcpy the content.
3724 	*/
3725 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3726 	if (val1 == NULL)
3727 	    return(NULL);
3728 	if (val2->nodeNr != 0) {
3729 	    if (val2->nodeNr == 1)
3730 		*(val1->nodeTab) = *(val2->nodeTab);
3731 	    else {
3732 		memcpy(val1->nodeTab, val2->nodeTab,
3733 		    val2->nodeNr * sizeof(xmlNodePtr));
3734 	    }
3735 	    val1->nodeNr = val2->nodeNr;
3736 	}
3737 	return(val1);
3738 #endif
3739     }
3740 
3741     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3742     initNr = val1->nodeNr;
3743 
3744     for (i = 0;i < val2->nodeNr;i++) {
3745 	n2 = val2->nodeTab[i];
3746 	/*
3747 	 * check against duplicates
3748 	 */
3749 	skip = 0;
3750 	for (j = 0; j < initNr; j++) {
3751 	    n1 = val1->nodeTab[j];
3752 	    if (n1 == n2) {
3753 		skip = 1;
3754 		break;
3755 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3756 		       (n2->type == XML_NAMESPACE_DECL)) {
3757 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759 			((xmlNsPtr) n2)->prefix)))
3760 		{
3761 		    skip = 1;
3762 		    break;
3763 		}
3764 	    }
3765 	}
3766 	if (skip)
3767 	    continue;
3768 
3769 	/*
3770 	 * grow the nodeTab if needed
3771 	 */
3772 	if (val1->nodeMax == 0) {
3773 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 						    sizeof(xmlNodePtr));
3775 	    if (val1->nodeTab == NULL) {
3776 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3777 		return(NULL);
3778 	    }
3779 	    memset(val1->nodeTab, 0 ,
3780 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 	    val1->nodeMax = XML_NODESET_DEFAULT;
3782 	} else if (val1->nodeNr == val1->nodeMax) {
3783 	    xmlNodePtr *temp;
3784 
3785 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3786 					     sizeof(xmlNodePtr));
3787 	    if (temp == NULL) {
3788 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3789 		return(NULL);
3790 	    }
3791 	    val1->nodeTab = temp;
3792 	    val1->nodeMax *= 2;
3793 	}
3794 	if (n2->type == XML_NAMESPACE_DECL) {
3795 	    xmlNsPtr ns = (xmlNsPtr) n2;
3796 
3797 	    val1->nodeTab[val1->nodeNr++] =
3798 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799 	} else
3800 	    val1->nodeTab[val1->nodeNr++] = n2;
3801     }
3802 
3803     return(val1);
3804 }
3805 
3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3807 /**
3808  * xmlXPathNodeSetMergeUnique:
3809  * @val1:  the first NodeSet or NULL
3810  * @val2:  the second NodeSet
3811  *
3812  * Merges two nodesets, all nodes from @val2 are added to @val1
3813  * if @val1 is NULL, a new set is created and copied from @val2
3814  *
3815  * Returns @val1 once extended or NULL in case of error.
3816  */
3817 static xmlNodeSetPtr
3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819     int i;
3820 
3821     if (val2 == NULL) return(val1);
3822     if (val1 == NULL) {
3823 	val1 = xmlXPathNodeSetCreate(NULL);
3824     }
3825     if (val1 == NULL)
3826         return (NULL);
3827 
3828     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3829 
3830     for (i = 0;i < val2->nodeNr;i++) {
3831 	/*
3832 	 * grow the nodeTab if needed
3833 	 */
3834 	if (val1->nodeMax == 0) {
3835 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836 						    sizeof(xmlNodePtr));
3837 	    if (val1->nodeTab == NULL) {
3838 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3839 		return(NULL);
3840 	    }
3841 	    memset(val1->nodeTab, 0 ,
3842 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843 	    val1->nodeMax = XML_NODESET_DEFAULT;
3844 	} else if (val1->nodeNr == val1->nodeMax) {
3845 	    xmlNodePtr *temp;
3846 
3847 	    val1->nodeMax *= 2;
3848 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849 					     sizeof(xmlNodePtr));
3850 	    if (temp == NULL) {
3851 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3852 		return(NULL);
3853 	    }
3854 	    val1->nodeTab = temp;
3855 	}
3856 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3858 
3859 	    val1->nodeTab[val1->nodeNr++] =
3860 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3861 	} else
3862 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3863     }
3864 
3865     return(val1);
3866 }
3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3868 
3869 /**
3870  * xmlXPathNodeSetMergeAndClear:
3871  * @set1:  the first NodeSet or NULL
3872  * @set2:  the second NodeSet
3873  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3874  *
3875  * Merges two nodesets, all nodes from @set2 are added to @set1
3876  * if @set1 is NULL, a new set is created and copied from @set2.
3877  * Checks for duplicate nodes. Clears set2.
3878  *
3879  * Returns @set1 once extended or NULL in case of error.
3880  */
3881 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3883 			     int hasNullEntries)
3884 {
3885     if ((set1 == NULL) && (hasNullEntries == 0)) {
3886 	/*
3887 	* Note that doing a memcpy of the list, namespace nodes are
3888 	* just assigned to set1, since set2 is cleared anyway.
3889 	*/
3890 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3891 	if (set1 == NULL)
3892 	    return(NULL);
3893 	if (set2->nodeNr != 0) {
3894 	    memcpy(set1->nodeTab, set2->nodeTab,
3895 		set2->nodeNr * sizeof(xmlNodePtr));
3896 	    set1->nodeNr = set2->nodeNr;
3897 	}
3898     } else {
3899 	int i, j, initNbSet1;
3900 	xmlNodePtr n1, n2;
3901 
3902 	if (set1 == NULL)
3903             set1 = xmlXPathNodeSetCreate(NULL);
3904         if (set1 == NULL)
3905             return (NULL);
3906 
3907 	initNbSet1 = set1->nodeNr;
3908 	for (i = 0;i < set2->nodeNr;i++) {
3909 	    n2 = set2->nodeTab[i];
3910 	    /*
3911 	    * Skip NULLed entries.
3912 	    */
3913 	    if (n2 == NULL)
3914 		continue;
3915 	    /*
3916 	    * Skip duplicates.
3917 	    */
3918 	    for (j = 0; j < initNbSet1; j++) {
3919 		n1 = set1->nodeTab[j];
3920 		if (n1 == n2) {
3921 		    goto skip_node;
3922 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3923 		    (n2->type == XML_NAMESPACE_DECL))
3924 		{
3925 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927 			((xmlNsPtr) n2)->prefix)))
3928 		    {
3929 			/*
3930 			* Free the namespace node.
3931 			*/
3932 			set2->nodeTab[i] = NULL;
3933 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3934 			goto skip_node;
3935 		    }
3936 		}
3937 	    }
3938 	    /*
3939 	    * grow the nodeTab if needed
3940 	    */
3941 	    if (set1->nodeMax == 0) {
3942 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944 		if (set1->nodeTab == NULL) {
3945 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3946 		    return(NULL);
3947 		}
3948 		memset(set1->nodeTab, 0,
3949 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950 		set1->nodeMax = XML_NODESET_DEFAULT;
3951 	    } else if (set1->nodeNr >= set1->nodeMax) {
3952 		xmlNodePtr *temp;
3953 
3954 		temp = (xmlNodePtr *) xmlRealloc(
3955 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3956 		if (temp == NULL) {
3957 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3958 		    return(NULL);
3959 		}
3960 		set1->nodeTab = temp;
3961 		set1->nodeMax *= 2;
3962 	    }
3963 	    if (n2->type == XML_NAMESPACE_DECL) {
3964 		xmlNsPtr ns = (xmlNsPtr) n2;
3965 
3966 		set1->nodeTab[set1->nodeNr++] =
3967 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3968 	    } else
3969 		set1->nodeTab[set1->nodeNr++] = n2;
3970 skip_node:
3971 	    {}
3972 	}
3973     }
3974     set2->nodeNr = 0;
3975     return(set1);
3976 }
3977 
3978 /**
3979  * xmlXPathNodeSetMergeAndClearNoDupls:
3980  * @set1:  the first NodeSet or NULL
3981  * @set2:  the second NodeSet
3982  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3983  *
3984  * Merges two nodesets, all nodes from @set2 are added to @set1
3985  * if @set1 is NULL, a new set is created and copied from @set2.
3986  * Doesn't chack for duplicate nodes. Clears set2.
3987  *
3988  * Returns @set1 once extended or NULL in case of error.
3989  */
3990 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3992 				    int hasNullEntries)
3993 {
3994     if (set2 == NULL)
3995 	return(set1);
3996     if ((set1 == NULL) && (hasNullEntries == 0)) {
3997 	/*
3998 	* Note that doing a memcpy of the list, namespace nodes are
3999 	* just assigned to set1, since set2 is cleared anyway.
4000 	*/
4001 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4002 	if (set1 == NULL)
4003 	    return(NULL);
4004 	if (set2->nodeNr != 0) {
4005 	    memcpy(set1->nodeTab, set2->nodeTab,
4006 		set2->nodeNr * sizeof(xmlNodePtr));
4007 	    set1->nodeNr = set2->nodeNr;
4008 	}
4009     } else {
4010 	int i;
4011 	xmlNodePtr n2;
4012 
4013 	if (set1 == NULL)
4014 	    set1 = xmlXPathNodeSetCreate(NULL);
4015         if (set1 == NULL)
4016             return (NULL);
4017 
4018 	for (i = 0;i < set2->nodeNr;i++) {
4019 	    n2 = set2->nodeTab[i];
4020 	    /*
4021 	    * Skip NULLed entries.
4022 	    */
4023 	    if (n2 == NULL)
4024 		continue;
4025 	    if (set1->nodeMax == 0) {
4026 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028 		if (set1->nodeTab == NULL) {
4029 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4030 		    return(NULL);
4031 		}
4032 		memset(set1->nodeTab, 0,
4033 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034 		set1->nodeMax = XML_NODESET_DEFAULT;
4035 	    } else if (set1->nodeNr >= set1->nodeMax) {
4036 		xmlNodePtr *temp;
4037 
4038 		temp = (xmlNodePtr *) xmlRealloc(
4039 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4040 		if (temp == NULL) {
4041 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4042 		    return(NULL);
4043 		}
4044 		set1->nodeTab = temp;
4045 		set1->nodeMax *= 2;
4046 	    }
4047 	    set1->nodeTab[set1->nodeNr++] = n2;
4048 	}
4049     }
4050     set2->nodeNr = 0;
4051     return(set1);
4052 }
4053 
4054 /**
4055  * xmlXPathNodeSetDel:
4056  * @cur:  the initial node set
4057  * @val:  an xmlNodePtr
4058  *
4059  * Removes an xmlNodePtr from an existing NodeSet
4060  */
4061 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4063     int i;
4064 
4065     if (cur == NULL) return;
4066     if (val == NULL) return;
4067 
4068     /*
4069      * find node in nodeTab
4070      */
4071     for (i = 0;i < cur->nodeNr;i++)
4072         if (cur->nodeTab[i] == val) break;
4073 
4074     if (i >= cur->nodeNr) {	/* not found */
4075 #ifdef DEBUG
4076         xmlGenericError(xmlGenericErrorContext,
4077 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4078 		val->name);
4079 #endif
4080         return;
4081     }
4082     if ((cur->nodeTab[i] != NULL) &&
4083 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4085     cur->nodeNr--;
4086     for (;i < cur->nodeNr;i++)
4087         cur->nodeTab[i] = cur->nodeTab[i + 1];
4088     cur->nodeTab[cur->nodeNr] = NULL;
4089 }
4090 
4091 /**
4092  * xmlXPathNodeSetRemove:
4093  * @cur:  the initial node set
4094  * @val:  the index to remove
4095  *
4096  * Removes an entry from an existing NodeSet list.
4097  */
4098 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100     if (cur == NULL) return;
4101     if (val >= cur->nodeNr) return;
4102     if ((cur->nodeTab[val] != NULL) &&
4103 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4105     cur->nodeNr--;
4106     for (;val < cur->nodeNr;val++)
4107         cur->nodeTab[val] = cur->nodeTab[val + 1];
4108     cur->nodeTab[cur->nodeNr] = NULL;
4109 }
4110 
4111 /**
4112  * xmlXPathFreeNodeSet:
4113  * @obj:  the xmlNodeSetPtr to free
4114  *
4115  * Free the NodeSet compound (not the actual nodes !).
4116  */
4117 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119     if (obj == NULL) return;
4120     if (obj->nodeTab != NULL) {
4121 	int i;
4122 
4123 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4124 	for (i = 0;i < obj->nodeNr;i++)
4125 	    if ((obj->nodeTab[i] != NULL) &&
4126 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4128 	xmlFree(obj->nodeTab);
4129     }
4130     xmlFree(obj);
4131 }
4132 
4133 /**
4134  * xmlXPathNodeSetClear:
4135  * @set:  the node set to clear
4136  *
4137  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138  * are feed), but does *not* free the list itself. Sets the length of the
4139  * list to 0.
4140  */
4141 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4143 {
4144     if ((set == NULL) || (set->nodeNr <= 0))
4145 	return;
4146     else if (hasNsNodes) {
4147 	int i;
4148 	xmlNodePtr node;
4149 
4150 	for (i = 0; i < set->nodeNr; i++) {
4151 	    node = set->nodeTab[i];
4152 	    if ((node != NULL) &&
4153 		(node->type == XML_NAMESPACE_DECL))
4154 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4155 	}
4156     }
4157     set->nodeNr = 0;
4158 }
4159 
4160 /**
4161  * xmlXPathNodeSetClearFromPos:
4162  * @set: the node set to be cleared
4163  * @pos: the start position to clear from
4164  *
4165  * Clears the list from temporary XPath objects (e.g. namespace nodes
4166  * are feed) starting with the entry at @pos, but does *not* free the list
4167  * itself. Sets the length of the list to @pos.
4168  */
4169 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4171 {
4172     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4173 	return;
4174     else if ((hasNsNodes)) {
4175 	int i;
4176 	xmlNodePtr node;
4177 
4178 	for (i = pos; i < set->nodeNr; i++) {
4179 	    node = set->nodeTab[i];
4180 	    if ((node != NULL) &&
4181 		(node->type == XML_NAMESPACE_DECL))
4182 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4183 	}
4184     }
4185     set->nodeNr = pos;
4186 }
4187 
4188 /**
4189  * xmlXPathFreeValueTree:
4190  * @obj:  the xmlNodeSetPtr to free
4191  *
4192  * Free the NodeSet compound and the actual tree, this is different
4193  * from xmlXPathFreeNodeSet()
4194  */
4195 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4197     int i;
4198 
4199     if (obj == NULL) return;
4200 
4201     if (obj->nodeTab != NULL) {
4202 	for (i = 0;i < obj->nodeNr;i++) {
4203 	    if (obj->nodeTab[i] != NULL) {
4204 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4206 		} else {
4207 		    xmlFreeNodeList(obj->nodeTab[i]);
4208 		}
4209 	    }
4210 	}
4211 	xmlFree(obj->nodeTab);
4212     }
4213     xmlFree(obj);
4214 }
4215 
4216 #if defined(DEBUG) || defined(DEBUG_STEP)
4217 /**
4218  * xmlGenericErrorContextNodeSet:
4219  * @output:  a FILE * for the output
4220  * @obj:  the xmlNodeSetPtr to display
4221  *
4222  * Quick display of a NodeSet
4223  */
4224 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4226     int i;
4227 
4228     if (output == NULL) output = xmlGenericErrorContext;
4229     if (obj == NULL)  {
4230         fprintf(output, "NodeSet == NULL !\n");
4231 	return;
4232     }
4233     if (obj->nodeNr == 0) {
4234         fprintf(output, "NodeSet is empty\n");
4235 	return;
4236     }
4237     if (obj->nodeTab == NULL) {
4238 	fprintf(output, " nodeTab == NULL !\n");
4239 	return;
4240     }
4241     for (i = 0; i < obj->nodeNr; i++) {
4242         if (obj->nodeTab[i] == NULL) {
4243 	    fprintf(output, " NULL !\n");
4244 	    return;
4245         }
4246 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248 	    fprintf(output, " /");
4249 	else if (obj->nodeTab[i]->name == NULL)
4250 	    fprintf(output, " noname!");
4251 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4252     }
4253     fprintf(output, "\n");
4254 }
4255 #endif
4256 
4257 /**
4258  * xmlXPathNewNodeSet:
4259  * @val:  the NodePtr value
4260  *
4261  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262  * it with the single Node @val
4263  *
4264  * Returns the newly created object.
4265  */
4266 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4267 xmlXPathNewNodeSet(xmlNodePtr val) {
4268     xmlXPathObjectPtr ret;
4269 
4270     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4271     if (ret == NULL) {
4272         xmlXPathErrMemory(NULL, "creating nodeset\n");
4273 	return(NULL);
4274     }
4275     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276     ret->type = XPATH_NODESET;
4277     ret->boolval = 0;
4278     ret->nodesetval = xmlXPathNodeSetCreate(val);
4279     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4280 #ifdef XP_DEBUG_OBJ_USAGE
4281     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4282 #endif
4283     return(ret);
4284 }
4285 
4286 /**
4287  * xmlXPathNewValueTree:
4288  * @val:  the NodePtr value
4289  *
4290  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291  * it with the tree root @val
4292  *
4293  * Returns the newly created object.
4294  */
4295 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4296 xmlXPathNewValueTree(xmlNodePtr val) {
4297     xmlXPathObjectPtr ret;
4298 
4299     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300     if (ret == NULL) {
4301         xmlXPathErrMemory(NULL, "creating result value tree\n");
4302 	return(NULL);
4303     }
4304     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305     ret->type = XPATH_XSLT_TREE;
4306     ret->boolval = 1;
4307     ret->user = (void *) val;
4308     ret->nodesetval = xmlXPathNodeSetCreate(val);
4309 #ifdef XP_DEBUG_OBJ_USAGE
4310     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4311 #endif
4312     return(ret);
4313 }
4314 
4315 /**
4316  * xmlXPathNewNodeSetList:
4317  * @val:  an existing NodeSet
4318  *
4319  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320  * it with the Nodeset @val
4321  *
4322  * Returns the newly created object.
4323  */
4324 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4326 {
4327     xmlXPathObjectPtr ret;
4328     int i;
4329 
4330     if (val == NULL)
4331         ret = NULL;
4332     else if (val->nodeTab == NULL)
4333         ret = xmlXPathNewNodeSet(NULL);
4334     else {
4335         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4336         if (ret)
4337             for (i = 1; i < val->nodeNr; ++i)
4338                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4339     }
4340 
4341     return (ret);
4342 }
4343 
4344 /**
4345  * xmlXPathWrapNodeSet:
4346  * @val:  the NodePtr value
4347  *
4348  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4349  *
4350  * Returns the newly created object.
4351  */
4352 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354     xmlXPathObjectPtr ret;
4355 
4356     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357     if (ret == NULL) {
4358         xmlXPathErrMemory(NULL, "creating node set object\n");
4359 	return(NULL);
4360     }
4361     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362     ret->type = XPATH_NODESET;
4363     ret->nodesetval = val;
4364 #ifdef XP_DEBUG_OBJ_USAGE
4365     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366 #endif
4367     return(ret);
4368 }
4369 
4370 /**
4371  * xmlXPathFreeNodeSetList:
4372  * @obj:  an existing NodeSetList object
4373  *
4374  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375  * the list contrary to xmlXPathFreeObject().
4376  */
4377 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379     if (obj == NULL) return;
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4382 #endif
4383     xmlFree(obj);
4384 }
4385 
4386 /**
4387  * xmlXPathDifference:
4388  * @nodes1:  a node-set
4389  * @nodes2:  a node-set
4390  *
4391  * Implements the EXSLT - Sets difference() function:
4392  *    node-set set:difference (node-set, node-set)
4393  *
4394  * Returns the difference between the two node sets, or nodes1 if
4395  *         nodes2 is empty
4396  */
4397 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4399     xmlNodeSetPtr ret;
4400     int i, l1;
4401     xmlNodePtr cur;
4402 
4403     if (xmlXPathNodeSetIsEmpty(nodes2))
4404 	return(nodes1);
4405 
4406     ret = xmlXPathNodeSetCreate(NULL);
4407     if (xmlXPathNodeSetIsEmpty(nodes1))
4408 	return(ret);
4409 
4410     l1 = xmlXPathNodeSetGetLength(nodes1);
4411 
4412     for (i = 0; i < l1; i++) {
4413 	cur = xmlXPathNodeSetItem(nodes1, i);
4414 	if (!xmlXPathNodeSetContains(nodes2, cur))
4415 	    xmlXPathNodeSetAddUnique(ret, cur);
4416     }
4417     return(ret);
4418 }
4419 
4420 /**
4421  * xmlXPathIntersection:
4422  * @nodes1:  a node-set
4423  * @nodes2:  a node-set
4424  *
4425  * Implements the EXSLT - Sets intersection() function:
4426  *    node-set set:intersection (node-set, node-set)
4427  *
4428  * Returns a node set comprising the nodes that are within both the
4429  *         node sets passed as arguments
4430  */
4431 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4434     int i, l1;
4435     xmlNodePtr cur;
4436 
4437     if (ret == NULL)
4438         return(ret);
4439     if (xmlXPathNodeSetIsEmpty(nodes1))
4440 	return(ret);
4441     if (xmlXPathNodeSetIsEmpty(nodes2))
4442 	return(ret);
4443 
4444     l1 = xmlXPathNodeSetGetLength(nodes1);
4445 
4446     for (i = 0; i < l1; i++) {
4447 	cur = xmlXPathNodeSetItem(nodes1, i);
4448 	if (xmlXPathNodeSetContains(nodes2, cur))
4449 	    xmlXPathNodeSetAddUnique(ret, cur);
4450     }
4451     return(ret);
4452 }
4453 
4454 /**
4455  * xmlXPathDistinctSorted:
4456  * @nodes:  a node-set, sorted by document order
4457  *
4458  * Implements the EXSLT - Sets distinct() function:
4459  *    node-set set:distinct (node-set)
4460  *
4461  * Returns a subset of the nodes contained in @nodes, or @nodes if
4462  *         it is empty
4463  */
4464 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4466     xmlNodeSetPtr ret;
4467     xmlHashTablePtr hash;
4468     int i, l;
4469     xmlChar * strval;
4470     xmlNodePtr cur;
4471 
4472     if (xmlXPathNodeSetIsEmpty(nodes))
4473 	return(nodes);
4474 
4475     ret = xmlXPathNodeSetCreate(NULL);
4476     if (ret == NULL)
4477         return(ret);
4478     l = xmlXPathNodeSetGetLength(nodes);
4479     hash = xmlHashCreate (l);
4480     for (i = 0; i < l; i++) {
4481 	cur = xmlXPathNodeSetItem(nodes, i);
4482 	strval = xmlXPathCastNodeToString(cur);
4483 	if (xmlHashLookup(hash, strval) == NULL) {
4484 	    xmlHashAddEntry(hash, strval, strval);
4485 	    xmlXPathNodeSetAddUnique(ret, cur);
4486 	} else {
4487 	    xmlFree(strval);
4488 	}
4489     }
4490     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4491     return(ret);
4492 }
4493 
4494 /**
4495  * xmlXPathDistinct:
4496  * @nodes:  a node-set
4497  *
4498  * Implements the EXSLT - Sets distinct() function:
4499  *    node-set set:distinct (node-set)
4500  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501  * is called with the sorted node-set
4502  *
4503  * Returns a subset of the nodes contained in @nodes, or @nodes if
4504  *         it is empty
4505  */
4506 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4507 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508     if (xmlXPathNodeSetIsEmpty(nodes))
4509 	return(nodes);
4510 
4511     xmlXPathNodeSetSort(nodes);
4512     return(xmlXPathDistinctSorted(nodes));
4513 }
4514 
4515 /**
4516  * xmlXPathHasSameNodes:
4517  * @nodes1:  a node-set
4518  * @nodes2:  a node-set
4519  *
4520  * Implements the EXSLT - Sets has-same-nodes function:
4521  *    boolean set:has-same-node(node-set, node-set)
4522  *
4523  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4524  *         otherwise
4525  */
4526 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4528     int i, l;
4529     xmlNodePtr cur;
4530 
4531     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532 	xmlXPathNodeSetIsEmpty(nodes2))
4533 	return(0);
4534 
4535     l = xmlXPathNodeSetGetLength(nodes1);
4536     for (i = 0; i < l; i++) {
4537 	cur = xmlXPathNodeSetItem(nodes1, i);
4538 	if (xmlXPathNodeSetContains(nodes2, cur))
4539 	    return(1);
4540     }
4541     return(0);
4542 }
4543 
4544 /**
4545  * xmlXPathNodeLeadingSorted:
4546  * @nodes: a node-set, sorted by document order
4547  * @node: a node
4548  *
4549  * Implements the EXSLT - Sets leading() function:
4550  *    node-set set:leading (node-set, node-set)
4551  *
4552  * Returns the nodes in @nodes that precede @node in document order,
4553  *         @nodes if @node is NULL or an empty node-set if @nodes
4554  *         doesn't contain @node
4555  */
4556 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4558     int i, l;
4559     xmlNodePtr cur;
4560     xmlNodeSetPtr ret;
4561 
4562     if (node == NULL)
4563 	return(nodes);
4564 
4565     ret = xmlXPathNodeSetCreate(NULL);
4566     if (ret == NULL)
4567         return(ret);
4568     if (xmlXPathNodeSetIsEmpty(nodes) ||
4569 	(!xmlXPathNodeSetContains(nodes, node)))
4570 	return(ret);
4571 
4572     l = xmlXPathNodeSetGetLength(nodes);
4573     for (i = 0; i < l; i++) {
4574 	cur = xmlXPathNodeSetItem(nodes, i);
4575 	if (cur == node)
4576 	    break;
4577 	xmlXPathNodeSetAddUnique(ret, cur);
4578     }
4579     return(ret);
4580 }
4581 
4582 /**
4583  * xmlXPathNodeLeading:
4584  * @nodes:  a node-set
4585  * @node:  a node
4586  *
4587  * Implements the EXSLT - Sets leading() function:
4588  *    node-set set:leading (node-set, node-set)
4589  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4590  * is called.
4591  *
4592  * Returns the nodes in @nodes that precede @node in document order,
4593  *         @nodes if @node is NULL or an empty node-set if @nodes
4594  *         doesn't contain @node
4595  */
4596 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598     xmlXPathNodeSetSort(nodes);
4599     return(xmlXPathNodeLeadingSorted(nodes, node));
4600 }
4601 
4602 /**
4603  * xmlXPathLeadingSorted:
4604  * @nodes1:  a node-set, sorted by document order
4605  * @nodes2:  a node-set, sorted by document order
4606  *
4607  * Implements the EXSLT - Sets leading() function:
4608  *    node-set set:leading (node-set, node-set)
4609  *
4610  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4612  *         an empty node-set if @nodes1 doesn't contain @nodes2
4613  */
4614 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616     if (xmlXPathNodeSetIsEmpty(nodes2))
4617 	return(nodes1);
4618     return(xmlXPathNodeLeadingSorted(nodes1,
4619 				     xmlXPathNodeSetItem(nodes2, 1)));
4620 }
4621 
4622 /**
4623  * xmlXPathLeading:
4624  * @nodes1:  a node-set
4625  * @nodes2:  a node-set
4626  *
4627  * Implements the EXSLT - Sets leading() function:
4628  *    node-set set:leading (node-set, node-set)
4629  * @nodes1 and @nodes2 are sorted by document order, then
4630  * #exslSetsLeadingSorted is called.
4631  *
4632  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4634  *         an empty node-set if @nodes1 doesn't contain @nodes2
4635  */
4636 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638     if (xmlXPathNodeSetIsEmpty(nodes2))
4639 	return(nodes1);
4640     if (xmlXPathNodeSetIsEmpty(nodes1))
4641 	return(xmlXPathNodeSetCreate(NULL));
4642     xmlXPathNodeSetSort(nodes1);
4643     xmlXPathNodeSetSort(nodes2);
4644     return(xmlXPathNodeLeadingSorted(nodes1,
4645 				     xmlXPathNodeSetItem(nodes2, 1)));
4646 }
4647 
4648 /**
4649  * xmlXPathNodeTrailingSorted:
4650  * @nodes: a node-set, sorted by document order
4651  * @node: a node
4652  *
4653  * Implements the EXSLT - Sets trailing() function:
4654  *    node-set set:trailing (node-set, node-set)
4655  *
4656  * Returns the nodes in @nodes that follow @node in document order,
4657  *         @nodes if @node is NULL or an empty node-set if @nodes
4658  *         doesn't contain @node
4659  */
4660 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4662     int i, l;
4663     xmlNodePtr cur;
4664     xmlNodeSetPtr ret;
4665 
4666     if (node == NULL)
4667 	return(nodes);
4668 
4669     ret = xmlXPathNodeSetCreate(NULL);
4670     if (ret == NULL)
4671         return(ret);
4672     if (xmlXPathNodeSetIsEmpty(nodes) ||
4673 	(!xmlXPathNodeSetContains(nodes, node)))
4674 	return(ret);
4675 
4676     l = xmlXPathNodeSetGetLength(nodes);
4677     for (i = l - 1; i >= 0; i--) {
4678 	cur = xmlXPathNodeSetItem(nodes, i);
4679 	if (cur == node)
4680 	    break;
4681 	xmlXPathNodeSetAddUnique(ret, cur);
4682     }
4683     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4684     return(ret);
4685 }
4686 
4687 /**
4688  * xmlXPathNodeTrailing:
4689  * @nodes:  a node-set
4690  * @node:  a node
4691  *
4692  * Implements the EXSLT - Sets trailing() function:
4693  *    node-set set:trailing (node-set, node-set)
4694  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4695  * is called.
4696  *
4697  * Returns the nodes in @nodes that follow @node in document order,
4698  *         @nodes if @node is NULL or an empty node-set if @nodes
4699  *         doesn't contain @node
4700  */
4701 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703     xmlXPathNodeSetSort(nodes);
4704     return(xmlXPathNodeTrailingSorted(nodes, node));
4705 }
4706 
4707 /**
4708  * xmlXPathTrailingSorted:
4709  * @nodes1:  a node-set, sorted by document order
4710  * @nodes2:  a node-set, sorted by document order
4711  *
4712  * Implements the EXSLT - Sets trailing() function:
4713  *    node-set set:trailing (node-set, node-set)
4714  *
4715  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4717  *         an empty node-set if @nodes1 doesn't contain @nodes2
4718  */
4719 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721     if (xmlXPathNodeSetIsEmpty(nodes2))
4722 	return(nodes1);
4723     return(xmlXPathNodeTrailingSorted(nodes1,
4724 				      xmlXPathNodeSetItem(nodes2, 0)));
4725 }
4726 
4727 /**
4728  * xmlXPathTrailing:
4729  * @nodes1:  a node-set
4730  * @nodes2:  a node-set
4731  *
4732  * Implements the EXSLT - Sets trailing() function:
4733  *    node-set set:trailing (node-set, node-set)
4734  * @nodes1 and @nodes2 are sorted by document order, then
4735  * #xmlXPathTrailingSorted is called.
4736  *
4737  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4739  *         an empty node-set if @nodes1 doesn't contain @nodes2
4740  */
4741 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743     if (xmlXPathNodeSetIsEmpty(nodes2))
4744 	return(nodes1);
4745     if (xmlXPathNodeSetIsEmpty(nodes1))
4746 	return(xmlXPathNodeSetCreate(NULL));
4747     xmlXPathNodeSetSort(nodes1);
4748     xmlXPathNodeSetSort(nodes2);
4749     return(xmlXPathNodeTrailingSorted(nodes1,
4750 				      xmlXPathNodeSetItem(nodes2, 0)));
4751 }
4752 
4753 /************************************************************************
4754  *									*
4755  *		Routines to handle extra functions			*
4756  *									*
4757  ************************************************************************/
4758 
4759 /**
4760  * xmlXPathRegisterFunc:
4761  * @ctxt:  the XPath context
4762  * @name:  the function name
4763  * @f:  the function implementation or NULL
4764  *
4765  * Register a new function. If @f is NULL it unregisters the function
4766  *
4767  * Returns 0 in case of success, -1 in case of error
4768  */
4769 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771 		     xmlXPathFunction f) {
4772     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4773 }
4774 
4775 /**
4776  * xmlXPathRegisterFuncNS:
4777  * @ctxt:  the XPath context
4778  * @name:  the function name
4779  * @ns_uri:  the function namespace URI
4780  * @f:  the function implementation or NULL
4781  *
4782  * Register a new function. If @f is NULL it unregisters the function
4783  *
4784  * Returns 0 in case of success, -1 in case of error
4785  */
4786 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4789     if (ctxt == NULL)
4790 	return(-1);
4791     if (name == NULL)
4792 	return(-1);
4793 
4794     if (ctxt->funcHash == NULL)
4795 	ctxt->funcHash = xmlHashCreate(0);
4796     if (ctxt->funcHash == NULL)
4797 	return(-1);
4798     if (f == NULL)
4799         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4800     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4801 }
4802 
4803 /**
4804  * xmlXPathRegisterFuncLookup:
4805  * @ctxt:  the XPath context
4806  * @f:  the lookup function
4807  * @funcCtxt:  the lookup data
4808  *
4809  * Registers an external mechanism to do function lookup.
4810  */
4811 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813 			    xmlXPathFuncLookupFunc f,
4814 			    void *funcCtxt) {
4815     if (ctxt == NULL)
4816 	return;
4817     ctxt->funcLookupFunc = f;
4818     ctxt->funcLookupData = funcCtxt;
4819 }
4820 
4821 /**
4822  * xmlXPathFunctionLookup:
4823  * @ctxt:  the XPath context
4824  * @name:  the function name
4825  *
4826  * Search in the Function array of the context for the given
4827  * function.
4828  *
4829  * Returns the xmlXPathFunction or NULL if not found
4830  */
4831 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4833     if (ctxt == NULL)
4834 	return (NULL);
4835 
4836     if (ctxt->funcLookupFunc != NULL) {
4837 	xmlXPathFunction ret;
4838 	xmlXPathFuncLookupFunc f;
4839 
4840 	f = ctxt->funcLookupFunc;
4841 	ret = f(ctxt->funcLookupData, name, NULL);
4842 	if (ret != NULL)
4843 	    return(ret);
4844     }
4845     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4846 }
4847 
4848 /**
4849  * xmlXPathFunctionLookupNS:
4850  * @ctxt:  the XPath context
4851  * @name:  the function name
4852  * @ns_uri:  the function namespace URI
4853  *
4854  * Search in the Function array of the context for the given
4855  * function.
4856  *
4857  * Returns the xmlXPathFunction or NULL if not found
4858  */
4859 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 			 const xmlChar *ns_uri) {
4862     xmlXPathFunction ret;
4863 
4864     if (ctxt == NULL)
4865 	return(NULL);
4866     if (name == NULL)
4867 	return(NULL);
4868 
4869     if (ctxt->funcLookupFunc != NULL) {
4870 	xmlXPathFuncLookupFunc f;
4871 
4872 	f = ctxt->funcLookupFunc;
4873 	ret = f(ctxt->funcLookupData, name, ns_uri);
4874 	if (ret != NULL)
4875 	    return(ret);
4876     }
4877 
4878     if (ctxt->funcHash == NULL)
4879 	return(NULL);
4880 
4881     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4882     return(ret);
4883 }
4884 
4885 /**
4886  * xmlXPathRegisteredFuncsCleanup:
4887  * @ctxt:  the XPath context
4888  *
4889  * Cleanup the XPath context data associated to registered functions
4890  */
4891 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4893     if (ctxt == NULL)
4894 	return;
4895 
4896     xmlHashFree(ctxt->funcHash, NULL);
4897     ctxt->funcHash = NULL;
4898 }
4899 
4900 /************************************************************************
4901  *									*
4902  *			Routines to handle Variables			*
4903  *									*
4904  ************************************************************************/
4905 
4906 /**
4907  * xmlXPathRegisterVariable:
4908  * @ctxt:  the XPath context
4909  * @name:  the variable name
4910  * @value:  the variable value or NULL
4911  *
4912  * Register a new variable value. If @value is NULL it unregisters
4913  * the variable
4914  *
4915  * Returns 0 in case of success, -1 in case of error
4916  */
4917 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919 			 xmlXPathObjectPtr value) {
4920     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4921 }
4922 
4923 /**
4924  * xmlXPathRegisterVariableNS:
4925  * @ctxt:  the XPath context
4926  * @name:  the variable name
4927  * @ns_uri:  the variable namespace URI
4928  * @value:  the variable value or NULL
4929  *
4930  * Register a new variable value. If @value is NULL it unregisters
4931  * the variable
4932  *
4933  * Returns 0 in case of success, -1 in case of error
4934  */
4935 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937 			   const xmlChar *ns_uri,
4938 			   xmlXPathObjectPtr value) {
4939     if (ctxt == NULL)
4940 	return(-1);
4941     if (name == NULL)
4942 	return(-1);
4943 
4944     if (ctxt->varHash == NULL)
4945 	ctxt->varHash = xmlHashCreate(0);
4946     if (ctxt->varHash == NULL)
4947 	return(-1);
4948     if (value == NULL)
4949         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4950 	                           (xmlHashDeallocator)xmlXPathFreeObject));
4951     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4952 			       (void *) value,
4953 			       (xmlHashDeallocator)xmlXPathFreeObject));
4954 }
4955 
4956 /**
4957  * xmlXPathRegisterVariableLookup:
4958  * @ctxt:  the XPath context
4959  * @f:  the lookup function
4960  * @data:  the lookup data
4961  *
4962  * register an external mechanism to do variable lookup
4963  */
4964 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966 	 xmlXPathVariableLookupFunc f, void *data) {
4967     if (ctxt == NULL)
4968 	return;
4969     ctxt->varLookupFunc = f;
4970     ctxt->varLookupData = data;
4971 }
4972 
4973 /**
4974  * xmlXPathVariableLookup:
4975  * @ctxt:  the XPath context
4976  * @name:  the variable name
4977  *
4978  * Search in the Variable array of the context for the given
4979  * variable value.
4980  *
4981  * Returns a copy of the value or NULL if not found
4982  */
4983 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4985     if (ctxt == NULL)
4986 	return(NULL);
4987 
4988     if (ctxt->varLookupFunc != NULL) {
4989 	xmlXPathObjectPtr ret;
4990 
4991 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992 	        (ctxt->varLookupData, name, NULL);
4993 	return(ret);
4994     }
4995     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4996 }
4997 
4998 /**
4999  * xmlXPathVariableLookupNS:
5000  * @ctxt:  the XPath context
5001  * @name:  the variable name
5002  * @ns_uri:  the variable namespace URI
5003  *
5004  * Search in the Variable array of the context for the given
5005  * variable value.
5006  *
5007  * Returns the a copy of the value or NULL if not found
5008  */
5009 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011 			 const xmlChar *ns_uri) {
5012     if (ctxt == NULL)
5013 	return(NULL);
5014 
5015     if (ctxt->varLookupFunc != NULL) {
5016 	xmlXPathObjectPtr ret;
5017 
5018 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019 	        (ctxt->varLookupData, name, ns_uri);
5020 	if (ret != NULL) return(ret);
5021     }
5022 
5023     if (ctxt->varHash == NULL)
5024 	return(NULL);
5025     if (name == NULL)
5026 	return(NULL);
5027 
5028     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5029 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5030 }
5031 
5032 /**
5033  * xmlXPathRegisteredVariablesCleanup:
5034  * @ctxt:  the XPath context
5035  *
5036  * Cleanup the XPath context data associated to registered variables
5037  */
5038 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5040     if (ctxt == NULL)
5041 	return;
5042 
5043     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5044     ctxt->varHash = NULL;
5045 }
5046 
5047 /**
5048  * xmlXPathRegisterNs:
5049  * @ctxt:  the XPath context
5050  * @prefix:  the namespace prefix cannot be NULL or empty string
5051  * @ns_uri:  the namespace name
5052  *
5053  * Register a new namespace. If @ns_uri is NULL it unregisters
5054  * the namespace
5055  *
5056  * Returns 0 in case of success, -1 in case of error
5057  */
5058 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060 			   const xmlChar *ns_uri) {
5061     if (ctxt == NULL)
5062 	return(-1);
5063     if (prefix == NULL)
5064 	return(-1);
5065     if (prefix[0] == 0)
5066 	return(-1);
5067 
5068     if (ctxt->nsHash == NULL)
5069 	ctxt->nsHash = xmlHashCreate(10);
5070     if (ctxt->nsHash == NULL)
5071 	return(-1);
5072     if (ns_uri == NULL)
5073         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5074 	                          (xmlHashDeallocator)xmlFree));
5075     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5076 			      (xmlHashDeallocator)xmlFree));
5077 }
5078 
5079 /**
5080  * xmlXPathNsLookup:
5081  * @ctxt:  the XPath context
5082  * @prefix:  the namespace prefix value
5083  *
5084  * Search in the namespace declaration array of the context for the given
5085  * namespace name associated to the given prefix
5086  *
5087  * Returns the value or NULL if not found
5088  */
5089 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5090 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5091     if (ctxt == NULL)
5092 	return(NULL);
5093     if (prefix == NULL)
5094 	return(NULL);
5095 
5096 #ifdef XML_XML_NAMESPACE
5097     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098 	return(XML_XML_NAMESPACE);
5099 #endif
5100 
5101     if (ctxt->namespaces != NULL) {
5102 	int i;
5103 
5104 	for (i = 0;i < ctxt->nsNr;i++) {
5105 	    if ((ctxt->namespaces[i] != NULL) &&
5106 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107 		return(ctxt->namespaces[i]->href);
5108 	}
5109     }
5110 
5111     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5112 }
5113 
5114 /**
5115  * xmlXPathRegisteredNsCleanup:
5116  * @ctxt:  the XPath context
5117  *
5118  * Cleanup the XPath context data associated to registered variables
5119  */
5120 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5121 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5122     if (ctxt == NULL)
5123 	return;
5124 
5125     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5126     ctxt->nsHash = NULL;
5127 }
5128 
5129 /************************************************************************
5130  *									*
5131  *			Routines to handle Values			*
5132  *									*
5133  ************************************************************************/
5134 
5135 /* Allocations are terrible, one needs to optimize all this !!! */
5136 
5137 /**
5138  * xmlXPathNewFloat:
5139  * @val:  the double value
5140  *
5141  * Create a new xmlXPathObjectPtr of type double and of value @val
5142  *
5143  * Returns the newly created object.
5144  */
5145 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5146 xmlXPathNewFloat(double val) {
5147     xmlXPathObjectPtr ret;
5148 
5149     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5150     if (ret == NULL) {
5151         xmlXPathErrMemory(NULL, "creating float object\n");
5152 	return(NULL);
5153     }
5154     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155     ret->type = XPATH_NUMBER;
5156     ret->floatval = val;
5157 #ifdef XP_DEBUG_OBJ_USAGE
5158     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5159 #endif
5160     return(ret);
5161 }
5162 
5163 /**
5164  * xmlXPathNewBoolean:
5165  * @val:  the boolean value
5166  *
5167  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5168  *
5169  * Returns the newly created object.
5170  */
5171 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5172 xmlXPathNewBoolean(int val) {
5173     xmlXPathObjectPtr ret;
5174 
5175     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5176     if (ret == NULL) {
5177         xmlXPathErrMemory(NULL, "creating boolean object\n");
5178 	return(NULL);
5179     }
5180     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181     ret->type = XPATH_BOOLEAN;
5182     ret->boolval = (val != 0);
5183 #ifdef XP_DEBUG_OBJ_USAGE
5184     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5185 #endif
5186     return(ret);
5187 }
5188 
5189 /**
5190  * xmlXPathNewString:
5191  * @val:  the xmlChar * value
5192  *
5193  * Create a new xmlXPathObjectPtr of type string and of value @val
5194  *
5195  * Returns the newly created object.
5196  */
5197 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5198 xmlXPathNewString(const xmlChar *val) {
5199     xmlXPathObjectPtr ret;
5200 
5201     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5202     if (ret == NULL) {
5203         xmlXPathErrMemory(NULL, "creating string object\n");
5204 	return(NULL);
5205     }
5206     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207     ret->type = XPATH_STRING;
5208     if (val != NULL)
5209 	ret->stringval = xmlStrdup(val);
5210     else
5211 	ret->stringval = xmlStrdup((const xmlChar *)"");
5212 #ifdef XP_DEBUG_OBJ_USAGE
5213     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5214 #endif
5215     return(ret);
5216 }
5217 
5218 /**
5219  * xmlXPathWrapString:
5220  * @val:  the xmlChar * value
5221  *
5222  * Wraps the @val string into an XPath object.
5223  *
5224  * Returns the newly created object.
5225  */
5226 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5227 xmlXPathWrapString (xmlChar *val) {
5228     xmlXPathObjectPtr ret;
5229 
5230     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231     if (ret == NULL) {
5232         xmlXPathErrMemory(NULL, "creating string object\n");
5233 	return(NULL);
5234     }
5235     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236     ret->type = XPATH_STRING;
5237     ret->stringval = val;
5238 #ifdef XP_DEBUG_OBJ_USAGE
5239     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5240 #endif
5241     return(ret);
5242 }
5243 
5244 /**
5245  * xmlXPathNewCString:
5246  * @val:  the char * value
5247  *
5248  * Create a new xmlXPathObjectPtr of type string and of value @val
5249  *
5250  * Returns the newly created object.
5251  */
5252 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5253 xmlXPathNewCString(const char *val) {
5254     xmlXPathObjectPtr ret;
5255 
5256     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5257     if (ret == NULL) {
5258         xmlXPathErrMemory(NULL, "creating string object\n");
5259 	return(NULL);
5260     }
5261     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262     ret->type = XPATH_STRING;
5263     ret->stringval = xmlStrdup(BAD_CAST val);
5264 #ifdef XP_DEBUG_OBJ_USAGE
5265     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5266 #endif
5267     return(ret);
5268 }
5269 
5270 /**
5271  * xmlXPathWrapCString:
5272  * @val:  the char * value
5273  *
5274  * Wraps a string into an XPath object.
5275  *
5276  * Returns the newly created object.
5277  */
5278 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5279 xmlXPathWrapCString (char * val) {
5280     return(xmlXPathWrapString((xmlChar *)(val)));
5281 }
5282 
5283 /**
5284  * xmlXPathWrapExternal:
5285  * @val:  the user data
5286  *
5287  * Wraps the @val data into an XPath object.
5288  *
5289  * Returns the newly created object.
5290  */
5291 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5292 xmlXPathWrapExternal (void *val) {
5293     xmlXPathObjectPtr ret;
5294 
5295     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5296     if (ret == NULL) {
5297         xmlXPathErrMemory(NULL, "creating user object\n");
5298 	return(NULL);
5299     }
5300     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301     ret->type = XPATH_USERS;
5302     ret->user = val;
5303 #ifdef XP_DEBUG_OBJ_USAGE
5304     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5305 #endif
5306     return(ret);
5307 }
5308 
5309 /**
5310  * xmlXPathObjectCopy:
5311  * @val:  the original object
5312  *
5313  * allocate a new copy of a given object
5314  *
5315  * Returns the newly created object.
5316  */
5317 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5318 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319     xmlXPathObjectPtr ret;
5320 
5321     if (val == NULL)
5322 	return(NULL);
5323 
5324     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5325     if (ret == NULL) {
5326         xmlXPathErrMemory(NULL, "copying object\n");
5327 	return(NULL);
5328     }
5329     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5330 #ifdef XP_DEBUG_OBJ_USAGE
5331     xmlXPathDebugObjUsageRequested(NULL, val->type);
5332 #endif
5333     switch (val->type) {
5334 	case XPATH_BOOLEAN:
5335 	case XPATH_NUMBER:
5336 	case XPATH_POINT:
5337 	case XPATH_RANGE:
5338 	    break;
5339 	case XPATH_STRING:
5340 	    ret->stringval = xmlStrdup(val->stringval);
5341 	    break;
5342 	case XPATH_XSLT_TREE:
5343 #if 0
5344 /*
5345   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346   this previous handling is no longer correct, and can cause some serious
5347   problems (ref. bug 145547)
5348 */
5349 	    if ((val->nodesetval != NULL) &&
5350 		(val->nodesetval->nodeTab != NULL)) {
5351 		xmlNodePtr cur, tmp;
5352 		xmlDocPtr top;
5353 
5354 		ret->boolval = 1;
5355 		top =  xmlNewDoc(NULL);
5356 		top->name = (char *)
5357 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5358 		ret->user = top;
5359 		if (top != NULL) {
5360 		    top->doc = top;
5361 		    cur = val->nodesetval->nodeTab[0]->children;
5362 		    while (cur != NULL) {
5363 			tmp = xmlDocCopyNode(cur, top, 1);
5364 			xmlAddChild((xmlNodePtr) top, tmp);
5365 			cur = cur->next;
5366 		    }
5367 		}
5368 
5369 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5370 	    } else
5371 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5372 	    /* Deallocate the copied tree value */
5373 	    break;
5374 #endif
5375 	case XPATH_NODESET:
5376 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5377 	    /* Do not deallocate the copied tree value */
5378 	    ret->boolval = 0;
5379 	    break;
5380 	case XPATH_LOCATIONSET:
5381 #ifdef LIBXML_XPTR_ENABLED
5382 	{
5383 	    xmlLocationSetPtr loc = val->user;
5384 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5385 	    break;
5386 	}
5387 #endif
5388         case XPATH_USERS:
5389 	    ret->user = val->user;
5390 	    break;
5391         case XPATH_UNDEFINED:
5392 	    xmlGenericError(xmlGenericErrorContext,
5393 		    "xmlXPathObjectCopy: unsupported type %d\n",
5394 		    val->type);
5395 	    break;
5396     }
5397     return(ret);
5398 }
5399 
5400 /**
5401  * xmlXPathFreeObject:
5402  * @obj:  the object to free
5403  *
5404  * Free up an xmlXPathObjectPtr object.
5405  */
5406 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5407 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408     if (obj == NULL) return;
5409     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5410 	if (obj->boolval) {
5411 #if 0
5412 	    if (obj->user != NULL) {
5413                 xmlXPathFreeNodeSet(obj->nodesetval);
5414 		xmlFreeNodeList((xmlNodePtr) obj->user);
5415 	    } else
5416 #endif
5417 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5418 	    if (obj->nodesetval != NULL)
5419 		xmlXPathFreeValueTree(obj->nodesetval);
5420 	} else {
5421 	    if (obj->nodesetval != NULL)
5422 		xmlXPathFreeNodeSet(obj->nodesetval);
5423 	}
5424 #ifdef LIBXML_XPTR_ENABLED
5425     } else if (obj->type == XPATH_LOCATIONSET) {
5426 	if (obj->user != NULL)
5427 	    xmlXPtrFreeLocationSet(obj->user);
5428 #endif
5429     } else if (obj->type == XPATH_STRING) {
5430 	if (obj->stringval != NULL)
5431 	    xmlFree(obj->stringval);
5432     }
5433 #ifdef XP_DEBUG_OBJ_USAGE
5434     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5435 #endif
5436     xmlFree(obj);
5437 }
5438 
5439 /**
5440  * xmlXPathReleaseObject:
5441  * @obj:  the xmlXPathObjectPtr to free or to cache
5442  *
5443  * Depending on the state of the cache this frees the given
5444  * XPath object or stores it in the cache.
5445  */
5446 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5447 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5448 {
5449 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5452 
5453 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5454 
5455     if (obj == NULL)
5456 	return;
5457     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5458 	 xmlXPathFreeObject(obj);
5459     } else {
5460 	xmlXPathContextCachePtr cache =
5461 	    (xmlXPathContextCachePtr) ctxt->cache;
5462 
5463 	switch (obj->type) {
5464 	    case XPATH_NODESET:
5465 	    case XPATH_XSLT_TREE:
5466 		if (obj->nodesetval != NULL) {
5467 		    if (obj->boolval) {
5468 			/*
5469 			* It looks like the @boolval is used for
5470 			* evaluation if this an XSLT Result Tree Fragment.
5471 			* TODO: Check if this assumption is correct.
5472 			*/
5473 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474 			xmlXPathFreeValueTree(obj->nodesetval);
5475 			obj->nodesetval = NULL;
5476 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5477 			(XP_CACHE_WANTS(cache->nodesetObjs,
5478 					cache->maxNodeset)))
5479 		    {
5480 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5481 			goto obj_cached;
5482 		    } else {
5483 			xmlXPathFreeNodeSet(obj->nodesetval);
5484 			obj->nodesetval = NULL;
5485 		    }
5486 		}
5487 		break;
5488 	    case XPATH_STRING:
5489 		if (obj->stringval != NULL)
5490 		    xmlFree(obj->stringval);
5491 
5492 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493 		    XP_CACHE_ADD(cache->stringObjs, obj);
5494 		    goto obj_cached;
5495 		}
5496 		break;
5497 	    case XPATH_BOOLEAN:
5498 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5500 		    goto obj_cached;
5501 		}
5502 		break;
5503 	    case XPATH_NUMBER:
5504 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505 		    XP_CACHE_ADD(cache->numberObjs, obj);
5506 		    goto obj_cached;
5507 		}
5508 		break;
5509 #ifdef LIBXML_XPTR_ENABLED
5510 	    case XPATH_LOCATIONSET:
5511 		if (obj->user != NULL) {
5512 		    xmlXPtrFreeLocationSet(obj->user);
5513 		}
5514 		goto free_obj;
5515 #endif
5516 	    default:
5517 		goto free_obj;
5518 	}
5519 
5520 	/*
5521 	* Fallback to adding to the misc-objects slot.
5522 	*/
5523 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524 	    XP_CACHE_ADD(cache->miscObjs, obj);
5525 	} else
5526 	    goto free_obj;
5527 
5528 obj_cached:
5529 
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5532 #endif
5533 
5534 	if (obj->nodesetval != NULL) {
5535 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5536 
5537 	    /*
5538 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5539 	    *  the list and free the ns-nodes.
5540 	    * URGENT TODO: Check if it's actually slowing things down.
5541 	    *  Maybe we shouldn't try to preserve the list.
5542 	    */
5543 	    if (tmpset->nodeNr > 1) {
5544 		int i;
5545 		xmlNodePtr node;
5546 
5547 		for (i = 0; i < tmpset->nodeNr; i++) {
5548 		    node = tmpset->nodeTab[i];
5549 		    if ((node != NULL) &&
5550 			(node->type == XML_NAMESPACE_DECL))
5551 		    {
5552 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5553 		    }
5554 		}
5555 	    } else if (tmpset->nodeNr == 1) {
5556 		if ((tmpset->nodeTab[0] != NULL) &&
5557 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5559 	    }
5560 	    tmpset->nodeNr = 0;
5561 	    memset(obj, 0, sizeof(xmlXPathObject));
5562 	    obj->nodesetval = tmpset;
5563 	} else
5564 	    memset(obj, 0, sizeof(xmlXPathObject));
5565 
5566 	return;
5567 
5568 free_obj:
5569 	/*
5570 	* Cache is full; free the object.
5571 	*/
5572 	if (obj->nodesetval != NULL)
5573 	    xmlXPathFreeNodeSet(obj->nodesetval);
5574 #ifdef XP_DEBUG_OBJ_USAGE
5575 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5576 #endif
5577 	xmlFree(obj);
5578     }
5579     return;
5580 }
5581 
5582 
5583 /************************************************************************
5584  *									*
5585  *			Type Casting Routines				*
5586  *									*
5587  ************************************************************************/
5588 
5589 /**
5590  * xmlXPathCastBooleanToString:
5591  * @val:  a boolean
5592  *
5593  * Converts a boolean to its string value.
5594  *
5595  * Returns a newly allocated string.
5596  */
5597 xmlChar *
xmlXPathCastBooleanToString(int val)5598 xmlXPathCastBooleanToString (int val) {
5599     xmlChar *ret;
5600     if (val)
5601 	ret = xmlStrdup((const xmlChar *) "true");
5602     else
5603 	ret = xmlStrdup((const xmlChar *) "false");
5604     return(ret);
5605 }
5606 
5607 /**
5608  * xmlXPathCastNumberToString:
5609  * @val:  a number
5610  *
5611  * Converts a number to its string value.
5612  *
5613  * Returns a newly allocated string.
5614  */
5615 xmlChar *
xmlXPathCastNumberToString(double val)5616 xmlXPathCastNumberToString (double val) {
5617     xmlChar *ret;
5618     switch (xmlXPathIsInf(val)) {
5619     case 1:
5620 	ret = xmlStrdup((const xmlChar *) "Infinity");
5621 	break;
5622     case -1:
5623 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5624 	break;
5625     default:
5626 	if (xmlXPathIsNaN(val)) {
5627 	    ret = xmlStrdup((const xmlChar *) "NaN");
5628 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629 	    ret = xmlStrdup((const xmlChar *) "0");
5630 	} else {
5631 	    /* could be improved */
5632 	    char buf[100];
5633 	    xmlXPathFormatNumber(val, buf, 99);
5634 	    buf[99] = 0;
5635 	    ret = xmlStrdup((const xmlChar *) buf);
5636 	}
5637     }
5638     return(ret);
5639 }
5640 
5641 /**
5642  * xmlXPathCastNodeToString:
5643  * @node:  a node
5644  *
5645  * Converts a node to its string value.
5646  *
5647  * Returns a newly allocated string.
5648  */
5649 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5650 xmlXPathCastNodeToString (xmlNodePtr node) {
5651 xmlChar *ret;
5652     if ((ret = xmlNodeGetContent(node)) == NULL)
5653 	ret = xmlStrdup((const xmlChar *) "");
5654     return(ret);
5655 }
5656 
5657 /**
5658  * xmlXPathCastNodeSetToString:
5659  * @ns:  a node-set
5660  *
5661  * Converts a node-set to its string value.
5662  *
5663  * Returns a newly allocated string.
5664  */
5665 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5666 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668 	return(xmlStrdup((const xmlChar *) ""));
5669 
5670     if (ns->nodeNr > 1)
5671 	xmlXPathNodeSetSort(ns);
5672     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5673 }
5674 
5675 /**
5676  * xmlXPathCastToString:
5677  * @val:  an XPath object
5678  *
5679  * Converts an existing object to its string() equivalent
5680  *
5681  * Returns the allocated string value of the object, NULL in case of error.
5682  *         It's up to the caller to free the string memory with xmlFree().
5683  */
5684 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5685 xmlXPathCastToString(xmlXPathObjectPtr val) {
5686     xmlChar *ret = NULL;
5687 
5688     if (val == NULL)
5689 	return(xmlStrdup((const xmlChar *) ""));
5690     switch (val->type) {
5691 	case XPATH_UNDEFINED:
5692 #ifdef DEBUG_EXPR
5693 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5694 #endif
5695 	    ret = xmlStrdup((const xmlChar *) "");
5696 	    break;
5697         case XPATH_NODESET:
5698         case XPATH_XSLT_TREE:
5699 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5700 	    break;
5701 	case XPATH_STRING:
5702 	    return(xmlStrdup(val->stringval));
5703         case XPATH_BOOLEAN:
5704 	    ret = xmlXPathCastBooleanToString(val->boolval);
5705 	    break;
5706 	case XPATH_NUMBER: {
5707 	    ret = xmlXPathCastNumberToString(val->floatval);
5708 	    break;
5709 	}
5710 	case XPATH_USERS:
5711 	case XPATH_POINT:
5712 	case XPATH_RANGE:
5713 	case XPATH_LOCATIONSET:
5714 	    TODO
5715 	    ret = xmlStrdup((const xmlChar *) "");
5716 	    break;
5717     }
5718     return(ret);
5719 }
5720 
5721 /**
5722  * xmlXPathConvertString:
5723  * @val:  an XPath object
5724  *
5725  * Converts an existing object to its string() equivalent
5726  *
5727  * Returns the new object, the old one is freed (or the operation
5728  *         is done directly on @val)
5729  */
5730 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5731 xmlXPathConvertString(xmlXPathObjectPtr val) {
5732     xmlChar *res = NULL;
5733 
5734     if (val == NULL)
5735 	return(xmlXPathNewCString(""));
5736 
5737     switch (val->type) {
5738     case XPATH_UNDEFINED:
5739 #ifdef DEBUG_EXPR
5740 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5741 #endif
5742 	break;
5743     case XPATH_NODESET:
5744     case XPATH_XSLT_TREE:
5745 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5746 	break;
5747     case XPATH_STRING:
5748 	return(val);
5749     case XPATH_BOOLEAN:
5750 	res = xmlXPathCastBooleanToString(val->boolval);
5751 	break;
5752     case XPATH_NUMBER:
5753 	res = xmlXPathCastNumberToString(val->floatval);
5754 	break;
5755     case XPATH_USERS:
5756     case XPATH_POINT:
5757     case XPATH_RANGE:
5758     case XPATH_LOCATIONSET:
5759 	TODO;
5760 	break;
5761     }
5762     xmlXPathFreeObject(val);
5763     if (res == NULL)
5764 	return(xmlXPathNewCString(""));
5765     return(xmlXPathWrapString(res));
5766 }
5767 
5768 /**
5769  * xmlXPathCastBooleanToNumber:
5770  * @val:  a boolean
5771  *
5772  * Converts a boolean to its number value
5773  *
5774  * Returns the number value
5775  */
5776 double
xmlXPathCastBooleanToNumber(int val)5777 xmlXPathCastBooleanToNumber(int val) {
5778     if (val)
5779 	return(1.0);
5780     return(0.0);
5781 }
5782 
5783 /**
5784  * xmlXPathCastStringToNumber:
5785  * @val:  a string
5786  *
5787  * Converts a string to its number value
5788  *
5789  * Returns the number value
5790  */
5791 double
xmlXPathCastStringToNumber(const xmlChar * val)5792 xmlXPathCastStringToNumber(const xmlChar * val) {
5793     return(xmlXPathStringEvalNumber(val));
5794 }
5795 
5796 /**
5797  * xmlXPathCastNodeToNumber:
5798  * @node:  a node
5799  *
5800  * Converts a node to its number value
5801  *
5802  * Returns the number value
5803  */
5804 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5805 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5806     xmlChar *strval;
5807     double ret;
5808 
5809     if (node == NULL)
5810 	return(xmlXPathNAN);
5811     strval = xmlXPathCastNodeToString(node);
5812     if (strval == NULL)
5813 	return(xmlXPathNAN);
5814     ret = xmlXPathCastStringToNumber(strval);
5815     xmlFree(strval);
5816 
5817     return(ret);
5818 }
5819 
5820 /**
5821  * xmlXPathCastNodeSetToNumber:
5822  * @ns:  a node-set
5823  *
5824  * Converts a node-set to its number value
5825  *
5826  * Returns the number value
5827  */
5828 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5829 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5830     xmlChar *str;
5831     double ret;
5832 
5833     if (ns == NULL)
5834 	return(xmlXPathNAN);
5835     str = xmlXPathCastNodeSetToString(ns);
5836     ret = xmlXPathCastStringToNumber(str);
5837     xmlFree(str);
5838     return(ret);
5839 }
5840 
5841 /**
5842  * xmlXPathCastToNumber:
5843  * @val:  an XPath object
5844  *
5845  * Converts an XPath object to its number value
5846  *
5847  * Returns the number value
5848  */
5849 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5850 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5851     double ret = 0.0;
5852 
5853     if (val == NULL)
5854 	return(xmlXPathNAN);
5855     switch (val->type) {
5856     case XPATH_UNDEFINED:
5857 #ifdef DEGUB_EXPR
5858 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5859 #endif
5860 	ret = xmlXPathNAN;
5861 	break;
5862     case XPATH_NODESET:
5863     case XPATH_XSLT_TREE:
5864 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5865 	break;
5866     case XPATH_STRING:
5867 	ret = xmlXPathCastStringToNumber(val->stringval);
5868 	break;
5869     case XPATH_NUMBER:
5870 	ret = val->floatval;
5871 	break;
5872     case XPATH_BOOLEAN:
5873 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5874 	break;
5875     case XPATH_USERS:
5876     case XPATH_POINT:
5877     case XPATH_RANGE:
5878     case XPATH_LOCATIONSET:
5879 	TODO;
5880 	ret = xmlXPathNAN;
5881 	break;
5882     }
5883     return(ret);
5884 }
5885 
5886 /**
5887  * xmlXPathConvertNumber:
5888  * @val:  an XPath object
5889  *
5890  * Converts an existing object to its number() equivalent
5891  *
5892  * Returns the new object, the old one is freed (or the operation
5893  *         is done directly on @val)
5894  */
5895 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5896 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897     xmlXPathObjectPtr ret;
5898 
5899     if (val == NULL)
5900 	return(xmlXPathNewFloat(0.0));
5901     if (val->type == XPATH_NUMBER)
5902 	return(val);
5903     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904     xmlXPathFreeObject(val);
5905     return(ret);
5906 }
5907 
5908 /**
5909  * xmlXPathCastNumberToBoolean:
5910  * @val:  a number
5911  *
5912  * Converts a number to its boolean value
5913  *
5914  * Returns the boolean value
5915  */
5916 int
xmlXPathCastNumberToBoolean(double val)5917 xmlXPathCastNumberToBoolean (double val) {
5918      if (xmlXPathIsNaN(val) || (val == 0.0))
5919 	 return(0);
5920      return(1);
5921 }
5922 
5923 /**
5924  * xmlXPathCastStringToBoolean:
5925  * @val:  a string
5926  *
5927  * Converts a string to its boolean value
5928  *
5929  * Returns the boolean value
5930  */
5931 int
xmlXPathCastStringToBoolean(const xmlChar * val)5932 xmlXPathCastStringToBoolean (const xmlChar *val) {
5933     if ((val == NULL) || (xmlStrlen(val) == 0))
5934 	return(0);
5935     return(1);
5936 }
5937 
5938 /**
5939  * xmlXPathCastNodeSetToBoolean:
5940  * @ns:  a node-set
5941  *
5942  * Converts a node-set to its boolean value
5943  *
5944  * Returns the boolean value
5945  */
5946 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5947 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948     if ((ns == NULL) || (ns->nodeNr == 0))
5949 	return(0);
5950     return(1);
5951 }
5952 
5953 /**
5954  * xmlXPathCastToBoolean:
5955  * @val:  an XPath object
5956  *
5957  * Converts an XPath object to its boolean value
5958  *
5959  * Returns the boolean value
5960  */
5961 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5962 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5963     int ret = 0;
5964 
5965     if (val == NULL)
5966 	return(0);
5967     switch (val->type) {
5968     case XPATH_UNDEFINED:
5969 #ifdef DEBUG_EXPR
5970 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5971 #endif
5972 	ret = 0;
5973 	break;
5974     case XPATH_NODESET:
5975     case XPATH_XSLT_TREE:
5976 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5977 	break;
5978     case XPATH_STRING:
5979 	ret = xmlXPathCastStringToBoolean(val->stringval);
5980 	break;
5981     case XPATH_NUMBER:
5982 	ret = xmlXPathCastNumberToBoolean(val->floatval);
5983 	break;
5984     case XPATH_BOOLEAN:
5985 	ret = val->boolval;
5986 	break;
5987     case XPATH_USERS:
5988     case XPATH_POINT:
5989     case XPATH_RANGE:
5990     case XPATH_LOCATIONSET:
5991 	TODO;
5992 	ret = 0;
5993 	break;
5994     }
5995     return(ret);
5996 }
5997 
5998 
5999 /**
6000  * xmlXPathConvertBoolean:
6001  * @val:  an XPath object
6002  *
6003  * Converts an existing object to its boolean() equivalent
6004  *
6005  * Returns the new object, the old one is freed (or the operation
6006  *         is done directly on @val)
6007  */
6008 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6009 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010     xmlXPathObjectPtr ret;
6011 
6012     if (val == NULL)
6013 	return(xmlXPathNewBoolean(0));
6014     if (val->type == XPATH_BOOLEAN)
6015 	return(val);
6016     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017     xmlXPathFreeObject(val);
6018     return(ret);
6019 }
6020 
6021 /************************************************************************
6022  *									*
6023  *		Routines to handle XPath contexts			*
6024  *									*
6025  ************************************************************************/
6026 
6027 /**
6028  * xmlXPathNewContext:
6029  * @doc:  the XML document
6030  *
6031  * Create a new xmlXPathContext
6032  *
6033  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6034  */
6035 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6036 xmlXPathNewContext(xmlDocPtr doc) {
6037     xmlXPathContextPtr ret;
6038 
6039     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6040     if (ret == NULL) {
6041         xmlXPathErrMemory(NULL, "creating context\n");
6042 	return(NULL);
6043     }
6044     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6045     ret->doc = doc;
6046     ret->node = NULL;
6047 
6048     ret->varHash = NULL;
6049 
6050     ret->nb_types = 0;
6051     ret->max_types = 0;
6052     ret->types = NULL;
6053 
6054     ret->funcHash = xmlHashCreate(0);
6055 
6056     ret->nb_axis = 0;
6057     ret->max_axis = 0;
6058     ret->axis = NULL;
6059 
6060     ret->nsHash = NULL;
6061     ret->user = NULL;
6062 
6063     ret->contextSize = -1;
6064     ret->proximityPosition = -1;
6065 
6066 #ifdef XP_DEFAULT_CACHE_ON
6067     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6068 	xmlXPathFreeContext(ret);
6069 	return(NULL);
6070     }
6071 #endif
6072 
6073     xmlXPathRegisterAllFunctions(ret);
6074 
6075     return(ret);
6076 }
6077 
6078 /**
6079  * xmlXPathFreeContext:
6080  * @ctxt:  the context to free
6081  *
6082  * Free up an xmlXPathContext
6083  */
6084 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6085 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6086     if (ctxt == NULL) return;
6087 
6088     if (ctxt->cache != NULL)
6089 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6090     xmlXPathRegisteredNsCleanup(ctxt);
6091     xmlXPathRegisteredFuncsCleanup(ctxt);
6092     xmlXPathRegisteredVariablesCleanup(ctxt);
6093     xmlResetError(&ctxt->lastError);
6094     xmlFree(ctxt);
6095 }
6096 
6097 /************************************************************************
6098  *									*
6099  *		Routines to handle XPath parser contexts		*
6100  *									*
6101  ************************************************************************/
6102 
6103 #define CHECK_CTXT(ctxt)						\
6104     if (ctxt == NULL) {						\
6105 	__xmlRaiseError(NULL, NULL, NULL,				\
6106 		NULL, NULL, XML_FROM_XPATH,				\
6107 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6108 		__FILE__, __LINE__,					\
6109 		NULL, NULL, NULL, 0, 0,					\
6110 		"NULL context pointer\n");				\
6111 	return(NULL);							\
6112     }									\
6113 
6114 #define CHECK_CTXT_NEG(ctxt)						\
6115     if (ctxt == NULL) {						\
6116 	__xmlRaiseError(NULL, NULL, NULL,				\
6117 		NULL, NULL, XML_FROM_XPATH,				\
6118 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6119 		__FILE__, __LINE__,					\
6120 		NULL, NULL, NULL, 0, 0,					\
6121 		"NULL context pointer\n");				\
6122 	return(-1);							\
6123     }									\
6124 
6125 
6126 #define CHECK_CONTEXT(ctxt)						\
6127     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6128         (ctxt->doc->children == NULL)) {				\
6129 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6130 	return(NULL);							\
6131     }
6132 
6133 
6134 /**
6135  * xmlXPathNewParserContext:
6136  * @str:  the XPath expression
6137  * @ctxt:  the XPath context
6138  *
6139  * Create a new xmlXPathParserContext
6140  *
6141  * Returns the xmlXPathParserContext just allocated.
6142  */
6143 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6144 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145     xmlXPathParserContextPtr ret;
6146 
6147     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6148     if (ret == NULL) {
6149         xmlXPathErrMemory(ctxt, "creating parser context\n");
6150 	return(NULL);
6151     }
6152     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153     ret->cur = ret->base = str;
6154     ret->context = ctxt;
6155 
6156     ret->comp = xmlXPathNewCompExpr();
6157     if (ret->comp == NULL) {
6158 	xmlFree(ret->valueTab);
6159 	xmlFree(ret);
6160 	return(NULL);
6161     }
6162     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163         ret->comp->dict = ctxt->dict;
6164 	xmlDictReference(ret->comp->dict);
6165     }
6166 
6167     return(ret);
6168 }
6169 
6170 /**
6171  * xmlXPathCompParserContext:
6172  * @comp:  the XPath compiled expression
6173  * @ctxt:  the XPath context
6174  *
6175  * Create a new xmlXPathParserContext when processing a compiled expression
6176  *
6177  * Returns the xmlXPathParserContext just allocated.
6178  */
6179 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6180 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181     xmlXPathParserContextPtr ret;
6182 
6183     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6184     if (ret == NULL) {
6185         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6186 	return(NULL);
6187     }
6188     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6189 
6190     /* Allocate the value stack */
6191     ret->valueTab = (xmlXPathObjectPtr *)
6192                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6193     if (ret->valueTab == NULL) {
6194 	xmlFree(ret);
6195 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6196 	return(NULL);
6197     }
6198     ret->valueNr = 0;
6199     ret->valueMax = 10;
6200     ret->value = NULL;
6201     ret->valueFrame = 0;
6202 
6203     ret->context = ctxt;
6204     ret->comp = comp;
6205 
6206     return(ret);
6207 }
6208 
6209 /**
6210  * xmlXPathFreeParserContext:
6211  * @ctxt:  the context to free
6212  *
6213  * Free up an xmlXPathParserContext
6214  */
6215 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6216 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217     if (ctxt->valueTab != NULL) {
6218         xmlFree(ctxt->valueTab);
6219     }
6220     if (ctxt->comp != NULL) {
6221 #ifdef XPATH_STREAMING
6222 	if (ctxt->comp->stream != NULL) {
6223 	    xmlFreePatternList(ctxt->comp->stream);
6224 	    ctxt->comp->stream = NULL;
6225 	}
6226 #endif
6227 	xmlXPathFreeCompExpr(ctxt->comp);
6228     }
6229     xmlFree(ctxt);
6230 }
6231 
6232 /************************************************************************
6233  *									*
6234  *		The implicit core function library			*
6235  *									*
6236  ************************************************************************/
6237 
6238 /**
6239  * xmlXPathNodeValHash:
6240  * @node:  a node pointer
6241  *
6242  * Function computing the beginning of the string value of the node,
6243  * used to speed up comparisons
6244  *
6245  * Returns an int usable as a hash
6246  */
6247 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6248 xmlXPathNodeValHash(xmlNodePtr node) {
6249     int len = 2;
6250     const xmlChar * string = NULL;
6251     xmlNodePtr tmp = NULL;
6252     unsigned int ret = 0;
6253 
6254     if (node == NULL)
6255 	return(0);
6256 
6257     if (node->type == XML_DOCUMENT_NODE) {
6258 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6259 	if (tmp == NULL)
6260 	    node = node->children;
6261 	else
6262 	    node = tmp;
6263 
6264 	if (node == NULL)
6265 	    return(0);
6266     }
6267 
6268     switch (node->type) {
6269 	case XML_COMMENT_NODE:
6270 	case XML_PI_NODE:
6271 	case XML_CDATA_SECTION_NODE:
6272 	case XML_TEXT_NODE:
6273 	    string = node->content;
6274 	    if (string == NULL)
6275 		return(0);
6276 	    if (string[0] == 0)
6277 		return(0);
6278 	    return(((unsigned int) string[0]) +
6279 		   (((unsigned int) string[1]) << 8));
6280 	case XML_NAMESPACE_DECL:
6281 	    string = ((xmlNsPtr)node)->href;
6282 	    if (string == NULL)
6283 		return(0);
6284 	    if (string[0] == 0)
6285 		return(0);
6286 	    return(((unsigned int) string[0]) +
6287 		   (((unsigned int) string[1]) << 8));
6288 	case XML_ATTRIBUTE_NODE:
6289 	    tmp = ((xmlAttrPtr) node)->children;
6290 	    break;
6291 	case XML_ELEMENT_NODE:
6292 	    tmp = node->children;
6293 	    break;
6294 	default:
6295 	    return(0);
6296     }
6297     while (tmp != NULL) {
6298 	switch (tmp->type) {
6299 	    case XML_COMMENT_NODE:
6300 	    case XML_PI_NODE:
6301 	    case XML_CDATA_SECTION_NODE:
6302 	    case XML_TEXT_NODE:
6303 		string = tmp->content;
6304 		break;
6305 	    case XML_NAMESPACE_DECL:
6306 		string = ((xmlNsPtr)tmp)->href;
6307 		break;
6308 	    default:
6309 		break;
6310 	}
6311 	if ((string != NULL) && (string[0] != 0)) {
6312 	    if (len == 1) {
6313 		return(ret + (((unsigned int) string[0]) << 8));
6314 	    }
6315 	    if (string[1] == 0) {
6316 		len = 1;
6317 		ret = (unsigned int) string[0];
6318 	    } else {
6319 		return(((unsigned int) string[0]) +
6320 		       (((unsigned int) string[1]) << 8));
6321 	    }
6322 	}
6323 	/*
6324 	 * Skip to next node
6325 	 */
6326 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327 	    if (tmp->children->type != XML_ENTITY_DECL) {
6328 		tmp = tmp->children;
6329 		continue;
6330 	    }
6331 	}
6332 	if (tmp == node)
6333 	    break;
6334 
6335 	if (tmp->next != NULL) {
6336 	    tmp = tmp->next;
6337 	    continue;
6338 	}
6339 
6340 	do {
6341 	    tmp = tmp->parent;
6342 	    if (tmp == NULL)
6343 		break;
6344 	    if (tmp == node) {
6345 		tmp = NULL;
6346 		break;
6347 	    }
6348 	    if (tmp->next != NULL) {
6349 		tmp = tmp->next;
6350 		break;
6351 	    }
6352 	} while (tmp != NULL);
6353     }
6354     return(ret);
6355 }
6356 
6357 /**
6358  * xmlXPathStringHash:
6359  * @string:  a string
6360  *
6361  * Function computing the beginning of the string value of the node,
6362  * used to speed up comparisons
6363  *
6364  * Returns an int usable as a hash
6365  */
6366 static unsigned int
xmlXPathStringHash(const xmlChar * string)6367 xmlXPathStringHash(const xmlChar * string) {
6368     if (string == NULL)
6369 	return((unsigned int) 0);
6370     if (string[0] == 0)
6371 	return(0);
6372     return(((unsigned int) string[0]) +
6373 	   (((unsigned int) string[1]) << 8));
6374 }
6375 
6376 /**
6377  * xmlXPathCompareNodeSetFloat:
6378  * @ctxt:  the XPath Parser context
6379  * @inf:  less than (1) or greater than (0)
6380  * @strict:  is the comparison strict
6381  * @arg:  the node set
6382  * @f:  the value
6383  *
6384  * Implement the compare operation between a nodeset and a number
6385  *     @ns < @val    (1, 1, ...
6386  *     @ns <= @val   (1, 0, ...
6387  *     @ns > @val    (0, 1, ...
6388  *     @ns >= @val   (0, 0, ...
6389  *
6390  * If one object to be compared is a node-set and the other is a number,
6391  * then the comparison will be true if and only if there is a node in the
6392  * node-set such that the result of performing the comparison on the number
6393  * to be compared and on the result of converting the string-value of that
6394  * node to a number using the number function is true.
6395  *
6396  * Returns 0 or 1 depending on the results of the test.
6397  */
6398 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6399 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6401     int i, ret = 0;
6402     xmlNodeSetPtr ns;
6403     xmlChar *str2;
6404 
6405     if ((f == NULL) || (arg == NULL) ||
6406 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6407 	xmlXPathReleaseObject(ctxt->context, arg);
6408 	xmlXPathReleaseObject(ctxt->context, f);
6409         return(0);
6410     }
6411     ns = arg->nodesetval;
6412     if (ns != NULL) {
6413 	for (i = 0;i < ns->nodeNr;i++) {
6414 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6415 	     if (str2 != NULL) {
6416 		 valuePush(ctxt,
6417 			   xmlXPathCacheNewString(ctxt->context, str2));
6418 		 xmlFree(str2);
6419 		 xmlXPathNumberFunction(ctxt, 1);
6420 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6421 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6422 		 if (ret)
6423 		     break;
6424 	     }
6425 	}
6426     }
6427     xmlXPathReleaseObject(ctxt->context, arg);
6428     xmlXPathReleaseObject(ctxt->context, f);
6429     return(ret);
6430 }
6431 
6432 /**
6433  * xmlXPathCompareNodeSetString:
6434  * @ctxt:  the XPath Parser context
6435  * @inf:  less than (1) or greater than (0)
6436  * @strict:  is the comparison strict
6437  * @arg:  the node set
6438  * @s:  the value
6439  *
6440  * Implement the compare operation between a nodeset and a string
6441  *     @ns < @val    (1, 1, ...
6442  *     @ns <= @val   (1, 0, ...
6443  *     @ns > @val    (0, 1, ...
6444  *     @ns >= @val   (0, 0, ...
6445  *
6446  * If one object to be compared is a node-set and the other is a string,
6447  * then the comparison will be true if and only if there is a node in
6448  * the node-set such that the result of performing the comparison on the
6449  * string-value of the node and the other string is true.
6450  *
6451  * Returns 0 or 1 depending on the results of the test.
6452  */
6453 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6454 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6456     int i, ret = 0;
6457     xmlNodeSetPtr ns;
6458     xmlChar *str2;
6459 
6460     if ((s == NULL) || (arg == NULL) ||
6461 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6462 	xmlXPathReleaseObject(ctxt->context, arg);
6463 	xmlXPathReleaseObject(ctxt->context, s);
6464         return(0);
6465     }
6466     ns = arg->nodesetval;
6467     if (ns != NULL) {
6468 	for (i = 0;i < ns->nodeNr;i++) {
6469 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6470 	     if (str2 != NULL) {
6471 		 valuePush(ctxt,
6472 			   xmlXPathCacheNewString(ctxt->context, str2));
6473 		 xmlFree(str2);
6474 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6475 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6476 		 if (ret)
6477 		     break;
6478 	     }
6479 	}
6480     }
6481     xmlXPathReleaseObject(ctxt->context, arg);
6482     xmlXPathReleaseObject(ctxt->context, s);
6483     return(ret);
6484 }
6485 
6486 /**
6487  * xmlXPathCompareNodeSets:
6488  * @inf:  less than (1) or greater than (0)
6489  * @strict:  is the comparison strict
6490  * @arg1:  the first node set object
6491  * @arg2:  the second node set object
6492  *
6493  * Implement the compare operation on nodesets:
6494  *
6495  * If both objects to be compared are node-sets, then the comparison
6496  * will be true if and only if there is a node in the first node-set
6497  * and a node in the second node-set such that the result of performing
6498  * the comparison on the string-values of the two nodes is true.
6499  * ....
6500  * When neither object to be compared is a node-set and the operator
6501  * is <=, <, >= or >, then the objects are compared by converting both
6502  * objects to numbers and comparing the numbers according to IEEE 754.
6503  * ....
6504  * The number function converts its argument to a number as follows:
6505  *  - a string that consists of optional whitespace followed by an
6506  *    optional minus sign followed by a Number followed by whitespace
6507  *    is converted to the IEEE 754 number that is nearest (according
6508  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6509  *    represented by the string; any other string is converted to NaN
6510  *
6511  * Conclusion all nodes need to be converted first to their string value
6512  * and then the comparison must be done when possible
6513  */
6514 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6515 xmlXPathCompareNodeSets(int inf, int strict,
6516 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6517     int i, j, init = 0;
6518     double val1;
6519     double *values2;
6520     int ret = 0;
6521     xmlNodeSetPtr ns1;
6522     xmlNodeSetPtr ns2;
6523 
6524     if ((arg1 == NULL) ||
6525 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526 	xmlXPathFreeObject(arg2);
6527         return(0);
6528     }
6529     if ((arg2 == NULL) ||
6530 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531 	xmlXPathFreeObject(arg1);
6532 	xmlXPathFreeObject(arg2);
6533         return(0);
6534     }
6535 
6536     ns1 = arg1->nodesetval;
6537     ns2 = arg2->nodesetval;
6538 
6539     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6540 	xmlXPathFreeObject(arg1);
6541 	xmlXPathFreeObject(arg2);
6542 	return(0);
6543     }
6544     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6545 	xmlXPathFreeObject(arg1);
6546 	xmlXPathFreeObject(arg2);
6547 	return(0);
6548     }
6549 
6550     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551     if (values2 == NULL) {
6552         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6553 	xmlXPathFreeObject(arg1);
6554 	xmlXPathFreeObject(arg2);
6555 	return(0);
6556     }
6557     for (i = 0;i < ns1->nodeNr;i++) {
6558 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6559 	if (xmlXPathIsNaN(val1))
6560 	    continue;
6561 	for (j = 0;j < ns2->nodeNr;j++) {
6562 	    if (init == 0) {
6563 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6564 	    }
6565 	    if (xmlXPathIsNaN(values2[j]))
6566 		continue;
6567 	    if (inf && strict)
6568 		ret = (val1 < values2[j]);
6569 	    else if (inf && !strict)
6570 		ret = (val1 <= values2[j]);
6571 	    else if (!inf && strict)
6572 		ret = (val1 > values2[j]);
6573 	    else if (!inf && !strict)
6574 		ret = (val1 >= values2[j]);
6575 	    if (ret)
6576 		break;
6577 	}
6578 	if (ret)
6579 	    break;
6580 	init = 1;
6581     }
6582     xmlFree(values2);
6583     xmlXPathFreeObject(arg1);
6584     xmlXPathFreeObject(arg2);
6585     return(ret);
6586 }
6587 
6588 /**
6589  * xmlXPathCompareNodeSetValue:
6590  * @ctxt:  the XPath Parser context
6591  * @inf:  less than (1) or greater than (0)
6592  * @strict:  is the comparison strict
6593  * @arg:  the node set
6594  * @val:  the value
6595  *
6596  * Implement the compare operation between a nodeset and a value
6597  *     @ns < @val    (1, 1, ...
6598  *     @ns <= @val   (1, 0, ...
6599  *     @ns > @val    (0, 1, ...
6600  *     @ns >= @val   (0, 0, ...
6601  *
6602  * If one object to be compared is a node-set and the other is a boolean,
6603  * then the comparison will be true if and only if the result of performing
6604  * the comparison on the boolean and on the result of converting
6605  * the node-set to a boolean using the boolean function is true.
6606  *
6607  * Returns 0 or 1 depending on the results of the test.
6608  */
6609 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6610 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612     if ((val == NULL) || (arg == NULL) ||
6613 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614         return(0);
6615 
6616     switch(val->type) {
6617         case XPATH_NUMBER:
6618 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6619         case XPATH_NODESET:
6620         case XPATH_XSLT_TREE:
6621 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6622         case XPATH_STRING:
6623 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6624         case XPATH_BOOLEAN:
6625 	    valuePush(ctxt, arg);
6626 	    xmlXPathBooleanFunction(ctxt, 1);
6627 	    valuePush(ctxt, val);
6628 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6629 	default:
6630 	    TODO
6631     }
6632     return(0);
6633 }
6634 
6635 /**
6636  * xmlXPathEqualNodeSetString:
6637  * @arg:  the nodeset object argument
6638  * @str:  the string to compare to.
6639  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6640  *
6641  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642  * If one object to be compared is a node-set and the other is a string,
6643  * then the comparison will be true if and only if there is a node in
6644  * the node-set such that the result of performing the comparison on the
6645  * string-value of the node and the other string is true.
6646  *
6647  * Returns 0 or 1 depending on the results of the test.
6648  */
6649 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6650 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6651 {
6652     int i;
6653     xmlNodeSetPtr ns;
6654     xmlChar *str2;
6655     unsigned int hash;
6656 
6657     if ((str == NULL) || (arg == NULL) ||
6658         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659         return (0);
6660     ns = arg->nodesetval;
6661     /*
6662      * A NULL nodeset compared with a string is always false
6663      * (since there is no node equal, and no node not equal)
6664      */
6665     if ((ns == NULL) || (ns->nodeNr <= 0) )
6666         return (0);
6667     hash = xmlXPathStringHash(str);
6668     for (i = 0; i < ns->nodeNr; i++) {
6669         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6672                 xmlFree(str2);
6673 		if (neq)
6674 		    continue;
6675                 return (1);
6676 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6677 		if (neq)
6678 		    continue;
6679                 return (1);
6680             } else if (neq) {
6681 		if (str2 != NULL)
6682 		    xmlFree(str2);
6683 		return (1);
6684 	    }
6685             if (str2 != NULL)
6686                 xmlFree(str2);
6687         } else if (neq)
6688 	    return (1);
6689     }
6690     return (0);
6691 }
6692 
6693 /**
6694  * xmlXPathEqualNodeSetFloat:
6695  * @arg:  the nodeset object argument
6696  * @f:  the float to compare to
6697  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6698  *
6699  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700  * If one object to be compared is a node-set and the other is a number,
6701  * then the comparison will be true if and only if there is a node in
6702  * the node-set such that the result of performing the comparison on the
6703  * number to be compared and on the result of converting the string-value
6704  * of that node to a number using the number function is true.
6705  *
6706  * Returns 0 or 1 depending on the results of the test.
6707  */
6708 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6709 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710     xmlXPathObjectPtr arg, double f, int neq) {
6711   int i, ret=0;
6712   xmlNodeSetPtr ns;
6713   xmlChar *str2;
6714   xmlXPathObjectPtr val;
6715   double v;
6716 
6717     if ((arg == NULL) ||
6718 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719         return(0);
6720 
6721     ns = arg->nodesetval;
6722     if (ns != NULL) {
6723 	for (i=0;i<ns->nodeNr;i++) {
6724 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6725 	    if (str2 != NULL) {
6726 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6727 		xmlFree(str2);
6728 		xmlXPathNumberFunction(ctxt, 1);
6729 		val = valuePop(ctxt);
6730 		v = val->floatval;
6731 		xmlXPathReleaseObject(ctxt->context, val);
6732 		if (!xmlXPathIsNaN(v)) {
6733 		    if ((!neq) && (v==f)) {
6734 			ret = 1;
6735 			break;
6736 		    } else if ((neq) && (v!=f)) {
6737 			ret = 1;
6738 			break;
6739 		    }
6740 		} else {	/* NaN is unequal to any value */
6741 		    if (neq)
6742 			ret = 1;
6743 		}
6744 	    }
6745 	}
6746     }
6747 
6748     return(ret);
6749 }
6750 
6751 
6752 /**
6753  * xmlXPathEqualNodeSets:
6754  * @arg1:  first nodeset object argument
6755  * @arg2:  second nodeset object argument
6756  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6757  *
6758  * Implement the equal / not equal operation on XPath nodesets:
6759  * @arg1 == @arg2  or  @arg1 != @arg2
6760  * If both objects to be compared are node-sets, then the comparison
6761  * will be true if and only if there is a node in the first node-set and
6762  * a node in the second node-set such that the result of performing the
6763  * comparison on the string-values of the two nodes is true.
6764  *
6765  * (needless to say, this is a costly operation)
6766  *
6767  * Returns 0 or 1 depending on the results of the test.
6768  */
6769 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6770 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6771     int i, j;
6772     unsigned int *hashs1;
6773     unsigned int *hashs2;
6774     xmlChar **values1;
6775     xmlChar **values2;
6776     int ret = 0;
6777     xmlNodeSetPtr ns1;
6778     xmlNodeSetPtr ns2;
6779 
6780     if ((arg1 == NULL) ||
6781 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6782         return(0);
6783     if ((arg2 == NULL) ||
6784 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6785         return(0);
6786 
6787     ns1 = arg1->nodesetval;
6788     ns2 = arg2->nodesetval;
6789 
6790     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6791 	return(0);
6792     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6793 	return(0);
6794 
6795     /*
6796      * for equal, check if there is a node pertaining to both sets
6797      */
6798     if (neq == 0)
6799 	for (i = 0;i < ns1->nodeNr;i++)
6800 	    for (j = 0;j < ns2->nodeNr;j++)
6801 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6802 		    return(1);
6803 
6804     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6805     if (values1 == NULL) {
6806         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6807 	return(0);
6808     }
6809     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810     if (hashs1 == NULL) {
6811         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6812 	xmlFree(values1);
6813 	return(0);
6814     }
6815     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817     if (values2 == NULL) {
6818         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6819 	xmlFree(hashs1);
6820 	xmlFree(values1);
6821 	return(0);
6822     }
6823     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824     if (hashs2 == NULL) {
6825         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6826 	xmlFree(hashs1);
6827 	xmlFree(values1);
6828 	xmlFree(values2);
6829 	return(0);
6830     }
6831     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832     for (i = 0;i < ns1->nodeNr;i++) {
6833 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6834 	for (j = 0;j < ns2->nodeNr;j++) {
6835 	    if (i == 0)
6836 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6837 	    if (hashs1[i] != hashs2[j]) {
6838 		if (neq) {
6839 		    ret = 1;
6840 		    break;
6841 		}
6842 	    }
6843 	    else {
6844 		if (values1[i] == NULL)
6845 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846 		if (values2[j] == NULL)
6847 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6848 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6849 		if (ret)
6850 		    break;
6851 	    }
6852 	}
6853 	if (ret)
6854 	    break;
6855     }
6856     for (i = 0;i < ns1->nodeNr;i++)
6857 	if (values1[i] != NULL)
6858 	    xmlFree(values1[i]);
6859     for (j = 0;j < ns2->nodeNr;j++)
6860 	if (values2[j] != NULL)
6861 	    xmlFree(values2[j]);
6862     xmlFree(values1);
6863     xmlFree(values2);
6864     xmlFree(hashs1);
6865     xmlFree(hashs2);
6866     return(ret);
6867 }
6868 
6869 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6870 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6872     int ret = 0;
6873     /*
6874      *At this point we are assured neither arg1 nor arg2
6875      *is a nodeset, so we can just pick the appropriate routine.
6876      */
6877     switch (arg1->type) {
6878         case XPATH_UNDEFINED:
6879 #ifdef DEBUG_EXPR
6880 	    xmlGenericError(xmlGenericErrorContext,
6881 		    "Equal: undefined\n");
6882 #endif
6883 	    break;
6884         case XPATH_BOOLEAN:
6885 	    switch (arg2->type) {
6886 	        case XPATH_UNDEFINED:
6887 #ifdef DEBUG_EXPR
6888 		    xmlGenericError(xmlGenericErrorContext,
6889 			    "Equal: undefined\n");
6890 #endif
6891 		    break;
6892 		case XPATH_BOOLEAN:
6893 #ifdef DEBUG_EXPR
6894 		    xmlGenericError(xmlGenericErrorContext,
6895 			    "Equal: %d boolean %d \n",
6896 			    arg1->boolval, arg2->boolval);
6897 #endif
6898 		    ret = (arg1->boolval == arg2->boolval);
6899 		    break;
6900 		case XPATH_NUMBER:
6901 		    ret = (arg1->boolval ==
6902 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6903 		    break;
6904 		case XPATH_STRING:
6905 		    if ((arg2->stringval == NULL) ||
6906 			(arg2->stringval[0] == 0)) ret = 0;
6907 		    else
6908 			ret = 1;
6909 		    ret = (arg1->boolval == ret);
6910 		    break;
6911 		case XPATH_USERS:
6912 		case XPATH_POINT:
6913 		case XPATH_RANGE:
6914 		case XPATH_LOCATIONSET:
6915 		    TODO
6916 		    break;
6917 		case XPATH_NODESET:
6918 		case XPATH_XSLT_TREE:
6919 		    break;
6920 	    }
6921 	    break;
6922         case XPATH_NUMBER:
6923 	    switch (arg2->type) {
6924 	        case XPATH_UNDEFINED:
6925 #ifdef DEBUG_EXPR
6926 		    xmlGenericError(xmlGenericErrorContext,
6927 			    "Equal: undefined\n");
6928 #endif
6929 		    break;
6930 		case XPATH_BOOLEAN:
6931 		    ret = (arg2->boolval==
6932 			   xmlXPathCastNumberToBoolean(arg1->floatval));
6933 		    break;
6934 		case XPATH_STRING:
6935 		    valuePush(ctxt, arg2);
6936 		    xmlXPathNumberFunction(ctxt, 1);
6937 		    arg2 = valuePop(ctxt);
6938 		    /* no break on purpose */
6939 		case XPATH_NUMBER:
6940 		    /* Hand check NaN and Infinity equalities */
6941 		    if (xmlXPathIsNaN(arg1->floatval) ||
6942 			    xmlXPathIsNaN(arg2->floatval)) {
6943 		        ret = 0;
6944 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945 		        if (xmlXPathIsInf(arg2->floatval) == 1)
6946 			    ret = 1;
6947 			else
6948 			    ret = 0;
6949 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950 			if (xmlXPathIsInf(arg2->floatval) == -1)
6951 			    ret = 1;
6952 			else
6953 			    ret = 0;
6954 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955 			if (xmlXPathIsInf(arg1->floatval) == 1)
6956 			    ret = 1;
6957 			else
6958 			    ret = 0;
6959 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960 			if (xmlXPathIsInf(arg1->floatval) == -1)
6961 			    ret = 1;
6962 			else
6963 			    ret = 0;
6964 		    } else {
6965 		        ret = (arg1->floatval == arg2->floatval);
6966 		    }
6967 		    break;
6968 		case XPATH_USERS:
6969 		case XPATH_POINT:
6970 		case XPATH_RANGE:
6971 		case XPATH_LOCATIONSET:
6972 		    TODO
6973 		    break;
6974 		case XPATH_NODESET:
6975 		case XPATH_XSLT_TREE:
6976 		    break;
6977 	    }
6978 	    break;
6979         case XPATH_STRING:
6980 	    switch (arg2->type) {
6981 	        case XPATH_UNDEFINED:
6982 #ifdef DEBUG_EXPR
6983 		    xmlGenericError(xmlGenericErrorContext,
6984 			    "Equal: undefined\n");
6985 #endif
6986 		    break;
6987 		case XPATH_BOOLEAN:
6988 		    if ((arg1->stringval == NULL) ||
6989 			(arg1->stringval[0] == 0)) ret = 0;
6990 		    else
6991 			ret = 1;
6992 		    ret = (arg2->boolval == ret);
6993 		    break;
6994 		case XPATH_STRING:
6995 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6996 		    break;
6997 		case XPATH_NUMBER:
6998 		    valuePush(ctxt, arg1);
6999 		    xmlXPathNumberFunction(ctxt, 1);
7000 		    arg1 = valuePop(ctxt);
7001 		    /* Hand check NaN and Infinity equalities */
7002 		    if (xmlXPathIsNaN(arg1->floatval) ||
7003 			    xmlXPathIsNaN(arg2->floatval)) {
7004 		        ret = 0;
7005 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006 			if (xmlXPathIsInf(arg2->floatval) == 1)
7007 			    ret = 1;
7008 			else
7009 			    ret = 0;
7010 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011 			if (xmlXPathIsInf(arg2->floatval) == -1)
7012 			    ret = 1;
7013 			else
7014 			    ret = 0;
7015 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016 			if (xmlXPathIsInf(arg1->floatval) == 1)
7017 			    ret = 1;
7018 			else
7019 			    ret = 0;
7020 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021 			if (xmlXPathIsInf(arg1->floatval) == -1)
7022 			    ret = 1;
7023 			else
7024 			    ret = 0;
7025 		    } else {
7026 		        ret = (arg1->floatval == arg2->floatval);
7027 		    }
7028 		    break;
7029 		case XPATH_USERS:
7030 		case XPATH_POINT:
7031 		case XPATH_RANGE:
7032 		case XPATH_LOCATIONSET:
7033 		    TODO
7034 		    break;
7035 		case XPATH_NODESET:
7036 		case XPATH_XSLT_TREE:
7037 		    break;
7038 	    }
7039 	    break;
7040         case XPATH_USERS:
7041 	case XPATH_POINT:
7042 	case XPATH_RANGE:
7043 	case XPATH_LOCATIONSET:
7044 	    TODO
7045 	    break;
7046 	case XPATH_NODESET:
7047 	case XPATH_XSLT_TREE:
7048 	    break;
7049     }
7050     xmlXPathReleaseObject(ctxt->context, arg1);
7051     xmlXPathReleaseObject(ctxt->context, arg2);
7052     return(ret);
7053 }
7054 
7055 /**
7056  * xmlXPathEqualValues:
7057  * @ctxt:  the XPath Parser context
7058  *
7059  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7060  *
7061  * Returns 0 or 1 depending on the results of the test.
7062  */
7063 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7064 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065     xmlXPathObjectPtr arg1, arg2, argtmp;
7066     int ret = 0;
7067 
7068     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7069     arg2 = valuePop(ctxt);
7070     arg1 = valuePop(ctxt);
7071     if ((arg1 == NULL) || (arg2 == NULL)) {
7072 	if (arg1 != NULL)
7073 	    xmlXPathReleaseObject(ctxt->context, arg1);
7074 	else
7075 	    xmlXPathReleaseObject(ctxt->context, arg2);
7076 	XP_ERROR0(XPATH_INVALID_OPERAND);
7077     }
7078 
7079     if (arg1 == arg2) {
7080 #ifdef DEBUG_EXPR
7081         xmlGenericError(xmlGenericErrorContext,
7082 		"Equal: by pointer\n");
7083 #endif
7084 	xmlXPathFreeObject(arg1);
7085         return(1);
7086     }
7087 
7088     /*
7089      *If either argument is a nodeset, it's a 'special case'
7090      */
7091     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7093 	/*
7094 	 *Hack it to assure arg1 is the nodeset
7095 	 */
7096 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7097 		argtmp = arg2;
7098 		arg2 = arg1;
7099 		arg1 = argtmp;
7100 	}
7101 	switch (arg2->type) {
7102 	    case XPATH_UNDEFINED:
7103 #ifdef DEBUG_EXPR
7104 		xmlGenericError(xmlGenericErrorContext,
7105 			"Equal: undefined\n");
7106 #endif
7107 		break;
7108 	    case XPATH_NODESET:
7109 	    case XPATH_XSLT_TREE:
7110 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7111 		break;
7112 	    case XPATH_BOOLEAN:
7113 		if ((arg1->nodesetval == NULL) ||
7114 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7115 		else
7116 		    ret = 1;
7117 		ret = (ret == arg2->boolval);
7118 		break;
7119 	    case XPATH_NUMBER:
7120 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7121 		break;
7122 	    case XPATH_STRING:
7123 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7124 		break;
7125 	    case XPATH_USERS:
7126 	    case XPATH_POINT:
7127 	    case XPATH_RANGE:
7128 	    case XPATH_LOCATIONSET:
7129 		TODO
7130 		break;
7131 	}
7132 	xmlXPathReleaseObject(ctxt->context, arg1);
7133 	xmlXPathReleaseObject(ctxt->context, arg2);
7134 	return(ret);
7135     }
7136 
7137     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7138 }
7139 
7140 /**
7141  * xmlXPathNotEqualValues:
7142  * @ctxt:  the XPath Parser context
7143  *
7144  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7145  *
7146  * Returns 0 or 1 depending on the results of the test.
7147  */
7148 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7149 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150     xmlXPathObjectPtr arg1, arg2, argtmp;
7151     int ret = 0;
7152 
7153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7154     arg2 = valuePop(ctxt);
7155     arg1 = valuePop(ctxt);
7156     if ((arg1 == NULL) || (arg2 == NULL)) {
7157 	if (arg1 != NULL)
7158 	    xmlXPathReleaseObject(ctxt->context, arg1);
7159 	else
7160 	    xmlXPathReleaseObject(ctxt->context, arg2);
7161 	XP_ERROR0(XPATH_INVALID_OPERAND);
7162     }
7163 
7164     if (arg1 == arg2) {
7165 #ifdef DEBUG_EXPR
7166         xmlGenericError(xmlGenericErrorContext,
7167 		"NotEqual: by pointer\n");
7168 #endif
7169 	xmlXPathReleaseObject(ctxt->context, arg1);
7170         return(0);
7171     }
7172 
7173     /*
7174      *If either argument is a nodeset, it's a 'special case'
7175      */
7176     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7178 	/*
7179 	 *Hack it to assure arg1 is the nodeset
7180 	 */
7181 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7182 		argtmp = arg2;
7183 		arg2 = arg1;
7184 		arg1 = argtmp;
7185 	}
7186 	switch (arg2->type) {
7187 	    case XPATH_UNDEFINED:
7188 #ifdef DEBUG_EXPR
7189 		xmlGenericError(xmlGenericErrorContext,
7190 			"NotEqual: undefined\n");
7191 #endif
7192 		break;
7193 	    case XPATH_NODESET:
7194 	    case XPATH_XSLT_TREE:
7195 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7196 		break;
7197 	    case XPATH_BOOLEAN:
7198 		if ((arg1->nodesetval == NULL) ||
7199 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7200 		else
7201 		    ret = 1;
7202 		ret = (ret != arg2->boolval);
7203 		break;
7204 	    case XPATH_NUMBER:
7205 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7206 		break;
7207 	    case XPATH_STRING:
7208 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7209 		break;
7210 	    case XPATH_USERS:
7211 	    case XPATH_POINT:
7212 	    case XPATH_RANGE:
7213 	    case XPATH_LOCATIONSET:
7214 		TODO
7215 		break;
7216 	}
7217 	xmlXPathReleaseObject(ctxt->context, arg1);
7218 	xmlXPathReleaseObject(ctxt->context, arg2);
7219 	return(ret);
7220     }
7221 
7222     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223 }
7224 
7225 /**
7226  * xmlXPathCompareValues:
7227  * @ctxt:  the XPath Parser context
7228  * @inf:  less than (1) or greater than (0)
7229  * @strict:  is the comparison strict
7230  *
7231  * Implement the compare operation on XPath objects:
7232  *     @arg1 < @arg2    (1, 1, ...
7233  *     @arg1 <= @arg2   (1, 0, ...
7234  *     @arg1 > @arg2    (0, 1, ...
7235  *     @arg1 >= @arg2   (0, 0, ...
7236  *
7237  * When neither object to be compared is a node-set and the operator is
7238  * <=, <, >=, >, then the objects are compared by converted both objects
7239  * to numbers and comparing the numbers according to IEEE 754. The <
7240  * comparison will be true if and only if the first number is less than the
7241  * second number. The <= comparison will be true if and only if the first
7242  * number is less than or equal to the second number. The > comparison
7243  * will be true if and only if the first number is greater than the second
7244  * number. The >= comparison will be true if and only if the first number
7245  * is greater than or equal to the second number.
7246  *
7247  * Returns 1 if the comparison succeeded, 0 if it failed
7248  */
7249 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7250 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7251     int ret = 0, arg1i = 0, arg2i = 0;
7252     xmlXPathObjectPtr arg1, arg2;
7253 
7254     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7255     arg2 = valuePop(ctxt);
7256     arg1 = valuePop(ctxt);
7257     if ((arg1 == NULL) || (arg2 == NULL)) {
7258 	if (arg1 != NULL)
7259 	    xmlXPathReleaseObject(ctxt->context, arg1);
7260 	else
7261 	    xmlXPathReleaseObject(ctxt->context, arg2);
7262 	XP_ERROR0(XPATH_INVALID_OPERAND);
7263     }
7264 
7265     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7267 	/*
7268 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269 	 * are not freed from within this routine; they will be freed from the
7270 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7271 	 */
7272 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7274 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7275 	} else {
7276 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7277 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7278 			                          arg1, arg2);
7279 	    } else {
7280 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7281 			                          arg2, arg1);
7282 	    }
7283 	}
7284 	return(ret);
7285     }
7286 
7287     if (arg1->type != XPATH_NUMBER) {
7288 	valuePush(ctxt, arg1);
7289 	xmlXPathNumberFunction(ctxt, 1);
7290 	arg1 = valuePop(ctxt);
7291     }
7292     if (arg1->type != XPATH_NUMBER) {
7293 	xmlXPathFreeObject(arg1);
7294 	xmlXPathFreeObject(arg2);
7295 	XP_ERROR0(XPATH_INVALID_OPERAND);
7296     }
7297     if (arg2->type != XPATH_NUMBER) {
7298 	valuePush(ctxt, arg2);
7299 	xmlXPathNumberFunction(ctxt, 1);
7300 	arg2 = valuePop(ctxt);
7301     }
7302     if (arg2->type != XPATH_NUMBER) {
7303 	xmlXPathReleaseObject(ctxt->context, arg1);
7304 	xmlXPathReleaseObject(ctxt->context, arg2);
7305 	XP_ERROR0(XPATH_INVALID_OPERAND);
7306     }
7307     /*
7308      * Add tests for infinity and nan
7309      * => feedback on 3.4 for Inf and NaN
7310      */
7311     /* Hand check NaN and Infinity comparisons */
7312     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7313 	ret=0;
7314     } else {
7315 	arg1i=xmlXPathIsInf(arg1->floatval);
7316 	arg2i=xmlXPathIsInf(arg2->floatval);
7317 	if (inf && strict) {
7318 	    if ((arg1i == -1 && arg2i != -1) ||
7319 		(arg2i == 1 && arg1i != 1)) {
7320 		ret = 1;
7321 	    } else if (arg1i == 0 && arg2i == 0) {
7322 		ret = (arg1->floatval < arg2->floatval);
7323 	    } else {
7324 		ret = 0;
7325 	    }
7326 	}
7327 	else if (inf && !strict) {
7328 	    if (arg1i == -1 || arg2i == 1) {
7329 		ret = 1;
7330 	    } else if (arg1i == 0 && arg2i == 0) {
7331 		ret = (arg1->floatval <= arg2->floatval);
7332 	    } else {
7333 		ret = 0;
7334 	    }
7335 	}
7336 	else if (!inf && strict) {
7337 	    if ((arg1i == 1 && arg2i != 1) ||
7338 		(arg2i == -1 && arg1i != -1)) {
7339 		ret = 1;
7340 	    } else if (arg1i == 0 && arg2i == 0) {
7341 		ret = (arg1->floatval > arg2->floatval);
7342 	    } else {
7343 		ret = 0;
7344 	    }
7345 	}
7346 	else if (!inf && !strict) {
7347 	    if (arg1i == 1 || arg2i == -1) {
7348 		ret = 1;
7349 	    } else if (arg1i == 0 && arg2i == 0) {
7350 		ret = (arg1->floatval >= arg2->floatval);
7351 	    } else {
7352 		ret = 0;
7353 	    }
7354 	}
7355     }
7356     xmlXPathReleaseObject(ctxt->context, arg1);
7357     xmlXPathReleaseObject(ctxt->context, arg2);
7358     return(ret);
7359 }
7360 
7361 /**
7362  * xmlXPathValueFlipSign:
7363  * @ctxt:  the XPath Parser context
7364  *
7365  * Implement the unary - operation on an XPath object
7366  * The numeric operators convert their operands to numbers as if
7367  * by calling the number function.
7368  */
7369 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7370 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7371     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7372     CAST_TO_NUMBER;
7373     CHECK_TYPE(XPATH_NUMBER);
7374     if (xmlXPathIsNaN(ctxt->value->floatval))
7375         ctxt->value->floatval=xmlXPathNAN;
7376     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377         ctxt->value->floatval=xmlXPathNINF;
7378     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379         ctxt->value->floatval=xmlXPathPINF;
7380     else if (ctxt->value->floatval == 0) {
7381         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382 	    ctxt->value->floatval = xmlXPathNZERO;
7383 	else
7384 	    ctxt->value->floatval = 0;
7385     }
7386     else
7387         ctxt->value->floatval = - ctxt->value->floatval;
7388 }
7389 
7390 /**
7391  * xmlXPathAddValues:
7392  * @ctxt:  the XPath Parser context
7393  *
7394  * Implement the add operation on XPath objects:
7395  * The numeric operators convert their operands to numbers as if
7396  * by calling the number function.
7397  */
7398 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7399 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400     xmlXPathObjectPtr arg;
7401     double val;
7402 
7403     arg = valuePop(ctxt);
7404     if (arg == NULL)
7405 	XP_ERROR(XPATH_INVALID_OPERAND);
7406     val = xmlXPathCastToNumber(arg);
7407     xmlXPathReleaseObject(ctxt->context, arg);
7408     CAST_TO_NUMBER;
7409     CHECK_TYPE(XPATH_NUMBER);
7410     ctxt->value->floatval += val;
7411 }
7412 
7413 /**
7414  * xmlXPathSubValues:
7415  * @ctxt:  the XPath Parser context
7416  *
7417  * Implement the subtraction operation on XPath objects:
7418  * The numeric operators convert their operands to numbers as if
7419  * by calling the number function.
7420  */
7421 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7422 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423     xmlXPathObjectPtr arg;
7424     double val;
7425 
7426     arg = valuePop(ctxt);
7427     if (arg == NULL)
7428 	XP_ERROR(XPATH_INVALID_OPERAND);
7429     val = xmlXPathCastToNumber(arg);
7430     xmlXPathReleaseObject(ctxt->context, arg);
7431     CAST_TO_NUMBER;
7432     CHECK_TYPE(XPATH_NUMBER);
7433     ctxt->value->floatval -= val;
7434 }
7435 
7436 /**
7437  * xmlXPathMultValues:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the multiply operation on XPath objects:
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7445 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446     xmlXPathObjectPtr arg;
7447     double val;
7448 
7449     arg = valuePop(ctxt);
7450     if (arg == NULL)
7451 	XP_ERROR(XPATH_INVALID_OPERAND);
7452     val = xmlXPathCastToNumber(arg);
7453     xmlXPathReleaseObject(ctxt->context, arg);
7454     CAST_TO_NUMBER;
7455     CHECK_TYPE(XPATH_NUMBER);
7456     ctxt->value->floatval *= val;
7457 }
7458 
7459 /**
7460  * xmlXPathDivValues:
7461  * @ctxt:  the XPath Parser context
7462  *
7463  * Implement the div operation on XPath objects @arg1 / @arg2:
7464  * The numeric operators convert their operands to numbers as if
7465  * by calling the number function.
7466  */
7467 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7468 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469     xmlXPathObjectPtr arg;
7470     double val;
7471 
7472     arg = valuePop(ctxt);
7473     if (arg == NULL)
7474 	XP_ERROR(XPATH_INVALID_OPERAND);
7475     val = xmlXPathCastToNumber(arg);
7476     xmlXPathReleaseObject(ctxt->context, arg);
7477     CAST_TO_NUMBER;
7478     CHECK_TYPE(XPATH_NUMBER);
7479     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480 	ctxt->value->floatval = xmlXPathNAN;
7481     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7482 	if (ctxt->value->floatval == 0)
7483 	    ctxt->value->floatval = xmlXPathNAN;
7484 	else if (ctxt->value->floatval > 0)
7485 	    ctxt->value->floatval = xmlXPathNINF;
7486 	else if (ctxt->value->floatval < 0)
7487 	    ctxt->value->floatval = xmlXPathPINF;
7488     }
7489     else if (val == 0) {
7490 	if (ctxt->value->floatval == 0)
7491 	    ctxt->value->floatval = xmlXPathNAN;
7492 	else if (ctxt->value->floatval > 0)
7493 	    ctxt->value->floatval = xmlXPathPINF;
7494 	else if (ctxt->value->floatval < 0)
7495 	    ctxt->value->floatval = xmlXPathNINF;
7496     } else
7497 	ctxt->value->floatval /= val;
7498 }
7499 
7500 /**
7501  * xmlXPathModValues:
7502  * @ctxt:  the XPath Parser context
7503  *
7504  * Implement the mod operation on XPath objects: @arg1 / @arg2
7505  * The numeric operators convert their operands to numbers as if
7506  * by calling the number function.
7507  */
7508 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7509 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510     xmlXPathObjectPtr arg;
7511     double arg1, arg2;
7512 
7513     arg = valuePop(ctxt);
7514     if (arg == NULL)
7515 	XP_ERROR(XPATH_INVALID_OPERAND);
7516     arg2 = xmlXPathCastToNumber(arg);
7517     xmlXPathReleaseObject(ctxt->context, arg);
7518     CAST_TO_NUMBER;
7519     CHECK_TYPE(XPATH_NUMBER);
7520     arg1 = ctxt->value->floatval;
7521     if (arg2 == 0)
7522 	ctxt->value->floatval = xmlXPathNAN;
7523     else {
7524 	ctxt->value->floatval = fmod(arg1, arg2);
7525     }
7526 }
7527 
7528 /************************************************************************
7529  *									*
7530  *		The traversal functions					*
7531  *									*
7532  ************************************************************************/
7533 
7534 /*
7535  * A traversal function enumerates nodes along an axis.
7536  * Initially it must be called with NULL, and it indicates
7537  * termination on the axis by returning NULL.
7538  */
7539 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7541 
7542 /*
7543  * xmlXPathTraversalFunctionExt:
7544  * A traversal function enumerates nodes along an axis.
7545  * Initially it must be called with NULL, and it indicates
7546  * termination on the axis by returning NULL.
7547  * The context node of the traversal is specified via @contextNode.
7548  */
7549 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550                     (xmlNodePtr cur, xmlNodePtr contextNode);
7551 
7552 /*
7553  * xmlXPathNodeSetMergeFunction:
7554  * Used for merging node sets in xmlXPathCollectAndTest().
7555  */
7556 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7558 
7559 
7560 /**
7561  * xmlXPathNextSelf:
7562  * @ctxt:  the XPath Parser context
7563  * @cur:  the current node in the traversal
7564  *
7565  * Traversal function for the "self" direction
7566  * The self axis contains just the context node itself
7567  *
7568  * Returns the next element following that axis
7569  */
7570 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7571 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7573     if (cur == NULL)
7574         return(ctxt->context->node);
7575     return(NULL);
7576 }
7577 
7578 /**
7579  * xmlXPathNextChild:
7580  * @ctxt:  the XPath Parser context
7581  * @cur:  the current node in the traversal
7582  *
7583  * Traversal function for the "child" direction
7584  * The child axis contains the children of the context node in document order.
7585  *
7586  * Returns the next element following that axis
7587  */
7588 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7589 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7590     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7591     if (cur == NULL) {
7592 	if (ctxt->context->node == NULL) return(NULL);
7593 	switch (ctxt->context->node->type) {
7594             case XML_ELEMENT_NODE:
7595             case XML_TEXT_NODE:
7596             case XML_CDATA_SECTION_NODE:
7597             case XML_ENTITY_REF_NODE:
7598             case XML_ENTITY_NODE:
7599             case XML_PI_NODE:
7600             case XML_COMMENT_NODE:
7601             case XML_NOTATION_NODE:
7602             case XML_DTD_NODE:
7603 		return(ctxt->context->node->children);
7604             case XML_DOCUMENT_NODE:
7605             case XML_DOCUMENT_TYPE_NODE:
7606             case XML_DOCUMENT_FRAG_NODE:
7607             case XML_HTML_DOCUMENT_NODE:
7608 #ifdef LIBXML_DOCB_ENABLED
7609 	    case XML_DOCB_DOCUMENT_NODE:
7610 #endif
7611 		return(((xmlDocPtr) ctxt->context->node)->children);
7612 	    case XML_ELEMENT_DECL:
7613 	    case XML_ATTRIBUTE_DECL:
7614 	    case XML_ENTITY_DECL:
7615             case XML_ATTRIBUTE_NODE:
7616 	    case XML_NAMESPACE_DECL:
7617 	    case XML_XINCLUDE_START:
7618 	    case XML_XINCLUDE_END:
7619 		return(NULL);
7620 	}
7621 	return(NULL);
7622     }
7623     if ((cur->type == XML_DOCUMENT_NODE) ||
7624         (cur->type == XML_HTML_DOCUMENT_NODE))
7625 	return(NULL);
7626     return(cur->next);
7627 }
7628 
7629 /**
7630  * xmlXPathNextChildElement:
7631  * @ctxt:  the XPath Parser context
7632  * @cur:  the current node in the traversal
7633  *
7634  * Traversal function for the "child" direction and nodes of type element.
7635  * The child axis contains the children of the context node in document order.
7636  *
7637  * Returns the next element following that axis
7638  */
7639 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7640 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642     if (cur == NULL) {
7643 	cur = ctxt->context->node;
7644 	if (cur == NULL) return(NULL);
7645 	/*
7646 	* Get the first element child.
7647 	*/
7648 	switch (cur->type) {
7649             case XML_ELEMENT_NODE:
7650 	    case XML_DOCUMENT_FRAG_NODE:
7651 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652             case XML_ENTITY_NODE:
7653 		cur = cur->children;
7654 		if (cur != NULL) {
7655 		    if (cur->type == XML_ELEMENT_NODE)
7656 			return(cur);
7657 		    do {
7658 			cur = cur->next;
7659 		    } while ((cur != NULL) &&
7660 			(cur->type != XML_ELEMENT_NODE));
7661 		    return(cur);
7662 		}
7663 		return(NULL);
7664             case XML_DOCUMENT_NODE:
7665             case XML_HTML_DOCUMENT_NODE:
7666 #ifdef LIBXML_DOCB_ENABLED
7667 	    case XML_DOCB_DOCUMENT_NODE:
7668 #endif
7669 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7670 	    default:
7671 		return(NULL);
7672 	}
7673 	return(NULL);
7674     }
7675     /*
7676     * Get the next sibling element node.
7677     */
7678     switch (cur->type) {
7679 	case XML_ELEMENT_NODE:
7680 	case XML_TEXT_NODE:
7681 	case XML_ENTITY_REF_NODE:
7682 	case XML_ENTITY_NODE:
7683 	case XML_CDATA_SECTION_NODE:
7684 	case XML_PI_NODE:
7685 	case XML_COMMENT_NODE:
7686 	case XML_XINCLUDE_END:
7687 	    break;
7688 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7689 	default:
7690 	    return(NULL);
7691     }
7692     if (cur->next != NULL) {
7693 	if (cur->next->type == XML_ELEMENT_NODE)
7694 	    return(cur->next);
7695 	cur = cur->next;
7696 	do {
7697 	    cur = cur->next;
7698 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7699 	return(cur);
7700     }
7701     return(NULL);
7702 }
7703 
7704 /**
7705  * xmlXPathNextDescendantOrSelfElemParent:
7706  * @ctxt:  the XPath Parser context
7707  * @cur:  the current node in the traversal
7708  *
7709  * Traversal function for the "descendant-or-self" axis.
7710  * Additionally it returns only nodes which can be parents of
7711  * element nodes.
7712  *
7713  *
7714  * Returns the next element following that axis
7715  */
7716 static xmlNodePtr
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,xmlNodePtr contextNode)7717 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718 				       xmlNodePtr contextNode)
7719 {
7720     if (cur == NULL) {
7721 	if (contextNode == NULL)
7722 	    return(NULL);
7723 	switch (contextNode->type) {
7724 	    case XML_ELEMENT_NODE:
7725 	    case XML_XINCLUDE_START:
7726 	    case XML_DOCUMENT_FRAG_NODE:
7727 	    case XML_DOCUMENT_NODE:
7728 #ifdef LIBXML_DOCB_ENABLED
7729 	    case XML_DOCB_DOCUMENT_NODE:
7730 #endif
7731 	    case XML_HTML_DOCUMENT_NODE:
7732 		return(contextNode);
7733 	    default:
7734 		return(NULL);
7735 	}
7736 	return(NULL);
7737     } else {
7738 	xmlNodePtr start = cur;
7739 
7740 	while (cur != NULL) {
7741 	    switch (cur->type) {
7742 		case XML_ELEMENT_NODE:
7743 		/* TODO: OK to have XInclude here? */
7744 		case XML_XINCLUDE_START:
7745 		case XML_DOCUMENT_FRAG_NODE:
7746 		    if (cur != start)
7747 			return(cur);
7748 		    if (cur->children != NULL) {
7749 			cur = cur->children;
7750 			continue;
7751 		    }
7752 		    break;
7753 		/* Not sure if we need those here. */
7754 		case XML_DOCUMENT_NODE:
7755 #ifdef LIBXML_DOCB_ENABLED
7756 		case XML_DOCB_DOCUMENT_NODE:
7757 #endif
7758 		case XML_HTML_DOCUMENT_NODE:
7759 		    if (cur != start)
7760 			return(cur);
7761 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7762 		default:
7763 		    break;
7764 	    }
7765 
7766 next_sibling:
7767 	    if ((cur == NULL) || (cur == contextNode))
7768 		return(NULL);
7769 	    if (cur->next != NULL) {
7770 		cur = cur->next;
7771 	    } else {
7772 		cur = cur->parent;
7773 		goto next_sibling;
7774 	    }
7775 	}
7776     }
7777     return(NULL);
7778 }
7779 
7780 /**
7781  * xmlXPathNextDescendant:
7782  * @ctxt:  the XPath Parser context
7783  * @cur:  the current node in the traversal
7784  *
7785  * Traversal function for the "descendant" direction
7786  * the descendant axis contains the descendants of the context node in document
7787  * order; a descendant is a child or a child of a child and so on.
7788  *
7789  * Returns the next element following that axis
7790  */
7791 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7792 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7794     if (cur == NULL) {
7795 	if (ctxt->context->node == NULL)
7796 	    return(NULL);
7797 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799 	    return(NULL);
7800 
7801         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802 	    return(ctxt->context->doc->children);
7803         return(ctxt->context->node->children);
7804     }
7805 
7806     if (cur->children != NULL) {
7807 	/*
7808 	 * Do not descend on entities declarations
7809 	 */
7810 	if (cur->children->type != XML_ENTITY_DECL) {
7811 	    cur = cur->children;
7812 	    /*
7813 	     * Skip DTDs
7814 	     */
7815 	    if (cur->type != XML_DTD_NODE)
7816 		return(cur);
7817 	}
7818     }
7819 
7820     if (cur == ctxt->context->node) return(NULL);
7821 
7822     while (cur->next != NULL) {
7823 	cur = cur->next;
7824 	if ((cur->type != XML_ENTITY_DECL) &&
7825 	    (cur->type != XML_DTD_NODE))
7826 	    return(cur);
7827     }
7828 
7829     do {
7830         cur = cur->parent;
7831 	if (cur == NULL) break;
7832 	if (cur == ctxt->context->node) return(NULL);
7833 	if (cur->next != NULL) {
7834 	    cur = cur->next;
7835 	    return(cur);
7836 	}
7837     } while (cur != NULL);
7838     return(cur);
7839 }
7840 
7841 /**
7842  * xmlXPathNextDescendantOrSelf:
7843  * @ctxt:  the XPath Parser context
7844  * @cur:  the current node in the traversal
7845  *
7846  * Traversal function for the "descendant-or-self" direction
7847  * the descendant-or-self axis contains the context node and the descendants
7848  * of the context node in document order; thus the context node is the first
7849  * node on the axis, and the first child of the context node is the second node
7850  * on the axis
7851  *
7852  * Returns the next element following that axis
7853  */
7854 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7855 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7856     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7857     if (cur == NULL) {
7858 	if (ctxt->context->node == NULL)
7859 	    return(NULL);
7860 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7862 	    return(NULL);
7863         return(ctxt->context->node);
7864     }
7865 
7866     return(xmlXPathNextDescendant(ctxt, cur));
7867 }
7868 
7869 /**
7870  * xmlXPathNextParent:
7871  * @ctxt:  the XPath Parser context
7872  * @cur:  the current node in the traversal
7873  *
7874  * Traversal function for the "parent" direction
7875  * The parent axis contains the parent of the context node, if there is one.
7876  *
7877  * Returns the next element following that axis
7878  */
7879 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7880 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7881     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7882     /*
7883      * the parent of an attribute or namespace node is the element
7884      * to which the attribute or namespace node is attached
7885      * Namespace handling !!!
7886      */
7887     if (cur == NULL) {
7888 	if (ctxt->context->node == NULL) return(NULL);
7889 	switch (ctxt->context->node->type) {
7890             case XML_ELEMENT_NODE:
7891             case XML_TEXT_NODE:
7892             case XML_CDATA_SECTION_NODE:
7893             case XML_ENTITY_REF_NODE:
7894             case XML_ENTITY_NODE:
7895             case XML_PI_NODE:
7896             case XML_COMMENT_NODE:
7897             case XML_NOTATION_NODE:
7898             case XML_DTD_NODE:
7899 	    case XML_ELEMENT_DECL:
7900 	    case XML_ATTRIBUTE_DECL:
7901 	    case XML_XINCLUDE_START:
7902 	    case XML_XINCLUDE_END:
7903 	    case XML_ENTITY_DECL:
7904 		if (ctxt->context->node->parent == NULL)
7905 		    return((xmlNodePtr) ctxt->context->doc);
7906 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7907 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7908 		     (xmlStrEqual(ctxt->context->node->parent->name,
7909 				 BAD_CAST "fake node libxslt"))))
7910 		    return(NULL);
7911 		return(ctxt->context->node->parent);
7912             case XML_ATTRIBUTE_NODE: {
7913 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7914 
7915 		return(att->parent);
7916 	    }
7917             case XML_DOCUMENT_NODE:
7918             case XML_DOCUMENT_TYPE_NODE:
7919             case XML_DOCUMENT_FRAG_NODE:
7920             case XML_HTML_DOCUMENT_NODE:
7921 #ifdef LIBXML_DOCB_ENABLED
7922 	    case XML_DOCB_DOCUMENT_NODE:
7923 #endif
7924                 return(NULL);
7925 	    case XML_NAMESPACE_DECL: {
7926 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7927 
7928 		if ((ns->next != NULL) &&
7929 		    (ns->next->type != XML_NAMESPACE_DECL))
7930 		    return((xmlNodePtr) ns->next);
7931                 return(NULL);
7932 	    }
7933 	}
7934     }
7935     return(NULL);
7936 }
7937 
7938 /**
7939  * xmlXPathNextAncestor:
7940  * @ctxt:  the XPath Parser context
7941  * @cur:  the current node in the traversal
7942  *
7943  * Traversal function for the "ancestor" direction
7944  * the ancestor axis contains the ancestors of the context node; the ancestors
7945  * of the context node consist of the parent of context node and the parent's
7946  * parent and so on; the nodes are ordered in reverse document order; thus the
7947  * parent is the first node on the axis, and the parent's parent is the second
7948  * node on the axis
7949  *
7950  * Returns the next element following that axis
7951  */
7952 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7953 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955     /*
7956      * the parent of an attribute or namespace node is the element
7957      * to which the attribute or namespace node is attached
7958      * !!!!!!!!!!!!!
7959      */
7960     if (cur == NULL) {
7961 	if (ctxt->context->node == NULL) return(NULL);
7962 	switch (ctxt->context->node->type) {
7963             case XML_ELEMENT_NODE:
7964             case XML_TEXT_NODE:
7965             case XML_CDATA_SECTION_NODE:
7966             case XML_ENTITY_REF_NODE:
7967             case XML_ENTITY_NODE:
7968             case XML_PI_NODE:
7969             case XML_COMMENT_NODE:
7970 	    case XML_DTD_NODE:
7971 	    case XML_ELEMENT_DECL:
7972 	    case XML_ATTRIBUTE_DECL:
7973 	    case XML_ENTITY_DECL:
7974             case XML_NOTATION_NODE:
7975 	    case XML_XINCLUDE_START:
7976 	    case XML_XINCLUDE_END:
7977 		if (ctxt->context->node->parent == NULL)
7978 		    return((xmlNodePtr) ctxt->context->doc);
7979 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7981 		     (xmlStrEqual(ctxt->context->node->parent->name,
7982 				 BAD_CAST "fake node libxslt"))))
7983 		    return(NULL);
7984 		return(ctxt->context->node->parent);
7985             case XML_ATTRIBUTE_NODE: {
7986 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7987 
7988 		return(tmp->parent);
7989 	    }
7990             case XML_DOCUMENT_NODE:
7991             case XML_DOCUMENT_TYPE_NODE:
7992             case XML_DOCUMENT_FRAG_NODE:
7993             case XML_HTML_DOCUMENT_NODE:
7994 #ifdef LIBXML_DOCB_ENABLED
7995 	    case XML_DOCB_DOCUMENT_NODE:
7996 #endif
7997                 return(NULL);
7998 	    case XML_NAMESPACE_DECL: {
7999 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000 
8001 		if ((ns->next != NULL) &&
8002 		    (ns->next->type != XML_NAMESPACE_DECL))
8003 		    return((xmlNodePtr) ns->next);
8004 		/* Bad, how did that namespace end up here ? */
8005                 return(NULL);
8006 	    }
8007 	}
8008 	return(NULL);
8009     }
8010     if (cur == ctxt->context->doc->children)
8011 	return((xmlNodePtr) ctxt->context->doc);
8012     if (cur == (xmlNodePtr) ctxt->context->doc)
8013 	return(NULL);
8014     switch (cur->type) {
8015 	case XML_ELEMENT_NODE:
8016 	case XML_TEXT_NODE:
8017 	case XML_CDATA_SECTION_NODE:
8018 	case XML_ENTITY_REF_NODE:
8019 	case XML_ENTITY_NODE:
8020 	case XML_PI_NODE:
8021 	case XML_COMMENT_NODE:
8022 	case XML_NOTATION_NODE:
8023 	case XML_DTD_NODE:
8024         case XML_ELEMENT_DECL:
8025         case XML_ATTRIBUTE_DECL:
8026         case XML_ENTITY_DECL:
8027 	case XML_XINCLUDE_START:
8028 	case XML_XINCLUDE_END:
8029 	    if (cur->parent == NULL)
8030 		return(NULL);
8031 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8032 		((cur->parent->name[0] == ' ') ||
8033 		 (xmlStrEqual(cur->parent->name,
8034 			      BAD_CAST "fake node libxslt"))))
8035 		return(NULL);
8036 	    return(cur->parent);
8037 	case XML_ATTRIBUTE_NODE: {
8038 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8039 
8040 	    return(att->parent);
8041 	}
8042 	case XML_NAMESPACE_DECL: {
8043 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8044 
8045 	    if ((ns->next != NULL) &&
8046 	        (ns->next->type != XML_NAMESPACE_DECL))
8047 	        return((xmlNodePtr) ns->next);
8048 	    /* Bad, how did that namespace end up here ? */
8049             return(NULL);
8050 	}
8051 	case XML_DOCUMENT_NODE:
8052 	case XML_DOCUMENT_TYPE_NODE:
8053 	case XML_DOCUMENT_FRAG_NODE:
8054 	case XML_HTML_DOCUMENT_NODE:
8055 #ifdef LIBXML_DOCB_ENABLED
8056 	case XML_DOCB_DOCUMENT_NODE:
8057 #endif
8058 	    return(NULL);
8059     }
8060     return(NULL);
8061 }
8062 
8063 /**
8064  * xmlXPathNextAncestorOrSelf:
8065  * @ctxt:  the XPath Parser context
8066  * @cur:  the current node in the traversal
8067  *
8068  * Traversal function for the "ancestor-or-self" direction
8069  * he ancestor-or-self axis contains the context node and ancestors of
8070  * the context node in reverse document order; thus the context node is
8071  * the first node on the axis, and the context node's parent the second;
8072  * parent here is defined the same as with the parent axis.
8073  *
8074  * Returns the next element following that axis
8075  */
8076 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8077 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8079     if (cur == NULL)
8080         return(ctxt->context->node);
8081     return(xmlXPathNextAncestor(ctxt, cur));
8082 }
8083 
8084 /**
8085  * xmlXPathNextFollowingSibling:
8086  * @ctxt:  the XPath Parser context
8087  * @cur:  the current node in the traversal
8088  *
8089  * Traversal function for the "following-sibling" direction
8090  * The following-sibling axis contains the following siblings of the context
8091  * node in document order.
8092  *
8093  * Returns the next element following that axis
8094  */
8095 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8096 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8097     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8098     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8100 	return(NULL);
8101     if (cur == (xmlNodePtr) ctxt->context->doc)
8102         return(NULL);
8103     if (cur == NULL)
8104         return(ctxt->context->node->next);
8105     return(cur->next);
8106 }
8107 
8108 /**
8109  * xmlXPathNextPrecedingSibling:
8110  * @ctxt:  the XPath Parser context
8111  * @cur:  the current node in the traversal
8112  *
8113  * Traversal function for the "preceding-sibling" direction
8114  * The preceding-sibling axis contains the preceding siblings of the context
8115  * node in reverse document order; the first preceding sibling is first on the
8116  * axis; the sibling preceding that node is the second on the axis and so on.
8117  *
8118  * Returns the next element following that axis
8119  */
8120 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8121 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8122     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8123     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8125 	return(NULL);
8126     if (cur == (xmlNodePtr) ctxt->context->doc)
8127         return(NULL);
8128     if (cur == NULL)
8129         return(ctxt->context->node->prev);
8130     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8131 	cur = cur->prev;
8132 	if (cur == NULL)
8133 	    return(ctxt->context->node->prev);
8134     }
8135     return(cur->prev);
8136 }
8137 
8138 /**
8139  * xmlXPathNextFollowing:
8140  * @ctxt:  the XPath Parser context
8141  * @cur:  the current node in the traversal
8142  *
8143  * Traversal function for the "following" direction
8144  * The following axis contains all nodes in the same document as the context
8145  * node that are after the context node in document order, excluding any
8146  * descendants and excluding attribute nodes and namespace nodes; the nodes
8147  * are ordered in document order
8148  *
8149  * Returns the next element following that axis
8150  */
8151 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8152 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8155         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156         return(cur->children);
8157 
8158     if (cur == NULL) {
8159         cur = ctxt->context->node;
8160         if (cur->type == XML_NAMESPACE_DECL)
8161             return(NULL);
8162         if (cur->type == XML_ATTRIBUTE_NODE)
8163             cur = cur->parent;
8164     }
8165     if (cur == NULL) return(NULL) ; /* ERROR */
8166     if (cur->next != NULL) return(cur->next) ;
8167     do {
8168         cur = cur->parent;
8169         if (cur == NULL) break;
8170         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171         if (cur->next != NULL) return(cur->next);
8172     } while (cur != NULL);
8173     return(cur);
8174 }
8175 
8176 /*
8177  * xmlXPathIsAncestor:
8178  * @ancestor:  the ancestor node
8179  * @node:  the current node
8180  *
8181  * Check that @ancestor is a @node's ancestor
8182  *
8183  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8184  */
8185 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8186 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187     if ((ancestor == NULL) || (node == NULL)) return(0);
8188     /* nodes need to be in the same document */
8189     if (ancestor->doc != node->doc) return(0);
8190     /* avoid searching if ancestor or node is the root node */
8191     if (ancestor == (xmlNodePtr) node->doc) return(1);
8192     if (node == (xmlNodePtr) ancestor->doc) return(0);
8193     while (node->parent != NULL) {
8194         if (node->parent == ancestor)
8195             return(1);
8196 	node = node->parent;
8197     }
8198     return(0);
8199 }
8200 
8201 /**
8202  * xmlXPathNextPreceding:
8203  * @ctxt:  the XPath Parser context
8204  * @cur:  the current node in the traversal
8205  *
8206  * Traversal function for the "preceding" direction
8207  * the preceding axis contains all nodes in the same document as the context
8208  * node that are before the context node in document order, excluding any
8209  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210  * ordered in reverse document order
8211  *
8212  * Returns the next element following that axis
8213  */
8214 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8215 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8216 {
8217     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8218     if (cur == NULL) {
8219         cur = ctxt->context->node;
8220         if (cur->type == XML_NAMESPACE_DECL)
8221             return(NULL);
8222         if (cur->type == XML_ATTRIBUTE_NODE)
8223             return(cur->parent);
8224     }
8225     if (cur == NULL)
8226 	return (NULL);
8227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228 	cur = cur->prev;
8229     do {
8230         if (cur->prev != NULL) {
8231             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8232             return (cur);
8233         }
8234 
8235         cur = cur->parent;
8236         if (cur == NULL)
8237             return (NULL);
8238         if (cur == ctxt->context->doc->children)
8239             return (NULL);
8240     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8241     return (cur);
8242 }
8243 
8244 /**
8245  * xmlXPathNextPrecedingInternal:
8246  * @ctxt:  the XPath Parser context
8247  * @cur:  the current node in the traversal
8248  *
8249  * Traversal function for the "preceding" direction
8250  * the preceding axis contains all nodes in the same document as the context
8251  * node that are before the context node in document order, excluding any
8252  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253  * ordered in reverse document order
8254  * This is a faster implementation but internal only since it requires a
8255  * state kept in the parser context: ctxt->ancestor.
8256  *
8257  * Returns the next element following that axis
8258  */
8259 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8260 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8261                               xmlNodePtr cur)
8262 {
8263     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8264     if (cur == NULL) {
8265         cur = ctxt->context->node;
8266         if (cur == NULL)
8267             return (NULL);
8268         if (cur->type == XML_NAMESPACE_DECL)
8269             return (NULL);
8270         ctxt->ancestor = cur->parent;
8271     }
8272     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8273 	cur = cur->prev;
8274     while (cur->prev == NULL) {
8275         cur = cur->parent;
8276         if (cur == NULL)
8277             return (NULL);
8278         if (cur == ctxt->context->doc->children)
8279             return (NULL);
8280         if (cur != ctxt->ancestor)
8281             return (cur);
8282         ctxt->ancestor = cur->parent;
8283     }
8284     cur = cur->prev;
8285     while (cur->last != NULL)
8286         cur = cur->last;
8287     return (cur);
8288 }
8289 
8290 /**
8291  * xmlXPathNextNamespace:
8292  * @ctxt:  the XPath Parser context
8293  * @cur:  the current attribute in the traversal
8294  *
8295  * Traversal function for the "namespace" direction
8296  * the namespace axis contains the namespace nodes of the context node;
8297  * the order of nodes on this axis is implementation-defined; the axis will
8298  * be empty unless the context node is an element
8299  *
8300  * We keep the XML namespace node at the end of the list.
8301  *
8302  * Returns the next element following that axis
8303  */
8304 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8305 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8306     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8307     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8308     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8309         if (ctxt->context->tmpNsList != NULL)
8310 	    xmlFree(ctxt->context->tmpNsList);
8311 	ctxt->context->tmpNsList =
8312 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8313 	ctxt->context->tmpNsNr = 0;
8314 	if (ctxt->context->tmpNsList != NULL) {
8315 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316 		ctxt->context->tmpNsNr++;
8317 	    }
8318 	}
8319 	return((xmlNodePtr) xmlXPathXMLNamespace);
8320     }
8321     if (ctxt->context->tmpNsNr > 0) {
8322 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8323     } else {
8324 	if (ctxt->context->tmpNsList != NULL)
8325 	    xmlFree(ctxt->context->tmpNsList);
8326 	ctxt->context->tmpNsList = NULL;
8327 	return(NULL);
8328     }
8329 }
8330 
8331 /**
8332  * xmlXPathNextAttribute:
8333  * @ctxt:  the XPath Parser context
8334  * @cur:  the current attribute in the traversal
8335  *
8336  * Traversal function for the "attribute" direction
8337  * TODO: support DTD inherited default attributes
8338  *
8339  * Returns the next element following that axis
8340  */
8341 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8342 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8343     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8344     if (ctxt->context->node == NULL)
8345 	return(NULL);
8346     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8347 	return(NULL);
8348     if (cur == NULL) {
8349         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8350 	    return(NULL);
8351         return((xmlNodePtr)ctxt->context->node->properties);
8352     }
8353     return((xmlNodePtr)cur->next);
8354 }
8355 
8356 /************************************************************************
8357  *									*
8358  *		NodeTest Functions					*
8359  *									*
8360  ************************************************************************/
8361 
8362 #define IS_FUNCTION			200
8363 
8364 
8365 /************************************************************************
8366  *									*
8367  *		Implicit tree core function library			*
8368  *									*
8369  ************************************************************************/
8370 
8371 /**
8372  * xmlXPathRoot:
8373  * @ctxt:  the XPath Parser context
8374  *
8375  * Initialize the context to the root of the document
8376  */
8377 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8378 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8379     if ((ctxt == NULL) || (ctxt->context == NULL))
8380 	return;
8381     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8382     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383 	ctxt->context->node));
8384 }
8385 
8386 /************************************************************************
8387  *									*
8388  *		The explicit core function library			*
8389  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8390  *									*
8391  ************************************************************************/
8392 
8393 
8394 /**
8395  * xmlXPathLastFunction:
8396  * @ctxt:  the XPath Parser context
8397  * @nargs:  the number of arguments
8398  *
8399  * Implement the last() XPath function
8400  *    number last()
8401  * The last function returns the number of nodes in the context node list.
8402  */
8403 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8404 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8405     CHECK_ARITY(0);
8406     if (ctxt->context->contextSize >= 0) {
8407 	valuePush(ctxt,
8408 	    xmlXPathCacheNewFloat(ctxt->context,
8409 		(double) ctxt->context->contextSize));
8410 #ifdef DEBUG_EXPR
8411 	xmlGenericError(xmlGenericErrorContext,
8412 		"last() : %d\n", ctxt->context->contextSize);
8413 #endif
8414     } else {
8415 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8416     }
8417 }
8418 
8419 /**
8420  * xmlXPathPositionFunction:
8421  * @ctxt:  the XPath Parser context
8422  * @nargs:  the number of arguments
8423  *
8424  * Implement the position() XPath function
8425  *    number position()
8426  * The position function returns the position of the context node in the
8427  * context node list. The first position is 1, and so the last position
8428  * will be equal to last().
8429  */
8430 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8431 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8432     CHECK_ARITY(0);
8433     if (ctxt->context->proximityPosition >= 0) {
8434 	valuePush(ctxt,
8435 	      xmlXPathCacheNewFloat(ctxt->context,
8436 		(double) ctxt->context->proximityPosition));
8437 #ifdef DEBUG_EXPR
8438 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439 		ctxt->context->proximityPosition);
8440 #endif
8441     } else {
8442 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8443     }
8444 }
8445 
8446 /**
8447  * xmlXPathCountFunction:
8448  * @ctxt:  the XPath Parser context
8449  * @nargs:  the number of arguments
8450  *
8451  * Implement the count() XPath function
8452  *    number count(node-set)
8453  */
8454 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8455 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456     xmlXPathObjectPtr cur;
8457 
8458     CHECK_ARITY(1);
8459     if ((ctxt->value == NULL) ||
8460 	((ctxt->value->type != XPATH_NODESET) &&
8461 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8462 	XP_ERROR(XPATH_INVALID_TYPE);
8463     cur = valuePop(ctxt);
8464 
8465     if ((cur == NULL) || (cur->nodesetval == NULL))
8466 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8467     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8468 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469 	    (double) cur->nodesetval->nodeNr));
8470     } else {
8471 	if ((cur->nodesetval->nodeNr != 1) ||
8472 	    (cur->nodesetval->nodeTab == NULL)) {
8473 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8474 	} else {
8475 	    xmlNodePtr tmp;
8476 	    int i = 0;
8477 
8478 	    tmp = cur->nodesetval->nodeTab[0];
8479 	    if (tmp != NULL) {
8480 		tmp = tmp->children;
8481 		while (tmp != NULL) {
8482 		    tmp = tmp->next;
8483 		    i++;
8484 		}
8485 	    }
8486 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8487 	}
8488     }
8489     xmlXPathReleaseObject(ctxt->context, cur);
8490 }
8491 
8492 /**
8493  * xmlXPathGetElementsByIds:
8494  * @doc:  the document
8495  * @ids:  a whitespace separated list of IDs
8496  *
8497  * Selects elements by their unique ID.
8498  *
8499  * Returns a node-set of selected elements.
8500  */
8501 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8502 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8503     xmlNodeSetPtr ret;
8504     const xmlChar *cur = ids;
8505     xmlChar *ID;
8506     xmlAttrPtr attr;
8507     xmlNodePtr elem = NULL;
8508 
8509     if (ids == NULL) return(NULL);
8510 
8511     ret = xmlXPathNodeSetCreate(NULL);
8512     if (ret == NULL)
8513         return(ret);
8514 
8515     while (IS_BLANK_CH(*cur)) cur++;
8516     while (*cur != 0) {
8517 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8518 	    cur++;
8519 
8520         ID = xmlStrndup(ids, cur - ids);
8521 	if (ID != NULL) {
8522 	    /*
8523 	     * We used to check the fact that the value passed
8524 	     * was an NCName, but this generated much troubles for
8525 	     * me and Aleksey Sanin, people blatantly violated that
8526 	     * constaint, like Visa3D spec.
8527 	     * if (xmlValidateNCName(ID, 1) == 0)
8528 	     */
8529 	    attr = xmlGetID(doc, ID);
8530 	    if (attr != NULL) {
8531 		if (attr->type == XML_ATTRIBUTE_NODE)
8532 		    elem = attr->parent;
8533 		else if (attr->type == XML_ELEMENT_NODE)
8534 		    elem = (xmlNodePtr) attr;
8535 		else
8536 		    elem = NULL;
8537 		if (elem != NULL)
8538 		    xmlXPathNodeSetAdd(ret, elem);
8539 	    }
8540 	    xmlFree(ID);
8541 	}
8542 
8543 	while (IS_BLANK_CH(*cur)) cur++;
8544 	ids = cur;
8545     }
8546     return(ret);
8547 }
8548 
8549 /**
8550  * xmlXPathIdFunction:
8551  * @ctxt:  the XPath Parser context
8552  * @nargs:  the number of arguments
8553  *
8554  * Implement the id() XPath function
8555  *    node-set id(object)
8556  * The id function selects elements by their unique ID
8557  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558  * then the result is the union of the result of applying id to the
8559  * string value of each of the nodes in the argument node-set. When the
8560  * argument to id is of any other type, the argument is converted to a
8561  * string as if by a call to the string function; the string is split
8562  * into a whitespace-separated list of tokens (whitespace is any sequence
8563  * of characters matching the production S); the result is a node-set
8564  * containing the elements in the same document as the context node that
8565  * have a unique ID equal to any of the tokens in the list.
8566  */
8567 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8568 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569     xmlChar *tokens;
8570     xmlNodeSetPtr ret;
8571     xmlXPathObjectPtr obj;
8572 
8573     CHECK_ARITY(1);
8574     obj = valuePop(ctxt);
8575     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8576     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8577 	xmlNodeSetPtr ns;
8578 	int i;
8579 
8580 	ret = xmlXPathNodeSetCreate(NULL);
8581         /*
8582          * FIXME -- in an out-of-memory condition this will behave badly.
8583          * The solution is not clear -- we already popped an item from
8584          * ctxt, so the object is in a corrupt state.
8585          */
8586 
8587 	if (obj->nodesetval != NULL) {
8588 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8589 		tokens =
8590 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592 		ret = xmlXPathNodeSetMerge(ret, ns);
8593 		xmlXPathFreeNodeSet(ns);
8594 		if (tokens != NULL)
8595 		    xmlFree(tokens);
8596 	    }
8597 	}
8598 	xmlXPathReleaseObject(ctxt->context, obj);
8599 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8600 	return;
8601     }
8602     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8603     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8604     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8605     xmlXPathReleaseObject(ctxt->context, obj);
8606     return;
8607 }
8608 
8609 /**
8610  * xmlXPathLocalNameFunction:
8611  * @ctxt:  the XPath Parser context
8612  * @nargs:  the number of arguments
8613  *
8614  * Implement the local-name() XPath function
8615  *    string local-name(node-set?)
8616  * The local-name function returns a string containing the local part
8617  * of the name of the node in the argument node-set that is first in
8618  * document order. If the node-set is empty or the first node has no
8619  * name, an empty string is returned. If the argument is omitted it
8620  * defaults to the context node.
8621  */
8622 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8623 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624     xmlXPathObjectPtr cur;
8625 
8626     if (ctxt == NULL) return;
8627 
8628     if (nargs == 0) {
8629 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630 	    ctxt->context->node));
8631 	nargs = 1;
8632     }
8633 
8634     CHECK_ARITY(1);
8635     if ((ctxt->value == NULL) ||
8636 	((ctxt->value->type != XPATH_NODESET) &&
8637 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8638 	XP_ERROR(XPATH_INVALID_TYPE);
8639     cur = valuePop(ctxt);
8640 
8641     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643     } else {
8644 	int i = 0; /* Should be first in document order !!!!! */
8645 	switch (cur->nodesetval->nodeTab[i]->type) {
8646 	case XML_ELEMENT_NODE:
8647 	case XML_ATTRIBUTE_NODE:
8648 	case XML_PI_NODE:
8649 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8650 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8651 	    else
8652 		valuePush(ctxt,
8653 		      xmlXPathCacheNewString(ctxt->context,
8654 			cur->nodesetval->nodeTab[i]->name));
8655 	    break;
8656 	case XML_NAMESPACE_DECL:
8657 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8658 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8659 	    break;
8660 	default:
8661 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8662 	}
8663     }
8664     xmlXPathReleaseObject(ctxt->context, cur);
8665 }
8666 
8667 /**
8668  * xmlXPathNamespaceURIFunction:
8669  * @ctxt:  the XPath Parser context
8670  * @nargs:  the number of arguments
8671  *
8672  * Implement the namespace-uri() XPath function
8673  *    string namespace-uri(node-set?)
8674  * The namespace-uri function returns a string containing the
8675  * namespace URI of the expanded name of the node in the argument
8676  * node-set that is first in document order. If the node-set is empty,
8677  * the first node has no name, or the expanded name has no namespace
8678  * URI, an empty string is returned. If the argument is omitted it
8679  * defaults to the context node.
8680  */
8681 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8682 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683     xmlXPathObjectPtr cur;
8684 
8685     if (ctxt == NULL) return;
8686 
8687     if (nargs == 0) {
8688 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689 	    ctxt->context->node));
8690 	nargs = 1;
8691     }
8692     CHECK_ARITY(1);
8693     if ((ctxt->value == NULL) ||
8694 	((ctxt->value->type != XPATH_NODESET) &&
8695 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8696 	XP_ERROR(XPATH_INVALID_TYPE);
8697     cur = valuePop(ctxt);
8698 
8699     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701     } else {
8702 	int i = 0; /* Should be first in document order !!!!! */
8703 	switch (cur->nodesetval->nodeTab[i]->type) {
8704 	case XML_ELEMENT_NODE:
8705 	case XML_ATTRIBUTE_NODE:
8706 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8707 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8708 	    else
8709 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8710 			  cur->nodesetval->nodeTab[i]->ns->href));
8711 	    break;
8712 	default:
8713 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8714 	}
8715     }
8716     xmlXPathReleaseObject(ctxt->context, cur);
8717 }
8718 
8719 /**
8720  * xmlXPathNameFunction:
8721  * @ctxt:  the XPath Parser context
8722  * @nargs:  the number of arguments
8723  *
8724  * Implement the name() XPath function
8725  *    string name(node-set?)
8726  * The name function returns a string containing a QName representing
8727  * the name of the node in the argument node-set that is first in document
8728  * order. The QName must represent the name with respect to the namespace
8729  * declarations in effect on the node whose name is being represented.
8730  * Typically, this will be the form in which the name occurred in the XML
8731  * source. This need not be the case if there are namespace declarations
8732  * in effect on the node that associate multiple prefixes with the same
8733  * namespace. However, an implementation may include information about
8734  * the original prefix in its representation of nodes; in this case, an
8735  * implementation can ensure that the returned string is always the same
8736  * as the QName used in the XML source. If the argument it omitted it
8737  * defaults to the context node.
8738  * Libxml keep the original prefix so the "real qualified name" used is
8739  * returned.
8740  */
8741 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8742 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8743 {
8744     xmlXPathObjectPtr cur;
8745 
8746     if (nargs == 0) {
8747 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748 	    ctxt->context->node));
8749         nargs = 1;
8750     }
8751 
8752     CHECK_ARITY(1);
8753     if ((ctxt->value == NULL) ||
8754         ((ctxt->value->type != XPATH_NODESET) &&
8755          (ctxt->value->type != XPATH_XSLT_TREE)))
8756         XP_ERROR(XPATH_INVALID_TYPE);
8757     cur = valuePop(ctxt);
8758 
8759     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8760         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8761     } else {
8762         int i = 0;              /* Should be first in document order !!!!! */
8763 
8764         switch (cur->nodesetval->nodeTab[i]->type) {
8765             case XML_ELEMENT_NODE:
8766             case XML_ATTRIBUTE_NODE:
8767 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8768 		    valuePush(ctxt,
8769 			xmlXPathCacheNewCString(ctxt->context, ""));
8770 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8772 		    valuePush(ctxt,
8773 		        xmlXPathCacheNewString(ctxt->context,
8774 			    cur->nodesetval->nodeTab[i]->name));
8775 		} else {
8776 		    xmlChar *fullname;
8777 
8778 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8780 				     NULL, 0);
8781 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8782 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783 		    if (fullname == NULL) {
8784 			XP_ERROR(XPATH_MEMORY_ERROR);
8785 		    }
8786 		    valuePush(ctxt, xmlXPathCacheWrapString(
8787 			ctxt->context, fullname));
8788                 }
8789                 break;
8790             default:
8791 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792 		    cur->nodesetval->nodeTab[i]));
8793                 xmlXPathLocalNameFunction(ctxt, 1);
8794         }
8795     }
8796     xmlXPathReleaseObject(ctxt->context, cur);
8797 }
8798 
8799 
8800 /**
8801  * xmlXPathStringFunction:
8802  * @ctxt:  the XPath Parser context
8803  * @nargs:  the number of arguments
8804  *
8805  * Implement the string() XPath function
8806  *    string string(object?)
8807  * The string function converts an object to a string as follows:
8808  *    - A node-set is converted to a string by returning the value of
8809  *      the node in the node-set that is first in document order.
8810  *      If the node-set is empty, an empty string is returned.
8811  *    - A number is converted to a string as follows
8812  *      + NaN is converted to the string NaN
8813  *      + positive zero is converted to the string 0
8814  *      + negative zero is converted to the string 0
8815  *      + positive infinity is converted to the string Infinity
8816  *      + negative infinity is converted to the string -Infinity
8817  *      + if the number is an integer, the number is represented in
8818  *        decimal form as a Number with no decimal point and no leading
8819  *        zeros, preceded by a minus sign (-) if the number is negative
8820  *      + otherwise, the number is represented in decimal form as a
8821  *        Number including a decimal point with at least one digit
8822  *        before the decimal point and at least one digit after the
8823  *        decimal point, preceded by a minus sign (-) if the number
8824  *        is negative; there must be no leading zeros before the decimal
8825  *        point apart possibly from the one required digit immediately
8826  *        before the decimal point; beyond the one required digit
8827  *        after the decimal point there must be as many, but only as
8828  *        many, more digits as are needed to uniquely distinguish the
8829  *        number from all other IEEE 754 numeric values.
8830  *    - The boolean false value is converted to the string false.
8831  *      The boolean true value is converted to the string true.
8832  *
8833  * If the argument is omitted, it defaults to a node-set with the
8834  * context node as its only member.
8835  */
8836 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8837 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838     xmlXPathObjectPtr cur;
8839 
8840     if (ctxt == NULL) return;
8841     if (nargs == 0) {
8842     valuePush(ctxt,
8843 	xmlXPathCacheWrapString(ctxt->context,
8844 	    xmlXPathCastNodeToString(ctxt->context->node)));
8845 	return;
8846     }
8847 
8848     CHECK_ARITY(1);
8849     cur = valuePop(ctxt);
8850     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8851     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8852 }
8853 
8854 /**
8855  * xmlXPathStringLengthFunction:
8856  * @ctxt:  the XPath Parser context
8857  * @nargs:  the number of arguments
8858  *
8859  * Implement the string-length() XPath function
8860  *    number string-length(string?)
8861  * The string-length returns the number of characters in the string
8862  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863  * the context node converted to a string, in other words the value
8864  * of the context node.
8865  */
8866 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8867 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868     xmlXPathObjectPtr cur;
8869 
8870     if (nargs == 0) {
8871         if ((ctxt == NULL) || (ctxt->context == NULL))
8872 	    return;
8873 	if (ctxt->context->node == NULL) {
8874 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8875 	} else {
8876 	    xmlChar *content;
8877 
8878 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8879 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880 		xmlUTF8Strlen(content)));
8881 	    xmlFree(content);
8882 	}
8883 	return;
8884     }
8885     CHECK_ARITY(1);
8886     CAST_TO_STRING;
8887     CHECK_TYPE(XPATH_STRING);
8888     cur = valuePop(ctxt);
8889     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8890 	xmlUTF8Strlen(cur->stringval)));
8891     xmlXPathReleaseObject(ctxt->context, cur);
8892 }
8893 
8894 /**
8895  * xmlXPathConcatFunction:
8896  * @ctxt:  the XPath Parser context
8897  * @nargs:  the number of arguments
8898  *
8899  * Implement the concat() XPath function
8900  *    string concat(string, string, string*)
8901  * The concat function returns the concatenation of its arguments.
8902  */
8903 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8904 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905     xmlXPathObjectPtr cur, newobj;
8906     xmlChar *tmp;
8907 
8908     if (ctxt == NULL) return;
8909     if (nargs < 2) {
8910 	CHECK_ARITY(2);
8911     }
8912 
8913     CAST_TO_STRING;
8914     cur = valuePop(ctxt);
8915     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8916 	xmlXPathReleaseObject(ctxt->context, cur);
8917 	return;
8918     }
8919     nargs--;
8920 
8921     while (nargs > 0) {
8922 	CAST_TO_STRING;
8923 	newobj = valuePop(ctxt);
8924 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8925 	    xmlXPathReleaseObject(ctxt->context, newobj);
8926 	    xmlXPathReleaseObject(ctxt->context, cur);
8927 	    XP_ERROR(XPATH_INVALID_TYPE);
8928 	}
8929 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930 	newobj->stringval = cur->stringval;
8931 	cur->stringval = tmp;
8932 	xmlXPathReleaseObject(ctxt->context, newobj);
8933 	nargs--;
8934     }
8935     valuePush(ctxt, cur);
8936 }
8937 
8938 /**
8939  * xmlXPathContainsFunction:
8940  * @ctxt:  the XPath Parser context
8941  * @nargs:  the number of arguments
8942  *
8943  * Implement the contains() XPath function
8944  *    boolean contains(string, string)
8945  * The contains function returns true if the first argument string
8946  * contains the second argument string, and otherwise returns false.
8947  */
8948 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)8949 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950     xmlXPathObjectPtr hay, needle;
8951 
8952     CHECK_ARITY(2);
8953     CAST_TO_STRING;
8954     CHECK_TYPE(XPATH_STRING);
8955     needle = valuePop(ctxt);
8956     CAST_TO_STRING;
8957     hay = valuePop(ctxt);
8958 
8959     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8960 	xmlXPathReleaseObject(ctxt->context, hay);
8961 	xmlXPathReleaseObject(ctxt->context, needle);
8962 	XP_ERROR(XPATH_INVALID_TYPE);
8963     }
8964     if (xmlStrstr(hay->stringval, needle->stringval))
8965 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8966     else
8967 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968     xmlXPathReleaseObject(ctxt->context, hay);
8969     xmlXPathReleaseObject(ctxt->context, needle);
8970 }
8971 
8972 /**
8973  * xmlXPathStartsWithFunction:
8974  * @ctxt:  the XPath Parser context
8975  * @nargs:  the number of arguments
8976  *
8977  * Implement the starts-with() XPath function
8978  *    boolean starts-with(string, string)
8979  * The starts-with function returns true if the first argument string
8980  * starts with the second argument string, and otherwise returns false.
8981  */
8982 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8983 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984     xmlXPathObjectPtr hay, needle;
8985     int n;
8986 
8987     CHECK_ARITY(2);
8988     CAST_TO_STRING;
8989     CHECK_TYPE(XPATH_STRING);
8990     needle = valuePop(ctxt);
8991     CAST_TO_STRING;
8992     hay = valuePop(ctxt);
8993 
8994     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8995 	xmlXPathReleaseObject(ctxt->context, hay);
8996 	xmlXPathReleaseObject(ctxt->context, needle);
8997 	XP_ERROR(XPATH_INVALID_TYPE);
8998     }
8999     n = xmlStrlen(needle->stringval);
9000     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9001         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9002     else
9003         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004     xmlXPathReleaseObject(ctxt->context, hay);
9005     xmlXPathReleaseObject(ctxt->context, needle);
9006 }
9007 
9008 /**
9009  * xmlXPathSubstringFunction:
9010  * @ctxt:  the XPath Parser context
9011  * @nargs:  the number of arguments
9012  *
9013  * Implement the substring() XPath function
9014  *    string substring(string, number, number?)
9015  * The substring function returns the substring of the first argument
9016  * starting at the position specified in the second argument with
9017  * length specified in the third argument. For example,
9018  * substring("12345",2,3) returns "234". If the third argument is not
9019  * specified, it returns the substring starting at the position specified
9020  * in the second argument and continuing to the end of the string. For
9021  * example, substring("12345",2) returns "2345".  More precisely, each
9022  * character in the string (see [3.6 Strings]) is considered to have a
9023  * numeric position: the position of the first character is 1, the position
9024  * of the second character is 2 and so on. The returned substring contains
9025  * those characters for which the position of the character is greater than
9026  * or equal to the second argument and, if the third argument is specified,
9027  * less than the sum of the second and third arguments; the comparisons
9028  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9029  *  - substring("12345", 1.5, 2.6) returns "234"
9030  *  - substring("12345", 0, 3) returns "12"
9031  *  - substring("12345", 0 div 0, 3) returns ""
9032  *  - substring("12345", 1, 0 div 0) returns ""
9033  *  - substring("12345", -42, 1 div 0) returns "12345"
9034  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9035  */
9036 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9037 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038     xmlXPathObjectPtr str, start, len;
9039     double le=0, in;
9040     int i, l, m;
9041     xmlChar *ret;
9042 
9043     if (nargs < 2) {
9044 	CHECK_ARITY(2);
9045     }
9046     if (nargs > 3) {
9047 	CHECK_ARITY(3);
9048     }
9049     /*
9050      * take care of possible last (position) argument
9051     */
9052     if (nargs == 3) {
9053 	CAST_TO_NUMBER;
9054 	CHECK_TYPE(XPATH_NUMBER);
9055 	len = valuePop(ctxt);
9056 	le = len->floatval;
9057 	xmlXPathReleaseObject(ctxt->context, len);
9058     }
9059 
9060     CAST_TO_NUMBER;
9061     CHECK_TYPE(XPATH_NUMBER);
9062     start = valuePop(ctxt);
9063     in = start->floatval;
9064     xmlXPathReleaseObject(ctxt->context, start);
9065     CAST_TO_STRING;
9066     CHECK_TYPE(XPATH_STRING);
9067     str = valuePop(ctxt);
9068     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9069 
9070     /*
9071      * If last pos not present, calculate last position
9072     */
9073     if (nargs != 3) {
9074 	le = (double)m;
9075 	if (in < 1.0)
9076 	    in = 1.0;
9077     }
9078 
9079     /* Need to check for the special cases where either
9080      * the index is NaN, the length is NaN, or both
9081      * arguments are infinity (relying on Inf + -Inf = NaN)
9082      */
9083     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9084         /*
9085          * To meet the requirements of the spec, the arguments
9086 	 * must be converted to integer format before
9087 	 * initial index calculations are done
9088          *
9089          * First we go to integer form, rounding up
9090 	 * and checking for special cases
9091          */
9092         i = (int) in;
9093         if (((double)i)+0.5 <= in) i++;
9094 
9095 	if (xmlXPathIsInf(le) == 1) {
9096 	    l = m;
9097 	    if (i < 1)
9098 		i = 1;
9099 	}
9100 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9101 	    l = 0;
9102 	else {
9103 	    l = (int) le;
9104 	    if (((double)l)+0.5 <= le) l++;
9105 	}
9106 
9107 	/* Now we normalize inidices */
9108         i -= 1;
9109         l += i;
9110         if (i < 0)
9111             i = 0;
9112         if (l > m)
9113             l = m;
9114 
9115         /* number of chars to copy */
9116         l -= i;
9117 
9118         ret = xmlUTF8Strsub(str->stringval, i, l);
9119     }
9120     else {
9121         ret = NULL;
9122     }
9123     if (ret == NULL)
9124 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9125     else {
9126 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9127 	xmlFree(ret);
9128     }
9129     xmlXPathReleaseObject(ctxt->context, str);
9130 }
9131 
9132 /**
9133  * xmlXPathSubstringBeforeFunction:
9134  * @ctxt:  the XPath Parser context
9135  * @nargs:  the number of arguments
9136  *
9137  * Implement the substring-before() XPath function
9138  *    string substring-before(string, string)
9139  * The substring-before function returns the substring of the first
9140  * argument string that precedes the first occurrence of the second
9141  * argument string in the first argument string, or the empty string
9142  * if the first argument string does not contain the second argument
9143  * string. For example, substring-before("1999/04/01","/") returns 1999.
9144  */
9145 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9146 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147   xmlXPathObjectPtr str;
9148   xmlXPathObjectPtr find;
9149   xmlBufferPtr target;
9150   const xmlChar *point;
9151   int offset;
9152 
9153   CHECK_ARITY(2);
9154   CAST_TO_STRING;
9155   find = valuePop(ctxt);
9156   CAST_TO_STRING;
9157   str = valuePop(ctxt);
9158 
9159   target = xmlBufferCreate();
9160   if (target) {
9161     point = xmlStrstr(str->stringval, find->stringval);
9162     if (point) {
9163       offset = (int)(point - str->stringval);
9164       xmlBufferAdd(target, str->stringval, offset);
9165     }
9166     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167 	xmlBufferContent(target)));
9168     xmlBufferFree(target);
9169   }
9170   xmlXPathReleaseObject(ctxt->context, str);
9171   xmlXPathReleaseObject(ctxt->context, find);
9172 }
9173 
9174 /**
9175  * xmlXPathSubstringAfterFunction:
9176  * @ctxt:  the XPath Parser context
9177  * @nargs:  the number of arguments
9178  *
9179  * Implement the substring-after() XPath function
9180  *    string substring-after(string, string)
9181  * The substring-after function returns the substring of the first
9182  * argument string that follows the first occurrence of the second
9183  * argument string in the first argument string, or the empty stringi
9184  * if the first argument string does not contain the second argument
9185  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186  * and substring-after("1999/04/01","19") returns 99/04/01.
9187  */
9188 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190   xmlXPathObjectPtr str;
9191   xmlXPathObjectPtr find;
9192   xmlBufferPtr target;
9193   const xmlChar *point;
9194   int offset;
9195 
9196   CHECK_ARITY(2);
9197   CAST_TO_STRING;
9198   find = valuePop(ctxt);
9199   CAST_TO_STRING;
9200   str = valuePop(ctxt);
9201 
9202   target = xmlBufferCreate();
9203   if (target) {
9204     point = xmlStrstr(str->stringval, find->stringval);
9205     if (point) {
9206       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207       xmlBufferAdd(target, &str->stringval[offset],
9208 		   xmlStrlen(str->stringval) - offset);
9209     }
9210     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211 	xmlBufferContent(target)));
9212     xmlBufferFree(target);
9213   }
9214   xmlXPathReleaseObject(ctxt->context, str);
9215   xmlXPathReleaseObject(ctxt->context, find);
9216 }
9217 
9218 /**
9219  * xmlXPathNormalizeFunction:
9220  * @ctxt:  the XPath Parser context
9221  * @nargs:  the number of arguments
9222  *
9223  * Implement the normalize-space() XPath function
9224  *    string normalize-space(string?)
9225  * The normalize-space function returns the argument string with white
9226  * space normalized by stripping leading and trailing whitespace
9227  * and replacing sequences of whitespace characters by a single
9228  * space. Whitespace characters are the same allowed by the S production
9229  * in XML. If the argument is omitted, it defaults to the context
9230  * node converted to a string, in other words the value of the context node.
9231  */
9232 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9233 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234   xmlXPathObjectPtr obj = NULL;
9235   xmlChar *source = NULL;
9236   xmlBufferPtr target;
9237   xmlChar blank;
9238 
9239   if (ctxt == NULL) return;
9240   if (nargs == 0) {
9241     /* Use current context node */
9242       valuePush(ctxt,
9243 	  xmlXPathCacheWrapString(ctxt->context,
9244 	    xmlXPathCastNodeToString(ctxt->context->node)));
9245     nargs = 1;
9246   }
9247 
9248   CHECK_ARITY(1);
9249   CAST_TO_STRING;
9250   CHECK_TYPE(XPATH_STRING);
9251   obj = valuePop(ctxt);
9252   source = obj->stringval;
9253 
9254   target = xmlBufferCreate();
9255   if (target && source) {
9256 
9257     /* Skip leading whitespaces */
9258     while (IS_BLANK_CH(*source))
9259       source++;
9260 
9261     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9262     blank = 0;
9263     while (*source) {
9264       if (IS_BLANK_CH(*source)) {
9265 	blank = 0x20;
9266       } else {
9267 	if (blank) {
9268 	  xmlBufferAdd(target, &blank, 1);
9269 	  blank = 0;
9270 	}
9271 	xmlBufferAdd(target, source, 1);
9272       }
9273       source++;
9274     }
9275     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276 	xmlBufferContent(target)));
9277     xmlBufferFree(target);
9278   }
9279   xmlXPathReleaseObject(ctxt->context, obj);
9280 }
9281 
9282 /**
9283  * xmlXPathTranslateFunction:
9284  * @ctxt:  the XPath Parser context
9285  * @nargs:  the number of arguments
9286  *
9287  * Implement the translate() XPath function
9288  *    string translate(string, string, string)
9289  * The translate function returns the first argument string with
9290  * occurrences of characters in the second argument string replaced
9291  * by the character at the corresponding position in the third argument
9292  * string. For example, translate("bar","abc","ABC") returns the string
9293  * BAr. If there is a character in the second argument string with no
9294  * character at a corresponding position in the third argument string
9295  * (because the second argument string is longer than the third argument
9296  * string), then occurrences of that character in the first argument
9297  * string are removed. For example, translate("--aaa--","abc-","ABC")
9298  * returns "AAA". If a character occurs more than once in second
9299  * argument string, then the first occurrence determines the replacement
9300  * character. If the third argument string is longer than the second
9301  * argument string, then excess characters are ignored.
9302  */
9303 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9304 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9305     xmlXPathObjectPtr str;
9306     xmlXPathObjectPtr from;
9307     xmlXPathObjectPtr to;
9308     xmlBufferPtr target;
9309     int offset, max;
9310     xmlChar ch;
9311     const xmlChar *point;
9312     xmlChar *cptr;
9313 
9314     CHECK_ARITY(3);
9315 
9316     CAST_TO_STRING;
9317     to = valuePop(ctxt);
9318     CAST_TO_STRING;
9319     from = valuePop(ctxt);
9320     CAST_TO_STRING;
9321     str = valuePop(ctxt);
9322 
9323     target = xmlBufferCreate();
9324     if (target) {
9325 	max = xmlUTF8Strlen(to->stringval);
9326 	for (cptr = str->stringval; (ch=*cptr); ) {
9327 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9328 	    if (offset >= 0) {
9329 		if (offset < max) {
9330 		    point = xmlUTF8Strpos(to->stringval, offset);
9331 		    if (point)
9332 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9333 		}
9334 	    } else
9335 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9336 
9337 	    /* Step to next character in input */
9338 	    cptr++;
9339 	    if ( ch & 0x80 ) {
9340 		/* if not simple ascii, verify proper format */
9341 		if ( (ch & 0xc0) != 0xc0 ) {
9342 		    xmlGenericError(xmlGenericErrorContext,
9343 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9344                     /* not asserting an XPath error is probably better */
9345 		    break;
9346 		}
9347 		/* then skip over remaining bytes for this char */
9348 		while ( (ch <<= 1) & 0x80 )
9349 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9350 			xmlGenericError(xmlGenericErrorContext,
9351 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9352                         /* not asserting an XPath error is probably better */
9353 			break;
9354 		    }
9355 		if (ch & 0x80) /* must have had error encountered */
9356 		    break;
9357 	    }
9358 	}
9359     }
9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361 	xmlBufferContent(target)));
9362     xmlBufferFree(target);
9363     xmlXPathReleaseObject(ctxt->context, str);
9364     xmlXPathReleaseObject(ctxt->context, from);
9365     xmlXPathReleaseObject(ctxt->context, to);
9366 }
9367 
9368 /**
9369  * xmlXPathBooleanFunction:
9370  * @ctxt:  the XPath Parser context
9371  * @nargs:  the number of arguments
9372  *
9373  * Implement the boolean() XPath function
9374  *    boolean boolean(object)
9375  * The boolean function converts its argument to a boolean as follows:
9376  *    - a number is true if and only if it is neither positive or
9377  *      negative zero nor NaN
9378  *    - a node-set is true if and only if it is non-empty
9379  *    - a string is true if and only if its length is non-zero
9380  */
9381 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9382 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383     xmlXPathObjectPtr cur;
9384 
9385     CHECK_ARITY(1);
9386     cur = valuePop(ctxt);
9387     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9388     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9389     valuePush(ctxt, cur);
9390 }
9391 
9392 /**
9393  * xmlXPathNotFunction:
9394  * @ctxt:  the XPath Parser context
9395  * @nargs:  the number of arguments
9396  *
9397  * Implement the not() XPath function
9398  *    boolean not(boolean)
9399  * The not function returns true if its argument is false,
9400  * and false otherwise.
9401  */
9402 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9403 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9404     CHECK_ARITY(1);
9405     CAST_TO_BOOLEAN;
9406     CHECK_TYPE(XPATH_BOOLEAN);
9407     ctxt->value->boolval = ! ctxt->value->boolval;
9408 }
9409 
9410 /**
9411  * xmlXPathTrueFunction:
9412  * @ctxt:  the XPath Parser context
9413  * @nargs:  the number of arguments
9414  *
9415  * Implement the true() XPath function
9416  *    boolean true()
9417  */
9418 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9419 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420     CHECK_ARITY(0);
9421     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9422 }
9423 
9424 /**
9425  * xmlXPathFalseFunction:
9426  * @ctxt:  the XPath Parser context
9427  * @nargs:  the number of arguments
9428  *
9429  * Implement the false() XPath function
9430  *    boolean false()
9431  */
9432 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9433 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9434     CHECK_ARITY(0);
9435     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9436 }
9437 
9438 /**
9439  * xmlXPathLangFunction:
9440  * @ctxt:  the XPath Parser context
9441  * @nargs:  the number of arguments
9442  *
9443  * Implement the lang() XPath function
9444  *    boolean lang(string)
9445  * The lang function returns true or false depending on whether the
9446  * language of the context node as specified by xml:lang attributes
9447  * is the same as or is a sublanguage of the language specified by
9448  * the argument string. The language of the context node is determined
9449  * by the value of the xml:lang attribute on the context node, or, if
9450  * the context node has no xml:lang attribute, by the value of the
9451  * xml:lang attribute on the nearest ancestor of the context node that
9452  * has an xml:lang attribute. If there is no such attribute, then lang
9453  * returns false. If there is such an attribute, then lang returns
9454  * true if the attribute value is equal to the argument ignoring case,
9455  * or if there is some suffix starting with - such that the attribute
9456  * value is equal to the argument ignoring that suffix of the attribute
9457  * value and ignoring case.
9458  */
9459 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9460 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461     xmlXPathObjectPtr val = NULL;
9462     const xmlChar *theLang = NULL;
9463     const xmlChar *lang;
9464     int ret = 0;
9465     int i;
9466 
9467     CHECK_ARITY(1);
9468     CAST_TO_STRING;
9469     CHECK_TYPE(XPATH_STRING);
9470     val = valuePop(ctxt);
9471     lang = val->stringval;
9472     theLang = xmlNodeGetLang(ctxt->context->node);
9473     if ((theLang != NULL) && (lang != NULL)) {
9474         for (i = 0;lang[i] != 0;i++)
9475 	    if (toupper(lang[i]) != toupper(theLang[i]))
9476 	        goto not_equal;
9477 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9478 	    ret = 1;
9479     }
9480 not_equal:
9481     if (theLang != NULL)
9482 	xmlFree((void *)theLang);
9483 
9484     xmlXPathReleaseObject(ctxt->context, val);
9485     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9486 }
9487 
9488 /**
9489  * xmlXPathNumberFunction:
9490  * @ctxt:  the XPath Parser context
9491  * @nargs:  the number of arguments
9492  *
9493  * Implement the number() XPath function
9494  *    number number(object?)
9495  */
9496 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9497 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498     xmlXPathObjectPtr cur;
9499     double res;
9500 
9501     if (ctxt == NULL) return;
9502     if (nargs == 0) {
9503 	if (ctxt->context->node == NULL) {
9504 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9505 	} else {
9506 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9507 
9508 	    res = xmlXPathStringEvalNumber(content);
9509 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9510 	    xmlFree(content);
9511 	}
9512 	return;
9513     }
9514 
9515     CHECK_ARITY(1);
9516     cur = valuePop(ctxt);
9517     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9518 }
9519 
9520 /**
9521  * xmlXPathSumFunction:
9522  * @ctxt:  the XPath Parser context
9523  * @nargs:  the number of arguments
9524  *
9525  * Implement the sum() XPath function
9526  *    number sum(node-set)
9527  * The sum function returns the sum of the values of the nodes in
9528  * the argument node-set.
9529  */
9530 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9531 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532     xmlXPathObjectPtr cur;
9533     int i;
9534     double res = 0.0;
9535 
9536     CHECK_ARITY(1);
9537     if ((ctxt->value == NULL) ||
9538 	((ctxt->value->type != XPATH_NODESET) &&
9539 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9540 	XP_ERROR(XPATH_INVALID_TYPE);
9541     cur = valuePop(ctxt);
9542 
9543     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9544 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9546 	}
9547     }
9548     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549     xmlXPathReleaseObject(ctxt->context, cur);
9550 }
9551 
9552 /*
9553  * To assure working code on multiple platforms, we want to only depend
9554  * upon the characteristic truncation of converting a floating point value
9555  * to an integer.  Unfortunately, because of the different storage sizes
9556  * of our internal floating point value (double) and integer (int), we
9557  * can't directly convert (see bug 301162).  This macro is a messy
9558  * 'workaround'
9559  */
9560 #define XTRUNC(f, v)            \
9561     f = fmod((v), INT_MAX);     \
9562     f = (v) - (f) + (double)((int)(f));
9563 
9564 /**
9565  * xmlXPathFloorFunction:
9566  * @ctxt:  the XPath Parser context
9567  * @nargs:  the number of arguments
9568  *
9569  * Implement the floor() XPath function
9570  *    number floor(number)
9571  * The floor function returns the largest (closest to positive infinity)
9572  * number that is not greater than the argument and that is an integer.
9573  */
9574 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9575 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576     double f;
9577 
9578     CHECK_ARITY(1);
9579     CAST_TO_NUMBER;
9580     CHECK_TYPE(XPATH_NUMBER);
9581 
9582     XTRUNC(f, ctxt->value->floatval);
9583     if (f != ctxt->value->floatval) {
9584 	if (ctxt->value->floatval > 0)
9585 	    ctxt->value->floatval = f;
9586 	else
9587 	    ctxt->value->floatval = f - 1;
9588     }
9589 }
9590 
9591 /**
9592  * xmlXPathCeilingFunction:
9593  * @ctxt:  the XPath Parser context
9594  * @nargs:  the number of arguments
9595  *
9596  * Implement the ceiling() XPath function
9597  *    number ceiling(number)
9598  * The ceiling function returns the smallest (closest to negative infinity)
9599  * number that is not less than the argument and that is an integer.
9600  */
9601 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9602 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9603     double f;
9604 
9605     CHECK_ARITY(1);
9606     CAST_TO_NUMBER;
9607     CHECK_TYPE(XPATH_NUMBER);
9608 
9609 #if 0
9610     ctxt->value->floatval = ceil(ctxt->value->floatval);
9611 #else
9612     XTRUNC(f, ctxt->value->floatval);
9613     if (f != ctxt->value->floatval) {
9614 	if (ctxt->value->floatval > 0)
9615 	    ctxt->value->floatval = f + 1;
9616 	else {
9617 	    if (ctxt->value->floatval < 0 && f == 0)
9618 	        ctxt->value->floatval = xmlXPathNZERO;
9619 	    else
9620 	        ctxt->value->floatval = f;
9621 	}
9622 
9623     }
9624 #endif
9625 }
9626 
9627 /**
9628  * xmlXPathRoundFunction:
9629  * @ctxt:  the XPath Parser context
9630  * @nargs:  the number of arguments
9631  *
9632  * Implement the round() XPath function
9633  *    number round(number)
9634  * The round function returns the number that is closest to the
9635  * argument and that is an integer. If there are two such numbers,
9636  * then the one that is even is returned.
9637  */
9638 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9639 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9640     double f;
9641 
9642     CHECK_ARITY(1);
9643     CAST_TO_NUMBER;
9644     CHECK_TYPE(XPATH_NUMBER);
9645 
9646     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9649 	(ctxt->value->floatval == 0.0))
9650 	return;
9651 
9652     XTRUNC(f, ctxt->value->floatval);
9653     if (ctxt->value->floatval < 0) {
9654 	if (ctxt->value->floatval < f - 0.5)
9655 	    ctxt->value->floatval = f - 1;
9656 	else
9657 	    ctxt->value->floatval = f;
9658 	if (ctxt->value->floatval == 0)
9659 	    ctxt->value->floatval = xmlXPathNZERO;
9660     } else {
9661 	if (ctxt->value->floatval < f + 0.5)
9662 	    ctxt->value->floatval = f;
9663 	else
9664 	    ctxt->value->floatval = f + 1;
9665     }
9666 }
9667 
9668 /************************************************************************
9669  *									*
9670  *			The Parser					*
9671  *									*
9672  ************************************************************************/
9673 
9674 /*
9675  * a few forward declarations since we use a recursive call based
9676  * implementation.
9677  */
9678 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9679 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9680 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9681 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9682 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9683 	                                  int qualified);
9684 
9685 /**
9686  * xmlXPathCurrentChar:
9687  * @ctxt:  the XPath parser context
9688  * @cur:  pointer to the beginning of the char
9689  * @len:  pointer to the length of the char read
9690  *
9691  * The current char value, if using UTF-8 this may actually span multiple
9692  * bytes in the input buffer.
9693  *
9694  * Returns the current char value and its length
9695  */
9696 
9697 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9698 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9699     unsigned char c;
9700     unsigned int val;
9701     const xmlChar *cur;
9702 
9703     if (ctxt == NULL)
9704 	return(0);
9705     cur = ctxt->cur;
9706 
9707     /*
9708      * We are supposed to handle UTF8, check it's valid
9709      * From rfc2044: encoding of the Unicode values on UTF-8:
9710      *
9711      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9712      * 0000 0000-0000 007F   0xxxxxxx
9713      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9714      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9715      *
9716      * Check for the 0x110000 limit too
9717      */
9718     c = *cur;
9719     if (c & 0x80) {
9720 	if ((cur[1] & 0xc0) != 0x80)
9721 	    goto encoding_error;
9722 	if ((c & 0xe0) == 0xe0) {
9723 
9724 	    if ((cur[2] & 0xc0) != 0x80)
9725 		goto encoding_error;
9726 	    if ((c & 0xf0) == 0xf0) {
9727 		if (((c & 0xf8) != 0xf0) ||
9728 		    ((cur[3] & 0xc0) != 0x80))
9729 		    goto encoding_error;
9730 		/* 4-byte code */
9731 		*len = 4;
9732 		val = (cur[0] & 0x7) << 18;
9733 		val |= (cur[1] & 0x3f) << 12;
9734 		val |= (cur[2] & 0x3f) << 6;
9735 		val |= cur[3] & 0x3f;
9736 	    } else {
9737 	      /* 3-byte code */
9738 		*len = 3;
9739 		val = (cur[0] & 0xf) << 12;
9740 		val |= (cur[1] & 0x3f) << 6;
9741 		val |= cur[2] & 0x3f;
9742 	    }
9743 	} else {
9744 	  /* 2-byte code */
9745 	    *len = 2;
9746 	    val = (cur[0] & 0x1f) << 6;
9747 	    val |= cur[1] & 0x3f;
9748 	}
9749 	if (!IS_CHAR(val)) {
9750 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9751 	}
9752 	return(val);
9753     } else {
9754 	/* 1-byte code */
9755 	*len = 1;
9756 	return((int) *cur);
9757     }
9758 encoding_error:
9759     /*
9760      * If we detect an UTF8 error that probably means that the
9761      * input encoding didn't get properly advertised in the
9762      * declaration header. Report the error and switch the encoding
9763      * to ISO-Latin-1 (if you don't like this policy, just declare the
9764      * encoding !)
9765      */
9766     *len = 0;
9767     XP_ERROR0(XPATH_ENCODING_ERROR);
9768 }
9769 
9770 /**
9771  * xmlXPathParseNCName:
9772  * @ctxt:  the XPath Parser context
9773  *
9774  * parse an XML namespace non qualified name.
9775  *
9776  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9777  *
9778  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779  *                       CombiningChar | Extender
9780  *
9781  * Returns the namespace name or NULL
9782  */
9783 
9784 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9785 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9786     const xmlChar *in;
9787     xmlChar *ret;
9788     int count = 0;
9789 
9790     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9791     /*
9792      * Accelerator for simple ASCII names
9793      */
9794     in = ctxt->cur;
9795     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796 	((*in >= 0x41) && (*in <= 0x5A)) ||
9797 	(*in == '_')) {
9798 	in++;
9799 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9801 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9802 	       (*in == '_') || (*in == '.') ||
9803 	       (*in == '-'))
9804 	    in++;
9805 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806             (*in == '[') || (*in == ']') || (*in == ':') ||
9807             (*in == '@') || (*in == '*')) {
9808 	    count = in - ctxt->cur;
9809 	    if (count == 0)
9810 		return(NULL);
9811 	    ret = xmlStrndup(ctxt->cur, count);
9812 	    ctxt->cur = in;
9813 	    return(ret);
9814 	}
9815     }
9816     return(xmlXPathParseNameComplex(ctxt, 0));
9817 }
9818 
9819 
9820 /**
9821  * xmlXPathParseQName:
9822  * @ctxt:  the XPath Parser context
9823  * @prefix:  a xmlChar **
9824  *
9825  * parse an XML qualified name
9826  *
9827  * [NS 5] QName ::= (Prefix ':')? LocalPart
9828  *
9829  * [NS 6] Prefix ::= NCName
9830  *
9831  * [NS 7] LocalPart ::= NCName
9832  *
9833  * Returns the function returns the local part, and prefix is updated
9834  *   to get the Prefix if any.
9835  */
9836 
9837 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9838 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839     xmlChar *ret = NULL;
9840 
9841     *prefix = NULL;
9842     ret = xmlXPathParseNCName(ctxt);
9843     if (ret && CUR == ':') {
9844         *prefix = ret;
9845 	NEXT;
9846 	ret = xmlXPathParseNCName(ctxt);
9847     }
9848     return(ret);
9849 }
9850 
9851 /**
9852  * xmlXPathParseName:
9853  * @ctxt:  the XPath Parser context
9854  *
9855  * parse an XML name
9856  *
9857  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858  *                  CombiningChar | Extender
9859  *
9860  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9861  *
9862  * Returns the namespace name or NULL
9863  */
9864 
9865 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9866 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9867     const xmlChar *in;
9868     xmlChar *ret;
9869     int count = 0;
9870 
9871     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872     /*
9873      * Accelerator for simple ASCII names
9874      */
9875     in = ctxt->cur;
9876     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 	((*in >= 0x41) && (*in <= 0x5A)) ||
9878 	(*in == '_') || (*in == ':')) {
9879 	in++;
9880 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9883 	       (*in == '_') || (*in == '-') ||
9884 	       (*in == ':') || (*in == '.'))
9885 	    in++;
9886 	if ((*in > 0) && (*in < 0x80)) {
9887 	    count = in - ctxt->cur;
9888 	    ret = xmlStrndup(ctxt->cur, count);
9889 	    ctxt->cur = in;
9890 	    return(ret);
9891 	}
9892     }
9893     return(xmlXPathParseNameComplex(ctxt, 1));
9894 }
9895 
9896 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9897 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9898     xmlChar buf[XML_MAX_NAMELEN + 5];
9899     int len = 0, l;
9900     int c;
9901 
9902     /*
9903      * Handler for more complex cases
9904      */
9905     c = CUR_CHAR(l);
9906     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9907         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908         (c == '*') || /* accelerators */
9909 	(!IS_LETTER(c) && (c != '_') &&
9910          ((qualified) && (c != ':')))) {
9911 	return(NULL);
9912     }
9913 
9914     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916             (c == '.') || (c == '-') ||
9917 	    (c == '_') || ((qualified) && (c == ':')) ||
9918 	    (IS_COMBINING(c)) ||
9919 	    (IS_EXTENDER(c)))) {
9920 	COPY_BUF(l,buf,len,c);
9921 	NEXTL(l);
9922 	c = CUR_CHAR(l);
9923 	if (len >= XML_MAX_NAMELEN) {
9924 	    /*
9925 	     * Okay someone managed to make a huge name, so he's ready to pay
9926 	     * for the processing speed.
9927 	     */
9928 	    xmlChar *buffer;
9929 	    int max = len * 2;
9930 
9931 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9932 	    if (buffer == NULL) {
9933 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9934 	    }
9935 	    memcpy(buffer, buf, len);
9936 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937 		   (c == '.') || (c == '-') ||
9938 		   (c == '_') || ((qualified) && (c == ':')) ||
9939 		   (IS_COMBINING(c)) ||
9940 		   (IS_EXTENDER(c))) {
9941 		if (len + 10 > max) {
9942 		    max *= 2;
9943 		    buffer = (xmlChar *) xmlRealloc(buffer,
9944 			                            max * sizeof(xmlChar));
9945 		    if (buffer == NULL) {
9946 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9947 		    }
9948 		}
9949 		COPY_BUF(l,buffer,len,c);
9950 		NEXTL(l);
9951 		c = CUR_CHAR(l);
9952 	    }
9953 	    buffer[len] = 0;
9954 	    return(buffer);
9955 	}
9956     }
9957     if (len == 0)
9958 	return(NULL);
9959     return(xmlStrndup(buf, len));
9960 }
9961 
9962 #define MAX_FRAC 20
9963 
9964 /*
9965  * These are used as divisors for the fractional part of a number.
9966  * Since the table includes 1.0 (representing '0' fractional digits),
9967  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9968  */
9969 static double my_pow10[MAX_FRAC+1] = {
9970     1.0, 10.0, 100.0, 1000.0, 10000.0,
9971     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9973     100000000000000.0,
9974     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9975     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9976 };
9977 
9978 /**
9979  * xmlXPathStringEvalNumber:
9980  * @str:  A string to scan
9981  *
9982  *  [30a]  Float  ::= Number ('e' Digits?)?
9983  *
9984  *  [30]   Number ::=   Digits ('.' Digits?)?
9985  *                    | '.' Digits
9986  *  [31]   Digits ::=   [0-9]+
9987  *
9988  * Compile a Number in the string
9989  * In complement of the Number expression, this function also handles
9990  * negative values : '-' Number.
9991  *
9992  * Returns the double value.
9993  */
9994 double
xmlXPathStringEvalNumber(const xmlChar * str)9995 xmlXPathStringEvalNumber(const xmlChar *str) {
9996     const xmlChar *cur = str;
9997     double ret;
9998     int ok = 0;
9999     int isneg = 0;
10000     int exponent = 0;
10001     int is_exponent_negative = 0;
10002 #ifdef __GNUC__
10003     unsigned long tmp = 0;
10004     double temp;
10005 #endif
10006     if (cur == NULL) return(0);
10007     while (IS_BLANK_CH(*cur)) cur++;
10008     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009         return(xmlXPathNAN);
10010     }
10011     if (*cur == '-') {
10012 	isneg = 1;
10013 	cur++;
10014     }
10015 
10016 #ifdef __GNUC__
10017     /*
10018      * tmp/temp is a workaround against a gcc compiler bug
10019      * http://veillard.com/gcc.bug
10020      */
10021     ret = 0;
10022     while ((*cur >= '0') && (*cur <= '9')) {
10023 	ret = ret * 10;
10024 	tmp = (*cur - '0');
10025 	ok = 1;
10026 	cur++;
10027 	temp = (double) tmp;
10028 	ret = ret + temp;
10029     }
10030 #else
10031     ret = 0;
10032     while ((*cur >= '0') && (*cur <= '9')) {
10033 	ret = ret * 10 + (*cur - '0');
10034 	ok = 1;
10035 	cur++;
10036     }
10037 #endif
10038 
10039     if (*cur == '.') {
10040 	int v, frac = 0;
10041 	double fraction = 0;
10042 
10043         cur++;
10044 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045 	    return(xmlXPathNAN);
10046 	}
10047 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048 	    v = (*cur - '0');
10049 	    fraction = fraction * 10 + v;
10050 	    frac = frac + 1;
10051 	    cur++;
10052 	}
10053 	fraction /= my_pow10[frac];
10054 	ret = ret + fraction;
10055 	while ((*cur >= '0') && (*cur <= '9'))
10056 	    cur++;
10057     }
10058     if ((*cur == 'e') || (*cur == 'E')) {
10059       cur++;
10060       if (*cur == '-') {
10061 	is_exponent_negative = 1;
10062 	cur++;
10063       } else if (*cur == '+') {
10064         cur++;
10065       }
10066       while ((*cur >= '0') && (*cur <= '9')) {
10067 	exponent = exponent * 10 + (*cur - '0');
10068 	cur++;
10069       }
10070     }
10071     while (IS_BLANK_CH(*cur)) cur++;
10072     if (*cur != 0) return(xmlXPathNAN);
10073     if (isneg) ret = -ret;
10074     if (is_exponent_negative) exponent = -exponent;
10075     ret *= pow(10.0, (double)exponent);
10076     return(ret);
10077 }
10078 
10079 /**
10080  * xmlXPathCompNumber:
10081  * @ctxt:  the XPath Parser context
10082  *
10083  *  [30]   Number ::=   Digits ('.' Digits?)?
10084  *                    | '.' Digits
10085  *  [31]   Digits ::=   [0-9]+
10086  *
10087  * Compile a Number, then push it on the stack
10088  *
10089  */
10090 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10091 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092 {
10093     double ret = 0.0;
10094     int ok = 0;
10095     int exponent = 0;
10096     int is_exponent_negative = 0;
10097 #ifdef __GNUC__
10098     unsigned long tmp = 0;
10099     double temp;
10100 #endif
10101 
10102     CHECK_ERROR;
10103     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104         XP_ERROR(XPATH_NUMBER_ERROR);
10105     }
10106 #ifdef __GNUC__
10107     /*
10108      * tmp/temp is a workaround against a gcc compiler bug
10109      * http://veillard.com/gcc.bug
10110      */
10111     ret = 0;
10112     while ((CUR >= '0') && (CUR <= '9')) {
10113 	ret = ret * 10;
10114 	tmp = (CUR - '0');
10115         ok = 1;
10116         NEXT;
10117 	temp = (double) tmp;
10118 	ret = ret + temp;
10119     }
10120 #else
10121     ret = 0;
10122     while ((CUR >= '0') && (CUR <= '9')) {
10123 	ret = ret * 10 + (CUR - '0');
10124 	ok = 1;
10125 	NEXT;
10126     }
10127 #endif
10128     if (CUR == '.') {
10129 	int v, frac = 0;
10130 	double fraction = 0;
10131 
10132         NEXT;
10133         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134             XP_ERROR(XPATH_NUMBER_ERROR);
10135         }
10136         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137 	    v = (CUR - '0');
10138 	    fraction = fraction * 10 + v;
10139 	    frac = frac + 1;
10140             NEXT;
10141         }
10142         fraction /= my_pow10[frac];
10143         ret = ret + fraction;
10144         while ((CUR >= '0') && (CUR <= '9'))
10145             NEXT;
10146     }
10147     if ((CUR == 'e') || (CUR == 'E')) {
10148         NEXT;
10149         if (CUR == '-') {
10150             is_exponent_negative = 1;
10151             NEXT;
10152         } else if (CUR == '+') {
10153 	    NEXT;
10154 	}
10155         while ((CUR >= '0') && (CUR <= '9')) {
10156             exponent = exponent * 10 + (CUR - '0');
10157             NEXT;
10158         }
10159         if (is_exponent_negative)
10160             exponent = -exponent;
10161         ret *= pow(10.0, (double) exponent);
10162     }
10163     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165 }
10166 
10167 /**
10168  * xmlXPathParseLiteral:
10169  * @ctxt:  the XPath Parser context
10170  *
10171  * Parse a Literal
10172  *
10173  *  [29]   Literal ::=   '"' [^"]* '"'
10174  *                    | "'" [^']* "'"
10175  *
10176  * Returns the value found or NULL in case of error
10177  */
10178 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180     const xmlChar *q;
10181     xmlChar *ret = NULL;
10182 
10183     if (CUR == '"') {
10184         NEXT;
10185 	q = CUR_PTR;
10186 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187 	    NEXT;
10188 	if (!IS_CHAR_CH(CUR)) {
10189 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190 	} else {
10191 	    ret = xmlStrndup(q, CUR_PTR - q);
10192 	    NEXT;
10193         }
10194     } else if (CUR == '\'') {
10195         NEXT;
10196 	q = CUR_PTR;
10197 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198 	    NEXT;
10199 	if (!IS_CHAR_CH(CUR)) {
10200 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201 	} else {
10202 	    ret = xmlStrndup(q, CUR_PTR - q);
10203 	    NEXT;
10204         }
10205     } else {
10206 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207     }
10208     return(ret);
10209 }
10210 
10211 /**
10212  * xmlXPathCompLiteral:
10213  * @ctxt:  the XPath Parser context
10214  *
10215  * Parse a Literal and push it on the stack.
10216  *
10217  *  [29]   Literal ::=   '"' [^"]* '"'
10218  *                    | "'" [^']* "'"
10219  *
10220  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221  */
10222 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224     const xmlChar *q;
10225     xmlChar *ret = NULL;
10226 
10227     if (CUR == '"') {
10228         NEXT;
10229 	q = CUR_PTR;
10230 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231 	    NEXT;
10232 	if (!IS_CHAR_CH(CUR)) {
10233 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234 	} else {
10235 	    ret = xmlStrndup(q, CUR_PTR - q);
10236 	    NEXT;
10237         }
10238     } else if (CUR == '\'') {
10239         NEXT;
10240 	q = CUR_PTR;
10241 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242 	    NEXT;
10243 	if (!IS_CHAR_CH(CUR)) {
10244 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245 	} else {
10246 	    ret = xmlStrndup(q, CUR_PTR - q);
10247 	    NEXT;
10248         }
10249     } else {
10250 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10251     }
10252     if (ret == NULL) return;
10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255     xmlFree(ret);
10256 }
10257 
10258 /**
10259  * xmlXPathCompVariableReference:
10260  * @ctxt:  the XPath Parser context
10261  *
10262  * Parse a VariableReference, evaluate it and push it on the stack.
10263  *
10264  * The variable bindings consist of a mapping from variable names
10265  * to variable values. The value of a variable is an object, which can be
10266  * of any of the types that are possible for the value of an expression,
10267  * and may also be of additional types not specified here.
10268  *
10269  * Early evaluation is possible since:
10270  * The variable bindings [...] used to evaluate a subexpression are
10271  * always the same as those used to evaluate the containing expression.
10272  *
10273  *  [36]   VariableReference ::=   '$' QName
10274  */
10275 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277     xmlChar *name;
10278     xmlChar *prefix;
10279 
10280     SKIP_BLANKS;
10281     if (CUR != '$') {
10282 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283     }
10284     NEXT;
10285     name = xmlXPathParseQName(ctxt, &prefix);
10286     if (name == NULL) {
10287 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288     }
10289     ctxt->comp->last = -1;
10290     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291 	           name, prefix);
10292     SKIP_BLANKS;
10293     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295     }
10296 }
10297 
10298 /**
10299  * xmlXPathIsNodeType:
10300  * @name:  a name string
10301  *
10302  * Is the name given a NodeType one.
10303  *
10304  *  [38]   NodeType ::=   'comment'
10305  *                    | 'text'
10306  *                    | 'processing-instruction'
10307  *                    | 'node'
10308  *
10309  * Returns 1 if true 0 otherwise
10310  */
10311 int
xmlXPathIsNodeType(const xmlChar * name)10312 xmlXPathIsNodeType(const xmlChar *name) {
10313     if (name == NULL)
10314 	return(0);
10315 
10316     if (xmlStrEqual(name, BAD_CAST "node"))
10317 	return(1);
10318     if (xmlStrEqual(name, BAD_CAST "text"))
10319 	return(1);
10320     if (xmlStrEqual(name, BAD_CAST "comment"))
10321 	return(1);
10322     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10323 	return(1);
10324     return(0);
10325 }
10326 
10327 /**
10328  * xmlXPathCompFunctionCall:
10329  * @ctxt:  the XPath Parser context
10330  *
10331  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332  *  [17]   Argument ::=   Expr
10333  *
10334  * Compile a function call, the evaluation of all arguments are
10335  * pushed on the stack
10336  */
10337 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10338 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10339     xmlChar *name;
10340     xmlChar *prefix;
10341     int nbargs = 0;
10342     int sort = 1;
10343 
10344     name = xmlXPathParseQName(ctxt, &prefix);
10345     if (name == NULL) {
10346 	xmlFree(prefix);
10347 	XP_ERROR(XPATH_EXPR_ERROR);
10348     }
10349     SKIP_BLANKS;
10350 #ifdef DEBUG_EXPR
10351     if (prefix == NULL)
10352 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353 			name);
10354     else
10355 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356 			prefix, name);
10357 #endif
10358 
10359     if (CUR != '(') {
10360 	XP_ERROR(XPATH_EXPR_ERROR);
10361     }
10362     NEXT;
10363     SKIP_BLANKS;
10364 
10365     /*
10366     * Optimization for count(): we don't need the node-set to be sorted.
10367     */
10368     if ((prefix == NULL) && (name[0] == 'c') &&
10369 	xmlStrEqual(name, BAD_CAST "count"))
10370     {
10371 	sort = 0;
10372     }
10373     ctxt->comp->last = -1;
10374     if (CUR != ')') {
10375 	while (CUR != 0) {
10376 	    int op1 = ctxt->comp->last;
10377 	    ctxt->comp->last = -1;
10378 	    xmlXPathCompileExpr(ctxt, sort);
10379 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10380 		xmlFree(name);
10381 		xmlFree(prefix);
10382 		return;
10383 	    }
10384 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385 	    nbargs++;
10386 	    if (CUR == ')') break;
10387 	    if (CUR != ',') {
10388 		XP_ERROR(XPATH_EXPR_ERROR);
10389 	    }
10390 	    NEXT;
10391 	    SKIP_BLANKS;
10392 	}
10393     }
10394     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395 	           name, prefix);
10396     NEXT;
10397     SKIP_BLANKS;
10398 }
10399 
10400 /**
10401  * xmlXPathCompPrimaryExpr:
10402  * @ctxt:  the XPath Parser context
10403  *
10404  *  [15]   PrimaryExpr ::=   VariableReference
10405  *                | '(' Expr ')'
10406  *                | Literal
10407  *                | Number
10408  *                | FunctionCall
10409  *
10410  * Compile a primary expression.
10411  */
10412 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10413 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10414     SKIP_BLANKS;
10415     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416     else if (CUR == '(') {
10417 	NEXT;
10418 	SKIP_BLANKS;
10419 	xmlXPathCompileExpr(ctxt, 1);
10420 	CHECK_ERROR;
10421 	if (CUR != ')') {
10422 	    XP_ERROR(XPATH_EXPR_ERROR);
10423 	}
10424 	NEXT;
10425 	SKIP_BLANKS;
10426     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427 	xmlXPathCompNumber(ctxt);
10428     } else if ((CUR == '\'') || (CUR == '"')) {
10429 	xmlXPathCompLiteral(ctxt);
10430     } else {
10431 	xmlXPathCompFunctionCall(ctxt);
10432     }
10433     SKIP_BLANKS;
10434 }
10435 
10436 /**
10437  * xmlXPathCompFilterExpr:
10438  * @ctxt:  the XPath Parser context
10439  *
10440  *  [20]   FilterExpr ::=   PrimaryExpr
10441  *               | FilterExpr Predicate
10442  *
10443  * Compile a filter expression.
10444  * Square brackets are used to filter expressions in the same way that
10445  * they are used in location paths. It is an error if the expression to
10446  * be filtered does not evaluate to a node-set. The context node list
10447  * used for evaluating the expression in square brackets is the node-set
10448  * to be filtered listed in document order.
10449  */
10450 
10451 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10452 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453     xmlXPathCompPrimaryExpr(ctxt);
10454     CHECK_ERROR;
10455     SKIP_BLANKS;
10456 
10457     while (CUR == '[') {
10458 	xmlXPathCompPredicate(ctxt, 1);
10459 	SKIP_BLANKS;
10460     }
10461 
10462 
10463 }
10464 
10465 /**
10466  * xmlXPathScanName:
10467  * @ctxt:  the XPath Parser context
10468  *
10469  * Trickery: parse an XML name but without consuming the input flow
10470  * Needed to avoid insanity in the parser state.
10471  *
10472  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473  *                  CombiningChar | Extender
10474  *
10475  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476  *
10477  * [6] Names ::= Name (S Name)*
10478  *
10479  * Returns the Name parsed or NULL
10480  */
10481 
10482 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10483 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10484     int len = 0, l;
10485     int c;
10486     const xmlChar *cur;
10487     xmlChar *ret;
10488 
10489     cur = ctxt->cur;
10490 
10491     c = CUR_CHAR(l);
10492     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493 	(!IS_LETTER(c) && (c != '_') &&
10494          (c != ':'))) {
10495 	return(NULL);
10496     }
10497 
10498     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500             (c == '.') || (c == '-') ||
10501 	    (c == '_') || (c == ':') ||
10502 	    (IS_COMBINING(c)) ||
10503 	    (IS_EXTENDER(c)))) {
10504 	len += l;
10505 	NEXTL(l);
10506 	c = CUR_CHAR(l);
10507     }
10508     ret = xmlStrndup(cur, ctxt->cur - cur);
10509     ctxt->cur = cur;
10510     return(ret);
10511 }
10512 
10513 /**
10514  * xmlXPathCompPathExpr:
10515  * @ctxt:  the XPath Parser context
10516  *
10517  *  [19]   PathExpr ::=   LocationPath
10518  *               | FilterExpr
10519  *               | FilterExpr '/' RelativeLocationPath
10520  *               | FilterExpr '//' RelativeLocationPath
10521  *
10522  * Compile a path expression.
10523  * The / operator and // operators combine an arbitrary expression
10524  * and a relative location path. It is an error if the expression
10525  * does not evaluate to a node-set.
10526  * The / operator does composition in the same way as when / is
10527  * used in a location path. As in location paths, // is short for
10528  * /descendant-or-self::node()/.
10529  */
10530 
10531 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10532 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533     int lc = 1;           /* Should we branch to LocationPath ?         */
10534     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535 
10536     SKIP_BLANKS;
10537     if ((CUR == '$') || (CUR == '(') ||
10538 	(IS_ASCII_DIGIT(CUR)) ||
10539         (CUR == '\'') || (CUR == '"') ||
10540 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10541 	lc = 0;
10542     } else if (CUR == '*') {
10543 	/* relative or absolute location path */
10544 	lc = 1;
10545     } else if (CUR == '/') {
10546 	/* relative or absolute location path */
10547 	lc = 1;
10548     } else if (CUR == '@') {
10549 	/* relative abbreviated attribute location path */
10550 	lc = 1;
10551     } else if (CUR == '.') {
10552 	/* relative abbreviated attribute location path */
10553 	lc = 1;
10554     } else {
10555 	/*
10556 	 * Problem is finding if we have a name here whether it's:
10557 	 *   - a nodetype
10558 	 *   - a function call in which case it's followed by '('
10559 	 *   - an axis in which case it's followed by ':'
10560 	 *   - a element name
10561 	 * We do an a priori analysis here rather than having to
10562 	 * maintain parsed token content through the recursive function
10563 	 * calls. This looks uglier but makes the code easier to
10564 	 * read/write/debug.
10565 	 */
10566 	SKIP_BLANKS;
10567 	name = xmlXPathScanName(ctxt);
10568 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569 #ifdef DEBUG_STEP
10570 	    xmlGenericError(xmlGenericErrorContext,
10571 		    "PathExpr: Axis\n");
10572 #endif
10573 	    lc = 1;
10574 	    xmlFree(name);
10575 	} else if (name != NULL) {
10576 	    int len =xmlStrlen(name);
10577 
10578 
10579 	    while (NXT(len) != 0) {
10580 		if (NXT(len) == '/') {
10581 		    /* element name */
10582 #ifdef DEBUG_STEP
10583 		    xmlGenericError(xmlGenericErrorContext,
10584 			    "PathExpr: AbbrRelLocation\n");
10585 #endif
10586 		    lc = 1;
10587 		    break;
10588 		} else if (IS_BLANK_CH(NXT(len))) {
10589 		    /* ignore blanks */
10590 		    ;
10591 		} else if (NXT(len) == ':') {
10592 #ifdef DEBUG_STEP
10593 		    xmlGenericError(xmlGenericErrorContext,
10594 			    "PathExpr: AbbrRelLocation\n");
10595 #endif
10596 		    lc = 1;
10597 		    break;
10598 		} else if ((NXT(len) == '(')) {
10599 		    /* Note Type or Function */
10600 		    if (xmlXPathIsNodeType(name)) {
10601 #ifdef DEBUG_STEP
10602 		        xmlGenericError(xmlGenericErrorContext,
10603 				"PathExpr: Type search\n");
10604 #endif
10605 			lc = 1;
10606 		    } else {
10607 #ifdef DEBUG_STEP
10608 		        xmlGenericError(xmlGenericErrorContext,
10609 				"PathExpr: function call\n");
10610 #endif
10611 			lc = 0;
10612 		    }
10613                     break;
10614 		} else if ((NXT(len) == '[')) {
10615 		    /* element name */
10616 #ifdef DEBUG_STEP
10617 		    xmlGenericError(xmlGenericErrorContext,
10618 			    "PathExpr: AbbrRelLocation\n");
10619 #endif
10620 		    lc = 1;
10621 		    break;
10622 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623 			   (NXT(len) == '=')) {
10624 		    lc = 1;
10625 		    break;
10626 		} else {
10627 		    lc = 1;
10628 		    break;
10629 		}
10630 		len++;
10631 	    }
10632 	    if (NXT(len) == 0) {
10633 #ifdef DEBUG_STEP
10634 		xmlGenericError(xmlGenericErrorContext,
10635 			"PathExpr: AbbrRelLocation\n");
10636 #endif
10637 		/* element name */
10638 		lc = 1;
10639 	    }
10640 	    xmlFree(name);
10641 	} else {
10642 	    /* make sure all cases are covered explicitly */
10643 	    XP_ERROR(XPATH_EXPR_ERROR);
10644 	}
10645     }
10646 
10647     if (lc) {
10648 	if (CUR == '/') {
10649 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650 	} else {
10651 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10652 	}
10653 	xmlXPathCompLocationPath(ctxt);
10654     } else {
10655 	xmlXPathCompFilterExpr(ctxt);
10656 	CHECK_ERROR;
10657 	if ((CUR == '/') && (NXT(1) == '/')) {
10658 	    SKIP(2);
10659 	    SKIP_BLANKS;
10660 
10661 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664 
10665 	    xmlXPathCompRelativeLocationPath(ctxt);
10666 	} else if (CUR == '/') {
10667 	    xmlXPathCompRelativeLocationPath(ctxt);
10668 	}
10669     }
10670     SKIP_BLANKS;
10671 }
10672 
10673 /**
10674  * xmlXPathCompUnionExpr:
10675  * @ctxt:  the XPath Parser context
10676  *
10677  *  [18]   UnionExpr ::=   PathExpr
10678  *               | UnionExpr '|' PathExpr
10679  *
10680  * Compile an union expression.
10681  */
10682 
10683 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10684 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685     xmlXPathCompPathExpr(ctxt);
10686     CHECK_ERROR;
10687     SKIP_BLANKS;
10688     while (CUR == '|') {
10689 	int op1 = ctxt->comp->last;
10690 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10691 
10692 	NEXT;
10693 	SKIP_BLANKS;
10694 	xmlXPathCompPathExpr(ctxt);
10695 
10696 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697 
10698 	SKIP_BLANKS;
10699     }
10700 }
10701 
10702 /**
10703  * xmlXPathCompUnaryExpr:
10704  * @ctxt:  the XPath Parser context
10705  *
10706  *  [27]   UnaryExpr ::=   UnionExpr
10707  *                   | '-' UnaryExpr
10708  *
10709  * Compile an unary expression.
10710  */
10711 
10712 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10713 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10714     int minus = 0;
10715     int found = 0;
10716 
10717     SKIP_BLANKS;
10718     while (CUR == '-') {
10719         minus = 1 - minus;
10720 	found = 1;
10721 	NEXT;
10722 	SKIP_BLANKS;
10723     }
10724 
10725     xmlXPathCompUnionExpr(ctxt);
10726     CHECK_ERROR;
10727     if (found) {
10728 	if (minus)
10729 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730 	else
10731 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10732     }
10733 }
10734 
10735 /**
10736  * xmlXPathCompMultiplicativeExpr:
10737  * @ctxt:  the XPath Parser context
10738  *
10739  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10740  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10741  *                   | MultiplicativeExpr 'div' UnaryExpr
10742  *                   | MultiplicativeExpr 'mod' UnaryExpr
10743  *  [34]   MultiplyOperator ::=   '*'
10744  *
10745  * Compile an Additive expression.
10746  */
10747 
10748 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10749 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750     xmlXPathCompUnaryExpr(ctxt);
10751     CHECK_ERROR;
10752     SKIP_BLANKS;
10753     while ((CUR == '*') ||
10754            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756 	int op = -1;
10757 	int op1 = ctxt->comp->last;
10758 
10759         if (CUR == '*') {
10760 	    op = 0;
10761 	    NEXT;
10762 	} else if (CUR == 'd') {
10763 	    op = 1;
10764 	    SKIP(3);
10765 	} else if (CUR == 'm') {
10766 	    op = 2;
10767 	    SKIP(3);
10768 	}
10769 	SKIP_BLANKS;
10770         xmlXPathCompUnaryExpr(ctxt);
10771 	CHECK_ERROR;
10772 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10773 	SKIP_BLANKS;
10774     }
10775 }
10776 
10777 /**
10778  * xmlXPathCompAdditiveExpr:
10779  * @ctxt:  the XPath Parser context
10780  *
10781  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10782  *                   | AdditiveExpr '+' MultiplicativeExpr
10783  *                   | AdditiveExpr '-' MultiplicativeExpr
10784  *
10785  * Compile an Additive expression.
10786  */
10787 
10788 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10789 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10790 
10791     xmlXPathCompMultiplicativeExpr(ctxt);
10792     CHECK_ERROR;
10793     SKIP_BLANKS;
10794     while ((CUR == '+') || (CUR == '-')) {
10795 	int plus;
10796 	int op1 = ctxt->comp->last;
10797 
10798         if (CUR == '+') plus = 1;
10799 	else plus = 0;
10800 	NEXT;
10801 	SKIP_BLANKS;
10802         xmlXPathCompMultiplicativeExpr(ctxt);
10803 	CHECK_ERROR;
10804 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10805 	SKIP_BLANKS;
10806     }
10807 }
10808 
10809 /**
10810  * xmlXPathCompRelationalExpr:
10811  * @ctxt:  the XPath Parser context
10812  *
10813  *  [24]   RelationalExpr ::=   AdditiveExpr
10814  *                 | RelationalExpr '<' AdditiveExpr
10815  *                 | RelationalExpr '>' AdditiveExpr
10816  *                 | RelationalExpr '<=' AdditiveExpr
10817  *                 | RelationalExpr '>=' AdditiveExpr
10818  *
10819  *  A <= B > C is allowed ? Answer from James, yes with
10820  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821  *  which is basically what got implemented.
10822  *
10823  * Compile a Relational expression, then push the result
10824  * on the stack
10825  */
10826 
10827 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10828 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829     xmlXPathCompAdditiveExpr(ctxt);
10830     CHECK_ERROR;
10831     SKIP_BLANKS;
10832     while ((CUR == '<') ||
10833            (CUR == '>') ||
10834            ((CUR == '<') && (NXT(1) == '=')) ||
10835            ((CUR == '>') && (NXT(1) == '='))) {
10836 	int inf, strict;
10837 	int op1 = ctxt->comp->last;
10838 
10839         if (CUR == '<') inf = 1;
10840 	else inf = 0;
10841 	if (NXT(1) == '=') strict = 0;
10842 	else strict = 1;
10843 	NEXT;
10844 	if (!strict) NEXT;
10845 	SKIP_BLANKS;
10846         xmlXPathCompAdditiveExpr(ctxt);
10847 	CHECK_ERROR;
10848 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10849 	SKIP_BLANKS;
10850     }
10851 }
10852 
10853 /**
10854  * xmlXPathCompEqualityExpr:
10855  * @ctxt:  the XPath Parser context
10856  *
10857  *  [23]   EqualityExpr ::=   RelationalExpr
10858  *                 | EqualityExpr '=' RelationalExpr
10859  *                 | EqualityExpr '!=' RelationalExpr
10860  *
10861  *  A != B != C is allowed ? Answer from James, yes with
10862  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10863  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10864  *  which is basically what got implemented.
10865  *
10866  * Compile an Equality expression.
10867  *
10868  */
10869 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10870 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871     xmlXPathCompRelationalExpr(ctxt);
10872     CHECK_ERROR;
10873     SKIP_BLANKS;
10874     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10875 	int eq;
10876 	int op1 = ctxt->comp->last;
10877 
10878         if (CUR == '=') eq = 1;
10879 	else eq = 0;
10880 	NEXT;
10881 	if (!eq) NEXT;
10882 	SKIP_BLANKS;
10883         xmlXPathCompRelationalExpr(ctxt);
10884 	CHECK_ERROR;
10885 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10886 	SKIP_BLANKS;
10887     }
10888 }
10889 
10890 /**
10891  * xmlXPathCompAndExpr:
10892  * @ctxt:  the XPath Parser context
10893  *
10894  *  [22]   AndExpr ::=   EqualityExpr
10895  *                 | AndExpr 'and' EqualityExpr
10896  *
10897  * Compile an AND expression.
10898  *
10899  */
10900 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10901 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902     xmlXPathCompEqualityExpr(ctxt);
10903     CHECK_ERROR;
10904     SKIP_BLANKS;
10905     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906 	int op1 = ctxt->comp->last;
10907         SKIP(3);
10908 	SKIP_BLANKS;
10909         xmlXPathCompEqualityExpr(ctxt);
10910 	CHECK_ERROR;
10911 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10912 	SKIP_BLANKS;
10913     }
10914 }
10915 
10916 /**
10917  * xmlXPathCompileExpr:
10918  * @ctxt:  the XPath Parser context
10919  *
10920  *  [14]   Expr ::=   OrExpr
10921  *  [21]   OrExpr ::=   AndExpr
10922  *                 | OrExpr 'or' AndExpr
10923  *
10924  * Parse and compile an expression
10925  */
10926 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10927 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928     xmlXPathCompAndExpr(ctxt);
10929     CHECK_ERROR;
10930     SKIP_BLANKS;
10931     while ((CUR == 'o') && (NXT(1) == 'r')) {
10932 	int op1 = ctxt->comp->last;
10933         SKIP(2);
10934 	SKIP_BLANKS;
10935         xmlXPathCompAndExpr(ctxt);
10936 	CHECK_ERROR;
10937 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10938 	SKIP_BLANKS;
10939     }
10940     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941 	/* more ops could be optimized too */
10942 	/*
10943 	* This is the main place to eliminate sorting for
10944 	* operations which don't require a sorted node-set.
10945 	* E.g. count().
10946 	*/
10947 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948     }
10949 }
10950 
10951 /**
10952  * xmlXPathCompPredicate:
10953  * @ctxt:  the XPath Parser context
10954  * @filter:  act as a filter
10955  *
10956  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10957  *  [9]   PredicateExpr ::=   Expr
10958  *
10959  * Compile a predicate expression
10960  */
10961 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10962 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963     int op1 = ctxt->comp->last;
10964 
10965     SKIP_BLANKS;
10966     if (CUR != '[') {
10967 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968     }
10969     NEXT;
10970     SKIP_BLANKS;
10971 
10972     ctxt->comp->last = -1;
10973     /*
10974     * This call to xmlXPathCompileExpr() will deactivate sorting
10975     * of the predicate result.
10976     * TODO: Sorting is still activated for filters, since I'm not
10977     *  sure if needed. Normally sorting should not be needed, since
10978     *  a filter can only diminish the number of items in a sequence,
10979     *  but won't change its order; so if the initial sequence is sorted,
10980     *  subsequent sorting is not needed.
10981     */
10982     if (! filter)
10983 	xmlXPathCompileExpr(ctxt, 0);
10984     else
10985 	xmlXPathCompileExpr(ctxt, 1);
10986     CHECK_ERROR;
10987 
10988     if (CUR != ']') {
10989 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990     }
10991 
10992     if (filter)
10993 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994     else
10995 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10996 
10997     NEXT;
10998     SKIP_BLANKS;
10999 }
11000 
11001 /**
11002  * xmlXPathCompNodeTest:
11003  * @ctxt:  the XPath Parser context
11004  * @test:  pointer to a xmlXPathTestVal
11005  * @type:  pointer to a xmlXPathTypeVal
11006  * @prefix:  placeholder for a possible name prefix
11007  *
11008  * [7] NodeTest ::=   NameTest
11009  *		    | NodeType '(' ')'
11010  *		    | 'processing-instruction' '(' Literal ')'
11011  *
11012  * [37] NameTest ::=  '*'
11013  *		    | NCName ':' '*'
11014  *		    | QName
11015  * [38] NodeType ::= 'comment'
11016  *		   | 'text'
11017  *		   | 'processing-instruction'
11018  *		   | 'node'
11019  *
11020  * Returns the name found and updates @test, @type and @prefix appropriately
11021  */
11022 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11023 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11025 		     xmlChar *name) {
11026     int blanks;
11027 
11028     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029 	STRANGE;
11030 	return(NULL);
11031     }
11032     *type = (xmlXPathTypeVal) 0;
11033     *test = (xmlXPathTestVal) 0;
11034     *prefix = NULL;
11035     SKIP_BLANKS;
11036 
11037     if ((name == NULL) && (CUR == '*')) {
11038 	/*
11039 	 * All elements
11040 	 */
11041 	NEXT;
11042 	*test = NODE_TEST_ALL;
11043 	return(NULL);
11044     }
11045 
11046     if (name == NULL)
11047 	name = xmlXPathParseNCName(ctxt);
11048     if (name == NULL) {
11049 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11050     }
11051 
11052     blanks = IS_BLANK_CH(CUR);
11053     SKIP_BLANKS;
11054     if (CUR == '(') {
11055 	NEXT;
11056 	/*
11057 	 * NodeType or PI search
11058 	 */
11059 	if (xmlStrEqual(name, BAD_CAST "comment"))
11060 	    *type = NODE_TYPE_COMMENT;
11061 	else if (xmlStrEqual(name, BAD_CAST "node"))
11062 	    *type = NODE_TYPE_NODE;
11063 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064 	    *type = NODE_TYPE_PI;
11065 	else if (xmlStrEqual(name, BAD_CAST "text"))
11066 	    *type = NODE_TYPE_TEXT;
11067 	else {
11068 	    if (name != NULL)
11069 		xmlFree(name);
11070 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11071 	}
11072 
11073 	*test = NODE_TEST_TYPE;
11074 
11075 	SKIP_BLANKS;
11076 	if (*type == NODE_TYPE_PI) {
11077 	    /*
11078 	     * Specific case: search a PI by name.
11079 	     */
11080 	    if (name != NULL)
11081 		xmlFree(name);
11082 	    name = NULL;
11083 	    if (CUR != ')') {
11084 		name = xmlXPathParseLiteral(ctxt);
11085 		CHECK_ERROR NULL;
11086 		*test = NODE_TEST_PI;
11087 		SKIP_BLANKS;
11088 	    }
11089 	}
11090 	if (CUR != ')') {
11091 	    if (name != NULL)
11092 		xmlFree(name);
11093 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11094 	}
11095 	NEXT;
11096 	return(name);
11097     }
11098     *test = NODE_TEST_NAME;
11099     if ((!blanks) && (CUR == ':')) {
11100 	NEXT;
11101 
11102 	/*
11103 	 * Since currently the parser context don't have a
11104 	 * namespace list associated:
11105 	 * The namespace name for this prefix can be computed
11106 	 * only at evaluation time. The compilation is done
11107 	 * outside of any context.
11108 	 */
11109 #if 0
11110 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11111 	if (name != NULL)
11112 	    xmlFree(name);
11113 	if (*prefix == NULL) {
11114 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115 	}
11116 #else
11117 	*prefix = name;
11118 #endif
11119 
11120 	if (CUR == '*') {
11121 	    /*
11122 	     * All elements
11123 	     */
11124 	    NEXT;
11125 	    *test = NODE_TEST_ALL;
11126 	    return(NULL);
11127 	}
11128 
11129 	name = xmlXPathParseNCName(ctxt);
11130 	if (name == NULL) {
11131 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11132 	}
11133     }
11134     return(name);
11135 }
11136 
11137 /**
11138  * xmlXPathIsAxisName:
11139  * @name:  a preparsed name token
11140  *
11141  * [6] AxisName ::=   'ancestor'
11142  *                  | 'ancestor-or-self'
11143  *                  | 'attribute'
11144  *                  | 'child'
11145  *                  | 'descendant'
11146  *                  | 'descendant-or-self'
11147  *                  | 'following'
11148  *                  | 'following-sibling'
11149  *                  | 'namespace'
11150  *                  | 'parent'
11151  *                  | 'preceding'
11152  *                  | 'preceding-sibling'
11153  *                  | 'self'
11154  *
11155  * Returns the axis or 0
11156  */
11157 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11158 xmlXPathIsAxisName(const xmlChar *name) {
11159     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11160     switch (name[0]) {
11161 	case 'a':
11162 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163 		ret = AXIS_ANCESTOR;
11164 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165 		ret = AXIS_ANCESTOR_OR_SELF;
11166 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11167 		ret = AXIS_ATTRIBUTE;
11168 	    break;
11169 	case 'c':
11170 	    if (xmlStrEqual(name, BAD_CAST "child"))
11171 		ret = AXIS_CHILD;
11172 	    break;
11173 	case 'd':
11174 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11175 		ret = AXIS_DESCENDANT;
11176 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177 		ret = AXIS_DESCENDANT_OR_SELF;
11178 	    break;
11179 	case 'f':
11180 	    if (xmlStrEqual(name, BAD_CAST "following"))
11181 		ret = AXIS_FOLLOWING;
11182 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183 		ret = AXIS_FOLLOWING_SIBLING;
11184 	    break;
11185 	case 'n':
11186 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11187 		ret = AXIS_NAMESPACE;
11188 	    break;
11189 	case 'p':
11190 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11191 		ret = AXIS_PARENT;
11192 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11193 		ret = AXIS_PRECEDING;
11194 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195 		ret = AXIS_PRECEDING_SIBLING;
11196 	    break;
11197 	case 's':
11198 	    if (xmlStrEqual(name, BAD_CAST "self"))
11199 		ret = AXIS_SELF;
11200 	    break;
11201     }
11202     return(ret);
11203 }
11204 
11205 /**
11206  * xmlXPathCompStep:
11207  * @ctxt:  the XPath Parser context
11208  *
11209  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11210  *                  | AbbreviatedStep
11211  *
11212  * [12] AbbreviatedStep ::=   '.' | '..'
11213  *
11214  * [5] AxisSpecifier ::= AxisName '::'
11215  *                  | AbbreviatedAxisSpecifier
11216  *
11217  * [13] AbbreviatedAxisSpecifier ::= '@'?
11218  *
11219  * Modified for XPtr range support as:
11220  *
11221  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222  *                     | AbbreviatedStep
11223  *                     | 'range-to' '(' Expr ')' Predicate*
11224  *
11225  * Compile one step in a Location Path
11226  * A location step of . is short for self::node(). This is
11227  * particularly useful in conjunction with //. For example, the
11228  * location path .//para is short for
11229  * self::node()/descendant-or-self::node()/child::para
11230  * and so will select all para descendant elements of the context
11231  * node.
11232  * Similarly, a location step of .. is short for parent::node().
11233  * For example, ../title is short for parent::node()/child::title
11234  * and so will select the title children of the parent of the context
11235  * node.
11236  */
11237 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11238 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239 #ifdef LIBXML_XPTR_ENABLED
11240     int rangeto = 0;
11241     int op2 = -1;
11242 #endif
11243 
11244     SKIP_BLANKS;
11245     if ((CUR == '.') && (NXT(1) == '.')) {
11246 	SKIP(2);
11247 	SKIP_BLANKS;
11248 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250     } else if (CUR == '.') {
11251 	NEXT;
11252 	SKIP_BLANKS;
11253     } else {
11254 	xmlChar *name = NULL;
11255 	const xmlChar *prefix = NULL;
11256 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11259 	int op1;
11260 
11261 	/*
11262 	 * The modification needed for XPointer change to the production
11263 	 */
11264 #ifdef LIBXML_XPTR_ENABLED
11265 	if (ctxt->xptr) {
11266 	    name = xmlXPathParseNCName(ctxt);
11267 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268                 op2 = ctxt->comp->last;
11269 		xmlFree(name);
11270 		SKIP_BLANKS;
11271 		if (CUR != '(') {
11272 		    XP_ERROR(XPATH_EXPR_ERROR);
11273 		}
11274 		NEXT;
11275 		SKIP_BLANKS;
11276 
11277 		xmlXPathCompileExpr(ctxt, 1);
11278 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11279 		CHECK_ERROR;
11280 
11281 		SKIP_BLANKS;
11282 		if (CUR != ')') {
11283 		    XP_ERROR(XPATH_EXPR_ERROR);
11284 		}
11285 		NEXT;
11286 		rangeto = 1;
11287 		goto eval_predicates;
11288 	    }
11289 	}
11290 #endif
11291 	if (CUR == '*') {
11292 	    axis = AXIS_CHILD;
11293 	} else {
11294 	    if (name == NULL)
11295 		name = xmlXPathParseNCName(ctxt);
11296 	    if (name != NULL) {
11297 		axis = xmlXPathIsAxisName(name);
11298 		if (axis != 0) {
11299 		    SKIP_BLANKS;
11300 		    if ((CUR == ':') && (NXT(1) == ':')) {
11301 			SKIP(2);
11302 			xmlFree(name);
11303 			name = NULL;
11304 		    } else {
11305 			/* an element name can conflict with an axis one :-\ */
11306 			axis = AXIS_CHILD;
11307 		    }
11308 		} else {
11309 		    axis = AXIS_CHILD;
11310 		}
11311 	    } else if (CUR == '@') {
11312 		NEXT;
11313 		axis = AXIS_ATTRIBUTE;
11314 	    } else {
11315 		axis = AXIS_CHILD;
11316 	    }
11317 	}
11318 
11319         if (ctxt->error != XPATH_EXPRESSION_OK) {
11320             xmlFree(name);
11321             return;
11322         }
11323 
11324 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11325 	if (test == 0)
11326 	    return;
11327 
11328         if ((prefix != NULL) && (ctxt->context != NULL) &&
11329 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332 	    }
11333 	}
11334 #ifdef DEBUG_STEP
11335 	xmlGenericError(xmlGenericErrorContext,
11336 		"Basis : computing new set\n");
11337 #endif
11338 
11339 #ifdef DEBUG_STEP
11340 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341 	if (ctxt->value == NULL)
11342 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11343 	else if (ctxt->value->nodesetval == NULL)
11344 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345 	else
11346 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11347 #endif
11348 
11349 #ifdef LIBXML_XPTR_ENABLED
11350 eval_predicates:
11351 #endif
11352 	op1 = ctxt->comp->last;
11353 	ctxt->comp->last = -1;
11354 
11355 	SKIP_BLANKS;
11356 	while (CUR == '[') {
11357 	    xmlXPathCompPredicate(ctxt, 0);
11358 	}
11359 
11360 #ifdef LIBXML_XPTR_ENABLED
11361 	if (rangeto) {
11362 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363 	} else
11364 #endif
11365 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366 			   test, type, (void *)prefix, (void *)name);
11367 
11368     }
11369 #ifdef DEBUG_STEP
11370     xmlGenericError(xmlGenericErrorContext, "Step : ");
11371     if (ctxt->value == NULL)
11372 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11373     else if (ctxt->value->nodesetval == NULL)
11374 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375     else
11376 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377 		ctxt->value->nodesetval);
11378 #endif
11379 }
11380 
11381 /**
11382  * xmlXPathCompRelativeLocationPath:
11383  * @ctxt:  the XPath Parser context
11384  *
11385  *  [3]   RelativeLocationPath ::=   Step
11386  *                     | RelativeLocationPath '/' Step
11387  *                     | AbbreviatedRelativeLocationPath
11388  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11389  *
11390  * Compile a relative location path.
11391  */
11392 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11393 xmlXPathCompRelativeLocationPath
11394 (xmlXPathParserContextPtr ctxt) {
11395     SKIP_BLANKS;
11396     if ((CUR == '/') && (NXT(1) == '/')) {
11397 	SKIP(2);
11398 	SKIP_BLANKS;
11399 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401     } else if (CUR == '/') {
11402 	    NEXT;
11403 	SKIP_BLANKS;
11404     }
11405     xmlXPathCompStep(ctxt);
11406     CHECK_ERROR;
11407     SKIP_BLANKS;
11408     while (CUR == '/') {
11409 	if ((CUR == '/') && (NXT(1) == '/')) {
11410 	    SKIP(2);
11411 	    SKIP_BLANKS;
11412 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414 	    xmlXPathCompStep(ctxt);
11415 	} else if (CUR == '/') {
11416 	    NEXT;
11417 	    SKIP_BLANKS;
11418 	    xmlXPathCompStep(ctxt);
11419 	}
11420 	SKIP_BLANKS;
11421     }
11422 }
11423 
11424 /**
11425  * xmlXPathCompLocationPath:
11426  * @ctxt:  the XPath Parser context
11427  *
11428  *  [1]   LocationPath ::=   RelativeLocationPath
11429  *                     | AbsoluteLocationPath
11430  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11431  *                     | AbbreviatedAbsoluteLocationPath
11432  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11433  *                           '//' RelativeLocationPath
11434  *
11435  * Compile a location path
11436  *
11437  * // is short for /descendant-or-self::node()/. For example,
11438  * //para is short for /descendant-or-self::node()/child::para and
11439  * so will select any para element in the document (even a para element
11440  * that is a document element will be selected by //para since the
11441  * document element node is a child of the root node); div//para is
11442  * short for div/descendant-or-self::node()/child::para and so will
11443  * select all para descendants of div children.
11444  */
11445 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11446 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11447     SKIP_BLANKS;
11448     if (CUR != '/') {
11449         xmlXPathCompRelativeLocationPath(ctxt);
11450     } else {
11451 	while (CUR == '/') {
11452 	    if ((CUR == '/') && (NXT(1) == '/')) {
11453 		SKIP(2);
11454 		SKIP_BLANKS;
11455 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457 		xmlXPathCompRelativeLocationPath(ctxt);
11458 	    } else if (CUR == '/') {
11459 		NEXT;
11460 		SKIP_BLANKS;
11461 		if ((CUR != 0 ) &&
11462 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463 		     (CUR == '@') || (CUR == '*')))
11464 		    xmlXPathCompRelativeLocationPath(ctxt);
11465 	    }
11466 	    CHECK_ERROR;
11467 	}
11468     }
11469 }
11470 
11471 /************************************************************************
11472  *									*
11473  *		XPath precompiled expression evaluation			*
11474  *									*
11475  ************************************************************************/
11476 
11477 static int
11478 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479 
11480 #ifdef DEBUG_STEP
11481 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11482 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11483 			  int nbNodes)
11484 {
11485     xmlGenericError(xmlGenericErrorContext, "new step : ");
11486     switch (op->value) {
11487         case AXIS_ANCESTOR:
11488             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11489             break;
11490         case AXIS_ANCESTOR_OR_SELF:
11491             xmlGenericError(xmlGenericErrorContext,
11492                             "axis 'ancestors-or-self' ");
11493             break;
11494         case AXIS_ATTRIBUTE:
11495             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11496             break;
11497         case AXIS_CHILD:
11498             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11499             break;
11500         case AXIS_DESCENDANT:
11501             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11502             break;
11503         case AXIS_DESCENDANT_OR_SELF:
11504             xmlGenericError(xmlGenericErrorContext,
11505                             "axis 'descendant-or-self' ");
11506             break;
11507         case AXIS_FOLLOWING:
11508             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11509             break;
11510         case AXIS_FOLLOWING_SIBLING:
11511             xmlGenericError(xmlGenericErrorContext,
11512                             "axis 'following-siblings' ");
11513             break;
11514         case AXIS_NAMESPACE:
11515             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11516             break;
11517         case AXIS_PARENT:
11518             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11519             break;
11520         case AXIS_PRECEDING:
11521             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11522             break;
11523         case AXIS_PRECEDING_SIBLING:
11524             xmlGenericError(xmlGenericErrorContext,
11525                             "axis 'preceding-sibling' ");
11526             break;
11527         case AXIS_SELF:
11528             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11529             break;
11530     }
11531     xmlGenericError(xmlGenericErrorContext,
11532 	" context contains %d nodes\n", nbNodes);
11533     switch (op->value2) {
11534         case NODE_TEST_NONE:
11535             xmlGenericError(xmlGenericErrorContext,
11536                             "           searching for none !!!\n");
11537             break;
11538         case NODE_TEST_TYPE:
11539             xmlGenericError(xmlGenericErrorContext,
11540                             "           searching for type %d\n", op->value3);
11541             break;
11542         case NODE_TEST_PI:
11543             xmlGenericError(xmlGenericErrorContext,
11544                             "           searching for PI !!!\n");
11545             break;
11546         case NODE_TEST_ALL:
11547             xmlGenericError(xmlGenericErrorContext,
11548                             "           searching for *\n");
11549             break;
11550         case NODE_TEST_NS:
11551             xmlGenericError(xmlGenericErrorContext,
11552                             "           searching for namespace %s\n",
11553                             op->value5);
11554             break;
11555         case NODE_TEST_NAME:
11556             xmlGenericError(xmlGenericErrorContext,
11557                             "           searching for name %s\n", op->value5);
11558             if (op->value4)
11559                 xmlGenericError(xmlGenericErrorContext,
11560                                 "           with namespace %s\n", op->value4);
11561             break;
11562     }
11563     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11564 }
11565 #endif /* DEBUG_STEP */
11566 
11567 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11568 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569 			    xmlXPathStepOpPtr op,
11570 			    xmlNodeSetPtr set,
11571 			    int contextSize,
11572 			    int hasNsNodes)
11573 {
11574     if (op->ch1 != -1) {
11575 	xmlXPathCompExprPtr comp = ctxt->comp;
11576 	/*
11577 	* Process inner predicates first.
11578 	*/
11579 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580 	    /*
11581 	    * TODO: raise an internal error.
11582 	    */
11583 	}
11584 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586 	CHECK_ERROR0;
11587 	if (contextSize <= 0)
11588 	    return(0);
11589     }
11590     if (op->ch2 != -1) {
11591 	xmlXPathContextPtr xpctxt = ctxt->context;
11592 	xmlNodePtr contextNode, oldContextNode;
11593 	xmlDocPtr oldContextDoc;
11594 	int i, res, contextPos = 0, newContextSize;
11595 	xmlXPathStepOpPtr exprOp;
11596 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597 
11598 #ifdef LIBXML_XPTR_ENABLED
11599 	/*
11600 	* URGENT TODO: Check the following:
11601 	*  We don't expect location sets if evaluating prediates, right?
11602 	*  Only filters should expect location sets, right?
11603 	*/
11604 #endif
11605 	/*
11606 	* SPEC XPath 1.0:
11607 	*  "For each node in the node-set to be filtered, the
11608 	*  PredicateExpr is evaluated with that node as the
11609 	*  context node, with the number of nodes in the
11610 	*  node-set as the context size, and with the proximity
11611 	*  position of the node in the node-set with respect to
11612 	*  the axis as the context position;"
11613 	* @oldset is the node-set" to be filtered.
11614 	*
11615 	* SPEC XPath 1.0:
11616 	*  "only predicates change the context position and
11617 	*  context size (see [2.4 Predicates])."
11618 	* Example:
11619 	*   node-set  context pos
11620 	*    nA         1
11621 	*    nB         2
11622 	*    nC         3
11623 	*   After applying predicate [position() > 1] :
11624 	*   node-set  context pos
11625 	*    nB         1
11626 	*    nC         2
11627 	*/
11628 	oldContextNode = xpctxt->node;
11629 	oldContextDoc = xpctxt->doc;
11630 	/*
11631 	* Get the expression of this predicate.
11632 	*/
11633 	exprOp = &ctxt->comp->steps[op->ch2];
11634 	newContextSize = 0;
11635 	for (i = 0; i < set->nodeNr; i++) {
11636 	    if (set->nodeTab[i] == NULL)
11637 		continue;
11638 
11639 	    contextNode = set->nodeTab[i];
11640 	    xpctxt->node = contextNode;
11641 	    xpctxt->contextSize = contextSize;
11642 	    xpctxt->proximityPosition = ++contextPos;
11643 
11644 	    /*
11645 	    * Also set the xpath document in case things like
11646 	    * key() are evaluated in the predicate.
11647 	    */
11648 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649 		(contextNode->doc != NULL))
11650 		xpctxt->doc = contextNode->doc;
11651 	    /*
11652 	    * Evaluate the predicate expression with 1 context node
11653 	    * at a time; this node is packaged into a node set; this
11654 	    * node set is handed over to the evaluation mechanism.
11655 	    */
11656 	    if (contextObj == NULL)
11657 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658 	    else
11659 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660 		    contextNode);
11661 
11662 	    valuePush(ctxt, contextObj);
11663 
11664 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11665 
11666 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667 		xmlXPathNodeSetClear(set, hasNsNodes);
11668 		newContextSize = 0;
11669 		goto evaluation_exit;
11670 	    }
11671 
11672 	    if (res != 0) {
11673 		newContextSize++;
11674 	    } else {
11675 		/*
11676 		* Remove the entry from the initial node set.
11677 		*/
11678 		set->nodeTab[i] = NULL;
11679 		if (contextNode->type == XML_NAMESPACE_DECL)
11680 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11681 	    }
11682 	    if (ctxt->value == contextObj) {
11683 		/*
11684 		* Don't free the temporary XPath object holding the
11685 		* context node, in order to avoid massive recreation
11686 		* inside this loop.
11687 		*/
11688 		valuePop(ctxt);
11689 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690 	    } else {
11691 		/*
11692 		* TODO: The object was lost in the evaluation machinery.
11693 		*  Can this happen? Maybe in internal-error cases.
11694 		*/
11695 		contextObj = NULL;
11696 	    }
11697 	}
11698 
11699 	if (contextObj != NULL) {
11700 	    if (ctxt->value == contextObj)
11701 		valuePop(ctxt);
11702 	    xmlXPathReleaseObject(xpctxt, contextObj);
11703 	}
11704 evaluation_exit:
11705 	if (exprRes != NULL)
11706 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11707 	/*
11708 	* Reset/invalidate the context.
11709 	*/
11710 	xpctxt->node = oldContextNode;
11711 	xpctxt->doc = oldContextDoc;
11712 	xpctxt->contextSize = -1;
11713 	xpctxt->proximityPosition = -1;
11714 	return(newContextSize);
11715     }
11716     return(contextSize);
11717 }
11718 
11719 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11720 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721 				      xmlXPathStepOpPtr op,
11722 				      xmlNodeSetPtr set,
11723 				      int contextSize,
11724 				      int minPos,
11725 				      int maxPos,
11726 				      int hasNsNodes)
11727 {
11728     if (op->ch1 != -1) {
11729 	xmlXPathCompExprPtr comp = ctxt->comp;
11730 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731 	    /*
11732 	    * TODO: raise an internal error.
11733 	    */
11734 	}
11735 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737 	CHECK_ERROR0;
11738 	if (contextSize <= 0)
11739 	    return(0);
11740     }
11741     /*
11742     * Check if the node set contains a sufficient number of nodes for
11743     * the requested range.
11744     */
11745     if (contextSize < minPos) {
11746 	xmlXPathNodeSetClear(set, hasNsNodes);
11747 	return(0);
11748     }
11749     if (op->ch2 == -1) {
11750 	/*
11751 	* TODO: Can this ever happen?
11752 	*/
11753 	return (contextSize);
11754     } else {
11755 	xmlDocPtr oldContextDoc;
11756 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757 	xmlXPathStepOpPtr exprOp;
11758 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759 	xmlNodePtr oldContextNode, contextNode = NULL;
11760 	xmlXPathContextPtr xpctxt = ctxt->context;
11761         int frame;
11762 
11763 #ifdef LIBXML_XPTR_ENABLED
11764 	    /*
11765 	    * URGENT TODO: Check the following:
11766 	    *  We don't expect location sets if evaluating prediates, right?
11767 	    *  Only filters should expect location sets, right?
11768 	*/
11769 #endif /* LIBXML_XPTR_ENABLED */
11770 
11771 	/*
11772 	* Save old context.
11773 	*/
11774 	oldContextNode = xpctxt->node;
11775 	oldContextDoc = xpctxt->doc;
11776 	/*
11777 	* Get the expression of this predicate.
11778 	*/
11779 	exprOp = &ctxt->comp->steps[op->ch2];
11780 	for (i = 0; i < set->nodeNr; i++) {
11781             xmlXPathObjectPtr tmp;
11782 
11783 	    if (set->nodeTab[i] == NULL)
11784 		continue;
11785 
11786 	    contextNode = set->nodeTab[i];
11787 	    xpctxt->node = contextNode;
11788 	    xpctxt->contextSize = contextSize;
11789 	    xpctxt->proximityPosition = ++contextPos;
11790 
11791 	    /*
11792 	    * Initialize the new set.
11793 	    * Also set the xpath document in case things like
11794 	    * key() evaluation are attempted on the predicate
11795 	    */
11796 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797 		(contextNode->doc != NULL))
11798 		xpctxt->doc = contextNode->doc;
11799 	    /*
11800 	    * Evaluate the predicate expression with 1 context node
11801 	    * at a time; this node is packaged into a node set; this
11802 	    * node set is handed over to the evaluation mechanism.
11803 	    */
11804 	    if (contextObj == NULL)
11805 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806 	    else
11807 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808 		    contextNode);
11809 
11810             frame = xmlXPathSetFrame(ctxt);
11811 	    valuePush(ctxt, contextObj);
11812 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11813             tmp = valuePop(ctxt);
11814             xmlXPathPopFrame(ctxt, frame);
11815 
11816 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11817                 while (tmp != contextObj) {
11818                     /*
11819                      * Free up the result
11820                      * then pop off contextObj, which will be freed later
11821                      */
11822                     xmlXPathReleaseObject(xpctxt, tmp);
11823                     tmp = valuePop(ctxt);
11824                 }
11825 		goto evaluation_error;
11826 	    }
11827             /* push the result back onto the stack */
11828             valuePush(ctxt, tmp);
11829 
11830 	    if (res)
11831 		pos++;
11832 
11833 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11834 		/*
11835 		* Fits in the requested range.
11836 		*/
11837 		newContextSize++;
11838 		if (minPos == maxPos) {
11839 		    /*
11840 		    * Only 1 node was requested.
11841 		    */
11842 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11843 			/*
11844 			* As always: take care of those nasty
11845 			* namespace nodes.
11846 			*/
11847 			set->nodeTab[i] = NULL;
11848 		    }
11849 		    xmlXPathNodeSetClear(set, hasNsNodes);
11850 		    set->nodeNr = 1;
11851 		    set->nodeTab[0] = contextNode;
11852 		    goto evaluation_exit;
11853 		}
11854 		if (pos == maxPos) {
11855 		    /*
11856 		    * We are done.
11857 		    */
11858 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859 		    goto evaluation_exit;
11860 		}
11861 	    } else {
11862 		/*
11863 		* Remove the entry from the initial node set.
11864 		*/
11865 		set->nodeTab[i] = NULL;
11866 		if (contextNode->type == XML_NAMESPACE_DECL)
11867 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868 	    }
11869 	    if (exprRes != NULL) {
11870 		xmlXPathReleaseObject(ctxt->context, exprRes);
11871 		exprRes = NULL;
11872 	    }
11873 	    if (ctxt->value == contextObj) {
11874 		/*
11875 		* Don't free the temporary XPath object holding the
11876 		* context node, in order to avoid massive recreation
11877 		* inside this loop.
11878 		*/
11879 		valuePop(ctxt);
11880 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881 	    } else {
11882 		/*
11883 		* The object was lost in the evaluation machinery.
11884 		* Can this happen? Maybe in case of internal-errors.
11885 		*/
11886 		contextObj = NULL;
11887 	    }
11888 	}
11889 	goto evaluation_exit;
11890 
11891 evaluation_error:
11892 	xmlXPathNodeSetClear(set, hasNsNodes);
11893 	newContextSize = 0;
11894 
11895 evaluation_exit:
11896 	if (contextObj != NULL) {
11897 	    if (ctxt->value == contextObj)
11898 		valuePop(ctxt);
11899 	    xmlXPathReleaseObject(xpctxt, contextObj);
11900 	}
11901 	if (exprRes != NULL)
11902 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11903 	/*
11904 	* Reset/invalidate the context.
11905 	*/
11906 	xpctxt->node = oldContextNode;
11907 	xpctxt->doc = oldContextDoc;
11908 	xpctxt->contextSize = -1;
11909 	xpctxt->proximityPosition = -1;
11910 	return(newContextSize);
11911     }
11912     return(contextSize);
11913 }
11914 
11915 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11916 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917 			    xmlXPathStepOpPtr op,
11918 			    int *maxPos)
11919 {
11920 
11921     xmlXPathStepOpPtr exprOp;
11922 
11923     /*
11924     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925     */
11926 
11927     /*
11928     * If not -1, then ch1 will point to:
11929     * 1) For predicates (XPATH_OP_PREDICATE):
11930     *    - an inner predicate operator
11931     * 2) For filters (XPATH_OP_FILTER):
11932     *    - an inner filter operater OR
11933     *    - an expression selecting the node set.
11934     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11935     */
11936     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937 	return(0);
11938 
11939     if (op->ch2 != -1) {
11940 	exprOp = &ctxt->comp->steps[op->ch2];
11941     } else
11942 	return(0);
11943 
11944     if ((exprOp != NULL) &&
11945 	(exprOp->op == XPATH_OP_VALUE) &&
11946 	(exprOp->value4 != NULL) &&
11947 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948     {
11949 	/*
11950 	* We have a "[n]" predicate here.
11951 	* TODO: Unfortunately this simplistic test here is not
11952 	* able to detect a position() predicate in compound
11953 	* expressions like "[@attr = 'a" and position() = 1],
11954 	* and even not the usage of position() in
11955 	* "[position() = 1]"; thus - obviously - a position-range,
11956 	* like it "[position() < 5]", is also not detected.
11957 	* Maybe we could rewrite the AST to ease the optimization.
11958 	*/
11959 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11960 
11961 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962 	    (float) *maxPos)
11963 	{
11964 	    return(1);
11965 	}
11966     }
11967     return(0);
11968 }
11969 
11970 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11971 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972                            xmlXPathStepOpPtr op,
11973 			   xmlNodePtr * first, xmlNodePtr * last,
11974 			   int toBool)
11975 {
11976 
11977 #define XP_TEST_HIT \
11978     if (hasAxisRange != 0) { \
11979 	if (++pos == maxPos) { \
11980 	    addNode(seq, cur); \
11981 	goto axis_range_end; } \
11982     } else { \
11983 	addNode(seq, cur); \
11984 	if (breakOnFirstHit) goto first_hit; }
11985 
11986 #define XP_TEST_HIT_NS \
11987     if (hasAxisRange != 0) { \
11988 	if (++pos == maxPos) { \
11989 	    hasNsNodes = 1; \
11990 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991 	goto axis_range_end; } \
11992     } else { \
11993 	hasNsNodes = 1; \
11994 	xmlXPathNodeSetAddNs(seq, \
11995 	xpctxt->node, (xmlNsPtr) cur); \
11996 	if (breakOnFirstHit) goto first_hit; }
11997 
11998     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001     const xmlChar *prefix = op->value4;
12002     const xmlChar *name = op->value5;
12003     const xmlChar *URI = NULL;
12004 
12005 #ifdef DEBUG_STEP
12006     int nbMatches = 0, prevMatches = 0;
12007 #endif
12008     int total = 0, hasNsNodes = 0;
12009     /* The popped object holding the context nodes */
12010     xmlXPathObjectPtr obj;
12011     /* The set of context nodes for the node tests */
12012     xmlNodeSetPtr contextSeq;
12013     int contextIdx;
12014     xmlNodePtr contextNode;
12015     /* The context node for a compound traversal */
12016     xmlNodePtr outerContextNode;
12017     /* The final resulting node set wrt to all context nodes */
12018     xmlNodeSetPtr outSeq;
12019     /*
12020     * The temporary resulting node set wrt 1 context node.
12021     * Used to feed predicate evaluation.
12022     */
12023     xmlNodeSetPtr seq;
12024     xmlNodePtr cur;
12025     /* First predicate operator */
12026     xmlXPathStepOpPtr predOp;
12027     int maxPos; /* The requested position() (when a "[n]" predicate) */
12028     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029     int breakOnFirstHit;
12030 
12031     xmlXPathTraversalFunction next = NULL;
12032     /* compound axis traversal */
12033     xmlXPathTraversalFunctionExt outerNext = NULL;
12034     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035     xmlXPathNodeSetMergeFunction mergeAndClear;
12036     xmlNodePtr oldContextNode;
12037     xmlXPathContextPtr xpctxt = ctxt->context;
12038 
12039 
12040     CHECK_TYPE0(XPATH_NODESET);
12041     obj = valuePop(ctxt);
12042     /*
12043     * Setup namespaces.
12044     */
12045     if (prefix != NULL) {
12046         URI = xmlXPathNsLookup(xpctxt, prefix);
12047         if (URI == NULL) {
12048 	    xmlXPathReleaseObject(xpctxt, obj);
12049             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050 	}
12051     }
12052     /*
12053     * Setup axis.
12054     *
12055     * MAYBE FUTURE TODO: merging optimizations:
12056     * - If the nodes to be traversed wrt to the initial nodes and
12057     *   the current axis cannot overlap, then we could avoid searching
12058     *   for duplicates during the merge.
12059     *   But the question is how/when to evaluate if they cannot overlap.
12060     *   Example: if we know that for two initial nodes, the one is
12061     *   not in the ancestor-or-self axis of the other, then we could safely
12062     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063     *   the descendant-or-self axis.
12064     */
12065     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066     switch (axis) {
12067         case AXIS_ANCESTOR:
12068             first = NULL;
12069             next = xmlXPathNextAncestor;
12070             break;
12071         case AXIS_ANCESTOR_OR_SELF:
12072             first = NULL;
12073             next = xmlXPathNextAncestorOrSelf;
12074             break;
12075         case AXIS_ATTRIBUTE:
12076             first = NULL;
12077 	    last = NULL;
12078             next = xmlXPathNextAttribute;
12079 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080             break;
12081         case AXIS_CHILD:
12082 	    last = NULL;
12083 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084 		/*
12085 		* This iterator will give us only nodes which can
12086 		* hold element nodes.
12087 		*/
12088 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089 	    }
12090 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091 		(type == NODE_TYPE_NODE))
12092 	    {
12093 		/*
12094 		* Optimization if an element node type is 'element'.
12095 		*/
12096 		next = xmlXPathNextChildElement;
12097 	    } else
12098 		next = xmlXPathNextChild;
12099 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100             break;
12101         case AXIS_DESCENDANT:
12102 	    last = NULL;
12103             next = xmlXPathNextDescendant;
12104             break;
12105         case AXIS_DESCENDANT_OR_SELF:
12106 	    last = NULL;
12107             next = xmlXPathNextDescendantOrSelf;
12108             break;
12109         case AXIS_FOLLOWING:
12110 	    last = NULL;
12111             next = xmlXPathNextFollowing;
12112             break;
12113         case AXIS_FOLLOWING_SIBLING:
12114 	    last = NULL;
12115             next = xmlXPathNextFollowingSibling;
12116             break;
12117         case AXIS_NAMESPACE:
12118             first = NULL;
12119 	    last = NULL;
12120             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122             break;
12123         case AXIS_PARENT:
12124             first = NULL;
12125             next = xmlXPathNextParent;
12126             break;
12127         case AXIS_PRECEDING:
12128             first = NULL;
12129             next = xmlXPathNextPrecedingInternal;
12130             break;
12131         case AXIS_PRECEDING_SIBLING:
12132             first = NULL;
12133             next = xmlXPathNextPrecedingSibling;
12134             break;
12135         case AXIS_SELF:
12136             first = NULL;
12137 	    last = NULL;
12138             next = xmlXPathNextSelf;
12139 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140             break;
12141     }
12142 
12143 #ifdef DEBUG_STEP
12144     xmlXPathDebugDumpStepAxis(op,
12145 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12146 #endif
12147 
12148     if (next == NULL) {
12149 	xmlXPathReleaseObject(xpctxt, obj);
12150         return(0);
12151     }
12152     contextSeq = obj->nodesetval;
12153     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154 	xmlXPathReleaseObject(xpctxt, obj);
12155         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156         return(0);
12157     }
12158     /*
12159     * Predicate optimization ---------------------------------------------
12160     * If this step has a last predicate, which contains a position(),
12161     * then we'll optimize (although not exactly "position()", but only
12162     * the  short-hand form, i.e., "[n]".
12163     *
12164     * Example - expression "/foo[parent::bar][1]":
12165     *
12166     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12167     *   ROOT                               -- op->ch1
12168     *   PREDICATE                          -- op->ch2 (predOp)
12169     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12170     *       SORT
12171     *         COLLECT  'parent' 'name' 'node' bar
12172     *           NODE
12173     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12174     *
12175     */
12176     maxPos = 0;
12177     predOp = NULL;
12178     hasPredicateRange = 0;
12179     hasAxisRange = 0;
12180     if (op->ch2 != -1) {
12181 	/*
12182 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183 	*/
12184 	predOp = &ctxt->comp->steps[op->ch2];
12185 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186 	    if (predOp->ch1 != -1) {
12187 		/*
12188 		* Use the next inner predicate operator.
12189 		*/
12190 		predOp = &ctxt->comp->steps[predOp->ch1];
12191 		hasPredicateRange = 1;
12192 	    } else {
12193 		/*
12194 		* There's no other predicate than the [n] predicate.
12195 		*/
12196 		predOp = NULL;
12197 		hasAxisRange = 1;
12198 	    }
12199 	}
12200     }
12201     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12202     /*
12203     * Axis traversal -----------------------------------------------------
12204     */
12205     /*
12206      * 2.3 Node Tests
12207      *  - For the attribute axis, the principal node type is attribute.
12208      *  - For the namespace axis, the principal node type is namespace.
12209      *  - For other axes, the principal node type is element.
12210      *
12211      * A node test * is true for any node of the
12212      * principal node type. For example, child::* will
12213      * select all element children of the context node
12214      */
12215     oldContextNode = xpctxt->node;
12216     addNode = xmlXPathNodeSetAddUnique;
12217     outSeq = NULL;
12218     seq = NULL;
12219     outerContextNode = NULL;
12220     contextNode = NULL;
12221     contextIdx = 0;
12222 
12223 
12224     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225 	if (outerNext != NULL) {
12226 	    /*
12227 	    * This is a compound traversal.
12228 	    */
12229 	    if (contextNode == NULL) {
12230 		/*
12231 		* Set the context for the outer traversal.
12232 		*/
12233 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12234 		contextNode = outerNext(NULL, outerContextNode);
12235 	    } else
12236 		contextNode = outerNext(contextNode, outerContextNode);
12237 	    if (contextNode == NULL)
12238 		continue;
12239 	    /*
12240 	    * Set the context for the main traversal.
12241 	    */
12242 	    xpctxt->node = contextNode;
12243 	} else
12244 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245 
12246 	if (seq == NULL) {
12247 	    seq = xmlXPathNodeSetCreate(NULL);
12248 	    if (seq == NULL) {
12249 		total = 0;
12250 		goto error;
12251 	    }
12252 	}
12253 	/*
12254 	* Traverse the axis and test the nodes.
12255 	*/
12256 	pos = 0;
12257 	cur = NULL;
12258 	hasNsNodes = 0;
12259         do {
12260             cur = next(ctxt, cur);
12261             if (cur == NULL)
12262                 break;
12263 
12264 	    /*
12265 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12266 	    */
12267             if ((first != NULL) && (*first != NULL)) {
12268 		if (*first == cur)
12269 		    break;
12270 		if (((total % 256) == 0) &&
12271 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12273 #else
12274 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12275 #endif
12276 		{
12277 		    break;
12278 		}
12279 	    }
12280 	    if ((last != NULL) && (*last != NULL)) {
12281 		if (*last == cur)
12282 		    break;
12283 		if (((total % 256) == 0) &&
12284 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12286 #else
12287 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12288 #endif
12289 		{
12290 		    break;
12291 		}
12292 	    }
12293 
12294             total++;
12295 
12296 #ifdef DEBUG_STEP
12297             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298 #endif
12299 
12300 	    switch (test) {
12301                 case NODE_TEST_NONE:
12302 		    total = 0;
12303                     STRANGE
12304 		    goto error;
12305                 case NODE_TEST_TYPE:
12306 		    /*
12307 		    * TODO: Don't we need to use
12308 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12309 		    *  Surprisingly, some c14n tests fail, if we do this.
12310 		    */
12311 		    if (type == NODE_TYPE_NODE) {
12312 			switch (cur->type) {
12313 			    case XML_DOCUMENT_NODE:
12314 			    case XML_HTML_DOCUMENT_NODE:
12315 #ifdef LIBXML_DOCB_ENABLED
12316 			    case XML_DOCB_DOCUMENT_NODE:
12317 #endif
12318 			    case XML_ELEMENT_NODE:
12319 			    case XML_ATTRIBUTE_NODE:
12320 			    case XML_PI_NODE:
12321 			    case XML_COMMENT_NODE:
12322 			    case XML_CDATA_SECTION_NODE:
12323 			    case XML_TEXT_NODE:
12324 			    case XML_NAMESPACE_DECL:
12325 				XP_TEST_HIT
12326 				break;
12327 			    default:
12328 				break;
12329 			}
12330 		    } else if (cur->type == type) {
12331 			if (type == XML_NAMESPACE_DECL)
12332 			    XP_TEST_HIT_NS
12333 			else
12334 			    XP_TEST_HIT
12335 		    } else if ((type == NODE_TYPE_TEXT) &&
12336 			 (cur->type == XML_CDATA_SECTION_NODE))
12337 		    {
12338 			XP_TEST_HIT
12339 		    }
12340 		    break;
12341                 case NODE_TEST_PI:
12342                     if ((cur->type == XML_PI_NODE) &&
12343                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12344 		    {
12345 			XP_TEST_HIT
12346                     }
12347                     break;
12348                 case NODE_TEST_ALL:
12349                     if (axis == AXIS_ATTRIBUTE) {
12350                         if (cur->type == XML_ATTRIBUTE_NODE)
12351 			{
12352 			    XP_TEST_HIT
12353                         }
12354                     } else if (axis == AXIS_NAMESPACE) {
12355                         if (cur->type == XML_NAMESPACE_DECL)
12356 			{
12357 			    XP_TEST_HIT_NS
12358                         }
12359                     } else {
12360                         if (cur->type == XML_ELEMENT_NODE) {
12361                             if (prefix == NULL)
12362 			    {
12363 				XP_TEST_HIT
12364 
12365                             } else if ((cur->ns != NULL) &&
12366 				(xmlStrEqual(URI, cur->ns->href)))
12367 			    {
12368 				XP_TEST_HIT
12369                             }
12370                         }
12371                     }
12372                     break;
12373                 case NODE_TEST_NS:{
12374                         TODO;
12375                         break;
12376                     }
12377                 case NODE_TEST_NAME:
12378                     if (axis == AXIS_ATTRIBUTE) {
12379                         if (cur->type != XML_ATTRIBUTE_NODE)
12380 			    break;
12381 		    } else if (axis == AXIS_NAMESPACE) {
12382                         if (cur->type != XML_NAMESPACE_DECL)
12383 			    break;
12384 		    } else {
12385 		        if (cur->type != XML_ELEMENT_NODE)
12386 			    break;
12387 		    }
12388                     switch (cur->type) {
12389                         case XML_ELEMENT_NODE:
12390                             if (xmlStrEqual(name, cur->name)) {
12391                                 if (prefix == NULL) {
12392                                     if (cur->ns == NULL)
12393 				    {
12394 					XP_TEST_HIT
12395                                     }
12396                                 } else {
12397                                     if ((cur->ns != NULL) &&
12398                                         (xmlStrEqual(URI, cur->ns->href)))
12399 				    {
12400 					XP_TEST_HIT
12401                                     }
12402                                 }
12403                             }
12404                             break;
12405                         case XML_ATTRIBUTE_NODE:{
12406                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12407 
12408                                 if (xmlStrEqual(name, attr->name)) {
12409                                     if (prefix == NULL) {
12410                                         if ((attr->ns == NULL) ||
12411                                             (attr->ns->prefix == NULL))
12412 					{
12413 					    XP_TEST_HIT
12414                                         }
12415                                     } else {
12416                                         if ((attr->ns != NULL) &&
12417                                             (xmlStrEqual(URI,
12418 					      attr->ns->href)))
12419 					{
12420 					    XP_TEST_HIT
12421                                         }
12422                                     }
12423                                 }
12424                                 break;
12425                             }
12426                         case XML_NAMESPACE_DECL:
12427                             if (cur->type == XML_NAMESPACE_DECL) {
12428                                 xmlNsPtr ns = (xmlNsPtr) cur;
12429 
12430                                 if ((ns->prefix != NULL) && (name != NULL)
12431                                     && (xmlStrEqual(ns->prefix, name)))
12432 				{
12433 				    XP_TEST_HIT_NS
12434                                 }
12435                             }
12436                             break;
12437                         default:
12438                             break;
12439                     }
12440                     break;
12441 	    } /* switch(test) */
12442         } while (cur != NULL);
12443 
12444 	goto apply_predicates;
12445 
12446 axis_range_end: /* ----------------------------------------------------- */
12447 	/*
12448 	* We have a "/foo[n]", and position() = n was reached.
12449 	* Note that we can have as well "/foo/::parent::foo[1]", so
12450 	* a duplicate-aware merge is still needed.
12451 	* Merge with the result.
12452 	*/
12453 	if (outSeq == NULL) {
12454 	    outSeq = seq;
12455 	    seq = NULL;
12456 	} else
12457 	    outSeq = mergeAndClear(outSeq, seq, 0);
12458 	/*
12459 	* Break if only a true/false result was requested.
12460 	*/
12461 	if (toBool)
12462 	    break;
12463 	continue;
12464 
12465 first_hit: /* ---------------------------------------------------------- */
12466 	/*
12467 	* Break if only a true/false result was requested and
12468 	* no predicates existed and a node test succeeded.
12469 	*/
12470 	if (outSeq == NULL) {
12471 	    outSeq = seq;
12472 	    seq = NULL;
12473 	} else
12474 	    outSeq = mergeAndClear(outSeq, seq, 0);
12475 	break;
12476 
12477 #ifdef DEBUG_STEP
12478 	if (seq != NULL)
12479 	    nbMatches += seq->nodeNr;
12480 #endif
12481 
12482 apply_predicates: /* --------------------------------------------------- */
12483         /*
12484 	* Apply predicates.
12485 	*/
12486         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487 	    /*
12488 	    * E.g. when we have a "/foo[some expression][n]".
12489 	    */
12490 	    /*
12491 	    * QUESTION TODO: The old predicate evaluation took into
12492 	    *  account location-sets.
12493 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494 	    *  Do we expect such a set here?
12495 	    *  All what I learned now from the evaluation semantics
12496 	    *  does not indicate that a location-set will be processed
12497 	    *  here, so this looks OK.
12498 	    */
12499 	    /*
12500 	    * Iterate over all predicates, starting with the outermost
12501 	    * predicate.
12502 	    * TODO: Problem: we cannot execute the inner predicates first
12503 	    *  since we cannot go back *up* the operator tree!
12504 	    *  Options we have:
12505 	    *  1) Use of recursive functions (like is it currently done
12506 	    *     via xmlXPathCompOpEval())
12507 	    *  2) Add a predicate evaluation information stack to the
12508 	    *     context struct
12509 	    *  3) Change the way the operators are linked; we need a
12510 	    *     "parent" field on xmlXPathStepOp
12511 	    *
12512 	    * For the moment, I'll try to solve this with a recursive
12513 	    * function: xmlXPathCompOpEvalPredicate().
12514 	    */
12515 	    size = seq->nodeNr;
12516 	    if (hasPredicateRange != 0)
12517 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519 	    else
12520 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521 		    predOp, seq, size, hasNsNodes);
12522 
12523 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12524 		total = 0;
12525 		goto error;
12526 	    }
12527 	    /*
12528 	    * Add the filtered set of nodes to the result node set.
12529 	    */
12530 	    if (newSize == 0) {
12531 		/*
12532 		* The predicates filtered all nodes out.
12533 		*/
12534 		xmlXPathNodeSetClear(seq, hasNsNodes);
12535 	    } else if (seq->nodeNr > 0) {
12536 		/*
12537 		* Add to result set.
12538 		*/
12539 		if (outSeq == NULL) {
12540 		    if (size != newSize) {
12541 			/*
12542 			* We need to merge and clear here, since
12543 			* the sequence will contained NULLed entries.
12544 			*/
12545 			outSeq = mergeAndClear(NULL, seq, 1);
12546 		    } else {
12547 			outSeq = seq;
12548 			seq = NULL;
12549 		    }
12550 		} else
12551 		    outSeq = mergeAndClear(outSeq, seq,
12552 			(size != newSize) ? 1: 0);
12553 		/*
12554 		* Break if only a true/false result was requested.
12555 		*/
12556 		if (toBool)
12557 		    break;
12558 	    }
12559         } else if (seq->nodeNr > 0) {
12560 	    /*
12561 	    * Add to result set.
12562 	    */
12563 	    if (outSeq == NULL) {
12564 		outSeq = seq;
12565 		seq = NULL;
12566 	    } else {
12567 		outSeq = mergeAndClear(outSeq, seq, 0);
12568 	    }
12569 	}
12570     }
12571 
12572 error:
12573     if ((obj->boolval) && (obj->user != NULL)) {
12574 	/*
12575 	* QUESTION TODO: What does this do and why?
12576 	* TODO: Do we have to do this also for the "error"
12577 	* cleanup further down?
12578 	*/
12579 	ctxt->value->boolval = 1;
12580 	ctxt->value->user = obj->user;
12581 	obj->user = NULL;
12582 	obj->boolval = 0;
12583     }
12584     xmlXPathReleaseObject(xpctxt, obj);
12585 
12586     /*
12587     * Ensure we return at least an emtpy set.
12588     */
12589     if (outSeq == NULL) {
12590 	if ((seq != NULL) && (seq->nodeNr == 0))
12591 	    outSeq = seq;
12592 	else
12593 	    outSeq = xmlXPathNodeSetCreate(NULL);
12594         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12595     }
12596     if ((seq != NULL) && (seq != outSeq)) {
12597 	 xmlXPathFreeNodeSet(seq);
12598     }
12599     /*
12600     * Hand over the result. Better to push the set also in
12601     * case of errors.
12602     */
12603     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604     /*
12605     * Reset the context node.
12606     */
12607     xpctxt->node = oldContextNode;
12608 
12609 #ifdef DEBUG_STEP
12610     xmlGenericError(xmlGenericErrorContext,
12611 	"\nExamined %d nodes, found %d nodes at that step\n",
12612 	total, nbMatches);
12613 #endif
12614 
12615     return(total);
12616 }
12617 
12618 static int
12619 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12621 
12622 /**
12623  * xmlXPathCompOpEvalFirst:
12624  * @ctxt:  the XPath parser context with the compiled expression
12625  * @op:  an XPath compiled operation
12626  * @first:  the first elem found so far
12627  *
12628  * Evaluate the Precompiled XPath operation searching only the first
12629  * element in document order
12630  *
12631  * Returns the number of examined objects.
12632  */
12633 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12636 {
12637     int total = 0, cur;
12638     xmlXPathCompExprPtr comp;
12639     xmlXPathObjectPtr arg1, arg2;
12640 
12641     CHECK_ERROR0;
12642     comp = ctxt->comp;
12643     switch (op->op) {
12644         case XPATH_OP_END:
12645             return (0);
12646         case XPATH_OP_UNION:
12647             total =
12648                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649                                         first);
12650 	    CHECK_ERROR0;
12651             if ((ctxt->value != NULL)
12652                 && (ctxt->value->type == XPATH_NODESET)
12653                 && (ctxt->value->nodesetval != NULL)
12654                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655                 /*
12656                  * limit tree traversing to first node in the result
12657                  */
12658 		/*
12659 		* OPTIMIZE TODO: This implicitely sorts
12660 		*  the result, even if not needed. E.g. if the argument
12661 		*  of the count() function, no sorting is needed.
12662 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12663 		*  aready sorted?
12664 		*/
12665 		if (ctxt->value->nodesetval->nodeNr > 1)
12666 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667                 *first = ctxt->value->nodesetval->nodeTab[0];
12668             }
12669             cur =
12670                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671                                         first);
12672 	    CHECK_ERROR0;
12673             CHECK_TYPE0(XPATH_NODESET);
12674             arg2 = valuePop(ctxt);
12675 
12676             CHECK_TYPE0(XPATH_NODESET);
12677             arg1 = valuePop(ctxt);
12678 
12679             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680                                                     arg2->nodesetval);
12681             valuePush(ctxt, arg1);
12682 	    xmlXPathReleaseObject(ctxt->context, arg2);
12683             /* optimizer */
12684 	    if (total > cur)
12685 		xmlXPathCompSwap(op);
12686             return (total + cur);
12687         case XPATH_OP_ROOT:
12688             xmlXPathRoot(ctxt);
12689             return (0);
12690         case XPATH_OP_NODE:
12691             if (op->ch1 != -1)
12692                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693 	    CHECK_ERROR0;
12694             if (op->ch2 != -1)
12695                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696 	    CHECK_ERROR0;
12697 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698 		ctxt->context->node));
12699             return (total);
12700         case XPATH_OP_RESET:
12701             if (op->ch1 != -1)
12702                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12703 	    CHECK_ERROR0;
12704             if (op->ch2 != -1)
12705                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12706 	    CHECK_ERROR0;
12707             ctxt->context->node = NULL;
12708             return (total);
12709         case XPATH_OP_COLLECT:{
12710                 if (op->ch1 == -1)
12711                     return (total);
12712 
12713                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12714 		CHECK_ERROR0;
12715 
12716                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12717                 return (total);
12718             }
12719         case XPATH_OP_VALUE:
12720             valuePush(ctxt,
12721                       xmlXPathCacheObjectCopy(ctxt->context,
12722 			(xmlXPathObjectPtr) op->value4));
12723             return (0);
12724         case XPATH_OP_SORT:
12725             if (op->ch1 != -1)
12726                 total +=
12727                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728                                             first);
12729 	    CHECK_ERROR0;
12730             if ((ctxt->value != NULL)
12731                 && (ctxt->value->type == XPATH_NODESET)
12732                 && (ctxt->value->nodesetval != NULL)
12733 		&& (ctxt->value->nodesetval->nodeNr > 1))
12734                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735             return (total);
12736 #ifdef XP_OPTIMIZED_FILTER_FIRST
12737 	case XPATH_OP_FILTER:
12738                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12739             return (total);
12740 #endif
12741         default:
12742             return (xmlXPathCompOpEval(ctxt, op));
12743     }
12744 }
12745 
12746 /**
12747  * xmlXPathCompOpEvalLast:
12748  * @ctxt:  the XPath parser context with the compiled expression
12749  * @op:  an XPath compiled operation
12750  * @last:  the last elem found so far
12751  *
12752  * Evaluate the Precompiled XPath operation searching only the last
12753  * element in document order
12754  *
12755  * Returns the number of nodes traversed
12756  */
12757 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12758 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759                        xmlNodePtr * last)
12760 {
12761     int total = 0, cur;
12762     xmlXPathCompExprPtr comp;
12763     xmlXPathObjectPtr arg1, arg2;
12764     xmlNodePtr bak;
12765     xmlDocPtr bakd;
12766     int pp;
12767     int cs;
12768 
12769     CHECK_ERROR0;
12770     comp = ctxt->comp;
12771     switch (op->op) {
12772         case XPATH_OP_END:
12773             return (0);
12774         case XPATH_OP_UNION:
12775 	    bakd = ctxt->context->doc;
12776 	    bak = ctxt->context->node;
12777 	    pp = ctxt->context->proximityPosition;
12778 	    cs = ctxt->context->contextSize;
12779             total =
12780                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12781 	    CHECK_ERROR0;
12782             if ((ctxt->value != NULL)
12783                 && (ctxt->value->type == XPATH_NODESET)
12784                 && (ctxt->value->nodesetval != NULL)
12785                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786                 /*
12787                  * limit tree traversing to first node in the result
12788                  */
12789 		if (ctxt->value->nodesetval->nodeNr > 1)
12790 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12791                 *last =
12792                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12793                                                      nodesetval->nodeNr -
12794                                                      1];
12795             }
12796 	    ctxt->context->doc = bakd;
12797 	    ctxt->context->node = bak;
12798 	    ctxt->context->proximityPosition = pp;
12799 	    ctxt->context->contextSize = cs;
12800             cur =
12801                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12802 	    CHECK_ERROR0;
12803             if ((ctxt->value != NULL)
12804                 && (ctxt->value->type == XPATH_NODESET)
12805                 && (ctxt->value->nodesetval != NULL)
12806                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12807             }
12808             CHECK_TYPE0(XPATH_NODESET);
12809             arg2 = valuePop(ctxt);
12810 
12811             CHECK_TYPE0(XPATH_NODESET);
12812             arg1 = valuePop(ctxt);
12813 
12814             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815                                                     arg2->nodesetval);
12816             valuePush(ctxt, arg1);
12817 	    xmlXPathReleaseObject(ctxt->context, arg2);
12818             /* optimizer */
12819 	    if (total > cur)
12820 		xmlXPathCompSwap(op);
12821             return (total + cur);
12822         case XPATH_OP_ROOT:
12823             xmlXPathRoot(ctxt);
12824             return (0);
12825         case XPATH_OP_NODE:
12826             if (op->ch1 != -1)
12827                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12828 	    CHECK_ERROR0;
12829             if (op->ch2 != -1)
12830                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831 	    CHECK_ERROR0;
12832 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833 		ctxt->context->node));
12834             return (total);
12835         case XPATH_OP_RESET:
12836             if (op->ch1 != -1)
12837                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838 	    CHECK_ERROR0;
12839             if (op->ch2 != -1)
12840                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12841 	    CHECK_ERROR0;
12842             ctxt->context->node = NULL;
12843             return (total);
12844         case XPATH_OP_COLLECT:{
12845                 if (op->ch1 == -1)
12846                     return (0);
12847 
12848                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12849 		CHECK_ERROR0;
12850 
12851                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12852                 return (total);
12853             }
12854         case XPATH_OP_VALUE:
12855             valuePush(ctxt,
12856                       xmlXPathCacheObjectCopy(ctxt->context,
12857 			(xmlXPathObjectPtr) op->value4));
12858             return (0);
12859         case XPATH_OP_SORT:
12860             if (op->ch1 != -1)
12861                 total +=
12862                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863                                            last);
12864 	    CHECK_ERROR0;
12865             if ((ctxt->value != NULL)
12866                 && (ctxt->value->type == XPATH_NODESET)
12867                 && (ctxt->value->nodesetval != NULL)
12868 		&& (ctxt->value->nodesetval->nodeNr > 1))
12869                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870             return (total);
12871         default:
12872             return (xmlXPathCompOpEval(ctxt, op));
12873     }
12874 }
12875 
12876 #ifdef XP_OPTIMIZED_FILTER_FIRST
12877 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12878 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12880 {
12881     int total = 0;
12882     xmlXPathCompExprPtr comp;
12883     xmlXPathObjectPtr res;
12884     xmlXPathObjectPtr obj;
12885     xmlNodeSetPtr oldset;
12886     xmlNodePtr oldnode;
12887     xmlDocPtr oldDoc;
12888     int i;
12889 
12890     CHECK_ERROR0;
12891     comp = ctxt->comp;
12892     /*
12893     * Optimization for ()[last()] selection i.e. the last elem
12894     */
12895     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898 	int f = comp->steps[op->ch2].ch1;
12899 
12900 	if ((f != -1) &&
12901 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902 	    (comp->steps[f].value5 == NULL) &&
12903 	    (comp->steps[f].value == 0) &&
12904 	    (comp->steps[f].value4 != NULL) &&
12905 	    (xmlStrEqual
12906 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12907 	    xmlNodePtr last = NULL;
12908 
12909 	    total +=
12910 		xmlXPathCompOpEvalLast(ctxt,
12911 		    &comp->steps[op->ch1],
12912 		    &last);
12913 	    CHECK_ERROR0;
12914 	    /*
12915 	    * The nodeset should be in document order,
12916 	    * Keep only the last value
12917 	    */
12918 	    if ((ctxt->value != NULL) &&
12919 		(ctxt->value->type == XPATH_NODESET) &&
12920 		(ctxt->value->nodesetval != NULL) &&
12921 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12922 		(ctxt->value->nodesetval->nodeNr > 1)) {
12923 		ctxt->value->nodesetval->nodeTab[0] =
12924 		    ctxt->value->nodesetval->nodeTab[ctxt->
12925 		    value->
12926 		    nodesetval->
12927 		    nodeNr -
12928 		    1];
12929 		ctxt->value->nodesetval->nodeNr = 1;
12930 		*first = *(ctxt->value->nodesetval->nodeTab);
12931 	    }
12932 	    return (total);
12933 	}
12934     }
12935 
12936     if (op->ch1 != -1)
12937 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938     CHECK_ERROR0;
12939     if (op->ch2 == -1)
12940 	return (total);
12941     if (ctxt->value == NULL)
12942 	return (total);
12943 
12944 #ifdef LIBXML_XPTR_ENABLED
12945     oldnode = ctxt->context->node;
12946     /*
12947     * Hum are we filtering the result of an XPointer expression
12948     */
12949     if (ctxt->value->type == XPATH_LOCATIONSET) {
12950 	xmlXPathObjectPtr tmp = NULL;
12951 	xmlLocationSetPtr newlocset = NULL;
12952 	xmlLocationSetPtr oldlocset;
12953 
12954 	/*
12955 	* Extract the old locset, and then evaluate the result of the
12956 	* expression for all the element in the locset. use it to grow
12957 	* up a new locset.
12958 	*/
12959 	CHECK_TYPE0(XPATH_LOCATIONSET);
12960 	obj = valuePop(ctxt);
12961 	oldlocset = obj->user;
12962 	ctxt->context->node = NULL;
12963 
12964 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965 	    ctxt->context->contextSize = 0;
12966 	    ctxt->context->proximityPosition = 0;
12967 	    if (op->ch2 != -1)
12968 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969 	    res = valuePop(ctxt);
12970 	    if (res != NULL) {
12971 		xmlXPathReleaseObject(ctxt->context, res);
12972 	    }
12973 	    valuePush(ctxt, obj);
12974 	    CHECK_ERROR0;
12975 	    return (total);
12976 	}
12977 	newlocset = xmlXPtrLocationSetCreate(NULL);
12978 
12979 	for (i = 0; i < oldlocset->locNr; i++) {
12980 	    /*
12981 	    * Run the evaluation with a node list made of a
12982 	    * single item in the nodelocset.
12983 	    */
12984 	    ctxt->context->node = oldlocset->locTab[i]->user;
12985 	    ctxt->context->contextSize = oldlocset->locNr;
12986 	    ctxt->context->proximityPosition = i + 1;
12987 	    if (tmp == NULL) {
12988 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989 		    ctxt->context->node);
12990 	    } else {
12991 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992 		    ctxt->context->node);
12993 	    }
12994 	    valuePush(ctxt, tmp);
12995 	    if (op->ch2 != -1)
12996 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12998 		xmlXPathFreeObject(obj);
12999 		return(0);
13000 	    }
13001 	    /*
13002 	    * The result of the evaluation need to be tested to
13003 	    * decided whether the filter succeeded or not
13004 	    */
13005 	    res = valuePop(ctxt);
13006 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007 		xmlXPtrLocationSetAdd(newlocset,
13008 		    xmlXPathCacheObjectCopy(ctxt->context,
13009 			oldlocset->locTab[i]));
13010 	    }
13011 	    /*
13012 	    * Cleanup
13013 	    */
13014 	    if (res != NULL) {
13015 		xmlXPathReleaseObject(ctxt->context, res);
13016 	    }
13017 	    if (ctxt->value == tmp) {
13018 		valuePop(ctxt);
13019 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13020 		/*
13021 		* REVISIT TODO: Don't create a temporary nodeset
13022 		* for everly iteration.
13023 		*/
13024 		/* OLD: xmlXPathFreeObject(res); */
13025 	    } else
13026 		tmp = NULL;
13027 	    ctxt->context->node = NULL;
13028 	    /*
13029 	    * Only put the first node in the result, then leave.
13030 	    */
13031 	    if (newlocset->locNr > 0) {
13032 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033 		break;
13034 	    }
13035 	}
13036 	if (tmp != NULL) {
13037 	    xmlXPathReleaseObject(ctxt->context, tmp);
13038 	}
13039 	/*
13040 	* The result is used as the new evaluation locset.
13041 	*/
13042 	xmlXPathReleaseObject(ctxt->context, obj);
13043 	ctxt->context->node = NULL;
13044 	ctxt->context->contextSize = -1;
13045 	ctxt->context->proximityPosition = -1;
13046 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047 	ctxt->context->node = oldnode;
13048 	return (total);
13049     }
13050 #endif /* LIBXML_XPTR_ENABLED */
13051 
13052     /*
13053     * Extract the old set, and then evaluate the result of the
13054     * expression for all the element in the set. use it to grow
13055     * up a new set.
13056     */
13057     CHECK_TYPE0(XPATH_NODESET);
13058     obj = valuePop(ctxt);
13059     oldset = obj->nodesetval;
13060 
13061     oldnode = ctxt->context->node;
13062     oldDoc = ctxt->context->doc;
13063     ctxt->context->node = NULL;
13064 
13065     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066 	ctxt->context->contextSize = 0;
13067 	ctxt->context->proximityPosition = 0;
13068 	/* QUESTION TODO: Why was this code commented out?
13069 	    if (op->ch2 != -1)
13070 		total +=
13071 		    xmlXPathCompOpEval(ctxt,
13072 			&comp->steps[op->ch2]);
13073 	    CHECK_ERROR0;
13074 	    res = valuePop(ctxt);
13075 	    if (res != NULL)
13076 		xmlXPathFreeObject(res);
13077 	*/
13078 	valuePush(ctxt, obj);
13079 	ctxt->context->node = oldnode;
13080 	CHECK_ERROR0;
13081     } else {
13082 	xmlNodeSetPtr newset;
13083 	xmlXPathObjectPtr tmp = NULL;
13084 	/*
13085 	* Initialize the new set.
13086 	* Also set the xpath document in case things like
13087 	* key() evaluation are attempted on the predicate
13088 	*/
13089 	newset = xmlXPathNodeSetCreate(NULL);
13090         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13091 
13092 	for (i = 0; i < oldset->nodeNr; i++) {
13093 	    /*
13094 	    * Run the evaluation with a node list made of
13095 	    * a single item in the nodeset.
13096 	    */
13097 	    ctxt->context->node = oldset->nodeTab[i];
13098 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099 		(oldset->nodeTab[i]->doc != NULL))
13100 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13101 	    if (tmp == NULL) {
13102 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103 		    ctxt->context->node);
13104 	    } else {
13105 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106 		    ctxt->context->node);
13107 	    }
13108 	    valuePush(ctxt, tmp);
13109 	    ctxt->context->contextSize = oldset->nodeNr;
13110 	    ctxt->context->proximityPosition = i + 1;
13111 	    if (op->ch2 != -1)
13112 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13114 		xmlXPathFreeNodeSet(newset);
13115 		xmlXPathFreeObject(obj);
13116 		return(0);
13117 	    }
13118 	    /*
13119 	    * The result of the evaluation needs to be tested to
13120 	    * decide whether the filter succeeded or not
13121 	    */
13122 	    res = valuePop(ctxt);
13123 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13125 	    }
13126 	    /*
13127 	    * Cleanup
13128 	    */
13129 	    if (res != NULL) {
13130 		xmlXPathReleaseObject(ctxt->context, res);
13131 	    }
13132 	    if (ctxt->value == tmp) {
13133 		valuePop(ctxt);
13134 		/*
13135 		* Don't free the temporary nodeset
13136 		* in order to avoid massive recreation inside this
13137 		* loop.
13138 		*/
13139 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13140 	    } else
13141 		tmp = NULL;
13142 	    ctxt->context->node = NULL;
13143 	    /*
13144 	    * Only put the first node in the result, then leave.
13145 	    */
13146 	    if (newset->nodeNr > 0) {
13147 		*first = *(newset->nodeTab);
13148 		break;
13149 	    }
13150 	}
13151 	if (tmp != NULL) {
13152 	    xmlXPathReleaseObject(ctxt->context, tmp);
13153 	}
13154 	/*
13155 	* The result is used as the new evaluation set.
13156 	*/
13157 	xmlXPathReleaseObject(ctxt->context, obj);
13158 	ctxt->context->node = NULL;
13159 	ctxt->context->contextSize = -1;
13160 	ctxt->context->proximityPosition = -1;
13161 	/* may want to move this past the '}' later */
13162 	ctxt->context->doc = oldDoc;
13163 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13164     }
13165     ctxt->context->node = oldnode;
13166     return(total);
13167 }
13168 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13169 
13170 /**
13171  * xmlXPathCompOpEval:
13172  * @ctxt:  the XPath parser context with the compiled expression
13173  * @op:  an XPath compiled operation
13174  *
13175  * Evaluate the Precompiled XPath operation
13176  * Returns the number of nodes traversed
13177  */
13178 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13179 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180 {
13181     int total = 0;
13182     int equal, ret;
13183     xmlXPathCompExprPtr comp;
13184     xmlXPathObjectPtr arg1, arg2;
13185     xmlNodePtr bak;
13186     xmlDocPtr bakd;
13187     int pp;
13188     int cs;
13189 
13190     CHECK_ERROR0;
13191     comp = ctxt->comp;
13192     switch (op->op) {
13193         case XPATH_OP_END:
13194             return (0);
13195         case XPATH_OP_AND:
13196 	    bakd = ctxt->context->doc;
13197 	    bak = ctxt->context->node;
13198 	    pp = ctxt->context->proximityPosition;
13199 	    cs = ctxt->context->contextSize;
13200             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13201 	    CHECK_ERROR0;
13202             xmlXPathBooleanFunction(ctxt, 1);
13203             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204                 return (total);
13205             arg2 = valuePop(ctxt);
13206 	    ctxt->context->doc = bakd;
13207 	    ctxt->context->node = bak;
13208 	    ctxt->context->proximityPosition = pp;
13209 	    ctxt->context->contextSize = cs;
13210             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13211 	    if (ctxt->error) {
13212 		xmlXPathFreeObject(arg2);
13213 		return(0);
13214 	    }
13215             xmlXPathBooleanFunction(ctxt, 1);
13216             arg1 = valuePop(ctxt);
13217             arg1->boolval &= arg2->boolval;
13218             valuePush(ctxt, arg1);
13219 	    xmlXPathReleaseObject(ctxt->context, arg2);
13220             return (total);
13221         case XPATH_OP_OR:
13222 	    bakd = ctxt->context->doc;
13223 	    bak = ctxt->context->node;
13224 	    pp = ctxt->context->proximityPosition;
13225 	    cs = ctxt->context->contextSize;
13226             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227 	    CHECK_ERROR0;
13228             xmlXPathBooleanFunction(ctxt, 1);
13229             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230                 return (total);
13231             arg2 = valuePop(ctxt);
13232 	    ctxt->context->doc = bakd;
13233 	    ctxt->context->node = bak;
13234 	    ctxt->context->proximityPosition = pp;
13235 	    ctxt->context->contextSize = cs;
13236             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13237 	    if (ctxt->error) {
13238 		xmlXPathFreeObject(arg2);
13239 		return(0);
13240 	    }
13241             xmlXPathBooleanFunction(ctxt, 1);
13242             arg1 = valuePop(ctxt);
13243             arg1->boolval |= arg2->boolval;
13244             valuePush(ctxt, arg1);
13245 	    xmlXPathReleaseObject(ctxt->context, arg2);
13246             return (total);
13247         case XPATH_OP_EQUAL:
13248 	    bakd = ctxt->context->doc;
13249 	    bak = ctxt->context->node;
13250 	    pp = ctxt->context->proximityPosition;
13251 	    cs = ctxt->context->contextSize;
13252             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13253 	    CHECK_ERROR0;
13254 	    ctxt->context->doc = bakd;
13255 	    ctxt->context->node = bak;
13256 	    ctxt->context->proximityPosition = pp;
13257 	    ctxt->context->contextSize = cs;
13258             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13259 	    CHECK_ERROR0;
13260 	    if (op->value)
13261 		equal = xmlXPathEqualValues(ctxt);
13262 	    else
13263 		equal = xmlXPathNotEqualValues(ctxt);
13264 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13265             return (total);
13266         case XPATH_OP_CMP:
13267 	    bakd = ctxt->context->doc;
13268 	    bak = ctxt->context->node;
13269 	    pp = ctxt->context->proximityPosition;
13270 	    cs = ctxt->context->contextSize;
13271             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13272 	    CHECK_ERROR0;
13273 	    ctxt->context->doc = bakd;
13274 	    ctxt->context->node = bak;
13275 	    ctxt->context->proximityPosition = pp;
13276 	    ctxt->context->contextSize = cs;
13277             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13278 	    CHECK_ERROR0;
13279             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13281             return (total);
13282         case XPATH_OP_PLUS:
13283 	    bakd = ctxt->context->doc;
13284 	    bak = ctxt->context->node;
13285 	    pp = ctxt->context->proximityPosition;
13286 	    cs = ctxt->context->contextSize;
13287             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288 	    CHECK_ERROR0;
13289             if (op->ch2 != -1) {
13290 		ctxt->context->doc = bakd;
13291 		ctxt->context->node = bak;
13292 		ctxt->context->proximityPosition = pp;
13293 		ctxt->context->contextSize = cs;
13294                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295 	    }
13296 	    CHECK_ERROR0;
13297             if (op->value == 0)
13298                 xmlXPathSubValues(ctxt);
13299             else if (op->value == 1)
13300                 xmlXPathAddValues(ctxt);
13301             else if (op->value == 2)
13302                 xmlXPathValueFlipSign(ctxt);
13303             else if (op->value == 3) {
13304                 CAST_TO_NUMBER;
13305                 CHECK_TYPE0(XPATH_NUMBER);
13306             }
13307             return (total);
13308         case XPATH_OP_MULT:
13309 	    bakd = ctxt->context->doc;
13310 	    bak = ctxt->context->node;
13311 	    pp = ctxt->context->proximityPosition;
13312 	    cs = ctxt->context->contextSize;
13313             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13314 	    CHECK_ERROR0;
13315 	    ctxt->context->doc = bakd;
13316 	    ctxt->context->node = bak;
13317 	    ctxt->context->proximityPosition = pp;
13318 	    ctxt->context->contextSize = cs;
13319             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13320 	    CHECK_ERROR0;
13321             if (op->value == 0)
13322                 xmlXPathMultValues(ctxt);
13323             else if (op->value == 1)
13324                 xmlXPathDivValues(ctxt);
13325             else if (op->value == 2)
13326                 xmlXPathModValues(ctxt);
13327             return (total);
13328         case XPATH_OP_UNION:
13329 	    bakd = ctxt->context->doc;
13330 	    bak = ctxt->context->node;
13331 	    pp = ctxt->context->proximityPosition;
13332 	    cs = ctxt->context->contextSize;
13333             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334 	    CHECK_ERROR0;
13335 	    ctxt->context->doc = bakd;
13336 	    ctxt->context->node = bak;
13337 	    ctxt->context->proximityPosition = pp;
13338 	    ctxt->context->contextSize = cs;
13339             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13340 	    CHECK_ERROR0;
13341             CHECK_TYPE0(XPATH_NODESET);
13342             arg2 = valuePop(ctxt);
13343 
13344             CHECK_TYPE0(XPATH_NODESET);
13345             arg1 = valuePop(ctxt);
13346 
13347 	    if ((arg1->nodesetval == NULL) ||
13348 		((arg2->nodesetval != NULL) &&
13349 		 (arg2->nodesetval->nodeNr != 0)))
13350 	    {
13351 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352 							arg2->nodesetval);
13353 	    }
13354 
13355             valuePush(ctxt, arg1);
13356 	    xmlXPathReleaseObject(ctxt->context, arg2);
13357             return (total);
13358         case XPATH_OP_ROOT:
13359             xmlXPathRoot(ctxt);
13360             return (total);
13361         case XPATH_OP_NODE:
13362             if (op->ch1 != -1)
13363                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364 	    CHECK_ERROR0;
13365             if (op->ch2 != -1)
13366                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13367 	    CHECK_ERROR0;
13368 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369 		ctxt->context->node));
13370             return (total);
13371         case XPATH_OP_RESET:
13372             if (op->ch1 != -1)
13373                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374 	    CHECK_ERROR0;
13375             if (op->ch2 != -1)
13376                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13377 	    CHECK_ERROR0;
13378             ctxt->context->node = NULL;
13379             return (total);
13380         case XPATH_OP_COLLECT:{
13381                 if (op->ch1 == -1)
13382                     return (total);
13383 
13384                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385 		CHECK_ERROR0;
13386 
13387                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13388                 return (total);
13389             }
13390         case XPATH_OP_VALUE:
13391             valuePush(ctxt,
13392                       xmlXPathCacheObjectCopy(ctxt->context,
13393 			(xmlXPathObjectPtr) op->value4));
13394             return (total);
13395         case XPATH_OP_VARIABLE:{
13396 		xmlXPathObjectPtr val;
13397 
13398                 if (op->ch1 != -1)
13399                     total +=
13400                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401                 if (op->value5 == NULL) {
13402 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403 		    if (val == NULL) {
13404 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405 			return(0);
13406 		    }
13407                     valuePush(ctxt, val);
13408 		} else {
13409                     const xmlChar *URI;
13410 
13411                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412                     if (URI == NULL) {
13413                         xmlGenericError(xmlGenericErrorContext,
13414             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415                                     (char *) op->value4, (char *)op->value5);
13416                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13417                         return (total);
13418                     }
13419 		    val = xmlXPathVariableLookupNS(ctxt->context,
13420                                                        op->value4, URI);
13421 		    if (val == NULL) {
13422 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423 			return(0);
13424 		    }
13425                     valuePush(ctxt, val);
13426                 }
13427                 return (total);
13428             }
13429         case XPATH_OP_FUNCTION:{
13430                 xmlXPathFunction func;
13431                 const xmlChar *oldFunc, *oldFuncURI;
13432 		int i;
13433                 int frame;
13434 
13435                 frame = xmlXPathSetFrame(ctxt);
13436                 if (op->ch1 != -1)
13437                     total +=
13438                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439 		if (ctxt->valueNr < op->value) {
13440 		    xmlGenericError(xmlGenericErrorContext,
13441 			    "xmlXPathCompOpEval: parameter error\n");
13442 		    ctxt->error = XPATH_INVALID_OPERAND;
13443                     xmlXPathPopFrame(ctxt, frame);
13444 		    return (total);
13445 		}
13446 		for (i = 0; i < op->value; i++) {
13447 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448 			xmlGenericError(xmlGenericErrorContext,
13449 				"xmlXPathCompOpEval: parameter error\n");
13450 			ctxt->error = XPATH_INVALID_OPERAND;
13451                         xmlXPathPopFrame(ctxt, frame);
13452 			return (total);
13453 		    }
13454                 }
13455                 if (op->cache != NULL)
13456                     XML_CAST_FPTR(func) = op->cache;
13457                 else {
13458                     const xmlChar *URI = NULL;
13459 
13460                     if (op->value5 == NULL)
13461                         func =
13462                             xmlXPathFunctionLookup(ctxt->context,
13463                                                    op->value4);
13464                     else {
13465                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466                         if (URI == NULL) {
13467                             xmlGenericError(xmlGenericErrorContext,
13468             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469                                     (char *)op->value4, (char *)op->value5);
13470                             xmlXPathPopFrame(ctxt, frame);
13471                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13472                             return (total);
13473                         }
13474                         func = xmlXPathFunctionLookupNS(ctxt->context,
13475                                                         op->value4, URI);
13476                     }
13477                     if (func == NULL) {
13478                         xmlGenericError(xmlGenericErrorContext,
13479                                 "xmlXPathCompOpEval: function %s not found\n",
13480                                         (char *)op->value4);
13481                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13482                     }
13483                     op->cache = XML_CAST_FPTR(func);
13484                     op->cacheURI = (void *) URI;
13485                 }
13486                 oldFunc = ctxt->context->function;
13487                 oldFuncURI = ctxt->context->functionURI;
13488                 ctxt->context->function = op->value4;
13489                 ctxt->context->functionURI = op->cacheURI;
13490                 func(ctxt, op->value);
13491                 ctxt->context->function = oldFunc;
13492                 ctxt->context->functionURI = oldFuncURI;
13493                 xmlXPathPopFrame(ctxt, frame);
13494                 return (total);
13495             }
13496         case XPATH_OP_ARG:
13497 	    bakd = ctxt->context->doc;
13498 	    bak = ctxt->context->node;
13499 	    pp = ctxt->context->proximityPosition;
13500 	    cs = ctxt->context->contextSize;
13501             if (op->ch1 != -1)
13502                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503 	    ctxt->context->contextSize = cs;
13504 	    ctxt->context->proximityPosition = pp;
13505 	    ctxt->context->node = bak;
13506 	    ctxt->context->doc = bakd;
13507 	    CHECK_ERROR0;
13508             if (op->ch2 != -1) {
13509                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510 	        ctxt->context->doc = bakd;
13511 	        ctxt->context->node = bak;
13512 	        CHECK_ERROR0;
13513 	    }
13514             return (total);
13515         case XPATH_OP_PREDICATE:
13516         case XPATH_OP_FILTER:{
13517                 xmlXPathObjectPtr res;
13518                 xmlXPathObjectPtr obj, tmp;
13519                 xmlNodeSetPtr newset = NULL;
13520                 xmlNodeSetPtr oldset;
13521                 xmlNodePtr oldnode;
13522 		xmlDocPtr oldDoc;
13523                 int i;
13524 
13525                 /*
13526                  * Optimization for ()[1] selection i.e. the first elem
13527                  */
13528                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529 #ifdef XP_OPTIMIZED_FILTER_FIRST
13530 		    /*
13531 		    * FILTER TODO: Can we assume that the inner processing
13532 		    *  will result in an ordered list if we have an
13533 		    *  XPATH_OP_FILTER?
13534 		    *  What about an additional field or flag on
13535 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13536 		    *  to assume anything, so it would be more robust and
13537 		    *  easier to optimize.
13538 		    */
13539                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541 #else
13542 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543 #endif
13544                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545                     xmlXPathObjectPtr val;
13546 
13547                     val = comp->steps[op->ch2].value4;
13548                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549                         (val->floatval == 1.0)) {
13550                         xmlNodePtr first = NULL;
13551 
13552                         total +=
13553                             xmlXPathCompOpEvalFirst(ctxt,
13554                                                     &comp->steps[op->ch1],
13555                                                     &first);
13556 			CHECK_ERROR0;
13557                         /*
13558                          * The nodeset should be in document order,
13559                          * Keep only the first value
13560                          */
13561                         if ((ctxt->value != NULL) &&
13562                             (ctxt->value->type == XPATH_NODESET) &&
13563                             (ctxt->value->nodesetval != NULL) &&
13564                             (ctxt->value->nodesetval->nodeNr > 1))
13565                             ctxt->value->nodesetval->nodeNr = 1;
13566                         return (total);
13567                     }
13568                 }
13569                 /*
13570                  * Optimization for ()[last()] selection i.e. the last elem
13571                  */
13572                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575                     int f = comp->steps[op->ch2].ch1;
13576 
13577                     if ((f != -1) &&
13578                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579                         (comp->steps[f].value5 == NULL) &&
13580                         (comp->steps[f].value == 0) &&
13581                         (comp->steps[f].value4 != NULL) &&
13582                         (xmlStrEqual
13583                          (comp->steps[f].value4, BAD_CAST "last"))) {
13584                         xmlNodePtr last = NULL;
13585 
13586                         total +=
13587                             xmlXPathCompOpEvalLast(ctxt,
13588                                                    &comp->steps[op->ch1],
13589                                                    &last);
13590 			CHECK_ERROR0;
13591                         /*
13592                          * The nodeset should be in document order,
13593                          * Keep only the last value
13594                          */
13595                         if ((ctxt->value != NULL) &&
13596                             (ctxt->value->type == XPATH_NODESET) &&
13597                             (ctxt->value->nodesetval != NULL) &&
13598                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13599                             (ctxt->value->nodesetval->nodeNr > 1)) {
13600                             ctxt->value->nodesetval->nodeTab[0] =
13601                                 ctxt->value->nodesetval->nodeTab[ctxt->
13602                                                                  value->
13603                                                                  nodesetval->
13604                                                                  nodeNr -
13605                                                                  1];
13606                             ctxt->value->nodesetval->nodeNr = 1;
13607                         }
13608                         return (total);
13609                     }
13610                 }
13611 		/*
13612 		* Process inner predicates first.
13613 		* Example "index[parent::book][1]":
13614 		* ...
13615 		*   PREDICATE   <-- we are here "[1]"
13616 		*     PREDICATE <-- process "[parent::book]" first
13617 		*       SORT
13618 		*         COLLECT  'parent' 'name' 'node' book
13619 		*           NODE
13620 		*     ELEM Object is a number : 1
13621 		*/
13622                 if (op->ch1 != -1)
13623                     total +=
13624                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13625 		CHECK_ERROR0;
13626                 if (op->ch2 == -1)
13627                     return (total);
13628                 if (ctxt->value == NULL)
13629                     return (total);
13630 
13631                 oldnode = ctxt->context->node;
13632 
13633 #ifdef LIBXML_XPTR_ENABLED
13634                 /*
13635                  * Hum are we filtering the result of an XPointer expression
13636                  */
13637                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13638                     xmlLocationSetPtr newlocset = NULL;
13639                     xmlLocationSetPtr oldlocset;
13640 
13641                     /*
13642                      * Extract the old locset, and then evaluate the result of the
13643                      * expression for all the element in the locset. use it to grow
13644                      * up a new locset.
13645                      */
13646                     CHECK_TYPE0(XPATH_LOCATIONSET);
13647                     obj = valuePop(ctxt);
13648                     oldlocset = obj->user;
13649                     ctxt->context->node = NULL;
13650 
13651                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652                         ctxt->context->contextSize = 0;
13653                         ctxt->context->proximityPosition = 0;
13654                         if (op->ch2 != -1)
13655                             total +=
13656                                 xmlXPathCompOpEval(ctxt,
13657                                                    &comp->steps[op->ch2]);
13658                         res = valuePop(ctxt);
13659                         if (res != NULL) {
13660 			    xmlXPathReleaseObject(ctxt->context, res);
13661 			}
13662                         valuePush(ctxt, obj);
13663                         CHECK_ERROR0;
13664                         return (total);
13665                     }
13666                     newlocset = xmlXPtrLocationSetCreate(NULL);
13667 
13668                     for (i = 0; i < oldlocset->locNr; i++) {
13669                         /*
13670                          * Run the evaluation with a node list made of a
13671                          * single item in the nodelocset.
13672                          */
13673                         ctxt->context->node = oldlocset->locTab[i]->user;
13674                         ctxt->context->contextSize = oldlocset->locNr;
13675                         ctxt->context->proximityPosition = i + 1;
13676 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677 			    ctxt->context->node);
13678                         valuePush(ctxt, tmp);
13679 
13680                         if (op->ch2 != -1)
13681                             total +=
13682                                 xmlXPathCompOpEval(ctxt,
13683                                                    &comp->steps[op->ch2]);
13684 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13685 			    xmlXPathFreeObject(obj);
13686 			    return(0);
13687 			}
13688 
13689                         /*
13690                          * The result of the evaluation need to be tested to
13691                          * decided whether the filter succeeded or not
13692                          */
13693                         res = valuePop(ctxt);
13694                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695                             xmlXPtrLocationSetAdd(newlocset,
13696                                                   xmlXPathObjectCopy
13697                                                   (oldlocset->locTab[i]));
13698                         }
13699 
13700                         /*
13701                          * Cleanup
13702                          */
13703                         if (res != NULL) {
13704 			    xmlXPathReleaseObject(ctxt->context, res);
13705 			}
13706                         if (ctxt->value == tmp) {
13707                             res = valuePop(ctxt);
13708 			    xmlXPathReleaseObject(ctxt->context, res);
13709                         }
13710 
13711                         ctxt->context->node = NULL;
13712                     }
13713 
13714                     /*
13715                      * The result is used as the new evaluation locset.
13716                      */
13717 		    xmlXPathReleaseObject(ctxt->context, obj);
13718                     ctxt->context->node = NULL;
13719                     ctxt->context->contextSize = -1;
13720                     ctxt->context->proximityPosition = -1;
13721                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722                     ctxt->context->node = oldnode;
13723                     return (total);
13724                 }
13725 #endif /* LIBXML_XPTR_ENABLED */
13726 
13727                 /*
13728                  * Extract the old set, and then evaluate the result of the
13729                  * expression for all the element in the set. use it to grow
13730                  * up a new set.
13731                  */
13732                 CHECK_TYPE0(XPATH_NODESET);
13733                 obj = valuePop(ctxt);
13734                 oldset = obj->nodesetval;
13735 
13736                 oldnode = ctxt->context->node;
13737 		oldDoc = ctxt->context->doc;
13738                 ctxt->context->node = NULL;
13739 
13740                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741                     ctxt->context->contextSize = 0;
13742                     ctxt->context->proximityPosition = 0;
13743 /*
13744                     if (op->ch2 != -1)
13745                         total +=
13746                             xmlXPathCompOpEval(ctxt,
13747                                                &comp->steps[op->ch2]);
13748 		    CHECK_ERROR0;
13749                     res = valuePop(ctxt);
13750                     if (res != NULL)
13751                         xmlXPathFreeObject(res);
13752 */
13753                     valuePush(ctxt, obj);
13754                     ctxt->context->node = oldnode;
13755                     CHECK_ERROR0;
13756                 } else {
13757 		    tmp = NULL;
13758                     /*
13759                      * Initialize the new set.
13760 		     * Also set the xpath document in case things like
13761 		     * key() evaluation are attempted on the predicate
13762                      */
13763                     newset = xmlXPathNodeSetCreate(NULL);
13764 		    /*
13765 		    * SPEC XPath 1.0:
13766 		    *  "For each node in the node-set to be filtered, the
13767 		    *  PredicateExpr is evaluated with that node as the
13768 		    *  context node, with the number of nodes in the
13769 		    *  node-set as the context size, and with the proximity
13770 		    *  position of the node in the node-set with respect to
13771 		    *  the axis as the context position;"
13772 		    * @oldset is the node-set" to be filtered.
13773 		    *
13774 		    * SPEC XPath 1.0:
13775 		    *  "only predicates change the context position and
13776 		    *  context size (see [2.4 Predicates])."
13777 		    * Example:
13778 		    *   node-set  context pos
13779 		    *    nA         1
13780 		    *    nB         2
13781 		    *    nC         3
13782 		    *   After applying predicate [position() > 1] :
13783 		    *   node-set  context pos
13784 		    *    nB         1
13785 		    *    nC         2
13786 		    *
13787 		    * removed the first node in the node-set, then
13788 		    * the context position of the
13789 		    */
13790                     for (i = 0; i < oldset->nodeNr; i++) {
13791                         /*
13792                          * Run the evaluation with a node list made of
13793                          * a single item in the nodeset.
13794                          */
13795                         ctxt->context->node = oldset->nodeTab[i];
13796 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797 			    (oldset->nodeTab[i]->doc != NULL))
13798 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13799 			if (tmp == NULL) {
13800 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801 				ctxt->context->node);
13802 			} else {
13803 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804 				ctxt->context->node);
13805 			}
13806                         valuePush(ctxt, tmp);
13807                         ctxt->context->contextSize = oldset->nodeNr;
13808                         ctxt->context->proximityPosition = i + 1;
13809 			/*
13810 			* Evaluate the predicate against the context node.
13811 			* Can/should we optimize position() predicates
13812 			* here (e.g. "[1]")?
13813 			*/
13814                         if (op->ch2 != -1)
13815                             total +=
13816                                 xmlXPathCompOpEval(ctxt,
13817                                                    &comp->steps[op->ch2]);
13818 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13819 			    xmlXPathFreeNodeSet(newset);
13820 			    xmlXPathFreeObject(obj);
13821 			    return(0);
13822 			}
13823 
13824                         /*
13825                          * The result of the evaluation needs to be tested to
13826                          * decide whether the filter succeeded or not
13827                          */
13828 			/*
13829 			* OPTIMIZE TODO: Can we use
13830 			* xmlXPathNodeSetAdd*Unique()* instead?
13831 			*/
13832                         res = valuePop(ctxt);
13833                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835                         }
13836 
13837                         /*
13838                          * Cleanup
13839                          */
13840                         if (res != NULL) {
13841 			    xmlXPathReleaseObject(ctxt->context, res);
13842 			}
13843                         if (ctxt->value == tmp) {
13844                             valuePop(ctxt);
13845 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13846 			    /*
13847 			    * Don't free the temporary nodeset
13848 			    * in order to avoid massive recreation inside this
13849 			    * loop.
13850 			    */
13851                         } else
13852 			    tmp = NULL;
13853                         ctxt->context->node = NULL;
13854                     }
13855 		    if (tmp != NULL)
13856 			xmlXPathReleaseObject(ctxt->context, tmp);
13857                     /*
13858                      * The result is used as the new evaluation set.
13859                      */
13860 		    xmlXPathReleaseObject(ctxt->context, obj);
13861                     ctxt->context->node = NULL;
13862                     ctxt->context->contextSize = -1;
13863                     ctxt->context->proximityPosition = -1;
13864 		    /* may want to move this past the '}' later */
13865 		    ctxt->context->doc = oldDoc;
13866 		    valuePush(ctxt,
13867 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13868                 }
13869                 ctxt->context->node = oldnode;
13870                 return (total);
13871             }
13872         case XPATH_OP_SORT:
13873             if (op->ch1 != -1)
13874                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13875 	    CHECK_ERROR0;
13876             if ((ctxt->value != NULL) &&
13877                 (ctxt->value->type == XPATH_NODESET) &&
13878                 (ctxt->value->nodesetval != NULL) &&
13879 		(ctxt->value->nodesetval->nodeNr > 1))
13880 	    {
13881                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13882 	    }
13883             return (total);
13884 #ifdef LIBXML_XPTR_ENABLED
13885         case XPATH_OP_RANGETO:{
13886                 xmlXPathObjectPtr range;
13887                 xmlXPathObjectPtr res, obj;
13888                 xmlXPathObjectPtr tmp;
13889                 xmlLocationSetPtr newlocset = NULL;
13890 		    xmlLocationSetPtr oldlocset;
13891                 xmlNodeSetPtr oldset;
13892                 int i, j;
13893 
13894                 if (op->ch1 != -1)
13895                     total +=
13896                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897                 if (op->ch2 == -1)
13898                     return (total);
13899 
13900                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13901                     /*
13902                      * Extract the old locset, and then evaluate the result of the
13903                      * expression for all the element in the locset. use it to grow
13904                      * up a new locset.
13905                      */
13906                     CHECK_TYPE0(XPATH_LOCATIONSET);
13907                     obj = valuePop(ctxt);
13908                     oldlocset = obj->user;
13909 
13910                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911 		        ctxt->context->node = NULL;
13912                         ctxt->context->contextSize = 0;
13913                         ctxt->context->proximityPosition = 0;
13914                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915                         res = valuePop(ctxt);
13916                         if (res != NULL) {
13917 			    xmlXPathReleaseObject(ctxt->context, res);
13918 			}
13919                         valuePush(ctxt, obj);
13920                         CHECK_ERROR0;
13921                         return (total);
13922                     }
13923                     newlocset = xmlXPtrLocationSetCreate(NULL);
13924 
13925                     for (i = 0; i < oldlocset->locNr; i++) {
13926                         /*
13927                          * Run the evaluation with a node list made of a
13928                          * single item in the nodelocset.
13929                          */
13930                         ctxt->context->node = oldlocset->locTab[i]->user;
13931                         ctxt->context->contextSize = oldlocset->locNr;
13932                         ctxt->context->proximityPosition = i + 1;
13933 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934 			    ctxt->context->node);
13935                         valuePush(ctxt, tmp);
13936 
13937                         if (op->ch2 != -1)
13938                             total +=
13939                                 xmlXPathCompOpEval(ctxt,
13940                                                    &comp->steps[op->ch2]);
13941 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13942 			    xmlXPathFreeObject(obj);
13943 			    return(0);
13944 			}
13945 
13946                         res = valuePop(ctxt);
13947 			if (res->type == XPATH_LOCATIONSET) {
13948 			    xmlLocationSetPtr rloc =
13949 			        (xmlLocationSetPtr)res->user;
13950 			    for (j=0; j<rloc->locNr; j++) {
13951 			        range = xmlXPtrNewRange(
13952 				  oldlocset->locTab[i]->user,
13953 				  oldlocset->locTab[i]->index,
13954 				  rloc->locTab[j]->user2,
13955 				  rloc->locTab[j]->index2);
13956 				if (range != NULL) {
13957 				    xmlXPtrLocationSetAdd(newlocset, range);
13958 				}
13959 			    }
13960 			} else {
13961 			    range = xmlXPtrNewRangeNodeObject(
13962 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13963                             if (range != NULL) {
13964                                 xmlXPtrLocationSetAdd(newlocset,range);
13965 			    }
13966                         }
13967 
13968                         /*
13969                          * Cleanup
13970                          */
13971                         if (res != NULL) {
13972 			    xmlXPathReleaseObject(ctxt->context, res);
13973 			}
13974                         if (ctxt->value == tmp) {
13975                             res = valuePop(ctxt);
13976 			    xmlXPathReleaseObject(ctxt->context, res);
13977                         }
13978 
13979                         ctxt->context->node = NULL;
13980                     }
13981 		} else {	/* Not a location set */
13982                     CHECK_TYPE0(XPATH_NODESET);
13983                     obj = valuePop(ctxt);
13984                     oldset = obj->nodesetval;
13985                     ctxt->context->node = NULL;
13986 
13987                     newlocset = xmlXPtrLocationSetCreate(NULL);
13988 
13989                     if (oldset != NULL) {
13990                         for (i = 0; i < oldset->nodeNr; i++) {
13991                             /*
13992                              * Run the evaluation with a node list made of a single item
13993                              * in the nodeset.
13994                              */
13995                             ctxt->context->node = oldset->nodeTab[i];
13996 			    /*
13997 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13998 			    */
13999 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000 				ctxt->context->node);
14001                             valuePush(ctxt, tmp);
14002 
14003                             if (op->ch2 != -1)
14004                                 total +=
14005                                     xmlXPathCompOpEval(ctxt,
14006                                                    &comp->steps[op->ch2]);
14007 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14008 				xmlXPathFreeObject(obj);
14009 				return(0);
14010 			    }
14011 
14012                             res = valuePop(ctxt);
14013                             range =
14014                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015                                                       res);
14016                             if (range != NULL) {
14017                                 xmlXPtrLocationSetAdd(newlocset, range);
14018                             }
14019 
14020                             /*
14021                              * Cleanup
14022                              */
14023                             if (res != NULL) {
14024 				xmlXPathReleaseObject(ctxt->context, res);
14025 			    }
14026                             if (ctxt->value == tmp) {
14027                                 res = valuePop(ctxt);
14028 				xmlXPathReleaseObject(ctxt->context, res);
14029                             }
14030 
14031                             ctxt->context->node = NULL;
14032                         }
14033                     }
14034                 }
14035 
14036                 /*
14037                  * The result is used as the new evaluation set.
14038                  */
14039 		xmlXPathReleaseObject(ctxt->context, obj);
14040                 ctxt->context->node = NULL;
14041                 ctxt->context->contextSize = -1;
14042                 ctxt->context->proximityPosition = -1;
14043                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14044                 return (total);
14045             }
14046 #endif /* LIBXML_XPTR_ENABLED */
14047     }
14048     xmlGenericError(xmlGenericErrorContext,
14049                     "XPath: unknown precompiled operation %d\n", op->op);
14050     ctxt->error = XPATH_INVALID_OPERAND;
14051     return (total);
14052 }
14053 
14054 /**
14055  * xmlXPathCompOpEvalToBoolean:
14056  * @ctxt:  the XPath parser context
14057  *
14058  * Evaluates if the expression evaluates to true.
14059  *
14060  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061  */
14062 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)14063 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064 			    xmlXPathStepOpPtr op,
14065 			    int isPredicate)
14066 {
14067     xmlXPathObjectPtr resObj = NULL;
14068 
14069 start:
14070     /* comp = ctxt->comp; */
14071     switch (op->op) {
14072         case XPATH_OP_END:
14073             return (0);
14074 	case XPATH_OP_VALUE:
14075 	    resObj = (xmlXPathObjectPtr) op->value4;
14076 	    if (isPredicate)
14077 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078 	    return(xmlXPathCastToBoolean(resObj));
14079 	case XPATH_OP_SORT:
14080 	    /*
14081 	    * We don't need sorting for boolean results. Skip this one.
14082 	    */
14083             if (op->ch1 != -1) {
14084 		op = &ctxt->comp->steps[op->ch1];
14085 		goto start;
14086 	    }
14087 	    return(0);
14088 	case XPATH_OP_COLLECT:
14089 	    if (op->ch1 == -1)
14090 		return(0);
14091 
14092             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14094 		return(-1);
14095 
14096             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14098 		return(-1);
14099 
14100 	    resObj = valuePop(ctxt);
14101 	    if (resObj == NULL)
14102 		return(-1);
14103 	    break;
14104 	default:
14105 	    /*
14106 	    * Fallback to call xmlXPathCompOpEval().
14107 	    */
14108 	    xmlXPathCompOpEval(ctxt, op);
14109 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14110 		return(-1);
14111 
14112 	    resObj = valuePop(ctxt);
14113 	    if (resObj == NULL)
14114 		return(-1);
14115 	    break;
14116     }
14117 
14118     if (resObj) {
14119 	int res;
14120 
14121 	if (resObj->type == XPATH_BOOLEAN) {
14122 	    res = resObj->boolval;
14123 	} else if (isPredicate) {
14124 	    /*
14125 	    * For predicates a result of type "number" is handled
14126 	    * differently:
14127 	    * SPEC XPath 1.0:
14128 	    * "If the result is a number, the result will be converted
14129 	    *  to true if the number is equal to the context position
14130 	    *  and will be converted to false otherwise;"
14131 	    */
14132 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14133 	} else {
14134 	    res = xmlXPathCastToBoolean(resObj);
14135 	}
14136 	xmlXPathReleaseObject(ctxt->context, resObj);
14137 	return(res);
14138     }
14139 
14140     return(0);
14141 }
14142 
14143 #ifdef XPATH_STREAMING
14144 /**
14145  * xmlXPathRunStreamEval:
14146  * @ctxt:  the XPath parser context with the compiled expression
14147  *
14148  * Evaluate the Precompiled Streamable XPath expression in the given context.
14149  */
14150 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14151 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152 		      xmlXPathObjectPtr *resultSeq, int toBool)
14153 {
14154     int max_depth, min_depth;
14155     int from_root;
14156     int ret, depth;
14157     int eval_all_nodes;
14158     xmlNodePtr cur = NULL, limit = NULL;
14159     xmlStreamCtxtPtr patstream = NULL;
14160 
14161     int nb_nodes = 0;
14162 
14163     if ((ctxt == NULL) || (comp == NULL))
14164         return(-1);
14165     max_depth = xmlPatternMaxDepth(comp);
14166     if (max_depth == -1)
14167         return(-1);
14168     if (max_depth == -2)
14169         max_depth = 10000;
14170     min_depth = xmlPatternMinDepth(comp);
14171     if (min_depth == -1)
14172         return(-1);
14173     from_root = xmlPatternFromRoot(comp);
14174     if (from_root < 0)
14175         return(-1);
14176 #if 0
14177     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178 #endif
14179 
14180     if (! toBool) {
14181 	if (resultSeq == NULL)
14182 	    return(-1);
14183 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184 	if (*resultSeq == NULL)
14185 	    return(-1);
14186     }
14187 
14188     /*
14189      * handle the special cases of "/" amd "." being matched
14190      */
14191     if (min_depth == 0) {
14192 	if (from_root) {
14193 	    /* Select "/" */
14194 	    if (toBool)
14195 		return(1);
14196 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197 		(xmlNodePtr) ctxt->doc);
14198 	} else {
14199 	    /* Select "self::node()" */
14200 	    if (toBool)
14201 		return(1);
14202 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14203 	}
14204     }
14205     if (max_depth == 0) {
14206 	return(0);
14207     }
14208 
14209     if (from_root) {
14210         cur = (xmlNodePtr)ctxt->doc;
14211     } else if (ctxt->node != NULL) {
14212         switch (ctxt->node->type) {
14213             case XML_ELEMENT_NODE:
14214             case XML_DOCUMENT_NODE:
14215             case XML_DOCUMENT_FRAG_NODE:
14216             case XML_HTML_DOCUMENT_NODE:
14217 #ifdef LIBXML_DOCB_ENABLED
14218             case XML_DOCB_DOCUMENT_NODE:
14219 #endif
14220 	        cur = ctxt->node;
14221 		break;
14222             case XML_ATTRIBUTE_NODE:
14223             case XML_TEXT_NODE:
14224             case XML_CDATA_SECTION_NODE:
14225             case XML_ENTITY_REF_NODE:
14226             case XML_ENTITY_NODE:
14227             case XML_PI_NODE:
14228             case XML_COMMENT_NODE:
14229             case XML_NOTATION_NODE:
14230             case XML_DTD_NODE:
14231             case XML_DOCUMENT_TYPE_NODE:
14232             case XML_ELEMENT_DECL:
14233             case XML_ATTRIBUTE_DECL:
14234             case XML_ENTITY_DECL:
14235             case XML_NAMESPACE_DECL:
14236             case XML_XINCLUDE_START:
14237             case XML_XINCLUDE_END:
14238 		break;
14239 	}
14240 	limit = cur;
14241     }
14242     if (cur == NULL) {
14243         return(0);
14244     }
14245 
14246     patstream = xmlPatternGetStreamCtxt(comp);
14247     if (patstream == NULL) {
14248 	/*
14249 	* QUESTION TODO: Is this an error?
14250 	*/
14251 	return(0);
14252     }
14253 
14254     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14255 
14256     if (from_root) {
14257 	ret = xmlStreamPush(patstream, NULL, NULL);
14258 	if (ret < 0) {
14259 	} else if (ret == 1) {
14260 	    if (toBool)
14261 		goto return_1;
14262 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14263 	}
14264     }
14265     depth = 0;
14266     goto scan_children;
14267 next_node:
14268     do {
14269         nb_nodes++;
14270 
14271 	switch (cur->type) {
14272 	    case XML_ELEMENT_NODE:
14273 	    case XML_TEXT_NODE:
14274 	    case XML_CDATA_SECTION_NODE:
14275 	    case XML_COMMENT_NODE:
14276 	    case XML_PI_NODE:
14277 		if (cur->type == XML_ELEMENT_NODE) {
14278 		    ret = xmlStreamPush(patstream, cur->name,
14279 				(cur->ns ? cur->ns->href : NULL));
14280 		} else if (eval_all_nodes)
14281 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282 		else
14283 		    break;
14284 
14285 		if (ret < 0) {
14286 		    /* NOP. */
14287 		} else if (ret == 1) {
14288 		    if (toBool)
14289 			goto return_1;
14290 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14291 		}
14292 		if ((cur->children == NULL) || (depth >= max_depth)) {
14293 		    ret = xmlStreamPop(patstream);
14294 		    while (cur->next != NULL) {
14295 			cur = cur->next;
14296 			if ((cur->type != XML_ENTITY_DECL) &&
14297 			    (cur->type != XML_DTD_NODE))
14298 			    goto next_node;
14299 		    }
14300 		}
14301 	    default:
14302 		break;
14303 	}
14304 
14305 scan_children:
14306 	if ((cur->children != NULL) && (depth < max_depth)) {
14307 	    /*
14308 	     * Do not descend on entities declarations
14309 	     */
14310 	    if (cur->children->type != XML_ENTITY_DECL) {
14311 		cur = cur->children;
14312 		depth++;
14313 		/*
14314 		 * Skip DTDs
14315 		 */
14316 		if (cur->type != XML_DTD_NODE)
14317 		    continue;
14318 	    }
14319 	}
14320 
14321 	if (cur == limit)
14322 	    break;
14323 
14324 	while (cur->next != NULL) {
14325 	    cur = cur->next;
14326 	    if ((cur->type != XML_ENTITY_DECL) &&
14327 		(cur->type != XML_DTD_NODE))
14328 		goto next_node;
14329 	}
14330 
14331 	do {
14332 	    cur = cur->parent;
14333 	    depth--;
14334 	    if ((cur == NULL) || (cur == limit))
14335 	        goto done;
14336 	    if (cur->type == XML_ELEMENT_NODE) {
14337 		ret = xmlStreamPop(patstream);
14338 	    } else if ((eval_all_nodes) &&
14339 		((cur->type == XML_TEXT_NODE) ||
14340 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14341 		 (cur->type == XML_COMMENT_NODE) ||
14342 		 (cur->type == XML_PI_NODE)))
14343 	    {
14344 		ret = xmlStreamPop(patstream);
14345 	    }
14346 	    if (cur->next != NULL) {
14347 		cur = cur->next;
14348 		break;
14349 	    }
14350 	} while (cur != NULL);
14351 
14352     } while ((cur != NULL) && (depth >= 0));
14353 
14354 done:
14355 
14356 #if 0
14357     printf("stream eval: checked %d nodes selected %d\n",
14358            nb_nodes, retObj->nodesetval->nodeNr);
14359 #endif
14360 
14361     if (patstream)
14362 	xmlFreeStreamCtxt(patstream);
14363     return(0);
14364 
14365 return_1:
14366     if (patstream)
14367 	xmlFreeStreamCtxt(patstream);
14368     return(1);
14369 }
14370 #endif /* XPATH_STREAMING */
14371 
14372 /**
14373  * xmlXPathRunEval:
14374  * @ctxt:  the XPath parser context with the compiled expression
14375  * @toBool:  evaluate to a boolean result
14376  *
14377  * Evaluate the Precompiled XPath expression in the given context.
14378  */
14379 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381 {
14382     xmlXPathCompExprPtr comp;
14383 
14384     if ((ctxt == NULL) || (ctxt->comp == NULL))
14385 	return(-1);
14386 
14387     if (ctxt->valueTab == NULL) {
14388 	/* Allocate the value stack */
14389 	ctxt->valueTab = (xmlXPathObjectPtr *)
14390 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391 	if (ctxt->valueTab == NULL) {
14392 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14393 	    xmlFree(ctxt);
14394 	}
14395 	ctxt->valueNr = 0;
14396 	ctxt->valueMax = 10;
14397 	ctxt->value = NULL;
14398         ctxt->valueFrame = 0;
14399     }
14400 #ifdef XPATH_STREAMING
14401     if (ctxt->comp->stream) {
14402 	int res;
14403 
14404 	if (toBool) {
14405 	    /*
14406 	    * Evaluation to boolean result.
14407 	    */
14408 	    res = xmlXPathRunStreamEval(ctxt->context,
14409 		ctxt->comp->stream, NULL, 1);
14410 	    if (res != -1)
14411 		return(res);
14412 	} else {
14413 	    xmlXPathObjectPtr resObj = NULL;
14414 
14415 	    /*
14416 	    * Evaluation to a sequence.
14417 	    */
14418 	    res = xmlXPathRunStreamEval(ctxt->context,
14419 		ctxt->comp->stream, &resObj, 0);
14420 
14421 	    if ((res != -1) && (resObj != NULL)) {
14422 		valuePush(ctxt, resObj);
14423 		return(0);
14424 	    }
14425 	    if (resObj != NULL)
14426 		xmlXPathReleaseObject(ctxt->context, resObj);
14427 	}
14428 	/*
14429 	* QUESTION TODO: This falls back to normal XPath evaluation
14430 	* if res == -1. Is this intended?
14431 	*/
14432     }
14433 #endif
14434     comp = ctxt->comp;
14435     if (comp->last < 0) {
14436 	xmlGenericError(xmlGenericErrorContext,
14437 	    "xmlXPathRunEval: last is less than zero\n");
14438 	return(-1);
14439     }
14440     if (toBool)
14441 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14442 	    &comp->steps[comp->last], 0));
14443     else
14444 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445 
14446     return(0);
14447 }
14448 
14449 /************************************************************************
14450  *									*
14451  *			Public interfaces				*
14452  *									*
14453  ************************************************************************/
14454 
14455 /**
14456  * xmlXPathEvalPredicate:
14457  * @ctxt:  the XPath context
14458  * @res:  the Predicate Expression evaluation result
14459  *
14460  * Evaluate a predicate result for the current node.
14461  * A PredicateExpr is evaluated by evaluating the Expr and converting
14462  * the result to a boolean. If the result is a number, the result will
14463  * be converted to true if the number is equal to the position of the
14464  * context node in the context node list (as returned by the position
14465  * function) and will be converted to false otherwise; if the result
14466  * is not a number, then the result will be converted as if by a call
14467  * to the boolean function.
14468  *
14469  * Returns 1 if predicate is true, 0 otherwise
14470  */
14471 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14472 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473     if ((ctxt == NULL) || (res == NULL)) return(0);
14474     switch (res->type) {
14475         case XPATH_BOOLEAN:
14476 	    return(res->boolval);
14477         case XPATH_NUMBER:
14478 	    return(res->floatval == ctxt->proximityPosition);
14479         case XPATH_NODESET:
14480         case XPATH_XSLT_TREE:
14481 	    if (res->nodesetval == NULL)
14482 		return(0);
14483 	    return(res->nodesetval->nodeNr != 0);
14484         case XPATH_STRING:
14485 	    return((res->stringval != NULL) &&
14486 	           (xmlStrlen(res->stringval) != 0));
14487         default:
14488 	    STRANGE
14489     }
14490     return(0);
14491 }
14492 
14493 /**
14494  * xmlXPathEvaluatePredicateResult:
14495  * @ctxt:  the XPath Parser context
14496  * @res:  the Predicate Expression evaluation result
14497  *
14498  * Evaluate a predicate result for the current node.
14499  * A PredicateExpr is evaluated by evaluating the Expr and converting
14500  * the result to a boolean. If the result is a number, the result will
14501  * be converted to true if the number is equal to the position of the
14502  * context node in the context node list (as returned by the position
14503  * function) and will be converted to false otherwise; if the result
14504  * is not a number, then the result will be converted as if by a call
14505  * to the boolean function.
14506  *
14507  * Returns 1 if predicate is true, 0 otherwise
14508  */
14509 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14510 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511                                 xmlXPathObjectPtr res) {
14512     if ((ctxt == NULL) || (res == NULL)) return(0);
14513     switch (res->type) {
14514         case XPATH_BOOLEAN:
14515 	    return(res->boolval);
14516         case XPATH_NUMBER:
14517 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518 	    return((res->floatval == ctxt->context->proximityPosition) &&
14519 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14520 #else
14521 	    return(res->floatval == ctxt->context->proximityPosition);
14522 #endif
14523         case XPATH_NODESET:
14524         case XPATH_XSLT_TREE:
14525 	    if (res->nodesetval == NULL)
14526 		return(0);
14527 	    return(res->nodesetval->nodeNr != 0);
14528         case XPATH_STRING:
14529 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14530 #ifdef LIBXML_XPTR_ENABLED
14531 	case XPATH_LOCATIONSET:{
14532 	    xmlLocationSetPtr ptr = res->user;
14533 	    if (ptr == NULL)
14534 	        return(0);
14535 	    return (ptr->locNr != 0);
14536 	    }
14537 #endif
14538         default:
14539 	    STRANGE
14540     }
14541     return(0);
14542 }
14543 
14544 #ifdef XPATH_STREAMING
14545 /**
14546  * xmlXPathTryStreamCompile:
14547  * @ctxt: an XPath context
14548  * @str:  the XPath expression
14549  *
14550  * Try to compile the XPath expression as a streamable subset.
14551  *
14552  * Returns the compiled expression or NULL if failed to compile.
14553  */
14554 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14555 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556     /*
14557      * Optimization: use streaming patterns when the XPath expression can
14558      * be compiled to a stream lookup
14559      */
14560     xmlPatternPtr stream;
14561     xmlXPathCompExprPtr comp;
14562     xmlDictPtr dict = NULL;
14563     const xmlChar **namespaces = NULL;
14564     xmlNsPtr ns;
14565     int i, j;
14566 
14567     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568         (!xmlStrchr(str, '@'))) {
14569 	const xmlChar *tmp;
14570 
14571 	/*
14572 	 * We don't try to handle expressions using the verbose axis
14573 	 * specifiers ("::"), just the simplied form at this point.
14574 	 * Additionally, if there is no list of namespaces available and
14575 	 *  there's a ":" in the expression, indicating a prefixed QName,
14576 	 *  then we won't try to compile either. xmlPatterncompile() needs
14577 	 *  to have a list of namespaces at compilation time in order to
14578 	 *  compile prefixed name tests.
14579 	 */
14580 	tmp = xmlStrchr(str, ':');
14581 	if ((tmp != NULL) &&
14582 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14583 	    return(NULL);
14584 
14585 	if (ctxt != NULL) {
14586 	    dict = ctxt->dict;
14587 	    if (ctxt->nsNr > 0) {
14588 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589 		if (namespaces == NULL) {
14590 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591 		    return(NULL);
14592 		}
14593 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594 		    ns = ctxt->namespaces[j];
14595 		    namespaces[i++] = ns->href;
14596 		    namespaces[i++] = ns->prefix;
14597 		}
14598 		namespaces[i++] = NULL;
14599 		namespaces[i] = NULL;
14600 	    }
14601 	}
14602 
14603 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604 			&namespaces[0]);
14605 	if (namespaces != NULL) {
14606 	    xmlFree((xmlChar **)namespaces);
14607 	}
14608 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609 	    comp = xmlXPathNewCompExpr();
14610 	    if (comp == NULL) {
14611 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612 		return(NULL);
14613 	    }
14614 	    comp->stream = stream;
14615 	    comp->dict = dict;
14616 	    if (comp->dict)
14617 		xmlDictReference(comp->dict);
14618 	    return(comp);
14619 	}
14620 	xmlFreePattern(stream);
14621     }
14622     return(NULL);
14623 }
14624 #endif /* XPATH_STREAMING */
14625 
14626 static int
xmlXPathCanRewriteDosExpression(xmlChar * expr)14627 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628 {
14629     if (expr == NULL)
14630 	return(0);
14631     do {
14632         if ((*expr == '/') && (*(++expr) == '/'))
14633 	    return(1);
14634     } while (*expr++);
14635     return(0);
14636 }
14637 static void
xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14638 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639 {
14640     /*
14641     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642     * internal representation.
14643     */
14644     if (op->ch1 != -1) {
14645 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649 	{
14650 	    /*
14651 	    * This is a "child::foo"
14652 	    */
14653 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14654 
14655 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656 		(prevop->ch1 != -1) &&
14657 		((xmlXPathAxisVal) prevop->value ==
14658 		    AXIS_DESCENDANT_OR_SELF) &&
14659 		(prevop->ch2 == -1) &&
14660 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14663 	    {
14664 		/*
14665 		* This is a "/descendant-or-self::node()" without predicates.
14666 		* Eliminate it.
14667 		*/
14668 		op->ch1 = prevop->ch1;
14669 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14670 	    }
14671 	}
14672 	if (op->ch1 != -1)
14673 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674     }
14675     if (op->ch2 != -1)
14676 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677 }
14678 
14679 /**
14680  * xmlXPathCtxtCompile:
14681  * @ctxt: an XPath context
14682  * @str:  the XPath expression
14683  *
14684  * Compile an XPath expression
14685  *
14686  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687  *         the caller has to free the object.
14688  */
14689 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14690 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691     xmlXPathParserContextPtr pctxt;
14692     xmlXPathCompExprPtr comp;
14693 
14694 #ifdef XPATH_STREAMING
14695     comp = xmlXPathTryStreamCompile(ctxt, str);
14696     if (comp != NULL)
14697         return(comp);
14698 #endif
14699 
14700     xmlXPathInit();
14701 
14702     pctxt = xmlXPathNewParserContext(str, ctxt);
14703     if (pctxt == NULL)
14704         return NULL;
14705     xmlXPathCompileExpr(pctxt, 1);
14706 
14707     if( pctxt->error != XPATH_EXPRESSION_OK )
14708     {
14709         xmlXPathFreeParserContext(pctxt);
14710         return(NULL);
14711     }
14712 
14713     if (*pctxt->cur != 0) {
14714 	/*
14715 	 * aleksey: in some cases this line prints *second* error message
14716 	 * (see bug #78858) and probably this should be fixed.
14717 	 * However, we are not sure that all error messages are printed
14718 	 * out in other places. It's not critical so we leave it as-is for now
14719 	 */
14720 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721 	comp = NULL;
14722     } else {
14723 	comp = pctxt->comp;
14724 	pctxt->comp = NULL;
14725     }
14726     xmlXPathFreeParserContext(pctxt);
14727 
14728     if (comp != NULL) {
14729 	comp->expr = xmlStrdup(str);
14730 #ifdef DEBUG_EVAL_COUNTS
14731 	comp->string = xmlStrdup(str);
14732 	comp->nb = 0;
14733 #endif
14734 	if ((comp->expr != NULL) &&
14735 	    (comp->nbStep > 2) &&
14736 	    (comp->last >= 0) &&
14737 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738 	{
14739 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14740 	}
14741     }
14742     return(comp);
14743 }
14744 
14745 /**
14746  * xmlXPathCompile:
14747  * @str:  the XPath expression
14748  *
14749  * Compile an XPath expression
14750  *
14751  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752  *         the caller has to free the object.
14753  */
14754 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14755 xmlXPathCompile(const xmlChar *str) {
14756     return(xmlXPathCtxtCompile(NULL, str));
14757 }
14758 
14759 /**
14760  * xmlXPathCompiledEvalInternal:
14761  * @comp:  the compiled XPath expression
14762  * @ctxt:  the XPath context
14763  * @resObj: the resulting XPath object or NULL
14764  * @toBool: 1 if only a boolean result is requested
14765  *
14766  * Evaluate the Precompiled XPath expression in the given context.
14767  * The caller has to free @resObj.
14768  *
14769  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770  *         the caller has to free the object.
14771  */
14772 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObj,int toBool)14773 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774 			     xmlXPathContextPtr ctxt,
14775 			     xmlXPathObjectPtr *resObj,
14776 			     int toBool)
14777 {
14778     xmlXPathParserContextPtr pctxt;
14779 #ifndef LIBXML_THREAD_ENABLED
14780     static int reentance = 0;
14781 #endif
14782     int res;
14783 
14784     CHECK_CTXT_NEG(ctxt)
14785 
14786     if (comp == NULL)
14787 	return(-1);
14788     xmlXPathInit();
14789 
14790 #ifndef LIBXML_THREAD_ENABLED
14791     reentance++;
14792     if (reentance > 1)
14793 	xmlXPathDisableOptimizer = 1;
14794 #endif
14795 
14796 #ifdef DEBUG_EVAL_COUNTS
14797     comp->nb++;
14798     if ((comp->string != NULL) && (comp->nb > 100)) {
14799 	fprintf(stderr, "100 x %s\n", comp->string);
14800 	comp->nb = 0;
14801     }
14802 #endif
14803     pctxt = xmlXPathCompParserContext(comp, ctxt);
14804     res = xmlXPathRunEval(pctxt, toBool);
14805 
14806     if (resObj) {
14807 	if (pctxt->value == NULL) {
14808 	    xmlGenericError(xmlGenericErrorContext,
14809 		"xmlXPathCompiledEval: evaluation failed\n");
14810 	    *resObj = NULL;
14811 	} else {
14812 	    *resObj = valuePop(pctxt);
14813 	}
14814     }
14815 
14816     /*
14817     * Pop all remaining objects from the stack.
14818     */
14819     if (pctxt->valueNr > 0) {
14820 	xmlXPathObjectPtr tmp;
14821 	int stack = 0;
14822 
14823 	do {
14824 	    tmp = valuePop(pctxt);
14825 	    if (tmp != NULL) {
14826 		stack++;
14827 		xmlXPathReleaseObject(ctxt, tmp);
14828 	    }
14829 	} while (tmp != NULL);
14830 	if ((stack != 0) &&
14831 	    ((toBool) || ((resObj) && (*resObj))))
14832 	{
14833 	    xmlGenericError(xmlGenericErrorContext,
14834 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14835 		stack);
14836 	}
14837     }
14838 
14839     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840 	xmlXPathFreeObject(*resObj);
14841 	*resObj = NULL;
14842     }
14843     pctxt->comp = NULL;
14844     xmlXPathFreeParserContext(pctxt);
14845 #ifndef LIBXML_THREAD_ENABLED
14846     reentance--;
14847 #endif
14848 
14849     return(res);
14850 }
14851 
14852 /**
14853  * xmlXPathCompiledEval:
14854  * @comp:  the compiled XPath expression
14855  * @ctx:  the XPath context
14856  *
14857  * Evaluate the Precompiled XPath expression in the given context.
14858  *
14859  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860  *         the caller has to free the object.
14861  */
14862 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14863 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864 {
14865     xmlXPathObjectPtr res = NULL;
14866 
14867     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868     return(res);
14869 }
14870 
14871 /**
14872  * xmlXPathCompiledEvalToBoolean:
14873  * @comp:  the compiled XPath expression
14874  * @ctxt:  the XPath context
14875  *
14876  * Applies the XPath boolean() function on the result of the given
14877  * compiled expression.
14878  *
14879  * Returns 1 if the expression evaluated to true, 0 if to false and
14880  *         -1 in API and internal errors.
14881  */
14882 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14883 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884 			      xmlXPathContextPtr ctxt)
14885 {
14886     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887 }
14888 
14889 /**
14890  * xmlXPathEvalExpr:
14891  * @ctxt:  the XPath Parser context
14892  *
14893  * Parse and evaluate an XPath expression in the given context,
14894  * then push the result on the context stack
14895  */
14896 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14897 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898 #ifdef XPATH_STREAMING
14899     xmlXPathCompExprPtr comp;
14900 #endif
14901 
14902     if (ctxt == NULL) return;
14903 
14904 #ifdef XPATH_STREAMING
14905     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906     if (comp != NULL) {
14907         if (ctxt->comp != NULL)
14908 	    xmlXPathFreeCompExpr(ctxt->comp);
14909         ctxt->comp = comp;
14910 	if (ctxt->cur != NULL)
14911 	    while (*ctxt->cur != 0) ctxt->cur++;
14912     } else
14913 #endif
14914     {
14915 	xmlXPathCompileExpr(ctxt, 1);
14916 	/*
14917 	* In this scenario the expression string will sit in ctxt->base.
14918 	*/
14919 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920 	    (ctxt->comp != NULL) &&
14921 	    (ctxt->base != NULL) &&
14922 	    (ctxt->comp->nbStep > 2) &&
14923 	    (ctxt->comp->last >= 0) &&
14924 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14925 	{
14926 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14927 		&ctxt->comp->steps[ctxt->comp->last]);
14928 	}
14929     }
14930     CHECK_ERROR;
14931     xmlXPathRunEval(ctxt, 0);
14932 }
14933 
14934 /**
14935  * xmlXPathEval:
14936  * @str:  the XPath expression
14937  * @ctx:  the XPath context
14938  *
14939  * Evaluate the XPath Location Path in the given context.
14940  *
14941  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942  *         the caller has to free the object.
14943  */
14944 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14945 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946     xmlXPathParserContextPtr ctxt;
14947     xmlXPathObjectPtr res, tmp, init = NULL;
14948     int stack = 0;
14949 
14950     CHECK_CTXT(ctx)
14951 
14952     xmlXPathInit();
14953 
14954     ctxt = xmlXPathNewParserContext(str, ctx);
14955     if (ctxt == NULL)
14956         return NULL;
14957     xmlXPathEvalExpr(ctxt);
14958 
14959     if (ctxt->value == NULL) {
14960 	xmlGenericError(xmlGenericErrorContext,
14961 		"xmlXPathEval: evaluation failed\n");
14962 	res = NULL;
14963     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964 #ifdef XPATH_STREAMING
14965             && (ctxt->comp->stream == NULL)
14966 #endif
14967 	      ) {
14968 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969 	res = NULL;
14970     } else {
14971 	res = valuePop(ctxt);
14972     }
14973 
14974     do {
14975         tmp = valuePop(ctxt);
14976 	if (tmp != NULL) {
14977 	    if (tmp != init)
14978 		stack++;
14979 	    xmlXPathReleaseObject(ctx, tmp);
14980         }
14981     } while (tmp != NULL);
14982     if ((stack != 0) && (res != NULL)) {
14983 	xmlGenericError(xmlGenericErrorContext,
14984 		"xmlXPathEval: %d object left on the stack\n",
14985 	        stack);
14986     }
14987     if (ctxt->error != XPATH_EXPRESSION_OK) {
14988 	xmlXPathFreeObject(res);
14989 	res = NULL;
14990     }
14991 
14992     xmlXPathFreeParserContext(ctxt);
14993     return(res);
14994 }
14995 
14996 /**
14997  * xmlXPathEvalExpression:
14998  * @str:  the XPath expression
14999  * @ctxt:  the XPath context
15000  *
15001  * Evaluate the XPath expression in the given context.
15002  *
15003  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004  *         the caller has to free the object.
15005  */
15006 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)15007 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008     xmlXPathParserContextPtr pctxt;
15009     xmlXPathObjectPtr res, tmp;
15010     int stack = 0;
15011 
15012     CHECK_CTXT(ctxt)
15013 
15014     xmlXPathInit();
15015 
15016     pctxt = xmlXPathNewParserContext(str, ctxt);
15017     if (pctxt == NULL)
15018         return NULL;
15019     xmlXPathEvalExpr(pctxt);
15020 
15021     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023 	res = NULL;
15024     } else {
15025 	res = valuePop(pctxt);
15026     }
15027     do {
15028         tmp = valuePop(pctxt);
15029 	if (tmp != NULL) {
15030 	    xmlXPathReleaseObject(ctxt, tmp);
15031 	    stack++;
15032 	}
15033     } while (tmp != NULL);
15034     if ((stack != 0) && (res != NULL)) {
15035 	xmlGenericError(xmlGenericErrorContext,
15036 		"xmlXPathEvalExpression: %d object left on the stack\n",
15037 	        stack);
15038     }
15039     xmlXPathFreeParserContext(pctxt);
15040     return(res);
15041 }
15042 
15043 /************************************************************************
15044  *									*
15045  *	Extra functions not pertaining to the XPath spec		*
15046  *									*
15047  ************************************************************************/
15048 /**
15049  * xmlXPathEscapeUriFunction:
15050  * @ctxt:  the XPath Parser context
15051  * @nargs:  the number of arguments
15052  *
15053  * Implement the escape-uri() XPath function
15054  *    string escape-uri(string $str, bool $escape-reserved)
15055  *
15056  * This function applies the URI escaping rules defined in section 2 of [RFC
15057  * 2396] to the string supplied as $uri-part, which typically represents all
15058  * or part of a URI. The effect of the function is to replace any special
15059  * character in the string by an escape sequence of the form %xx%yy...,
15060  * where xxyy... is the hexadecimal representation of the octets used to
15061  * represent the character in UTF-8.
15062  *
15063  * The set of characters that are escaped depends on the setting of the
15064  * boolean argument $escape-reserved.
15065  *
15066  * If $escape-reserved is true, all characters are escaped other than lower
15067  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071  * A-F).
15072  *
15073  * If $escape-reserved is false, the behavior differs in that characters
15074  * referred to in [RFC 2396] as reserved characters are not escaped. These
15075  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15076  *
15077  * [RFC 2396] does not define whether escaped URIs should use lower case or
15078  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079  * compared using string comparison functions, this function must always use
15080  * the upper-case letters A-F.
15081  *
15082  * Generally, $escape-reserved should be set to true when escaping a string
15083  * that is to form a single part of a URI, and to false when escaping an
15084  * entire URI or URI reference.
15085  *
15086  * In the case of non-ascii characters, the string is encoded according to
15087  * utf-8 and then converted according to RFC 2396.
15088  *
15089  * Examples
15090  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094  *
15095  */
15096 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15097 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098     xmlXPathObjectPtr str;
15099     int escape_reserved;
15100     xmlBufferPtr target;
15101     xmlChar *cptr;
15102     xmlChar escape[4];
15103 
15104     CHECK_ARITY(2);
15105 
15106     escape_reserved = xmlXPathPopBoolean(ctxt);
15107 
15108     CAST_TO_STRING;
15109     str = valuePop(ctxt);
15110 
15111     target = xmlBufferCreate();
15112 
15113     escape[0] = '%';
15114     escape[3] = 0;
15115 
15116     if (target) {
15117 	for (cptr = str->stringval; *cptr; cptr++) {
15118 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119 		(*cptr >= 'a' && *cptr <= 'z') ||
15120 		(*cptr >= '0' && *cptr <= '9') ||
15121 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15124 		(*cptr == '%' &&
15125 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131 		(!escape_reserved &&
15132 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135 		  *cptr == ','))) {
15136 		xmlBufferAdd(target, cptr, 1);
15137 	    } else {
15138 		if ((*cptr >> 4) < 10)
15139 		    escape[1] = '0' + (*cptr >> 4);
15140 		else
15141 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15142 		if ((*cptr & 0xF) < 10)
15143 		    escape[2] = '0' + (*cptr & 0xF);
15144 		else
15145 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15146 
15147 		xmlBufferAdd(target, &escape[0], 3);
15148 	    }
15149 	}
15150     }
15151     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152 	xmlBufferContent(target)));
15153     xmlBufferFree(target);
15154     xmlXPathReleaseObject(ctxt->context, str);
15155 }
15156 
15157 /**
15158  * xmlXPathRegisterAllFunctions:
15159  * @ctxt:  the XPath context
15160  *
15161  * Registers all default XPath functions in this context
15162  */
15163 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15164 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165 {
15166     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167                          xmlXPathBooleanFunction);
15168     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169                          xmlXPathCeilingFunction);
15170     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171                          xmlXPathCountFunction);
15172     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173                          xmlXPathConcatFunction);
15174     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175                          xmlXPathContainsFunction);
15176     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177                          xmlXPathIdFunction);
15178     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179                          xmlXPathFalseFunction);
15180     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181                          xmlXPathFloorFunction);
15182     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183                          xmlXPathLastFunction);
15184     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185                          xmlXPathLangFunction);
15186     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187                          xmlXPathLocalNameFunction);
15188     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189                          xmlXPathNotFunction);
15190     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191                          xmlXPathNameFunction);
15192     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193                          xmlXPathNamespaceURIFunction);
15194     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195                          xmlXPathNormalizeFunction);
15196     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197                          xmlXPathNumberFunction);
15198     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199                          xmlXPathPositionFunction);
15200     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201                          xmlXPathRoundFunction);
15202     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203                          xmlXPathStringFunction);
15204     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205                          xmlXPathStringLengthFunction);
15206     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207                          xmlXPathStartsWithFunction);
15208     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209                          xmlXPathSubstringFunction);
15210     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211                          xmlXPathSubstringBeforeFunction);
15212     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213                          xmlXPathSubstringAfterFunction);
15214     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215                          xmlXPathSumFunction);
15216     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217                          xmlXPathTrueFunction);
15218     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219                          xmlXPathTranslateFunction);
15220 
15221     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223                          xmlXPathEscapeUriFunction);
15224 }
15225 
15226 #endif /* LIBXML_XPATH_ENABLED */
15227 #define bottom_xpath
15228 #include "elfgcchack.h"
15229