Home | History | Annotate | Download | only in src
      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 (at) 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
    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
    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
    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
    181 xmlXPathGetSign(double val) {
    182     return(trio_signbit(val));
    183 }
    184 
    185 
    186 /*
    187  * TODO: when compatibility allows remove all "fake node libxslt" strings
    188  *       the test should just be name[0] = ' '
    189  */
    190 #ifdef DEBUG_XPATH_EXPRESSION
    191 #define DEBUG_STEP
    192 #define DEBUG_EXPR
    193 #define DEBUG_EVAL_COUNTS
    194 #endif
    195 
    196 static xmlNs xmlXPathXMLNamespaceStruct = {
    197     NULL,
    198     XML_NAMESPACE_DECL,
    199     XML_XML_NAMESPACE,
    200     BAD_CAST "xml",
    201     NULL,
    202     NULL
    203 };
    204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    205 #ifndef LIBXML_THREAD_ENABLED
    206 /*
    207  * Optimizer is disabled only when threaded apps are detected while
    208  * the library ain't compiled for thread safety.
    209  */
    210 static int xmlXPathDisableOptimizer = 0;
    211 #endif
    212 
    213 /************************************************************************
    214  *									*
    215  *			Error handling routines				*
    216  *									*
    217  ************************************************************************/
    218 
    219 /**
    220  * XP_ERRORNULL:
    221  * @X:  the error code
    222  *
    223  * Macro to raise an XPath error and return NULL.
    224  */
    225 #define XP_ERRORNULL(X)							\
    226     { xmlXPathErr(ctxt, X); return(NULL); }
    227 
    228 /*
    229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    230  */
    231 static const char *xmlXPathErrorMessages[] = {
    232     "Ok\n",
    233     "Number encoding\n",
    234     "Unfinished literal\n",
    235     "Start of literal\n",
    236     "Expected $ for variable reference\n",
    237     "Undefined variable\n",
    238     "Invalid predicate\n",
    239     "Invalid expression\n",
    240     "Missing closing curly brace\n",
    241     "Unregistered function\n",
    242     "Invalid operand\n",
    243     "Invalid type\n",
    244     "Invalid number of arguments\n",
    245     "Invalid context size\n",
    246     "Invalid context position\n",
    247     "Memory allocation error\n",
    248     "Syntax error\n",
    249     "Resource error\n",
    250     "Sub resource error\n",
    251     "Undefined namespace prefix\n",
    252     "Encoding error\n",
    253     "Char out of XML range\n",
    254     "Invalid or incomplete context\n",
    255     "?? Unknown error ??\n"	/* Must be last in the list! */
    256 };
    257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    258 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    259 /**
    260  * xmlXPathErrMemory:
    261  * @ctxt:  an XPath context
    262  * @extra:  extra informations
    263  *
    264  * Handle a redefinition of attribute error
    265  */
    266 static void
    267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    268 {
    269     if (ctxt != NULL) {
    270         if (extra) {
    271             xmlChar buf[200];
    272 
    273             xmlStrPrintf(buf, 200,
    274                          BAD_CAST "Memory allocation failed : %s\n",
    275                          extra);
    276             ctxt->lastError.message = (char *) xmlStrdup(buf);
    277         } else {
    278             ctxt->lastError.message = (char *)
    279 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    280         }
    281         ctxt->lastError.domain = XML_FROM_XPATH;
    282         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    283 	if (ctxt->error != NULL)
    284 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    285     } else {
    286         if (extra)
    287             __xmlRaiseError(NULL, NULL, NULL,
    288                             NULL, NULL, XML_FROM_XPATH,
    289                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    290                             extra, NULL, NULL, 0, 0,
    291                             "Memory allocation failed : %s\n", extra);
    292         else
    293             __xmlRaiseError(NULL, NULL, NULL,
    294                             NULL, NULL, XML_FROM_XPATH,
    295                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    296                             NULL, NULL, NULL, 0, 0,
    297                             "Memory allocation failed\n");
    298     }
    299 }
    300 
    301 /**
    302  * xmlXPathPErrMemory:
    303  * @ctxt:  an XPath parser context
    304  * @extra:  extra informations
    305  *
    306  * Handle a redefinition of attribute error
    307  */
    308 static void
    309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    310 {
    311     if (ctxt == NULL)
    312 	xmlXPathErrMemory(NULL, extra);
    313     else {
    314 	ctxt->error = XPATH_MEMORY_ERROR;
    315 	xmlXPathErrMemory(ctxt->context, extra);
    316     }
    317 }
    318 
    319 /**
    320  * xmlXPathErr:
    321  * @ctxt:  a XPath parser context
    322  * @error:  the error code
    323  *
    324  * Handle an XPath error
    325  */
    326 void
    327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    328 {
    329     if ((error < 0) || (error > MAXERRNO))
    330 	error = MAXERRNO;
    331     if (ctxt == NULL) {
    332 	__xmlRaiseError(NULL, NULL, NULL,
    333 			NULL, NULL, XML_FROM_XPATH,
    334 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    335 			XML_ERR_ERROR, NULL, 0,
    336 			NULL, NULL, NULL, 0, 0,
    337 			"%s", xmlXPathErrorMessages[error]);
    338 	return;
    339     }
    340     ctxt->error = error;
    341     if (ctxt->context == NULL) {
    342 	__xmlRaiseError(NULL, NULL, NULL,
    343 			NULL, NULL, XML_FROM_XPATH,
    344 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    345 			XML_ERR_ERROR, NULL, 0,
    346 			(const char *) ctxt->base, NULL, NULL,
    347 			ctxt->cur - ctxt->base, 0,
    348 			"%s", xmlXPathErrorMessages[error]);
    349 	return;
    350     }
    351 
    352     /* cleanup current last error */
    353     xmlResetError(&ctxt->context->lastError);
    354 
    355     ctxt->context->lastError.domain = XML_FROM_XPATH;
    356     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    357                            XPATH_EXPRESSION_OK;
    358     ctxt->context->lastError.level = XML_ERR_ERROR;
    359     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    360     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    361     ctxt->context->lastError.node = ctxt->context->debugNode;
    362     if (ctxt->context->error != NULL) {
    363 	ctxt->context->error(ctxt->context->userData,
    364 	                     &ctxt->context->lastError);
    365     } else {
    366 	__xmlRaiseError(NULL, NULL, NULL,
    367 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    368 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    369 			XML_ERR_ERROR, NULL, 0,
    370 			(const char *) ctxt->base, NULL, NULL,
    371 			ctxt->cur - ctxt->base, 0,
    372 			"%s", xmlXPathErrorMessages[error]);
    373     }
    374 
    375 }
    376 
    377 /**
    378  * xmlXPatherror:
    379  * @ctxt:  the XPath Parser context
    380  * @file:  the file name
    381  * @line:  the line number
    382  * @no:  the error number
    383  *
    384  * Formats an error message.
    385  */
    386 void
    387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    388               int line ATTRIBUTE_UNUSED, int no) {
    389     xmlXPathErr(ctxt, no);
    390 }
    391 
    392 /************************************************************************
    393  *									*
    394  *			Utilities					*
    395  *									*
    396  ************************************************************************/
    397 
    398 /**
    399  * xsltPointerList:
    400  *
    401  * Pointer-list for various purposes.
    402  */
    403 typedef struct _xmlPointerList xmlPointerList;
    404 typedef xmlPointerList *xmlPointerListPtr;
    405 struct _xmlPointerList {
    406     void **items;
    407     int number;
    408     int size;
    409 };
    410 /*
    411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    412 * and here, we should make the functions public.
    413 */
    414 static int
    415 xmlPointerListAddSize(xmlPointerListPtr list,
    416 		       void *item,
    417 		       int initialSize)
    418 {
    419     if (list->items == NULL) {
    420 	if (initialSize <= 0)
    421 	    initialSize = 1;
    422 	list->items = (void **) xmlMalloc(
    423 	    initialSize * sizeof(void *));
    424 	if (list->items == NULL) {
    425 	    xmlXPathErrMemory(NULL,
    426 		"xmlPointerListCreate: allocating item\n");
    427 	    return(-1);
    428 	}
    429 	list->number = 0;
    430 	list->size = initialSize;
    431     } else if (list->size <= list->number) {
    432 	list->size *= 2;
    433 	list->items = (void **) xmlRealloc(list->items,
    434 	    list->size * sizeof(void *));
    435 	if (list->items == NULL) {
    436 	    xmlXPathErrMemory(NULL,
    437 		"xmlPointerListCreate: re-allocating item\n");
    438 	    list->size = 0;
    439 	    return(-1);
    440 	}
    441     }
    442     list->items[list->number++] = item;
    443     return(0);
    444 }
    445 
    446 /**
    447  * xsltPointerListCreate:
    448  *
    449  * Creates an xsltPointerList structure.
    450  *
    451  * Returns a xsltPointerList structure or NULL in case of an error.
    452  */
    453 static xmlPointerListPtr
    454 xmlPointerListCreate(int initialSize)
    455 {
    456     xmlPointerListPtr ret;
    457 
    458     ret = xmlMalloc(sizeof(xmlPointerList));
    459     if (ret == NULL) {
    460 	xmlXPathErrMemory(NULL,
    461 	    "xmlPointerListCreate: allocating item\n");
    462 	return (NULL);
    463     }
    464     memset(ret, 0, sizeof(xmlPointerList));
    465     if (initialSize > 0) {
    466 	xmlPointerListAddSize(ret, NULL, initialSize);
    467 	ret->number = 0;
    468     }
    469     return (ret);
    470 }
    471 
    472 /**
    473  * xsltPointerListFree:
    474  *
    475  * Frees the xsltPointerList structure. This does not free
    476  * the content of the list.
    477  */
    478 static void
    479 xmlPointerListFree(xmlPointerListPtr list)
    480 {
    481     if (list == NULL)
    482 	return;
    483     if (list->items != NULL)
    484 	xmlFree(list->items);
    485     xmlFree(list);
    486 }
    487 
    488 /************************************************************************
    489  *									*
    490  *			Parser Types					*
    491  *									*
    492  ************************************************************************/
    493 
    494 /*
    495  * Types are private:
    496  */
    497 
    498 typedef enum {
    499     XPATH_OP_END=0,
    500     XPATH_OP_AND,
    501     XPATH_OP_OR,
    502     XPATH_OP_EQUAL,
    503     XPATH_OP_CMP,
    504     XPATH_OP_PLUS,
    505     XPATH_OP_MULT,
    506     XPATH_OP_UNION,
    507     XPATH_OP_ROOT,
    508     XPATH_OP_NODE,
    509     XPATH_OP_RESET, /* 10 */
    510     XPATH_OP_COLLECT,
    511     XPATH_OP_VALUE, /* 12 */
    512     XPATH_OP_VARIABLE,
    513     XPATH_OP_FUNCTION,
    514     XPATH_OP_ARG,
    515     XPATH_OP_PREDICATE,
    516     XPATH_OP_FILTER, /* 17 */
    517     XPATH_OP_SORT /* 18 */
    518 #ifdef LIBXML_XPTR_ENABLED
    519     ,XPATH_OP_RANGETO
    520 #endif
    521 } xmlXPathOp;
    522 
    523 typedef enum {
    524     AXIS_ANCESTOR = 1,
    525     AXIS_ANCESTOR_OR_SELF,
    526     AXIS_ATTRIBUTE,
    527     AXIS_CHILD,
    528     AXIS_DESCENDANT,
    529     AXIS_DESCENDANT_OR_SELF,
    530     AXIS_FOLLOWING,
    531     AXIS_FOLLOWING_SIBLING,
    532     AXIS_NAMESPACE,
    533     AXIS_PARENT,
    534     AXIS_PRECEDING,
    535     AXIS_PRECEDING_SIBLING,
    536     AXIS_SELF
    537 } xmlXPathAxisVal;
    538 
    539 typedef enum {
    540     NODE_TEST_NONE = 0,
    541     NODE_TEST_TYPE = 1,
    542     NODE_TEST_PI = 2,
    543     NODE_TEST_ALL = 3,
    544     NODE_TEST_NS = 4,
    545     NODE_TEST_NAME = 5
    546 } xmlXPathTestVal;
    547 
    548 typedef enum {
    549     NODE_TYPE_NODE = 0,
    550     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    551     NODE_TYPE_TEXT = XML_TEXT_NODE,
    552     NODE_TYPE_PI = XML_PI_NODE
    553 } xmlXPathTypeVal;
    554 
    555 #define XP_REWRITE_DOS_CHILD_ELEM 1
    556 
    557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    559 struct _xmlXPathStepOp {
    560     xmlXPathOp op;		/* The identifier of the operation */
    561     int ch1;			/* First child */
    562     int ch2;			/* Second child */
    563     int value;
    564     int value2;
    565     int value3;
    566     void *value4;
    567     void *value5;
    568     void *cache;
    569     void *cacheURI;
    570     int rewriteType;
    571 };
    572 
    573 struct _xmlXPathCompExpr {
    574     int nbStep;			/* Number of steps in this expression */
    575     int maxStep;		/* Maximum number of steps allocated */
    576     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    577     int last;			/* index of last step in expression */
    578     xmlChar *expr;		/* the expression being computed */
    579     xmlDictPtr dict;		/* the dictionnary to use if any */
    580 #ifdef DEBUG_EVAL_COUNTS
    581     int nb;
    582     xmlChar *string;
    583 #endif
    584 #ifdef XPATH_STREAMING
    585     xmlPatternPtr stream;
    586 #endif
    587 };
    588 
    589 /************************************************************************
    590  *									*
    591  *			Forward declarations				*
    592  *									*
    593  ************************************************************************/
    594 static void
    595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    596 static void
    597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    598 static int
    599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    600                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    601 static int
    602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    603 			    xmlXPathStepOpPtr op,
    604 			    int isPredicate);
    605 
    606 /************************************************************************
    607  *									*
    608  *			Parser Type functions				*
    609  *									*
    610  ************************************************************************/
    611 
    612 /**
    613  * xmlXPathNewCompExpr:
    614  *
    615  * Create a new Xpath component
    616  *
    617  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    618  */
    619 static xmlXPathCompExprPtr
    620 xmlXPathNewCompExpr(void) {
    621     xmlXPathCompExprPtr cur;
    622 
    623     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    624     if (cur == NULL) {
    625         xmlXPathErrMemory(NULL, "allocating component\n");
    626 	return(NULL);
    627     }
    628     memset(cur, 0, sizeof(xmlXPathCompExpr));
    629     cur->maxStep = 10;
    630     cur->nbStep = 0;
    631     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    632 	                                   sizeof(xmlXPathStepOp));
    633     if (cur->steps == NULL) {
    634         xmlXPathErrMemory(NULL, "allocating steps\n");
    635 	xmlFree(cur);
    636 	return(NULL);
    637     }
    638     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    639     cur->last = -1;
    640 #ifdef DEBUG_EVAL_COUNTS
    641     cur->nb = 0;
    642 #endif
    643     return(cur);
    644 }
    645 
    646 /**
    647  * xmlXPathFreeCompExpr:
    648  * @comp:  an XPATH comp
    649  *
    650  * Free up the memory allocated by @comp
    651  */
    652 void
    653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
    654 {
    655     xmlXPathStepOpPtr op;
    656     int i;
    657 
    658     if (comp == NULL)
    659         return;
    660     if (comp->dict == NULL) {
    661 	for (i = 0; i < comp->nbStep; i++) {
    662 	    op = &comp->steps[i];
    663 	    if (op->value4 != NULL) {
    664 		if (op->op == XPATH_OP_VALUE)
    665 		    xmlXPathFreeObject(op->value4);
    666 		else
    667 		    xmlFree(op->value4);
    668 	    }
    669 	    if (op->value5 != NULL)
    670 		xmlFree(op->value5);
    671 	}
    672     } else {
    673 	for (i = 0; i < comp->nbStep; i++) {
    674 	    op = &comp->steps[i];
    675 	    if (op->value4 != NULL) {
    676 		if (op->op == XPATH_OP_VALUE)
    677 		    xmlXPathFreeObject(op->value4);
    678 	    }
    679 	}
    680         xmlDictFree(comp->dict);
    681     }
    682     if (comp->steps != NULL) {
    683         xmlFree(comp->steps);
    684     }
    685 #ifdef DEBUG_EVAL_COUNTS
    686     if (comp->string != NULL) {
    687         xmlFree(comp->string);
    688     }
    689 #endif
    690 #ifdef XPATH_STREAMING
    691     if (comp->stream != NULL) {
    692         xmlFreePatternList(comp->stream);
    693     }
    694 #endif
    695     if (comp->expr != NULL) {
    696         xmlFree(comp->expr);
    697     }
    698 
    699     xmlFree(comp);
    700 }
    701 
    702 /**
    703  * xmlXPathCompExprAdd:
    704  * @comp:  the compiled expression
    705  * @ch1: first child index
    706  * @ch2: second child index
    707  * @op:  an op
    708  * @value:  the first int value
    709  * @value2:  the second int value
    710  * @value3:  the third int value
    711  * @value4:  the first string value
    712  * @value5:  the second string value
    713  *
    714  * Add a step to an XPath Compiled Expression
    715  *
    716  * Returns -1 in case of failure, the index otherwise
    717  */
    718 static int
    719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
    720    xmlXPathOp op, int value,
    721    int value2, int value3, void *value4, void *value5) {
    722     if (comp->nbStep >= comp->maxStep) {
    723 	xmlXPathStepOp *real;
    724 
    725 	comp->maxStep *= 2;
    726 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
    727 		                      comp->maxStep * sizeof(xmlXPathStepOp));
    728 	if (real == NULL) {
    729 	    comp->maxStep /= 2;
    730 	    xmlXPathErrMemory(NULL, "adding step\n");
    731 	    return(-1);
    732 	}
    733 	comp->steps = real;
    734     }
    735     comp->last = comp->nbStep;
    736     comp->steps[comp->nbStep].rewriteType = 0;
    737     comp->steps[comp->nbStep].ch1 = ch1;
    738     comp->steps[comp->nbStep].ch2 = ch2;
    739     comp->steps[comp->nbStep].op = op;
    740     comp->steps[comp->nbStep].value = value;
    741     comp->steps[comp->nbStep].value2 = value2;
    742     comp->steps[comp->nbStep].value3 = value3;
    743     if ((comp->dict != NULL) &&
    744         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
    745 	 (op == XPATH_OP_COLLECT))) {
    746         if (value4 != NULL) {
    747 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
    748 	        (void *)xmlDictLookup(comp->dict, value4, -1);
    749 	    xmlFree(value4);
    750 	} else
    751 	    comp->steps[comp->nbStep].value4 = NULL;
    752         if (value5 != NULL) {
    753 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
    754 	        (void *)xmlDictLookup(comp->dict, value5, -1);
    755 	    xmlFree(value5);
    756 	} else
    757 	    comp->steps[comp->nbStep].value5 = NULL;
    758     } else {
    759 	comp->steps[comp->nbStep].value4 = value4;
    760 	comp->steps[comp->nbStep].value5 = value5;
    761     }
    762     comp->steps[comp->nbStep].cache = NULL;
    763     return(comp->nbStep++);
    764 }
    765 
    766 /**
    767  * xmlXPathCompSwap:
    768  * @comp:  the compiled expression
    769  * @op: operation index
    770  *
    771  * Swaps 2 operations in the compiled expression
    772  */
    773 static void
    774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
    775     int tmp;
    776 
    777 #ifndef LIBXML_THREAD_ENABLED
    778     /*
    779      * Since this manipulates possibly shared variables, this is
    780      * disabled if one detects that the library is used in a multithreaded
    781      * application
    782      */
    783     if (xmlXPathDisableOptimizer)
    784 	return;
    785 #endif
    786 
    787     tmp = op->ch1;
    788     op->ch1 = op->ch2;
    789     op->ch2 = tmp;
    790 }
    791 
    792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
    793     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
    794 	                (op), (val), (val2), (val3), (val4), (val5))
    795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
    796     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
    797 	                (op), (val), (val2), (val3), (val4), (val5))
    798 
    799 #define PUSH_LEAVE_EXPR(op, val, val2)					\
    800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
    801 
    802 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
    803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
    804 
    805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
    806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
    807 			(val), (val2), 0 ,NULL ,NULL)
    808 
    809 /************************************************************************
    810  *									*
    811  *		XPath object cache structures				*
    812  *									*
    813  ************************************************************************/
    814 
    815 /* #define XP_DEFAULT_CACHE_ON */
    816 
    817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
    818 
    819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
    820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
    821 struct _xmlXPathContextCache {
    822     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
    823     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
    824     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
    825     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
    826     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
    827     int maxNodeset;
    828     int maxString;
    829     int maxBoolean;
    830     int maxNumber;
    831     int maxMisc;
    832 #ifdef XP_DEBUG_OBJ_USAGE
    833     int dbgCachedAll;
    834     int dbgCachedNodeset;
    835     int dbgCachedString;
    836     int dbgCachedBool;
    837     int dbgCachedNumber;
    838     int dbgCachedPoint;
    839     int dbgCachedRange;
    840     int dbgCachedLocset;
    841     int dbgCachedUsers;
    842     int dbgCachedXSLTTree;
    843     int dbgCachedUndefined;
    844 
    845 
    846     int dbgReusedAll;
    847     int dbgReusedNodeset;
    848     int dbgReusedString;
    849     int dbgReusedBool;
    850     int dbgReusedNumber;
    851     int dbgReusedPoint;
    852     int dbgReusedRange;
    853     int dbgReusedLocset;
    854     int dbgReusedUsers;
    855     int dbgReusedXSLTTree;
    856     int dbgReusedUndefined;
    857 
    858 #endif
    859 };
    860 
    861 /************************************************************************
    862  *									*
    863  *		Debugging related functions				*
    864  *									*
    865  ************************************************************************/
    866 
    867 #define STRANGE							\
    868     xmlGenericError(xmlGenericErrorContext,				\
    869 	    "Internal error at %s:%d\n",				\
    870             __FILE__, __LINE__);
    871 
    872 #ifdef LIBXML_DEBUG_ENABLED
    873 static void
    874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
    875     int i;
    876     char shift[100];
    877 
    878     for (i = 0;((i < depth) && (i < 25));i++)
    879         shift[2 * i] = shift[2 * i + 1] = ' ';
    880     shift[2 * i] = shift[2 * i + 1] = 0;
    881     if (cur == NULL) {
    882 	fprintf(output, "%s", shift);
    883 	fprintf(output, "Node is NULL !\n");
    884 	return;
    885 
    886     }
    887 
    888     if ((cur->type == XML_DOCUMENT_NODE) ||
    889 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
    890 	fprintf(output, "%s", shift);
    891 	fprintf(output, " /\n");
    892     } else if (cur->type == XML_ATTRIBUTE_NODE)
    893 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
    894     else
    895 	xmlDebugDumpOneNode(output, cur, depth);
    896 }
    897 static void
    898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
    899     xmlNodePtr tmp;
    900     int i;
    901     char shift[100];
    902 
    903     for (i = 0;((i < depth) && (i < 25));i++)
    904         shift[2 * i] = shift[2 * i + 1] = ' ';
    905     shift[2 * i] = shift[2 * i + 1] = 0;
    906     if (cur == NULL) {
    907 	fprintf(output, "%s", shift);
    908 	fprintf(output, "Node is NULL !\n");
    909 	return;
    910 
    911     }
    912 
    913     while (cur != NULL) {
    914 	tmp = cur;
    915 	cur = cur->next;
    916 	xmlDebugDumpOneNode(output, tmp, depth);
    917     }
    918 }
    919 
    920 static void
    921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
    922     int i;
    923     char shift[100];
    924 
    925     for (i = 0;((i < depth) && (i < 25));i++)
    926         shift[2 * i] = shift[2 * i + 1] = ' ';
    927     shift[2 * i] = shift[2 * i + 1] = 0;
    928 
    929     if (cur == NULL) {
    930 	fprintf(output, "%s", shift);
    931 	fprintf(output, "NodeSet is NULL !\n");
    932 	return;
    933 
    934     }
    935 
    936     if (cur != NULL) {
    937 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
    938 	for (i = 0;i < cur->nodeNr;i++) {
    939 	    fprintf(output, "%s", shift);
    940 	    fprintf(output, "%d", i + 1);
    941 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
    942 	}
    943     }
    944 }
    945 
    946 static void
    947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
    948     int i;
    949     char shift[100];
    950 
    951     for (i = 0;((i < depth) && (i < 25));i++)
    952         shift[2 * i] = shift[2 * i + 1] = ' ';
    953     shift[2 * i] = shift[2 * i + 1] = 0;
    954 
    955     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
    956 	fprintf(output, "%s", shift);
    957 	fprintf(output, "Value Tree is NULL !\n");
    958 	return;
    959 
    960     }
    961 
    962     fprintf(output, "%s", shift);
    963     fprintf(output, "%d", i + 1);
    964     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
    965 }
    966 #if defined(LIBXML_XPTR_ENABLED)
    967 static void
    968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
    969     int i;
    970     char shift[100];
    971 
    972     for (i = 0;((i < depth) && (i < 25));i++)
    973         shift[2 * i] = shift[2 * i + 1] = ' ';
    974     shift[2 * i] = shift[2 * i + 1] = 0;
    975 
    976     if (cur == NULL) {
    977 	fprintf(output, "%s", shift);
    978 	fprintf(output, "LocationSet is NULL !\n");
    979 	return;
    980 
    981     }
    982 
    983     for (i = 0;i < cur->locNr;i++) {
    984 	fprintf(output, "%s", shift);
    985         fprintf(output, "%d : ", i + 1);
    986 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
    987     }
    988 }
    989 #endif /* LIBXML_XPTR_ENABLED */
    990 
    991 /**
    992  * xmlXPathDebugDumpObject:
    993  * @output:  the FILE * to dump the output
    994  * @cur:  the object to inspect
    995  * @depth:  indentation level
    996  *
    997  * Dump the content of the object for debugging purposes
    998  */
    999 void
   1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1001     int i;
   1002     char shift[100];
   1003 
   1004     if (output == NULL) return;
   1005 
   1006     for (i = 0;((i < depth) && (i < 25));i++)
   1007         shift[2 * i] = shift[2 * i + 1] = ' ';
   1008     shift[2 * i] = shift[2 * i + 1] = 0;
   1009 
   1010 
   1011     fprintf(output, "%s", shift);
   1012 
   1013     if (cur == NULL) {
   1014         fprintf(output, "Object is empty (NULL)\n");
   1015 	return;
   1016     }
   1017     switch(cur->type) {
   1018         case XPATH_UNDEFINED:
   1019 	    fprintf(output, "Object is uninitialized\n");
   1020 	    break;
   1021         case XPATH_NODESET:
   1022 	    fprintf(output, "Object is a Node Set :\n");
   1023 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1024 	    break;
   1025 	case XPATH_XSLT_TREE:
   1026 	    fprintf(output, "Object is an XSLT value tree :\n");
   1027 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1028 	    break;
   1029         case XPATH_BOOLEAN:
   1030 	    fprintf(output, "Object is a Boolean : ");
   1031 	    if (cur->boolval) fprintf(output, "true\n");
   1032 	    else fprintf(output, "false\n");
   1033 	    break;
   1034         case XPATH_NUMBER:
   1035 	    switch (xmlXPathIsInf(cur->floatval)) {
   1036 	    case 1:
   1037 		fprintf(output, "Object is a number : Infinity\n");
   1038 		break;
   1039 	    case -1:
   1040 		fprintf(output, "Object is a number : -Infinity\n");
   1041 		break;
   1042 	    default:
   1043 		if (xmlXPathIsNaN(cur->floatval)) {
   1044 		    fprintf(output, "Object is a number : NaN\n");
   1045 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1046 		    fprintf(output, "Object is a number : 0\n");
   1047 		} else {
   1048 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1049 		}
   1050 	    }
   1051 	    break;
   1052         case XPATH_STRING:
   1053 	    fprintf(output, "Object is a string : ");
   1054 	    xmlDebugDumpString(output, cur->stringval);
   1055 	    fprintf(output, "\n");
   1056 	    break;
   1057 	case XPATH_POINT:
   1058 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1059 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1060 	    fprintf(output, "\n");
   1061 	    break;
   1062 	case XPATH_RANGE:
   1063 	    if ((cur->user2 == NULL) ||
   1064 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1065 		fprintf(output, "Object is a collapsed range :\n");
   1066 		fprintf(output, "%s", shift);
   1067 		if (cur->index >= 0)
   1068 		    fprintf(output, "index %d in ", cur->index);
   1069 		fprintf(output, "node\n");
   1070 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1071 			              depth + 1);
   1072 	    } else  {
   1073 		fprintf(output, "Object is a range :\n");
   1074 		fprintf(output, "%s", shift);
   1075 		fprintf(output, "From ");
   1076 		if (cur->index >= 0)
   1077 		    fprintf(output, "index %d in ", cur->index);
   1078 		fprintf(output, "node\n");
   1079 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1080 			              depth + 1);
   1081 		fprintf(output, "%s", shift);
   1082 		fprintf(output, "To ");
   1083 		if (cur->index2 >= 0)
   1084 		    fprintf(output, "index %d in ", cur->index2);
   1085 		fprintf(output, "node\n");
   1086 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1087 			              depth + 1);
   1088 		fprintf(output, "\n");
   1089 	    }
   1090 	    break;
   1091 	case XPATH_LOCATIONSET:
   1092 #if defined(LIBXML_XPTR_ENABLED)
   1093 	    fprintf(output, "Object is a Location Set:\n");
   1094 	    xmlXPathDebugDumpLocationSet(output,
   1095 		    (xmlLocationSetPtr) cur->user, depth);
   1096 #endif
   1097 	    break;
   1098 	case XPATH_USERS:
   1099 	    fprintf(output, "Object is user defined\n");
   1100 	    break;
   1101     }
   1102 }
   1103 
   1104 static void
   1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1106 	                     xmlXPathStepOpPtr op, int depth) {
   1107     int i;
   1108     char shift[100];
   1109 
   1110     for (i = 0;((i < depth) && (i < 25));i++)
   1111         shift[2 * i] = shift[2 * i + 1] = ' ';
   1112     shift[2 * i] = shift[2 * i + 1] = 0;
   1113 
   1114     fprintf(output, "%s", shift);
   1115     if (op == NULL) {
   1116 	fprintf(output, "Step is NULL\n");
   1117 	return;
   1118     }
   1119     switch (op->op) {
   1120         case XPATH_OP_END:
   1121 	    fprintf(output, "END"); break;
   1122         case XPATH_OP_AND:
   1123 	    fprintf(output, "AND"); break;
   1124         case XPATH_OP_OR:
   1125 	    fprintf(output, "OR"); break;
   1126         case XPATH_OP_EQUAL:
   1127 	     if (op->value)
   1128 		 fprintf(output, "EQUAL =");
   1129 	     else
   1130 		 fprintf(output, "EQUAL !=");
   1131 	     break;
   1132         case XPATH_OP_CMP:
   1133 	     if (op->value)
   1134 		 fprintf(output, "CMP <");
   1135 	     else
   1136 		 fprintf(output, "CMP >");
   1137 	     if (!op->value2)
   1138 		 fprintf(output, "=");
   1139 	     break;
   1140         case XPATH_OP_PLUS:
   1141 	     if (op->value == 0)
   1142 		 fprintf(output, "PLUS -");
   1143 	     else if (op->value == 1)
   1144 		 fprintf(output, "PLUS +");
   1145 	     else if (op->value == 2)
   1146 		 fprintf(output, "PLUS unary -");
   1147 	     else if (op->value == 3)
   1148 		 fprintf(output, "PLUS unary - -");
   1149 	     break;
   1150         case XPATH_OP_MULT:
   1151 	     if (op->value == 0)
   1152 		 fprintf(output, "MULT *");
   1153 	     else if (op->value == 1)
   1154 		 fprintf(output, "MULT div");
   1155 	     else
   1156 		 fprintf(output, "MULT mod");
   1157 	     break;
   1158         case XPATH_OP_UNION:
   1159 	     fprintf(output, "UNION"); break;
   1160         case XPATH_OP_ROOT:
   1161 	     fprintf(output, "ROOT"); break;
   1162         case XPATH_OP_NODE:
   1163 	     fprintf(output, "NODE"); break;
   1164         case XPATH_OP_RESET:
   1165 	     fprintf(output, "RESET"); break;
   1166         case XPATH_OP_SORT:
   1167 	     fprintf(output, "SORT"); break;
   1168         case XPATH_OP_COLLECT: {
   1169 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1170 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1171 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1172 	    const xmlChar *prefix = op->value4;
   1173 	    const xmlChar *name = op->value5;
   1174 
   1175 	    fprintf(output, "COLLECT ");
   1176 	    switch (axis) {
   1177 		case AXIS_ANCESTOR:
   1178 		    fprintf(output, " 'ancestors' "); break;
   1179 		case AXIS_ANCESTOR_OR_SELF:
   1180 		    fprintf(output, " 'ancestors-or-self' "); break;
   1181 		case AXIS_ATTRIBUTE:
   1182 		    fprintf(output, " 'attributes' "); break;
   1183 		case AXIS_CHILD:
   1184 		    fprintf(output, " 'child' "); break;
   1185 		case AXIS_DESCENDANT:
   1186 		    fprintf(output, " 'descendant' "); break;
   1187 		case AXIS_DESCENDANT_OR_SELF:
   1188 		    fprintf(output, " 'descendant-or-self' "); break;
   1189 		case AXIS_FOLLOWING:
   1190 		    fprintf(output, " 'following' "); break;
   1191 		case AXIS_FOLLOWING_SIBLING:
   1192 		    fprintf(output, " 'following-siblings' "); break;
   1193 		case AXIS_NAMESPACE:
   1194 		    fprintf(output, " 'namespace' "); break;
   1195 		case AXIS_PARENT:
   1196 		    fprintf(output, " 'parent' "); break;
   1197 		case AXIS_PRECEDING:
   1198 		    fprintf(output, " 'preceding' "); break;
   1199 		case AXIS_PRECEDING_SIBLING:
   1200 		    fprintf(output, " 'preceding-sibling' "); break;
   1201 		case AXIS_SELF:
   1202 		    fprintf(output, " 'self' "); break;
   1203 	    }
   1204 	    switch (test) {
   1205                 case NODE_TEST_NONE:
   1206 		    fprintf(output, "'none' "); break;
   1207                 case NODE_TEST_TYPE:
   1208 		    fprintf(output, "'type' "); break;
   1209                 case NODE_TEST_PI:
   1210 		    fprintf(output, "'PI' "); break;
   1211                 case NODE_TEST_ALL:
   1212 		    fprintf(output, "'all' "); break;
   1213                 case NODE_TEST_NS:
   1214 		    fprintf(output, "'namespace' "); break;
   1215                 case NODE_TEST_NAME:
   1216 		    fprintf(output, "'name' "); break;
   1217 	    }
   1218 	    switch (type) {
   1219                 case NODE_TYPE_NODE:
   1220 		    fprintf(output, "'node' "); break;
   1221                 case NODE_TYPE_COMMENT:
   1222 		    fprintf(output, "'comment' "); break;
   1223                 case NODE_TYPE_TEXT:
   1224 		    fprintf(output, "'text' "); break;
   1225                 case NODE_TYPE_PI:
   1226 		    fprintf(output, "'PI' "); break;
   1227 	    }
   1228 	    if (prefix != NULL)
   1229 		fprintf(output, "%s:", prefix);
   1230 	    if (name != NULL)
   1231 		fprintf(output, "%s", (const char *) name);
   1232 	    break;
   1233 
   1234         }
   1235 	case XPATH_OP_VALUE: {
   1236 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1237 
   1238 	    fprintf(output, "ELEM ");
   1239 	    xmlXPathDebugDumpObject(output, object, 0);
   1240 	    goto finish;
   1241 	}
   1242 	case XPATH_OP_VARIABLE: {
   1243 	    const xmlChar *prefix = op->value5;
   1244 	    const xmlChar *name = op->value4;
   1245 
   1246 	    if (prefix != NULL)
   1247 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1248 	    else
   1249 		fprintf(output, "VARIABLE %s", name);
   1250 	    break;
   1251 	}
   1252 	case XPATH_OP_FUNCTION: {
   1253 	    int nbargs = op->value;
   1254 	    const xmlChar *prefix = op->value5;
   1255 	    const xmlChar *name = op->value4;
   1256 
   1257 	    if (prefix != NULL)
   1258 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1259 			prefix, name, nbargs);
   1260 	    else
   1261 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1262 	    break;
   1263 	}
   1264         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1265         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1266         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1267 #ifdef LIBXML_XPTR_ENABLED
   1268         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1269 #endif
   1270 	default:
   1271         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1272     }
   1273     fprintf(output, "\n");
   1274 finish:
   1275     if (op->ch1 >= 0)
   1276 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1277     if (op->ch2 >= 0)
   1278 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1279 }
   1280 
   1281 /**
   1282  * xmlXPathDebugDumpCompExpr:
   1283  * @output:  the FILE * for the output
   1284  * @comp:  the precompiled XPath expression
   1285  * @depth:  the indentation level.
   1286  *
   1287  * Dumps the tree of the compiled XPath expression.
   1288  */
   1289 void
   1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1291 	                  int depth) {
   1292     int i;
   1293     char shift[100];
   1294 
   1295     if ((output == NULL) || (comp == NULL)) return;
   1296 
   1297     for (i = 0;((i < depth) && (i < 25));i++)
   1298         shift[2 * i] = shift[2 * i + 1] = ' ';
   1299     shift[2 * i] = shift[2 * i + 1] = 0;
   1300 
   1301     fprintf(output, "%s", shift);
   1302 
   1303     fprintf(output, "Compiled Expression : %d elements\n",
   1304 	    comp->nbStep);
   1305     i = comp->last;
   1306     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1307 }
   1308 
   1309 #ifdef XP_DEBUG_OBJ_USAGE
   1310 
   1311 /*
   1312 * XPath object usage related debugging variables.
   1313 */
   1314 static int xmlXPathDebugObjCounterUndefined = 0;
   1315 static int xmlXPathDebugObjCounterNodeset = 0;
   1316 static int xmlXPathDebugObjCounterBool = 0;
   1317 static int xmlXPathDebugObjCounterNumber = 0;
   1318 static int xmlXPathDebugObjCounterString = 0;
   1319 static int xmlXPathDebugObjCounterPoint = 0;
   1320 static int xmlXPathDebugObjCounterRange = 0;
   1321 static int xmlXPathDebugObjCounterLocset = 0;
   1322 static int xmlXPathDebugObjCounterUsers = 0;
   1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1324 static int xmlXPathDebugObjCounterAll = 0;
   1325 
   1326 static int xmlXPathDebugObjTotalUndefined = 0;
   1327 static int xmlXPathDebugObjTotalNodeset = 0;
   1328 static int xmlXPathDebugObjTotalBool = 0;
   1329 static int xmlXPathDebugObjTotalNumber = 0;
   1330 static int xmlXPathDebugObjTotalString = 0;
   1331 static int xmlXPathDebugObjTotalPoint = 0;
   1332 static int xmlXPathDebugObjTotalRange = 0;
   1333 static int xmlXPathDebugObjTotalLocset = 0;
   1334 static int xmlXPathDebugObjTotalUsers = 0;
   1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1336 static int xmlXPathDebugObjTotalAll = 0;
   1337 
   1338 static int xmlXPathDebugObjMaxUndefined = 0;
   1339 static int xmlXPathDebugObjMaxNodeset = 0;
   1340 static int xmlXPathDebugObjMaxBool = 0;
   1341 static int xmlXPathDebugObjMaxNumber = 0;
   1342 static int xmlXPathDebugObjMaxString = 0;
   1343 static int xmlXPathDebugObjMaxPoint = 0;
   1344 static int xmlXPathDebugObjMaxRange = 0;
   1345 static int xmlXPathDebugObjMaxLocset = 0;
   1346 static int xmlXPathDebugObjMaxUsers = 0;
   1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1348 static int xmlXPathDebugObjMaxAll = 0;
   1349 
   1350 /* REVISIT TODO: Make this static when committing */
   1351 static void
   1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1353 {
   1354     if (ctxt != NULL) {
   1355 	if (ctxt->cache != NULL) {
   1356 	    xmlXPathContextCachePtr cache =
   1357 		(xmlXPathContextCachePtr) ctxt->cache;
   1358 
   1359 	    cache->dbgCachedAll = 0;
   1360 	    cache->dbgCachedNodeset = 0;
   1361 	    cache->dbgCachedString = 0;
   1362 	    cache->dbgCachedBool = 0;
   1363 	    cache->dbgCachedNumber = 0;
   1364 	    cache->dbgCachedPoint = 0;
   1365 	    cache->dbgCachedRange = 0;
   1366 	    cache->dbgCachedLocset = 0;
   1367 	    cache->dbgCachedUsers = 0;
   1368 	    cache->dbgCachedXSLTTree = 0;
   1369 	    cache->dbgCachedUndefined = 0;
   1370 
   1371 	    cache->dbgReusedAll = 0;
   1372 	    cache->dbgReusedNodeset = 0;
   1373 	    cache->dbgReusedString = 0;
   1374 	    cache->dbgReusedBool = 0;
   1375 	    cache->dbgReusedNumber = 0;
   1376 	    cache->dbgReusedPoint = 0;
   1377 	    cache->dbgReusedRange = 0;
   1378 	    cache->dbgReusedLocset = 0;
   1379 	    cache->dbgReusedUsers = 0;
   1380 	    cache->dbgReusedXSLTTree = 0;
   1381 	    cache->dbgReusedUndefined = 0;
   1382 	}
   1383     }
   1384 
   1385     xmlXPathDebugObjCounterUndefined = 0;
   1386     xmlXPathDebugObjCounterNodeset = 0;
   1387     xmlXPathDebugObjCounterBool = 0;
   1388     xmlXPathDebugObjCounterNumber = 0;
   1389     xmlXPathDebugObjCounterString = 0;
   1390     xmlXPathDebugObjCounterPoint = 0;
   1391     xmlXPathDebugObjCounterRange = 0;
   1392     xmlXPathDebugObjCounterLocset = 0;
   1393     xmlXPathDebugObjCounterUsers = 0;
   1394     xmlXPathDebugObjCounterXSLTTree = 0;
   1395     xmlXPathDebugObjCounterAll = 0;
   1396 
   1397     xmlXPathDebugObjTotalUndefined = 0;
   1398     xmlXPathDebugObjTotalNodeset = 0;
   1399     xmlXPathDebugObjTotalBool = 0;
   1400     xmlXPathDebugObjTotalNumber = 0;
   1401     xmlXPathDebugObjTotalString = 0;
   1402     xmlXPathDebugObjTotalPoint = 0;
   1403     xmlXPathDebugObjTotalRange = 0;
   1404     xmlXPathDebugObjTotalLocset = 0;
   1405     xmlXPathDebugObjTotalUsers = 0;
   1406     xmlXPathDebugObjTotalXSLTTree = 0;
   1407     xmlXPathDebugObjTotalAll = 0;
   1408 
   1409     xmlXPathDebugObjMaxUndefined = 0;
   1410     xmlXPathDebugObjMaxNodeset = 0;
   1411     xmlXPathDebugObjMaxBool = 0;
   1412     xmlXPathDebugObjMaxNumber = 0;
   1413     xmlXPathDebugObjMaxString = 0;
   1414     xmlXPathDebugObjMaxPoint = 0;
   1415     xmlXPathDebugObjMaxRange = 0;
   1416     xmlXPathDebugObjMaxLocset = 0;
   1417     xmlXPathDebugObjMaxUsers = 0;
   1418     xmlXPathDebugObjMaxXSLTTree = 0;
   1419     xmlXPathDebugObjMaxAll = 0;
   1420 
   1421 }
   1422 
   1423 static void
   1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1425 			      xmlXPathObjectType objType)
   1426 {
   1427     int isCached = 0;
   1428 
   1429     if (ctxt != NULL) {
   1430 	if (ctxt->cache != NULL) {
   1431 	    xmlXPathContextCachePtr cache =
   1432 		(xmlXPathContextCachePtr) ctxt->cache;
   1433 
   1434 	    isCached = 1;
   1435 
   1436 	    cache->dbgReusedAll++;
   1437 	    switch (objType) {
   1438 		case XPATH_UNDEFINED:
   1439 		    cache->dbgReusedUndefined++;
   1440 		    break;
   1441 		case XPATH_NODESET:
   1442 		    cache->dbgReusedNodeset++;
   1443 		    break;
   1444 		case XPATH_BOOLEAN:
   1445 		    cache->dbgReusedBool++;
   1446 		    break;
   1447 		case XPATH_NUMBER:
   1448 		    cache->dbgReusedNumber++;
   1449 		    break;
   1450 		case XPATH_STRING:
   1451 		    cache->dbgReusedString++;
   1452 		    break;
   1453 		case XPATH_POINT:
   1454 		    cache->dbgReusedPoint++;
   1455 		    break;
   1456 		case XPATH_RANGE:
   1457 		    cache->dbgReusedRange++;
   1458 		    break;
   1459 		case XPATH_LOCATIONSET:
   1460 		    cache->dbgReusedLocset++;
   1461 		    break;
   1462 		case XPATH_USERS:
   1463 		    cache->dbgReusedUsers++;
   1464 		    break;
   1465 		case XPATH_XSLT_TREE:
   1466 		    cache->dbgReusedXSLTTree++;
   1467 		    break;
   1468 		default:
   1469 		    break;
   1470 	    }
   1471 	}
   1472     }
   1473 
   1474     switch (objType) {
   1475 	case XPATH_UNDEFINED:
   1476 	    if (! isCached)
   1477 		xmlXPathDebugObjTotalUndefined++;
   1478 	    xmlXPathDebugObjCounterUndefined++;
   1479 	    if (xmlXPathDebugObjCounterUndefined >
   1480 		xmlXPathDebugObjMaxUndefined)
   1481 		xmlXPathDebugObjMaxUndefined =
   1482 		    xmlXPathDebugObjCounterUndefined;
   1483 	    break;
   1484 	case XPATH_NODESET:
   1485 	    if (! isCached)
   1486 		xmlXPathDebugObjTotalNodeset++;
   1487 	    xmlXPathDebugObjCounterNodeset++;
   1488 	    if (xmlXPathDebugObjCounterNodeset >
   1489 		xmlXPathDebugObjMaxNodeset)
   1490 		xmlXPathDebugObjMaxNodeset =
   1491 		    xmlXPathDebugObjCounterNodeset;
   1492 	    break;
   1493 	case XPATH_BOOLEAN:
   1494 	    if (! isCached)
   1495 		xmlXPathDebugObjTotalBool++;
   1496 	    xmlXPathDebugObjCounterBool++;
   1497 	    if (xmlXPathDebugObjCounterBool >
   1498 		xmlXPathDebugObjMaxBool)
   1499 		xmlXPathDebugObjMaxBool =
   1500 		    xmlXPathDebugObjCounterBool;
   1501 	    break;
   1502 	case XPATH_NUMBER:
   1503 	    if (! isCached)
   1504 		xmlXPathDebugObjTotalNumber++;
   1505 	    xmlXPathDebugObjCounterNumber++;
   1506 	    if (xmlXPathDebugObjCounterNumber >
   1507 		xmlXPathDebugObjMaxNumber)
   1508 		xmlXPathDebugObjMaxNumber =
   1509 		    xmlXPathDebugObjCounterNumber;
   1510 	    break;
   1511 	case XPATH_STRING:
   1512 	    if (! isCached)
   1513 		xmlXPathDebugObjTotalString++;
   1514 	    xmlXPathDebugObjCounterString++;
   1515 	    if (xmlXPathDebugObjCounterString >
   1516 		xmlXPathDebugObjMaxString)
   1517 		xmlXPathDebugObjMaxString =
   1518 		    xmlXPathDebugObjCounterString;
   1519 	    break;
   1520 	case XPATH_POINT:
   1521 	    if (! isCached)
   1522 		xmlXPathDebugObjTotalPoint++;
   1523 	    xmlXPathDebugObjCounterPoint++;
   1524 	    if (xmlXPathDebugObjCounterPoint >
   1525 		xmlXPathDebugObjMaxPoint)
   1526 		xmlXPathDebugObjMaxPoint =
   1527 		    xmlXPathDebugObjCounterPoint;
   1528 	    break;
   1529 	case XPATH_RANGE:
   1530 	    if (! isCached)
   1531 		xmlXPathDebugObjTotalRange++;
   1532 	    xmlXPathDebugObjCounterRange++;
   1533 	    if (xmlXPathDebugObjCounterRange >
   1534 		xmlXPathDebugObjMaxRange)
   1535 		xmlXPathDebugObjMaxRange =
   1536 		    xmlXPathDebugObjCounterRange;
   1537 	    break;
   1538 	case XPATH_LOCATIONSET:
   1539 	    if (! isCached)
   1540 		xmlXPathDebugObjTotalLocset++;
   1541 	    xmlXPathDebugObjCounterLocset++;
   1542 	    if (xmlXPathDebugObjCounterLocset >
   1543 		xmlXPathDebugObjMaxLocset)
   1544 		xmlXPathDebugObjMaxLocset =
   1545 		    xmlXPathDebugObjCounterLocset;
   1546 	    break;
   1547 	case XPATH_USERS:
   1548 	    if (! isCached)
   1549 		xmlXPathDebugObjTotalUsers++;
   1550 	    xmlXPathDebugObjCounterUsers++;
   1551 	    if (xmlXPathDebugObjCounterUsers >
   1552 		xmlXPathDebugObjMaxUsers)
   1553 		xmlXPathDebugObjMaxUsers =
   1554 		    xmlXPathDebugObjCounterUsers;
   1555 	    break;
   1556 	case XPATH_XSLT_TREE:
   1557 	    if (! isCached)
   1558 		xmlXPathDebugObjTotalXSLTTree++;
   1559 	    xmlXPathDebugObjCounterXSLTTree++;
   1560 	    if (xmlXPathDebugObjCounterXSLTTree >
   1561 		xmlXPathDebugObjMaxXSLTTree)
   1562 		xmlXPathDebugObjMaxXSLTTree =
   1563 		    xmlXPathDebugObjCounterXSLTTree;
   1564 	    break;
   1565 	default:
   1566 	    break;
   1567     }
   1568     if (! isCached)
   1569 	xmlXPathDebugObjTotalAll++;
   1570     xmlXPathDebugObjCounterAll++;
   1571     if (xmlXPathDebugObjCounterAll >
   1572 	xmlXPathDebugObjMaxAll)
   1573 	xmlXPathDebugObjMaxAll =
   1574 	    xmlXPathDebugObjCounterAll;
   1575 }
   1576 
   1577 static void
   1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1579 			      xmlXPathObjectType objType)
   1580 {
   1581     int isCached = 0;
   1582 
   1583     if (ctxt != NULL) {
   1584 	if (ctxt->cache != NULL) {
   1585 	    xmlXPathContextCachePtr cache =
   1586 		(xmlXPathContextCachePtr) ctxt->cache;
   1587 
   1588 	    isCached = 1;
   1589 
   1590 	    cache->dbgCachedAll++;
   1591 	    switch (objType) {
   1592 		case XPATH_UNDEFINED:
   1593 		    cache->dbgCachedUndefined++;
   1594 		    break;
   1595 		case XPATH_NODESET:
   1596 		    cache->dbgCachedNodeset++;
   1597 		    break;
   1598 		case XPATH_BOOLEAN:
   1599 		    cache->dbgCachedBool++;
   1600 		    break;
   1601 		case XPATH_NUMBER:
   1602 		    cache->dbgCachedNumber++;
   1603 		    break;
   1604 		case XPATH_STRING:
   1605 		    cache->dbgCachedString++;
   1606 		    break;
   1607 		case XPATH_POINT:
   1608 		    cache->dbgCachedPoint++;
   1609 		    break;
   1610 		case XPATH_RANGE:
   1611 		    cache->dbgCachedRange++;
   1612 		    break;
   1613 		case XPATH_LOCATIONSET:
   1614 		    cache->dbgCachedLocset++;
   1615 		    break;
   1616 		case XPATH_USERS:
   1617 		    cache->dbgCachedUsers++;
   1618 		    break;
   1619 		case XPATH_XSLT_TREE:
   1620 		    cache->dbgCachedXSLTTree++;
   1621 		    break;
   1622 		default:
   1623 		    break;
   1624 	    }
   1625 
   1626 	}
   1627     }
   1628     switch (objType) {
   1629 	case XPATH_UNDEFINED:
   1630 	    xmlXPathDebugObjCounterUndefined--;
   1631 	    break;
   1632 	case XPATH_NODESET:
   1633 	    xmlXPathDebugObjCounterNodeset--;
   1634 	    break;
   1635 	case XPATH_BOOLEAN:
   1636 	    xmlXPathDebugObjCounterBool--;
   1637 	    break;
   1638 	case XPATH_NUMBER:
   1639 	    xmlXPathDebugObjCounterNumber--;
   1640 	    break;
   1641 	case XPATH_STRING:
   1642 	    xmlXPathDebugObjCounterString--;
   1643 	    break;
   1644 	case XPATH_POINT:
   1645 	    xmlXPathDebugObjCounterPoint--;
   1646 	    break;
   1647 	case XPATH_RANGE:
   1648 	    xmlXPathDebugObjCounterRange--;
   1649 	    break;
   1650 	case XPATH_LOCATIONSET:
   1651 	    xmlXPathDebugObjCounterLocset--;
   1652 	    break;
   1653 	case XPATH_USERS:
   1654 	    xmlXPathDebugObjCounterUsers--;
   1655 	    break;
   1656 	case XPATH_XSLT_TREE:
   1657 	    xmlXPathDebugObjCounterXSLTTree--;
   1658 	    break;
   1659 	default:
   1660 	    break;
   1661     }
   1662     xmlXPathDebugObjCounterAll--;
   1663 }
   1664 
   1665 /* REVISIT TODO: Make this static when committing */
   1666 static void
   1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   1668 {
   1669     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   1670 	reqXSLTTree, reqUndefined;
   1671     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   1672 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   1673     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   1674 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   1675     int leftObjs = xmlXPathDebugObjCounterAll;
   1676 
   1677     reqAll = xmlXPathDebugObjTotalAll;
   1678     reqNodeset = xmlXPathDebugObjTotalNodeset;
   1679     reqString = xmlXPathDebugObjTotalString;
   1680     reqBool = xmlXPathDebugObjTotalBool;
   1681     reqNumber = xmlXPathDebugObjTotalNumber;
   1682     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   1683     reqUndefined = xmlXPathDebugObjTotalUndefined;
   1684 
   1685     printf("# XPath object usage:\n");
   1686 
   1687     if (ctxt != NULL) {
   1688 	if (ctxt->cache != NULL) {
   1689 	    xmlXPathContextCachePtr cache =
   1690 		(xmlXPathContextCachePtr) ctxt->cache;
   1691 
   1692 	    reAll = cache->dbgReusedAll;
   1693 	    reqAll += reAll;
   1694 	    reNodeset = cache->dbgReusedNodeset;
   1695 	    reqNodeset += reNodeset;
   1696 	    reString = cache->dbgReusedString;
   1697 	    reqString += reString;
   1698 	    reBool = cache->dbgReusedBool;
   1699 	    reqBool += reBool;
   1700 	    reNumber = cache->dbgReusedNumber;
   1701 	    reqNumber += reNumber;
   1702 	    reXSLTTree = cache->dbgReusedXSLTTree;
   1703 	    reqXSLTTree += reXSLTTree;
   1704 	    reUndefined = cache->dbgReusedUndefined;
   1705 	    reqUndefined += reUndefined;
   1706 
   1707 	    caAll = cache->dbgCachedAll;
   1708 	    caBool = cache->dbgCachedBool;
   1709 	    caNodeset = cache->dbgCachedNodeset;
   1710 	    caString = cache->dbgCachedString;
   1711 	    caNumber = cache->dbgCachedNumber;
   1712 	    caXSLTTree = cache->dbgCachedXSLTTree;
   1713 	    caUndefined = cache->dbgCachedUndefined;
   1714 
   1715 	    if (cache->nodesetObjs)
   1716 		leftObjs -= cache->nodesetObjs->number;
   1717 	    if (cache->stringObjs)
   1718 		leftObjs -= cache->stringObjs->number;
   1719 	    if (cache->booleanObjs)
   1720 		leftObjs -= cache->booleanObjs->number;
   1721 	    if (cache->numberObjs)
   1722 		leftObjs -= cache->numberObjs->number;
   1723 	    if (cache->miscObjs)
   1724 		leftObjs -= cache->miscObjs->number;
   1725 	}
   1726     }
   1727 
   1728     printf("# all\n");
   1729     printf("#   total  : %d\n", reqAll);
   1730     printf("#   left  : %d\n", leftObjs);
   1731     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   1732     printf("#   reused : %d\n", reAll);
   1733     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   1734 
   1735     printf("# node-sets\n");
   1736     printf("#   total  : %d\n", reqNodeset);
   1737     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   1738     printf("#   reused : %d\n", reNodeset);
   1739     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   1740 
   1741     printf("# strings\n");
   1742     printf("#   total  : %d\n", reqString);
   1743     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   1744     printf("#   reused : %d\n", reString);
   1745     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   1746 
   1747     printf("# booleans\n");
   1748     printf("#   total  : %d\n", reqBool);
   1749     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   1750     printf("#   reused : %d\n", reBool);
   1751     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   1752 
   1753     printf("# numbers\n");
   1754     printf("#   total  : %d\n", reqNumber);
   1755     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   1756     printf("#   reused : %d\n", reNumber);
   1757     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   1758 
   1759     printf("# XSLT result tree fragments\n");
   1760     printf("#   total  : %d\n", reqXSLTTree);
   1761     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   1762     printf("#   reused : %d\n", reXSLTTree);
   1763     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   1764 
   1765     printf("# undefined\n");
   1766     printf("#   total  : %d\n", reqUndefined);
   1767     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   1768     printf("#   reused : %d\n", reUndefined);
   1769     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   1770 
   1771 }
   1772 
   1773 #endif /* XP_DEBUG_OBJ_USAGE */
   1774 
   1775 #endif /* LIBXML_DEBUG_ENABLED */
   1776 
   1777 /************************************************************************
   1778  *									*
   1779  *			XPath object caching				*
   1780  *									*
   1781  ************************************************************************/
   1782 
   1783 /**
   1784  * xmlXPathNewCache:
   1785  *
   1786  * Create a new object cache
   1787  *
   1788  * Returns the xmlXPathCache just allocated.
   1789  */
   1790 static xmlXPathContextCachePtr
   1791 xmlXPathNewCache(void)
   1792 {
   1793     xmlXPathContextCachePtr ret;
   1794 
   1795     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   1796     if (ret == NULL) {
   1797         xmlXPathErrMemory(NULL, "creating object cache\n");
   1798 	return(NULL);
   1799     }
   1800     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   1801     ret->maxNodeset = 100;
   1802     ret->maxString = 100;
   1803     ret->maxBoolean = 100;
   1804     ret->maxNumber = 100;
   1805     ret->maxMisc = 100;
   1806     return(ret);
   1807 }
   1808 
   1809 static void
   1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   1811 {
   1812     int i;
   1813     xmlXPathObjectPtr obj;
   1814 
   1815     if (list == NULL)
   1816 	return;
   1817 
   1818     for (i = 0; i < list->number; i++) {
   1819 	obj = list->items[i];
   1820 	/*
   1821 	* Note that it is already assured that we don't need to
   1822 	* look out for namespace nodes in the node-set.
   1823 	*/
   1824 	if (obj->nodesetval != NULL) {
   1825 	    if (obj->nodesetval->nodeTab != NULL)
   1826 		xmlFree(obj->nodesetval->nodeTab);
   1827 	    xmlFree(obj->nodesetval);
   1828 	}
   1829 	xmlFree(obj);
   1830 #ifdef XP_DEBUG_OBJ_USAGE
   1831 	xmlXPathDebugObjCounterAll--;
   1832 #endif
   1833     }
   1834     xmlPointerListFree(list);
   1835 }
   1836 
   1837 static void
   1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   1839 {
   1840     if (cache == NULL)
   1841 	return;
   1842     if (cache->nodesetObjs)
   1843 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   1844     if (cache->stringObjs)
   1845 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   1846     if (cache->booleanObjs)
   1847 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   1848     if (cache->numberObjs)
   1849 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   1850     if (cache->miscObjs)
   1851 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   1852     xmlFree(cache);
   1853 }
   1854 
   1855 /**
   1856  * xmlXPathContextSetCache:
   1857  *
   1858  * @ctxt:  the XPath context
   1859  * @active: enables/disables (creates/frees) the cache
   1860  * @value: a value with semantics dependant on @options
   1861  * @options: options (currently only the value 0 is used)
   1862  *
   1863  * Creates/frees an object cache on the XPath context.
   1864  * If activates XPath objects (xmlXPathObject) will be cached internally
   1865  * to be reused.
   1866  * @options:
   1867  *   0: This will set the XPath object caching:
   1868  *      @value:
   1869  *        This will set the maximum number of XPath objects
   1870  *        to be cached per slot
   1871  *        There are 5 slots for: node-set, string, number, boolean, and
   1872  *        misc objects. Use <0 for the default number (100).
   1873  *   Other values for @options have currently no effect.
   1874  *
   1875  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   1876  */
   1877 int
   1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   1879 			int active,
   1880 			int value,
   1881 			int options)
   1882 {
   1883     if (ctxt == NULL)
   1884 	return(-1);
   1885     if (active) {
   1886 	xmlXPathContextCachePtr cache;
   1887 
   1888 	if (ctxt->cache == NULL) {
   1889 	    ctxt->cache = xmlXPathNewCache();
   1890 	    if (ctxt->cache == NULL)
   1891 		return(-1);
   1892 	}
   1893 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   1894 	if (options == 0) {
   1895 	    if (value < 0)
   1896 		value = 100;
   1897 	    cache->maxNodeset = value;
   1898 	    cache->maxString = value;
   1899 	    cache->maxNumber = value;
   1900 	    cache->maxBoolean = value;
   1901 	    cache->maxMisc = value;
   1902 	}
   1903     } else if (ctxt->cache != NULL) {
   1904 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   1905 	ctxt->cache = NULL;
   1906     }
   1907     return(0);
   1908 }
   1909 
   1910 /**
   1911  * xmlXPathCacheWrapNodeSet:
   1912  * @ctxt: the XPath context
   1913  * @val:  the NodePtr value
   1914  *
   1915  * This is the cached version of xmlXPathWrapNodeSet().
   1916  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   1917  *
   1918  * Returns the created or reused object.
   1919  */
   1920 static xmlXPathObjectPtr
   1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   1922 {
   1923     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1924 	xmlXPathContextCachePtr cache =
   1925 	    (xmlXPathContextCachePtr) ctxt->cache;
   1926 
   1927 	if ((cache->miscObjs != NULL) &&
   1928 	    (cache->miscObjs->number != 0))
   1929 	{
   1930 	    xmlXPathObjectPtr ret;
   1931 
   1932 	    ret = (xmlXPathObjectPtr)
   1933 		cache->miscObjs->items[--cache->miscObjs->number];
   1934 	    ret->type = XPATH_NODESET;
   1935 	    ret->nodesetval = val;
   1936 #ifdef XP_DEBUG_OBJ_USAGE
   1937 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   1938 #endif
   1939 	    return(ret);
   1940 	}
   1941     }
   1942 
   1943     return(xmlXPathWrapNodeSet(val));
   1944 
   1945 }
   1946 
   1947 /**
   1948  * xmlXPathCacheWrapString:
   1949  * @ctxt: the XPath context
   1950  * @val:  the xmlChar * value
   1951  *
   1952  * This is the cached version of xmlXPathWrapString().
   1953  * Wraps the @val string into an XPath object.
   1954  *
   1955  * Returns the created or reused object.
   1956  */
   1957 static xmlXPathObjectPtr
   1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   1959 {
   1960     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1961 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   1962 
   1963 	if ((cache->stringObjs != NULL) &&
   1964 	    (cache->stringObjs->number != 0))
   1965 	{
   1966 
   1967 	    xmlXPathObjectPtr ret;
   1968 
   1969 	    ret = (xmlXPathObjectPtr)
   1970 		cache->stringObjs->items[--cache->stringObjs->number];
   1971 	    ret->type = XPATH_STRING;
   1972 	    ret->stringval = val;
   1973 #ifdef XP_DEBUG_OBJ_USAGE
   1974 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1975 #endif
   1976 	    return(ret);
   1977 	} else if ((cache->miscObjs != NULL) &&
   1978 	    (cache->miscObjs->number != 0))
   1979 	{
   1980 	    xmlXPathObjectPtr ret;
   1981 	    /*
   1982 	    * Fallback to misc-cache.
   1983 	    */
   1984 	    ret = (xmlXPathObjectPtr)
   1985 		cache->miscObjs->items[--cache->miscObjs->number];
   1986 
   1987 	    ret->type = XPATH_STRING;
   1988 	    ret->stringval = val;
   1989 #ifdef XP_DEBUG_OBJ_USAGE
   1990 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1991 #endif
   1992 	    return(ret);
   1993 	}
   1994     }
   1995     return(xmlXPathWrapString(val));
   1996 }
   1997 
   1998 /**
   1999  * xmlXPathCacheNewNodeSet:
   2000  * @ctxt: the XPath context
   2001  * @val:  the NodePtr value
   2002  *
   2003  * This is the cached version of xmlXPathNewNodeSet().
   2004  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2005  * it with the single Node @val
   2006  *
   2007  * Returns the created or reused object.
   2008  */
   2009 static xmlXPathObjectPtr
   2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2011 {
   2012     if ((ctxt != NULL) && (ctxt->cache)) {
   2013 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2014 
   2015 	if ((cache->nodesetObjs != NULL) &&
   2016 	    (cache->nodesetObjs->number != 0))
   2017 	{
   2018 	    xmlXPathObjectPtr ret;
   2019 	    /*
   2020 	    * Use the nodset-cache.
   2021 	    */
   2022 	    ret = (xmlXPathObjectPtr)
   2023 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2024 	    ret->type = XPATH_NODESET;
   2025 	    ret->boolval = 0;
   2026 	    if (val) {
   2027 		if ((ret->nodesetval->nodeMax == 0) ||
   2028 		    (val->type == XML_NAMESPACE_DECL))
   2029 		{
   2030 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2031 		} else {
   2032 		    ret->nodesetval->nodeTab[0] = val;
   2033 		    ret->nodesetval->nodeNr = 1;
   2034 		}
   2035 	    }
   2036 #ifdef XP_DEBUG_OBJ_USAGE
   2037 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2038 #endif
   2039 	    return(ret);
   2040 	} else if ((cache->miscObjs != NULL) &&
   2041 	    (cache->miscObjs->number != 0))
   2042 	{
   2043 	    xmlXPathObjectPtr ret;
   2044 	    /*
   2045 	    * Fallback to misc-cache.
   2046 	    */
   2047 
   2048 	    ret = (xmlXPathObjectPtr)
   2049 		cache->miscObjs->items[--cache->miscObjs->number];
   2050 
   2051 	    ret->type = XPATH_NODESET;
   2052 	    ret->boolval = 0;
   2053 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2054 #ifdef XP_DEBUG_OBJ_USAGE
   2055 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2056 #endif
   2057 	    return(ret);
   2058 	}
   2059     }
   2060     return(xmlXPathNewNodeSet(val));
   2061 }
   2062 
   2063 /**
   2064  * xmlXPathCacheNewCString:
   2065  * @ctxt: the XPath context
   2066  * @val:  the char * value
   2067  *
   2068  * This is the cached version of xmlXPathNewCString().
   2069  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2070  *
   2071  * Returns the created or reused object.
   2072  */
   2073 static xmlXPathObjectPtr
   2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2075 {
   2076     if ((ctxt != NULL) && (ctxt->cache)) {
   2077 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2078 
   2079 	if ((cache->stringObjs != NULL) &&
   2080 	    (cache->stringObjs->number != 0))
   2081 	{
   2082 	    xmlXPathObjectPtr ret;
   2083 
   2084 	    ret = (xmlXPathObjectPtr)
   2085 		cache->stringObjs->items[--cache->stringObjs->number];
   2086 
   2087 	    ret->type = XPATH_STRING;
   2088 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2089 #ifdef XP_DEBUG_OBJ_USAGE
   2090 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2091 #endif
   2092 	    return(ret);
   2093 	} else if ((cache->miscObjs != NULL) &&
   2094 	    (cache->miscObjs->number != 0))
   2095 	{
   2096 	    xmlXPathObjectPtr ret;
   2097 
   2098 	    ret = (xmlXPathObjectPtr)
   2099 		cache->miscObjs->items[--cache->miscObjs->number];
   2100 
   2101 	    ret->type = XPATH_STRING;
   2102 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2103 #ifdef XP_DEBUG_OBJ_USAGE
   2104 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2105 #endif
   2106 	    return(ret);
   2107 	}
   2108     }
   2109     return(xmlXPathNewCString(val));
   2110 }
   2111 
   2112 /**
   2113  * xmlXPathCacheNewString:
   2114  * @ctxt: the XPath context
   2115  * @val:  the xmlChar * value
   2116  *
   2117  * This is the cached version of xmlXPathNewString().
   2118  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2119  *
   2120  * Returns the created or reused object.
   2121  */
   2122 static xmlXPathObjectPtr
   2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2124 {
   2125     if ((ctxt != NULL) && (ctxt->cache)) {
   2126 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2127 
   2128 	if ((cache->stringObjs != NULL) &&
   2129 	    (cache->stringObjs->number != 0))
   2130 	{
   2131 	    xmlXPathObjectPtr ret;
   2132 
   2133 	    ret = (xmlXPathObjectPtr)
   2134 		cache->stringObjs->items[--cache->stringObjs->number];
   2135 	    ret->type = XPATH_STRING;
   2136 	    if (val != NULL)
   2137 		ret->stringval = xmlStrdup(val);
   2138 	    else
   2139 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2140 #ifdef XP_DEBUG_OBJ_USAGE
   2141 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2142 #endif
   2143 	    return(ret);
   2144 	} else if ((cache->miscObjs != NULL) &&
   2145 	    (cache->miscObjs->number != 0))
   2146 	{
   2147 	    xmlXPathObjectPtr ret;
   2148 
   2149 	    ret = (xmlXPathObjectPtr)
   2150 		cache->miscObjs->items[--cache->miscObjs->number];
   2151 
   2152 	    ret->type = XPATH_STRING;
   2153 	    if (val != NULL)
   2154 		ret->stringval = xmlStrdup(val);
   2155 	    else
   2156 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2157 #ifdef XP_DEBUG_OBJ_USAGE
   2158 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2159 #endif
   2160 	    return(ret);
   2161 	}
   2162     }
   2163     return(xmlXPathNewString(val));
   2164 }
   2165 
   2166 /**
   2167  * xmlXPathCacheNewBoolean:
   2168  * @ctxt: the XPath context
   2169  * @val:  the boolean value
   2170  *
   2171  * This is the cached version of xmlXPathNewBoolean().
   2172  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2173  *
   2174  * Returns the created or reused object.
   2175  */
   2176 static xmlXPathObjectPtr
   2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2178 {
   2179     if ((ctxt != NULL) && (ctxt->cache)) {
   2180 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2181 
   2182 	if ((cache->booleanObjs != NULL) &&
   2183 	    (cache->booleanObjs->number != 0))
   2184 	{
   2185 	    xmlXPathObjectPtr ret;
   2186 
   2187 	    ret = (xmlXPathObjectPtr)
   2188 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2189 	    ret->type = XPATH_BOOLEAN;
   2190 	    ret->boolval = (val != 0);
   2191 #ifdef XP_DEBUG_OBJ_USAGE
   2192 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2193 #endif
   2194 	    return(ret);
   2195 	} else if ((cache->miscObjs != NULL) &&
   2196 	    (cache->miscObjs->number != 0))
   2197 	{
   2198 	    xmlXPathObjectPtr ret;
   2199 
   2200 	    ret = (xmlXPathObjectPtr)
   2201 		cache->miscObjs->items[--cache->miscObjs->number];
   2202 
   2203 	    ret->type = XPATH_BOOLEAN;
   2204 	    ret->boolval = (val != 0);
   2205 #ifdef XP_DEBUG_OBJ_USAGE
   2206 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2207 #endif
   2208 	    return(ret);
   2209 	}
   2210     }
   2211     return(xmlXPathNewBoolean(val));
   2212 }
   2213 
   2214 /**
   2215  * xmlXPathCacheNewFloat:
   2216  * @ctxt: the XPath context
   2217  * @val:  the double value
   2218  *
   2219  * This is the cached version of xmlXPathNewFloat().
   2220  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2221  *
   2222  * Returns the created or reused object.
   2223  */
   2224 static xmlXPathObjectPtr
   2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2226 {
   2227      if ((ctxt != NULL) && (ctxt->cache)) {
   2228 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2229 
   2230 	if ((cache->numberObjs != NULL) &&
   2231 	    (cache->numberObjs->number != 0))
   2232 	{
   2233 	    xmlXPathObjectPtr ret;
   2234 
   2235 	    ret = (xmlXPathObjectPtr)
   2236 		cache->numberObjs->items[--cache->numberObjs->number];
   2237 	    ret->type = XPATH_NUMBER;
   2238 	    ret->floatval = val;
   2239 #ifdef XP_DEBUG_OBJ_USAGE
   2240 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2241 #endif
   2242 	    return(ret);
   2243 	} else if ((cache->miscObjs != NULL) &&
   2244 	    (cache->miscObjs->number != 0))
   2245 	{
   2246 	    xmlXPathObjectPtr ret;
   2247 
   2248 	    ret = (xmlXPathObjectPtr)
   2249 		cache->miscObjs->items[--cache->miscObjs->number];
   2250 
   2251 	    ret->type = XPATH_NUMBER;
   2252 	    ret->floatval = val;
   2253 #ifdef XP_DEBUG_OBJ_USAGE
   2254 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2255 #endif
   2256 	    return(ret);
   2257 	}
   2258     }
   2259     return(xmlXPathNewFloat(val));
   2260 }
   2261 
   2262 /**
   2263  * xmlXPathCacheConvertString:
   2264  * @ctxt: the XPath context
   2265  * @val:  an XPath object
   2266  *
   2267  * This is the cached version of xmlXPathConvertString().
   2268  * Converts an existing object to its string() equivalent
   2269  *
   2270  * Returns a created or reused object, the old one is freed (cached)
   2271  *         (or the operation is done directly on @val)
   2272  */
   2273 
   2274 static xmlXPathObjectPtr
   2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2276     xmlChar *res = NULL;
   2277 
   2278     if (val == NULL)
   2279 	return(xmlXPathCacheNewCString(ctxt, ""));
   2280 
   2281     switch (val->type) {
   2282     case XPATH_UNDEFINED:
   2283 #ifdef DEBUG_EXPR
   2284 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2285 #endif
   2286 	break;
   2287     case XPATH_NODESET:
   2288     case XPATH_XSLT_TREE:
   2289 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2290 	break;
   2291     case XPATH_STRING:
   2292 	return(val);
   2293     case XPATH_BOOLEAN:
   2294 	res = xmlXPathCastBooleanToString(val->boolval);
   2295 	break;
   2296     case XPATH_NUMBER:
   2297 	res = xmlXPathCastNumberToString(val->floatval);
   2298 	break;
   2299     case XPATH_USERS:
   2300     case XPATH_POINT:
   2301     case XPATH_RANGE:
   2302     case XPATH_LOCATIONSET:
   2303 	TODO;
   2304 	break;
   2305     }
   2306     xmlXPathReleaseObject(ctxt, val);
   2307     if (res == NULL)
   2308 	return(xmlXPathCacheNewCString(ctxt, ""));
   2309     return(xmlXPathCacheWrapString(ctxt, res));
   2310 }
   2311 
   2312 /**
   2313  * xmlXPathCacheObjectCopy:
   2314  * @ctxt: the XPath context
   2315  * @val:  the original object
   2316  *
   2317  * This is the cached version of xmlXPathObjectCopy().
   2318  * Acquire a copy of a given object
   2319  *
   2320  * Returns a created or reused created object.
   2321  */
   2322 static xmlXPathObjectPtr
   2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2324 {
   2325     if (val == NULL)
   2326 	return(NULL);
   2327 
   2328     if (XP_HAS_CACHE(ctxt)) {
   2329 	switch (val->type) {
   2330 	    case XPATH_NODESET:
   2331 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2332 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2333 	    case XPATH_STRING:
   2334 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2335 	    case XPATH_BOOLEAN:
   2336 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2337 	    case XPATH_NUMBER:
   2338 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2339 	    default:
   2340 		break;
   2341 	}
   2342     }
   2343     return(xmlXPathObjectCopy(val));
   2344 }
   2345 
   2346 /**
   2347  * xmlXPathCacheConvertBoolean:
   2348  * @ctxt: the XPath context
   2349  * @val:  an XPath object
   2350  *
   2351  * This is the cached version of xmlXPathConvertBoolean().
   2352  * Converts an existing object to its boolean() equivalent
   2353  *
   2354  * Returns a created or reused object, the old one is freed (or the operation
   2355  *         is done directly on @val)
   2356  */
   2357 static xmlXPathObjectPtr
   2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2359     xmlXPathObjectPtr ret;
   2360 
   2361     if (val == NULL)
   2362 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2363     if (val->type == XPATH_BOOLEAN)
   2364 	return(val);
   2365     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2366     xmlXPathReleaseObject(ctxt, val);
   2367     return(ret);
   2368 }
   2369 
   2370 /**
   2371  * xmlXPathCacheConvertNumber:
   2372  * @ctxt: the XPath context
   2373  * @val:  an XPath object
   2374  *
   2375  * This is the cached version of xmlXPathConvertNumber().
   2376  * Converts an existing object to its number() equivalent
   2377  *
   2378  * Returns a created or reused object, the old one is freed (or the operation
   2379  *         is done directly on @val)
   2380  */
   2381 static xmlXPathObjectPtr
   2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2383     xmlXPathObjectPtr ret;
   2384 
   2385     if (val == NULL)
   2386 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2387     if (val->type == XPATH_NUMBER)
   2388 	return(val);
   2389     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2390     xmlXPathReleaseObject(ctxt, val);
   2391     return(ret);
   2392 }
   2393 
   2394 /************************************************************************
   2395  *									*
   2396  *		Parser stacks related functions and macros		*
   2397  *									*
   2398  ************************************************************************/
   2399 
   2400 /**
   2401  * valuePop:
   2402  * @ctxt: an XPath evaluation context
   2403  *
   2404  * Pops the top XPath object from the value stack
   2405  *
   2406  * Returns the XPath object just removed
   2407  */
   2408 xmlXPathObjectPtr
   2409 valuePop(xmlXPathParserContextPtr ctxt)
   2410 {
   2411     xmlXPathObjectPtr ret;
   2412 
   2413     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2414         return (NULL);
   2415     ctxt->valueNr--;
   2416     if (ctxt->valueNr > 0)
   2417         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2418     else
   2419         ctxt->value = NULL;
   2420     ret = ctxt->valueTab[ctxt->valueNr];
   2421     ctxt->valueTab[ctxt->valueNr] = NULL;
   2422     return (ret);
   2423 }
   2424 /**
   2425  * valuePush:
   2426  * @ctxt:  an XPath evaluation context
   2427  * @value:  the XPath object
   2428  *
   2429  * Pushes a new XPath object on top of the value stack
   2430  *
   2431  * returns the number of items on the value stack
   2432  */
   2433 int
   2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2435 {
   2436     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2437     if (ctxt->valueNr >= ctxt->valueMax) {
   2438         xmlXPathObjectPtr *tmp;
   2439 
   2440         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2441                                              2 * ctxt->valueMax *
   2442                                              sizeof(ctxt->valueTab[0]));
   2443         if (tmp == NULL) {
   2444             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
   2445             return (0);
   2446         }
   2447         ctxt->valueMax *= 2;
   2448 	ctxt->valueTab = tmp;
   2449     }
   2450     ctxt->valueTab[ctxt->valueNr] = value;
   2451     ctxt->value = value;
   2452     return (ctxt->valueNr++);
   2453 }
   2454 
   2455 /**
   2456  * xmlXPathPopBoolean:
   2457  * @ctxt:  an XPath parser context
   2458  *
   2459  * Pops a boolean from the stack, handling conversion if needed.
   2460  * Check error with #xmlXPathCheckError.
   2461  *
   2462  * Returns the boolean
   2463  */
   2464 int
   2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2466     xmlXPathObjectPtr obj;
   2467     int ret;
   2468 
   2469     obj = valuePop(ctxt);
   2470     if (obj == NULL) {
   2471 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2472 	return(0);
   2473     }
   2474     if (obj->type != XPATH_BOOLEAN)
   2475 	ret = xmlXPathCastToBoolean(obj);
   2476     else
   2477         ret = obj->boolval;
   2478     xmlXPathReleaseObject(ctxt->context, obj);
   2479     return(ret);
   2480 }
   2481 
   2482 /**
   2483  * xmlXPathPopNumber:
   2484  * @ctxt:  an XPath parser context
   2485  *
   2486  * Pops a number from the stack, handling conversion if needed.
   2487  * Check error with #xmlXPathCheckError.
   2488  *
   2489  * Returns the number
   2490  */
   2491 double
   2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2493     xmlXPathObjectPtr obj;
   2494     double ret;
   2495 
   2496     obj = valuePop(ctxt);
   2497     if (obj == NULL) {
   2498 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2499 	return(0);
   2500     }
   2501     if (obj->type != XPATH_NUMBER)
   2502 	ret = xmlXPathCastToNumber(obj);
   2503     else
   2504         ret = obj->floatval;
   2505     xmlXPathReleaseObject(ctxt->context, obj);
   2506     return(ret);
   2507 }
   2508 
   2509 /**
   2510  * xmlXPathPopString:
   2511  * @ctxt:  an XPath parser context
   2512  *
   2513  * Pops a string from the stack, handling conversion if needed.
   2514  * Check error with #xmlXPathCheckError.
   2515  *
   2516  * Returns the string
   2517  */
   2518 xmlChar *
   2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2520     xmlXPathObjectPtr obj;
   2521     xmlChar * ret;
   2522 
   2523     obj = valuePop(ctxt);
   2524     if (obj == NULL) {
   2525 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2526 	return(NULL);
   2527     }
   2528     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2529     /* TODO: needs refactoring somewhere else */
   2530     if (obj->stringval == ret)
   2531 	obj->stringval = NULL;
   2532     xmlXPathReleaseObject(ctxt->context, obj);
   2533     return(ret);
   2534 }
   2535 
   2536 /**
   2537  * xmlXPathPopNodeSet:
   2538  * @ctxt:  an XPath parser context
   2539  *
   2540  * Pops a node-set from the stack, handling conversion if needed.
   2541  * Check error with #xmlXPathCheckError.
   2542  *
   2543  * Returns the node-set
   2544  */
   2545 xmlNodeSetPtr
   2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2547     xmlXPathObjectPtr obj;
   2548     xmlNodeSetPtr ret;
   2549 
   2550     if (ctxt == NULL) return(NULL);
   2551     if (ctxt->value == NULL) {
   2552 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2553 	return(NULL);
   2554     }
   2555     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2556 	xmlXPathSetTypeError(ctxt);
   2557 	return(NULL);
   2558     }
   2559     obj = valuePop(ctxt);
   2560     ret = obj->nodesetval;
   2561 #if 0
   2562     /* to fix memory leak of not clearing obj->user */
   2563     if (obj->boolval && obj->user != NULL)
   2564         xmlFreeNodeList((xmlNodePtr) obj->user);
   2565 #endif
   2566     obj->nodesetval = NULL;
   2567     xmlXPathReleaseObject(ctxt->context, obj);
   2568     return(ret);
   2569 }
   2570 
   2571 /**
   2572  * xmlXPathPopExternal:
   2573  * @ctxt:  an XPath parser context
   2574  *
   2575  * Pops an external object from the stack, handling conversion if needed.
   2576  * Check error with #xmlXPathCheckError.
   2577  *
   2578  * Returns the object
   2579  */
   2580 void *
   2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   2582     xmlXPathObjectPtr obj;
   2583     void * ret;
   2584 
   2585     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   2586 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2587 	return(NULL);
   2588     }
   2589     if (ctxt->value->type != XPATH_USERS) {
   2590 	xmlXPathSetTypeError(ctxt);
   2591 	return(NULL);
   2592     }
   2593     obj = valuePop(ctxt);
   2594     ret = obj->user;
   2595     obj->user = NULL;
   2596     xmlXPathReleaseObject(ctxt->context, obj);
   2597     return(ret);
   2598 }
   2599 
   2600 /*
   2601  * Macros for accessing the content. Those should be used only by the parser,
   2602  * and not exported.
   2603  *
   2604  * Dirty macros, i.e. one need to make assumption on the context to use them
   2605  *
   2606  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   2607  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   2608  *           in ISO-Latin or UTF-8.
   2609  *           This should be used internally by the parser
   2610  *           only to compare to ASCII values otherwise it would break when
   2611  *           running with UTF-8 encoding.
   2612  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   2613  *           to compare on ASCII based substring.
   2614  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   2615  *           strings within the parser.
   2616  *   CURRENT Returns the current char value, with the full decoding of
   2617  *           UTF-8 if we are using this mode. It returns an int.
   2618  *   NEXT    Skip to the next character, this does the proper decoding
   2619  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   2620  *           It returns the pointer to the current xmlChar.
   2621  */
   2622 
   2623 #define CUR (*ctxt->cur)
   2624 #define SKIP(val) ctxt->cur += (val)
   2625 #define NXT(val) ctxt->cur[(val)]
   2626 #define CUR_PTR ctxt->cur
   2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   2628 
   2629 #define COPY_BUF(l,b,i,v)                                              \
   2630     if (l == 1) b[i++] = (xmlChar) v;                                  \
   2631     else i += xmlCopyChar(l,&b[i],v)
   2632 
   2633 #define NEXTL(l)  ctxt->cur += l
   2634 
   2635 #define SKIP_BLANKS							\
   2636     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   2637 
   2638 #define CURRENT (*ctxt->cur)
   2639 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   2640 
   2641 
   2642 #ifndef DBL_DIG
   2643 #define DBL_DIG 16
   2644 #endif
   2645 #ifndef DBL_EPSILON
   2646 #define DBL_EPSILON 1E-9
   2647 #endif
   2648 
   2649 #define UPPER_DOUBLE 1E9
   2650 #define LOWER_DOUBLE 1E-5
   2651 #define	LOWER_DOUBLE_EXP 5
   2652 
   2653 #define INTEGER_DIGITS DBL_DIG
   2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   2655 #define EXPONENT_DIGITS (3 + 2)
   2656 
   2657 /**
   2658  * xmlXPathFormatNumber:
   2659  * @number:     number to format
   2660  * @buffer:     output buffer
   2661  * @buffersize: size of output buffer
   2662  *
   2663  * Convert the number into a string representation.
   2664  */
   2665 static void
   2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   2667 {
   2668     switch (xmlXPathIsInf(number)) {
   2669     case 1:
   2670 	if (buffersize > (int)sizeof("Infinity"))
   2671 	    snprintf(buffer, buffersize, "Infinity");
   2672 	break;
   2673     case -1:
   2674 	if (buffersize > (int)sizeof("-Infinity"))
   2675 	    snprintf(buffer, buffersize, "-Infinity");
   2676 	break;
   2677     default:
   2678 	if (xmlXPathIsNaN(number)) {
   2679 	    if (buffersize > (int)sizeof("NaN"))
   2680 		snprintf(buffer, buffersize, "NaN");
   2681 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   2682 	    snprintf(buffer, buffersize, "0");
   2683 	} else if (number == ((int) number)) {
   2684 	    char work[30];
   2685 	    char *ptr, *cur;
   2686 	    int value = (int) number;
   2687 
   2688             ptr = &buffer[0];
   2689 	    if (value == 0) {
   2690 		*ptr++ = '0';
   2691 	    } else {
   2692 		snprintf(work, 29, "%d", value);
   2693 		cur = &work[0];
   2694 		while ((*cur) && (ptr - buffer < buffersize)) {
   2695 		    *ptr++ = *cur++;
   2696 		}
   2697 	    }
   2698 	    if (ptr - buffer < buffersize) {
   2699 		*ptr = 0;
   2700 	    } else if (buffersize > 0) {
   2701 		ptr--;
   2702 		*ptr = 0;
   2703 	    }
   2704 	} else {
   2705 	    /*
   2706 	      For the dimension of work,
   2707 	          DBL_DIG is number of significant digits
   2708 		  EXPONENT is only needed for "scientific notation"
   2709 	          3 is sign, decimal point, and terminating zero
   2710 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   2711 	      Note that this dimension is slightly (a few characters)
   2712 	      larger than actually necessary.
   2713 	    */
   2714 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   2715 	    int integer_place, fraction_place;
   2716 	    char *ptr;
   2717 	    char *after_fraction;
   2718 	    double absolute_value;
   2719 	    int size;
   2720 
   2721 	    absolute_value = fabs(number);
   2722 
   2723 	    /*
   2724 	     * First choose format - scientific or regular floating point.
   2725 	     * In either case, result is in work, and after_fraction points
   2726 	     * just past the fractional part.
   2727 	    */
   2728 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   2729 		  (absolute_value < LOWER_DOUBLE)) &&
   2730 		 (absolute_value != 0.0) ) {
   2731 		/* Use scientific notation */
   2732 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   2733 		fraction_place = DBL_DIG - 1;
   2734 		size = snprintf(work, sizeof(work),"%*.*e",
   2735 			 integer_place, fraction_place, number);
   2736 		while ((size > 0) && (work[size] != 'e')) size--;
   2737 
   2738 	    }
   2739 	    else {
   2740 		/* Use regular notation */
   2741 		if (absolute_value > 0.0) {
   2742 		    integer_place = (int)log10(absolute_value);
   2743 		    if (integer_place > 0)
   2744 		        fraction_place = DBL_DIG - integer_place - 1;
   2745 		    else
   2746 		        fraction_place = DBL_DIG - integer_place;
   2747 		} else {
   2748 		    fraction_place = 1;
   2749 		}
   2750 		size = snprintf(work, sizeof(work), "%0.*f",
   2751 				fraction_place, number);
   2752 	    }
   2753 
   2754 	    /* Remove fractional trailing zeroes */
   2755 	    after_fraction = work + size;
   2756 	    ptr = after_fraction;
   2757 	    while (*(--ptr) == '0')
   2758 		;
   2759 	    if (*ptr != '.')
   2760 	        ptr++;
   2761 	    while ((*ptr++ = *after_fraction++) != 0);
   2762 
   2763 	    /* Finally copy result back to caller */
   2764 	    size = strlen(work) + 1;
   2765 	    if (size > buffersize) {
   2766 		work[buffersize - 1] = 0;
   2767 		size = buffersize;
   2768 	    }
   2769 	    memmove(buffer, work, size);
   2770 	}
   2771 	break;
   2772     }
   2773 }
   2774 
   2775 
   2776 /************************************************************************
   2777  *									*
   2778  *			Routines to handle NodeSets			*
   2779  *									*
   2780  ************************************************************************/
   2781 
   2782 /**
   2783  * xmlXPathOrderDocElems:
   2784  * @doc:  an input document
   2785  *
   2786  * Call this routine to speed up XPath computation on static documents.
   2787  * This stamps all the element nodes with the document order
   2788  * Like for line information, the order is kept in the element->content
   2789  * field, the value stored is actually - the node number (starting at -1)
   2790  * to be able to differentiate from line numbers.
   2791  *
   2792  * Returns the number of elements found in the document or -1 in case
   2793  *    of error.
   2794  */
   2795 long
   2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
   2797     long count = 0;
   2798     xmlNodePtr cur;
   2799 
   2800     if (doc == NULL)
   2801 	return(-1);
   2802     cur = doc->children;
   2803     while (cur != NULL) {
   2804 	if (cur->type == XML_ELEMENT_NODE) {
   2805 	    cur->content = (void *) (-(++count));
   2806 	    if (cur->children != NULL) {
   2807 		cur = cur->children;
   2808 		continue;
   2809 	    }
   2810 	}
   2811 	if (cur->next != NULL) {
   2812 	    cur = cur->next;
   2813 	    continue;
   2814 	}
   2815 	do {
   2816 	    cur = cur->parent;
   2817 	    if (cur == NULL)
   2818 		break;
   2819 	    if (cur == (xmlNodePtr) doc) {
   2820 		cur = NULL;
   2821 		break;
   2822 	    }
   2823 	    if (cur->next != NULL) {
   2824 		cur = cur->next;
   2825 		break;
   2826 	    }
   2827 	} while (cur != NULL);
   2828     }
   2829     return(count);
   2830 }
   2831 
   2832 /**
   2833  * xmlXPathCmpNodes:
   2834  * @node1:  the first node
   2835  * @node2:  the second node
   2836  *
   2837  * Compare two nodes w.r.t document order
   2838  *
   2839  * Returns -2 in case of error 1 if first point < second point, 0 if
   2840  *         it's the same node, -1 otherwise
   2841  */
   2842 int
   2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   2844     int depth1, depth2;
   2845     int attr1 = 0, attr2 = 0;
   2846     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   2847     xmlNodePtr cur, root;
   2848 
   2849     if ((node1 == NULL) || (node2 == NULL))
   2850 	return(-2);
   2851     /*
   2852      * a couple of optimizations which will avoid computations in most cases
   2853      */
   2854     if (node1 == node2)		/* trivial case */
   2855 	return(0);
   2856     if (node1->type == XML_ATTRIBUTE_NODE) {
   2857 	attr1 = 1;
   2858 	attrNode1 = node1;
   2859 	node1 = node1->parent;
   2860     }
   2861     if (node2->type == XML_ATTRIBUTE_NODE) {
   2862 	attr2 = 1;
   2863 	attrNode2 = node2;
   2864 	node2 = node2->parent;
   2865     }
   2866     if (node1 == node2) {
   2867 	if (attr1 == attr2) {
   2868 	    /* not required, but we keep attributes in order */
   2869 	    if (attr1 != 0) {
   2870 	        cur = attrNode2->prev;
   2871 		while (cur != NULL) {
   2872 		    if (cur == attrNode1)
   2873 		        return (1);
   2874 		    cur = cur->prev;
   2875 		}
   2876 		return (-1);
   2877 	    }
   2878 	    return(0);
   2879 	}
   2880 	if (attr2 == 1)
   2881 	    return(1);
   2882 	return(-1);
   2883     }
   2884     if ((node1->type == XML_NAMESPACE_DECL) ||
   2885         (node2->type == XML_NAMESPACE_DECL))
   2886 	return(1);
   2887     if (node1 == node2->prev)
   2888 	return(1);
   2889     if (node1 == node2->next)
   2890 	return(-1);
   2891 
   2892     /*
   2893      * Speedup using document order if availble.
   2894      */
   2895     if ((node1->type == XML_ELEMENT_NODE) &&
   2896 	(node2->type == XML_ELEMENT_NODE) &&
   2897 	(0 > (long) node1->content) &&
   2898 	(0 > (long) node2->content) &&
   2899 	(node1->doc == node2->doc)) {
   2900 	long l1, l2;
   2901 
   2902 	l1 = -((long) node1->content);
   2903 	l2 = -((long) node2->content);
   2904 	if (l1 < l2)
   2905 	    return(1);
   2906 	if (l1 > l2)
   2907 	    return(-1);
   2908     }
   2909 
   2910     /*
   2911      * compute depth to root
   2912      */
   2913     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   2914 	if (cur == node1)
   2915 	    return(1);
   2916 	depth2++;
   2917     }
   2918     root = cur;
   2919     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   2920 	if (cur == node2)
   2921 	    return(-1);
   2922 	depth1++;
   2923     }
   2924     /*
   2925      * Distinct document (or distinct entities :-( ) case.
   2926      */
   2927     if (root != cur) {
   2928 	return(-2);
   2929     }
   2930     /*
   2931      * get the nearest common ancestor.
   2932      */
   2933     while (depth1 > depth2) {
   2934 	depth1--;
   2935 	node1 = node1->parent;
   2936     }
   2937     while (depth2 > depth1) {
   2938 	depth2--;
   2939 	node2 = node2->parent;
   2940     }
   2941     while (node1->parent != node2->parent) {
   2942 	node1 = node1->parent;
   2943 	node2 = node2->parent;
   2944 	/* should not happen but just in case ... */
   2945 	if ((node1 == NULL) || (node2 == NULL))
   2946 	    return(-2);
   2947     }
   2948     /*
   2949      * Find who's first.
   2950      */
   2951     if (node1 == node2->prev)
   2952 	return(1);
   2953     if (node1 == node2->next)
   2954 	return(-1);
   2955     /*
   2956      * Speedup using document order if availble.
   2957      */
   2958     if ((node1->type == XML_ELEMENT_NODE) &&
   2959 	(node2->type == XML_ELEMENT_NODE) &&
   2960 	(0 > (long) node1->content) &&
   2961 	(0 > (long) node2->content) &&
   2962 	(node1->doc == node2->doc)) {
   2963 	long l1, l2;
   2964 
   2965 	l1 = -((long) node1->content);
   2966 	l2 = -((long) node2->content);
   2967 	if (l1 < l2)
   2968 	    return(1);
   2969 	if (l1 > l2)
   2970 	    return(-1);
   2971     }
   2972 
   2973     for (cur = node1->next;cur != NULL;cur = cur->next)
   2974 	if (cur == node2)
   2975 	    return(1);
   2976     return(-1); /* assume there is no sibling list corruption */
   2977 }
   2978 
   2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   2980 /**
   2981  * xmlXPathCmpNodesExt:
   2982  * @node1:  the first node
   2983  * @node2:  the second node
   2984  *
   2985  * Compare two nodes w.r.t document order.
   2986  * This one is optimized for handling of non-element nodes.
   2987  *
   2988  * Returns -2 in case of error 1 if first point < second point, 0 if
   2989  *         it's the same node, -1 otherwise
   2990  */
   2991 static int
   2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
   2993     int depth1, depth2;
   2994     int misc = 0, precedence1 = 0, precedence2 = 0;
   2995     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
   2996     xmlNodePtr cur, root;
   2997     long l1, l2;
   2998 
   2999     if ((node1 == NULL) || (node2 == NULL))
   3000 	return(-2);
   3001 
   3002     if (node1 == node2)
   3003 	return(0);
   3004 
   3005     /*
   3006      * a couple of optimizations which will avoid computations in most cases
   3007      */
   3008     switch (node1->type) {
   3009 	case XML_ELEMENT_NODE:
   3010 	    if (node2->type == XML_ELEMENT_NODE) {
   3011 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
   3012 		    (0 > (long) node2->content) &&
   3013 		    (node1->doc == node2->doc))
   3014 		{
   3015 		    l1 = -((long) node1->content);
   3016 		    l2 = -((long) node2->content);
   3017 		    if (l1 < l2)
   3018 			return(1);
   3019 		    if (l1 > l2)
   3020 			return(-1);
   3021 		} else
   3022 		    goto turtle_comparison;
   3023 	    }
   3024 	    break;
   3025 	case XML_ATTRIBUTE_NODE:
   3026 	    precedence1 = 1; /* element is owner */
   3027 	    miscNode1 = node1;
   3028 	    node1 = node1->parent;
   3029 	    misc = 1;
   3030 	    break;
   3031 	case XML_TEXT_NODE:
   3032 	case XML_CDATA_SECTION_NODE:
   3033 	case XML_COMMENT_NODE:
   3034 	case XML_PI_NODE: {
   3035 	    miscNode1 = node1;
   3036 	    /*
   3037 	    * Find nearest element node.
   3038 	    */
   3039 	    if (node1->prev != NULL) {
   3040 		do {
   3041 		    node1 = node1->prev;
   3042 		    if (node1->type == XML_ELEMENT_NODE) {
   3043 			precedence1 = 3; /* element in prev-sibl axis */
   3044 			break;
   3045 		    }
   3046 		    if (node1->prev == NULL) {
   3047 			precedence1 = 2; /* element is parent */
   3048 			/*
   3049 			* URGENT TODO: Are there any cases, where the
   3050 			* parent of such a node is not an element node?
   3051 			*/
   3052 			node1 = node1->parent;
   3053 			break;
   3054 		    }
   3055 		} while (1);
   3056 	    } else {
   3057 		precedence1 = 2; /* element is parent */
   3058 		node1 = node1->parent;
   3059 	    }
   3060 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
   3061 		(0 <= (long) node1->content)) {
   3062 		/*
   3063 		* Fallback for whatever case.
   3064 		*/
   3065 		node1 = miscNode1;
   3066 		precedence1 = 0;
   3067 	    } else
   3068 		misc = 1;
   3069 	}
   3070 	    break;
   3071 	case XML_NAMESPACE_DECL:
   3072 	    /*
   3073 	    * TODO: why do we return 1 for namespace nodes?
   3074 	    */
   3075 	    return(1);
   3076 	default:
   3077 	    break;
   3078     }
   3079     switch (node2->type) {
   3080 	case XML_ELEMENT_NODE:
   3081 	    break;
   3082 	case XML_ATTRIBUTE_NODE:
   3083 	    precedence2 = 1; /* element is owner */
   3084 	    miscNode2 = node2;
   3085 	    node2 = node2->parent;
   3086 	    misc = 1;
   3087 	    break;
   3088 	case XML_TEXT_NODE:
   3089 	case XML_CDATA_SECTION_NODE:
   3090 	case XML_COMMENT_NODE:
   3091 	case XML_PI_NODE: {
   3092 	    miscNode2 = node2;
   3093 	    if (node2->prev != NULL) {
   3094 		do {
   3095 		    node2 = node2->prev;
   3096 		    if (node2->type == XML_ELEMENT_NODE) {
   3097 			precedence2 = 3; /* element in prev-sibl axis */
   3098 			break;
   3099 		    }
   3100 		    if (node2->prev == NULL) {
   3101 			precedence2 = 2; /* element is parent */
   3102 			node2 = node2->parent;
   3103 			break;
   3104 		    }
   3105 		} while (1);
   3106 	    } else {
   3107 		precedence2 = 2; /* element is parent */
   3108 		node2 = node2->parent;
   3109 	    }
   3110 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
   3111 		(0 <= (long) node1->content))
   3112 	    {
   3113 		node2 = miscNode2;
   3114 		precedence2 = 0;
   3115 	    } else
   3116 		misc = 1;
   3117 	}
   3118 	    break;
   3119 	case XML_NAMESPACE_DECL:
   3120 	    return(1);
   3121 	default:
   3122 	    break;
   3123     }
   3124     if (misc) {
   3125 	if (node1 == node2) {
   3126 	    if (precedence1 == precedence2) {
   3127 		/*
   3128 		* The ugly case; but normally there aren't many
   3129 		* adjacent non-element nodes around.
   3130 		*/
   3131 		cur = miscNode2->prev;
   3132 		while (cur != NULL) {
   3133 		    if (cur == miscNode1)
   3134 			return(1);
   3135 		    if (cur->type == XML_ELEMENT_NODE)
   3136 			return(-1);
   3137 		    cur = cur->prev;
   3138 		}
   3139 		return (-1);
   3140 	    } else {
   3141 		/*
   3142 		* Evaluate based on higher precedence wrt to the element.
   3143 		* TODO: This assumes attributes are sorted before content.
   3144 		*   Is this 100% correct?
   3145 		*/
   3146 		if (precedence1 < precedence2)
   3147 		    return(1);
   3148 		else
   3149 		    return(-1);
   3150 	    }
   3151 	}
   3152 	/*
   3153 	* Special case: One of the helper-elements is contained by the other.
   3154 	* <foo>
   3155 	*   <node2>
   3156 	*     <node1>Text-1(precedence1 == 2)</node1>
   3157 	*   </node2>
   3158 	*   Text-6(precedence2 == 3)
   3159 	* </foo>
   3160 	*/
   3161 	if ((precedence2 == 3) && (precedence1 > 1)) {
   3162 	    cur = node1->parent;
   3163 	    while (cur) {
   3164 		if (cur == node2)
   3165 		    return(1);
   3166 		cur = cur->parent;
   3167 	    }
   3168 	}
   3169 	if ((precedence1 == 3) && (precedence2 > 1)) {
   3170 	    cur = node2->parent;
   3171 	    while (cur) {
   3172 		if (cur == node1)
   3173 		    return(-1);
   3174 		cur = cur->parent;
   3175 	    }
   3176 	}
   3177     }
   3178 
   3179     /*
   3180      * Speedup using document order if availble.
   3181      */
   3182     if ((node1->type == XML_ELEMENT_NODE) &&
   3183 	(node2->type == XML_ELEMENT_NODE) &&
   3184 	(0 > (long) node1->content) &&
   3185 	(0 > (long) node2->content) &&
   3186 	(node1->doc == node2->doc)) {
   3187 
   3188 	l1 = -((long) node1->content);
   3189 	l2 = -((long) node2->content);
   3190 	if (l1 < l2)
   3191 	    return(1);
   3192 	if (l1 > l2)
   3193 	    return(-1);
   3194     }
   3195 
   3196 turtle_comparison:
   3197 
   3198     if (node1 == node2->prev)
   3199 	return(1);
   3200     if (node1 == node2->next)
   3201 	return(-1);
   3202     /*
   3203      * compute depth to root
   3204      */
   3205     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3206 	if (cur == node1)
   3207 	    return(1);
   3208 	depth2++;
   3209     }
   3210     root = cur;
   3211     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3212 	if (cur == node2)
   3213 	    return(-1);
   3214 	depth1++;
   3215     }
   3216     /*
   3217      * Distinct document (or distinct entities :-( ) case.
   3218      */
   3219     if (root != cur) {
   3220 	return(-2);
   3221     }
   3222     /*
   3223      * get the nearest common ancestor.
   3224      */
   3225     while (depth1 > depth2) {
   3226 	depth1--;
   3227 	node1 = node1->parent;
   3228     }
   3229     while (depth2 > depth1) {
   3230 	depth2--;
   3231 	node2 = node2->parent;
   3232     }
   3233     while (node1->parent != node2->parent) {
   3234 	node1 = node1->parent;
   3235 	node2 = node2->parent;
   3236 	/* should not happen but just in case ... */
   3237 	if ((node1 == NULL) || (node2 == NULL))
   3238 	    return(-2);
   3239     }
   3240     /*
   3241      * Find who's first.
   3242      */
   3243     if (node1 == node2->prev)
   3244 	return(1);
   3245     if (node1 == node2->next)
   3246 	return(-1);
   3247     /*
   3248      * Speedup using document order if availble.
   3249      */
   3250     if ((node1->type == XML_ELEMENT_NODE) &&
   3251 	(node2->type == XML_ELEMENT_NODE) &&
   3252 	(0 > (long) node1->content) &&
   3253 	(0 > (long) node2->content) &&
   3254 	(node1->doc == node2->doc)) {
   3255 
   3256 	l1 = -((long) node1->content);
   3257 	l2 = -((long) node2->content);
   3258 	if (l1 < l2)
   3259 	    return(1);
   3260 	if (l1 > l2)
   3261 	    return(-1);
   3262     }
   3263 
   3264     for (cur = node1->next;cur != NULL;cur = cur->next)
   3265 	if (cur == node2)
   3266 	    return(1);
   3267     return(-1); /* assume there is no sibling list corruption */
   3268 }
   3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
   3270 
   3271 /**
   3272  * xmlXPathNodeSetSort:
   3273  * @set:  the node set
   3274  *
   3275  * Sort the node set in document order
   3276  */
   3277 void
   3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3279     int i, j, incr, len;
   3280     xmlNodePtr tmp;
   3281 
   3282     if (set == NULL)
   3283 	return;
   3284 
   3285     /* Use Shell's sort to sort the node-set */
   3286     len = set->nodeNr;
   3287     for (incr = len / 2; incr > 0; incr /= 2) {
   3288 	for (i = incr; i < len; i++) {
   3289 	    j = i - incr;
   3290 	    while (j >= 0) {
   3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3292 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3293 			set->nodeTab[j + incr]) == -1)
   3294 #else
   3295 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3296 			set->nodeTab[j + incr]) == -1)
   3297 #endif
   3298 		{
   3299 		    tmp = set->nodeTab[j];
   3300 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3301 		    set->nodeTab[j + incr] = tmp;
   3302 		    j -= incr;
   3303 		} else
   3304 		    break;
   3305 	    }
   3306 	}
   3307     }
   3308 }
   3309 
   3310 #define XML_NODESET_DEFAULT	10
   3311 /**
   3312  * xmlXPathNodeSetDupNs:
   3313  * @node:  the parent node of the namespace XPath node
   3314  * @ns:  the libxml namespace declaration node.
   3315  *
   3316  * Namespace node in libxml don't match the XPath semantic. In a node set
   3317  * the namespace nodes are duplicated and the next pointer is set to the
   3318  * parent node in the XPath semantic.
   3319  *
   3320  * Returns the newly created object.
   3321  */
   3322 static xmlNodePtr
   3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3324     xmlNsPtr cur;
   3325 
   3326     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3327 	return(NULL);
   3328     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3329 	return((xmlNodePtr) ns);
   3330 
   3331     /*
   3332      * Allocate a new Namespace and fill the fields.
   3333      */
   3334     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3335     if (cur == NULL) {
   3336         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3337 	return(NULL);
   3338     }
   3339     memset(cur, 0, sizeof(xmlNs));
   3340     cur->type = XML_NAMESPACE_DECL;
   3341     if (ns->href != NULL)
   3342 	cur->href = xmlStrdup(ns->href);
   3343     if (ns->prefix != NULL)
   3344 	cur->prefix = xmlStrdup(ns->prefix);
   3345     cur->next = (xmlNsPtr) node;
   3346     return((xmlNodePtr) cur);
   3347 }
   3348 
   3349 /**
   3350  * xmlXPathNodeSetFreeNs:
   3351  * @ns:  the XPath namespace node found in a nodeset.
   3352  *
   3353  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3354  * the namespace nodes are duplicated and the next pointer is set to the
   3355  * parent node in the XPath semantic. Check if such a node needs to be freed
   3356  */
   3357 void
   3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3359     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3360 	return;
   3361 
   3362     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3363 	if (ns->href != NULL)
   3364 	    xmlFree((xmlChar *)ns->href);
   3365 	if (ns->prefix != NULL)
   3366 	    xmlFree((xmlChar *)ns->prefix);
   3367 	xmlFree(ns);
   3368     }
   3369 }
   3370 
   3371 /**
   3372  * xmlXPathNodeSetCreate:
   3373  * @val:  an initial xmlNodePtr, or NULL
   3374  *
   3375  * Create a new xmlNodeSetPtr of type double and of value @val
   3376  *
   3377  * Returns the newly created object.
   3378  */
   3379 xmlNodeSetPtr
   3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3381     xmlNodeSetPtr ret;
   3382 
   3383     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3384     if (ret == NULL) {
   3385         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3386 	return(NULL);
   3387     }
   3388     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3389     if (val != NULL) {
   3390         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3391 					     sizeof(xmlNodePtr));
   3392 	if (ret->nodeTab == NULL) {
   3393 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3394 	    xmlFree(ret);
   3395 	    return(NULL);
   3396 	}
   3397 	memset(ret->nodeTab, 0 ,
   3398 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3399         ret->nodeMax = XML_NODESET_DEFAULT;
   3400 	if (val->type == XML_NAMESPACE_DECL) {
   3401 	    xmlNsPtr ns = (xmlNsPtr) val;
   3402 
   3403 	    ret->nodeTab[ret->nodeNr++] =
   3404 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3405 	} else
   3406 	    ret->nodeTab[ret->nodeNr++] = val;
   3407     }
   3408     return(ret);
   3409 }
   3410 
   3411 /**
   3412  * xmlXPathNodeSetCreateSize:
   3413  * @size:  the initial size of the set
   3414  *
   3415  * Create a new xmlNodeSetPtr of type double and of value @val
   3416  *
   3417  * Returns the newly created object.
   3418  */
   3419 static xmlNodeSetPtr
   3420 xmlXPathNodeSetCreateSize(int size) {
   3421     xmlNodeSetPtr ret;
   3422 
   3423     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3424     if (ret == NULL) {
   3425         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3426 	return(NULL);
   3427     }
   3428     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3429     if (size < XML_NODESET_DEFAULT)
   3430 	size = XML_NODESET_DEFAULT;
   3431     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3432     if (ret->nodeTab == NULL) {
   3433 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3434 	xmlFree(ret);
   3435 	return(NULL);
   3436     }
   3437     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3438     ret->nodeMax = size;
   3439     return(ret);
   3440 }
   3441 
   3442 /**
   3443  * xmlXPathNodeSetContains:
   3444  * @cur:  the node-set
   3445  * @val:  the node
   3446  *
   3447  * checks whether @cur contains @val
   3448  *
   3449  * Returns true (1) if @cur contains @val, false (0) otherwise
   3450  */
   3451 int
   3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3453     int i;
   3454 
   3455     if ((cur == NULL) || (val == NULL)) return(0);
   3456     if (val->type == XML_NAMESPACE_DECL) {
   3457 	for (i = 0; i < cur->nodeNr; i++) {
   3458 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3459 		xmlNsPtr ns1, ns2;
   3460 
   3461 		ns1 = (xmlNsPtr) val;
   3462 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3463 		if (ns1 == ns2)
   3464 		    return(1);
   3465 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3466 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3467 		    return(1);
   3468 	    }
   3469 	}
   3470     } else {
   3471 	for (i = 0; i < cur->nodeNr; i++) {
   3472 	    if (cur->nodeTab[i] == val)
   3473 		return(1);
   3474 	}
   3475     }
   3476     return(0);
   3477 }
   3478 
   3479 /**
   3480  * xmlXPathNodeSetAddNs:
   3481  * @cur:  the initial node set
   3482  * @node:  the hosting node
   3483  * @ns:  a the namespace node
   3484  *
   3485  * add a new namespace node to an existing NodeSet
   3486  */
   3487 void
   3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3489     int i;
   3490 
   3491 
   3492     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3493         (ns->type != XML_NAMESPACE_DECL) ||
   3494 	(node->type != XML_ELEMENT_NODE))
   3495 	return;
   3496 
   3497     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3498     /*
   3499      * prevent duplicates
   3500      */
   3501     for (i = 0;i < cur->nodeNr;i++) {
   3502         if ((cur->nodeTab[i] != NULL) &&
   3503 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3504 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3505 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3506 	    return;
   3507     }
   3508 
   3509     /*
   3510      * grow the nodeTab if needed
   3511      */
   3512     if (cur->nodeMax == 0) {
   3513         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3514 					     sizeof(xmlNodePtr));
   3515 	if (cur->nodeTab == NULL) {
   3516 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3517 	    return;
   3518 	}
   3519 	memset(cur->nodeTab, 0 ,
   3520 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3521         cur->nodeMax = XML_NODESET_DEFAULT;
   3522     } else if (cur->nodeNr == cur->nodeMax) {
   3523         xmlNodePtr *temp;
   3524 
   3525         cur->nodeMax *= 2;
   3526 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3527 				      sizeof(xmlNodePtr));
   3528 	if (temp == NULL) {
   3529 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3530 	    return;
   3531 	}
   3532 	cur->nodeTab = temp;
   3533     }
   3534     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3535 }
   3536 
   3537 /**
   3538  * xmlXPathNodeSetAdd:
   3539  * @cur:  the initial node set
   3540  * @val:  a new xmlNodePtr
   3541  *
   3542  * add a new xmlNodePtr to an existing NodeSet
   3543  */
   3544 void
   3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3546     int i;
   3547 
   3548     if ((cur == NULL) || (val == NULL)) return;
   3549 
   3550 #if 0
   3551     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3552 	return;	/* an XSLT fake node */
   3553 #endif
   3554 
   3555     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3556     /*
   3557      * prevent duplcates
   3558      */
   3559     for (i = 0;i < cur->nodeNr;i++)
   3560         if (cur->nodeTab[i] == val) return;
   3561 
   3562     /*
   3563      * grow the nodeTab if needed
   3564      */
   3565     if (cur->nodeMax == 0) {
   3566         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3567 					     sizeof(xmlNodePtr));
   3568 	if (cur->nodeTab == NULL) {
   3569 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3570 	    return;
   3571 	}
   3572 	memset(cur->nodeTab, 0 ,
   3573 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3574         cur->nodeMax = XML_NODESET_DEFAULT;
   3575     } else if (cur->nodeNr == cur->nodeMax) {
   3576         xmlNodePtr *temp;
   3577 
   3578         cur->nodeMax *= 2;
   3579 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3580 				      sizeof(xmlNodePtr));
   3581 	if (temp == NULL) {
   3582 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3583 	    return;
   3584 	}
   3585 	cur->nodeTab = temp;
   3586     }
   3587     if (val->type == XML_NAMESPACE_DECL) {
   3588 	xmlNsPtr ns = (xmlNsPtr) val;
   3589 
   3590 	cur->nodeTab[cur->nodeNr++] =
   3591 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3592     } else
   3593 	cur->nodeTab[cur->nodeNr++] = val;
   3594 }
   3595 
   3596 /**
   3597  * xmlXPathNodeSetAddUnique:
   3598  * @cur:  the initial node set
   3599  * @val:  a new xmlNodePtr
   3600  *
   3601  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3602  * when we are sure the node is not already in the set.
   3603  */
   3604 void
   3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3606     if ((cur == NULL) || (val == NULL)) return;
   3607 
   3608 #if 0
   3609     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3610 	return;	/* an XSLT fake node */
   3611 #endif
   3612 
   3613     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3614     /*
   3615      * grow the nodeTab if needed
   3616      */
   3617     if (cur->nodeMax == 0) {
   3618         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3619 					     sizeof(xmlNodePtr));
   3620 	if (cur->nodeTab == NULL) {
   3621 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3622 	    return;
   3623 	}
   3624 	memset(cur->nodeTab, 0 ,
   3625 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3626         cur->nodeMax = XML_NODESET_DEFAULT;
   3627     } else if (cur->nodeNr == cur->nodeMax) {
   3628         xmlNodePtr *temp;
   3629 
   3630         cur->nodeMax *= 2;
   3631 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3632 				      sizeof(xmlNodePtr));
   3633 	if (temp == NULL) {
   3634 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3635 	    return;
   3636 	}
   3637 	cur->nodeTab = temp;
   3638     }
   3639     if (val->type == XML_NAMESPACE_DECL) {
   3640 	xmlNsPtr ns = (xmlNsPtr) val;
   3641 
   3642 	cur->nodeTab[cur->nodeNr++] =
   3643 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3644     } else
   3645 	cur->nodeTab[cur->nodeNr++] = val;
   3646 }
   3647 
   3648 /**
   3649  * xmlXPathNodeSetMerge:
   3650  * @val1:  the first NodeSet or NULL
   3651  * @val2:  the second NodeSet
   3652  *
   3653  * Merges two nodesets, all nodes from @val2 are added to @val1
   3654  * if @val1 is NULL, a new set is created and copied from @val2
   3655  *
   3656  * Returns @val1 once extended or NULL in case of error.
   3657  */
   3658 xmlNodeSetPtr
   3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3660     int i, j, initNr, skip;
   3661     xmlNodePtr n1, n2;
   3662 
   3663     if (val2 == NULL) return(val1);
   3664     if (val1 == NULL) {
   3665 	val1 = xmlXPathNodeSetCreate(NULL);
   3666     if (val1 == NULL)
   3667         return (NULL);
   3668 #if 0
   3669 	/*
   3670 	* TODO: The optimization won't work in every case, since
   3671 	*  those nasty namespace nodes need to be added with
   3672 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3673 	*  memcpy is not possible.
   3674 	*  If there was a flag on the nodesetval, indicating that
   3675 	*  some temporary nodes are in, that would be helpfull.
   3676 	*/
   3677 	/*
   3678 	* Optimization: Create an equally sized node-set
   3679 	* and memcpy the content.
   3680 	*/
   3681 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3682 	if (val1 == NULL)
   3683 	    return(NULL);
   3684 	if (val2->nodeNr != 0) {
   3685 	    if (val2->nodeNr == 1)
   3686 		*(val1->nodeTab) = *(val2->nodeTab);
   3687 	    else {
   3688 		memcpy(val1->nodeTab, val2->nodeTab,
   3689 		    val2->nodeNr * sizeof(xmlNodePtr));
   3690 	    }
   3691 	    val1->nodeNr = val2->nodeNr;
   3692 	}
   3693 	return(val1);
   3694 #endif
   3695     }
   3696 
   3697     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3698     initNr = val1->nodeNr;
   3699 
   3700     for (i = 0;i < val2->nodeNr;i++) {
   3701 	n2 = val2->nodeTab[i];
   3702 	/*
   3703 	 * check against duplicates
   3704 	 */
   3705 	skip = 0;
   3706 	for (j = 0; j < initNr; j++) {
   3707 	    n1 = val1->nodeTab[j];
   3708 	    if (n1 == n2) {
   3709 		skip = 1;
   3710 		break;
   3711 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3712 		       (n2->type == XML_NAMESPACE_DECL)) {
   3713 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3714 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3715 			((xmlNsPtr) n2)->prefix)))
   3716 		{
   3717 		    skip = 1;
   3718 		    break;
   3719 		}
   3720 	    }
   3721 	}
   3722 	if (skip)
   3723 	    continue;
   3724 
   3725 	/*
   3726 	 * grow the nodeTab if needed
   3727 	 */
   3728 	if (val1->nodeMax == 0) {
   3729 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3730 						    sizeof(xmlNodePtr));
   3731 	    if (val1->nodeTab == NULL) {
   3732 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3733 		return(NULL);
   3734 	    }
   3735 	    memset(val1->nodeTab, 0 ,
   3736 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3737 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3738 	} else if (val1->nodeNr == val1->nodeMax) {
   3739 	    xmlNodePtr *temp;
   3740 
   3741 	    val1->nodeMax *= 2;
   3742 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3743 					     sizeof(xmlNodePtr));
   3744 	    if (temp == NULL) {
   3745 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3746 		return(NULL);
   3747 	    }
   3748 	    val1->nodeTab = temp;
   3749 	}
   3750 	if (n2->type == XML_NAMESPACE_DECL) {
   3751 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3752 
   3753 	    val1->nodeTab[val1->nodeNr++] =
   3754 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3755 	} else
   3756 	    val1->nodeTab[val1->nodeNr++] = n2;
   3757     }
   3758 
   3759     return(val1);
   3760 }
   3761 
   3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3763 /**
   3764  * xmlXPathNodeSetMergeUnique:
   3765  * @val1:  the first NodeSet or NULL
   3766  * @val2:  the second NodeSet
   3767  *
   3768  * Merges two nodesets, all nodes from @val2 are added to @val1
   3769  * if @val1 is NULL, a new set is created and copied from @val2
   3770  *
   3771  * Returns @val1 once extended or NULL in case of error.
   3772  */
   3773 static xmlNodeSetPtr
   3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3775     int i;
   3776 
   3777     if (val2 == NULL) return(val1);
   3778     if (val1 == NULL) {
   3779 	val1 = xmlXPathNodeSetCreate(NULL);
   3780     }
   3781     if (val1 == NULL)
   3782         return (NULL);
   3783 
   3784     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3785 
   3786     for (i = 0;i < val2->nodeNr;i++) {
   3787 	/*
   3788 	 * grow the nodeTab if needed
   3789 	 */
   3790 	if (val1->nodeMax == 0) {
   3791 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3792 						    sizeof(xmlNodePtr));
   3793 	    if (val1->nodeTab == NULL) {
   3794 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3795 		return(NULL);
   3796 	    }
   3797 	    memset(val1->nodeTab, 0 ,
   3798 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3799 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3800 	} else if (val1->nodeNr == val1->nodeMax) {
   3801 	    xmlNodePtr *temp;
   3802 
   3803 	    val1->nodeMax *= 2;
   3804 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3805 					     sizeof(xmlNodePtr));
   3806 	    if (temp == NULL) {
   3807 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3808 		return(NULL);
   3809 	    }
   3810 	    val1->nodeTab = temp;
   3811 	}
   3812 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3813 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
   3814 
   3815 	    val1->nodeTab[val1->nodeNr++] =
   3816 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3817 	} else
   3818 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
   3819     }
   3820 
   3821     return(val1);
   3822 }
   3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3824 
   3825 /**
   3826  * xmlXPathNodeSetMergeAndClear:
   3827  * @set1:  the first NodeSet or NULL
   3828  * @set2:  the second NodeSet
   3829  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3830  *
   3831  * Merges two nodesets, all nodes from @set2 are added to @set1
   3832  * if @set1 is NULL, a new set is created and copied from @set2.
   3833  * Checks for duplicate nodes. Clears set2.
   3834  *
   3835  * Returns @set1 once extended or NULL in case of error.
   3836  */
   3837 static xmlNodeSetPtr
   3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3839 			     int hasNullEntries)
   3840 {
   3841     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3842 	/*
   3843 	* Note that doing a memcpy of the list, namespace nodes are
   3844 	* just assigned to set1, since set2 is cleared anyway.
   3845 	*/
   3846 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3847 	if (set1 == NULL)
   3848 	    return(NULL);
   3849 	if (set2->nodeNr != 0) {
   3850 	    memcpy(set1->nodeTab, set2->nodeTab,
   3851 		set2->nodeNr * sizeof(xmlNodePtr));
   3852 	    set1->nodeNr = set2->nodeNr;
   3853 	}
   3854     } else {
   3855 	int i, j, initNbSet1;
   3856 	xmlNodePtr n1, n2;
   3857 
   3858 	if (set1 == NULL)
   3859             set1 = xmlXPathNodeSetCreate(NULL);
   3860         if (set1 == NULL)
   3861             return (NULL);
   3862 
   3863 	initNbSet1 = set1->nodeNr;
   3864 	for (i = 0;i < set2->nodeNr;i++) {
   3865 	    n2 = set2->nodeTab[i];
   3866 	    /*
   3867 	    * Skip NULLed entries.
   3868 	    */
   3869 	    if (n2 == NULL)
   3870 		continue;
   3871 	    /*
   3872 	    * Skip duplicates.
   3873 	    */
   3874 	    for (j = 0; j < initNbSet1; j++) {
   3875 		n1 = set1->nodeTab[j];
   3876 		if (n1 == n2) {
   3877 		    goto skip_node;
   3878 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3879 		    (n2->type == XML_NAMESPACE_DECL))
   3880 		{
   3881 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3882 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3883 			((xmlNsPtr) n2)->prefix)))
   3884 		    {
   3885 			/*
   3886 			* Free the namespace node.
   3887 			*/
   3888 			set2->nodeTab[i] = NULL;
   3889 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3890 			goto skip_node;
   3891 		    }
   3892 		}
   3893 	    }
   3894 	    /*
   3895 	    * grow the nodeTab if needed
   3896 	    */
   3897 	    if (set1->nodeMax == 0) {
   3898 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3899 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3900 		if (set1->nodeTab == NULL) {
   3901 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3902 		    return(NULL);
   3903 		}
   3904 		memset(set1->nodeTab, 0,
   3905 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3906 		set1->nodeMax = XML_NODESET_DEFAULT;
   3907 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3908 		xmlNodePtr *temp;
   3909 
   3910 		set1->nodeMax *= 2;
   3911 		temp = (xmlNodePtr *) xmlRealloc(
   3912 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
   3913 		if (temp == NULL) {
   3914 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3915 		    return(NULL);
   3916 		}
   3917 		set1->nodeTab = temp;
   3918 	    }
   3919 	    if (n2->type == XML_NAMESPACE_DECL) {
   3920 		xmlNsPtr ns = (xmlNsPtr) n2;
   3921 
   3922 		set1->nodeTab[set1->nodeNr++] =
   3923 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3924 	    } else
   3925 		set1->nodeTab[set1->nodeNr++] = n2;
   3926 skip_node:
   3927 	    {}
   3928 	}
   3929     }
   3930     set2->nodeNr = 0;
   3931     return(set1);
   3932 }
   3933 
   3934 /**
   3935  * xmlXPathNodeSetMergeAndClearNoDupls:
   3936  * @set1:  the first NodeSet or NULL
   3937  * @set2:  the second NodeSet
   3938  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3939  *
   3940  * Merges two nodesets, all nodes from @set2 are added to @set1
   3941  * if @set1 is NULL, a new set is created and copied from @set2.
   3942  * Doesn't chack for duplicate nodes. Clears set2.
   3943  *
   3944  * Returns @set1 once extended or NULL in case of error.
   3945  */
   3946 static xmlNodeSetPtr
   3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3948 				    int hasNullEntries)
   3949 {
   3950     if (set2 == NULL)
   3951 	return(set1);
   3952     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3953 	/*
   3954 	* Note that doing a memcpy of the list, namespace nodes are
   3955 	* just assigned to set1, since set2 is cleared anyway.
   3956 	*/
   3957 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3958 	if (set1 == NULL)
   3959 	    return(NULL);
   3960 	if (set2->nodeNr != 0) {
   3961 	    memcpy(set1->nodeTab, set2->nodeTab,
   3962 		set2->nodeNr * sizeof(xmlNodePtr));
   3963 	    set1->nodeNr = set2->nodeNr;
   3964 	}
   3965     } else {
   3966 	int i;
   3967 	xmlNodePtr n2;
   3968 
   3969 	if (set1 == NULL)
   3970 	    set1 = xmlXPathNodeSetCreate(NULL);
   3971         if (set1 == NULL)
   3972             return (NULL);
   3973 
   3974 	for (i = 0;i < set2->nodeNr;i++) {
   3975 	    n2 = set2->nodeTab[i];
   3976 	    /*
   3977 	    * Skip NULLed entries.
   3978 	    */
   3979 	    if (n2 == NULL)
   3980 		continue;
   3981 	    if (set1->nodeMax == 0) {
   3982 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3983 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3984 		if (set1->nodeTab == NULL) {
   3985 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3986 		    return(NULL);
   3987 		}
   3988 		memset(set1->nodeTab, 0,
   3989 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3990 		set1->nodeMax = XML_NODESET_DEFAULT;
   3991 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3992 		xmlNodePtr *temp;
   3993 
   3994 		set1->nodeMax *= 2;
   3995 		temp = (xmlNodePtr *) xmlRealloc(
   3996 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
   3997 		if (temp == NULL) {
   3998 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3999 		    return(NULL);
   4000 		}
   4001 		set1->nodeTab = temp;
   4002 	    }
   4003 	    set1->nodeTab[set1->nodeNr++] = n2;
   4004 	}
   4005     }
   4006     set2->nodeNr = 0;
   4007     return(set1);
   4008 }
   4009 
   4010 /**
   4011  * xmlXPathNodeSetDel:
   4012  * @cur:  the initial node set
   4013  * @val:  an xmlNodePtr
   4014  *
   4015  * Removes an xmlNodePtr from an existing NodeSet
   4016  */
   4017 void
   4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4019     int i;
   4020 
   4021     if (cur == NULL) return;
   4022     if (val == NULL) return;
   4023 
   4024     /*
   4025      * find node in nodeTab
   4026      */
   4027     for (i = 0;i < cur->nodeNr;i++)
   4028         if (cur->nodeTab[i] == val) break;
   4029 
   4030     if (i >= cur->nodeNr) {	/* not found */
   4031 #ifdef DEBUG
   4032         xmlGenericError(xmlGenericErrorContext,
   4033 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4034 		val->name);
   4035 #endif
   4036         return;
   4037     }
   4038     if ((cur->nodeTab[i] != NULL) &&
   4039 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4040 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4041     cur->nodeNr--;
   4042     for (;i < cur->nodeNr;i++)
   4043         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4044     cur->nodeTab[cur->nodeNr] = NULL;
   4045 }
   4046 
   4047 /**
   4048  * xmlXPathNodeSetRemove:
   4049  * @cur:  the initial node set
   4050  * @val:  the index to remove
   4051  *
   4052  * Removes an entry from an existing NodeSet list.
   4053  */
   4054 void
   4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4056     if (cur == NULL) return;
   4057     if (val >= cur->nodeNr) return;
   4058     if ((cur->nodeTab[val] != NULL) &&
   4059 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4060 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4061     cur->nodeNr--;
   4062     for (;val < cur->nodeNr;val++)
   4063         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4064     cur->nodeTab[cur->nodeNr] = NULL;
   4065 }
   4066 
   4067 /**
   4068  * xmlXPathFreeNodeSet:
   4069  * @obj:  the xmlNodeSetPtr to free
   4070  *
   4071  * Free the NodeSet compound (not the actual nodes !).
   4072  */
   4073 void
   4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4075     if (obj == NULL) return;
   4076     if (obj->nodeTab != NULL) {
   4077 	int i;
   4078 
   4079 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4080 	for (i = 0;i < obj->nodeNr;i++)
   4081 	    if ((obj->nodeTab[i] != NULL) &&
   4082 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4083 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4084 	xmlFree(obj->nodeTab);
   4085     }
   4086     xmlFree(obj);
   4087 }
   4088 
   4089 /**
   4090  * xmlXPathNodeSetClear:
   4091  * @set:  the node set to clear
   4092  *
   4093  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4094  * are feed), but does *not* free the list itself. Sets the length of the
   4095  * list to 0.
   4096  */
   4097 static void
   4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4099 {
   4100     if ((set == NULL) || (set->nodeNr <= 0))
   4101 	return;
   4102     else if (hasNsNodes) {
   4103 	int i;
   4104 	xmlNodePtr node;
   4105 
   4106 	for (i = 0; i < set->nodeNr; i++) {
   4107 	    node = set->nodeTab[i];
   4108 	    if ((node != NULL) &&
   4109 		(node->type == XML_NAMESPACE_DECL))
   4110 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4111 	}
   4112     }
   4113     set->nodeNr = 0;
   4114 }
   4115 
   4116 /**
   4117  * xmlXPathNodeSetClearFromPos:
   4118  * @set: the node set to be cleared
   4119  * @pos: the start position to clear from
   4120  *
   4121  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4122  * are feed) starting with the entry at @pos, but does *not* free the list
   4123  * itself. Sets the length of the list to @pos.
   4124  */
   4125 static void
   4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4127 {
   4128     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4129 	return;
   4130     else if ((hasNsNodes)) {
   4131 	int i;
   4132 	xmlNodePtr node;
   4133 
   4134 	for (i = pos; i < set->nodeNr; i++) {
   4135 	    node = set->nodeTab[i];
   4136 	    if ((node != NULL) &&
   4137 		(node->type == XML_NAMESPACE_DECL))
   4138 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4139 	}
   4140     }
   4141     set->nodeNr = pos;
   4142 }
   4143 
   4144 /**
   4145  * xmlXPathFreeValueTree:
   4146  * @obj:  the xmlNodeSetPtr to free
   4147  *
   4148  * Free the NodeSet compound and the actual tree, this is different
   4149  * from xmlXPathFreeNodeSet()
   4150  */
   4151 static void
   4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4153     int i;
   4154 
   4155     if (obj == NULL) return;
   4156 
   4157     if (obj->nodeTab != NULL) {
   4158 	for (i = 0;i < obj->nodeNr;i++) {
   4159 	    if (obj->nodeTab[i] != NULL) {
   4160 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4161 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4162 		} else {
   4163 		    xmlFreeNodeList(obj->nodeTab[i]);
   4164 		}
   4165 	    }
   4166 	}
   4167 	xmlFree(obj->nodeTab);
   4168     }
   4169     xmlFree(obj);
   4170 }
   4171 
   4172 #if defined(DEBUG) || defined(DEBUG_STEP)
   4173 /**
   4174  * xmlGenericErrorContextNodeSet:
   4175  * @output:  a FILE * for the output
   4176  * @obj:  the xmlNodeSetPtr to display
   4177  *
   4178  * Quick display of a NodeSet
   4179  */
   4180 void
   4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4182     int i;
   4183 
   4184     if (output == NULL) output = xmlGenericErrorContext;
   4185     if (obj == NULL)  {
   4186         fprintf(output, "NodeSet == NULL !\n");
   4187 	return;
   4188     }
   4189     if (obj->nodeNr == 0) {
   4190         fprintf(output, "NodeSet is empty\n");
   4191 	return;
   4192     }
   4193     if (obj->nodeTab == NULL) {
   4194 	fprintf(output, " nodeTab == NULL !\n");
   4195 	return;
   4196     }
   4197     for (i = 0; i < obj->nodeNr; i++) {
   4198         if (obj->nodeTab[i] == NULL) {
   4199 	    fprintf(output, " NULL !\n");
   4200 	    return;
   4201         }
   4202 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4203 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4204 	    fprintf(output, " /");
   4205 	else if (obj->nodeTab[i]->name == NULL)
   4206 	    fprintf(output, " noname!");
   4207 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4208     }
   4209     fprintf(output, "\n");
   4210 }
   4211 #endif
   4212 
   4213 /**
   4214  * xmlXPathNewNodeSet:
   4215  * @val:  the NodePtr value
   4216  *
   4217  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4218  * it with the single Node @val
   4219  *
   4220  * Returns the newly created object.
   4221  */
   4222 xmlXPathObjectPtr
   4223 xmlXPathNewNodeSet(xmlNodePtr val) {
   4224     xmlXPathObjectPtr ret;
   4225 
   4226     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4227     if (ret == NULL) {
   4228         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4229 	return(NULL);
   4230     }
   4231     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4232     ret->type = XPATH_NODESET;
   4233     ret->boolval = 0;
   4234     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4235     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4236 #ifdef XP_DEBUG_OBJ_USAGE
   4237     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4238 #endif
   4239     return(ret);
   4240 }
   4241 
   4242 /**
   4243  * xmlXPathNewValueTree:
   4244  * @val:  the NodePtr value
   4245  *
   4246  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4247  * it with the tree root @val
   4248  *
   4249  * Returns the newly created object.
   4250  */
   4251 xmlXPathObjectPtr
   4252 xmlXPathNewValueTree(xmlNodePtr val) {
   4253     xmlXPathObjectPtr ret;
   4254 
   4255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4256     if (ret == NULL) {
   4257         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4258 	return(NULL);
   4259     }
   4260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4261     ret->type = XPATH_XSLT_TREE;
   4262     ret->boolval = 1;
   4263     ret->user = (void *) val;
   4264     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4265 #ifdef XP_DEBUG_OBJ_USAGE
   4266     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4267 #endif
   4268     return(ret);
   4269 }
   4270 
   4271 /**
   4272  * xmlXPathNewNodeSetList:
   4273  * @val:  an existing NodeSet
   4274  *
   4275  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4276  * it with the Nodeset @val
   4277  *
   4278  * Returns the newly created object.
   4279  */
   4280 xmlXPathObjectPtr
   4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4282 {
   4283     xmlXPathObjectPtr ret;
   4284     int i;
   4285 
   4286     if (val == NULL)
   4287         ret = NULL;
   4288     else if (val->nodeTab == NULL)
   4289         ret = xmlXPathNewNodeSet(NULL);
   4290     else {
   4291         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4292         if (ret)
   4293             for (i = 1; i < val->nodeNr; ++i)
   4294                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
   4295     }
   4296 
   4297     return (ret);
   4298 }
   4299 
   4300 /**
   4301  * xmlXPathWrapNodeSet:
   4302  * @val:  the NodePtr value
   4303  *
   4304  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4305  *
   4306  * Returns the newly created object.
   4307  */
   4308 xmlXPathObjectPtr
   4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4310     xmlXPathObjectPtr ret;
   4311 
   4312     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4313     if (ret == NULL) {
   4314         xmlXPathErrMemory(NULL, "creating node set object\n");
   4315 	return(NULL);
   4316     }
   4317     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4318     ret->type = XPATH_NODESET;
   4319     ret->nodesetval = val;
   4320 #ifdef XP_DEBUG_OBJ_USAGE
   4321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4322 #endif
   4323     return(ret);
   4324 }
   4325 
   4326 /**
   4327  * xmlXPathFreeNodeSetList:
   4328  * @obj:  an existing NodeSetList object
   4329  *
   4330  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4331  * the list contrary to xmlXPathFreeObject().
   4332  */
   4333 void
   4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4335     if (obj == NULL) return;
   4336 #ifdef XP_DEBUG_OBJ_USAGE
   4337     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4338 #endif
   4339     xmlFree(obj);
   4340 }
   4341 
   4342 /**
   4343  * xmlXPathDifference:
   4344  * @nodes1:  a node-set
   4345  * @nodes2:  a node-set
   4346  *
   4347  * Implements the EXSLT - Sets difference() function:
   4348  *    node-set set:difference (node-set, node-set)
   4349  *
   4350  * Returns the difference between the two node sets, or nodes1 if
   4351  *         nodes2 is empty
   4352  */
   4353 xmlNodeSetPtr
   4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4355     xmlNodeSetPtr ret;
   4356     int i, l1;
   4357     xmlNodePtr cur;
   4358 
   4359     if (xmlXPathNodeSetIsEmpty(nodes2))
   4360 	return(nodes1);
   4361 
   4362     ret = xmlXPathNodeSetCreate(NULL);
   4363     if (xmlXPathNodeSetIsEmpty(nodes1))
   4364 	return(ret);
   4365 
   4366     l1 = xmlXPathNodeSetGetLength(nodes1);
   4367 
   4368     for (i = 0; i < l1; i++) {
   4369 	cur = xmlXPathNodeSetItem(nodes1, i);
   4370 	if (!xmlXPathNodeSetContains(nodes2, cur))
   4371 	    xmlXPathNodeSetAddUnique(ret, cur);
   4372     }
   4373     return(ret);
   4374 }
   4375 
   4376 /**
   4377  * xmlXPathIntersection:
   4378  * @nodes1:  a node-set
   4379  * @nodes2:  a node-set
   4380  *
   4381  * Implements the EXSLT - Sets intersection() function:
   4382  *    node-set set:intersection (node-set, node-set)
   4383  *
   4384  * Returns a node set comprising the nodes that are within both the
   4385  *         node sets passed as arguments
   4386  */
   4387 xmlNodeSetPtr
   4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4389     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4390     int i, l1;
   4391     xmlNodePtr cur;
   4392 
   4393     if (ret == NULL)
   4394         return(ret);
   4395     if (xmlXPathNodeSetIsEmpty(nodes1))
   4396 	return(ret);
   4397     if (xmlXPathNodeSetIsEmpty(nodes2))
   4398 	return(ret);
   4399 
   4400     l1 = xmlXPathNodeSetGetLength(nodes1);
   4401 
   4402     for (i = 0; i < l1; i++) {
   4403 	cur = xmlXPathNodeSetItem(nodes1, i);
   4404 	if (xmlXPathNodeSetContains(nodes2, cur))
   4405 	    xmlXPathNodeSetAddUnique(ret, cur);
   4406     }
   4407     return(ret);
   4408 }
   4409 
   4410 /**
   4411  * xmlXPathDistinctSorted:
   4412  * @nodes:  a node-set, sorted by document order
   4413  *
   4414  * Implements the EXSLT - Sets distinct() function:
   4415  *    node-set set:distinct (node-set)
   4416  *
   4417  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4418  *         it is empty
   4419  */
   4420 xmlNodeSetPtr
   4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4422     xmlNodeSetPtr ret;
   4423     xmlHashTablePtr hash;
   4424     int i, l;
   4425     xmlChar * strval;
   4426     xmlNodePtr cur;
   4427 
   4428     if (xmlXPathNodeSetIsEmpty(nodes))
   4429 	return(nodes);
   4430 
   4431     ret = xmlXPathNodeSetCreate(NULL);
   4432     if (ret == NULL)
   4433         return(ret);
   4434     l = xmlXPathNodeSetGetLength(nodes);
   4435     hash = xmlHashCreate (l);
   4436     for (i = 0; i < l; i++) {
   4437 	cur = xmlXPathNodeSetItem(nodes, i);
   4438 	strval = xmlXPathCastNodeToString(cur);
   4439 	if (xmlHashLookup(hash, strval) == NULL) {
   4440 	    xmlHashAddEntry(hash, strval, strval);
   4441 	    xmlXPathNodeSetAddUnique(ret, cur);
   4442 	} else {
   4443 	    xmlFree(strval);
   4444 	}
   4445     }
   4446     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4447     return(ret);
   4448 }
   4449 
   4450 /**
   4451  * xmlXPathDistinct:
   4452  * @nodes:  a node-set
   4453  *
   4454  * Implements the EXSLT - Sets distinct() function:
   4455  *    node-set set:distinct (node-set)
   4456  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4457  * is called with the sorted node-set
   4458  *
   4459  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4460  *         it is empty
   4461  */
   4462 xmlNodeSetPtr
   4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4464     if (xmlXPathNodeSetIsEmpty(nodes))
   4465 	return(nodes);
   4466 
   4467     xmlXPathNodeSetSort(nodes);
   4468     return(xmlXPathDistinctSorted(nodes));
   4469 }
   4470 
   4471 /**
   4472  * xmlXPathHasSameNodes:
   4473  * @nodes1:  a node-set
   4474  * @nodes2:  a node-set
   4475  *
   4476  * Implements the EXSLT - Sets has-same-nodes function:
   4477  *    boolean set:has-same-node(node-set, node-set)
   4478  *
   4479  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4480  *         otherwise
   4481  */
   4482 int
   4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4484     int i, l;
   4485     xmlNodePtr cur;
   4486 
   4487     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4488 	xmlXPathNodeSetIsEmpty(nodes2))
   4489 	return(0);
   4490 
   4491     l = xmlXPathNodeSetGetLength(nodes1);
   4492     for (i = 0; i < l; i++) {
   4493 	cur = xmlXPathNodeSetItem(nodes1, i);
   4494 	if (xmlXPathNodeSetContains(nodes2, cur))
   4495 	    return(1);
   4496     }
   4497     return(0);
   4498 }
   4499 
   4500 /**
   4501  * xmlXPathNodeLeadingSorted:
   4502  * @nodes: a node-set, sorted by document order
   4503  * @node: a node
   4504  *
   4505  * Implements the EXSLT - Sets leading() function:
   4506  *    node-set set:leading (node-set, node-set)
   4507  *
   4508  * Returns the nodes in @nodes that precede @node in document order,
   4509  *         @nodes if @node is NULL or an empty node-set if @nodes
   4510  *         doesn't contain @node
   4511  */
   4512 xmlNodeSetPtr
   4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4514     int i, l;
   4515     xmlNodePtr cur;
   4516     xmlNodeSetPtr ret;
   4517 
   4518     if (node == NULL)
   4519 	return(nodes);
   4520 
   4521     ret = xmlXPathNodeSetCreate(NULL);
   4522     if (ret == NULL)
   4523         return(ret);
   4524     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4525 	(!xmlXPathNodeSetContains(nodes, node)))
   4526 	return(ret);
   4527 
   4528     l = xmlXPathNodeSetGetLength(nodes);
   4529     for (i = 0; i < l; i++) {
   4530 	cur = xmlXPathNodeSetItem(nodes, i);
   4531 	if (cur == node)
   4532 	    break;
   4533 	xmlXPathNodeSetAddUnique(ret, cur);
   4534     }
   4535     return(ret);
   4536 }
   4537 
   4538 /**
   4539  * xmlXPathNodeLeading:
   4540  * @nodes:  a node-set
   4541  * @node:  a node
   4542  *
   4543  * Implements the EXSLT - Sets leading() function:
   4544  *    node-set set:leading (node-set, node-set)
   4545  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4546  * is called.
   4547  *
   4548  * Returns the nodes in @nodes that precede @node in document order,
   4549  *         @nodes if @node is NULL or an empty node-set if @nodes
   4550  *         doesn't contain @node
   4551  */
   4552 xmlNodeSetPtr
   4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4554     xmlXPathNodeSetSort(nodes);
   4555     return(xmlXPathNodeLeadingSorted(nodes, node));
   4556 }
   4557 
   4558 /**
   4559  * xmlXPathLeadingSorted:
   4560  * @nodes1:  a node-set, sorted by document order
   4561  * @nodes2:  a node-set, sorted by document order
   4562  *
   4563  * Implements the EXSLT - Sets leading() function:
   4564  *    node-set set:leading (node-set, node-set)
   4565  *
   4566  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4567  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4568  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4569  */
   4570 xmlNodeSetPtr
   4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4572     if (xmlXPathNodeSetIsEmpty(nodes2))
   4573 	return(nodes1);
   4574     return(xmlXPathNodeLeadingSorted(nodes1,
   4575 				     xmlXPathNodeSetItem(nodes2, 1)));
   4576 }
   4577 
   4578 /**
   4579  * xmlXPathLeading:
   4580  * @nodes1:  a node-set
   4581  * @nodes2:  a node-set
   4582  *
   4583  * Implements the EXSLT - Sets leading() function:
   4584  *    node-set set:leading (node-set, node-set)
   4585  * @nodes1 and @nodes2 are sorted by document order, then
   4586  * #exslSetsLeadingSorted is called.
   4587  *
   4588  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4589  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4590  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4591  */
   4592 xmlNodeSetPtr
   4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4594     if (xmlXPathNodeSetIsEmpty(nodes2))
   4595 	return(nodes1);
   4596     if (xmlXPathNodeSetIsEmpty(nodes1))
   4597 	return(xmlXPathNodeSetCreate(NULL));
   4598     xmlXPathNodeSetSort(nodes1);
   4599     xmlXPathNodeSetSort(nodes2);
   4600     return(xmlXPathNodeLeadingSorted(nodes1,
   4601 				     xmlXPathNodeSetItem(nodes2, 1)));
   4602 }
   4603 
   4604 /**
   4605  * xmlXPathNodeTrailingSorted:
   4606  * @nodes: a node-set, sorted by document order
   4607  * @node: a node
   4608  *
   4609  * Implements the EXSLT - Sets trailing() function:
   4610  *    node-set set:trailing (node-set, node-set)
   4611  *
   4612  * Returns the nodes in @nodes that follow @node in document order,
   4613  *         @nodes if @node is NULL or an empty node-set if @nodes
   4614  *         doesn't contain @node
   4615  */
   4616 xmlNodeSetPtr
   4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4618     int i, l;
   4619     xmlNodePtr cur;
   4620     xmlNodeSetPtr ret;
   4621 
   4622     if (node == NULL)
   4623 	return(nodes);
   4624 
   4625     ret = xmlXPathNodeSetCreate(NULL);
   4626     if (ret == NULL)
   4627         return(ret);
   4628     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4629 	(!xmlXPathNodeSetContains(nodes, node)))
   4630 	return(ret);
   4631 
   4632     l = xmlXPathNodeSetGetLength(nodes);
   4633     for (i = l - 1; i >= 0; i--) {
   4634 	cur = xmlXPathNodeSetItem(nodes, i);
   4635 	if (cur == node)
   4636 	    break;
   4637 	xmlXPathNodeSetAddUnique(ret, cur);
   4638     }
   4639     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4640     return(ret);
   4641 }
   4642 
   4643 /**
   4644  * xmlXPathNodeTrailing:
   4645  * @nodes:  a node-set
   4646  * @node:  a node
   4647  *
   4648  * Implements the EXSLT - Sets trailing() function:
   4649  *    node-set set:trailing (node-set, node-set)
   4650  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4651  * is called.
   4652  *
   4653  * Returns the nodes in @nodes that follow @node in document order,
   4654  *         @nodes if @node is NULL or an empty node-set if @nodes
   4655  *         doesn't contain @node
   4656  */
   4657 xmlNodeSetPtr
   4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4659     xmlXPathNodeSetSort(nodes);
   4660     return(xmlXPathNodeTrailingSorted(nodes, node));
   4661 }
   4662 
   4663 /**
   4664  * xmlXPathTrailingSorted:
   4665  * @nodes1:  a node-set, sorted by document order
   4666  * @nodes2:  a node-set, sorted by document order
   4667  *
   4668  * Implements the EXSLT - Sets trailing() function:
   4669  *    node-set set:trailing (node-set, node-set)
   4670  *
   4671  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4672  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4673  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4674  */
   4675 xmlNodeSetPtr
   4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4677     if (xmlXPathNodeSetIsEmpty(nodes2))
   4678 	return(nodes1);
   4679     return(xmlXPathNodeTrailingSorted(nodes1,
   4680 				      xmlXPathNodeSetItem(nodes2, 0)));
   4681 }
   4682 
   4683 /**
   4684  * xmlXPathTrailing:
   4685  * @nodes1:  a node-set
   4686  * @nodes2:  a node-set
   4687  *
   4688  * Implements the EXSLT - Sets trailing() function:
   4689  *    node-set set:trailing (node-set, node-set)
   4690  * @nodes1 and @nodes2 are sorted by document order, then
   4691  * #xmlXPathTrailingSorted is called.
   4692  *
   4693  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4694  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4695  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4696  */
   4697 xmlNodeSetPtr
   4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4699     if (xmlXPathNodeSetIsEmpty(nodes2))
   4700 	return(nodes1);
   4701     if (xmlXPathNodeSetIsEmpty(nodes1))
   4702 	return(xmlXPathNodeSetCreate(NULL));
   4703     xmlXPathNodeSetSort(nodes1);
   4704     xmlXPathNodeSetSort(nodes2);
   4705     return(xmlXPathNodeTrailingSorted(nodes1,
   4706 				      xmlXPathNodeSetItem(nodes2, 0)));
   4707 }
   4708 
   4709 /************************************************************************
   4710  *									*
   4711  *		Routines to handle extra functions			*
   4712  *									*
   4713  ************************************************************************/
   4714 
   4715 /**
   4716  * xmlXPathRegisterFunc:
   4717  * @ctxt:  the XPath context
   4718  * @name:  the function name
   4719  * @f:  the function implementation or NULL
   4720  *
   4721  * Register a new function. If @f is NULL it unregisters the function
   4722  *
   4723  * Returns 0 in case of success, -1 in case of error
   4724  */
   4725 int
   4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4727 		     xmlXPathFunction f) {
   4728     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4729 }
   4730 
   4731 /**
   4732  * xmlXPathRegisterFuncNS:
   4733  * @ctxt:  the XPath context
   4734  * @name:  the function name
   4735  * @ns_uri:  the function namespace URI
   4736  * @f:  the function implementation or NULL
   4737  *
   4738  * Register a new function. If @f is NULL it unregisters the function
   4739  *
   4740  * Returns 0 in case of success, -1 in case of error
   4741  */
   4742 int
   4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4744 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4745     if (ctxt == NULL)
   4746 	return(-1);
   4747     if (name == NULL)
   4748 	return(-1);
   4749 
   4750     if (ctxt->funcHash == NULL)
   4751 	ctxt->funcHash = xmlHashCreate(0);
   4752     if (ctxt->funcHash == NULL)
   4753 	return(-1);
   4754     if (f == NULL)
   4755         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4756     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
   4757 }
   4758 
   4759 /**
   4760  * xmlXPathRegisterFuncLookup:
   4761  * @ctxt:  the XPath context
   4762  * @f:  the lookup function
   4763  * @funcCtxt:  the lookup data
   4764  *
   4765  * Registers an external mechanism to do function lookup.
   4766  */
   4767 void
   4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4769 			    xmlXPathFuncLookupFunc f,
   4770 			    void *funcCtxt) {
   4771     if (ctxt == NULL)
   4772 	return;
   4773     ctxt->funcLookupFunc = f;
   4774     ctxt->funcLookupData = funcCtxt;
   4775 }
   4776 
   4777 /**
   4778  * xmlXPathFunctionLookup:
   4779  * @ctxt:  the XPath context
   4780  * @name:  the function name
   4781  *
   4782  * Search in the Function array of the context for the given
   4783  * function.
   4784  *
   4785  * Returns the xmlXPathFunction or NULL if not found
   4786  */
   4787 xmlXPathFunction
   4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4789     if (ctxt == NULL)
   4790 	return (NULL);
   4791 
   4792     if (ctxt->funcLookupFunc != NULL) {
   4793 	xmlXPathFunction ret;
   4794 	xmlXPathFuncLookupFunc f;
   4795 
   4796 	f = ctxt->funcLookupFunc;
   4797 	ret = f(ctxt->funcLookupData, name, NULL);
   4798 	if (ret != NULL)
   4799 	    return(ret);
   4800     }
   4801     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4802 }
   4803 
   4804 /**
   4805  * xmlXPathFunctionLookupNS:
   4806  * @ctxt:  the XPath context
   4807  * @name:  the function name
   4808  * @ns_uri:  the function namespace URI
   4809  *
   4810  * Search in the Function array of the context for the given
   4811  * function.
   4812  *
   4813  * Returns the xmlXPathFunction or NULL if not found
   4814  */
   4815 xmlXPathFunction
   4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4817 			 const xmlChar *ns_uri) {
   4818     xmlXPathFunction ret;
   4819 
   4820     if (ctxt == NULL)
   4821 	return(NULL);
   4822     if (name == NULL)
   4823 	return(NULL);
   4824 
   4825     if (ctxt->funcLookupFunc != NULL) {
   4826 	xmlXPathFuncLookupFunc f;
   4827 
   4828 	f = ctxt->funcLookupFunc;
   4829 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4830 	if (ret != NULL)
   4831 	    return(ret);
   4832     }
   4833 
   4834     if (ctxt->funcHash == NULL)
   4835 	return(NULL);
   4836 
   4837     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4838     return(ret);
   4839 }
   4840 
   4841 /**
   4842  * xmlXPathRegisteredFuncsCleanup:
   4843  * @ctxt:  the XPath context
   4844  *
   4845  * Cleanup the XPath context data associated to registered functions
   4846  */
   4847 void
   4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4849     if (ctxt == NULL)
   4850 	return;
   4851 
   4852     xmlHashFree(ctxt->funcHash, NULL);
   4853     ctxt->funcHash = NULL;
   4854 }
   4855 
   4856 /************************************************************************
   4857  *									*
   4858  *			Routines to handle Variables			*
   4859  *									*
   4860  ************************************************************************/
   4861 
   4862 /**
   4863  * xmlXPathRegisterVariable:
   4864  * @ctxt:  the XPath context
   4865  * @name:  the variable name
   4866  * @value:  the variable value or NULL
   4867  *
   4868  * Register a new variable value. If @value is NULL it unregisters
   4869  * the variable
   4870  *
   4871  * Returns 0 in case of success, -1 in case of error
   4872  */
   4873 int
   4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   4875 			 xmlXPathObjectPtr value) {
   4876     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   4877 }
   4878 
   4879 /**
   4880  * xmlXPathRegisterVariableNS:
   4881  * @ctxt:  the XPath context
   4882  * @name:  the variable name
   4883  * @ns_uri:  the variable namespace URI
   4884  * @value:  the variable value or NULL
   4885  *
   4886  * Register a new variable value. If @value is NULL it unregisters
   4887  * the variable
   4888  *
   4889  * Returns 0 in case of success, -1 in case of error
   4890  */
   4891 int
   4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4893 			   const xmlChar *ns_uri,
   4894 			   xmlXPathObjectPtr value) {
   4895     if (ctxt == NULL)
   4896 	return(-1);
   4897     if (name == NULL)
   4898 	return(-1);
   4899 
   4900     if (ctxt->varHash == NULL)
   4901 	ctxt->varHash = xmlHashCreate(0);
   4902     if (ctxt->varHash == NULL)
   4903 	return(-1);
   4904     if (value == NULL)
   4905         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   4906 	                           (xmlHashDeallocator)xmlXPathFreeObject));
   4907     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   4908 			       (void *) value,
   4909 			       (xmlHashDeallocator)xmlXPathFreeObject));
   4910 }
   4911 
   4912 /**
   4913  * xmlXPathRegisterVariableLookup:
   4914  * @ctxt:  the XPath context
   4915  * @f:  the lookup function
   4916  * @data:  the lookup data
   4917  *
   4918  * register an external mechanism to do variable lookup
   4919  */
   4920 void
   4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   4922 	 xmlXPathVariableLookupFunc f, void *data) {
   4923     if (ctxt == NULL)
   4924 	return;
   4925     ctxt->varLookupFunc = f;
   4926     ctxt->varLookupData = data;
   4927 }
   4928 
   4929 /**
   4930  * xmlXPathVariableLookup:
   4931  * @ctxt:  the XPath context
   4932  * @name:  the variable name
   4933  *
   4934  * Search in the Variable array of the context for the given
   4935  * variable value.
   4936  *
   4937  * Returns a copy of the value or NULL if not found
   4938  */
   4939 xmlXPathObjectPtr
   4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4941     if (ctxt == NULL)
   4942 	return(NULL);
   4943 
   4944     if (ctxt->varLookupFunc != NULL) {
   4945 	xmlXPathObjectPtr ret;
   4946 
   4947 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   4948 	        (ctxt->varLookupData, name, NULL);
   4949 	return(ret);
   4950     }
   4951     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   4952 }
   4953 
   4954 /**
   4955  * xmlXPathVariableLookupNS:
   4956  * @ctxt:  the XPath context
   4957  * @name:  the variable name
   4958  * @ns_uri:  the variable namespace URI
   4959  *
   4960  * Search in the Variable array of the context for the given
   4961  * variable value.
   4962  *
   4963  * Returns the a copy of the value or NULL if not found
   4964  */
   4965 xmlXPathObjectPtr
   4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4967 			 const xmlChar *ns_uri) {
   4968     if (ctxt == NULL)
   4969 	return(NULL);
   4970 
   4971     if (ctxt->varLookupFunc != NULL) {
   4972 	xmlXPathObjectPtr ret;
   4973 
   4974 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   4975 	        (ctxt->varLookupData, name, ns_uri);
   4976 	if (ret != NULL) return(ret);
   4977     }
   4978 
   4979     if (ctxt->varHash == NULL)
   4980 	return(NULL);
   4981     if (name == NULL)
   4982 	return(NULL);
   4983 
   4984     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   4985 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   4986 }
   4987 
   4988 /**
   4989  * xmlXPathRegisteredVariablesCleanup:
   4990  * @ctxt:  the XPath context
   4991  *
   4992  * Cleanup the XPath context data associated to registered variables
   4993  */
   4994 void
   4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   4996     if (ctxt == NULL)
   4997 	return;
   4998 
   4999     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
   5000     ctxt->varHash = NULL;
   5001 }
   5002 
   5003 /**
   5004  * xmlXPathRegisterNs:
   5005  * @ctxt:  the XPath context
   5006  * @prefix:  the namespace prefix cannot be NULL or empty string
   5007  * @ns_uri:  the namespace name
   5008  *
   5009  * Register a new namespace. If @ns_uri is NULL it unregisters
   5010  * the namespace
   5011  *
   5012  * Returns 0 in case of success, -1 in case of error
   5013  */
   5014 int
   5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5016 			   const xmlChar *ns_uri) {
   5017     if (ctxt == NULL)
   5018 	return(-1);
   5019     if (prefix == NULL)
   5020 	return(-1);
   5021     if (prefix[0] == 0)
   5022 	return(-1);
   5023 
   5024     if (ctxt->nsHash == NULL)
   5025 	ctxt->nsHash = xmlHashCreate(10);
   5026     if (ctxt->nsHash == NULL)
   5027 	return(-1);
   5028     if (ns_uri == NULL)
   5029         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5030 	                          (xmlHashDeallocator)xmlFree));
   5031     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5032 			      (xmlHashDeallocator)xmlFree));
   5033 }
   5034 
   5035 /**
   5036  * xmlXPathNsLookup:
   5037  * @ctxt:  the XPath context
   5038  * @prefix:  the namespace prefix value
   5039  *
   5040  * Search in the namespace declaration array of the context for the given
   5041  * namespace name associated to the given prefix
   5042  *
   5043  * Returns the value or NULL if not found
   5044  */
   5045 const xmlChar *
   5046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5047     if (ctxt == NULL)
   5048 	return(NULL);
   5049     if (prefix == NULL)
   5050 	return(NULL);
   5051 
   5052 #ifdef XML_XML_NAMESPACE
   5053     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5054 	return(XML_XML_NAMESPACE);
   5055 #endif
   5056 
   5057     if (ctxt->namespaces != NULL) {
   5058 	int i;
   5059 
   5060 	for (i = 0;i < ctxt->nsNr;i++) {
   5061 	    if ((ctxt->namespaces[i] != NULL) &&
   5062 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5063 		return(ctxt->namespaces[i]->href);
   5064 	}
   5065     }
   5066 
   5067     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5068 }
   5069 
   5070 /**
   5071  * xmlXPathRegisteredNsCleanup:
   5072  * @ctxt:  the XPath context
   5073  *
   5074  * Cleanup the XPath context data associated to registered variables
   5075  */
   5076 void
   5077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5078     if (ctxt == NULL)
   5079 	return;
   5080 
   5081     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
   5082     ctxt->nsHash = NULL;
   5083 }
   5084 
   5085 /************************************************************************
   5086  *									*
   5087  *			Routines to handle Values			*
   5088  *									*
   5089  ************************************************************************/
   5090 
   5091 /* Allocations are terrible, one needs to optimize all this !!! */
   5092 
   5093 /**
   5094  * xmlXPathNewFloat:
   5095  * @val:  the double value
   5096  *
   5097  * Create a new xmlXPathObjectPtr of type double and of value @val
   5098  *
   5099  * Returns the newly created object.
   5100  */
   5101 xmlXPathObjectPtr
   5102 xmlXPathNewFloat(double val) {
   5103     xmlXPathObjectPtr ret;
   5104 
   5105     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5106     if (ret == NULL) {
   5107         xmlXPathErrMemory(NULL, "creating float object\n");
   5108 	return(NULL);
   5109     }
   5110     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5111     ret->type = XPATH_NUMBER;
   5112     ret->floatval = val;
   5113 #ifdef XP_DEBUG_OBJ_USAGE
   5114     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5115 #endif
   5116     return(ret);
   5117 }
   5118 
   5119 /**
   5120  * xmlXPathNewBoolean:
   5121  * @val:  the boolean value
   5122  *
   5123  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5124  *
   5125  * Returns the newly created object.
   5126  */
   5127 xmlXPathObjectPtr
   5128 xmlXPathNewBoolean(int val) {
   5129     xmlXPathObjectPtr ret;
   5130 
   5131     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5132     if (ret == NULL) {
   5133         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5134 	return(NULL);
   5135     }
   5136     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5137     ret->type = XPATH_BOOLEAN;
   5138     ret->boolval = (val != 0);
   5139 #ifdef XP_DEBUG_OBJ_USAGE
   5140     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5141 #endif
   5142     return(ret);
   5143 }
   5144 
   5145 /**
   5146  * xmlXPathNewString:
   5147  * @val:  the xmlChar * value
   5148  *
   5149  * Create a new xmlXPathObjectPtr of type string and of value @val
   5150  *
   5151  * Returns the newly created object.
   5152  */
   5153 xmlXPathObjectPtr
   5154 xmlXPathNewString(const xmlChar *val) {
   5155     xmlXPathObjectPtr ret;
   5156 
   5157     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5158     if (ret == NULL) {
   5159         xmlXPathErrMemory(NULL, "creating string object\n");
   5160 	return(NULL);
   5161     }
   5162     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5163     ret->type = XPATH_STRING;
   5164     if (val != NULL)
   5165 	ret->stringval = xmlStrdup(val);
   5166     else
   5167 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5168 #ifdef XP_DEBUG_OBJ_USAGE
   5169     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5170 #endif
   5171     return(ret);
   5172 }
   5173 
   5174 /**
   5175  * xmlXPathWrapString:
   5176  * @val:  the xmlChar * value
   5177  *
   5178  * Wraps the @val string into an XPath object.
   5179  *
   5180  * Returns the newly created object.
   5181  */
   5182 xmlXPathObjectPtr
   5183 xmlXPathWrapString (xmlChar *val) {
   5184     xmlXPathObjectPtr ret;
   5185 
   5186     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5187     if (ret == NULL) {
   5188         xmlXPathErrMemory(NULL, "creating string object\n");
   5189 	return(NULL);
   5190     }
   5191     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5192     ret->type = XPATH_STRING;
   5193     ret->stringval = val;
   5194 #ifdef XP_DEBUG_OBJ_USAGE
   5195     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5196 #endif
   5197     return(ret);
   5198 }
   5199 
   5200 /**
   5201  * xmlXPathNewCString:
   5202  * @val:  the char * value
   5203  *
   5204  * Create a new xmlXPathObjectPtr of type string and of value @val
   5205  *
   5206  * Returns the newly created object.
   5207  */
   5208 xmlXPathObjectPtr
   5209 xmlXPathNewCString(const char *val) {
   5210     xmlXPathObjectPtr ret;
   5211 
   5212     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5213     if (ret == NULL) {
   5214         xmlXPathErrMemory(NULL, "creating string object\n");
   5215 	return(NULL);
   5216     }
   5217     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5218     ret->type = XPATH_STRING;
   5219     ret->stringval = xmlStrdup(BAD_CAST val);
   5220 #ifdef XP_DEBUG_OBJ_USAGE
   5221     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5222 #endif
   5223     return(ret);
   5224 }
   5225 
   5226 /**
   5227  * xmlXPathWrapCString:
   5228  * @val:  the char * value
   5229  *
   5230  * Wraps a string into an XPath object.
   5231  *
   5232  * Returns the newly created object.
   5233  */
   5234 xmlXPathObjectPtr
   5235 xmlXPathWrapCString (char * val) {
   5236     return(xmlXPathWrapString((xmlChar *)(val)));
   5237 }
   5238 
   5239 /**
   5240  * xmlXPathWrapExternal:
   5241  * @val:  the user data
   5242  *
   5243  * Wraps the @val data into an XPath object.
   5244  *
   5245  * Returns the newly created object.
   5246  */
   5247 xmlXPathObjectPtr
   5248 xmlXPathWrapExternal (void *val) {
   5249     xmlXPathObjectPtr ret;
   5250 
   5251     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5252     if (ret == NULL) {
   5253         xmlXPathErrMemory(NULL, "creating user object\n");
   5254 	return(NULL);
   5255     }
   5256     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5257     ret->type = XPATH_USERS;
   5258     ret->user = val;
   5259 #ifdef XP_DEBUG_OBJ_USAGE
   5260     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5261 #endif
   5262     return(ret);
   5263 }
   5264 
   5265 /**
   5266  * xmlXPathObjectCopy:
   5267  * @val:  the original object
   5268  *
   5269  * allocate a new copy of a given object
   5270  *
   5271  * Returns the newly created object.
   5272  */
   5273 xmlXPathObjectPtr
   5274 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5275     xmlXPathObjectPtr ret;
   5276 
   5277     if (val == NULL)
   5278 	return(NULL);
   5279 
   5280     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5281     if (ret == NULL) {
   5282         xmlXPathErrMemory(NULL, "copying object\n");
   5283 	return(NULL);
   5284     }
   5285     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5286 #ifdef XP_DEBUG_OBJ_USAGE
   5287     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5288 #endif
   5289     switch (val->type) {
   5290 	case XPATH_BOOLEAN:
   5291 	case XPATH_NUMBER:
   5292 	case XPATH_POINT:
   5293 	case XPATH_RANGE:
   5294 	    break;
   5295 	case XPATH_STRING:
   5296 	    ret->stringval = xmlStrdup(val->stringval);
   5297 	    break;
   5298 	case XPATH_XSLT_TREE:
   5299 #if 0
   5300 /*
   5301   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5302   this previous handling is no longer correct, and can cause some serious
   5303   problems (ref. bug 145547)
   5304 */
   5305 	    if ((val->nodesetval != NULL) &&
   5306 		(val->nodesetval->nodeTab != NULL)) {
   5307 		xmlNodePtr cur, tmp;
   5308 		xmlDocPtr top;
   5309 
   5310 		ret->boolval = 1;
   5311 		top =  xmlNewDoc(NULL);
   5312 		top->name = (char *)
   5313 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5314 		ret->user = top;
   5315 		if (top != NULL) {
   5316 		    top->doc = top;
   5317 		    cur = val->nodesetval->nodeTab[0]->children;
   5318 		    while (cur != NULL) {
   5319 			tmp = xmlDocCopyNode(cur, top, 1);
   5320 			xmlAddChild((xmlNodePtr) top, tmp);
   5321 			cur = cur->next;
   5322 		    }
   5323 		}
   5324 
   5325 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5326 	    } else
   5327 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5328 	    /* Deallocate the copied tree value */
   5329 	    break;
   5330 #endif
   5331 	case XPATH_NODESET:
   5332 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5333 	    /* Do not deallocate the copied tree value */
   5334 	    ret->boolval = 0;
   5335 	    break;
   5336 	case XPATH_LOCATIONSET:
   5337 #ifdef LIBXML_XPTR_ENABLED
   5338 	{
   5339 	    xmlLocationSetPtr loc = val->user;
   5340 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5341 	    break;
   5342 	}
   5343 #endif
   5344         case XPATH_USERS:
   5345 	    ret->user = val->user;
   5346 	    break;
   5347         case XPATH_UNDEFINED:
   5348 	    xmlGenericError(xmlGenericErrorContext,
   5349 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5350 		    val->type);
   5351 	    break;
   5352     }
   5353     return(ret);
   5354 }
   5355 
   5356 /**
   5357  * xmlXPathFreeObject:
   5358  * @obj:  the object to free
   5359  *
   5360  * Free up an xmlXPathObjectPtr object.
   5361  */
   5362 void
   5363 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5364     if (obj == NULL) return;
   5365     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5366 	if (obj->boolval) {
   5367 #if 0
   5368 	    if (obj->user != NULL) {
   5369                 xmlXPathFreeNodeSet(obj->nodesetval);
   5370 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5371 	    } else
   5372 #endif
   5373 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5374 	    if (obj->nodesetval != NULL)
   5375 		xmlXPathFreeValueTree(obj->nodesetval);
   5376 	} else {
   5377 	    if (obj->nodesetval != NULL)
   5378 		xmlXPathFreeNodeSet(obj->nodesetval);
   5379 	}
   5380 #ifdef LIBXML_XPTR_ENABLED
   5381     } else if (obj->type == XPATH_LOCATIONSET) {
   5382 	if (obj->user != NULL)
   5383 	    xmlXPtrFreeLocationSet(obj->user);
   5384 #endif
   5385     } else if (obj->type == XPATH_STRING) {
   5386 	if (obj->stringval != NULL)
   5387 	    xmlFree(obj->stringval);
   5388     }
   5389 #ifdef XP_DEBUG_OBJ_USAGE
   5390     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5391 #endif
   5392     xmlFree(obj);
   5393 }
   5394 
   5395 /**
   5396  * xmlXPathReleaseObject:
   5397  * @obj:  the xmlXPathObjectPtr to free or to cache
   5398  *
   5399  * Depending on the state of the cache this frees the given
   5400  * XPath object or stores it in the cache.
   5401  */
   5402 static void
   5403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5404 {
   5405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5406 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5407     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5408 
   5409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5410 
   5411     if (obj == NULL)
   5412 	return;
   5413     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5414 	 xmlXPathFreeObject(obj);
   5415     } else {
   5416 	xmlXPathContextCachePtr cache =
   5417 	    (xmlXPathContextCachePtr) ctxt->cache;
   5418 
   5419 	switch (obj->type) {
   5420 	    case XPATH_NODESET:
   5421 	    case XPATH_XSLT_TREE:
   5422 		if (obj->nodesetval != NULL) {
   5423 		    if (obj->boolval) {
   5424 			/*
   5425 			* It looks like the @boolval is used for
   5426 			* evaluation if this an XSLT Result Tree Fragment.
   5427 			* TODO: Check if this assumption is correct.
   5428 			*/
   5429 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5430 			xmlXPathFreeValueTree(obj->nodesetval);
   5431 			obj->nodesetval = NULL;
   5432 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5433 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5434 					cache->maxNodeset)))
   5435 		    {
   5436 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5437 			goto obj_cached;
   5438 		    } else {
   5439 			xmlXPathFreeNodeSet(obj->nodesetval);
   5440 			obj->nodesetval = NULL;
   5441 		    }
   5442 		}
   5443 		break;
   5444 	    case XPATH_STRING:
   5445 		if (obj->stringval != NULL)
   5446 		    xmlFree(obj->stringval);
   5447 
   5448 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5449 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5450 		    goto obj_cached;
   5451 		}
   5452 		break;
   5453 	    case XPATH_BOOLEAN:
   5454 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5455 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5456 		    goto obj_cached;
   5457 		}
   5458 		break;
   5459 	    case XPATH_NUMBER:
   5460 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5461 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5462 		    goto obj_cached;
   5463 		}
   5464 		break;
   5465 #ifdef LIBXML_XPTR_ENABLED
   5466 	    case XPATH_LOCATIONSET:
   5467 		if (obj->user != NULL) {
   5468 		    xmlXPtrFreeLocationSet(obj->user);
   5469 		}
   5470 		goto free_obj;
   5471 #endif
   5472 	    default:
   5473 		goto free_obj;
   5474 	}
   5475 
   5476 	/*
   5477 	* Fallback to adding to the misc-objects slot.
   5478 	*/
   5479 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5480 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5481 	} else
   5482 	    goto free_obj;
   5483 
   5484 obj_cached:
   5485 
   5486 #ifdef XP_DEBUG_OBJ_USAGE
   5487 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5488 #endif
   5489 
   5490 	if (obj->nodesetval != NULL) {
   5491 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5492 
   5493 	    /*
   5494 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5495 	    *  the list and free the ns-nodes.
   5496 	    * URGENT TODO: Check if it's actually slowing things down.
   5497 	    *  Maybe we shouldn't try to preserve the list.
   5498 	    */
   5499 	    if (tmpset->nodeNr > 1) {
   5500 		int i;
   5501 		xmlNodePtr node;
   5502 
   5503 		for (i = 0; i < tmpset->nodeNr; i++) {
   5504 		    node = tmpset->nodeTab[i];
   5505 		    if ((node != NULL) &&
   5506 			(node->type == XML_NAMESPACE_DECL))
   5507 		    {
   5508 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5509 		    }
   5510 		}
   5511 	    } else if (tmpset->nodeNr == 1) {
   5512 		if ((tmpset->nodeTab[0] != NULL) &&
   5513 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5514 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5515 	    }
   5516 	    tmpset->nodeNr = 0;
   5517 	    memset(obj, 0, sizeof(xmlXPathObject));
   5518 	    obj->nodesetval = tmpset;
   5519 	} else
   5520 	    memset(obj, 0, sizeof(xmlXPathObject));
   5521 
   5522 	return;
   5523 
   5524 free_obj:
   5525 	/*
   5526 	* Cache is full; free the object.
   5527 	*/
   5528 	if (obj->nodesetval != NULL)
   5529 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5530 #ifdef XP_DEBUG_OBJ_USAGE
   5531 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5532 #endif
   5533 	xmlFree(obj);
   5534     }
   5535     return;
   5536 }
   5537 
   5538 
   5539 /************************************************************************
   5540  *									*
   5541  *			Type Casting Routines				*
   5542  *									*
   5543  ************************************************************************/
   5544 
   5545 /**
   5546  * xmlXPathCastBooleanToString:
   5547  * @val:  a boolean
   5548  *
   5549  * Converts a boolean to its string value.
   5550  *
   5551  * Returns a newly allocated string.
   5552  */
   5553 xmlChar *
   5554 xmlXPathCastBooleanToString (int val) {
   5555     xmlChar *ret;
   5556     if (val)
   5557 	ret = xmlStrdup((const xmlChar *) "true");
   5558     else
   5559 	ret = xmlStrdup((const xmlChar *) "false");
   5560     return(ret);
   5561 }
   5562 
   5563 /**
   5564  * xmlXPathCastNumberToString:
   5565  * @val:  a number
   5566  *
   5567  * Converts a number to its string value.
   5568  *
   5569  * Returns a newly allocated string.
   5570  */
   5571 xmlChar *
   5572 xmlXPathCastNumberToString (double val) {
   5573     xmlChar *ret;
   5574     switch (xmlXPathIsInf(val)) {
   5575     case 1:
   5576 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5577 	break;
   5578     case -1:
   5579 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5580 	break;
   5581     default:
   5582 	if (xmlXPathIsNaN(val)) {
   5583 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5584 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
   5585 	    ret = xmlStrdup((const xmlChar *) "0");
   5586 	} else {
   5587 	    /* could be improved */
   5588 	    char buf[100];
   5589 	    xmlXPathFormatNumber(val, buf, 99);
   5590 	    buf[99] = 0;
   5591 	    ret = xmlStrdup((const xmlChar *) buf);
   5592 	}
   5593     }
   5594     return(ret);
   5595 }
   5596 
   5597 /**
   5598  * xmlXPathCastNodeToString:
   5599  * @node:  a node
   5600  *
   5601  * Converts a node to its string value.
   5602  *
   5603  * Returns a newly allocated string.
   5604  */
   5605 xmlChar *
   5606 xmlXPathCastNodeToString (xmlNodePtr node) {
   5607 xmlChar *ret;
   5608     if ((ret = xmlNodeGetContent(node)) == NULL)
   5609 	ret = xmlStrdup((const xmlChar *) "");
   5610     return(ret);
   5611 }
   5612 
   5613 /**
   5614  * xmlXPathCastNodeSetToString:
   5615  * @ns:  a node-set
   5616  *
   5617  * Converts a node-set to its string value.
   5618  *
   5619  * Returns a newly allocated string.
   5620  */
   5621 xmlChar *
   5622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5623     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5624 	return(xmlStrdup((const xmlChar *) ""));
   5625 
   5626     if (ns->nodeNr > 1)
   5627 	xmlXPathNodeSetSort(ns);
   5628     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5629 }
   5630 
   5631 /**
   5632  * xmlXPathCastToString:
   5633  * @val:  an XPath object
   5634  *
   5635  * Converts an existing object to its string() equivalent
   5636  *
   5637  * Returns the allocated string value of the object, NULL in case of error.
   5638  *         It's up to the caller to free the string memory with xmlFree().
   5639  */
   5640 xmlChar *
   5641 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5642     xmlChar *ret = NULL;
   5643 
   5644     if (val == NULL)
   5645 	return(xmlStrdup((const xmlChar *) ""));
   5646     switch (val->type) {
   5647 	case XPATH_UNDEFINED:
   5648 #ifdef DEBUG_EXPR
   5649 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5650 #endif
   5651 	    ret = xmlStrdup((const xmlChar *) "");
   5652 	    break;
   5653         case XPATH_NODESET:
   5654         case XPATH_XSLT_TREE:
   5655 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5656 	    break;
   5657 	case XPATH_STRING:
   5658 	    return(xmlStrdup(val->stringval));
   5659         case XPATH_BOOLEAN:
   5660 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5661 	    break;
   5662 	case XPATH_NUMBER: {
   5663 	    ret = xmlXPathCastNumberToString(val->floatval);
   5664 	    break;
   5665 	}
   5666 	case XPATH_USERS:
   5667 	case XPATH_POINT:
   5668 	case XPATH_RANGE:
   5669 	case XPATH_LOCATIONSET:
   5670 	    TODO
   5671 	    ret = xmlStrdup((const xmlChar *) "");
   5672 	    break;
   5673     }
   5674     return(ret);
   5675 }
   5676 
   5677 /**
   5678  * xmlXPathConvertString:
   5679  * @val:  an XPath object
   5680  *
   5681  * Converts an existing object to its string() equivalent
   5682  *
   5683  * Returns the new object, the old one is freed (or the operation
   5684  *         is done directly on @val)
   5685  */
   5686 xmlXPathObjectPtr
   5687 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5688     xmlChar *res = NULL;
   5689 
   5690     if (val == NULL)
   5691 	return(xmlXPathNewCString(""));
   5692 
   5693     switch (val->type) {
   5694     case XPATH_UNDEFINED:
   5695 #ifdef DEBUG_EXPR
   5696 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5697 #endif
   5698 	break;
   5699     case XPATH_NODESET:
   5700     case XPATH_XSLT_TREE:
   5701 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5702 	break;
   5703     case XPATH_STRING:
   5704 	return(val);
   5705     case XPATH_BOOLEAN:
   5706 	res = xmlXPathCastBooleanToString(val->boolval);
   5707 	break;
   5708     case XPATH_NUMBER:
   5709 	res = xmlXPathCastNumberToString(val->floatval);
   5710 	break;
   5711     case XPATH_USERS:
   5712     case XPATH_POINT:
   5713     case XPATH_RANGE:
   5714     case XPATH_LOCATIONSET:
   5715 	TODO;
   5716 	break;
   5717     }
   5718     xmlXPathFreeObject(val);
   5719     if (res == NULL)
   5720 	return(xmlXPathNewCString(""));
   5721     return(xmlXPathWrapString(res));
   5722 }
   5723 
   5724 /**
   5725  * xmlXPathCastBooleanToNumber:
   5726  * @val:  a boolean
   5727  *
   5728  * Converts a boolean to its number value
   5729  *
   5730  * Returns the number value
   5731  */
   5732 double
   5733 xmlXPathCastBooleanToNumber(int val) {
   5734     if (val)
   5735 	return(1.0);
   5736     return(0.0);
   5737 }
   5738 
   5739 /**
   5740  * xmlXPathCastStringToNumber:
   5741  * @val:  a string
   5742  *
   5743  * Converts a string to its number value
   5744  *
   5745  * Returns the number value
   5746  */
   5747 double
   5748 xmlXPathCastStringToNumber(const xmlChar * val) {
   5749     return(xmlXPathStringEvalNumber(val));
   5750 }
   5751 
   5752 /**
   5753  * xmlXPathCastNodeToNumber:
   5754  * @node:  a node
   5755  *
   5756  * Converts a node to its number value
   5757  *
   5758  * Returns the number value
   5759  */
   5760 double
   5761 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5762     xmlChar *strval;
   5763     double ret;
   5764 
   5765     if (node == NULL)
   5766 	return(xmlXPathNAN);
   5767     strval = xmlXPathCastNodeToString(node);
   5768     if (strval == NULL)
   5769 	return(xmlXPathNAN);
   5770     ret = xmlXPathCastStringToNumber(strval);
   5771     xmlFree(strval);
   5772 
   5773     return(ret);
   5774 }
   5775 
   5776 /**
   5777  * xmlXPathCastNodeSetToNumber:
   5778  * @ns:  a node-set
   5779  *
   5780  * Converts a node-set to its number value
   5781  *
   5782  * Returns the number value
   5783  */
   5784 double
   5785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5786     xmlChar *str;
   5787     double ret;
   5788 
   5789     if (ns == NULL)
   5790 	return(xmlXPathNAN);
   5791     str = xmlXPathCastNodeSetToString(ns);
   5792     ret = xmlXPathCastStringToNumber(str);
   5793     xmlFree(str);
   5794     return(ret);
   5795 }
   5796 
   5797 /**
   5798  * xmlXPathCastToNumber:
   5799  * @val:  an XPath object
   5800  *
   5801  * Converts an XPath object to its number value
   5802  *
   5803  * Returns the number value
   5804  */
   5805 double
   5806 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5807     double ret = 0.0;
   5808 
   5809     if (val == NULL)
   5810 	return(xmlXPathNAN);
   5811     switch (val->type) {
   5812     case XPATH_UNDEFINED:
   5813 #ifdef DEGUB_EXPR
   5814 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5815 #endif
   5816 	ret = xmlXPathNAN;
   5817 	break;
   5818     case XPATH_NODESET:
   5819     case XPATH_XSLT_TREE:
   5820 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5821 	break;
   5822     case XPATH_STRING:
   5823 	ret = xmlXPathCastStringToNumber(val->stringval);
   5824 	break;
   5825     case XPATH_NUMBER:
   5826 	ret = val->floatval;
   5827 	break;
   5828     case XPATH_BOOLEAN:
   5829 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5830 	break;
   5831     case XPATH_USERS:
   5832     case XPATH_POINT:
   5833     case XPATH_RANGE:
   5834     case XPATH_LOCATIONSET:
   5835 	TODO;
   5836 	ret = xmlXPathNAN;
   5837 	break;
   5838     }
   5839     return(ret);
   5840 }
   5841 
   5842 /**
   5843  * xmlXPathConvertNumber:
   5844  * @val:  an XPath object
   5845  *
   5846  * Converts an existing object to its number() equivalent
   5847  *
   5848  * Returns the new object, the old one is freed (or the operation
   5849  *         is done directly on @val)
   5850  */
   5851 xmlXPathObjectPtr
   5852 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5853     xmlXPathObjectPtr ret;
   5854 
   5855     if (val == NULL)
   5856 	return(xmlXPathNewFloat(0.0));
   5857     if (val->type == XPATH_NUMBER)
   5858 	return(val);
   5859     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5860     xmlXPathFreeObject(val);
   5861     return(ret);
   5862 }
   5863 
   5864 /**
   5865  * xmlXPathCastNumberToBoolean:
   5866  * @val:  a number
   5867  *
   5868  * Converts a number to its boolean value
   5869  *
   5870  * Returns the boolean value
   5871  */
   5872 int
   5873 xmlXPathCastNumberToBoolean (double val) {
   5874      if (xmlXPathIsNaN(val) || (val == 0.0))
   5875 	 return(0);
   5876      return(1);
   5877 }
   5878 
   5879 /**
   5880  * xmlXPathCastStringToBoolean:
   5881  * @val:  a string
   5882  *
   5883  * Converts a string to its boolean value
   5884  *
   5885  * Returns the boolean value
   5886  */
   5887 int
   5888 xmlXPathCastStringToBoolean (const xmlChar *val) {
   5889     if ((val == NULL) || (xmlStrlen(val) == 0))
   5890 	return(0);
   5891     return(1);
   5892 }
   5893 
   5894 /**
   5895  * xmlXPathCastNodeSetToBoolean:
   5896  * @ns:  a node-set
   5897  *
   5898  * Converts a node-set to its boolean value
   5899  *
   5900  * Returns the boolean value
   5901  */
   5902 int
   5903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   5904     if ((ns == NULL) || (ns->nodeNr == 0))
   5905 	return(0);
   5906     return(1);
   5907 }
   5908 
   5909 /**
   5910  * xmlXPathCastToBoolean:
   5911  * @val:  an XPath object
   5912  *
   5913  * Converts an XPath object to its boolean value
   5914  *
   5915  * Returns the boolean value
   5916  */
   5917 int
   5918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   5919     int ret = 0;
   5920 
   5921     if (val == NULL)
   5922 	return(0);
   5923     switch (val->type) {
   5924     case XPATH_UNDEFINED:
   5925 #ifdef DEBUG_EXPR
   5926 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   5927 #endif
   5928 	ret = 0;
   5929 	break;
   5930     case XPATH_NODESET:
   5931     case XPATH_XSLT_TREE:
   5932 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   5933 	break;
   5934     case XPATH_STRING:
   5935 	ret = xmlXPathCastStringToBoolean(val->stringval);
   5936 	break;
   5937     case XPATH_NUMBER:
   5938 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   5939 	break;
   5940     case XPATH_BOOLEAN:
   5941 	ret = val->boolval;
   5942 	break;
   5943     case XPATH_USERS:
   5944     case XPATH_POINT:
   5945     case XPATH_RANGE:
   5946     case XPATH_LOCATIONSET:
   5947 	TODO;
   5948 	ret = 0;
   5949 	break;
   5950     }
   5951     return(ret);
   5952 }
   5953 
   5954 
   5955 /**
   5956  * xmlXPathConvertBoolean:
   5957  * @val:  an XPath object
   5958  *
   5959  * Converts an existing object to its boolean() equivalent
   5960  *
   5961  * Returns the new object, the old one is freed (or the operation
   5962  *         is done directly on @val)
   5963  */
   5964 xmlXPathObjectPtr
   5965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   5966     xmlXPathObjectPtr ret;
   5967 
   5968     if (val == NULL)
   5969 	return(xmlXPathNewBoolean(0));
   5970     if (val->type == XPATH_BOOLEAN)
   5971 	return(val);
   5972     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   5973     xmlXPathFreeObject(val);
   5974     return(ret);
   5975 }
   5976 
   5977 /************************************************************************
   5978  *									*
   5979  *		Routines to handle XPath contexts			*
   5980  *									*
   5981  ************************************************************************/
   5982 
   5983 /**
   5984  * xmlXPathNewContext:
   5985  * @doc:  the XML document
   5986  *
   5987  * Create a new xmlXPathContext
   5988  *
   5989  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   5990  */
   5991 xmlXPathContextPtr
   5992 xmlXPathNewContext(xmlDocPtr doc) {
   5993     xmlXPathContextPtr ret;
   5994 
   5995     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   5996     if (ret == NULL) {
   5997         xmlXPathErrMemory(NULL, "creating context\n");
   5998 	return(NULL);
   5999     }
   6000     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6001     ret->doc = doc;
   6002     ret->node = NULL;
   6003 
   6004     ret->varHash = NULL;
   6005 
   6006     ret->nb_types = 0;
   6007     ret->max_types = 0;
   6008     ret->types = NULL;
   6009 
   6010     ret->funcHash = xmlHashCreate(0);
   6011 
   6012     ret->nb_axis = 0;
   6013     ret->max_axis = 0;
   6014     ret->axis = NULL;
   6015 
   6016     ret->nsHash = NULL;
   6017     ret->user = NULL;
   6018 
   6019     ret->contextSize = -1;
   6020     ret->proximityPosition = -1;
   6021 
   6022 #ifdef XP_DEFAULT_CACHE_ON
   6023     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6024 	xmlXPathFreeContext(ret);
   6025 	return(NULL);
   6026     }
   6027 #endif
   6028 
   6029     xmlXPathRegisterAllFunctions(ret);
   6030 
   6031     return(ret);
   6032 }
   6033 
   6034 /**
   6035  * xmlXPathFreeContext:
   6036  * @ctxt:  the context to free
   6037  *
   6038  * Free up an xmlXPathContext
   6039  */
   6040 void
   6041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6042     if (ctxt == NULL) return;
   6043 
   6044     if (ctxt->cache != NULL)
   6045 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6046     xmlXPathRegisteredNsCleanup(ctxt);
   6047     xmlXPathRegisteredFuncsCleanup(ctxt);
   6048     xmlXPathRegisteredVariablesCleanup(ctxt);
   6049     xmlResetError(&ctxt->lastError);
   6050     xmlFree(ctxt);
   6051 }
   6052 
   6053 /************************************************************************
   6054  *									*
   6055  *		Routines to handle XPath parser contexts		*
   6056  *									*
   6057  ************************************************************************/
   6058 
   6059 #define CHECK_CTXT(ctxt)						\
   6060     if (ctxt == NULL) {						\
   6061 	__xmlRaiseError(NULL, NULL, NULL,				\
   6062 		NULL, NULL, XML_FROM_XPATH,				\
   6063 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6064 		__FILE__, __LINE__,					\
   6065 		NULL, NULL, NULL, 0, 0,					\
   6066 		"NULL context pointer\n");				\
   6067 	return(NULL);							\
   6068     }									\
   6069 
   6070 #define CHECK_CTXT_NEG(ctxt)						\
   6071     if (ctxt == NULL) {						\
   6072 	__xmlRaiseError(NULL, NULL, NULL,				\
   6073 		NULL, NULL, XML_FROM_XPATH,				\
   6074 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6075 		__FILE__, __LINE__,					\
   6076 		NULL, NULL, NULL, 0, 0,					\
   6077 		"NULL context pointer\n");				\
   6078 	return(-1);							\
   6079     }									\
   6080 
   6081 
   6082 #define CHECK_CONTEXT(ctxt)						\
   6083     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6084         (ctxt->doc->children == NULL)) {				\
   6085 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6086 	return(NULL);							\
   6087     }
   6088 
   6089 
   6090 /**
   6091  * xmlXPathNewParserContext:
   6092  * @str:  the XPath expression
   6093  * @ctxt:  the XPath context
   6094  *
   6095  * Create a new xmlXPathParserContext
   6096  *
   6097  * Returns the xmlXPathParserContext just allocated.
   6098  */
   6099 xmlXPathParserContextPtr
   6100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6101     xmlXPathParserContextPtr ret;
   6102 
   6103     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6104     if (ret == NULL) {
   6105         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6106 	return(NULL);
   6107     }
   6108     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6109     ret->cur = ret->base = str;
   6110     ret->context = ctxt;
   6111 
   6112     ret->comp = xmlXPathNewCompExpr();
   6113     if (ret->comp == NULL) {
   6114 	xmlFree(ret->valueTab);
   6115 	xmlFree(ret);
   6116 	return(NULL);
   6117     }
   6118     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6119         ret->comp->dict = ctxt->dict;
   6120 	xmlDictReference(ret->comp->dict);
   6121     }
   6122 
   6123     return(ret);
   6124 }
   6125 
   6126 /**
   6127  * xmlXPathCompParserContext:
   6128  * @comp:  the XPath compiled expression
   6129  * @ctxt:  the XPath context
   6130  *
   6131  * Create a new xmlXPathParserContext when processing a compiled expression
   6132  *
   6133  * Returns the xmlXPathParserContext just allocated.
   6134  */
   6135 static xmlXPathParserContextPtr
   6136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6137     xmlXPathParserContextPtr ret;
   6138 
   6139     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6140     if (ret == NULL) {
   6141         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6142 	return(NULL);
   6143     }
   6144     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6145 
   6146     /* Allocate the value stack */
   6147     ret->valueTab = (xmlXPathObjectPtr *)
   6148                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6149     if (ret->valueTab == NULL) {
   6150 	xmlFree(ret);
   6151 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6152 	return(NULL);
   6153     }
   6154     ret->valueNr = 0;
   6155     ret->valueMax = 10;
   6156     ret->value = NULL;
   6157 
   6158     ret->context = ctxt;
   6159     ret->comp = comp;
   6160 
   6161     return(ret);
   6162 }
   6163 
   6164 /**
   6165  * xmlXPathFreeParserContext:
   6166  * @ctxt:  the context to free
   6167  *
   6168  * Free up an xmlXPathParserContext
   6169  */
   6170 void
   6171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6172     if (ctxt->valueTab != NULL) {
   6173         xmlFree(ctxt->valueTab);
   6174     }
   6175     if (ctxt->comp != NULL) {
   6176 #ifdef XPATH_STREAMING
   6177 	if (ctxt->comp->stream != NULL) {
   6178 	    xmlFreePatternList(ctxt->comp->stream);
   6179 	    ctxt->comp->stream = NULL;
   6180 	}
   6181 #endif
   6182 	xmlXPathFreeCompExpr(ctxt->comp);
   6183     }
   6184     xmlFree(ctxt);
   6185 }
   6186 
   6187 /************************************************************************
   6188  *									*
   6189  *		The implicit core function library			*
   6190  *									*
   6191  ************************************************************************/
   6192 
   6193 /**
   6194  * xmlXPathNodeValHash:
   6195  * @node:  a node pointer
   6196  *
   6197  * Function computing the beginning of the string value of the node,
   6198  * used to speed up comparisons
   6199  *
   6200  * Returns an int usable as a hash
   6201  */
   6202 static unsigned int
   6203 xmlXPathNodeValHash(xmlNodePtr node) {
   6204     int len = 2;
   6205     const xmlChar * string = NULL;
   6206     xmlNodePtr tmp = NULL;
   6207     unsigned int ret = 0;
   6208 
   6209     if (node == NULL)
   6210 	return(0);
   6211 
   6212     if (node->type == XML_DOCUMENT_NODE) {
   6213 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6214 	if (tmp == NULL)
   6215 	    node = node->children;
   6216 	else
   6217 	    node = tmp;
   6218 
   6219 	if (node == NULL)
   6220 	    return(0);
   6221     }
   6222 
   6223     switch (node->type) {
   6224 	case XML_COMMENT_NODE:
   6225 	case XML_PI_NODE:
   6226 	case XML_CDATA_SECTION_NODE:
   6227 	case XML_TEXT_NODE:
   6228 	    string = node->content;
   6229 	    if (string == NULL)
   6230 		return(0);
   6231 	    if (string[0] == 0)
   6232 		return(0);
   6233 	    return(((unsigned int) string[0]) +
   6234 		   (((unsigned int) string[1]) << 8));
   6235 	case XML_NAMESPACE_DECL:
   6236 	    string = ((xmlNsPtr)node)->href;
   6237 	    if (string == NULL)
   6238 		return(0);
   6239 	    if (string[0] == 0)
   6240 		return(0);
   6241 	    return(((unsigned int) string[0]) +
   6242 		   (((unsigned int) string[1]) << 8));
   6243 	case XML_ATTRIBUTE_NODE:
   6244 	    tmp = ((xmlAttrPtr) node)->children;
   6245 	    break;
   6246 	case XML_ELEMENT_NODE:
   6247 	    tmp = node->children;
   6248 	    break;
   6249 	default:
   6250 	    return(0);
   6251     }
   6252     while (tmp != NULL) {
   6253 	switch (tmp->type) {
   6254 	    case XML_COMMENT_NODE:
   6255 	    case XML_PI_NODE:
   6256 	    case XML_CDATA_SECTION_NODE:
   6257 	    case XML_TEXT_NODE:
   6258 		string = tmp->content;
   6259 		break;
   6260 	    case XML_NAMESPACE_DECL:
   6261 		string = ((xmlNsPtr)tmp)->href;
   6262 		break;
   6263 	    default:
   6264 		break;
   6265 	}
   6266 	if ((string != NULL) && (string[0] != 0)) {
   6267 	    if (len == 1) {
   6268 		return(ret + (((unsigned int) string[0]) << 8));
   6269 	    }
   6270 	    if (string[1] == 0) {
   6271 		len = 1;
   6272 		ret = (unsigned int) string[0];
   6273 	    } else {
   6274 		return(((unsigned int) string[0]) +
   6275 		       (((unsigned int) string[1]) << 8));
   6276 	    }
   6277 	}
   6278 	/*
   6279 	 * Skip to next node
   6280 	 */
   6281 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6282 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6283 		tmp = tmp->children;
   6284 		continue;
   6285 	    }
   6286 	}
   6287 	if (tmp == node)
   6288 	    break;
   6289 
   6290 	if (tmp->next != NULL) {
   6291 	    tmp = tmp->next;
   6292 	    continue;
   6293 	}
   6294 
   6295 	do {
   6296 	    tmp = tmp->parent;
   6297 	    if (tmp == NULL)
   6298 		break;
   6299 	    if (tmp == node) {
   6300 		tmp = NULL;
   6301 		break;
   6302 	    }
   6303 	    if (tmp->next != NULL) {
   6304 		tmp = tmp->next;
   6305 		break;
   6306 	    }
   6307 	} while (tmp != NULL);
   6308     }
   6309     return(ret);
   6310 }
   6311 
   6312 /**
   6313  * xmlXPathStringHash:
   6314  * @string:  a string
   6315  *
   6316  * Function computing the beginning of the string value of the node,
   6317  * used to speed up comparisons
   6318  *
   6319  * Returns an int usable as a hash
   6320  */
   6321 static unsigned int
   6322 xmlXPathStringHash(const xmlChar * string) {
   6323     if (string == NULL)
   6324 	return((unsigned int) 0);
   6325     if (string[0] == 0)
   6326 	return(0);
   6327     return(((unsigned int) string[0]) +
   6328 	   (((unsigned int) string[1]) << 8));
   6329 }
   6330 
   6331 /**
   6332  * xmlXPathCompareNodeSetFloat:
   6333  * @ctxt:  the XPath Parser context
   6334  * @inf:  less than (1) or greater than (0)
   6335  * @strict:  is the comparison strict
   6336  * @arg:  the node set
   6337  * @f:  the value
   6338  *
   6339  * Implement the compare operation between a nodeset and a number
   6340  *     @ns < @val    (1, 1, ...
   6341  *     @ns <= @val   (1, 0, ...
   6342  *     @ns > @val    (0, 1, ...
   6343  *     @ns >= @val   (0, 0, ...
   6344  *
   6345  * If one object to be compared is a node-set and the other is a number,
   6346  * then the comparison will be true if and only if there is a node in the
   6347  * node-set such that the result of performing the comparison on the number
   6348  * to be compared and on the result of converting the string-value of that
   6349  * node to a number using the number function is true.
   6350  *
   6351  * Returns 0 or 1 depending on the results of the test.
   6352  */
   6353 static int
   6354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6355 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6356     int i, ret = 0;
   6357     xmlNodeSetPtr ns;
   6358     xmlChar *str2;
   6359 
   6360     if ((f == NULL) || (arg == NULL) ||
   6361 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6362 	xmlXPathReleaseObject(ctxt->context, arg);
   6363 	xmlXPathReleaseObject(ctxt->context, f);
   6364         return(0);
   6365     }
   6366     ns = arg->nodesetval;
   6367     if (ns != NULL) {
   6368 	for (i = 0;i < ns->nodeNr;i++) {
   6369 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6370 	     if (str2 != NULL) {
   6371 		 valuePush(ctxt,
   6372 			   xmlXPathCacheNewString(ctxt->context, str2));
   6373 		 xmlFree(str2);
   6374 		 xmlXPathNumberFunction(ctxt, 1);
   6375 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6376 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6377 		 if (ret)
   6378 		     break;
   6379 	     }
   6380 	}
   6381     }
   6382     xmlXPathReleaseObject(ctxt->context, arg);
   6383     xmlXPathReleaseObject(ctxt->context, f);
   6384     return(ret);
   6385 }
   6386 
   6387 /**
   6388  * xmlXPathCompareNodeSetString:
   6389  * @ctxt:  the XPath Parser context
   6390  * @inf:  less than (1) or greater than (0)
   6391  * @strict:  is the comparison strict
   6392  * @arg:  the node set
   6393  * @s:  the value
   6394  *
   6395  * Implement the compare operation between a nodeset and a string
   6396  *     @ns < @val    (1, 1, ...
   6397  *     @ns <= @val   (1, 0, ...
   6398  *     @ns > @val    (0, 1, ...
   6399  *     @ns >= @val   (0, 0, ...
   6400  *
   6401  * If one object to be compared is a node-set and the other is a string,
   6402  * then the comparison will be true if and only if there is a node in
   6403  * the node-set such that the result of performing the comparison on the
   6404  * string-value of the node and the other string is true.
   6405  *
   6406  * Returns 0 or 1 depending on the results of the test.
   6407  */
   6408 static int
   6409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6410 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6411     int i, ret = 0;
   6412     xmlNodeSetPtr ns;
   6413     xmlChar *str2;
   6414 
   6415     if ((s == NULL) || (arg == NULL) ||
   6416 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6417 	xmlXPathReleaseObject(ctxt->context, arg);
   6418 	xmlXPathReleaseObject(ctxt->context, s);
   6419         return(0);
   6420     }
   6421     ns = arg->nodesetval;
   6422     if (ns != NULL) {
   6423 	for (i = 0;i < ns->nodeNr;i++) {
   6424 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6425 	     if (str2 != NULL) {
   6426 		 valuePush(ctxt,
   6427 			   xmlXPathCacheNewString(ctxt->context, str2));
   6428 		 xmlFree(str2);
   6429 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6430 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6431 		 if (ret)
   6432 		     break;
   6433 	     }
   6434 	}
   6435     }
   6436     xmlXPathReleaseObject(ctxt->context, arg);
   6437     xmlXPathReleaseObject(ctxt->context, s);
   6438     return(ret);
   6439 }
   6440 
   6441 /**
   6442  * xmlXPathCompareNodeSets:
   6443  * @inf:  less than (1) or greater than (0)
   6444  * @strict:  is the comparison strict
   6445  * @arg1:  the first node set object
   6446  * @arg2:  the second node set object
   6447  *
   6448  * Implement the compare operation on nodesets:
   6449  *
   6450  * If both objects to be compared are node-sets, then the comparison
   6451  * will be true if and only if there is a node in the first node-set
   6452  * and a node in the second node-set such that the result of performing
   6453  * the comparison on the string-values of the two nodes is true.
   6454  * ....
   6455  * When neither object to be compared is a node-set and the operator
   6456  * is <=, <, >= or >, then the objects are compared by converting both
   6457  * objects to numbers and comparing the numbers according to IEEE 754.
   6458  * ....
   6459  * The number function converts its argument to a number as follows:
   6460  *  - a string that consists of optional whitespace followed by an
   6461  *    optional minus sign followed by a Number followed by whitespace
   6462  *    is converted to the IEEE 754 number that is nearest (according
   6463  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6464  *    represented by the string; any other string is converted to NaN
   6465  *
   6466  * Conclusion all nodes need to be converted first to their string value
   6467  * and then the comparison must be done when possible
   6468  */
   6469 static int
   6470 xmlXPathCompareNodeSets(int inf, int strict,
   6471 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6472     int i, j, init = 0;
   6473     double val1;
   6474     double *values2;
   6475     int ret = 0;
   6476     xmlNodeSetPtr ns1;
   6477     xmlNodeSetPtr ns2;
   6478 
   6479     if ((arg1 == NULL) ||
   6480 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6481 	xmlXPathFreeObject(arg2);
   6482         return(0);
   6483     }
   6484     if ((arg2 == NULL) ||
   6485 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6486 	xmlXPathFreeObject(arg1);
   6487 	xmlXPathFreeObject(arg2);
   6488         return(0);
   6489     }
   6490 
   6491     ns1 = arg1->nodesetval;
   6492     ns2 = arg2->nodesetval;
   6493 
   6494     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6495 	xmlXPathFreeObject(arg1);
   6496 	xmlXPathFreeObject(arg2);
   6497 	return(0);
   6498     }
   6499     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6500 	xmlXPathFreeObject(arg1);
   6501 	xmlXPathFreeObject(arg2);
   6502 	return(0);
   6503     }
   6504 
   6505     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6506     if (values2 == NULL) {
   6507         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6508 	xmlXPathFreeObject(arg1);
   6509 	xmlXPathFreeObject(arg2);
   6510 	return(0);
   6511     }
   6512     for (i = 0;i < ns1->nodeNr;i++) {
   6513 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6514 	if (xmlXPathIsNaN(val1))
   6515 	    continue;
   6516 	for (j = 0;j < ns2->nodeNr;j++) {
   6517 	    if (init == 0) {
   6518 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6519 	    }
   6520 	    if (xmlXPathIsNaN(values2[j]))
   6521 		continue;
   6522 	    if (inf && strict)
   6523 		ret = (val1 < values2[j]);
   6524 	    else if (inf && !strict)
   6525 		ret = (val1 <= values2[j]);
   6526 	    else if (!inf && strict)
   6527 		ret = (val1 > values2[j]);
   6528 	    else if (!inf && !strict)
   6529 		ret = (val1 >= values2[j]);
   6530 	    if (ret)
   6531 		break;
   6532 	}
   6533 	if (ret)
   6534 	    break;
   6535 	init = 1;
   6536     }
   6537     xmlFree(values2);
   6538     xmlXPathFreeObject(arg1);
   6539     xmlXPathFreeObject(arg2);
   6540     return(ret);
   6541 }
   6542 
   6543 /**
   6544  * xmlXPathCompareNodeSetValue:
   6545  * @ctxt:  the XPath Parser context
   6546  * @inf:  less than (1) or greater than (0)
   6547  * @strict:  is the comparison strict
   6548  * @arg:  the node set
   6549  * @val:  the value
   6550  *
   6551  * Implement the compare operation between a nodeset and a value
   6552  *     @ns < @val    (1, 1, ...
   6553  *     @ns <= @val   (1, 0, ...
   6554  *     @ns > @val    (0, 1, ...
   6555  *     @ns >= @val   (0, 0, ...
   6556  *
   6557  * If one object to be compared is a node-set and the other is a boolean,
   6558  * then the comparison will be true if and only if the result of performing
   6559  * the comparison on the boolean and on the result of converting
   6560  * the node-set to a boolean using the boolean function is true.
   6561  *
   6562  * Returns 0 or 1 depending on the results of the test.
   6563  */
   6564 static int
   6565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6566 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6567     if ((val == NULL) || (arg == NULL) ||
   6568 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6569         return(0);
   6570 
   6571     switch(val->type) {
   6572         case XPATH_NUMBER:
   6573 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6574         case XPATH_NODESET:
   6575         case XPATH_XSLT_TREE:
   6576 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6577         case XPATH_STRING:
   6578 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6579         case XPATH_BOOLEAN:
   6580 	    valuePush(ctxt, arg);
   6581 	    xmlXPathBooleanFunction(ctxt, 1);
   6582 	    valuePush(ctxt, val);
   6583 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6584 	default:
   6585 	    TODO
   6586     }
   6587     return(0);
   6588 }
   6589 
   6590 /**
   6591  * xmlXPathEqualNodeSetString:
   6592  * @arg:  the nodeset object argument
   6593  * @str:  the string to compare to.
   6594  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6595  *
   6596  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6597  * If one object to be compared is a node-set and the other is a string,
   6598  * then the comparison will be true if and only if there is a node in
   6599  * the node-set such that the result of performing the comparison on the
   6600  * string-value of the node and the other string is true.
   6601  *
   6602  * Returns 0 or 1 depending on the results of the test.
   6603  */
   6604 static int
   6605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6606 {
   6607     int i;
   6608     xmlNodeSetPtr ns;
   6609     xmlChar *str2;
   6610     unsigned int hash;
   6611 
   6612     if ((str == NULL) || (arg == NULL) ||
   6613         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6614         return (0);
   6615     ns = arg->nodesetval;
   6616     /*
   6617      * A NULL nodeset compared with a string is always false
   6618      * (since there is no node equal, and no node not equal)
   6619      */
   6620     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6621         return (0);
   6622     hash = xmlXPathStringHash(str);
   6623     for (i = 0; i < ns->nodeNr; i++) {
   6624         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6625             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6626             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6627                 xmlFree(str2);
   6628 		if (neq)
   6629 		    continue;
   6630                 return (1);
   6631 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6632 		if (neq)
   6633 		    continue;
   6634                 return (1);
   6635             } else if (neq) {
   6636 		if (str2 != NULL)
   6637 		    xmlFree(str2);
   6638 		return (1);
   6639 	    }
   6640             if (str2 != NULL)
   6641                 xmlFree(str2);
   6642         } else if (neq)
   6643 	    return (1);
   6644     }
   6645     return (0);
   6646 }
   6647 
   6648 /**
   6649  * xmlXPathEqualNodeSetFloat:
   6650  * @arg:  the nodeset object argument
   6651  * @f:  the float to compare to
   6652  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6653  *
   6654  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6655  * If one object to be compared is a node-set and the other is a number,
   6656  * then the comparison will be true if and only if there is a node in
   6657  * the node-set such that the result of performing the comparison on the
   6658  * number to be compared and on the result of converting the string-value
   6659  * of that node to a number using the number function is true.
   6660  *
   6661  * Returns 0 or 1 depending on the results of the test.
   6662  */
   6663 static int
   6664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6665     xmlXPathObjectPtr arg, double f, int neq) {
   6666   int i, ret=0;
   6667   xmlNodeSetPtr ns;
   6668   xmlChar *str2;
   6669   xmlXPathObjectPtr val;
   6670   double v;
   6671 
   6672     if ((arg == NULL) ||
   6673 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6674         return(0);
   6675 
   6676     ns = arg->nodesetval;
   6677     if (ns != NULL) {
   6678 	for (i=0;i<ns->nodeNr;i++) {
   6679 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6680 	    if (str2 != NULL) {
   6681 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6682 		xmlFree(str2);
   6683 		xmlXPathNumberFunction(ctxt, 1);
   6684 		val = valuePop(ctxt);
   6685 		v = val->floatval;
   6686 		xmlXPathReleaseObject(ctxt->context, val);
   6687 		if (!xmlXPathIsNaN(v)) {
   6688 		    if ((!neq) && (v==f)) {
   6689 			ret = 1;
   6690 			break;
   6691 		    } else if ((neq) && (v!=f)) {
   6692 			ret = 1;
   6693 			break;
   6694 		    }
   6695 		} else {	/* NaN is unequal to any value */
   6696 		    if (neq)
   6697 			ret = 1;
   6698 		}
   6699 	    }
   6700 	}
   6701     }
   6702 
   6703     return(ret);
   6704 }
   6705 
   6706 
   6707 /**
   6708  * xmlXPathEqualNodeSets:
   6709  * @arg1:  first nodeset object argument
   6710  * @arg2:  second nodeset object argument
   6711  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6712  *
   6713  * Implement the equal / not equal operation on XPath nodesets:
   6714  * @arg1 == @arg2  or  @arg1 != @arg2
   6715  * If both objects to be compared are node-sets, then the comparison
   6716  * will be true if and only if there is a node in the first node-set and
   6717  * a node in the second node-set such that the result of performing the
   6718  * comparison on the string-values of the two nodes is true.
   6719  *
   6720  * (needless to say, this is a costly operation)
   6721  *
   6722  * Returns 0 or 1 depending on the results of the test.
   6723  */
   6724 static int
   6725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6726     int i, j;
   6727     unsigned int *hashs1;
   6728     unsigned int *hashs2;
   6729     xmlChar **values1;
   6730     xmlChar **values2;
   6731     int ret = 0;
   6732     xmlNodeSetPtr ns1;
   6733     xmlNodeSetPtr ns2;
   6734 
   6735     if ((arg1 == NULL) ||
   6736 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6737         return(0);
   6738     if ((arg2 == NULL) ||
   6739 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6740         return(0);
   6741 
   6742     ns1 = arg1->nodesetval;
   6743     ns2 = arg2->nodesetval;
   6744 
   6745     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6746 	return(0);
   6747     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6748 	return(0);
   6749 
   6750     /*
   6751      * for equal, check if there is a node pertaining to both sets
   6752      */
   6753     if (neq == 0)
   6754 	for (i = 0;i < ns1->nodeNr;i++)
   6755 	    for (j = 0;j < ns2->nodeNr;j++)
   6756 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6757 		    return(1);
   6758 
   6759     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6760     if (values1 == NULL) {
   6761         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6762 	return(0);
   6763     }
   6764     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6765     if (hashs1 == NULL) {
   6766         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6767 	xmlFree(values1);
   6768 	return(0);
   6769     }
   6770     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6771     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6772     if (values2 == NULL) {
   6773         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6774 	xmlFree(hashs1);
   6775 	xmlFree(values1);
   6776 	return(0);
   6777     }
   6778     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6779     if (hashs2 == NULL) {
   6780         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6781 	xmlFree(hashs1);
   6782 	xmlFree(values1);
   6783 	xmlFree(values2);
   6784 	return(0);
   6785     }
   6786     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6787     for (i = 0;i < ns1->nodeNr;i++) {
   6788 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6789 	for (j = 0;j < ns2->nodeNr;j++) {
   6790 	    if (i == 0)
   6791 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6792 	    if (hashs1[i] != hashs2[j]) {
   6793 		if (neq) {
   6794 		    ret = 1;
   6795 		    break;
   6796 		}
   6797 	    }
   6798 	    else {
   6799 		if (values1[i] == NULL)
   6800 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6801 		if (values2[j] == NULL)
   6802 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6803 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6804 		if (ret)
   6805 		    break;
   6806 	    }
   6807 	}
   6808 	if (ret)
   6809 	    break;
   6810     }
   6811     for (i = 0;i < ns1->nodeNr;i++)
   6812 	if (values1[i] != NULL)
   6813 	    xmlFree(values1[i]);
   6814     for (j = 0;j < ns2->nodeNr;j++)
   6815 	if (values2[j] != NULL)
   6816 	    xmlFree(values2[j]);
   6817     xmlFree(values1);
   6818     xmlFree(values2);
   6819     xmlFree(hashs1);
   6820     xmlFree(hashs2);
   6821     return(ret);
   6822 }
   6823 
   6824 static int
   6825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6826   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6827     int ret = 0;
   6828     /*
   6829      *At this point we are assured neither arg1 nor arg2
   6830      *is a nodeset, so we can just pick the appropriate routine.
   6831      */
   6832     switch (arg1->type) {
   6833         case XPATH_UNDEFINED:
   6834 #ifdef DEBUG_EXPR
   6835 	    xmlGenericError(xmlGenericErrorContext,
   6836 		    "Equal: undefined\n");
   6837 #endif
   6838 	    break;
   6839         case XPATH_BOOLEAN:
   6840 	    switch (arg2->type) {
   6841 	        case XPATH_UNDEFINED:
   6842 #ifdef DEBUG_EXPR
   6843 		    xmlGenericError(xmlGenericErrorContext,
   6844 			    "Equal: undefined\n");
   6845 #endif
   6846 		    break;
   6847 		case XPATH_BOOLEAN:
   6848 #ifdef DEBUG_EXPR
   6849 		    xmlGenericError(xmlGenericErrorContext,
   6850 			    "Equal: %d boolean %d \n",
   6851 			    arg1->boolval, arg2->boolval);
   6852 #endif
   6853 		    ret = (arg1->boolval == arg2->boolval);
   6854 		    break;
   6855 		case XPATH_NUMBER:
   6856 		    ret = (arg1->boolval ==
   6857 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   6858 		    break;
   6859 		case XPATH_STRING:
   6860 		    if ((arg2->stringval == NULL) ||
   6861 			(arg2->stringval[0] == 0)) ret = 0;
   6862 		    else
   6863 			ret = 1;
   6864 		    ret = (arg1->boolval == ret);
   6865 		    break;
   6866 		case XPATH_USERS:
   6867 		case XPATH_POINT:
   6868 		case XPATH_RANGE:
   6869 		case XPATH_LOCATIONSET:
   6870 		    TODO
   6871 		    break;
   6872 		case XPATH_NODESET:
   6873 		case XPATH_XSLT_TREE:
   6874 		    break;
   6875 	    }
   6876 	    break;
   6877         case XPATH_NUMBER:
   6878 	    switch (arg2->type) {
   6879 	        case XPATH_UNDEFINED:
   6880 #ifdef DEBUG_EXPR
   6881 		    xmlGenericError(xmlGenericErrorContext,
   6882 			    "Equal: undefined\n");
   6883 #endif
   6884 		    break;
   6885 		case XPATH_BOOLEAN:
   6886 		    ret = (arg2->boolval==
   6887 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   6888 		    break;
   6889 		case XPATH_STRING:
   6890 		    valuePush(ctxt, arg2);
   6891 		    xmlXPathNumberFunction(ctxt, 1);
   6892 		    arg2 = valuePop(ctxt);
   6893 		    /* no break on purpose */
   6894 		case XPATH_NUMBER:
   6895 		    /* Hand check NaN and Infinity equalities */
   6896 		    if (xmlXPathIsNaN(arg1->floatval) ||
   6897 			    xmlXPathIsNaN(arg2->floatval)) {
   6898 		        ret = 0;
   6899 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   6900 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   6901 			    ret = 1;
   6902 			else
   6903 			    ret = 0;
   6904 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   6905 			if (xmlXPathIsInf(arg2->floatval) == -1)
   6906 			    ret = 1;
   6907 			else
   6908 			    ret = 0;
   6909 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   6910 			if (xmlXPathIsInf(arg1->floatval) == 1)
   6911 			    ret = 1;
   6912 			else
   6913 			    ret = 0;
   6914 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   6915 			if (xmlXPathIsInf(arg1->floatval) == -1)
   6916 			    ret = 1;
   6917 			else
   6918 			    ret = 0;
   6919 		    } else {
   6920 		        ret = (arg1->floatval == arg2->floatval);
   6921 		    }
   6922 		    break;
   6923 		case XPATH_USERS:
   6924 		case XPATH_POINT:
   6925 		case XPATH_RANGE:
   6926 		case XPATH_LOCATIONSET:
   6927 		    TODO
   6928 		    break;
   6929 		case XPATH_NODESET:
   6930 		case XPATH_XSLT_TREE:
   6931 		    break;
   6932 	    }
   6933 	    break;
   6934         case XPATH_STRING:
   6935 	    switch (arg2->type) {
   6936 	        case XPATH_UNDEFINED:
   6937 #ifdef DEBUG_EXPR
   6938 		    xmlGenericError(xmlGenericErrorContext,
   6939 			    "Equal: undefined\n");
   6940 #endif
   6941 		    break;
   6942 		case XPATH_BOOLEAN:
   6943 		    if ((arg1->stringval == NULL) ||
   6944 			(arg1->stringval[0] == 0)) ret = 0;
   6945 		    else
   6946 			ret = 1;
   6947 		    ret = (arg2->boolval == ret);
   6948 		    break;
   6949 		case XPATH_STRING:
   6950 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   6951 		    break;
   6952 		case XPATH_NUMBER:
   6953 		    valuePush(ctxt, arg1);
   6954 		    xmlXPathNumberFunction(ctxt, 1);
   6955 		    arg1 = valuePop(ctxt);
   6956 		    /* Hand check NaN and Infinity equalities */
   6957 		    if (xmlXPathIsNaN(arg1->floatval) ||
   6958 			    xmlXPathIsNaN(arg2->floatval)) {
   6959 		        ret = 0;
   6960 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   6961 			if (xmlXPathIsInf(arg2->floatval) == 1)
   6962 			    ret = 1;
   6963 			else
   6964 			    ret = 0;
   6965 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   6966 			if (xmlXPathIsInf(arg2->floatval) == -1)
   6967 			    ret = 1;
   6968 			else
   6969 			    ret = 0;
   6970 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   6971 			if (xmlXPathIsInf(arg1->floatval) == 1)
   6972 			    ret = 1;
   6973 			else
   6974 			    ret = 0;
   6975 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   6976 			if (xmlXPathIsInf(arg1->floatval) == -1)
   6977 			    ret = 1;
   6978 			else
   6979 			    ret = 0;
   6980 		    } else {
   6981 		        ret = (arg1->floatval == arg2->floatval);
   6982 		    }
   6983 		    break;
   6984 		case XPATH_USERS:
   6985 		case XPATH_POINT:
   6986 		case XPATH_RANGE:
   6987 		case XPATH_LOCATIONSET:
   6988 		    TODO
   6989 		    break;
   6990 		case XPATH_NODESET:
   6991 		case XPATH_XSLT_TREE:
   6992 		    break;
   6993 	    }
   6994 	    break;
   6995         case XPATH_USERS:
   6996 	case XPATH_POINT:
   6997 	case XPATH_RANGE:
   6998 	case XPATH_LOCATIONSET:
   6999 	    TODO
   7000 	    break;
   7001 	case XPATH_NODESET:
   7002 	case XPATH_XSLT_TREE:
   7003 	    break;
   7004     }
   7005     xmlXPathReleaseObject(ctxt->context, arg1);
   7006     xmlXPathReleaseObject(ctxt->context, arg2);
   7007     return(ret);
   7008 }
   7009 
   7010 /**
   7011  * xmlXPathEqualValues:
   7012  * @ctxt:  the XPath Parser context
   7013  *
   7014  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7015  *
   7016  * Returns 0 or 1 depending on the results of the test.
   7017  */
   7018 int
   7019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7020     xmlXPathObjectPtr arg1, arg2, argtmp;
   7021     int ret = 0;
   7022 
   7023     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7024     arg2 = valuePop(ctxt);
   7025     arg1 = valuePop(ctxt);
   7026     if ((arg1 == NULL) || (arg2 == NULL)) {
   7027 	if (arg1 != NULL)
   7028 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7029 	else
   7030 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7031 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7032     }
   7033 
   7034     if (arg1 == arg2) {
   7035 #ifdef DEBUG_EXPR
   7036         xmlGenericError(xmlGenericErrorContext,
   7037 		"Equal: by pointer\n");
   7038 #endif
   7039 	xmlXPathFreeObject(arg1);
   7040         return(1);
   7041     }
   7042 
   7043     /*
   7044      *If either argument is a nodeset, it's a 'special case'
   7045      */
   7046     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7047       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7048 	/*
   7049 	 *Hack it to assure arg1 is the nodeset
   7050 	 */
   7051 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7052 		argtmp = arg2;
   7053 		arg2 = arg1;
   7054 		arg1 = argtmp;
   7055 	}
   7056 	switch (arg2->type) {
   7057 	    case XPATH_UNDEFINED:
   7058 #ifdef DEBUG_EXPR
   7059 		xmlGenericError(xmlGenericErrorContext,
   7060 			"Equal: undefined\n");
   7061 #endif
   7062 		break;
   7063 	    case XPATH_NODESET:
   7064 	    case XPATH_XSLT_TREE:
   7065 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7066 		break;
   7067 	    case XPATH_BOOLEAN:
   7068 		if ((arg1->nodesetval == NULL) ||
   7069 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7070 		else
   7071 		    ret = 1;
   7072 		ret = (ret == arg2->boolval);
   7073 		break;
   7074 	    case XPATH_NUMBER:
   7075 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7076 		break;
   7077 	    case XPATH_STRING:
   7078 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7079 		break;
   7080 	    case XPATH_USERS:
   7081 	    case XPATH_POINT:
   7082 	    case XPATH_RANGE:
   7083 	    case XPATH_LOCATIONSET:
   7084 		TODO
   7085 		break;
   7086 	}
   7087 	xmlXPathReleaseObject(ctxt->context, arg1);
   7088 	xmlXPathReleaseObject(ctxt->context, arg2);
   7089 	return(ret);
   7090     }
   7091 
   7092     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7093 }
   7094 
   7095 /**
   7096  * xmlXPathNotEqualValues:
   7097  * @ctxt:  the XPath Parser context
   7098  *
   7099  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7100  *
   7101  * Returns 0 or 1 depending on the results of the test.
   7102  */
   7103 int
   7104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7105     xmlXPathObjectPtr arg1, arg2, argtmp;
   7106     int ret = 0;
   7107 
   7108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7109     arg2 = valuePop(ctxt);
   7110     arg1 = valuePop(ctxt);
   7111     if ((arg1 == NULL) || (arg2 == NULL)) {
   7112 	if (arg1 != NULL)
   7113 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7114 	else
   7115 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7116 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7117     }
   7118 
   7119     if (arg1 == arg2) {
   7120 #ifdef DEBUG_EXPR
   7121         xmlGenericError(xmlGenericErrorContext,
   7122 		"NotEqual: by pointer\n");
   7123 #endif
   7124 	xmlXPathReleaseObject(ctxt->context, arg1);
   7125         return(0);
   7126     }
   7127 
   7128     /*
   7129      *If either argument is a nodeset, it's a 'special case'
   7130      */
   7131     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7132       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7133 	/*
   7134 	 *Hack it to assure arg1 is the nodeset
   7135 	 */
   7136 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7137 		argtmp = arg2;
   7138 		arg2 = arg1;
   7139 		arg1 = argtmp;
   7140 	}
   7141 	switch (arg2->type) {
   7142 	    case XPATH_UNDEFINED:
   7143 #ifdef DEBUG_EXPR
   7144 		xmlGenericError(xmlGenericErrorContext,
   7145 			"NotEqual: undefined\n");
   7146 #endif
   7147 		break;
   7148 	    case XPATH_NODESET:
   7149 	    case XPATH_XSLT_TREE:
   7150 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7151 		break;
   7152 	    case XPATH_BOOLEAN:
   7153 		if ((arg1->nodesetval == NULL) ||
   7154 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7155 		else
   7156 		    ret = 1;
   7157 		ret = (ret != arg2->boolval);
   7158 		break;
   7159 	    case XPATH_NUMBER:
   7160 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7161 		break;
   7162 	    case XPATH_STRING:
   7163 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7164 		break;
   7165 	    case XPATH_USERS:
   7166 	    case XPATH_POINT:
   7167 	    case XPATH_RANGE:
   7168 	    case XPATH_LOCATIONSET:
   7169 		TODO
   7170 		break;
   7171 	}
   7172 	xmlXPathReleaseObject(ctxt->context, arg1);
   7173 	xmlXPathReleaseObject(ctxt->context, arg2);
   7174 	return(ret);
   7175     }
   7176 
   7177     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7178 }
   7179 
   7180 /**
   7181  * xmlXPathCompareValues:
   7182  * @ctxt:  the XPath Parser context
   7183  * @inf:  less than (1) or greater than (0)
   7184  * @strict:  is the comparison strict
   7185  *
   7186  * Implement the compare operation on XPath objects:
   7187  *     @arg1 < @arg2    (1, 1, ...
   7188  *     @arg1 <= @arg2   (1, 0, ...
   7189  *     @arg1 > @arg2    (0, 1, ...
   7190  *     @arg1 >= @arg2   (0, 0, ...
   7191  *
   7192  * When neither object to be compared is a node-set and the operator is
   7193  * <=, <, >=, >, then the objects are compared by converted both objects
   7194  * to numbers and comparing the numbers according to IEEE 754. The <
   7195  * comparison will be true if and only if the first number is less than the
   7196  * second number. The <= comparison will be true if and only if the first
   7197  * number is less than or equal to the second number. The > comparison
   7198  * will be true if and only if the first number is greater than the second
   7199  * number. The >= comparison will be true if and only if the first number
   7200  * is greater than or equal to the second number.
   7201  *
   7202  * Returns 1 if the comparison succeeded, 0 if it failed
   7203  */
   7204 int
   7205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7206     int ret = 0, arg1i = 0, arg2i = 0;
   7207     xmlXPathObjectPtr arg1, arg2;
   7208 
   7209     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7210     arg2 = valuePop(ctxt);
   7211     arg1 = valuePop(ctxt);
   7212     if ((arg1 == NULL) || (arg2 == NULL)) {
   7213 	if (arg1 != NULL)
   7214 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7215 	else
   7216 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7217 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7218     }
   7219 
   7220     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7221       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7222 	/*
   7223 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7224 	 * are not freed from within this routine; they will be freed from the
   7225 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7226 	 */
   7227 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7228 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7229 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7230 	} else {
   7231 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7232 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7233 			                          arg1, arg2);
   7234 	    } else {
   7235 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7236 			                          arg2, arg1);
   7237 	    }
   7238 	}
   7239 	return(ret);
   7240     }
   7241 
   7242     if (arg1->type != XPATH_NUMBER) {
   7243 	valuePush(ctxt, arg1);
   7244 	xmlXPathNumberFunction(ctxt, 1);
   7245 	arg1 = valuePop(ctxt);
   7246     }
   7247     if (arg1->type != XPATH_NUMBER) {
   7248 	xmlXPathFreeObject(arg1);
   7249 	xmlXPathFreeObject(arg2);
   7250 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7251     }
   7252     if (arg2->type != XPATH_NUMBER) {
   7253 	valuePush(ctxt, arg2);
   7254 	xmlXPathNumberFunction(ctxt, 1);
   7255 	arg2 = valuePop(ctxt);
   7256     }
   7257     if (arg2->type != XPATH_NUMBER) {
   7258 	xmlXPathReleaseObject(ctxt->context, arg1);
   7259 	xmlXPathReleaseObject(ctxt->context, arg2);
   7260 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7261     }
   7262     /*
   7263      * Add tests for infinity and nan
   7264      * => feedback on 3.4 for Inf and NaN
   7265      */
   7266     /* Hand check NaN and Infinity comparisons */
   7267     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7268 	ret=0;
   7269     } else {
   7270 	arg1i=xmlXPathIsInf(arg1->floatval);
   7271 	arg2i=xmlXPathIsInf(arg2->floatval);
   7272 	if (inf && strict) {
   7273 	    if ((arg1i == -1 && arg2i != -1) ||
   7274 		(arg2i == 1 && arg1i != 1)) {
   7275 		ret = 1;
   7276 	    } else if (arg1i == 0 && arg2i == 0) {
   7277 		ret = (arg1->floatval < arg2->floatval);
   7278 	    } else {
   7279 		ret = 0;
   7280 	    }
   7281 	}
   7282 	else if (inf && !strict) {
   7283 	    if (arg1i == -1 || arg2i == 1) {
   7284 		ret = 1;
   7285 	    } else if (arg1i == 0 && arg2i == 0) {
   7286 		ret = (arg1->floatval <= arg2->floatval);
   7287 	    } else {
   7288 		ret = 0;
   7289 	    }
   7290 	}
   7291 	else if (!inf && strict) {
   7292 	    if ((arg1i == 1 && arg2i != 1) ||
   7293 		(arg2i == -1 && arg1i != -1)) {
   7294 		ret = 1;
   7295 	    } else if (arg1i == 0 && arg2i == 0) {
   7296 		ret = (arg1->floatval > arg2->floatval);
   7297 	    } else {
   7298 		ret = 0;
   7299 	    }
   7300 	}
   7301 	else if (!inf && !strict) {
   7302 	    if (arg1i == 1 || arg2i == -1) {
   7303 		ret = 1;
   7304 	    } else if (arg1i == 0 && arg2i == 0) {
   7305 		ret = (arg1->floatval >= arg2->floatval);
   7306 	    } else {
   7307 		ret = 0;
   7308 	    }
   7309 	}
   7310     }
   7311     xmlXPathReleaseObject(ctxt->context, arg1);
   7312     xmlXPathReleaseObject(ctxt->context, arg2);
   7313     return(ret);
   7314 }
   7315 
   7316 /**
   7317  * xmlXPathValueFlipSign:
   7318  * @ctxt:  the XPath Parser context
   7319  *
   7320  * Implement the unary - operation on an XPath object
   7321  * The numeric operators convert their operands to numbers as if
   7322  * by calling the number function.
   7323  */
   7324 void
   7325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7326     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7327     CAST_TO_NUMBER;
   7328     CHECK_TYPE(XPATH_NUMBER);
   7329     if (xmlXPathIsNaN(ctxt->value->floatval))
   7330         ctxt->value->floatval=xmlXPathNAN;
   7331     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
   7332         ctxt->value->floatval=xmlXPathNINF;
   7333     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
   7334         ctxt->value->floatval=xmlXPathPINF;
   7335     else if (ctxt->value->floatval == 0) {
   7336         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
   7337 	    ctxt->value->floatval = xmlXPathNZERO;
   7338 	else
   7339 	    ctxt->value->floatval = 0;
   7340     }
   7341     else
   7342         ctxt->value->floatval = - ctxt->value->floatval;
   7343 }
   7344 
   7345 /**
   7346  * xmlXPathAddValues:
   7347  * @ctxt:  the XPath Parser context
   7348  *
   7349  * Implement the add operation on XPath objects:
   7350  * The numeric operators convert their operands to numbers as if
   7351  * by calling the number function.
   7352  */
   7353 void
   7354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7355     xmlXPathObjectPtr arg;
   7356     double val;
   7357 
   7358     arg = valuePop(ctxt);
   7359     if (arg == NULL)
   7360 	XP_ERROR(XPATH_INVALID_OPERAND);
   7361     val = xmlXPathCastToNumber(arg);
   7362     xmlXPathReleaseObject(ctxt->context, arg);
   7363     CAST_TO_NUMBER;
   7364     CHECK_TYPE(XPATH_NUMBER);
   7365     ctxt->value->floatval += val;
   7366 }
   7367 
   7368 /**
   7369  * xmlXPathSubValues:
   7370  * @ctxt:  the XPath Parser context
   7371  *
   7372  * Implement the subtraction operation on XPath objects:
   7373  * The numeric operators convert their operands to numbers as if
   7374  * by calling the number function.
   7375  */
   7376 void
   7377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7378     xmlXPathObjectPtr arg;
   7379     double val;
   7380 
   7381     arg = valuePop(ctxt);
   7382     if (arg == NULL)
   7383 	XP_ERROR(XPATH_INVALID_OPERAND);
   7384     val = xmlXPathCastToNumber(arg);
   7385     xmlXPathReleaseObject(ctxt->context, arg);
   7386     CAST_TO_NUMBER;
   7387     CHECK_TYPE(XPATH_NUMBER);
   7388     ctxt->value->floatval -= val;
   7389 }
   7390 
   7391 /**
   7392  * xmlXPathMultValues:
   7393  * @ctxt:  the XPath Parser context
   7394  *
   7395  * Implement the multiply operation on XPath objects:
   7396  * The numeric operators convert their operands to numbers as if
   7397  * by calling the number function.
   7398  */
   7399 void
   7400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7401     xmlXPathObjectPtr arg;
   7402     double val;
   7403 
   7404     arg = valuePop(ctxt);
   7405     if (arg == NULL)
   7406 	XP_ERROR(XPATH_INVALID_OPERAND);
   7407     val = xmlXPathCastToNumber(arg);
   7408     xmlXPathReleaseObject(ctxt->context, arg);
   7409     CAST_TO_NUMBER;
   7410     CHECK_TYPE(XPATH_NUMBER);
   7411     ctxt->value->floatval *= val;
   7412 }
   7413 
   7414 /**
   7415  * xmlXPathDivValues:
   7416  * @ctxt:  the XPath Parser context
   7417  *
   7418  * Implement the div operation on XPath objects @arg1 / @arg2:
   7419  * The numeric operators convert their operands to numbers as if
   7420  * by calling the number function.
   7421  */
   7422 void
   7423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7424     xmlXPathObjectPtr arg;
   7425     double val;
   7426 
   7427     arg = valuePop(ctxt);
   7428     if (arg == NULL)
   7429 	XP_ERROR(XPATH_INVALID_OPERAND);
   7430     val = xmlXPathCastToNumber(arg);
   7431     xmlXPathReleaseObject(ctxt->context, arg);
   7432     CAST_TO_NUMBER;
   7433     CHECK_TYPE(XPATH_NUMBER);
   7434     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
   7435 	ctxt->value->floatval = xmlXPathNAN;
   7436     else if (val == 0 && xmlXPathGetSign(val) != 0) {
   7437 	if (ctxt->value->floatval == 0)
   7438 	    ctxt->value->floatval = xmlXPathNAN;
   7439 	else if (ctxt->value->floatval > 0)
   7440 	    ctxt->value->floatval = xmlXPathNINF;
   7441 	else if (ctxt->value->floatval < 0)
   7442 	    ctxt->value->floatval = xmlXPathPINF;
   7443     }
   7444     else if (val == 0) {
   7445 	if (ctxt->value->floatval == 0)
   7446 	    ctxt->value->floatval = xmlXPathNAN;
   7447 	else if (ctxt->value->floatval > 0)
   7448 	    ctxt->value->floatval = xmlXPathPINF;
   7449 	else if (ctxt->value->floatval < 0)
   7450 	    ctxt->value->floatval = xmlXPathNINF;
   7451     } else
   7452 	ctxt->value->floatval /= val;
   7453 }
   7454 
   7455 /**
   7456  * xmlXPathModValues:
   7457  * @ctxt:  the XPath Parser context
   7458  *
   7459  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7460  * The numeric operators convert their operands to numbers as if
   7461  * by calling the number function.
   7462  */
   7463 void
   7464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7465     xmlXPathObjectPtr arg;
   7466     double arg1, arg2;
   7467 
   7468     arg = valuePop(ctxt);
   7469     if (arg == NULL)
   7470 	XP_ERROR(XPATH_INVALID_OPERAND);
   7471     arg2 = xmlXPathCastToNumber(arg);
   7472     xmlXPathReleaseObject(ctxt->context, arg);
   7473     CAST_TO_NUMBER;
   7474     CHECK_TYPE(XPATH_NUMBER);
   7475     arg1 = ctxt->value->floatval;
   7476     if (arg2 == 0)
   7477 	ctxt->value->floatval = xmlXPathNAN;
   7478     else {
   7479 	ctxt->value->floatval = fmod(arg1, arg2);
   7480     }
   7481 }
   7482 
   7483 /************************************************************************
   7484  *									*
   7485  *		The traversal functions					*
   7486  *									*
   7487  ************************************************************************/
   7488 
   7489 /*
   7490  * A traversal function enumerates nodes along an axis.
   7491  * Initially it must be called with NULL, and it indicates
   7492  * termination on the axis by returning NULL.
   7493  */
   7494 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7495                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7496 
   7497 /*
   7498  * xmlXPathTraversalFunctionExt:
   7499  * A traversal function enumerates nodes along an axis.
   7500  * Initially it must be called with NULL, and it indicates
   7501  * termination on the axis by returning NULL.
   7502  * The context node of the traversal is specified via @contextNode.
   7503  */
   7504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7505                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7506 
   7507 /*
   7508  * xmlXPathNodeSetMergeFunction:
   7509  * Used for merging node sets in xmlXPathCollectAndTest().
   7510  */
   7511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7512 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7513 
   7514 
   7515 /**
   7516  * xmlXPathNextSelf:
   7517  * @ctxt:  the XPath Parser context
   7518  * @cur:  the current node in the traversal
   7519  *
   7520  * Traversal function for the "self" direction
   7521  * The self axis contains just the context node itself
   7522  *
   7523  * Returns the next element following that axis
   7524  */
   7525 xmlNodePtr
   7526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7527     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7528     if (cur == NULL)
   7529         return(ctxt->context->node);
   7530     return(NULL);
   7531 }
   7532 
   7533 /**
   7534  * xmlXPathNextChild:
   7535  * @ctxt:  the XPath Parser context
   7536  * @cur:  the current node in the traversal
   7537  *
   7538  * Traversal function for the "child" direction
   7539  * The child axis contains the children of the context node in document order.
   7540  *
   7541  * Returns the next element following that axis
   7542  */
   7543 xmlNodePtr
   7544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7545     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7546     if (cur == NULL) {
   7547 	if (ctxt->context->node == NULL) return(NULL);
   7548 	switch (ctxt->context->node->type) {
   7549             case XML_ELEMENT_NODE:
   7550             case XML_TEXT_NODE:
   7551             case XML_CDATA_SECTION_NODE:
   7552             case XML_ENTITY_REF_NODE:
   7553             case XML_ENTITY_NODE:
   7554             case XML_PI_NODE:
   7555             case XML_COMMENT_NODE:
   7556             case XML_NOTATION_NODE:
   7557             case XML_DTD_NODE:
   7558 		return(ctxt->context->node->children);
   7559             case XML_DOCUMENT_NODE:
   7560             case XML_DOCUMENT_TYPE_NODE:
   7561             case XML_DOCUMENT_FRAG_NODE:
   7562             case XML_HTML_DOCUMENT_NODE:
   7563 #ifdef LIBXML_DOCB_ENABLED
   7564 	    case XML_DOCB_DOCUMENT_NODE:
   7565 #endif
   7566 		return(((xmlDocPtr) ctxt->context->node)->children);
   7567 	    case XML_ELEMENT_DECL:
   7568 	    case XML_ATTRIBUTE_DECL:
   7569 	    case XML_ENTITY_DECL:
   7570             case XML_ATTRIBUTE_NODE:
   7571 	    case XML_NAMESPACE_DECL:
   7572 	    case XML_XINCLUDE_START:
   7573 	    case XML_XINCLUDE_END:
   7574 		return(NULL);
   7575 	}
   7576 	return(NULL);
   7577     }
   7578     if ((cur->type == XML_DOCUMENT_NODE) ||
   7579         (cur->type == XML_HTML_DOCUMENT_NODE))
   7580 	return(NULL);
   7581     return(cur->next);
   7582 }
   7583 
   7584 /**
   7585  * xmlXPathNextChildElement:
   7586  * @ctxt:  the XPath Parser context
   7587  * @cur:  the current node in the traversal
   7588  *
   7589  * Traversal function for the "child" direction and nodes of type element.
   7590  * The child axis contains the children of the context node in document order.
   7591  *
   7592  * Returns the next element following that axis
   7593  */
   7594 static xmlNodePtr
   7595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7596     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7597     if (cur == NULL) {
   7598 	cur = ctxt->context->node;
   7599 	if (cur == NULL) return(NULL);
   7600 	/*
   7601 	* Get the first element child.
   7602 	*/
   7603 	switch (cur->type) {
   7604             case XML_ELEMENT_NODE:
   7605 	    case XML_DOCUMENT_FRAG_NODE:
   7606 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7607             case XML_ENTITY_NODE:
   7608 		cur = cur->children;
   7609 		if (cur != NULL) {
   7610 		    if (cur->type == XML_ELEMENT_NODE)
   7611 			return(cur);
   7612 		    do {
   7613 			cur = cur->next;
   7614 		    } while ((cur != NULL) &&
   7615 			(cur->type != XML_ELEMENT_NODE));
   7616 		    return(cur);
   7617 		}
   7618 		return(NULL);
   7619             case XML_DOCUMENT_NODE:
   7620             case XML_HTML_DOCUMENT_NODE:
   7621 #ifdef LIBXML_DOCB_ENABLED
   7622 	    case XML_DOCB_DOCUMENT_NODE:
   7623 #endif
   7624 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7625 	    default:
   7626 		return(NULL);
   7627 	}
   7628 	return(NULL);
   7629     }
   7630     /*
   7631     * Get the next sibling element node.
   7632     */
   7633     switch (cur->type) {
   7634 	case XML_ELEMENT_NODE:
   7635 	case XML_TEXT_NODE:
   7636 	case XML_ENTITY_REF_NODE:
   7637 	case XML_ENTITY_NODE:
   7638 	case XML_CDATA_SECTION_NODE:
   7639 	case XML_PI_NODE:
   7640 	case XML_COMMENT_NODE:
   7641 	case XML_XINCLUDE_END:
   7642 	    break;
   7643 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7644 	default:
   7645 	    return(NULL);
   7646     }
   7647     if (cur->next != NULL) {
   7648 	if (cur->next->type == XML_ELEMENT_NODE)
   7649 	    return(cur->next);
   7650 	cur = cur->next;
   7651 	do {
   7652 	    cur = cur->next;
   7653 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7654 	return(cur);
   7655     }
   7656     return(NULL);
   7657 }
   7658 
   7659 /**
   7660  * xmlXPathNextDescendantOrSelfElemParent:
   7661  * @ctxt:  the XPath Parser context
   7662  * @cur:  the current node in the traversal
   7663  *
   7664  * Traversal function for the "descendant-or-self" axis.
   7665  * Additionally it returns only nodes which can be parents of
   7666  * element nodes.
   7667  *
   7668  *
   7669  * Returns the next element following that axis
   7670  */
   7671 static xmlNodePtr
   7672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7673 				       xmlNodePtr contextNode)
   7674 {
   7675     if (cur == NULL) {
   7676 	if (contextNode == NULL)
   7677 	    return(NULL);
   7678 	switch (contextNode->type) {
   7679 	    case XML_ELEMENT_NODE:
   7680 	    case XML_XINCLUDE_START:
   7681 	    case XML_DOCUMENT_FRAG_NODE:
   7682 	    case XML_DOCUMENT_NODE:
   7683 #ifdef LIBXML_DOCB_ENABLED
   7684 	    case XML_DOCB_DOCUMENT_NODE:
   7685 #endif
   7686 	    case XML_HTML_DOCUMENT_NODE:
   7687 		return(contextNode);
   7688 	    default:
   7689 		return(NULL);
   7690 	}
   7691 	return(NULL);
   7692     } else {
   7693 	xmlNodePtr start = cur;
   7694 
   7695 	while (cur != NULL) {
   7696 	    switch (cur->type) {
   7697 		case XML_ELEMENT_NODE:
   7698 		/* TODO: OK to have XInclude here? */
   7699 		case XML_XINCLUDE_START:
   7700 		case XML_DOCUMENT_FRAG_NODE:
   7701 		    if (cur != start)
   7702 			return(cur);
   7703 		    if (cur->children != NULL) {
   7704 			cur = cur->children;
   7705 			continue;
   7706 		    }
   7707 		    break;
   7708 		/* Not sure if we need those here. */
   7709 		case XML_DOCUMENT_NODE:
   7710 #ifdef LIBXML_DOCB_ENABLED
   7711 		case XML_DOCB_DOCUMENT_NODE:
   7712 #endif
   7713 		case XML_HTML_DOCUMENT_NODE:
   7714 		    if (cur != start)
   7715 			return(cur);
   7716 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7717 		default:
   7718 		    break;
   7719 	    }
   7720 
   7721 next_sibling:
   7722 	    if ((cur == NULL) || (cur == contextNode))
   7723 		return(NULL);
   7724 	    if (cur->next != NULL) {
   7725 		cur = cur->next;
   7726 	    } else {
   7727 		cur = cur->parent;
   7728 		goto next_sibling;
   7729 	    }
   7730 	}
   7731     }
   7732     return(NULL);
   7733 }
   7734 
   7735 /**
   7736  * xmlXPathNextDescendant:
   7737  * @ctxt:  the XPath Parser context
   7738  * @cur:  the current node in the traversal
   7739  *
   7740  * Traversal function for the "descendant" direction
   7741  * the descendant axis contains the descendants of the context node in document
   7742  * order; a descendant is a child or a child of a child and so on.
   7743  *
   7744  * Returns the next element following that axis
   7745  */
   7746 xmlNodePtr
   7747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7748     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7749     if (cur == NULL) {
   7750 	if (ctxt->context->node == NULL)
   7751 	    return(NULL);
   7752 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7753 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7754 	    return(NULL);
   7755 
   7756         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7757 	    return(ctxt->context->doc->children);
   7758         return(ctxt->context->node->children);
   7759     }
   7760 
   7761     if (cur->children != NULL) {
   7762 	/*
   7763 	 * Do not descend on entities declarations
   7764 	 */
   7765 	if (cur->children->type != XML_ENTITY_DECL) {
   7766 	    cur = cur->children;
   7767 	    /*
   7768 	     * Skip DTDs
   7769 	     */
   7770 	    if (cur->type != XML_DTD_NODE)
   7771 		return(cur);
   7772 	}
   7773     }
   7774 
   7775     if (cur == ctxt->context->node) return(NULL);
   7776 
   7777     while (cur->next != NULL) {
   7778 	cur = cur->next;
   7779 	if ((cur->type != XML_ENTITY_DECL) &&
   7780 	    (cur->type != XML_DTD_NODE))
   7781 	    return(cur);
   7782     }
   7783 
   7784     do {
   7785         cur = cur->parent;
   7786 	if (cur == NULL) break;
   7787 	if (cur == ctxt->context->node) return(NULL);
   7788 	if (cur->next != NULL) {
   7789 	    cur = cur->next;
   7790 	    return(cur);
   7791 	}
   7792     } while (cur != NULL);
   7793     return(cur);
   7794 }
   7795 
   7796 /**
   7797  * xmlXPathNextDescendantOrSelf:
   7798  * @ctxt:  the XPath Parser context
   7799  * @cur:  the current node in the traversal
   7800  *
   7801  * Traversal function for the "descendant-or-self" direction
   7802  * the descendant-or-self axis contains the context node and the descendants
   7803  * of the context node in document order; thus the context node is the first
   7804  * node on the axis, and the first child of the context node is the second node
   7805  * on the axis
   7806  *
   7807  * Returns the next element following that axis
   7808  */
   7809 xmlNodePtr
   7810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7811     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7812     if (cur == NULL) {
   7813 	if (ctxt->context->node == NULL)
   7814 	    return(NULL);
   7815 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7816 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7817 	    return(NULL);
   7818         return(ctxt->context->node);
   7819     }
   7820 
   7821     return(xmlXPathNextDescendant(ctxt, cur));
   7822 }
   7823 
   7824 /**
   7825  * xmlXPathNextParent:
   7826  * @ctxt:  the XPath Parser context
   7827  * @cur:  the current node in the traversal
   7828  *
   7829  * Traversal function for the "parent" direction
   7830  * The parent axis contains the parent of the context node, if there is one.
   7831  *
   7832  * Returns the next element following that axis
   7833  */
   7834 xmlNodePtr
   7835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7836     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7837     /*
   7838      * the parent of an attribute or namespace node is the element
   7839      * to which the attribute or namespace node is attached
   7840      * Namespace handling !!!
   7841      */
   7842     if (cur == NULL) {
   7843 	if (ctxt->context->node == NULL) return(NULL);
   7844 	switch (ctxt->context->node->type) {
   7845             case XML_ELEMENT_NODE:
   7846             case XML_TEXT_NODE:
   7847             case XML_CDATA_SECTION_NODE:
   7848             case XML_ENTITY_REF_NODE:
   7849             case XML_ENTITY_NODE:
   7850             case XML_PI_NODE:
   7851             case XML_COMMENT_NODE:
   7852             case XML_NOTATION_NODE:
   7853             case XML_DTD_NODE:
   7854 	    case XML_ELEMENT_DECL:
   7855 	    case XML_ATTRIBUTE_DECL:
   7856 	    case XML_XINCLUDE_START:
   7857 	    case XML_XINCLUDE_END:
   7858 	    case XML_ENTITY_DECL:
   7859 		if (ctxt->context->node->parent == NULL)
   7860 		    return((xmlNodePtr) ctxt->context->doc);
   7861 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7862 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7863 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7864 				 BAD_CAST "fake node libxslt"))))
   7865 		    return(NULL);
   7866 		return(ctxt->context->node->parent);
   7867             case XML_ATTRIBUTE_NODE: {
   7868 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7869 
   7870 		return(att->parent);
   7871 	    }
   7872             case XML_DOCUMENT_NODE:
   7873             case XML_DOCUMENT_TYPE_NODE:
   7874             case XML_DOCUMENT_FRAG_NODE:
   7875             case XML_HTML_DOCUMENT_NODE:
   7876 #ifdef LIBXML_DOCB_ENABLED
   7877 	    case XML_DOCB_DOCUMENT_NODE:
   7878 #endif
   7879                 return(NULL);
   7880 	    case XML_NAMESPACE_DECL: {
   7881 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7882 
   7883 		if ((ns->next != NULL) &&
   7884 		    (ns->next->type != XML_NAMESPACE_DECL))
   7885 		    return((xmlNodePtr) ns->next);
   7886                 return(NULL);
   7887 	    }
   7888 	}
   7889     }
   7890     return(NULL);
   7891 }
   7892 
   7893 /**
   7894  * xmlXPathNextAncestor:
   7895  * @ctxt:  the XPath Parser context
   7896  * @cur:  the current node in the traversal
   7897  *
   7898  * Traversal function for the "ancestor" direction
   7899  * the ancestor axis contains the ancestors of the context node; the ancestors
   7900  * of the context node consist of the parent of context node and the parent's
   7901  * parent and so on; the nodes are ordered in reverse document order; thus the
   7902  * parent is the first node on the axis, and the parent's parent is the second
   7903  * node on the axis
   7904  *
   7905  * Returns the next element following that axis
   7906  */
   7907 xmlNodePtr
   7908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7909     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7910     /*
   7911      * the parent of an attribute or namespace node is the element
   7912      * to which the attribute or namespace node is attached
   7913      * !!!!!!!!!!!!!
   7914      */
   7915     if (cur == NULL) {
   7916 	if (ctxt->context->node == NULL) return(NULL);
   7917 	switch (ctxt->context->node->type) {
   7918             case XML_ELEMENT_NODE:
   7919             case XML_TEXT_NODE:
   7920             case XML_CDATA_SECTION_NODE:
   7921             case XML_ENTITY_REF_NODE:
   7922             case XML_ENTITY_NODE:
   7923             case XML_PI_NODE:
   7924             case XML_COMMENT_NODE:
   7925 	    case XML_DTD_NODE:
   7926 	    case XML_ELEMENT_DECL:
   7927 	    case XML_ATTRIBUTE_DECL:
   7928 	    case XML_ENTITY_DECL:
   7929             case XML_NOTATION_NODE:
   7930 	    case XML_XINCLUDE_START:
   7931 	    case XML_XINCLUDE_END:
   7932 		if (ctxt->context->node->parent == NULL)
   7933 		    return((xmlNodePtr) ctxt->context->doc);
   7934 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7935 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7936 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7937 				 BAD_CAST "fake node libxslt"))))
   7938 		    return(NULL);
   7939 		return(ctxt->context->node->parent);
   7940             case XML_ATTRIBUTE_NODE: {
   7941 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   7942 
   7943 		return(tmp->parent);
   7944 	    }
   7945             case XML_DOCUMENT_NODE:
   7946             case XML_DOCUMENT_TYPE_NODE:
   7947             case XML_DOCUMENT_FRAG_NODE:
   7948             case XML_HTML_DOCUMENT_NODE:
   7949 #ifdef LIBXML_DOCB_ENABLED
   7950 	    case XML_DOCB_DOCUMENT_NODE:
   7951 #endif
   7952                 return(NULL);
   7953 	    case XML_NAMESPACE_DECL: {
   7954 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7955 
   7956 		if ((ns->next != NULL) &&
   7957 		    (ns->next->type != XML_NAMESPACE_DECL))
   7958 		    return((xmlNodePtr) ns->next);
   7959 		/* Bad, how did that namespace end up here ? */
   7960                 return(NULL);
   7961 	    }
   7962 	}
   7963 	return(NULL);
   7964     }
   7965     if (cur == ctxt->context->doc->children)
   7966 	return((xmlNodePtr) ctxt->context->doc);
   7967     if (cur == (xmlNodePtr) ctxt->context->doc)
   7968 	return(NULL);
   7969     switch (cur->type) {
   7970 	case XML_ELEMENT_NODE:
   7971 	case XML_TEXT_NODE:
   7972 	case XML_CDATA_SECTION_NODE:
   7973 	case XML_ENTITY_REF_NODE:
   7974 	case XML_ENTITY_NODE:
   7975 	case XML_PI_NODE:
   7976 	case XML_COMMENT_NODE:
   7977 	case XML_NOTATION_NODE:
   7978 	case XML_DTD_NODE:
   7979         case XML_ELEMENT_DECL:
   7980         case XML_ATTRIBUTE_DECL:
   7981         case XML_ENTITY_DECL:
   7982 	case XML_XINCLUDE_START:
   7983 	case XML_XINCLUDE_END:
   7984 	    if (cur->parent == NULL)
   7985 		return(NULL);
   7986 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   7987 		((cur->parent->name[0] == ' ') ||
   7988 		 (xmlStrEqual(cur->parent->name,
   7989 			      BAD_CAST "fake node libxslt"))))
   7990 		return(NULL);
   7991 	    return(cur->parent);
   7992 	case XML_ATTRIBUTE_NODE: {
   7993 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7994 
   7995 	    return(att->parent);
   7996 	}
   7997 	case XML_NAMESPACE_DECL: {
   7998 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7999 
   8000 	    if ((ns->next != NULL) &&
   8001 	        (ns->next->type != XML_NAMESPACE_DECL))
   8002 	        return((xmlNodePtr) ns->next);
   8003 	    /* Bad, how did that namespace end up here ? */
   8004             return(NULL);
   8005 	}
   8006 	case XML_DOCUMENT_NODE:
   8007 	case XML_DOCUMENT_TYPE_NODE:
   8008 	case XML_DOCUMENT_FRAG_NODE:
   8009 	case XML_HTML_DOCUMENT_NODE:
   8010 #ifdef LIBXML_DOCB_ENABLED
   8011 	case XML_DOCB_DOCUMENT_NODE:
   8012 #endif
   8013 	    return(NULL);
   8014     }
   8015     return(NULL);
   8016 }
   8017 
   8018 /**
   8019  * xmlXPathNextAncestorOrSelf:
   8020  * @ctxt:  the XPath Parser context
   8021  * @cur:  the current node in the traversal
   8022  *
   8023  * Traversal function for the "ancestor-or-self" direction
   8024  * he ancestor-or-self axis contains the context node and ancestors of
   8025  * the context node in reverse document order; thus the context node is
   8026  * the first node on the axis, and the context node's parent the second;
   8027  * parent here is defined the same as with the parent axis.
   8028  *
   8029  * Returns the next element following that axis
   8030  */
   8031 xmlNodePtr
   8032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8034     if (cur == NULL)
   8035         return(ctxt->context->node);
   8036     return(xmlXPathNextAncestor(ctxt, cur));
   8037 }
   8038 
   8039 /**
   8040  * xmlXPathNextFollowingSibling:
   8041  * @ctxt:  the XPath Parser context
   8042  * @cur:  the current node in the traversal
   8043  *
   8044  * Traversal function for the "following-sibling" direction
   8045  * The following-sibling axis contains the following siblings of the context
   8046  * node in document order.
   8047  *
   8048  * Returns the next element following that axis
   8049  */
   8050 xmlNodePtr
   8051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8052     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8053     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8054 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8055 	return(NULL);
   8056     if (cur == (xmlNodePtr) ctxt->context->doc)
   8057         return(NULL);
   8058     if (cur == NULL)
   8059         return(ctxt->context->node->next);
   8060     return(cur->next);
   8061 }
   8062 
   8063 /**
   8064  * xmlXPathNextPrecedingSibling:
   8065  * @ctxt:  the XPath Parser context
   8066  * @cur:  the current node in the traversal
   8067  *
   8068  * Traversal function for the "preceding-sibling" direction
   8069  * The preceding-sibling axis contains the preceding siblings of the context
   8070  * node in reverse document order; the first preceding sibling is first on the
   8071  * axis; the sibling preceding that node is the second on the axis and so on.
   8072  *
   8073  * Returns the next element following that axis
   8074  */
   8075 xmlNodePtr
   8076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8077     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8078     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8079 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8080 	return(NULL);
   8081     if (cur == (xmlNodePtr) ctxt->context->doc)
   8082         return(NULL);
   8083     if (cur == NULL)
   8084         return(ctxt->context->node->prev);
   8085     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8086 	cur = cur->prev;
   8087 	if (cur == NULL)
   8088 	    return(ctxt->context->node->prev);
   8089     }
   8090     return(cur->prev);
   8091 }
   8092 
   8093 /**
   8094  * xmlXPathNextFollowing:
   8095  * @ctxt:  the XPath Parser context
   8096  * @cur:  the current node in the traversal
   8097  *
   8098  * Traversal function for the "following" direction
   8099  * The following axis contains all nodes in the same document as the context
   8100  * node that are after the context node in document order, excluding any
   8101  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8102  * are ordered in document order
   8103  *
   8104  * Returns the next element following that axis
   8105  */
   8106 xmlNodePtr
   8107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8109     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8110         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8111         return(cur->children);
   8112 
   8113     if (cur == NULL) {
   8114         cur = ctxt->context->node;
   8115         if (cur->type == XML_NAMESPACE_DECL)
   8116             return(NULL);
   8117         if (cur->type == XML_ATTRIBUTE_NODE)
   8118             cur = cur->parent;
   8119     }
   8120     if (cur == NULL) return(NULL) ; /* ERROR */
   8121     if (cur->next != NULL) return(cur->next) ;
   8122     do {
   8123         cur = cur->parent;
   8124         if (cur == NULL) break;
   8125         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8126         if (cur->next != NULL) return(cur->next);
   8127     } while (cur != NULL);
   8128     return(cur);
   8129 }
   8130 
   8131 /*
   8132  * xmlXPathIsAncestor:
   8133  * @ancestor:  the ancestor node
   8134  * @node:  the current node
   8135  *
   8136  * Check that @ancestor is a @node's ancestor
   8137  *
   8138  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8139  */
   8140 static int
   8141 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8142     if ((ancestor == NULL) || (node == NULL)) return(0);
   8143     /* nodes need to be in the same document */
   8144     if (ancestor->doc != node->doc) return(0);
   8145     /* avoid searching if ancestor or node is the root node */
   8146     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8147     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8148     while (node->parent != NULL) {
   8149         if (node->parent == ancestor)
   8150             return(1);
   8151 	node = node->parent;
   8152     }
   8153     return(0);
   8154 }
   8155 
   8156 /**
   8157  * xmlXPathNextPreceding:
   8158  * @ctxt:  the XPath Parser context
   8159  * @cur:  the current node in the traversal
   8160  *
   8161  * Traversal function for the "preceding" direction
   8162  * the preceding axis contains all nodes in the same document as the context
   8163  * node that are before the context node in document order, excluding any
   8164  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8165  * ordered in reverse document order
   8166  *
   8167  * Returns the next element following that axis
   8168  */
   8169 xmlNodePtr
   8170 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8171 {
   8172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8173     if (cur == NULL) {
   8174         cur = ctxt->context->node;
   8175         if (cur->type == XML_NAMESPACE_DECL)
   8176             return(NULL);
   8177         if (cur->type == XML_ATTRIBUTE_NODE)
   8178             return(cur->parent);
   8179     }
   8180     if (cur == NULL)
   8181 	return (NULL);
   8182     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8183 	cur = cur->prev;
   8184     do {
   8185         if (cur->prev != NULL) {
   8186             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8187             return (cur);
   8188         }
   8189 
   8190         cur = cur->parent;
   8191         if (cur == NULL)
   8192             return (NULL);
   8193         if (cur == ctxt->context->doc->children)
   8194             return (NULL);
   8195     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8196     return (cur);
   8197 }
   8198 
   8199 /**
   8200  * xmlXPathNextPrecedingInternal:
   8201  * @ctxt:  the XPath Parser context
   8202  * @cur:  the current node in the traversal
   8203  *
   8204  * Traversal function for the "preceding" direction
   8205  * the preceding axis contains all nodes in the same document as the context
   8206  * node that are before the context node in document order, excluding any
   8207  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8208  * ordered in reverse document order
   8209  * This is a faster implementation but internal only since it requires a
   8210  * state kept in the parser context: ctxt->ancestor.
   8211  *
   8212  * Returns the next element following that axis
   8213  */
   8214 static xmlNodePtr
   8215 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8216                               xmlNodePtr cur)
   8217 {
   8218     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8219     if (cur == NULL) {
   8220         cur = ctxt->context->node;
   8221         if (cur == NULL)
   8222             return (NULL);
   8223         if (cur->type == XML_NAMESPACE_DECL)
   8224             return (NULL);
   8225         ctxt->ancestor = cur->parent;
   8226     }
   8227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8228 	cur = cur->prev;
   8229     while (cur->prev == NULL) {
   8230         cur = cur->parent;
   8231         if (cur == NULL)
   8232             return (NULL);
   8233         if (cur == ctxt->context->doc->children)
   8234             return (NULL);
   8235         if (cur != ctxt->ancestor)
   8236             return (cur);
   8237         ctxt->ancestor = cur->parent;
   8238     }
   8239     cur = cur->prev;
   8240     while (cur->last != NULL)
   8241         cur = cur->last;
   8242     return (cur);
   8243 }
   8244 
   8245 /**
   8246  * xmlXPathNextNamespace:
   8247  * @ctxt:  the XPath Parser context
   8248  * @cur:  the current attribute in the traversal
   8249  *
   8250  * Traversal function for the "namespace" direction
   8251  * the namespace axis contains the namespace nodes of the context node;
   8252  * the order of nodes on this axis is implementation-defined; the axis will
   8253  * be empty unless the context node is an element
   8254  *
   8255  * We keep the XML namespace node at the end of the list.
   8256  *
   8257  * Returns the next element following that axis
   8258  */
   8259 xmlNodePtr
   8260 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8261     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8262     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8263     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
   8264         if (ctxt->context->tmpNsList != NULL)
   8265 	    xmlFree(ctxt->context->tmpNsList);
   8266 	ctxt->context->tmpNsList =
   8267 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8268 	ctxt->context->tmpNsNr = 0;
   8269 	if (ctxt->context->tmpNsList != NULL) {
   8270 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8271 		ctxt->context->tmpNsNr++;
   8272 	    }
   8273 	}
   8274 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8275     }
   8276     if (ctxt->context->tmpNsNr > 0) {
   8277 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8278     } else {
   8279 	if (ctxt->context->tmpNsList != NULL)
   8280 	    xmlFree(ctxt->context->tmpNsList);
   8281 	ctxt->context->tmpNsList = NULL;
   8282 	return(NULL);
   8283     }
   8284 }
   8285 
   8286 /**
   8287  * xmlXPathNextAttribute:
   8288  * @ctxt:  the XPath Parser context
   8289  * @cur:  the current attribute in the traversal
   8290  *
   8291  * Traversal function for the "attribute" direction
   8292  * TODO: support DTD inherited default attributes
   8293  *
   8294  * Returns the next element following that axis
   8295  */
   8296 xmlNodePtr
   8297 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8298     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8299     if (ctxt->context->node == NULL)
   8300 	return(NULL);
   8301     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8302 	return(NULL);
   8303     if (cur == NULL) {
   8304         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8305 	    return(NULL);
   8306         return((xmlNodePtr)ctxt->context->node->properties);
   8307     }
   8308     return((xmlNodePtr)cur->next);
   8309 }
   8310 
   8311 /************************************************************************
   8312  *									*
   8313  *		NodeTest Functions					*
   8314  *									*
   8315  ************************************************************************/
   8316 
   8317 #define IS_FUNCTION			200
   8318 
   8319 
   8320 /************************************************************************
   8321  *									*
   8322  *		Implicit tree core function library			*
   8323  *									*
   8324  ************************************************************************/
   8325 
   8326 /**
   8327  * xmlXPathRoot:
   8328  * @ctxt:  the XPath Parser context
   8329  *
   8330  * Initialize the context to the root of the document
   8331  */
   8332 void
   8333 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8334     if ((ctxt == NULL) || (ctxt->context == NULL))
   8335 	return;
   8336     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8337     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8338 	ctxt->context->node));
   8339 }
   8340 
   8341 /************************************************************************
   8342  *									*
   8343  *		The explicit core function library			*
   8344  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8345  *									*
   8346  ************************************************************************/
   8347 
   8348 
   8349 /**
   8350  * xmlXPathLastFunction:
   8351  * @ctxt:  the XPath Parser context
   8352  * @nargs:  the number of arguments
   8353  *
   8354  * Implement the last() XPath function
   8355  *    number last()
   8356  * The last function returns the number of nodes in the context node list.
   8357  */
   8358 void
   8359 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8360     CHECK_ARITY(0);
   8361     if (ctxt->context->contextSize >= 0) {
   8362 	valuePush(ctxt,
   8363 	    xmlXPathCacheNewFloat(ctxt->context,
   8364 		(double) ctxt->context->contextSize));
   8365 #ifdef DEBUG_EXPR
   8366 	xmlGenericError(xmlGenericErrorContext,
   8367 		"last() : %d\n", ctxt->context->contextSize);
   8368 #endif
   8369     } else {
   8370 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8371     }
   8372 }
   8373 
   8374 /**
   8375  * xmlXPathPositionFunction:
   8376  * @ctxt:  the XPath Parser context
   8377  * @nargs:  the number of arguments
   8378  *
   8379  * Implement the position() XPath function
   8380  *    number position()
   8381  * The position function returns the position of the context node in the
   8382  * context node list. The first position is 1, and so the last position
   8383  * will be equal to last().
   8384  */
   8385 void
   8386 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8387     CHECK_ARITY(0);
   8388     if (ctxt->context->proximityPosition >= 0) {
   8389 	valuePush(ctxt,
   8390 	      xmlXPathCacheNewFloat(ctxt->context,
   8391 		(double) ctxt->context->proximityPosition));
   8392 #ifdef DEBUG_EXPR
   8393 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8394 		ctxt->context->proximityPosition);
   8395 #endif
   8396     } else {
   8397 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8398     }
   8399 }
   8400 
   8401 /**
   8402  * xmlXPathCountFunction:
   8403  * @ctxt:  the XPath Parser context
   8404  * @nargs:  the number of arguments
   8405  *
   8406  * Implement the count() XPath function
   8407  *    number count(node-set)
   8408  */
   8409 void
   8410 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8411     xmlXPathObjectPtr cur;
   8412 
   8413     CHECK_ARITY(1);
   8414     if ((ctxt->value == NULL) ||
   8415 	((ctxt->value->type != XPATH_NODESET) &&
   8416 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8417 	XP_ERROR(XPATH_INVALID_TYPE);
   8418     cur = valuePop(ctxt);
   8419 
   8420     if ((cur == NULL) || (cur->nodesetval == NULL))
   8421 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8422     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8423 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8424 	    (double) cur->nodesetval->nodeNr));
   8425     } else {
   8426 	if ((cur->nodesetval->nodeNr != 1) ||
   8427 	    (cur->nodesetval->nodeTab == NULL)) {
   8428 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8429 	} else {
   8430 	    xmlNodePtr tmp;
   8431 	    int i = 0;
   8432 
   8433 	    tmp = cur->nodesetval->nodeTab[0];
   8434 	    if (tmp != NULL) {
   8435 		tmp = tmp->children;
   8436 		while (tmp != NULL) {
   8437 		    tmp = tmp->next;
   8438 		    i++;
   8439 		}
   8440 	    }
   8441 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8442 	}
   8443     }
   8444     xmlXPathReleaseObject(ctxt->context, cur);
   8445 }
   8446 
   8447 /**
   8448  * xmlXPathGetElementsByIds:
   8449  * @doc:  the document
   8450  * @ids:  a whitespace separated list of IDs
   8451  *
   8452  * Selects elements by their unique ID.
   8453  *
   8454  * Returns a node-set of selected elements.
   8455  */
   8456 static xmlNodeSetPtr
   8457 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8458     xmlNodeSetPtr ret;
   8459     const xmlChar *cur = ids;
   8460     xmlChar *ID;
   8461     xmlAttrPtr attr;
   8462     xmlNodePtr elem = NULL;
   8463 
   8464     if (ids == NULL) return(NULL);
   8465 
   8466     ret = xmlXPathNodeSetCreate(NULL);
   8467     if (ret == NULL)
   8468         return(ret);
   8469 
   8470     while (IS_BLANK_CH(*cur)) cur++;
   8471     while (*cur != 0) {
   8472 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8473 	    cur++;
   8474 
   8475         ID = xmlStrndup(ids, cur - ids);
   8476 	if (ID != NULL) {
   8477 	    /*
   8478 	     * We used to check the fact that the value passed
   8479 	     * was an NCName, but this generated much troubles for
   8480 	     * me and Aleksey Sanin, people blatantly violated that
   8481 	     * constaint, like Visa3D spec.
   8482 	     * if (xmlValidateNCName(ID, 1) == 0)
   8483 	     */
   8484 	    attr = xmlGetID(doc, ID);
   8485 	    if (attr != NULL) {
   8486 		if (attr->type == XML_ATTRIBUTE_NODE)
   8487 		    elem = attr->parent;
   8488 		else if (attr->type == XML_ELEMENT_NODE)
   8489 		    elem = (xmlNodePtr) attr;
   8490 		else
   8491 		    elem = NULL;
   8492 		if (elem != NULL)
   8493 		    xmlXPathNodeSetAdd(ret, elem);
   8494 	    }
   8495 	    xmlFree(ID);
   8496 	}
   8497 
   8498 	while (IS_BLANK_CH(*cur)) cur++;
   8499 	ids = cur;
   8500     }
   8501     return(ret);
   8502 }
   8503 
   8504 /**
   8505  * xmlXPathIdFunction:
   8506  * @ctxt:  the XPath Parser context
   8507  * @nargs:  the number of arguments
   8508  *
   8509  * Implement the id() XPath function
   8510  *    node-set id(object)
   8511  * The id function selects elements by their unique ID
   8512  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8513  * then the result is the union of the result of applying id to the
   8514  * string value of each of the nodes in the argument node-set. When the
   8515  * argument to id is of any other type, the argument is converted to a
   8516  * string as if by a call to the string function; the string is split
   8517  * into a whitespace-separated list of tokens (whitespace is any sequence
   8518  * of characters matching the production S); the result is a node-set
   8519  * containing the elements in the same document as the context node that
   8520  * have a unique ID equal to any of the tokens in the list.
   8521  */
   8522 void
   8523 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8524     xmlChar *tokens;
   8525     xmlNodeSetPtr ret;
   8526     xmlXPathObjectPtr obj;
   8527 
   8528     CHECK_ARITY(1);
   8529     obj = valuePop(ctxt);
   8530     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8531     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8532 	xmlNodeSetPtr ns;
   8533 	int i;
   8534 
   8535 	ret = xmlXPathNodeSetCreate(NULL);
   8536         /*
   8537          * FIXME -- in an out-of-memory condition this will behave badly.
   8538          * The solution is not clear -- we already popped an item from
   8539          * ctxt, so the object is in a corrupt state.
   8540          */
   8541 
   8542 	if (obj->nodesetval != NULL) {
   8543 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8544 		tokens =
   8545 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8546 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8547 		ret = xmlXPathNodeSetMerge(ret, ns);
   8548 		xmlXPathFreeNodeSet(ns);
   8549 		if (tokens != NULL)
   8550 		    xmlFree(tokens);
   8551 	    }
   8552 	}
   8553 	xmlXPathReleaseObject(ctxt->context, obj);
   8554 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8555 	return;
   8556     }
   8557     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8558     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8559     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8560     xmlXPathReleaseObject(ctxt->context, obj);
   8561     return;
   8562 }
   8563 
   8564 /**
   8565  * xmlXPathLocalNameFunction:
   8566  * @ctxt:  the XPath Parser context
   8567  * @nargs:  the number of arguments
   8568  *
   8569  * Implement the local-name() XPath function
   8570  *    string local-name(node-set?)
   8571  * The local-name function returns a string containing the local part
   8572  * of the name of the node in the argument node-set that is first in
   8573  * document order. If the node-set is empty or the first node has no
   8574  * name, an empty string is returned. If the argument is omitted it
   8575  * defaults to the context node.
   8576  */
   8577 void
   8578 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8579     xmlXPathObjectPtr cur;
   8580 
   8581     if (ctxt == NULL) return;
   8582 
   8583     if (nargs == 0) {
   8584 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8585 	    ctxt->context->node));
   8586 	nargs = 1;
   8587     }
   8588 
   8589     CHECK_ARITY(1);
   8590     if ((ctxt->value == NULL) ||
   8591 	((ctxt->value->type != XPATH_NODESET) &&
   8592 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8593 	XP_ERROR(XPATH_INVALID_TYPE);
   8594     cur = valuePop(ctxt);
   8595 
   8596     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8597 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8598     } else {
   8599 	int i = 0; /* Should be first in document order !!!!! */
   8600 	switch (cur->nodesetval->nodeTab[i]->type) {
   8601 	case XML_ELEMENT_NODE:
   8602 	case XML_ATTRIBUTE_NODE:
   8603 	case XML_PI_NODE:
   8604 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8605 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8606 	    else
   8607 		valuePush(ctxt,
   8608 		      xmlXPathCacheNewString(ctxt->context,
   8609 			cur->nodesetval->nodeTab[i]->name));
   8610 	    break;
   8611 	case XML_NAMESPACE_DECL:
   8612 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8613 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8614 	    break;
   8615 	default:
   8616 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8617 	}
   8618     }
   8619     xmlXPathReleaseObject(ctxt->context, cur);
   8620 }
   8621 
   8622 /**
   8623  * xmlXPathNamespaceURIFunction:
   8624  * @ctxt:  the XPath Parser context
   8625  * @nargs:  the number of arguments
   8626  *
   8627  * Implement the namespace-uri() XPath function
   8628  *    string namespace-uri(node-set?)
   8629  * The namespace-uri function returns a string containing the
   8630  * namespace URI of the expanded name of the node in the argument
   8631  * node-set that is first in document order. If the node-set is empty,
   8632  * the first node has no name, or the expanded name has no namespace
   8633  * URI, an empty string is returned. If the argument is omitted it
   8634  * defaults to the context node.
   8635  */
   8636 void
   8637 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8638     xmlXPathObjectPtr cur;
   8639 
   8640     if (ctxt == NULL) return;
   8641 
   8642     if (nargs == 0) {
   8643 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8644 	    ctxt->context->node));
   8645 	nargs = 1;
   8646     }
   8647     CHECK_ARITY(1);
   8648     if ((ctxt->value == NULL) ||
   8649 	((ctxt->value->type != XPATH_NODESET) &&
   8650 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8651 	XP_ERROR(XPATH_INVALID_TYPE);
   8652     cur = valuePop(ctxt);
   8653 
   8654     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8655 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8656     } else {
   8657 	int i = 0; /* Should be first in document order !!!!! */
   8658 	switch (cur->nodesetval->nodeTab[i]->type) {
   8659 	case XML_ELEMENT_NODE:
   8660 	case XML_ATTRIBUTE_NODE:
   8661 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8662 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8663 	    else
   8664 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8665 			  cur->nodesetval->nodeTab[i]->ns->href));
   8666 	    break;
   8667 	default:
   8668 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8669 	}
   8670     }
   8671     xmlXPathReleaseObject(ctxt->context, cur);
   8672 }
   8673 
   8674 /**
   8675  * xmlXPathNameFunction:
   8676  * @ctxt:  the XPath Parser context
   8677  * @nargs:  the number of arguments
   8678  *
   8679  * Implement the name() XPath function
   8680  *    string name(node-set?)
   8681  * The name function returns a string containing a QName representing
   8682  * the name of the node in the argument node-set that is first in document
   8683  * order. The QName must represent the name with respect to the namespace
   8684  * declarations in effect on the node whose name is being represented.
   8685  * Typically, this will be the form in which the name occurred in the XML
   8686  * source. This need not be the case if there are namespace declarations
   8687  * in effect on the node that associate multiple prefixes with the same
   8688  * namespace. However, an implementation may include information about
   8689  * the original prefix in its representation of nodes; in this case, an
   8690  * implementation can ensure that the returned string is always the same
   8691  * as the QName used in the XML source. If the argument it omitted it
   8692  * defaults to the context node.
   8693  * Libxml keep the original prefix so the "real qualified name" used is
   8694  * returned.
   8695  */
   8696 static void
   8697 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8698 {
   8699     xmlXPathObjectPtr cur;
   8700 
   8701     if (nargs == 0) {
   8702 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8703 	    ctxt->context->node));
   8704         nargs = 1;
   8705     }
   8706 
   8707     CHECK_ARITY(1);
   8708     if ((ctxt->value == NULL) ||
   8709         ((ctxt->value->type != XPATH_NODESET) &&
   8710          (ctxt->value->type != XPATH_XSLT_TREE)))
   8711         XP_ERROR(XPATH_INVALID_TYPE);
   8712     cur = valuePop(ctxt);
   8713 
   8714     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8715         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8716     } else {
   8717         int i = 0;              /* Should be first in document order !!!!! */
   8718 
   8719         switch (cur->nodesetval->nodeTab[i]->type) {
   8720             case XML_ELEMENT_NODE:
   8721             case XML_ATTRIBUTE_NODE:
   8722 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8723 		    valuePush(ctxt,
   8724 			xmlXPathCacheNewCString(ctxt->context, ""));
   8725 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8726                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8727 		    valuePush(ctxt,
   8728 		        xmlXPathCacheNewString(ctxt->context,
   8729 			    cur->nodesetval->nodeTab[i]->name));
   8730 		} else {
   8731 		    xmlChar *fullname;
   8732 
   8733 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8734 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8735 				     NULL, 0);
   8736 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8737 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8738 		    if (fullname == NULL) {
   8739 			XP_ERROR(XPATH_MEMORY_ERROR);
   8740 		    }
   8741 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8742 			ctxt->context, fullname));
   8743                 }
   8744                 break;
   8745             default:
   8746 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8747 		    cur->nodesetval->nodeTab[i]));
   8748                 xmlXPathLocalNameFunction(ctxt, 1);
   8749         }
   8750     }
   8751     xmlXPathReleaseObject(ctxt->context, cur);
   8752 }
   8753 
   8754 
   8755 /**
   8756  * xmlXPathStringFunction:
   8757  * @ctxt:  the XPath Parser context
   8758  * @nargs:  the number of arguments
   8759  *
   8760  * Implement the string() XPath function
   8761  *    string string(object?)
   8762  * The string function converts an object to a string as follows:
   8763  *    - A node-set is converted to a string by returning the value of
   8764  *      the node in the node-set that is first in document order.
   8765  *      If the node-set is empty, an empty string is returned.
   8766  *    - A number is converted to a string as follows
   8767  *      + NaN is converted to the string NaN
   8768  *      + positive zero is converted to the string 0
   8769  *      + negative zero is converted to the string 0
   8770  *      + positive infinity is converted to the string Infinity
   8771  *      + negative infinity is converted to the string -Infinity
   8772  *      + if the number is an integer, the number is represented in
   8773  *        decimal form as a Number with no decimal point and no leading
   8774  *        zeros, preceded by a minus sign (-) if the number is negative
   8775  *      + otherwise, the number is represented in decimal form as a
   8776  *        Number including a decimal point with at least one digit
   8777  *        before the decimal point and at least one digit after the
   8778  *        decimal point, preceded by a minus sign (-) if the number
   8779  *        is negative; there must be no leading zeros before the decimal
   8780  *        point apart possibly from the one required digit immediately
   8781  *        before the decimal point; beyond the one required digit
   8782  *        after the decimal point there must be as many, but only as
   8783  *        many, more digits as are needed to uniquely distinguish the
   8784  *        number from all other IEEE 754 numeric values.
   8785  *    - The boolean false value is converted to the string false.
   8786  *      The boolean true value is converted to the string true.
   8787  *
   8788  * If the argument is omitted, it defaults to a node-set with the
   8789  * context node as its only member.
   8790  */
   8791 void
   8792 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8793     xmlXPathObjectPtr cur;
   8794 
   8795     if (ctxt == NULL) return;
   8796     if (nargs == 0) {
   8797     valuePush(ctxt,
   8798 	xmlXPathCacheWrapString(ctxt->context,
   8799 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8800 	return;
   8801     }
   8802 
   8803     CHECK_ARITY(1);
   8804     cur = valuePop(ctxt);
   8805     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8806     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8807 }
   8808 
   8809 /**
   8810  * xmlXPathStringLengthFunction:
   8811  * @ctxt:  the XPath Parser context
   8812  * @nargs:  the number of arguments
   8813  *
   8814  * Implement the string-length() XPath function
   8815  *    number string-length(string?)
   8816  * The string-length returns the number of characters in the string
   8817  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8818  * the context node converted to a string, in other words the value
   8819  * of the context node.
   8820  */
   8821 void
   8822 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8823     xmlXPathObjectPtr cur;
   8824 
   8825     if (nargs == 0) {
   8826         if ((ctxt == NULL) || (ctxt->context == NULL))
   8827 	    return;
   8828 	if (ctxt->context->node == NULL) {
   8829 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8830 	} else {
   8831 	    xmlChar *content;
   8832 
   8833 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8834 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8835 		xmlUTF8Strlen(content)));
   8836 	    xmlFree(content);
   8837 	}
   8838 	return;
   8839     }
   8840     CHECK_ARITY(1);
   8841     CAST_TO_STRING;
   8842     CHECK_TYPE(XPATH_STRING);
   8843     cur = valuePop(ctxt);
   8844     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8845 	xmlUTF8Strlen(cur->stringval)));
   8846     xmlXPathReleaseObject(ctxt->context, cur);
   8847 }
   8848 
   8849 /**
   8850  * xmlXPathConcatFunction:
   8851  * @ctxt:  the XPath Parser context
   8852  * @nargs:  the number of arguments
   8853  *
   8854  * Implement the concat() XPath function
   8855  *    string concat(string, string, string*)
   8856  * The concat function returns the concatenation of its arguments.
   8857  */
   8858 void
   8859 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8860     xmlXPathObjectPtr cur, newobj;
   8861     xmlChar *tmp;
   8862 
   8863     if (ctxt == NULL) return;
   8864     if (nargs < 2) {
   8865 	CHECK_ARITY(2);
   8866     }
   8867 
   8868     CAST_TO_STRING;
   8869     cur = valuePop(ctxt);
   8870     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   8871 	xmlXPathReleaseObject(ctxt->context, cur);
   8872 	return;
   8873     }
   8874     nargs--;
   8875 
   8876     while (nargs > 0) {
   8877 	CAST_TO_STRING;
   8878 	newobj = valuePop(ctxt);
   8879 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   8880 	    xmlXPathReleaseObject(ctxt->context, newobj);
   8881 	    xmlXPathReleaseObject(ctxt->context, cur);
   8882 	    XP_ERROR(XPATH_INVALID_TYPE);
   8883 	}
   8884 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   8885 	newobj->stringval = cur->stringval;
   8886 	cur->stringval = tmp;
   8887 	xmlXPathReleaseObject(ctxt->context, newobj);
   8888 	nargs--;
   8889     }
   8890     valuePush(ctxt, cur);
   8891 }
   8892 
   8893 /**
   8894  * xmlXPathContainsFunction:
   8895  * @ctxt:  the XPath Parser context
   8896  * @nargs:  the number of arguments
   8897  *
   8898  * Implement the contains() XPath function
   8899  *    boolean contains(string, string)
   8900  * The contains function returns true if the first argument string
   8901  * contains the second argument string, and otherwise returns false.
   8902  */
   8903 void
   8904 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8905     xmlXPathObjectPtr hay, needle;
   8906 
   8907     CHECK_ARITY(2);
   8908     CAST_TO_STRING;
   8909     CHECK_TYPE(XPATH_STRING);
   8910     needle = valuePop(ctxt);
   8911     CAST_TO_STRING;
   8912     hay = valuePop(ctxt);
   8913 
   8914     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8915 	xmlXPathReleaseObject(ctxt->context, hay);
   8916 	xmlXPathReleaseObject(ctxt->context, needle);
   8917 	XP_ERROR(XPATH_INVALID_TYPE);
   8918     }
   8919     if (xmlStrstr(hay->stringval, needle->stringval))
   8920 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   8921     else
   8922 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   8923     xmlXPathReleaseObject(ctxt->context, hay);
   8924     xmlXPathReleaseObject(ctxt->context, needle);
   8925 }
   8926 
   8927 /**
   8928  * xmlXPathStartsWithFunction:
   8929  * @ctxt:  the XPath Parser context
   8930  * @nargs:  the number of arguments
   8931  *
   8932  * Implement the starts-with() XPath function
   8933  *    boolean starts-with(string, string)
   8934  * The starts-with function returns true if the first argument string
   8935  * starts with the second argument string, and otherwise returns false.
   8936  */
   8937 void
   8938 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8939     xmlXPathObjectPtr hay, needle;
   8940     int n;
   8941 
   8942     CHECK_ARITY(2);
   8943     CAST_TO_STRING;
   8944     CHECK_TYPE(XPATH_STRING);
   8945     needle = valuePop(ctxt);
   8946     CAST_TO_STRING;
   8947     hay = valuePop(ctxt);
   8948 
   8949     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8950 	xmlXPathReleaseObject(ctxt->context, hay);
   8951 	xmlXPathReleaseObject(ctxt->context, needle);
   8952 	XP_ERROR(XPATH_INVALID_TYPE);
   8953     }
   8954     n = xmlStrlen(needle->stringval);
   8955     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   8956         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   8957     else
   8958         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   8959     xmlXPathReleaseObject(ctxt->context, hay);
   8960     xmlXPathReleaseObject(ctxt->context, needle);
   8961 }
   8962 
   8963 /**
   8964  * xmlXPathSubstringFunction:
   8965  * @ctxt:  the XPath Parser context
   8966  * @nargs:  the number of arguments
   8967  *
   8968  * Implement the substring() XPath function
   8969  *    string substring(string, number, number?)
   8970  * The substring function returns the substring of the first argument
   8971  * starting at the position specified in the second argument with
   8972  * length specified in the third argument. For example,
   8973  * substring("12345",2,3) returns "234". If the third argument is not
   8974  * specified, it returns the substring starting at the position specified
   8975  * in the second argument and continuing to the end of the string. For
   8976  * example, substring("12345",2) returns "2345".  More precisely, each
   8977  * character in the string (see [3.6 Strings]) is considered to have a
   8978  * numeric position: the position of the first character is 1, the position
   8979  * of the second character is 2 and so on. The returned substring contains
   8980  * those characters for which the position of the character is greater than
   8981  * or equal to the second argument and, if the third argument is specified,
   8982  * less than the sum of the second and third arguments; the comparisons
   8983  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   8984  *  - substring("12345", 1.5, 2.6) returns "234"
   8985  *  - substring("12345", 0, 3) returns "12"
   8986  *  - substring("12345", 0 div 0, 3) returns ""
   8987  *  - substring("12345", 1, 0 div 0) returns ""
   8988  *  - substring("12345", -42, 1 div 0) returns "12345"
   8989  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   8990  */
   8991 void
   8992 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8993     xmlXPathObjectPtr str, start, len;
   8994     double le=0, in;
   8995     int i, l, m;
   8996     xmlChar *ret;
   8997 
   8998     if (nargs < 2) {
   8999 	CHECK_ARITY(2);
   9000     }
   9001     if (nargs > 3) {
   9002 	CHECK_ARITY(3);
   9003     }
   9004     /*
   9005      * take care of possible last (position) argument
   9006     */
   9007     if (nargs == 3) {
   9008 	CAST_TO_NUMBER;
   9009 	CHECK_TYPE(XPATH_NUMBER);
   9010 	len = valuePop(ctxt);
   9011 	le = len->floatval;
   9012 	xmlXPathReleaseObject(ctxt->context, len);
   9013     }
   9014 
   9015     CAST_TO_NUMBER;
   9016     CHECK_TYPE(XPATH_NUMBER);
   9017     start = valuePop(ctxt);
   9018     in = start->floatval;
   9019     xmlXPathReleaseObject(ctxt->context, start);
   9020     CAST_TO_STRING;
   9021     CHECK_TYPE(XPATH_STRING);
   9022     str = valuePop(ctxt);
   9023     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9024 
   9025     /*
   9026      * If last pos not present, calculate last position
   9027     */
   9028     if (nargs != 3) {
   9029 	le = (double)m;
   9030 	if (in < 1.0)
   9031 	    in = 1.0;
   9032     }
   9033 
   9034     /* Need to check for the special cases where either
   9035      * the index is NaN, the length is NaN, or both
   9036      * arguments are infinity (relying on Inf + -Inf = NaN)
   9037      */
   9038     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9039         /*
   9040          * To meet the requirements of the spec, the arguments
   9041 	 * must be converted to integer format before
   9042 	 * initial index calculations are done
   9043          *
   9044          * First we go to integer form, rounding up
   9045 	 * and checking for special cases
   9046          */
   9047         i = (int) in;
   9048         if (((double)i)+0.5 <= in) i++;
   9049 
   9050 	if (xmlXPathIsInf(le) == 1) {
   9051 	    l = m;
   9052 	    if (i < 1)
   9053 		i = 1;
   9054 	}
   9055 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9056 	    l = 0;
   9057 	else {
   9058 	    l = (int) le;
   9059 	    if (((double)l)+0.5 <= le) l++;
   9060 	}
   9061 
   9062 	/* Now we normalize inidices */
   9063         i -= 1;
   9064         l += i;
   9065         if (i < 0)
   9066             i = 0;
   9067         if (l > m)
   9068             l = m;
   9069 
   9070         /* number of chars to copy */
   9071         l -= i;
   9072 
   9073         ret = xmlUTF8Strsub(str->stringval, i, l);
   9074     }
   9075     else {
   9076         ret = NULL;
   9077     }
   9078     if (ret == NULL)
   9079 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9080     else {
   9081 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9082 	xmlFree(ret);
   9083     }
   9084     xmlXPathReleaseObject(ctxt->context, str);
   9085 }
   9086 
   9087 /**
   9088  * xmlXPathSubstringBeforeFunction:
   9089  * @ctxt:  the XPath Parser context
   9090  * @nargs:  the number of arguments
   9091  *
   9092  * Implement the substring-before() XPath function
   9093  *    string substring-before(string, string)
   9094  * The substring-before function returns the substring of the first
   9095  * argument string that precedes the first occurrence of the second
   9096  * argument string in the first argument string, or the empty string
   9097  * if the first argument string does not contain the second argument
   9098  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9099  */
   9100 void
   9101 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9102   xmlXPathObjectPtr str;
   9103   xmlXPathObjectPtr find;
   9104   xmlBufferPtr target;
   9105   const xmlChar *point;
   9106   int offset;
   9107 
   9108   CHECK_ARITY(2);
   9109   CAST_TO_STRING;
   9110   find = valuePop(ctxt);
   9111   CAST_TO_STRING;
   9112   str = valuePop(ctxt);
   9113 
   9114   target = xmlBufferCreate();
   9115   if (target) {
   9116     point = xmlStrstr(str->stringval, find->stringval);
   9117     if (point) {
   9118       offset = (int)(point - str->stringval);
   9119       xmlBufferAdd(target, str->stringval, offset);
   9120     }
   9121     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9122 	xmlBufferContent(target)));
   9123     xmlBufferFree(target);
   9124   }
   9125   xmlXPathReleaseObject(ctxt->context, str);
   9126   xmlXPathReleaseObject(ctxt->context, find);
   9127 }
   9128 
   9129 /**
   9130  * xmlXPathSubstringAfterFunction:
   9131  * @ctxt:  the XPath Parser context
   9132  * @nargs:  the number of arguments
   9133  *
   9134  * Implement the substring-after() XPath function
   9135  *    string substring-after(string, string)
   9136  * The substring-after function returns the substring of the first
   9137  * argument string that follows the first occurrence of the second
   9138  * argument string in the first argument string, or the empty stringi
   9139  * if the first argument string does not contain the second argument
   9140  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9141  * and substring-after("1999/04/01","19") returns 99/04/01.
   9142  */
   9143 void
   9144 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9145   xmlXPathObjectPtr str;
   9146   xmlXPathObjectPtr find;
   9147   xmlBufferPtr target;
   9148   const xmlChar *point;
   9149   int offset;
   9150 
   9151   CHECK_ARITY(2);
   9152   CAST_TO_STRING;
   9153   find = valuePop(ctxt);
   9154   CAST_TO_STRING;
   9155   str = valuePop(ctxt);
   9156 
   9157   target = xmlBufferCreate();
   9158   if (target) {
   9159     point = xmlStrstr(str->stringval, find->stringval);
   9160     if (point) {
   9161       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9162       xmlBufferAdd(target, &str->stringval[offset],
   9163 		   xmlStrlen(str->stringval) - offset);
   9164     }
   9165     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9166 	xmlBufferContent(target)));
   9167     xmlBufferFree(target);
   9168   }
   9169   xmlXPathReleaseObject(ctxt->context, str);
   9170   xmlXPathReleaseObject(ctxt->context, find);
   9171 }
   9172 
   9173 /**
   9174  * xmlXPathNormalizeFunction:
   9175  * @ctxt:  the XPath Parser context
   9176  * @nargs:  the number of arguments
   9177  *
   9178  * Implement the normalize-space() XPath function
   9179  *    string normalize-space(string?)
   9180  * The normalize-space function returns the argument string with white
   9181  * space normalized by stripping leading and trailing whitespace
   9182  * and replacing sequences of whitespace characters by a single
   9183  * space. Whitespace characters are the same allowed by the S production
   9184  * in XML. If the argument is omitted, it defaults to the context
   9185  * node converted to a string, in other words the value of the context node.
   9186  */
   9187 void
   9188 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9189   xmlXPathObjectPtr obj = NULL;
   9190   xmlChar *source = NULL;
   9191   xmlBufferPtr target;
   9192   xmlChar blank;
   9193 
   9194   if (ctxt == NULL) return;
   9195   if (nargs == 0) {
   9196     /* Use current context node */
   9197       valuePush(ctxt,
   9198 	  xmlXPathCacheWrapString(ctxt->context,
   9199 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9200     nargs = 1;
   9201   }
   9202 
   9203   CHECK_ARITY(1);
   9204   CAST_TO_STRING;
   9205   CHECK_TYPE(XPATH_STRING);
   9206   obj = valuePop(ctxt);
   9207   source = obj->stringval;
   9208 
   9209   target = xmlBufferCreate();
   9210   if (target && source) {
   9211 
   9212     /* Skip leading whitespaces */
   9213     while (IS_BLANK_CH(*source))
   9214       source++;
   9215 
   9216     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9217     blank = 0;
   9218     while (*source) {
   9219       if (IS_BLANK_CH(*source)) {
   9220 	blank = 0x20;
   9221       } else {
   9222 	if (blank) {
   9223 	  xmlBufferAdd(target, &blank, 1);
   9224 	  blank = 0;
   9225 	}
   9226 	xmlBufferAdd(target, source, 1);
   9227       }
   9228       source++;
   9229     }
   9230     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9231 	xmlBufferContent(target)));
   9232     xmlBufferFree(target);
   9233   }
   9234   xmlXPathReleaseObject(ctxt->context, obj);
   9235 }
   9236 
   9237 /**
   9238  * xmlXPathTranslateFunction:
   9239  * @ctxt:  the XPath Parser context
   9240  * @nargs:  the number of arguments
   9241  *
   9242  * Implement the translate() XPath function
   9243  *    string translate(string, string, string)
   9244  * The translate function returns the first argument string with
   9245  * occurrences of characters in the second argument string replaced
   9246  * by the character at the corresponding position in the third argument
   9247  * string. For example, translate("bar","abc","ABC") returns the string
   9248  * BAr. If there is a character in the second argument string with no
   9249  * character at a corresponding position in the third argument string
   9250  * (because the second argument string is longer than the third argument
   9251  * string), then occurrences of that character in the first argument
   9252  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9253  * returns "AAA". If a character occurs more than once in second
   9254  * argument string, then the first occurrence determines the replacement
   9255  * character. If the third argument string is longer than the second
   9256  * argument string, then excess characters are ignored.
   9257  */
   9258 void
   9259 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9260     xmlXPathObjectPtr str;
   9261     xmlXPathObjectPtr from;
   9262     xmlXPathObjectPtr to;
   9263     xmlBufferPtr target;
   9264     int offset, max;
   9265     xmlChar ch;
   9266     const xmlChar *point;
   9267     xmlChar *cptr;
   9268 
   9269     CHECK_ARITY(3);
   9270 
   9271     CAST_TO_STRING;
   9272     to = valuePop(ctxt);
   9273     CAST_TO_STRING;
   9274     from = valuePop(ctxt);
   9275     CAST_TO_STRING;
   9276     str = valuePop(ctxt);
   9277 
   9278     target = xmlBufferCreate();
   9279     if (target) {
   9280 	max = xmlUTF8Strlen(to->stringval);
   9281 	for (cptr = str->stringval; (ch=*cptr); ) {
   9282 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9283 	    if (offset >= 0) {
   9284 		if (offset < max) {
   9285 		    point = xmlUTF8Strpos(to->stringval, offset);
   9286 		    if (point)
   9287 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
   9288 		}
   9289 	    } else
   9290 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9291 
   9292 	    /* Step to next character in input */
   9293 	    cptr++;
   9294 	    if ( ch & 0x80 ) {
   9295 		/* if not simple ascii, verify proper format */
   9296 		if ( (ch & 0xc0) != 0xc0 ) {
   9297 		    xmlGenericError(xmlGenericErrorContext,
   9298 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9299 		    break;
   9300 		}
   9301 		/* then skip over remaining bytes for this char */
   9302 		while ( (ch <<= 1) & 0x80 )
   9303 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9304 			xmlGenericError(xmlGenericErrorContext,
   9305 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9306 			break;
   9307 		    }
   9308 		if (ch & 0x80) /* must have had error encountered */
   9309 		    break;
   9310 	    }
   9311 	}
   9312     }
   9313     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9314 	xmlBufferContent(target)));
   9315     xmlBufferFree(target);
   9316     xmlXPathReleaseObject(ctxt->context, str);
   9317     xmlXPathReleaseObject(ctxt->context, from);
   9318     xmlXPathReleaseObject(ctxt->context, to);
   9319 }
   9320 
   9321 /**
   9322  * xmlXPathBooleanFunction:
   9323  * @ctxt:  the XPath Parser context
   9324  * @nargs:  the number of arguments
   9325  *
   9326  * Implement the boolean() XPath function
   9327  *    boolean boolean(object)
   9328  * The boolean function converts its argument to a boolean as follows:
   9329  *    - a number is true if and only if it is neither positive or
   9330  *      negative zero nor NaN
   9331  *    - a node-set is true if and only if it is non-empty
   9332  *    - a string is true if and only if its length is non-zero
   9333  */
   9334 void
   9335 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9336     xmlXPathObjectPtr cur;
   9337 
   9338     CHECK_ARITY(1);
   9339     cur = valuePop(ctxt);
   9340     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9341     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9342     valuePush(ctxt, cur);
   9343 }
   9344 
   9345 /**
   9346  * xmlXPathNotFunction:
   9347  * @ctxt:  the XPath Parser context
   9348  * @nargs:  the number of arguments
   9349  *
   9350  * Implement the not() XPath function
   9351  *    boolean not(boolean)
   9352  * The not function returns true if its argument is false,
   9353  * and false otherwise.
   9354  */
   9355 void
   9356 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9357     CHECK_ARITY(1);
   9358     CAST_TO_BOOLEAN;
   9359     CHECK_TYPE(XPATH_BOOLEAN);
   9360     ctxt->value->boolval = ! ctxt->value->boolval;
   9361 }
   9362 
   9363 /**
   9364  * xmlXPathTrueFunction:
   9365  * @ctxt:  the XPath Parser context
   9366  * @nargs:  the number of arguments
   9367  *
   9368  * Implement the true() XPath function
   9369  *    boolean true()
   9370  */
   9371 void
   9372 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9373     CHECK_ARITY(0);
   9374     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9375 }
   9376 
   9377 /**
   9378  * xmlXPathFalseFunction:
   9379  * @ctxt:  the XPath Parser context
   9380  * @nargs:  the number of arguments
   9381  *
   9382  * Implement the false() XPath function
   9383  *    boolean false()
   9384  */
   9385 void
   9386 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9387     CHECK_ARITY(0);
   9388     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9389 }
   9390 
   9391 /**
   9392  * xmlXPathLangFunction:
   9393  * @ctxt:  the XPath Parser context
   9394  * @nargs:  the number of arguments
   9395  *
   9396  * Implement the lang() XPath function
   9397  *    boolean lang(string)
   9398  * The lang function returns true or false depending on whether the
   9399  * language of the context node as specified by xml:lang attributes
   9400  * is the same as or is a sublanguage of the language specified by
   9401  * the argument string. The language of the context node is determined
   9402  * by the value of the xml:lang attribute on the context node, or, if
   9403  * the context node has no xml:lang attribute, by the value of the
   9404  * xml:lang attribute on the nearest ancestor of the context node that
   9405  * has an xml:lang attribute. If there is no such attribute, then lang
   9406  * returns false. If there is such an attribute, then lang returns
   9407  * true if the attribute value is equal to the argument ignoring case,
   9408  * or if there is some suffix starting with - such that the attribute
   9409  * value is equal to the argument ignoring that suffix of the attribute
   9410  * value and ignoring case.
   9411  */
   9412 void
   9413 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9414     xmlXPathObjectPtr val = NULL;
   9415     const xmlChar *theLang = NULL;
   9416     const xmlChar *lang;
   9417     int ret = 0;
   9418     int i;
   9419 
   9420     CHECK_ARITY(1);
   9421     CAST_TO_STRING;
   9422     CHECK_TYPE(XPATH_STRING);
   9423     val = valuePop(ctxt);
   9424     lang = val->stringval;
   9425     theLang = xmlNodeGetLang(ctxt->context->node);
   9426     if ((theLang != NULL) && (lang != NULL)) {
   9427         for (i = 0;lang[i] != 0;i++)
   9428 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9429 	        goto not_equal;
   9430 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9431 	    ret = 1;
   9432     }
   9433 not_equal:
   9434     if (theLang != NULL)
   9435 	xmlFree((void *)theLang);
   9436 
   9437     xmlXPathReleaseObject(ctxt->context, val);
   9438     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9439 }
   9440 
   9441 /**
   9442  * xmlXPathNumberFunction:
   9443  * @ctxt:  the XPath Parser context
   9444  * @nargs:  the number of arguments
   9445  *
   9446  * Implement the number() XPath function
   9447  *    number number(object?)
   9448  */
   9449 void
   9450 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9451     xmlXPathObjectPtr cur;
   9452     double res;
   9453 
   9454     if (ctxt == NULL) return;
   9455     if (nargs == 0) {
   9456 	if (ctxt->context->node == NULL) {
   9457 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9458 	} else {
   9459 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9460 
   9461 	    res = xmlXPathStringEvalNumber(content);
   9462 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9463 	    xmlFree(content);
   9464 	}
   9465 	return;
   9466     }
   9467 
   9468     CHECK_ARITY(1);
   9469     cur = valuePop(ctxt);
   9470     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9471 }
   9472 
   9473 /**
   9474  * xmlXPathSumFunction:
   9475  * @ctxt:  the XPath Parser context
   9476  * @nargs:  the number of arguments
   9477  *
   9478  * Implement the sum() XPath function
   9479  *    number sum(node-set)
   9480  * The sum function returns the sum of the values of the nodes in
   9481  * the argument node-set.
   9482  */
   9483 void
   9484 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9485     xmlXPathObjectPtr cur;
   9486     int i;
   9487     double res = 0.0;
   9488 
   9489     CHECK_ARITY(1);
   9490     if ((ctxt->value == NULL) ||
   9491 	((ctxt->value->type != XPATH_NODESET) &&
   9492 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9493 	XP_ERROR(XPATH_INVALID_TYPE);
   9494     cur = valuePop(ctxt);
   9495 
   9496     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9497 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9498 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9499 	}
   9500     }
   9501     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9502     xmlXPathReleaseObject(ctxt->context, cur);
   9503 }
   9504 
   9505 /*
   9506  * To assure working code on multiple platforms, we want to only depend
   9507  * upon the characteristic truncation of converting a floating point value
   9508  * to an integer.  Unfortunately, because of the different storage sizes
   9509  * of our internal floating point value (double) and integer (int), we
   9510  * can't directly convert (see bug 301162).  This macro is a messy
   9511  * 'workaround'
   9512  */
   9513 #define XTRUNC(f, v)            \
   9514     f = fmod((v), INT_MAX);     \
   9515     f = (v) - (f) + (double)((int)(f));
   9516 
   9517 /**
   9518  * xmlXPathFloorFunction:
   9519  * @ctxt:  the XPath Parser context
   9520  * @nargs:  the number of arguments
   9521  *
   9522  * Implement the floor() XPath function
   9523  *    number floor(number)
   9524  * The floor function returns the largest (closest to positive infinity)
   9525  * number that is not greater than the argument and that is an integer.
   9526  */
   9527 void
   9528 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9529     double f;
   9530 
   9531     CHECK_ARITY(1);
   9532     CAST_TO_NUMBER;
   9533     CHECK_TYPE(XPATH_NUMBER);
   9534 
   9535     XTRUNC(f, ctxt->value->floatval);
   9536     if (f != ctxt->value->floatval) {
   9537 	if (ctxt->value->floatval > 0)
   9538 	    ctxt->value->floatval = f;
   9539 	else
   9540 	    ctxt->value->floatval = f - 1;
   9541     }
   9542 }
   9543 
   9544 /**
   9545  * xmlXPathCeilingFunction:
   9546  * @ctxt:  the XPath Parser context
   9547  * @nargs:  the number of arguments
   9548  *
   9549  * Implement the ceiling() XPath function
   9550  *    number ceiling(number)
   9551  * The ceiling function returns the smallest (closest to negative infinity)
   9552  * number that is not less than the argument and that is an integer.
   9553  */
   9554 void
   9555 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9556     double f;
   9557 
   9558     CHECK_ARITY(1);
   9559     CAST_TO_NUMBER;
   9560     CHECK_TYPE(XPATH_NUMBER);
   9561 
   9562 #if 0
   9563     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9564 #else
   9565     XTRUNC(f, ctxt->value->floatval);
   9566     if (f != ctxt->value->floatval) {
   9567 	if (ctxt->value->floatval > 0)
   9568 	    ctxt->value->floatval = f + 1;
   9569 	else {
   9570 	    if (ctxt->value->floatval < 0 && f == 0)
   9571 	        ctxt->value->floatval = xmlXPathNZERO;
   9572 	    else
   9573 	        ctxt->value->floatval = f;
   9574 	}
   9575 
   9576     }
   9577 #endif
   9578 }
   9579 
   9580 /**
   9581  * xmlXPathRoundFunction:
   9582  * @ctxt:  the XPath Parser context
   9583  * @nargs:  the number of arguments
   9584  *
   9585  * Implement the round() XPath function
   9586  *    number round(number)
   9587  * The round function returns the number that is closest to the
   9588  * argument and that is an integer. If there are two such numbers,
   9589  * then the one that is even is returned.
   9590  */
   9591 void
   9592 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9593     double f;
   9594 
   9595     CHECK_ARITY(1);
   9596     CAST_TO_NUMBER;
   9597     CHECK_TYPE(XPATH_NUMBER);
   9598 
   9599     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
   9600 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
   9601 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
   9602 	(ctxt->value->floatval == 0.0))
   9603 	return;
   9604 
   9605     XTRUNC(f, ctxt->value->floatval);
   9606     if (ctxt->value->floatval < 0) {
   9607 	if (ctxt->value->floatval < f - 0.5)
   9608 	    ctxt->value->floatval = f - 1;
   9609 	else
   9610 	    ctxt->value->floatval = f;
   9611 	if (ctxt->value->floatval == 0)
   9612 	    ctxt->value->floatval = xmlXPathNZERO;
   9613     } else {
   9614 	if (ctxt->value->floatval < f + 0.5)
   9615 	    ctxt->value->floatval = f;
   9616 	else
   9617 	    ctxt->value->floatval = f + 1;
   9618     }
   9619 }
   9620 
   9621 /************************************************************************
   9622  *									*
   9623  *			The Parser					*
   9624  *									*
   9625  ************************************************************************/
   9626 
   9627 /*
   9628  * a few forward declarations since we use a recursive call based
   9629  * implementation.
   9630  */
   9631 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9632 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9633 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9634 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9635 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9636 	                                  int qualified);
   9637 
   9638 /**
   9639  * xmlXPathCurrentChar:
   9640  * @ctxt:  the XPath parser context
   9641  * @cur:  pointer to the beginning of the char
   9642  * @len:  pointer to the length of the char read
   9643  *
   9644  * The current char value, if using UTF-8 this may actually span multiple
   9645  * bytes in the input buffer.
   9646  *
   9647  * Returns the current char value and its length
   9648  */
   9649 
   9650 static int
   9651 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9652     unsigned char c;
   9653     unsigned int val;
   9654     const xmlChar *cur;
   9655 
   9656     if (ctxt == NULL)
   9657 	return(0);
   9658     cur = ctxt->cur;
   9659 
   9660     /*
   9661      * We are supposed to handle UTF8, check it's valid
   9662      * From rfc2044: encoding of the Unicode values on UTF-8:
   9663      *
   9664      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9665      * 0000 0000-0000 007F   0xxxxxxx
   9666      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9667      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9668      *
   9669      * Check for the 0x110000 limit too
   9670      */
   9671     c = *cur;
   9672     if (c & 0x80) {
   9673 	if ((cur[1] & 0xc0) != 0x80)
   9674 	    goto encoding_error;
   9675 	if ((c & 0xe0) == 0xe0) {
   9676 
   9677 	    if ((cur[2] & 0xc0) != 0x80)
   9678 		goto encoding_error;
   9679 	    if ((c & 0xf0) == 0xf0) {
   9680 		if (((c & 0xf8) != 0xf0) ||
   9681 		    ((cur[3] & 0xc0) != 0x80))
   9682 		    goto encoding_error;
   9683 		/* 4-byte code */
   9684 		*len = 4;
   9685 		val = (cur[0] & 0x7) << 18;
   9686 		val |= (cur[1] & 0x3f) << 12;
   9687 		val |= (cur[2] & 0x3f) << 6;
   9688 		val |= cur[3] & 0x3f;
   9689 	    } else {
   9690 	      /* 3-byte code */
   9691 		*len = 3;
   9692 		val = (cur[0] & 0xf) << 12;
   9693 		val |= (cur[1] & 0x3f) << 6;
   9694 		val |= cur[2] & 0x3f;
   9695 	    }
   9696 	} else {
   9697 	  /* 2-byte code */
   9698 	    *len = 2;
   9699 	    val = (cur[0] & 0x1f) << 6;
   9700 	    val |= cur[1] & 0x3f;
   9701 	}
   9702 	if (!IS_CHAR(val)) {
   9703 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9704 	}
   9705 	return(val);
   9706     } else {
   9707 	/* 1-byte code */
   9708 	*len = 1;
   9709 	return((int) *cur);
   9710     }
   9711 encoding_error:
   9712     /*
   9713      * If we detect an UTF8 error that probably means that the
   9714      * input encoding didn't get properly advertised in the
   9715      * declaration header. Report the error and switch the encoding
   9716      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9717      * encoding !)
   9718      */
   9719     *len = 0;
   9720     XP_ERROR0(XPATH_ENCODING_ERROR);
   9721 }
   9722 
   9723 /**
   9724  * xmlXPathParseNCName:
   9725  * @ctxt:  the XPath Parser context
   9726  *
   9727  * parse an XML namespace non qualified name.
   9728  *
   9729  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9730  *
   9731  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9732  *                       CombiningChar | Extender
   9733  *
   9734  * Returns the namespace name or NULL
   9735  */
   9736 
   9737 xmlChar *
   9738 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9739     const xmlChar *in;
   9740     xmlChar *ret;
   9741     int count = 0;
   9742 
   9743     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9744     /*
   9745      * Accelerator for simple ASCII names
   9746      */
   9747     in = ctxt->cur;
   9748     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9749 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9750 	(*in == '_')) {
   9751 	in++;
   9752 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9753 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9754 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9755 	       (*in == '_') || (*in == '.') ||
   9756 	       (*in == '-'))
   9757 	    in++;
   9758 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9759             (*in == '[') || (*in == ']') || (*in == ':') ||
   9760             (*in == '@') || (*in == '*')) {
   9761 	    count = in - ctxt->cur;
   9762 	    if (count == 0)
   9763 		return(NULL);
   9764 	    ret = xmlStrndup(ctxt->cur, count);
   9765 	    ctxt->cur = in;
   9766 	    return(ret);
   9767 	}
   9768     }
   9769     return(xmlXPathParseNameComplex(ctxt, 0));
   9770 }
   9771 
   9772 
   9773 /**
   9774  * xmlXPathParseQName:
   9775  * @ctxt:  the XPath Parser context
   9776  * @prefix:  a xmlChar **
   9777  *
   9778  * parse an XML qualified name
   9779  *
   9780  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9781  *
   9782  * [NS 6] Prefix ::= NCName
   9783  *
   9784  * [NS 7] LocalPart ::= NCName
   9785  *
   9786  * Returns the function returns the local part, and prefix is updated
   9787  *   to get the Prefix if any.
   9788  */
   9789 
   9790 static xmlChar *
   9791 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9792     xmlChar *ret = NULL;
   9793 
   9794     *prefix = NULL;
   9795     ret = xmlXPathParseNCName(ctxt);
   9796     if (ret && CUR == ':') {
   9797         *prefix = ret;
   9798 	NEXT;
   9799 	ret = xmlXPathParseNCName(ctxt);
   9800     }
   9801     return(ret);
   9802 }
   9803 
   9804 /**
   9805  * xmlXPathParseName:
   9806  * @ctxt:  the XPath Parser context
   9807  *
   9808  * parse an XML name
   9809  *
   9810  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9811  *                  CombiningChar | Extender
   9812  *
   9813  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9814  *
   9815  * Returns the namespace name or NULL
   9816  */
   9817 
   9818 xmlChar *
   9819 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9820     const xmlChar *in;
   9821     xmlChar *ret;
   9822     int count = 0;
   9823 
   9824     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9825     /*
   9826      * Accelerator for simple ASCII names
   9827      */
   9828     in = ctxt->cur;
   9829     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9830 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9831 	(*in == '_') || (*in == ':')) {
   9832 	in++;
   9833 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9834 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9835 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9836 	       (*in == '_') || (*in == '-') ||
   9837 	       (*in == ':') || (*in == '.'))
   9838 	    in++;
   9839 	if ((*in > 0) && (*in < 0x80)) {
   9840 	    count = in - ctxt->cur;
   9841 	    ret = xmlStrndup(ctxt->cur, count);
   9842 	    ctxt->cur = in;
   9843 	    return(ret);
   9844 	}
   9845     }
   9846     return(xmlXPathParseNameComplex(ctxt, 1));
   9847 }
   9848 
   9849 static xmlChar *
   9850 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9851     xmlChar buf[XML_MAX_NAMELEN + 5];
   9852     int len = 0, l;
   9853     int c;
   9854 
   9855     /*
   9856      * Handler for more complex cases
   9857      */
   9858     c = CUR_CHAR(l);
   9859     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9860         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9861         (c == '*') || /* accelerators */
   9862 	(!IS_LETTER(c) && (c != '_') &&
   9863          ((qualified) && (c != ':')))) {
   9864 	return(NULL);
   9865     }
   9866 
   9867     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9868 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   9869             (c == '.') || (c == '-') ||
   9870 	    (c == '_') || ((qualified) && (c == ':')) ||
   9871 	    (IS_COMBINING(c)) ||
   9872 	    (IS_EXTENDER(c)))) {
   9873 	COPY_BUF(l,buf,len,c);
   9874 	NEXTL(l);
   9875 	c = CUR_CHAR(l);
   9876 	if (len >= XML_MAX_NAMELEN) {
   9877 	    /*
   9878 	     * Okay someone managed to make a huge name, so he's ready to pay
   9879 	     * for the processing speed.
   9880 	     */
   9881 	    xmlChar *buffer;
   9882 	    int max = len * 2;
   9883 
   9884 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   9885 	    if (buffer == NULL) {
   9886 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9887 	    }
   9888 	    memcpy(buffer, buf, len);
   9889 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   9890 		   (c == '.') || (c == '-') ||
   9891 		   (c == '_') || ((qualified) && (c == ':')) ||
   9892 		   (IS_COMBINING(c)) ||
   9893 		   (IS_EXTENDER(c))) {
   9894 		if (len + 10 > max) {
   9895 		    max *= 2;
   9896 		    buffer = (xmlChar *) xmlRealloc(buffer,
   9897 			                            max * sizeof(xmlChar));
   9898 		    if (buffer == NULL) {
   9899 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9900 		    }
   9901 		}
   9902 		COPY_BUF(l,buffer,len,c);
   9903 		NEXTL(l);
   9904 		c = CUR_CHAR(l);
   9905 	    }
   9906 	    buffer[len] = 0;
   9907 	    return(buffer);
   9908 	}
   9909     }
   9910     if (len == 0)
   9911 	return(NULL);
   9912     return(xmlStrndup(buf, len));
   9913 }
   9914 
   9915 #define MAX_FRAC 20
   9916 
   9917 /*
   9918  * These are used as divisors for the fractional part of a number.
   9919  * Since the table includes 1.0 (representing '0' fractional digits),
   9920  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
   9921  */
   9922 static double my_pow10[MAX_FRAC+1] = {
   9923     1.0, 10.0, 100.0, 1000.0, 10000.0,
   9924     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
   9925     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
   9926     100000000000000.0,
   9927     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
   9928     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
   9929 };
   9930 
   9931 /**
   9932  * xmlXPathStringEvalNumber:
   9933  * @str:  A string to scan
   9934  *
   9935  *  [30a]  Float  ::= Number ('e' Digits?)?
   9936  *
   9937  *  [30]   Number ::=   Digits ('.' Digits?)?
   9938  *                    | '.' Digits
   9939  *  [31]   Digits ::=   [0-9]+
   9940  *
   9941  * Compile a Number in the string
   9942  * In complement of the Number expression, this function also handles
   9943  * negative values : '-' Number.
   9944  *
   9945  * Returns the double value.
   9946  */
   9947 double
   9948 xmlXPathStringEvalNumber(const xmlChar *str) {
   9949     const xmlChar *cur = str;
   9950     double ret;
   9951     int ok = 0;
   9952     int isneg = 0;
   9953     int exponent = 0;
   9954     int is_exponent_negative = 0;
   9955 #ifdef __GNUC__
   9956     unsigned long tmp = 0;
   9957     double temp;
   9958 #endif
   9959     if (cur == NULL) return(0);
   9960     while (IS_BLANK_CH(*cur)) cur++;
   9961     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   9962         return(xmlXPathNAN);
   9963     }
   9964     if (*cur == '-') {
   9965 	isneg = 1;
   9966 	cur++;
   9967     }
   9968 
   9969 #ifdef __GNUC__
   9970     /*
   9971      * tmp/temp is a workaround against a gcc compiler bug
   9972      * http://veillard.com/gcc.bug
   9973      */
   9974     ret = 0;
   9975     while ((*cur >= '0') && (*cur <= '9')) {
   9976 	ret = ret * 10;
   9977 	tmp = (*cur - '0');
   9978 	ok = 1;
   9979 	cur++;
   9980 	temp = (double) tmp;
   9981 	ret = ret + temp;
   9982     }
   9983 #else
   9984     ret = 0;
   9985     while ((*cur >= '0') && (*cur <= '9')) {
   9986 	ret = ret * 10 + (*cur - '0');
   9987 	ok = 1;
   9988 	cur++;
   9989     }
   9990 #endif
   9991 
   9992     if (*cur == '.') {
   9993 	int v, frac = 0;
   9994 	double fraction = 0;
   9995 
   9996         cur++;
   9997 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   9998 	    return(xmlXPathNAN);
   9999 	}
   10000 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
   10001 	    v = (*cur - '0');
   10002 	    fraction = fraction * 10 + v;
   10003 	    frac = frac + 1;
   10004 	    cur++;
   10005 	}
   10006 	fraction /= my_pow10[frac];
   10007 	ret = ret + fraction;
   10008 	while ((*cur >= '0') && (*cur <= '9'))
   10009 	    cur++;
   10010     }
   10011     if ((*cur == 'e') || (*cur == 'E')) {
   10012       cur++;
   10013       if (*cur == '-') {
   10014 	is_exponent_negative = 1;
   10015 	cur++;
   10016       } else if (*cur == '+') {
   10017         cur++;
   10018       }
   10019       while ((*cur >= '0') && (*cur <= '9')) {
   10020 	exponent = exponent * 10 + (*cur - '0');
   10021 	cur++;
   10022       }
   10023     }
   10024     while (IS_BLANK_CH(*cur)) cur++;
   10025     if (*cur != 0) return(xmlXPathNAN);
   10026     if (isneg) ret = -ret;
   10027     if (is_exponent_negative) exponent = -exponent;
   10028     ret *= pow(10.0, (double)exponent);
   10029     return(ret);
   10030 }
   10031 
   10032 /**
   10033  * xmlXPathCompNumber:
   10034  * @ctxt:  the XPath Parser context
   10035  *
   10036  *  [30]   Number ::=   Digits ('.' Digits?)?
   10037  *                    | '.' Digits
   10038  *  [31]   Digits ::=   [0-9]+
   10039  *
   10040  * Compile a Number, then push it on the stack
   10041  *
   10042  */
   10043 static void
   10044 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10045 {
   10046     double ret = 0.0;
   10047     double mult = 1;
   10048     int ok = 0;
   10049     int exponent = 0;
   10050     int is_exponent_negative = 0;
   10051 #ifdef __GNUC__
   10052     unsigned long tmp = 0;
   10053     double temp;
   10054 #endif
   10055 
   10056     CHECK_ERROR;
   10057     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10058         XP_ERROR(XPATH_NUMBER_ERROR);
   10059     }
   10060 #ifdef __GNUC__
   10061     /*
   10062      * tmp/temp is a workaround against a gcc compiler bug
   10063      * http://veillard.com/gcc.bug
   10064      */
   10065     ret = 0;
   10066     while ((CUR >= '0') && (CUR <= '9')) {
   10067 	ret = ret * 10;
   10068 	tmp = (CUR - '0');
   10069         ok = 1;
   10070         NEXT;
   10071 	temp = (double) tmp;
   10072 	ret = ret + temp;
   10073     }
   10074 #else
   10075     ret = 0;
   10076     while ((CUR >= '0') && (CUR <= '9')) {
   10077 	ret = ret * 10 + (CUR - '0');
   10078 	ok = 1;
   10079 	NEXT;
   10080     }
   10081 #endif
   10082     if (CUR == '.') {
   10083         NEXT;
   10084         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10085             XP_ERROR(XPATH_NUMBER_ERROR);
   10086         }
   10087         while ((CUR >= '0') && (CUR <= '9')) {
   10088             mult /= 10;
   10089             ret = ret + (CUR - '0') * mult;
   10090             NEXT;
   10091         }
   10092     }
   10093     if ((CUR == 'e') || (CUR == 'E')) {
   10094         NEXT;
   10095         if (CUR == '-') {
   10096             is_exponent_negative = 1;
   10097             NEXT;
   10098         } else if (CUR == '+') {
   10099 	    NEXT;
   10100 	}
   10101         while ((CUR >= '0') && (CUR <= '9')) {
   10102             exponent = exponent * 10 + (CUR - '0');
   10103             NEXT;
   10104         }
   10105         if (is_exponent_negative)
   10106             exponent = -exponent;
   10107         ret *= pow(10.0, (double) exponent);
   10108     }
   10109     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10110                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10111 }
   10112 
   10113 /**
   10114  * xmlXPathParseLiteral:
   10115  * @ctxt:  the XPath Parser context
   10116  *
   10117  * Parse a Literal
   10118  *
   10119  *  [29]   Literal ::=   '"' [^"]* '"'
   10120  *                    | "'" [^']* "'"
   10121  *
   10122  * Returns the value found or NULL in case of error
   10123  */
   10124 static xmlChar *
   10125 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10126     const xmlChar *q;
   10127     xmlChar *ret = NULL;
   10128 
   10129     if (CUR == '"') {
   10130         NEXT;
   10131 	q = CUR_PTR;
   10132 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10133 	    NEXT;
   10134 	if (!IS_CHAR_CH(CUR)) {
   10135 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10136 	} else {
   10137 	    ret = xmlStrndup(q, CUR_PTR - q);
   10138 	    NEXT;
   10139         }
   10140     } else if (CUR == '\'') {
   10141         NEXT;
   10142 	q = CUR_PTR;
   10143 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10144 	    NEXT;
   10145 	if (!IS_CHAR_CH(CUR)) {
   10146 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10147 	} else {
   10148 	    ret = xmlStrndup(q, CUR_PTR - q);
   10149 	    NEXT;
   10150         }
   10151     } else {
   10152 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10153     }
   10154     return(ret);
   10155 }
   10156 
   10157 /**
   10158  * xmlXPathCompLiteral:
   10159  * @ctxt:  the XPath Parser context
   10160  *
   10161  * Parse a Literal and push it on the stack.
   10162  *
   10163  *  [29]   Literal ::=   '"' [^"]* '"'
   10164  *                    | "'" [^']* "'"
   10165  *
   10166  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10167  */
   10168 static void
   10169 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10170     const xmlChar *q;
   10171     xmlChar *ret = NULL;
   10172 
   10173     if (CUR == '"') {
   10174         NEXT;
   10175 	q = CUR_PTR;
   10176 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10177 	    NEXT;
   10178 	if (!IS_CHAR_CH(CUR)) {
   10179 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10180 	} else {
   10181 	    ret = xmlStrndup(q, CUR_PTR - q);
   10182 	    NEXT;
   10183         }
   10184     } else if (CUR == '\'') {
   10185         NEXT;
   10186 	q = CUR_PTR;
   10187 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10188 	    NEXT;
   10189 	if (!IS_CHAR_CH(CUR)) {
   10190 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10191 	} else {
   10192 	    ret = xmlStrndup(q, CUR_PTR - q);
   10193 	    NEXT;
   10194         }
   10195     } else {
   10196 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10197     }
   10198     if (ret == NULL) return;
   10199     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10200 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10201     xmlFree(ret);
   10202 }
   10203 
   10204 /**
   10205  * xmlXPathCompVariableReference:
   10206  * @ctxt:  the XPath Parser context
   10207  *
   10208  * Parse a VariableReference, evaluate it and push it on the stack.
   10209  *
   10210  * The variable bindings consist of a mapping from variable names
   10211  * to variable values. The value of a variable is an object, which can be
   10212  * of any of the types that are possible for the value of an expression,
   10213  * and may also be of additional types not specified here.
   10214  *
   10215  * Early evaluation is possible since:
   10216  * The variable bindings [...] used to evaluate a subexpression are
   10217  * always the same as those used to evaluate the containing expression.
   10218  *
   10219  *  [36]   VariableReference ::=   '$' QName
   10220  */
   10221 static void
   10222 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10223     xmlChar *name;
   10224     xmlChar *prefix;
   10225 
   10226     SKIP_BLANKS;
   10227     if (CUR != '$') {
   10228 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10229     }
   10230     NEXT;
   10231     name = xmlXPathParseQName(ctxt, &prefix);
   10232     if (name == NULL) {
   10233 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10234     }
   10235     ctxt->comp->last = -1;
   10236     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10237 	           name, prefix);
   10238     SKIP_BLANKS;
   10239     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10240 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
   10241     }
   10242 }
   10243 
   10244 /**
   10245  * xmlXPathIsNodeType:
   10246  * @name:  a name string
   10247  *
   10248  * Is the name given a NodeType one.
   10249  *
   10250  *  [38]   NodeType ::=   'comment'
   10251  *                    | 'text'
   10252  *                    | 'processing-instruction'
   10253  *                    | 'node'
   10254  *
   10255  * Returns 1 if true 0 otherwise
   10256  */
   10257 int
   10258 xmlXPathIsNodeType(const xmlChar *name) {
   10259     if (name == NULL)
   10260 	return(0);
   10261 
   10262     if (xmlStrEqual(name, BAD_CAST "node"))
   10263 	return(1);
   10264     if (xmlStrEqual(name, BAD_CAST "text"))
   10265 	return(1);
   10266     if (xmlStrEqual(name, BAD_CAST "comment"))
   10267 	return(1);
   10268     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10269 	return(1);
   10270     return(0);
   10271 }
   10272 
   10273 /**
   10274  * xmlXPathCompFunctionCall:
   10275  * @ctxt:  the XPath Parser context
   10276  *
   10277  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10278  *  [17]   Argument ::=   Expr
   10279  *
   10280  * Compile a function call, the evaluation of all arguments are
   10281  * pushed on the stack
   10282  */
   10283 static void
   10284 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10285     xmlChar *name;
   10286     xmlChar *prefix;
   10287     int nbargs = 0;
   10288     int sort = 1;
   10289 
   10290     name = xmlXPathParseQName(ctxt, &prefix);
   10291     if (name == NULL) {
   10292 	xmlFree(prefix);
   10293 	XP_ERROR(XPATH_EXPR_ERROR);
   10294     }
   10295     SKIP_BLANKS;
   10296 #ifdef DEBUG_EXPR
   10297     if (prefix == NULL)
   10298 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10299 			name);
   10300     else
   10301 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10302 			prefix, name);
   10303 #endif
   10304 
   10305     if (CUR != '(') {
   10306 	XP_ERROR(XPATH_EXPR_ERROR);
   10307     }
   10308     NEXT;
   10309     SKIP_BLANKS;
   10310 
   10311     /*
   10312     * Optimization for count(): we don't need the node-set to be sorted.
   10313     */
   10314     if ((prefix == NULL) && (name[0] == 'c') &&
   10315 	xmlStrEqual(name, BAD_CAST "count"))
   10316     {
   10317 	sort = 0;
   10318     }
   10319     ctxt->comp->last = -1;
   10320     if (CUR != ')') {
   10321 	while (CUR != 0) {
   10322 	    int op1 = ctxt->comp->last;
   10323 	    ctxt->comp->last = -1;
   10324 	    xmlXPathCompileExpr(ctxt, sort);
   10325 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10326 		xmlFree(name);
   10327 		xmlFree(prefix);
   10328 		return;
   10329 	    }
   10330 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10331 	    nbargs++;
   10332 	    if (CUR == ')') break;
   10333 	    if (CUR != ',') {
   10334 		XP_ERROR(XPATH_EXPR_ERROR);
   10335 	    }
   10336 	    NEXT;
   10337 	    SKIP_BLANKS;
   10338 	}
   10339     }
   10340     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10341 	           name, prefix);
   10342     NEXT;
   10343     SKIP_BLANKS;
   10344 }
   10345 
   10346 /**
   10347  * xmlXPathCompPrimaryExpr:
   10348  * @ctxt:  the XPath Parser context
   10349  *
   10350  *  [15]   PrimaryExpr ::=   VariableReference
   10351  *                | '(' Expr ')'
   10352  *                | Literal
   10353  *                | Number
   10354  *                | FunctionCall
   10355  *
   10356  * Compile a primary expression.
   10357  */
   10358 static void
   10359 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10360     SKIP_BLANKS;
   10361     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10362     else if (CUR == '(') {
   10363 	NEXT;
   10364 	SKIP_BLANKS;
   10365 	xmlXPathCompileExpr(ctxt, 1);
   10366 	CHECK_ERROR;
   10367 	if (CUR != ')') {
   10368 	    XP_ERROR(XPATH_EXPR_ERROR);
   10369 	}
   10370 	NEXT;
   10371 	SKIP_BLANKS;
   10372     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10373 	xmlXPathCompNumber(ctxt);
   10374     } else if ((CUR == '\'') || (CUR == '"')) {
   10375 	xmlXPathCompLiteral(ctxt);
   10376     } else {
   10377 	xmlXPathCompFunctionCall(ctxt);
   10378     }
   10379     SKIP_BLANKS;
   10380 }
   10381 
   10382 /**
   10383  * xmlXPathCompFilterExpr:
   10384  * @ctxt:  the XPath Parser context
   10385  *
   10386  *  [20]   FilterExpr ::=   PrimaryExpr
   10387  *               | FilterExpr Predicate
   10388  *
   10389  * Compile a filter expression.
   10390  * Square brackets are used to filter expressions in the same way that
   10391  * they are used in location paths. It is an error if the expression to
   10392  * be filtered does not evaluate to a node-set. The context node list
   10393  * used for evaluating the expression in square brackets is the node-set
   10394  * to be filtered listed in document order.
   10395  */
   10396 
   10397 static void
   10398 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10399     xmlXPathCompPrimaryExpr(ctxt);
   10400     CHECK_ERROR;
   10401     SKIP_BLANKS;
   10402 
   10403     while (CUR == '[') {
   10404 	xmlXPathCompPredicate(ctxt, 1);
   10405 	SKIP_BLANKS;
   10406     }
   10407 
   10408 
   10409 }
   10410 
   10411 /**
   10412  * xmlXPathScanName:
   10413  * @ctxt:  the XPath Parser context
   10414  *
   10415  * Trickery: parse an XML name but without consuming the input flow
   10416  * Needed to avoid insanity in the parser state.
   10417  *
   10418  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10419  *                  CombiningChar | Extender
   10420  *
   10421  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10422  *
   10423  * [6] Names ::= Name (S Name)*
   10424  *
   10425  * Returns the Name parsed or NULL
   10426  */
   10427 
   10428 static xmlChar *
   10429 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10430     int len = 0, l;
   10431     int c;
   10432     const xmlChar *cur;
   10433     xmlChar *ret;
   10434 
   10435     cur = ctxt->cur;
   10436 
   10437     c = CUR_CHAR(l);
   10438     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10439 	(!IS_LETTER(c) && (c != '_') &&
   10440          (c != ':'))) {
   10441 	return(NULL);
   10442     }
   10443 
   10444     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10445 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10446             (c == '.') || (c == '-') ||
   10447 	    (c == '_') || (c == ':') ||
   10448 	    (IS_COMBINING(c)) ||
   10449 	    (IS_EXTENDER(c)))) {
   10450 	len += l;
   10451 	NEXTL(l);
   10452 	c = CUR_CHAR(l);
   10453     }
   10454     ret = xmlStrndup(cur, ctxt->cur - cur);
   10455     ctxt->cur = cur;
   10456     return(ret);
   10457 }
   10458 
   10459 /**
   10460  * xmlXPathCompPathExpr:
   10461  * @ctxt:  the XPath Parser context
   10462  *
   10463  *  [19]   PathExpr ::=   LocationPath
   10464  *               | FilterExpr
   10465  *               | FilterExpr '/' RelativeLocationPath
   10466  *               | FilterExpr '//' RelativeLocationPath
   10467  *
   10468  * Compile a path expression.
   10469  * The / operator and // operators combine an arbitrary expression
   10470  * and a relative location path. It is an error if the expression
   10471  * does not evaluate to a node-set.
   10472  * The / operator does composition in the same way as when / is
   10473  * used in a location path. As in location paths, // is short for
   10474  * /descendant-or-self::node()/.
   10475  */
   10476 
   10477 static void
   10478 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10479     int lc = 1;           /* Should we branch to LocationPath ?         */
   10480     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10481 
   10482     SKIP_BLANKS;
   10483     if ((CUR == '$') || (CUR == '(') ||
   10484 	(IS_ASCII_DIGIT(CUR)) ||
   10485         (CUR == '\'') || (CUR == '"') ||
   10486 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10487 	lc = 0;
   10488     } else if (CUR == '*') {
   10489 	/* relative or absolute location path */
   10490 	lc = 1;
   10491     } else if (CUR == '/') {
   10492 	/* relative or absolute location path */
   10493 	lc = 1;
   10494     } else if (CUR == '@') {
   10495 	/* relative abbreviated attribute location path */
   10496 	lc = 1;
   10497     } else if (CUR == '.') {
   10498 	/* relative abbreviated attribute location path */
   10499 	lc = 1;
   10500     } else {
   10501 	/*
   10502 	 * Problem is finding if we have a name here whether it's:
   10503 	 *   - a nodetype
   10504 	 *   - a function call in which case it's followed by '('
   10505 	 *   - an axis in which case it's followed by ':'
   10506 	 *   - a element name
   10507 	 * We do an a priori analysis here rather than having to
   10508 	 * maintain parsed token content through the recursive function
   10509 	 * calls. This looks uglier but makes the code easier to
   10510 	 * read/write/debug.
   10511 	 */
   10512 	SKIP_BLANKS;
   10513 	name = xmlXPathScanName(ctxt);
   10514 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10515 #ifdef DEBUG_STEP
   10516 	    xmlGenericError(xmlGenericErrorContext,
   10517 		    "PathExpr: Axis\n");
   10518 #endif
   10519 	    lc = 1;
   10520 	    xmlFree(name);
   10521 	} else if (name != NULL) {
   10522 	    int len =xmlStrlen(name);
   10523 
   10524 
   10525 	    while (NXT(len) != 0) {
   10526 		if (NXT(len) == '/') {
   10527 		    /* element name */
   10528 #ifdef DEBUG_STEP
   10529 		    xmlGenericError(xmlGenericErrorContext,
   10530 			    "PathExpr: AbbrRelLocation\n");
   10531 #endif
   10532 		    lc = 1;
   10533 		    break;
   10534 		} else if (IS_BLANK_CH(NXT(len))) {
   10535 		    /* ignore blanks */
   10536 		    ;
   10537 		} else if (NXT(len) == ':') {
   10538 #ifdef DEBUG_STEP
   10539 		    xmlGenericError(xmlGenericErrorContext,
   10540 			    "PathExpr: AbbrRelLocation\n");
   10541 #endif
   10542 		    lc = 1;
   10543 		    break;
   10544 		} else if ((NXT(len) == '(')) {
   10545 		    /* Note Type or Function */
   10546 		    if (xmlXPathIsNodeType(name)) {
   10547 #ifdef DEBUG_STEP
   10548 		        xmlGenericError(xmlGenericErrorContext,
   10549 				"PathExpr: Type search\n");
   10550 #endif
   10551 			lc = 1;
   10552 		    } else {
   10553 #ifdef DEBUG_STEP
   10554 		        xmlGenericError(xmlGenericErrorContext,
   10555 				"PathExpr: function call\n");
   10556 #endif
   10557 			lc = 0;
   10558 		    }
   10559                     break;
   10560 		} else if ((NXT(len) == '[')) {
   10561 		    /* element name */
   10562 #ifdef DEBUG_STEP
   10563 		    xmlGenericError(xmlGenericErrorContext,
   10564 			    "PathExpr: AbbrRelLocation\n");
   10565 #endif
   10566 		    lc = 1;
   10567 		    break;
   10568 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10569 			   (NXT(len) == '=')) {
   10570 		    lc = 1;
   10571 		    break;
   10572 		} else {
   10573 		    lc = 1;
   10574 		    break;
   10575 		}
   10576 		len++;
   10577 	    }
   10578 	    if (NXT(len) == 0) {
   10579 #ifdef DEBUG_STEP
   10580 		xmlGenericError(xmlGenericErrorContext,
   10581 			"PathExpr: AbbrRelLocation\n");
   10582 #endif
   10583 		/* element name */
   10584 		lc = 1;
   10585 	    }
   10586 	    xmlFree(name);
   10587 	} else {
   10588 	    /* make sure all cases are covered explicitly */
   10589 	    XP_ERROR(XPATH_EXPR_ERROR);
   10590 	}
   10591     }
   10592 
   10593     if (lc) {
   10594 	if (CUR == '/') {
   10595 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10596 	} else {
   10597 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10598 	}
   10599 	xmlXPathCompLocationPath(ctxt);
   10600     } else {
   10601 	xmlXPathCompFilterExpr(ctxt);
   10602 	CHECK_ERROR;
   10603 	if ((CUR == '/') && (NXT(1) == '/')) {
   10604 	    SKIP(2);
   10605 	    SKIP_BLANKS;
   10606 
   10607 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10608 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10609 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10610 
   10611 	    xmlXPathCompRelativeLocationPath(ctxt);
   10612 	} else if (CUR == '/') {
   10613 	    xmlXPathCompRelativeLocationPath(ctxt);
   10614 	}
   10615     }
   10616     SKIP_BLANKS;
   10617 }
   10618 
   10619 /**
   10620  * xmlXPathCompUnionExpr:
   10621  * @ctxt:  the XPath Parser context
   10622  *
   10623  *  [18]   UnionExpr ::=   PathExpr
   10624  *               | UnionExpr '|' PathExpr
   10625  *
   10626  * Compile an union expression.
   10627  */
   10628 
   10629 static void
   10630 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10631     xmlXPathCompPathExpr(ctxt);
   10632     CHECK_ERROR;
   10633     SKIP_BLANKS;
   10634     while (CUR == '|') {
   10635 	int op1 = ctxt->comp->last;
   10636 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10637 
   10638 	NEXT;
   10639 	SKIP_BLANKS;
   10640 	xmlXPathCompPathExpr(ctxt);
   10641 
   10642 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10643 
   10644 	SKIP_BLANKS;
   10645     }
   10646 }
   10647 
   10648 /**
   10649  * xmlXPathCompUnaryExpr:
   10650  * @ctxt:  the XPath Parser context
   10651  *
   10652  *  [27]   UnaryExpr ::=   UnionExpr
   10653  *                   | '-' UnaryExpr
   10654  *
   10655  * Compile an unary expression.
   10656  */
   10657 
   10658 static void
   10659 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10660     int minus = 0;
   10661     int found = 0;
   10662 
   10663     SKIP_BLANKS;
   10664     while (CUR == '-') {
   10665         minus = 1 - minus;
   10666 	found = 1;
   10667 	NEXT;
   10668 	SKIP_BLANKS;
   10669     }
   10670 
   10671     xmlXPathCompUnionExpr(ctxt);
   10672     CHECK_ERROR;
   10673     if (found) {
   10674 	if (minus)
   10675 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10676 	else
   10677 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10678     }
   10679 }
   10680 
   10681 /**
   10682  * xmlXPathCompMultiplicativeExpr:
   10683  * @ctxt:  the XPath Parser context
   10684  *
   10685  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10686  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10687  *                   | MultiplicativeExpr 'div' UnaryExpr
   10688  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10689  *  [34]   MultiplyOperator ::=   '*'
   10690  *
   10691  * Compile an Additive expression.
   10692  */
   10693 
   10694 static void
   10695 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10696     xmlXPathCompUnaryExpr(ctxt);
   10697     CHECK_ERROR;
   10698     SKIP_BLANKS;
   10699     while ((CUR == '*') ||
   10700            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10701            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10702 	int op = -1;
   10703 	int op1 = ctxt->comp->last;
   10704 
   10705         if (CUR == '*') {
   10706 	    op = 0;
   10707 	    NEXT;
   10708 	} else if (CUR == 'd') {
   10709 	    op = 1;
   10710 	    SKIP(3);
   10711 	} else if (CUR == 'm') {
   10712 	    op = 2;
   10713 	    SKIP(3);
   10714 	}
   10715 	SKIP_BLANKS;
   10716         xmlXPathCompUnaryExpr(ctxt);
   10717 	CHECK_ERROR;
   10718 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10719 	SKIP_BLANKS;
   10720     }
   10721 }
   10722 
   10723 /**
   10724  * xmlXPathCompAdditiveExpr:
   10725  * @ctxt:  the XPath Parser context
   10726  *
   10727  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10728  *                   | AdditiveExpr '+' MultiplicativeExpr
   10729  *                   | AdditiveExpr '-' MultiplicativeExpr
   10730  *
   10731  * Compile an Additive expression.
   10732  */
   10733 
   10734 static void
   10735 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10736 
   10737     xmlXPathCompMultiplicativeExpr(ctxt);
   10738     CHECK_ERROR;
   10739     SKIP_BLANKS;
   10740     while ((CUR == '+') || (CUR == '-')) {
   10741 	int plus;
   10742 	int op1 = ctxt->comp->last;
   10743 
   10744         if (CUR == '+') plus = 1;
   10745 	else plus = 0;
   10746 	NEXT;
   10747 	SKIP_BLANKS;
   10748         xmlXPathCompMultiplicativeExpr(ctxt);
   10749 	CHECK_ERROR;
   10750 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10751 	SKIP_BLANKS;
   10752     }
   10753 }
   10754 
   10755 /**
   10756  * xmlXPathCompRelationalExpr:
   10757  * @ctxt:  the XPath Parser context
   10758  *
   10759  *  [24]   RelationalExpr ::=   AdditiveExpr
   10760  *                 | RelationalExpr '<' AdditiveExpr
   10761  *                 | RelationalExpr '>' AdditiveExpr
   10762  *                 | RelationalExpr '<=' AdditiveExpr
   10763  *                 | RelationalExpr '>=' AdditiveExpr
   10764  *
   10765  *  A <= B > C is allowed ? Answer from James, yes with
   10766  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10767  *  which is basically what got implemented.
   10768  *
   10769  * Compile a Relational expression, then push the result
   10770  * on the stack
   10771  */
   10772 
   10773 static void
   10774 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10775     xmlXPathCompAdditiveExpr(ctxt);
   10776     CHECK_ERROR;
   10777     SKIP_BLANKS;
   10778     while ((CUR == '<') ||
   10779            (CUR == '>') ||
   10780            ((CUR == '<') && (NXT(1) == '=')) ||
   10781            ((CUR == '>') && (NXT(1) == '='))) {
   10782 	int inf, strict;
   10783 	int op1 = ctxt->comp->last;
   10784 
   10785         if (CUR == '<') inf = 1;
   10786 	else inf = 0;
   10787 	if (NXT(1) == '=') strict = 0;
   10788 	else strict = 1;
   10789 	NEXT;
   10790 	if (!strict) NEXT;
   10791 	SKIP_BLANKS;
   10792         xmlXPathCompAdditiveExpr(ctxt);
   10793 	CHECK_ERROR;
   10794 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10795 	SKIP_BLANKS;
   10796     }
   10797 }
   10798 
   10799 /**
   10800  * xmlXPathCompEqualityExpr:
   10801  * @ctxt:  the XPath Parser context
   10802  *
   10803  *  [23]   EqualityExpr ::=   RelationalExpr
   10804  *                 | EqualityExpr '=' RelationalExpr
   10805  *                 | EqualityExpr '!=' RelationalExpr
   10806  *
   10807  *  A != B != C is allowed ? Answer from James, yes with
   10808  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10809  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10810  *  which is basically what got implemented.
   10811  *
   10812  * Compile an Equality expression.
   10813  *
   10814  */
   10815 static void
   10816 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10817     xmlXPathCompRelationalExpr(ctxt);
   10818     CHECK_ERROR;
   10819     SKIP_BLANKS;
   10820     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10821 	int eq;
   10822 	int op1 = ctxt->comp->last;
   10823 
   10824         if (CUR == '=') eq = 1;
   10825 	else eq = 0;
   10826 	NEXT;
   10827 	if (!eq) NEXT;
   10828 	SKIP_BLANKS;
   10829         xmlXPathCompRelationalExpr(ctxt);
   10830 	CHECK_ERROR;
   10831 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10832 	SKIP_BLANKS;
   10833     }
   10834 }
   10835 
   10836 /**
   10837  * xmlXPathCompAndExpr:
   10838  * @ctxt:  the XPath Parser context
   10839  *
   10840  *  [22]   AndExpr ::=   EqualityExpr
   10841  *                 | AndExpr 'and' EqualityExpr
   10842  *
   10843  * Compile an AND expression.
   10844  *
   10845  */
   10846 static void
   10847 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10848     xmlXPathCompEqualityExpr(ctxt);
   10849     CHECK_ERROR;
   10850     SKIP_BLANKS;
   10851     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10852 	int op1 = ctxt->comp->last;
   10853         SKIP(3);
   10854 	SKIP_BLANKS;
   10855         xmlXPathCompEqualityExpr(ctxt);
   10856 	CHECK_ERROR;
   10857 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   10858 	SKIP_BLANKS;
   10859     }
   10860 }
   10861 
   10862 /**
   10863  * xmlXPathCompileExpr:
   10864  * @ctxt:  the XPath Parser context
   10865  *
   10866  *  [14]   Expr ::=   OrExpr
   10867  *  [21]   OrExpr ::=   AndExpr
   10868  *                 | OrExpr 'or' AndExpr
   10869  *
   10870  * Parse and compile an expression
   10871  */
   10872 static void
   10873 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   10874     xmlXPathCompAndExpr(ctxt);
   10875     CHECK_ERROR;
   10876     SKIP_BLANKS;
   10877     while ((CUR == 'o') && (NXT(1) == 'r')) {
   10878 	int op1 = ctxt->comp->last;
   10879         SKIP(2);
   10880 	SKIP_BLANKS;
   10881         xmlXPathCompAndExpr(ctxt);
   10882 	CHECK_ERROR;
   10883 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   10884 	SKIP_BLANKS;
   10885     }
   10886     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   10887 	/* more ops could be optimized too */
   10888 	/*
   10889 	* This is the main place to eliminate sorting for
   10890 	* operations which don't require a sorted node-set.
   10891 	* E.g. count().
   10892 	*/
   10893 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   10894     }
   10895 }
   10896 
   10897 /**
   10898  * xmlXPathCompPredicate:
   10899  * @ctxt:  the XPath Parser context
   10900  * @filter:  act as a filter
   10901  *
   10902  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   10903  *  [9]   PredicateExpr ::=   Expr
   10904  *
   10905  * Compile a predicate expression
   10906  */
   10907 static void
   10908 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   10909     int op1 = ctxt->comp->last;
   10910 
   10911     SKIP_BLANKS;
   10912     if (CUR != '[') {
   10913 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10914     }
   10915     NEXT;
   10916     SKIP_BLANKS;
   10917 
   10918     ctxt->comp->last = -1;
   10919     /*
   10920     * This call to xmlXPathCompileExpr() will deactivate sorting
   10921     * of the predicate result.
   10922     * TODO: Sorting is still activated for filters, since I'm not
   10923     *  sure if needed. Normally sorting should not be needed, since
   10924     *  a filter can only diminish the number of items in a sequence,
   10925     *  but won't change its order; so if the initial sequence is sorted,
   10926     *  subsequent sorting is not needed.
   10927     */
   10928     if (! filter)
   10929 	xmlXPathCompileExpr(ctxt, 0);
   10930     else
   10931 	xmlXPathCompileExpr(ctxt, 1);
   10932     CHECK_ERROR;
   10933 
   10934     if (CUR != ']') {
   10935 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10936     }
   10937 
   10938     if (filter)
   10939 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   10940     else
   10941 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   10942 
   10943     NEXT;
   10944     SKIP_BLANKS;
   10945 }
   10946 
   10947 /**
   10948  * xmlXPathCompNodeTest:
   10949  * @ctxt:  the XPath Parser context
   10950  * @test:  pointer to a xmlXPathTestVal
   10951  * @type:  pointer to a xmlXPathTypeVal
   10952  * @prefix:  placeholder for a possible name prefix
   10953  *
   10954  * [7] NodeTest ::=   NameTest
   10955  *		    | NodeType '(' ')'
   10956  *		    | 'processing-instruction' '(' Literal ')'
   10957  *
   10958  * [37] NameTest ::=  '*'
   10959  *		    | NCName ':' '*'
   10960  *		    | QName
   10961  * [38] NodeType ::= 'comment'
   10962  *		   | 'text'
   10963  *		   | 'processing-instruction'
   10964  *		   | 'node'
   10965  *
   10966  * Returns the name found and updates @test, @type and @prefix appropriately
   10967  */
   10968 static xmlChar *
   10969 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   10970 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   10971 		     xmlChar *name) {
   10972     int blanks;
   10973 
   10974     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   10975 	STRANGE;
   10976 	return(NULL);
   10977     }
   10978     *type = (xmlXPathTypeVal) 0;
   10979     *test = (xmlXPathTestVal) 0;
   10980     *prefix = NULL;
   10981     SKIP_BLANKS;
   10982 
   10983     if ((name == NULL) && (CUR == '*')) {
   10984 	/*
   10985 	 * All elements
   10986 	 */
   10987 	NEXT;
   10988 	*test = NODE_TEST_ALL;
   10989 	return(NULL);
   10990     }
   10991 
   10992     if (name == NULL)
   10993 	name = xmlXPathParseNCName(ctxt);
   10994     if (name == NULL) {
   10995 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   10996     }
   10997 
   10998     blanks = IS_BLANK_CH(CUR);
   10999     SKIP_BLANKS;
   11000     if (CUR == '(') {
   11001 	NEXT;
   11002 	/*
   11003 	 * NodeType or PI search
   11004 	 */
   11005 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11006 	    *type = NODE_TYPE_COMMENT;
   11007 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11008 	    *type = NODE_TYPE_NODE;
   11009 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11010 	    *type = NODE_TYPE_PI;
   11011 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11012 	    *type = NODE_TYPE_TEXT;
   11013 	else {
   11014 	    if (name != NULL)
   11015 		xmlFree(name);
   11016 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11017 	}
   11018 
   11019 	*test = NODE_TEST_TYPE;
   11020 
   11021 	SKIP_BLANKS;
   11022 	if (*type == NODE_TYPE_PI) {
   11023 	    /*
   11024 	     * Specific case: search a PI by name.
   11025 	     */
   11026 	    if (name != NULL)
   11027 		xmlFree(name);
   11028 	    name = NULL;
   11029 	    if (CUR != ')') {
   11030 		name = xmlXPathParseLiteral(ctxt);
   11031 		CHECK_ERROR NULL;
   11032 		*test = NODE_TEST_PI;
   11033 		SKIP_BLANKS;
   11034 	    }
   11035 	}
   11036 	if (CUR != ')') {
   11037 	    if (name != NULL)
   11038 		xmlFree(name);
   11039 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11040 	}
   11041 	NEXT;
   11042 	return(name);
   11043     }
   11044     *test = NODE_TEST_NAME;
   11045     if ((!blanks) && (CUR == ':')) {
   11046 	NEXT;
   11047 
   11048 	/*
   11049 	 * Since currently the parser context don't have a
   11050 	 * namespace list associated:
   11051 	 * The namespace name for this prefix can be computed
   11052 	 * only at evaluation time. The compilation is done
   11053 	 * outside of any context.
   11054 	 */
   11055 #if 0
   11056 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11057 	if (name != NULL)
   11058 	    xmlFree(name);
   11059 	if (*prefix == NULL) {
   11060 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11061 	}
   11062 #else
   11063 	*prefix = name;
   11064 #endif
   11065 
   11066 	if (CUR == '*') {
   11067 	    /*
   11068 	     * All elements
   11069 	     */
   11070 	    NEXT;
   11071 	    *test = NODE_TEST_ALL;
   11072 	    return(NULL);
   11073 	}
   11074 
   11075 	name = xmlXPathParseNCName(ctxt);
   11076 	if (name == NULL) {
   11077 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11078 	}
   11079     }
   11080     return(name);
   11081 }
   11082 
   11083 /**
   11084  * xmlXPathIsAxisName:
   11085  * @name:  a preparsed name token
   11086  *
   11087  * [6] AxisName ::=   'ancestor'
   11088  *                  | 'ancestor-or-self'
   11089  *                  | 'attribute'
   11090  *                  | 'child'
   11091  *                  | 'descendant'
   11092  *                  | 'descendant-or-self'
   11093  *                  | 'following'
   11094  *                  | 'following-sibling'
   11095  *                  | 'namespace'
   11096  *                  | 'parent'
   11097  *                  | 'preceding'
   11098  *                  | 'preceding-sibling'
   11099  *                  | 'self'
   11100  *
   11101  * Returns the axis or 0
   11102  */
   11103 static xmlXPathAxisVal
   11104 xmlXPathIsAxisName(const xmlChar *name) {
   11105     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11106     switch (name[0]) {
   11107 	case 'a':
   11108 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11109 		ret = AXIS_ANCESTOR;
   11110 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11111 		ret = AXIS_ANCESTOR_OR_SELF;
   11112 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11113 		ret = AXIS_ATTRIBUTE;
   11114 	    break;
   11115 	case 'c':
   11116 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11117 		ret = AXIS_CHILD;
   11118 	    break;
   11119 	case 'd':
   11120 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11121 		ret = AXIS_DESCENDANT;
   11122 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11123 		ret = AXIS_DESCENDANT_OR_SELF;
   11124 	    break;
   11125 	case 'f':
   11126 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11127 		ret = AXIS_FOLLOWING;
   11128 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11129 		ret = AXIS_FOLLOWING_SIBLING;
   11130 	    break;
   11131 	case 'n':
   11132 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11133 		ret = AXIS_NAMESPACE;
   11134 	    break;
   11135 	case 'p':
   11136 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11137 		ret = AXIS_PARENT;
   11138 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11139 		ret = AXIS_PRECEDING;
   11140 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11141 		ret = AXIS_PRECEDING_SIBLING;
   11142 	    break;
   11143 	case 's':
   11144 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11145 		ret = AXIS_SELF;
   11146 	    break;
   11147     }
   11148     return(ret);
   11149 }
   11150 
   11151 /**
   11152  * xmlXPathCompStep:
   11153  * @ctxt:  the XPath Parser context
   11154  *
   11155  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11156  *                  | AbbreviatedStep
   11157  *
   11158  * [12] AbbreviatedStep ::=   '.' | '..'
   11159  *
   11160  * [5] AxisSpecifier ::= AxisName '::'
   11161  *                  | AbbreviatedAxisSpecifier
   11162  *
   11163  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11164  *
   11165  * Modified for XPtr range support as:
   11166  *
   11167  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11168  *                     | AbbreviatedStep
   11169  *                     | 'range-to' '(' Expr ')' Predicate*
   11170  *
   11171  * Compile one step in a Location Path
   11172  * A location step of . is short for self::node(). This is
   11173  * particularly useful in conjunction with //. For example, the
   11174  * location path .//para is short for
   11175  * self::node()/descendant-or-self::node()/child::para
   11176  * and so will select all para descendant elements of the context
   11177  * node.
   11178  * Similarly, a location step of .. is short for parent::node().
   11179  * For example, ../title is short for parent::node()/child::title
   11180  * and so will select the title children of the parent of the context
   11181  * node.
   11182  */
   11183 static void
   11184 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11185 #ifdef LIBXML_XPTR_ENABLED
   11186     int rangeto = 0;
   11187     int op2 = -1;
   11188 #endif
   11189 
   11190     SKIP_BLANKS;
   11191     if ((CUR == '.') && (NXT(1) == '.')) {
   11192 	SKIP(2);
   11193 	SKIP_BLANKS;
   11194 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11195 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11196     } else if (CUR == '.') {
   11197 	NEXT;
   11198 	SKIP_BLANKS;
   11199     } else {
   11200 	xmlChar *name = NULL;
   11201 	const xmlChar *prefix = NULL;
   11202 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11203 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11204 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11205 	int op1;
   11206 
   11207 	/*
   11208 	 * The modification needed for XPointer change to the production
   11209 	 */
   11210 #ifdef LIBXML_XPTR_ENABLED
   11211 	if (ctxt->xptr) {
   11212 	    name = xmlXPathParseNCName(ctxt);
   11213 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11214                 op2 = ctxt->comp->last;
   11215 		xmlFree(name);
   11216 		SKIP_BLANKS;
   11217 		if (CUR != '(') {
   11218 		    XP_ERROR(XPATH_EXPR_ERROR);
   11219 		}
   11220 		NEXT;
   11221 		SKIP_BLANKS;
   11222 
   11223 		xmlXPathCompileExpr(ctxt, 1);
   11224 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11225 		CHECK_ERROR;
   11226 
   11227 		SKIP_BLANKS;
   11228 		if (CUR != ')') {
   11229 		    XP_ERROR(XPATH_EXPR_ERROR);
   11230 		}
   11231 		NEXT;
   11232 		rangeto = 1;
   11233 		goto eval_predicates;
   11234 	    }
   11235 	}
   11236 #endif
   11237 	if (CUR == '*') {
   11238 	    axis = AXIS_CHILD;
   11239 	} else {
   11240 	    if (name == NULL)
   11241 		name = xmlXPathParseNCName(ctxt);
   11242 	    if (name != NULL) {
   11243 		axis = xmlXPathIsAxisName(name);
   11244 		if (axis != 0) {
   11245 		    SKIP_BLANKS;
   11246 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11247 			SKIP(2);
   11248 			xmlFree(name);
   11249 			name = NULL;
   11250 		    } else {
   11251 			/* an element name can conflict with an axis one :-\ */
   11252 			axis = AXIS_CHILD;
   11253 		    }
   11254 		} else {
   11255 		    axis = AXIS_CHILD;
   11256 		}
   11257 	    } else if (CUR == '@') {
   11258 		NEXT;
   11259 		axis = AXIS_ATTRIBUTE;
   11260 	    } else {
   11261 		axis = AXIS_CHILD;
   11262 	    }
   11263 	}
   11264 
   11265 	CHECK_ERROR;
   11266 
   11267 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11268 	if (test == 0)
   11269 	    return;
   11270 
   11271         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11272 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11273 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11274 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11275 	    }
   11276 	}
   11277 #ifdef DEBUG_STEP
   11278 	xmlGenericError(xmlGenericErrorContext,
   11279 		"Basis : computing new set\n");
   11280 #endif
   11281 
   11282 #ifdef DEBUG_STEP
   11283 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11284 	if (ctxt->value == NULL)
   11285 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11286 	else if (ctxt->value->nodesetval == NULL)
   11287 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11288 	else
   11289 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11290 #endif
   11291 
   11292 #ifdef LIBXML_XPTR_ENABLED
   11293 eval_predicates:
   11294 #endif
   11295 	op1 = ctxt->comp->last;
   11296 	ctxt->comp->last = -1;
   11297 
   11298 	SKIP_BLANKS;
   11299 	while (CUR == '[') {
   11300 	    xmlXPathCompPredicate(ctxt, 0);
   11301 	}
   11302 
   11303 #ifdef LIBXML_XPTR_ENABLED
   11304 	if (rangeto) {
   11305 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11306 	} else
   11307 #endif
   11308 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11309 			   test, type, (void *)prefix, (void *)name);
   11310 
   11311     }
   11312 #ifdef DEBUG_STEP
   11313     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11314     if (ctxt->value == NULL)
   11315 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11316     else if (ctxt->value->nodesetval == NULL)
   11317 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11318     else
   11319 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11320 		ctxt->value->nodesetval);
   11321 #endif
   11322 }
   11323 
   11324 /**
   11325  * xmlXPathCompRelativeLocationPath:
   11326  * @ctxt:  the XPath Parser context
   11327  *
   11328  *  [3]   RelativeLocationPath ::=   Step
   11329  *                     | RelativeLocationPath '/' Step
   11330  *                     | AbbreviatedRelativeLocationPath
   11331  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11332  *
   11333  * Compile a relative location path.
   11334  */
   11335 static void
   11336 xmlXPathCompRelativeLocationPath
   11337 (xmlXPathParserContextPtr ctxt) {
   11338     SKIP_BLANKS;
   11339     if ((CUR == '/') && (NXT(1) == '/')) {
   11340 	SKIP(2);
   11341 	SKIP_BLANKS;
   11342 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11343 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11344     } else if (CUR == '/') {
   11345 	    NEXT;
   11346 	SKIP_BLANKS;
   11347     }
   11348     xmlXPathCompStep(ctxt);
   11349     CHECK_ERROR;
   11350     SKIP_BLANKS;
   11351     while (CUR == '/') {
   11352 	if ((CUR == '/') && (NXT(1) == '/')) {
   11353 	    SKIP(2);
   11354 	    SKIP_BLANKS;
   11355 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11356 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11357 	    xmlXPathCompStep(ctxt);
   11358 	} else if (CUR == '/') {
   11359 	    NEXT;
   11360 	    SKIP_BLANKS;
   11361 	    xmlXPathCompStep(ctxt);
   11362 	}
   11363 	SKIP_BLANKS;
   11364     }
   11365 }
   11366 
   11367 /**
   11368  * xmlXPathCompLocationPath:
   11369  * @ctxt:  the XPath Parser context
   11370  *
   11371  *  [1]   LocationPath ::=   RelativeLocationPath
   11372  *                     | AbsoluteLocationPath
   11373  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11374  *                     | AbbreviatedAbsoluteLocationPath
   11375  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11376  *                           '//' RelativeLocationPath
   11377  *
   11378  * Compile a location path
   11379  *
   11380  * // is short for /descendant-or-self::node()/. For example,
   11381  * //para is short for /descendant-or-self::node()/child::para and
   11382  * so will select any para element in the document (even a para element
   11383  * that is a document element will be selected by //para since the
   11384  * document element node is a child of the root node); div//para is
   11385  * short for div/descendant-or-self::node()/child::para and so will
   11386  * select all para descendants of div children.
   11387  */
   11388 static void
   11389 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11390     SKIP_BLANKS;
   11391     if (CUR != '/') {
   11392         xmlXPathCompRelativeLocationPath(ctxt);
   11393     } else {
   11394 	while (CUR == '/') {
   11395 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11396 		SKIP(2);
   11397 		SKIP_BLANKS;
   11398 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11399 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11400 		xmlXPathCompRelativeLocationPath(ctxt);
   11401 	    } else if (CUR == '/') {
   11402 		NEXT;
   11403 		SKIP_BLANKS;
   11404 		if ((CUR != 0 ) &&
   11405 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11406 		     (CUR == '@') || (CUR == '*')))
   11407 		    xmlXPathCompRelativeLocationPath(ctxt);
   11408 	    }
   11409 	    CHECK_ERROR;
   11410 	}
   11411     }
   11412 }
   11413 
   11414 /************************************************************************
   11415  *									*
   11416  *		XPath precompiled expression evaluation			*
   11417  *									*
   11418  ************************************************************************/
   11419 
   11420 static int
   11421 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11422 
   11423 #ifdef DEBUG_STEP
   11424 static void
   11425 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11426 			  int nbNodes)
   11427 {
   11428     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11429     switch (op->value) {
   11430         case AXIS_ANCESTOR:
   11431             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11432             break;
   11433         case AXIS_ANCESTOR_OR_SELF:
   11434             xmlGenericError(xmlGenericErrorContext,
   11435                             "axis 'ancestors-or-self' ");
   11436             break;
   11437         case AXIS_ATTRIBUTE:
   11438             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11439             break;
   11440         case AXIS_CHILD:
   11441             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11442             break;
   11443         case AXIS_DESCENDANT:
   11444             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11445             break;
   11446         case AXIS_DESCENDANT_OR_SELF:
   11447             xmlGenericError(xmlGenericErrorContext,
   11448                             "axis 'descendant-or-self' ");
   11449             break;
   11450         case AXIS_FOLLOWING:
   11451             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11452             break;
   11453         case AXIS_FOLLOWING_SIBLING:
   11454             xmlGenericError(xmlGenericErrorContext,
   11455                             "axis 'following-siblings' ");
   11456             break;
   11457         case AXIS_NAMESPACE:
   11458             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11459             break;
   11460         case AXIS_PARENT:
   11461             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11462             break;
   11463         case AXIS_PRECEDING:
   11464             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11465             break;
   11466         case AXIS_PRECEDING_SIBLING:
   11467             xmlGenericError(xmlGenericErrorContext,
   11468                             "axis 'preceding-sibling' ");
   11469             break;
   11470         case AXIS_SELF:
   11471             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11472             break;
   11473     }
   11474     xmlGenericError(xmlGenericErrorContext,
   11475 	" context contains %d nodes\n", nbNodes);
   11476     switch (op->value2) {
   11477         case NODE_TEST_NONE:
   11478             xmlGenericError(xmlGenericErrorContext,
   11479                             "           searching for none !!!\n");
   11480             break;
   11481         case NODE_TEST_TYPE:
   11482             xmlGenericError(xmlGenericErrorContext,
   11483                             "           searching for type %d\n", op->value3);
   11484             break;
   11485         case NODE_TEST_PI:
   11486             xmlGenericError(xmlGenericErrorContext,
   11487                             "           searching for PI !!!\n");
   11488             break;
   11489         case NODE_TEST_ALL:
   11490             xmlGenericError(xmlGenericErrorContext,
   11491                             "           searching for *\n");
   11492             break;
   11493         case NODE_TEST_NS:
   11494             xmlGenericError(xmlGenericErrorContext,
   11495                             "           searching for namespace %s\n",
   11496                             op->value5);
   11497             break;
   11498         case NODE_TEST_NAME:
   11499             xmlGenericError(xmlGenericErrorContext,
   11500                             "           searching for name %s\n", op->value5);
   11501             if (op->value4)
   11502                 xmlGenericError(xmlGenericErrorContext,
   11503                                 "           with namespace %s\n", op->value4);
   11504             break;
   11505     }
   11506     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11507 }
   11508 #endif /* DEBUG_STEP */
   11509 
   11510 static int
   11511 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11512 			    xmlXPathStepOpPtr op,
   11513 			    xmlNodeSetPtr set,
   11514 			    int contextSize,
   11515 			    int hasNsNodes)
   11516 {
   11517     if (op->ch1 != -1) {
   11518 	xmlXPathCompExprPtr comp = ctxt->comp;
   11519 	/*
   11520 	* Process inner predicates first.
   11521 	*/
   11522 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11523 	    /*
   11524 	    * TODO: raise an internal error.
   11525 	    */
   11526 	}
   11527 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11528 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11529 	CHECK_ERROR0;
   11530 	if (contextSize <= 0)
   11531 	    return(0);
   11532     }
   11533     if (op->ch2 != -1) {
   11534 	xmlXPathContextPtr xpctxt = ctxt->context;
   11535 	xmlNodePtr contextNode, oldContextNode;
   11536 	xmlDocPtr oldContextDoc;
   11537 	int i, res, contextPos = 0, newContextSize;
   11538 	xmlXPathStepOpPtr exprOp;
   11539 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11540 
   11541 #ifdef LIBXML_XPTR_ENABLED
   11542 	/*
   11543 	* URGENT TODO: Check the following:
   11544 	*  We don't expect location sets if evaluating prediates, right?
   11545 	*  Only filters should expect location sets, right?
   11546 	*/
   11547 #endif
   11548 	/*
   11549 	* SPEC XPath 1.0:
   11550 	*  "For each node in the node-set to be filtered, the
   11551 	*  PredicateExpr is evaluated with that node as the
   11552 	*  context node, with the number of nodes in the
   11553 	*  node-set as the context size, and with the proximity
   11554 	*  position of the node in the node-set with respect to
   11555 	*  the axis as the context position;"
   11556 	* @oldset is the node-set" to be filtered.
   11557 	*
   11558 	* SPEC XPath 1.0:
   11559 	*  "only predicates change the context position and
   11560 	*  context size (see [2.4 Predicates])."
   11561 	* Example:
   11562 	*   node-set  context pos
   11563 	*    nA         1
   11564 	*    nB         2
   11565 	*    nC         3
   11566 	*   After applying predicate [position() > 1] :
   11567 	*   node-set  context pos
   11568 	*    nB         1
   11569 	*    nC         2
   11570 	*/
   11571 	oldContextNode = xpctxt->node;
   11572 	oldContextDoc = xpctxt->doc;
   11573 	/*
   11574 	* Get the expression of this predicate.
   11575 	*/
   11576 	exprOp = &ctxt->comp->steps[op->ch2];
   11577 	newContextSize = 0;
   11578 	for (i = 0; i < set->nodeNr; i++) {
   11579 	    if (set->nodeTab[i] == NULL)
   11580 		continue;
   11581 
   11582 	    contextNode = set->nodeTab[i];
   11583 	    xpctxt->node = contextNode;
   11584 	    xpctxt->contextSize = contextSize;
   11585 	    xpctxt->proximityPosition = ++contextPos;
   11586 
   11587 	    /*
   11588 	    * Also set the xpath document in case things like
   11589 	    * key() are evaluated in the predicate.
   11590 	    */
   11591 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11592 		(contextNode->doc != NULL))
   11593 		xpctxt->doc = contextNode->doc;
   11594 	    /*
   11595 	    * Evaluate the predicate expression with 1 context node
   11596 	    * at a time; this node is packaged into a node set; this
   11597 	    * node set is handed over to the evaluation mechanism.
   11598 	    */
   11599 	    if (contextObj == NULL)
   11600 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11601 	    else
   11602 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11603 		    contextNode);
   11604 
   11605 	    valuePush(ctxt, contextObj);
   11606 
   11607 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11608 
   11609 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11610 		xmlXPathNodeSetClear(set, hasNsNodes);
   11611 		newContextSize = 0;
   11612 		goto evaluation_exit;
   11613 	    }
   11614 
   11615 	    if (res != 0) {
   11616 		newContextSize++;
   11617 	    } else {
   11618 		/*
   11619 		* Remove the entry from the initial node set.
   11620 		*/
   11621 		set->nodeTab[i] = NULL;
   11622 		if (contextNode->type == XML_NAMESPACE_DECL)
   11623 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11624 	    }
   11625 	    if (ctxt->value == contextObj) {
   11626 		/*
   11627 		* Don't free the temporary XPath object holding the
   11628 		* context node, in order to avoid massive recreation
   11629 		* inside this loop.
   11630 		*/
   11631 		valuePop(ctxt);
   11632 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11633 	    } else {
   11634 		/*
   11635 		* TODO: The object was lost in the evaluation machinery.
   11636 		*  Can this happen? Maybe in internal-error cases.
   11637 		*/
   11638 		contextObj = NULL;
   11639 	    }
   11640 	}
   11641 
   11642 	if (contextObj != NULL) {
   11643 	    if (ctxt->value == contextObj)
   11644 		valuePop(ctxt);
   11645 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11646 	}
   11647 evaluation_exit:
   11648 	if (exprRes != NULL)
   11649 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11650 	/*
   11651 	* Reset/invalidate the context.
   11652 	*/
   11653 	xpctxt->node = oldContextNode;
   11654 	xpctxt->doc = oldContextDoc;
   11655 	xpctxt->contextSize = -1;
   11656 	xpctxt->proximityPosition = -1;
   11657 	return(newContextSize);
   11658     }
   11659     return(contextSize);
   11660 }
   11661 
   11662 static int
   11663 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11664 				      xmlXPathStepOpPtr op,
   11665 				      xmlNodeSetPtr set,
   11666 				      int contextSize,
   11667 				      int minPos,
   11668 				      int maxPos,
   11669 				      int hasNsNodes)
   11670 {
   11671     if (op->ch1 != -1) {
   11672 	xmlXPathCompExprPtr comp = ctxt->comp;
   11673 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11674 	    /*
   11675 	    * TODO: raise an internal error.
   11676 	    */
   11677 	}
   11678 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11679 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11680 	CHECK_ERROR0;
   11681 	if (contextSize <= 0)
   11682 	    return(0);
   11683     }
   11684     /*
   11685     * Check if the node set contains a sufficient number of nodes for
   11686     * the requested range.
   11687     */
   11688     if (contextSize < minPos) {
   11689 	xmlXPathNodeSetClear(set, hasNsNodes);
   11690 	return(0);
   11691     }
   11692     if (op->ch2 == -1) {
   11693 	/*
   11694 	* TODO: Can this ever happen?
   11695 	*/
   11696 	return (contextSize);
   11697     } else {
   11698 	xmlDocPtr oldContextDoc;
   11699 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11700 	xmlXPathStepOpPtr exprOp;
   11701 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11702 	xmlNodePtr oldContextNode, contextNode = NULL;
   11703 	xmlXPathContextPtr xpctxt = ctxt->context;
   11704 
   11705 #ifdef LIBXML_XPTR_ENABLED
   11706 	    /*
   11707 	    * URGENT TODO: Check the following:
   11708 	    *  We don't expect location sets if evaluating prediates, right?
   11709 	    *  Only filters should expect location sets, right?
   11710 	*/
   11711 #endif /* LIBXML_XPTR_ENABLED */
   11712 
   11713 	/*
   11714 	* Save old context.
   11715 	*/
   11716 	oldContextNode = xpctxt->node;
   11717 	oldContextDoc = xpctxt->doc;
   11718 	/*
   11719 	* Get the expression of this predicate.
   11720 	*/
   11721 	exprOp = &ctxt->comp->steps[op->ch2];
   11722 	for (i = 0; i < set->nodeNr; i++) {
   11723 	    if (set->nodeTab[i] == NULL)
   11724 		continue;
   11725 
   11726 	    contextNode = set->nodeTab[i];
   11727 	    xpctxt->node = contextNode;
   11728 	    xpctxt->contextSize = contextSize;
   11729 	    xpctxt->proximityPosition = ++contextPos;
   11730 
   11731 	    /*
   11732 	    * Initialize the new set.
   11733 	    * Also set the xpath document in case things like
   11734 	    * key() evaluation are attempted on the predicate
   11735 	    */
   11736 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11737 		(contextNode->doc != NULL))
   11738 		xpctxt->doc = contextNode->doc;
   11739 	    /*
   11740 	    * Evaluate the predicate expression with 1 context node
   11741 	    * at a time; this node is packaged into a node set; this
   11742 	    * node set is handed over to the evaluation mechanism.
   11743 	    */
   11744 	    if (contextObj == NULL)
   11745 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11746 	    else
   11747 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11748 		    contextNode);
   11749 
   11750 	    valuePush(ctxt, contextObj);
   11751 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11752 
   11753 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11754 	        xmlXPathObjectPtr tmp;
   11755 		/* pop the result if any */
   11756 		tmp = valuePop(ctxt);
   11757                 while (tmp != contextObj) {
   11758                     /*
   11759                      * Free up the result
   11760                      * then pop off contextObj, which will be freed later
   11761                      */
   11762                     xmlXPathReleaseObject(xpctxt, tmp);
   11763                     tmp = valuePop(ctxt);
   11764                 }
   11765 		goto evaluation_error;
   11766 	    }
   11767 
   11768 	    if (res)
   11769 		pos++;
   11770 
   11771 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11772 		/*
   11773 		* Fits in the requested range.
   11774 		*/
   11775 		newContextSize++;
   11776 		if (minPos == maxPos) {
   11777 		    /*
   11778 		    * Only 1 node was requested.
   11779 		    */
   11780 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11781 			/*
   11782 			* As always: take care of those nasty
   11783 			* namespace nodes.
   11784 			*/
   11785 			set->nodeTab[i] = NULL;
   11786 		    }
   11787 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11788 		    set->nodeNr = 1;
   11789 		    set->nodeTab[0] = contextNode;
   11790 		    goto evaluation_exit;
   11791 		}
   11792 		if (pos == maxPos) {
   11793 		    /*
   11794 		    * We are done.
   11795 		    */
   11796 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11797 		    goto evaluation_exit;
   11798 		}
   11799 	    } else {
   11800 		/*
   11801 		* Remove the entry from the initial node set.
   11802 		*/
   11803 		set->nodeTab[i] = NULL;
   11804 		if (contextNode->type == XML_NAMESPACE_DECL)
   11805 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11806 	    }
   11807 	    if (exprRes != NULL) {
   11808 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11809 		exprRes = NULL;
   11810 	    }
   11811 	    if (ctxt->value == contextObj) {
   11812 		/*
   11813 		* Don't free the temporary XPath object holding the
   11814 		* context node, in order to avoid massive recreation
   11815 		* inside this loop.
   11816 		*/
   11817 		valuePop(ctxt);
   11818 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11819 	    } else {
   11820 		/*
   11821 		* The object was lost in the evaluation machinery.
   11822 		* Can this happen? Maybe in case of internal-errors.
   11823 		*/
   11824 		contextObj = NULL;
   11825 	    }
   11826 	}
   11827 	goto evaluation_exit;
   11828 
   11829 evaluation_error:
   11830 	xmlXPathNodeSetClear(set, hasNsNodes);
   11831 	newContextSize = 0;
   11832 
   11833 evaluation_exit:
   11834 	if (contextObj != NULL) {
   11835 	    if (ctxt->value == contextObj)
   11836 		valuePop(ctxt);
   11837 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11838 	}
   11839 	if (exprRes != NULL)
   11840 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11841 	/*
   11842 	* Reset/invalidate the context.
   11843 	*/
   11844 	xpctxt->node = oldContextNode;
   11845 	xpctxt->doc = oldContextDoc;
   11846 	xpctxt->contextSize = -1;
   11847 	xpctxt->proximityPosition = -1;
   11848 	return(newContextSize);
   11849     }
   11850     return(contextSize);
   11851 }
   11852 
   11853 static int
   11854 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11855 			    xmlXPathStepOpPtr op,
   11856 			    int *maxPos)
   11857 {
   11858 
   11859     xmlXPathStepOpPtr exprOp;
   11860 
   11861     /*
   11862     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   11863     */
   11864 
   11865     /*
   11866     * If not -1, then ch1 will point to:
   11867     * 1) For predicates (XPATH_OP_PREDICATE):
   11868     *    - an inner predicate operator
   11869     * 2) For filters (XPATH_OP_FILTER):
   11870     *    - an inner filter operater OR
   11871     *    - an expression selecting the node set.
   11872     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   11873     */
   11874     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   11875 	return(0);
   11876 
   11877     if (op->ch2 != -1) {
   11878 	exprOp = &ctxt->comp->steps[op->ch2];
   11879     } else
   11880 	return(0);
   11881 
   11882     if ((exprOp != NULL) &&
   11883 	(exprOp->op == XPATH_OP_VALUE) &&
   11884 	(exprOp->value4 != NULL) &&
   11885 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   11886     {
   11887 	/*
   11888 	* We have a "[n]" predicate here.
   11889 	* TODO: Unfortunately this simplistic test here is not
   11890 	* able to detect a position() predicate in compound
   11891 	* expressions like "[@attr = 'a" and position() = 1],
   11892 	* and even not the usage of position() in
   11893 	* "[position() = 1]"; thus - obviously - a position-range,
   11894 	* like it "[position() < 5]", is also not detected.
   11895 	* Maybe we could rewrite the AST to ease the optimization.
   11896 	*/
   11897 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   11898 
   11899 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   11900 	    (float) *maxPos)
   11901 	{
   11902 	    return(1);
   11903 	}
   11904     }
   11905     return(0);
   11906 }
   11907 
   11908 static int
   11909 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   11910                            xmlXPathStepOpPtr op,
   11911 			   xmlNodePtr * first, xmlNodePtr * last,
   11912 			   int toBool)
   11913 {
   11914 
   11915 #define XP_TEST_HIT \
   11916     if (hasAxisRange != 0) { \
   11917 	if (++pos == maxPos) { \
   11918 	    addNode(seq, cur); \
   11919 	goto axis_range_end; } \
   11920     } else { \
   11921 	addNode(seq, cur); \
   11922 	if (breakOnFirstHit) goto first_hit; }
   11923 
   11924 #define XP_TEST_HIT_NS \
   11925     if (hasAxisRange != 0) { \
   11926 	if (++pos == maxPos) { \
   11927 	    hasNsNodes = 1; \
   11928 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
   11929 	goto axis_range_end; } \
   11930     } else { \
   11931 	hasNsNodes = 1; \
   11932 	xmlXPathNodeSetAddNs(seq, \
   11933 	xpctxt->node, (xmlNsPtr) cur); \
   11934 	if (breakOnFirstHit) goto first_hit; }
   11935 
   11936     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   11937     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   11938     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   11939     const xmlChar *prefix = op->value4;
   11940     const xmlChar *name = op->value5;
   11941     const xmlChar *URI = NULL;
   11942 
   11943 #ifdef DEBUG_STEP
   11944     int nbMatches = 0, prevMatches = 0;
   11945 #endif
   11946     int total = 0, hasNsNodes = 0;
   11947     /* The popped object holding the context nodes */
   11948     xmlXPathObjectPtr obj;
   11949     /* The set of context nodes for the node tests */
   11950     xmlNodeSetPtr contextSeq;
   11951     int contextIdx;
   11952     xmlNodePtr contextNode;
   11953     /* The context node for a compound traversal */
   11954     xmlNodePtr outerContextNode;
   11955     /* The final resulting node set wrt to all context nodes */
   11956     xmlNodeSetPtr outSeq;
   11957     /*
   11958     * The temporary resulting node set wrt 1 context node.
   11959     * Used to feed predicate evaluation.
   11960     */
   11961     xmlNodeSetPtr seq;
   11962     xmlNodePtr cur;
   11963     /* First predicate operator */
   11964     xmlXPathStepOpPtr predOp;
   11965     int maxPos; /* The requested position() (when a "[n]" predicate) */
   11966     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   11967     int breakOnFirstHit;
   11968 
   11969     xmlXPathTraversalFunction next = NULL;
   11970     /* compound axis traversal */
   11971     xmlXPathTraversalFunctionExt outerNext = NULL;
   11972     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   11973     xmlXPathNodeSetMergeFunction mergeAndClear;
   11974     xmlNodePtr oldContextNode;
   11975     xmlXPathContextPtr xpctxt = ctxt->context;
   11976 
   11977 
   11978     CHECK_TYPE0(XPATH_NODESET);
   11979     obj = valuePop(ctxt);
   11980     /*
   11981     * Setup namespaces.
   11982     */
   11983     if (prefix != NULL) {
   11984         URI = xmlXPathNsLookup(xpctxt, prefix);
   11985         if (URI == NULL) {
   11986 	    xmlXPathReleaseObject(xpctxt, obj);
   11987             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11988 	}
   11989     }
   11990     /*
   11991     * Setup axis.
   11992     *
   11993     * MAYBE FUTURE TODO: merging optimizations:
   11994     * - If the nodes to be traversed wrt to the initial nodes and
   11995     *   the current axis cannot overlap, then we could avoid searching
   11996     *   for duplicates during the merge.
   11997     *   But the question is how/when to evaluate if they cannot overlap.
   11998     *   Example: if we know that for two initial nodes, the one is
   11999     *   not in the ancestor-or-self axis of the other, then we could safely
   12000     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12001     *   the descendant-or-self axis.
   12002     */
   12003     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12004     switch (axis) {
   12005         case AXIS_ANCESTOR:
   12006             first = NULL;
   12007             next = xmlXPathNextAncestor;
   12008             break;
   12009         case AXIS_ANCESTOR_OR_SELF:
   12010             first = NULL;
   12011             next = xmlXPathNextAncestorOrSelf;
   12012             break;
   12013         case AXIS_ATTRIBUTE:
   12014             first = NULL;
   12015 	    last = NULL;
   12016             next = xmlXPathNextAttribute;
   12017 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12018             break;
   12019         case AXIS_CHILD:
   12020 	    last = NULL;
   12021 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
   12022 		/*
   12023 		* This iterator will give us only nodes which can
   12024 		* hold element nodes.
   12025 		*/
   12026 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
   12027 	    }
   12028 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12029 		(type == NODE_TYPE_NODE))
   12030 	    {
   12031 		/*
   12032 		* Optimization if an element node type is 'element'.
   12033 		*/
   12034 		next = xmlXPathNextChildElement;
   12035 	    } else
   12036 		next = xmlXPathNextChild;
   12037 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12038             break;
   12039         case AXIS_DESCENDANT:
   12040 	    last = NULL;
   12041             next = xmlXPathNextDescendant;
   12042             break;
   12043         case AXIS_DESCENDANT_OR_SELF:
   12044 	    last = NULL;
   12045             next = xmlXPathNextDescendantOrSelf;
   12046             break;
   12047         case AXIS_FOLLOWING:
   12048 	    last = NULL;
   12049             next = xmlXPathNextFollowing;
   12050             break;
   12051         case AXIS_FOLLOWING_SIBLING:
   12052 	    last = NULL;
   12053             next = xmlXPathNextFollowingSibling;
   12054             break;
   12055         case AXIS_NAMESPACE:
   12056             first = NULL;
   12057 	    last = NULL;
   12058             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12059 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12060             break;
   12061         case AXIS_PARENT:
   12062             first = NULL;
   12063             next = xmlXPathNextParent;
   12064             break;
   12065         case AXIS_PRECEDING:
   12066             first = NULL;
   12067             next = xmlXPathNextPrecedingInternal;
   12068             break;
   12069         case AXIS_PRECEDING_SIBLING:
   12070             first = NULL;
   12071             next = xmlXPathNextPrecedingSibling;
   12072             break;
   12073         case AXIS_SELF:
   12074             first = NULL;
   12075 	    last = NULL;
   12076             next = xmlXPathNextSelf;
   12077 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12078             break;
   12079     }
   12080 
   12081 #ifdef DEBUG_STEP
   12082     xmlXPathDebugDumpStepAxis(op,
   12083 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12084 #endif
   12085 
   12086     if (next == NULL) {
   12087 	xmlXPathReleaseObject(xpctxt, obj);
   12088         return(0);
   12089     }
   12090     contextSeq = obj->nodesetval;
   12091     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12092 	xmlXPathReleaseObject(xpctxt, obj);
   12093         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12094         return(0);
   12095     }
   12096     /*
   12097     * Predicate optimization ---------------------------------------------
   12098     * If this step has a last predicate, which contains a position(),
   12099     * then we'll optimize (although not exactly "position()", but only
   12100     * the  short-hand form, i.e., "[n]".
   12101     *
   12102     * Example - expression "/foo[parent::bar][1]":
   12103     *
   12104     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12105     *   ROOT                               -- op->ch1
   12106     *   PREDICATE                          -- op->ch2 (predOp)
   12107     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12108     *       SORT
   12109     *         COLLECT  'parent' 'name' 'node' bar
   12110     *           NODE
   12111     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12112     *
   12113     */
   12114     maxPos = 0;
   12115     predOp = NULL;
   12116     hasPredicateRange = 0;
   12117     hasAxisRange = 0;
   12118     if (op->ch2 != -1) {
   12119 	/*
   12120 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12121 	*/
   12122 	predOp = &ctxt->comp->steps[op->ch2];
   12123 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12124 	    if (predOp->ch1 != -1) {
   12125 		/*
   12126 		* Use the next inner predicate operator.
   12127 		*/
   12128 		predOp = &ctxt->comp->steps[predOp->ch1];
   12129 		hasPredicateRange = 1;
   12130 	    } else {
   12131 		/*
   12132 		* There's no other predicate than the [n] predicate.
   12133 		*/
   12134 		predOp = NULL;
   12135 		hasAxisRange = 1;
   12136 	    }
   12137 	}
   12138     }
   12139     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12140     /*
   12141     * Axis traversal -----------------------------------------------------
   12142     */
   12143     /*
   12144      * 2.3 Node Tests
   12145      *  - For the attribute axis, the principal node type is attribute.
   12146      *  - For the namespace axis, the principal node type is namespace.
   12147      *  - For other axes, the principal node type is element.
   12148      *
   12149      * A node test * is true for any node of the
   12150      * principal node type. For example, child::* will
   12151      * select all element children of the context node
   12152      */
   12153     oldContextNode = xpctxt->node;
   12154     addNode = xmlXPathNodeSetAddUnique;
   12155     outSeq = NULL;
   12156     seq = NULL;
   12157     outerContextNode = NULL;
   12158     contextNode = NULL;
   12159     contextIdx = 0;
   12160 
   12161 
   12162     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
   12163 	if (outerNext != NULL) {
   12164 	    /*
   12165 	    * This is a compound traversal.
   12166 	    */
   12167 	    if (contextNode == NULL) {
   12168 		/*
   12169 		* Set the context for the outer traversal.
   12170 		*/
   12171 		outerContextNode = contextSeq->nodeTab[contextIdx++];
   12172 		contextNode = outerNext(NULL, outerContextNode);
   12173 	    } else
   12174 		contextNode = outerNext(contextNode, outerContextNode);
   12175 	    if (contextNode == NULL)
   12176 		continue;
   12177 	    /*
   12178 	    * Set the context for the main traversal.
   12179 	    */
   12180 	    xpctxt->node = contextNode;
   12181 	} else
   12182 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12183 
   12184 	if (seq == NULL) {
   12185 	    seq = xmlXPathNodeSetCreate(NULL);
   12186 	    if (seq == NULL) {
   12187 		total = 0;
   12188 		goto error;
   12189 	    }
   12190 	}
   12191 	/*
   12192 	* Traverse the axis and test the nodes.
   12193 	*/
   12194 	pos = 0;
   12195 	cur = NULL;
   12196 	hasNsNodes = 0;
   12197         do {
   12198             cur = next(ctxt, cur);
   12199             if (cur == NULL)
   12200                 break;
   12201 
   12202 	    /*
   12203 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12204 	    */
   12205             if ((first != NULL) && (*first != NULL)) {
   12206 		if (*first == cur)
   12207 		    break;
   12208 		if (((total % 256) == 0) &&
   12209 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12210 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12211 #else
   12212 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12213 #endif
   12214 		{
   12215 		    break;
   12216 		}
   12217 	    }
   12218 	    if ((last != NULL) && (*last != NULL)) {
   12219 		if (*last == cur)
   12220 		    break;
   12221 		if (((total % 256) == 0) &&
   12222 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12223 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12224 #else
   12225 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12226 #endif
   12227 		{
   12228 		    break;
   12229 		}
   12230 	    }
   12231 
   12232             total++;
   12233 
   12234 #ifdef DEBUG_STEP
   12235             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12236 #endif
   12237 
   12238 	    switch (test) {
   12239                 case NODE_TEST_NONE:
   12240 		    total = 0;
   12241                     STRANGE
   12242 		    goto error;
   12243                 case NODE_TEST_TYPE:
   12244 		    /*
   12245 		    * TODO: Don't we need to use
   12246 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12247 		    *  Surprisingly, some c14n tests fail, if we do this.
   12248 		    */
   12249 		    if (type == NODE_TYPE_NODE) {
   12250 			switch (cur->type) {
   12251 			    case XML_DOCUMENT_NODE:
   12252 			    case XML_HTML_DOCUMENT_NODE:
   12253 #ifdef LIBXML_DOCB_ENABLED
   12254 			    case XML_DOCB_DOCUMENT_NODE:
   12255 #endif
   12256 			    case XML_ELEMENT_NODE:
   12257 			    case XML_ATTRIBUTE_NODE:
   12258 			    case XML_PI_NODE:
   12259 			    case XML_COMMENT_NODE:
   12260 			    case XML_CDATA_SECTION_NODE:
   12261 			    case XML_TEXT_NODE:
   12262 			    case XML_NAMESPACE_DECL:
   12263 				XP_TEST_HIT
   12264 				break;
   12265 			    default:
   12266 				break;
   12267 			}
   12268 		    } else if (cur->type == type) {
   12269 			if (cur->type == XML_NAMESPACE_DECL)
   12270 			    XP_TEST_HIT_NS
   12271 			else
   12272 			    XP_TEST_HIT
   12273 		    } else if ((type == NODE_TYPE_TEXT) &&
   12274 			 (cur->type == XML_CDATA_SECTION_NODE))
   12275 		    {
   12276 			XP_TEST_HIT
   12277 		    }
   12278 		    break;
   12279                 case NODE_TEST_PI:
   12280                     if ((cur->type == XML_PI_NODE) &&
   12281                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12282 		    {
   12283 			XP_TEST_HIT
   12284                     }
   12285                     break;
   12286                 case NODE_TEST_ALL:
   12287                     if (axis == AXIS_ATTRIBUTE) {
   12288                         if (cur->type == XML_ATTRIBUTE_NODE)
   12289 			{
   12290 			    XP_TEST_HIT
   12291                         }
   12292                     } else if (axis == AXIS_NAMESPACE) {
   12293                         if (cur->type == XML_NAMESPACE_DECL)
   12294 			{
   12295 			    XP_TEST_HIT_NS
   12296                         }
   12297                     } else {
   12298                         if (cur->type == XML_ELEMENT_NODE) {
   12299                             if (prefix == NULL)
   12300 			    {
   12301 				XP_TEST_HIT
   12302 
   12303                             } else if ((cur->ns != NULL) &&
   12304 				(xmlStrEqual(URI, cur->ns->href)))
   12305 			    {
   12306 				XP_TEST_HIT
   12307                             }
   12308                         }
   12309                     }
   12310                     break;
   12311                 case NODE_TEST_NS:{
   12312                         TODO;
   12313                         break;
   12314                     }
   12315                 case NODE_TEST_NAME:
   12316                     if (axis == AXIS_ATTRIBUTE) {
   12317                         if (cur->type != XML_ATTRIBUTE_NODE)
   12318 			    break;
   12319 		    } else if (axis == AXIS_NAMESPACE) {
   12320                         if (cur->type != XML_NAMESPACE_DECL)
   12321 			    break;
   12322 		    } else {
   12323 		        if (cur->type != XML_ELEMENT_NODE)
   12324 			    break;
   12325 		    }
   12326                     switch (cur->type) {
   12327                         case XML_ELEMENT_NODE:
   12328                             if (xmlStrEqual(name, cur->name)) {
   12329                                 if (prefix == NULL) {
   12330                                     if (cur->ns == NULL)
   12331 				    {
   12332 					XP_TEST_HIT
   12333                                     }
   12334                                 } else {
   12335                                     if ((cur->ns != NULL) &&
   12336                                         (xmlStrEqual(URI, cur->ns->href)))
   12337 				    {
   12338 					XP_TEST_HIT
   12339                                     }
   12340                                 }
   12341                             }
   12342                             break;
   12343                         case XML_ATTRIBUTE_NODE:{
   12344                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12345 
   12346                                 if (xmlStrEqual(name, attr->name)) {
   12347                                     if (prefix == NULL) {
   12348                                         if ((attr->ns == NULL) ||
   12349                                             (attr->ns->prefix == NULL))
   12350 					{
   12351 					    XP_TEST_HIT
   12352                                         }
   12353                                     } else {
   12354                                         if ((attr->ns != NULL) &&
   12355                                             (xmlStrEqual(URI,
   12356 					      attr->ns->href)))
   12357 					{
   12358 					    XP_TEST_HIT
   12359                                         }
   12360                                     }
   12361                                 }
   12362                                 break;
   12363                             }
   12364                         case XML_NAMESPACE_DECL:
   12365                             if (cur->type == XML_NAMESPACE_DECL) {
   12366                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12367 
   12368                                 if ((ns->prefix != NULL) && (name != NULL)
   12369                                     && (xmlStrEqual(ns->prefix, name)))
   12370 				{
   12371 				    XP_TEST_HIT_NS
   12372                                 }
   12373                             }
   12374                             break;
   12375                         default:
   12376                             break;
   12377                     }
   12378                     break;
   12379 	    } /* switch(test) */
   12380         } while (cur != NULL);
   12381 
   12382 	goto apply_predicates;
   12383 
   12384 axis_range_end: /* ----------------------------------------------------- */
   12385 	/*
   12386 	* We have a "/foo[n]", and position() = n was reached.
   12387 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12388 	* a duplicate-aware merge is still needed.
   12389 	* Merge with the result.
   12390 	*/
   12391 	if (outSeq == NULL) {
   12392 	    outSeq = seq;
   12393 	    seq = NULL;
   12394 	} else
   12395 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12396 	/*
   12397 	* Break if only a true/false result was requested.
   12398 	*/
   12399 	if (toBool)
   12400 	    break;
   12401 	continue;
   12402 
   12403 first_hit: /* ---------------------------------------------------------- */
   12404 	/*
   12405 	* Break if only a true/false result was requested and
   12406 	* no predicates existed and a node test succeeded.
   12407 	*/
   12408 	if (outSeq == NULL) {
   12409 	    outSeq = seq;
   12410 	    seq = NULL;
   12411 	} else
   12412 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12413 	break;
   12414 
   12415 #ifdef DEBUG_STEP
   12416 	if (seq != NULL)
   12417 	    nbMatches += seq->nodeNr;
   12418 #endif
   12419 
   12420 apply_predicates: /* --------------------------------------------------- */
   12421         /*
   12422 	* Apply predicates.
   12423 	*/
   12424         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12425 	    /*
   12426 	    * E.g. when we have a "/foo[some expression][n]".
   12427 	    */
   12428 	    /*
   12429 	    * QUESTION TODO: The old predicate evaluation took into
   12430 	    *  account location-sets.
   12431 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12432 	    *  Do we expect such a set here?
   12433 	    *  All what I learned now from the evaluation semantics
   12434 	    *  does not indicate that a location-set will be processed
   12435 	    *  here, so this looks OK.
   12436 	    */
   12437 	    /*
   12438 	    * Iterate over all predicates, starting with the outermost
   12439 	    * predicate.
   12440 	    * TODO: Problem: we cannot execute the inner predicates first
   12441 	    *  since we cannot go back *up* the operator tree!
   12442 	    *  Options we have:
   12443 	    *  1) Use of recursive functions (like is it currently done
   12444 	    *     via xmlXPathCompOpEval())
   12445 	    *  2) Add a predicate evaluation information stack to the
   12446 	    *     context struct
   12447 	    *  3) Change the way the operators are linked; we need a
   12448 	    *     "parent" field on xmlXPathStepOp
   12449 	    *
   12450 	    * For the moment, I'll try to solve this with a recursive
   12451 	    * function: xmlXPathCompOpEvalPredicate().
   12452 	    */
   12453 	    size = seq->nodeNr;
   12454 	    if (hasPredicateRange != 0)
   12455 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12456 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12457 	    else
   12458 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12459 		    predOp, seq, size, hasNsNodes);
   12460 
   12461 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12462 		total = 0;
   12463 		goto error;
   12464 	    }
   12465 	    /*
   12466 	    * Add the filtered set of nodes to the result node set.
   12467 	    */
   12468 	    if (newSize == 0) {
   12469 		/*
   12470 		* The predicates filtered all nodes out.
   12471 		*/
   12472 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12473 	    } else if (seq->nodeNr > 0) {
   12474 		/*
   12475 		* Add to result set.
   12476 		*/
   12477 		if (outSeq == NULL) {
   12478 		    if (size != newSize) {
   12479 			/*
   12480 			* We need to merge and clear here, since
   12481 			* the sequence will contained NULLed entries.
   12482 			*/
   12483 			outSeq = mergeAndClear(NULL, seq, 1);
   12484 		    } else {
   12485 			outSeq = seq;
   12486 			seq = NULL;
   12487 		    }
   12488 		} else
   12489 		    outSeq = mergeAndClear(outSeq, seq,
   12490 			(size != newSize) ? 1: 0);
   12491 		/*
   12492 		* Break if only a true/false result was requested.
   12493 		*/
   12494 		if (toBool)
   12495 		    break;
   12496 	    }
   12497         } else if (seq->nodeNr > 0) {
   12498 	    /*
   12499 	    * Add to result set.
   12500 	    */
   12501 	    if (outSeq == NULL) {
   12502 		outSeq = seq;
   12503 		seq = NULL;
   12504 	    } else {
   12505 		outSeq = mergeAndClear(outSeq, seq, 0);
   12506 	    }
   12507 	}
   12508     }
   12509 
   12510 error:
   12511     if ((obj->boolval) && (obj->user != NULL)) {
   12512 	/*
   12513 	* QUESTION TODO: What does this do and why?
   12514 	* TODO: Do we have to do this also for the "error"
   12515 	* cleanup further down?
   12516 	*/
   12517 	ctxt->value->boolval = 1;
   12518 	ctxt->value->user = obj->user;
   12519 	obj->user = NULL;
   12520 	obj->boolval = 0;
   12521     }
   12522     xmlXPathReleaseObject(xpctxt, obj);
   12523 
   12524     /*
   12525     * Ensure we return at least an emtpy set.
   12526     */
   12527     if (outSeq == NULL) {
   12528 	if ((seq != NULL) && (seq->nodeNr == 0))
   12529 	    outSeq = seq;
   12530 	else
   12531 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12532         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12533     }
   12534     if ((seq != NULL) && (seq != outSeq)) {
   12535 	 xmlXPathFreeNodeSet(seq);
   12536     }
   12537     /*
   12538     * Hand over the result. Better to push the set also in
   12539     * case of errors.
   12540     */
   12541     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12542     /*
   12543     * Reset the context node.
   12544     */
   12545     xpctxt->node = oldContextNode;
   12546 
   12547 #ifdef DEBUG_STEP
   12548     xmlGenericError(xmlGenericErrorContext,
   12549 	"\nExamined %d nodes, found %d nodes at that step\n",
   12550 	total, nbMatches);
   12551 #endif
   12552 
   12553     return(total);
   12554 }
   12555 
   12556 static int
   12557 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12558 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12559 
   12560 /**
   12561  * xmlXPathCompOpEvalFirst:
   12562  * @ctxt:  the XPath parser context with the compiled expression
   12563  * @op:  an XPath compiled operation
   12564  * @first:  the first elem found so far
   12565  *
   12566  * Evaluate the Precompiled XPath operation searching only the first
   12567  * element in document order
   12568  *
   12569  * Returns the number of examined objects.
   12570  */
   12571 static int
   12572 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12573                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12574 {
   12575     int total = 0, cur;
   12576     xmlXPathCompExprPtr comp;
   12577     xmlXPathObjectPtr arg1, arg2;
   12578 
   12579     CHECK_ERROR0;
   12580     comp = ctxt->comp;
   12581     switch (op->op) {
   12582         case XPATH_OP_END:
   12583             return (0);
   12584         case XPATH_OP_UNION:
   12585             total =
   12586                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12587                                         first);
   12588 	    CHECK_ERROR0;
   12589             if ((ctxt->value != NULL)
   12590                 && (ctxt->value->type == XPATH_NODESET)
   12591                 && (ctxt->value->nodesetval != NULL)
   12592                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12593                 /*
   12594                  * limit tree traversing to first node in the result
   12595                  */
   12596 		/*
   12597 		* OPTIMIZE TODO: This implicitely sorts
   12598 		*  the result, even if not needed. E.g. if the argument
   12599 		*  of the count() function, no sorting is needed.
   12600 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12601 		*  aready sorted?
   12602 		*/
   12603 		if (ctxt->value->nodesetval->nodeNr > 1)
   12604 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12605                 *first = ctxt->value->nodesetval->nodeTab[0];
   12606             }
   12607             cur =
   12608                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12609                                         first);
   12610 	    CHECK_ERROR0;
   12611             CHECK_TYPE0(XPATH_NODESET);
   12612             arg2 = valuePop(ctxt);
   12613 
   12614             CHECK_TYPE0(XPATH_NODESET);
   12615             arg1 = valuePop(ctxt);
   12616 
   12617             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12618                                                     arg2->nodesetval);
   12619             valuePush(ctxt, arg1);
   12620 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12621             /* optimizer */
   12622 	    if (total > cur)
   12623 		xmlXPathCompSwap(op);
   12624             return (total + cur);
   12625         case XPATH_OP_ROOT:
   12626             xmlXPathRoot(ctxt);
   12627             return (0);
   12628         case XPATH_OP_NODE:
   12629             if (op->ch1 != -1)
   12630                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12631 	    CHECK_ERROR0;
   12632             if (op->ch2 != -1)
   12633                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12634 	    CHECK_ERROR0;
   12635 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12636 		ctxt->context->node));
   12637             return (total);
   12638         case XPATH_OP_RESET:
   12639             if (op->ch1 != -1)
   12640                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12641 	    CHECK_ERROR0;
   12642             if (op->ch2 != -1)
   12643                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12644 	    CHECK_ERROR0;
   12645             ctxt->context->node = NULL;
   12646             return (total);
   12647         case XPATH_OP_COLLECT:{
   12648                 if (op->ch1 == -1)
   12649                     return (total);
   12650 
   12651                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12652 		CHECK_ERROR0;
   12653 
   12654                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12655                 return (total);
   12656             }
   12657         case XPATH_OP_VALUE:
   12658             valuePush(ctxt,
   12659                       xmlXPathCacheObjectCopy(ctxt->context,
   12660 			(xmlXPathObjectPtr) op->value4));
   12661             return (0);
   12662         case XPATH_OP_SORT:
   12663             if (op->ch1 != -1)
   12664                 total +=
   12665                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12666                                             first);
   12667 	    CHECK_ERROR0;
   12668             if ((ctxt->value != NULL)
   12669                 && (ctxt->value->type == XPATH_NODESET)
   12670                 && (ctxt->value->nodesetval != NULL)
   12671 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12672                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12673             return (total);
   12674 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12675 	case XPATH_OP_FILTER:
   12676                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12677             return (total);
   12678 #endif
   12679         default:
   12680             return (xmlXPathCompOpEval(ctxt, op));
   12681     }
   12682 }
   12683 
   12684 /**
   12685  * xmlXPathCompOpEvalLast:
   12686  * @ctxt:  the XPath parser context with the compiled expression
   12687  * @op:  an XPath compiled operation
   12688  * @last:  the last elem found so far
   12689  *
   12690  * Evaluate the Precompiled XPath operation searching only the last
   12691  * element in document order
   12692  *
   12693  * Returns the number of nodes traversed
   12694  */
   12695 static int
   12696 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12697                        xmlNodePtr * last)
   12698 {
   12699     int total = 0, cur;
   12700     xmlXPathCompExprPtr comp;
   12701     xmlXPathObjectPtr arg1, arg2;
   12702     xmlNodePtr bak;
   12703     xmlDocPtr bakd;
   12704     int pp;
   12705     int cs;
   12706 
   12707     CHECK_ERROR0;
   12708     comp = ctxt->comp;
   12709     switch (op->op) {
   12710         case XPATH_OP_END:
   12711             return (0);
   12712         case XPATH_OP_UNION:
   12713 	    bakd = ctxt->context->doc;
   12714 	    bak = ctxt->context->node;
   12715 	    pp = ctxt->context->proximityPosition;
   12716 	    cs = ctxt->context->contextSize;
   12717             total =
   12718                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12719 	    CHECK_ERROR0;
   12720             if ((ctxt->value != NULL)
   12721                 && (ctxt->value->type == XPATH_NODESET)
   12722                 && (ctxt->value->nodesetval != NULL)
   12723                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12724                 /*
   12725                  * limit tree traversing to first node in the result
   12726                  */
   12727 		if (ctxt->value->nodesetval->nodeNr > 1)
   12728 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12729                 *last =
   12730                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12731                                                      nodesetval->nodeNr -
   12732                                                      1];
   12733             }
   12734 	    ctxt->context->doc = bakd;
   12735 	    ctxt->context->node = bak;
   12736 	    ctxt->context->proximityPosition = pp;
   12737 	    ctxt->context->contextSize = cs;
   12738             cur =
   12739                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12740 	    CHECK_ERROR0;
   12741             if ((ctxt->value != NULL)
   12742                 && (ctxt->value->type == XPATH_NODESET)
   12743                 && (ctxt->value->nodesetval != NULL)
   12744                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12745             }
   12746             CHECK_TYPE0(XPATH_NODESET);
   12747             arg2 = valuePop(ctxt);
   12748 
   12749             CHECK_TYPE0(XPATH_NODESET);
   12750             arg1 = valuePop(ctxt);
   12751 
   12752             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12753                                                     arg2->nodesetval);
   12754             valuePush(ctxt, arg1);
   12755 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12756             /* optimizer */
   12757 	    if (total > cur)
   12758 		xmlXPathCompSwap(op);
   12759             return (total + cur);
   12760         case XPATH_OP_ROOT:
   12761             xmlXPathRoot(ctxt);
   12762             return (0);
   12763         case XPATH_OP_NODE:
   12764             if (op->ch1 != -1)
   12765                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12766 	    CHECK_ERROR0;
   12767             if (op->ch2 != -1)
   12768                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12769 	    CHECK_ERROR0;
   12770 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12771 		ctxt->context->node));
   12772             return (total);
   12773         case XPATH_OP_RESET:
   12774             if (op->ch1 != -1)
   12775                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12776 	    CHECK_ERROR0;
   12777             if (op->ch2 != -1)
   12778                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12779 	    CHECK_ERROR0;
   12780             ctxt->context->node = NULL;
   12781             return (total);
   12782         case XPATH_OP_COLLECT:{
   12783                 if (op->ch1 == -1)
   12784                     return (0);
   12785 
   12786                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12787 		CHECK_ERROR0;
   12788 
   12789                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12790                 return (total);
   12791             }
   12792         case XPATH_OP_VALUE:
   12793             valuePush(ctxt,
   12794                       xmlXPathCacheObjectCopy(ctxt->context,
   12795 			(xmlXPathObjectPtr) op->value4));
   12796             return (0);
   12797         case XPATH_OP_SORT:
   12798             if (op->ch1 != -1)
   12799                 total +=
   12800                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12801                                            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))
   12807                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12808             return (total);
   12809         default:
   12810             return (xmlXPathCompOpEval(ctxt, op));
   12811     }
   12812 }
   12813 
   12814 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12815 static int
   12816 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12817 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12818 {
   12819     int total = 0;
   12820     xmlXPathCompExprPtr comp;
   12821     xmlXPathObjectPtr res;
   12822     xmlXPathObjectPtr obj;
   12823     xmlNodeSetPtr oldset;
   12824     xmlNodePtr oldnode;
   12825     xmlDocPtr oldDoc;
   12826     int i;
   12827 
   12828     CHECK_ERROR0;
   12829     comp = ctxt->comp;
   12830     /*
   12831     * Optimization for ()[last()] selection i.e. the last elem
   12832     */
   12833     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12834 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12835 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12836 	int f = comp->steps[op->ch2].ch1;
   12837 
   12838 	if ((f != -1) &&
   12839 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12840 	    (comp->steps[f].value5 == NULL) &&
   12841 	    (comp->steps[f].value == 0) &&
   12842 	    (comp->steps[f].value4 != NULL) &&
   12843 	    (xmlStrEqual
   12844 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12845 	    xmlNodePtr last = NULL;
   12846 
   12847 	    total +=
   12848 		xmlXPathCompOpEvalLast(ctxt,
   12849 		    &comp->steps[op->ch1],
   12850 		    &last);
   12851 	    CHECK_ERROR0;
   12852 	    /*
   12853 	    * The nodeset should be in document order,
   12854 	    * Keep only the last value
   12855 	    */
   12856 	    if ((ctxt->value != NULL) &&
   12857 		(ctxt->value->type == XPATH_NODESET) &&
   12858 		(ctxt->value->nodesetval != NULL) &&
   12859 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12860 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12861 		ctxt->value->nodesetval->nodeTab[0] =
   12862 		    ctxt->value->nodesetval->nodeTab[ctxt->
   12863 		    value->
   12864 		    nodesetval->
   12865 		    nodeNr -
   12866 		    1];
   12867 		ctxt->value->nodesetval->nodeNr = 1;
   12868 		*first = *(ctxt->value->nodesetval->nodeTab);
   12869 	    }
   12870 	    return (total);
   12871 	}
   12872     }
   12873 
   12874     if (op->ch1 != -1)
   12875 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12876     CHECK_ERROR0;
   12877     if (op->ch2 == -1)
   12878 	return (total);
   12879     if (ctxt->value == NULL)
   12880 	return (total);
   12881 
   12882 #ifdef LIBXML_XPTR_ENABLED
   12883     oldnode = ctxt->context->node;
   12884     /*
   12885     * Hum are we filtering the result of an XPointer expression
   12886     */
   12887     if (ctxt->value->type == XPATH_LOCATIONSET) {
   12888 	xmlXPathObjectPtr tmp = NULL;
   12889 	xmlLocationSetPtr newlocset = NULL;
   12890 	xmlLocationSetPtr oldlocset;
   12891 
   12892 	/*
   12893 	* Extract the old locset, and then evaluate the result of the
   12894 	* expression for all the element in the locset. use it to grow
   12895 	* up a new locset.
   12896 	*/
   12897 	CHECK_TYPE0(XPATH_LOCATIONSET);
   12898 	obj = valuePop(ctxt);
   12899 	oldlocset = obj->user;
   12900 	ctxt->context->node = NULL;
   12901 
   12902 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   12903 	    ctxt->context->contextSize = 0;
   12904 	    ctxt->context->proximityPosition = 0;
   12905 	    if (op->ch2 != -1)
   12906 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12907 	    res = valuePop(ctxt);
   12908 	    if (res != NULL) {
   12909 		xmlXPathReleaseObject(ctxt->context, res);
   12910 	    }
   12911 	    valuePush(ctxt, obj);
   12912 	    CHECK_ERROR0;
   12913 	    return (total);
   12914 	}
   12915 	newlocset = xmlXPtrLocationSetCreate(NULL);
   12916 
   12917 	for (i = 0; i < oldlocset->locNr; i++) {
   12918 	    /*
   12919 	    * Run the evaluation with a node list made of a
   12920 	    * single item in the nodelocset.
   12921 	    */
   12922 	    ctxt->context->node = oldlocset->locTab[i]->user;
   12923 	    ctxt->context->contextSize = oldlocset->locNr;
   12924 	    ctxt->context->proximityPosition = i + 1;
   12925 	    if (tmp == NULL) {
   12926 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   12927 		    ctxt->context->node);
   12928 	    } else {
   12929 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   12930 		    ctxt->context->node);
   12931 	    }
   12932 	    valuePush(ctxt, tmp);
   12933 	    if (op->ch2 != -1)
   12934 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12935 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12936 		xmlXPathFreeObject(obj);
   12937 		return(0);
   12938 	    }
   12939 	    /*
   12940 	    * The result of the evaluation need to be tested to
   12941 	    * decided whether the filter succeeded or not
   12942 	    */
   12943 	    res = valuePop(ctxt);
   12944 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   12945 		xmlXPtrLocationSetAdd(newlocset,
   12946 		    xmlXPathCacheObjectCopy(ctxt->context,
   12947 			oldlocset->locTab[i]));
   12948 	    }
   12949 	    /*
   12950 	    * Cleanup
   12951 	    */
   12952 	    if (res != NULL) {
   12953 		xmlXPathReleaseObject(ctxt->context, res);
   12954 	    }
   12955 	    if (ctxt->value == tmp) {
   12956 		valuePop(ctxt);
   12957 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   12958 		/*
   12959 		* REVISIT TODO: Don't create a temporary nodeset
   12960 		* for everly iteration.
   12961 		*/
   12962 		/* OLD: xmlXPathFreeObject(res); */
   12963 	    } else
   12964 		tmp = NULL;
   12965 	    ctxt->context->node = NULL;
   12966 	    /*
   12967 	    * Only put the first node in the result, then leave.
   12968 	    */
   12969 	    if (newlocset->locNr > 0) {
   12970 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   12971 		break;
   12972 	    }
   12973 	}
   12974 	if (tmp != NULL) {
   12975 	    xmlXPathReleaseObject(ctxt->context, tmp);
   12976 	}
   12977 	/*
   12978 	* The result is used as the new evaluation locset.
   12979 	*/
   12980 	xmlXPathReleaseObject(ctxt->context, obj);
   12981 	ctxt->context->node = NULL;
   12982 	ctxt->context->contextSize = -1;
   12983 	ctxt->context->proximityPosition = -1;
   12984 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   12985 	ctxt->context->node = oldnode;
   12986 	return (total);
   12987     }
   12988 #endif /* LIBXML_XPTR_ENABLED */
   12989 
   12990     /*
   12991     * Extract the old set, and then evaluate the result of the
   12992     * expression for all the element in the set. use it to grow
   12993     * up a new set.
   12994     */
   12995     CHECK_TYPE0(XPATH_NODESET);
   12996     obj = valuePop(ctxt);
   12997     oldset = obj->nodesetval;
   12998 
   12999     oldnode = ctxt->context->node;
   13000     oldDoc = ctxt->context->doc;
   13001     ctxt->context->node = NULL;
   13002 
   13003     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13004 	ctxt->context->contextSize = 0;
   13005 	ctxt->context->proximityPosition = 0;
   13006 	/* QUESTION TODO: Why was this code commented out?
   13007 	    if (op->ch2 != -1)
   13008 		total +=
   13009 		    xmlXPathCompOpEval(ctxt,
   13010 			&comp->steps[op->ch2]);
   13011 	    CHECK_ERROR0;
   13012 	    res = valuePop(ctxt);
   13013 	    if (res != NULL)
   13014 		xmlXPathFreeObject(res);
   13015 	*/
   13016 	valuePush(ctxt, obj);
   13017 	ctxt->context->node = oldnode;
   13018 	CHECK_ERROR0;
   13019     } else {
   13020 	xmlNodeSetPtr newset;
   13021 	xmlXPathObjectPtr tmp = NULL;
   13022 	/*
   13023 	* Initialize the new set.
   13024 	* Also set the xpath document in case things like
   13025 	* key() evaluation are attempted on the predicate
   13026 	*/
   13027 	newset = xmlXPathNodeSetCreate(NULL);
   13028         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13029 
   13030 	for (i = 0; i < oldset->nodeNr; i++) {
   13031 	    /*
   13032 	    * Run the evaluation with a node list made of
   13033 	    * a single item in the nodeset.
   13034 	    */
   13035 	    ctxt->context->node = oldset->nodeTab[i];
   13036 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13037 		(oldset->nodeTab[i]->doc != NULL))
   13038 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13039 	    if (tmp == NULL) {
   13040 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13041 		    ctxt->context->node);
   13042 	    } else {
   13043 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13044 		    ctxt->context->node);
   13045 	    }
   13046 	    valuePush(ctxt, tmp);
   13047 	    ctxt->context->contextSize = oldset->nodeNr;
   13048 	    ctxt->context->proximityPosition = i + 1;
   13049 	    if (op->ch2 != -1)
   13050 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13051 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13052 		xmlXPathFreeNodeSet(newset);
   13053 		xmlXPathFreeObject(obj);
   13054 		return(0);
   13055 	    }
   13056 	    /*
   13057 	    * The result of the evaluation needs to be tested to
   13058 	    * decide whether the filter succeeded or not
   13059 	    */
   13060 	    res = valuePop(ctxt);
   13061 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13062 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13063 	    }
   13064 	    /*
   13065 	    * Cleanup
   13066 	    */
   13067 	    if (res != NULL) {
   13068 		xmlXPathReleaseObject(ctxt->context, res);
   13069 	    }
   13070 	    if (ctxt->value == tmp) {
   13071 		valuePop(ctxt);
   13072 		/*
   13073 		* Don't free the temporary nodeset
   13074 		* in order to avoid massive recreation inside this
   13075 		* loop.
   13076 		*/
   13077 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13078 	    } else
   13079 		tmp = NULL;
   13080 	    ctxt->context->node = NULL;
   13081 	    /*
   13082 	    * Only put the first node in the result, then leave.
   13083 	    */
   13084 	    if (newset->nodeNr > 0) {
   13085 		*first = *(newset->nodeTab);
   13086 		break;
   13087 	    }
   13088 	}
   13089 	if (tmp != NULL) {
   13090 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13091 	}
   13092 	/*
   13093 	* The result is used as the new evaluation set.
   13094 	*/
   13095 	xmlXPathReleaseObject(ctxt->context, obj);
   13096 	ctxt->context->node = NULL;
   13097 	ctxt->context->contextSize = -1;
   13098 	ctxt->context->proximityPosition = -1;
   13099 	/* may want to move this past the '}' later */
   13100 	ctxt->context->doc = oldDoc;
   13101 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13102     }
   13103     ctxt->context->node = oldnode;
   13104     return(total);
   13105 }
   13106 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13107 
   13108 /**
   13109  * xmlXPathCompOpEval:
   13110  * @ctxt:  the XPath parser context with the compiled expression
   13111  * @op:  an XPath compiled operation
   13112  *
   13113  * Evaluate the Precompiled XPath operation
   13114  * Returns the number of nodes traversed
   13115  */
   13116 static int
   13117 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13118 {
   13119     int total = 0;
   13120     int equal, ret;
   13121     xmlXPathCompExprPtr comp;
   13122     xmlXPathObjectPtr arg1, arg2;
   13123     xmlNodePtr bak;
   13124     xmlDocPtr bakd;
   13125     int pp;
   13126     int cs;
   13127 
   13128     CHECK_ERROR0;
   13129     comp = ctxt->comp;
   13130     switch (op->op) {
   13131         case XPATH_OP_END:
   13132             return (0);
   13133         case XPATH_OP_AND:
   13134 	    bakd = ctxt->context->doc;
   13135 	    bak = ctxt->context->node;
   13136 	    pp = ctxt->context->proximityPosition;
   13137 	    cs = ctxt->context->contextSize;
   13138             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13139 	    CHECK_ERROR0;
   13140             xmlXPathBooleanFunction(ctxt, 1);
   13141             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13142                 return (total);
   13143             arg2 = valuePop(ctxt);
   13144 	    ctxt->context->doc = bakd;
   13145 	    ctxt->context->node = bak;
   13146 	    ctxt->context->proximityPosition = pp;
   13147 	    ctxt->context->contextSize = cs;
   13148             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13149 	    if (ctxt->error) {
   13150 		xmlXPathFreeObject(arg2);
   13151 		return(0);
   13152 	    }
   13153             xmlXPathBooleanFunction(ctxt, 1);
   13154             arg1 = valuePop(ctxt);
   13155             arg1->boolval &= arg2->boolval;
   13156             valuePush(ctxt, arg1);
   13157 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13158             return (total);
   13159         case XPATH_OP_OR:
   13160 	    bakd = ctxt->context->doc;
   13161 	    bak = ctxt->context->node;
   13162 	    pp = ctxt->context->proximityPosition;
   13163 	    cs = ctxt->context->contextSize;
   13164             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13165 	    CHECK_ERROR0;
   13166             xmlXPathBooleanFunction(ctxt, 1);
   13167             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13168                 return (total);
   13169             arg2 = valuePop(ctxt);
   13170 	    ctxt->context->doc = bakd;
   13171 	    ctxt->context->node = bak;
   13172 	    ctxt->context->proximityPosition = pp;
   13173 	    ctxt->context->contextSize = cs;
   13174             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13175 	    if (ctxt->error) {
   13176 		xmlXPathFreeObject(arg2);
   13177 		return(0);
   13178 	    }
   13179             xmlXPathBooleanFunction(ctxt, 1);
   13180             arg1 = valuePop(ctxt);
   13181             arg1->boolval |= arg2->boolval;
   13182             valuePush(ctxt, arg1);
   13183 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13184             return (total);
   13185         case XPATH_OP_EQUAL:
   13186 	    bakd = ctxt->context->doc;
   13187 	    bak = ctxt->context->node;
   13188 	    pp = ctxt->context->proximityPosition;
   13189 	    cs = ctxt->context->contextSize;
   13190             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13191 	    CHECK_ERROR0;
   13192 	    ctxt->context->doc = bakd;
   13193 	    ctxt->context->node = bak;
   13194 	    ctxt->context->proximityPosition = pp;
   13195 	    ctxt->context->contextSize = cs;
   13196             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13197 	    CHECK_ERROR0;
   13198 	    if (op->value)
   13199 		equal = xmlXPathEqualValues(ctxt);
   13200 	    else
   13201 		equal = xmlXPathNotEqualValues(ctxt);
   13202 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13203             return (total);
   13204         case XPATH_OP_CMP:
   13205 	    bakd = ctxt->context->doc;
   13206 	    bak = ctxt->context->node;
   13207 	    pp = ctxt->context->proximityPosition;
   13208 	    cs = ctxt->context->contextSize;
   13209             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13210 	    CHECK_ERROR0;
   13211 	    ctxt->context->doc = bakd;
   13212 	    ctxt->context->node = bak;
   13213 	    ctxt->context->proximityPosition = pp;
   13214 	    ctxt->context->contextSize = cs;
   13215             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13216 	    CHECK_ERROR0;
   13217             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13218 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13219             return (total);
   13220         case XPATH_OP_PLUS:
   13221 	    bakd = ctxt->context->doc;
   13222 	    bak = ctxt->context->node;
   13223 	    pp = ctxt->context->proximityPosition;
   13224 	    cs = ctxt->context->contextSize;
   13225             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13226 	    CHECK_ERROR0;
   13227             if (op->ch2 != -1) {
   13228 		ctxt->context->doc = bakd;
   13229 		ctxt->context->node = bak;
   13230 		ctxt->context->proximityPosition = pp;
   13231 		ctxt->context->contextSize = cs;
   13232                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13233 	    }
   13234 	    CHECK_ERROR0;
   13235             if (op->value == 0)
   13236                 xmlXPathSubValues(ctxt);
   13237             else if (op->value == 1)
   13238                 xmlXPathAddValues(ctxt);
   13239             else if (op->value == 2)
   13240                 xmlXPathValueFlipSign(ctxt);
   13241             else if (op->value == 3) {
   13242                 CAST_TO_NUMBER;
   13243                 CHECK_TYPE0(XPATH_NUMBER);
   13244             }
   13245             return (total);
   13246         case XPATH_OP_MULT:
   13247 	    bakd = ctxt->context->doc;
   13248 	    bak = ctxt->context->node;
   13249 	    pp = ctxt->context->proximityPosition;
   13250 	    cs = ctxt->context->contextSize;
   13251             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13252 	    CHECK_ERROR0;
   13253 	    ctxt->context->doc = bakd;
   13254 	    ctxt->context->node = bak;
   13255 	    ctxt->context->proximityPosition = pp;
   13256 	    ctxt->context->contextSize = cs;
   13257             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13258 	    CHECK_ERROR0;
   13259             if (op->value == 0)
   13260                 xmlXPathMultValues(ctxt);
   13261             else if (op->value == 1)
   13262                 xmlXPathDivValues(ctxt);
   13263             else if (op->value == 2)
   13264                 xmlXPathModValues(ctxt);
   13265             return (total);
   13266         case XPATH_OP_UNION:
   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             CHECK_TYPE0(XPATH_NODESET);
   13280             arg2 = valuePop(ctxt);
   13281 
   13282             CHECK_TYPE0(XPATH_NODESET);
   13283             arg1 = valuePop(ctxt);
   13284 
   13285 	    if ((arg1->nodesetval == NULL) ||
   13286 		((arg2->nodesetval != NULL) &&
   13287 		 (arg2->nodesetval->nodeNr != 0)))
   13288 	    {
   13289 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13290 							arg2->nodesetval);
   13291 	    }
   13292 
   13293             valuePush(ctxt, arg1);
   13294 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13295             return (total);
   13296         case XPATH_OP_ROOT:
   13297             xmlXPathRoot(ctxt);
   13298             return (total);
   13299         case XPATH_OP_NODE:
   13300             if (op->ch1 != -1)
   13301                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13302 	    CHECK_ERROR0;
   13303             if (op->ch2 != -1)
   13304                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13305 	    CHECK_ERROR0;
   13306 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13307 		ctxt->context->node));
   13308             return (total);
   13309         case XPATH_OP_RESET:
   13310             if (op->ch1 != -1)
   13311                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13312 	    CHECK_ERROR0;
   13313             if (op->ch2 != -1)
   13314                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13315 	    CHECK_ERROR0;
   13316             ctxt->context->node = NULL;
   13317             return (total);
   13318         case XPATH_OP_COLLECT:{
   13319                 if (op->ch1 == -1)
   13320                     return (total);
   13321 
   13322                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13323 		CHECK_ERROR0;
   13324 
   13325                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13326                 return (total);
   13327             }
   13328         case XPATH_OP_VALUE:
   13329             valuePush(ctxt,
   13330                       xmlXPathCacheObjectCopy(ctxt->context,
   13331 			(xmlXPathObjectPtr) op->value4));
   13332             return (total);
   13333         case XPATH_OP_VARIABLE:{
   13334 		xmlXPathObjectPtr val;
   13335 
   13336                 if (op->ch1 != -1)
   13337                     total +=
   13338                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13339                 if (op->value5 == NULL) {
   13340 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13341 		    if (val == NULL) {
   13342 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13343 			return(0);
   13344 		    }
   13345                     valuePush(ctxt, val);
   13346 		} else {
   13347                     const xmlChar *URI;
   13348 
   13349                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13350                     if (URI == NULL) {
   13351                         xmlGenericError(xmlGenericErrorContext,
   13352             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13353                                     (char *) op->value4, (char *)op->value5);
   13354                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13355                         return (total);
   13356                     }
   13357 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13358                                                        op->value4, URI);
   13359 		    if (val == NULL) {
   13360 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13361 			return(0);
   13362 		    }
   13363                     valuePush(ctxt, val);
   13364                 }
   13365                 return (total);
   13366             }
   13367         case XPATH_OP_FUNCTION:{
   13368                 xmlXPathFunction func;
   13369                 const xmlChar *oldFunc, *oldFuncURI;
   13370 		int i;
   13371 
   13372                 if (op->ch1 != -1)
   13373                     total +=
   13374                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13375 		if (ctxt->valueNr < op->value) {
   13376 		    xmlGenericError(xmlGenericErrorContext,
   13377 			    "xmlXPathCompOpEval: parameter error\n");
   13378 		    ctxt->error = XPATH_INVALID_OPERAND;
   13379 		    return (total);
   13380 		}
   13381 		for (i = 0; i < op->value; i++)
   13382 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13383 			xmlGenericError(xmlGenericErrorContext,
   13384 				"xmlXPathCompOpEval: parameter error\n");
   13385 			ctxt->error = XPATH_INVALID_OPERAND;
   13386 			return (total);
   13387 		    }
   13388                 if (op->cache != NULL)
   13389                     XML_CAST_FPTR(func) = op->cache;
   13390                 else {
   13391                     const xmlChar *URI = NULL;
   13392 
   13393                     if (op->value5 == NULL)
   13394                         func =
   13395                             xmlXPathFunctionLookup(ctxt->context,
   13396                                                    op->value4);
   13397                     else {
   13398                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13399                         if (URI == NULL) {
   13400                             xmlGenericError(xmlGenericErrorContext,
   13401             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13402                                     (char *)op->value4, (char *)op->value5);
   13403                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13404                             return (total);
   13405                         }
   13406                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13407                                                         op->value4, URI);
   13408                     }
   13409                     if (func == NULL) {
   13410                         xmlGenericError(xmlGenericErrorContext,
   13411                                 "xmlXPathCompOpEval: function %s not found\n",
   13412                                         (char *)op->value4);
   13413                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13414                     }
   13415                     op->cache = XML_CAST_FPTR(func);
   13416                     op->cacheURI = (void *) URI;
   13417                 }
   13418                 oldFunc = ctxt->context->function;
   13419                 oldFuncURI = ctxt->context->functionURI;
   13420                 ctxt->context->function = op->value4;
   13421                 ctxt->context->functionURI = op->cacheURI;
   13422                 func(ctxt, op->value);
   13423                 ctxt->context->function = oldFunc;
   13424                 ctxt->context->functionURI = oldFuncURI;
   13425                 return (total);
   13426             }
   13427         case XPATH_OP_ARG:
   13428 	    bakd = ctxt->context->doc;
   13429 	    bak = ctxt->context->node;
   13430 	    pp = ctxt->context->proximityPosition;
   13431 	    cs = ctxt->context->contextSize;
   13432             if (op->ch1 != -1)
   13433                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13434 	    ctxt->context->contextSize = cs;
   13435 	    ctxt->context->proximityPosition = pp;
   13436 	    ctxt->context->node = bak;
   13437 	    ctxt->context->doc = bakd;
   13438 	    CHECK_ERROR0;
   13439             if (op->ch2 != -1) {
   13440                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13441 	        ctxt->context->doc = bakd;
   13442 	        ctxt->context->node = bak;
   13443 	        CHECK_ERROR0;
   13444 	    }
   13445             return (total);
   13446         case XPATH_OP_PREDICATE:
   13447         case XPATH_OP_FILTER:{
   13448                 xmlXPathObjectPtr res;
   13449                 xmlXPathObjectPtr obj, tmp;
   13450                 xmlNodeSetPtr newset = NULL;
   13451                 xmlNodeSetPtr oldset;
   13452                 xmlNodePtr oldnode;
   13453 		xmlDocPtr oldDoc;
   13454                 int i;
   13455 
   13456                 /*
   13457                  * Optimization for ()[1] selection i.e. the first elem
   13458                  */
   13459                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13460 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13461 		    /*
   13462 		    * FILTER TODO: Can we assume that the inner processing
   13463 		    *  will result in an ordered list if we have an
   13464 		    *  XPATH_OP_FILTER?
   13465 		    *  What about an additional field or flag on
   13466 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13467 		    *  to assume anything, so it would be more robust and
   13468 		    *  easier to optimize.
   13469 		    */
   13470                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13471 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13472 #else
   13473 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13474 #endif
   13475                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13476                     xmlXPathObjectPtr val;
   13477 
   13478                     val = comp->steps[op->ch2].value4;
   13479                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13480                         (val->floatval == 1.0)) {
   13481                         xmlNodePtr first = NULL;
   13482 
   13483                         total +=
   13484                             xmlXPathCompOpEvalFirst(ctxt,
   13485                                                     &comp->steps[op->ch1],
   13486                                                     &first);
   13487 			CHECK_ERROR0;
   13488                         /*
   13489                          * The nodeset should be in document order,
   13490                          * Keep only the first value
   13491                          */
   13492                         if ((ctxt->value != NULL) &&
   13493                             (ctxt->value->type == XPATH_NODESET) &&
   13494                             (ctxt->value->nodesetval != NULL) &&
   13495                             (ctxt->value->nodesetval->nodeNr > 1))
   13496                             ctxt->value->nodesetval->nodeNr = 1;
   13497                         return (total);
   13498                     }
   13499                 }
   13500                 /*
   13501                  * Optimization for ()[last()] selection i.e. the last elem
   13502                  */
   13503                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13504                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13505                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13506                     int f = comp->steps[op->ch2].ch1;
   13507 
   13508                     if ((f != -1) &&
   13509                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13510                         (comp->steps[f].value5 == NULL) &&
   13511                         (comp->steps[f].value == 0) &&
   13512                         (comp->steps[f].value4 != NULL) &&
   13513                         (xmlStrEqual
   13514                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13515                         xmlNodePtr last = NULL;
   13516 
   13517                         total +=
   13518                             xmlXPathCompOpEvalLast(ctxt,
   13519                                                    &comp->steps[op->ch1],
   13520                                                    &last);
   13521 			CHECK_ERROR0;
   13522                         /*
   13523                          * The nodeset should be in document order,
   13524                          * Keep only the last value
   13525                          */
   13526                         if ((ctxt->value != NULL) &&
   13527                             (ctxt->value->type == XPATH_NODESET) &&
   13528                             (ctxt->value->nodesetval != NULL) &&
   13529                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13530                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13531                             ctxt->value->nodesetval->nodeTab[0] =
   13532                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13533                                                                  value->
   13534                                                                  nodesetval->
   13535                                                                  nodeNr -
   13536                                                                  1];
   13537                             ctxt->value->nodesetval->nodeNr = 1;
   13538                         }
   13539                         return (total);
   13540                     }
   13541                 }
   13542 		/*
   13543 		* Process inner predicates first.
   13544 		* Example "index[parent::book][1]":
   13545 		* ...
   13546 		*   PREDICATE   <-- we are here "[1]"
   13547 		*     PREDICATE <-- process "[parent::book]" first
   13548 		*       SORT
   13549 		*         COLLECT  'parent' 'name' 'node' book
   13550 		*           NODE
   13551 		*     ELEM Object is a number : 1
   13552 		*/
   13553                 if (op->ch1 != -1)
   13554                     total +=
   13555                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13556 		CHECK_ERROR0;
   13557                 if (op->ch2 == -1)
   13558                     return (total);
   13559                 if (ctxt->value == NULL)
   13560                     return (total);
   13561 
   13562                 oldnode = ctxt->context->node;
   13563 
   13564 #ifdef LIBXML_XPTR_ENABLED
   13565                 /*
   13566                  * Hum are we filtering the result of an XPointer expression
   13567                  */
   13568                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13569                     xmlLocationSetPtr newlocset = NULL;
   13570                     xmlLocationSetPtr oldlocset;
   13571 
   13572                     /*
   13573                      * Extract the old locset, and then evaluate the result of the
   13574                      * expression for all the element in the locset. use it to grow
   13575                      * up a new locset.
   13576                      */
   13577                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13578                     obj = valuePop(ctxt);
   13579                     oldlocset = obj->user;
   13580                     ctxt->context->node = NULL;
   13581 
   13582                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13583                         ctxt->context->contextSize = 0;
   13584                         ctxt->context->proximityPosition = 0;
   13585                         if (op->ch2 != -1)
   13586                             total +=
   13587                                 xmlXPathCompOpEval(ctxt,
   13588                                                    &comp->steps[op->ch2]);
   13589                         res = valuePop(ctxt);
   13590                         if (res != NULL) {
   13591 			    xmlXPathReleaseObject(ctxt->context, res);
   13592 			}
   13593                         valuePush(ctxt, obj);
   13594                         CHECK_ERROR0;
   13595                         return (total);
   13596                     }
   13597                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13598 
   13599                     for (i = 0; i < oldlocset->locNr; i++) {
   13600                         /*
   13601                          * Run the evaluation with a node list made of a
   13602                          * single item in the nodelocset.
   13603                          */
   13604                         ctxt->context->node = oldlocset->locTab[i]->user;
   13605                         ctxt->context->contextSize = oldlocset->locNr;
   13606                         ctxt->context->proximityPosition = i + 1;
   13607 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13608 			    ctxt->context->node);
   13609                         valuePush(ctxt, tmp);
   13610 
   13611                         if (op->ch2 != -1)
   13612                             total +=
   13613                                 xmlXPathCompOpEval(ctxt,
   13614                                                    &comp->steps[op->ch2]);
   13615 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13616 			    xmlXPathFreeObject(obj);
   13617 			    return(0);
   13618 			}
   13619 
   13620                         /*
   13621                          * The result of the evaluation need to be tested to
   13622                          * decided whether the filter succeeded or not
   13623                          */
   13624                         res = valuePop(ctxt);
   13625                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13626                             xmlXPtrLocationSetAdd(newlocset,
   13627                                                   xmlXPathObjectCopy
   13628                                                   (oldlocset->locTab[i]));
   13629                         }
   13630 
   13631                         /*
   13632                          * Cleanup
   13633                          */
   13634                         if (res != NULL) {
   13635 			    xmlXPathReleaseObject(ctxt->context, res);
   13636 			}
   13637                         if (ctxt->value == tmp) {
   13638                             res = valuePop(ctxt);
   13639 			    xmlXPathReleaseObject(ctxt->context, res);
   13640                         }
   13641 
   13642                         ctxt->context->node = NULL;
   13643                     }
   13644 
   13645                     /*
   13646                      * The result is used as the new evaluation locset.
   13647                      */
   13648 		    xmlXPathReleaseObject(ctxt->context, obj);
   13649                     ctxt->context->node = NULL;
   13650                     ctxt->context->contextSize = -1;
   13651                     ctxt->context->proximityPosition = -1;
   13652                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13653                     ctxt->context->node = oldnode;
   13654                     return (total);
   13655                 }
   13656 #endif /* LIBXML_XPTR_ENABLED */
   13657 
   13658                 /*
   13659                  * Extract the old set, and then evaluate the result of the
   13660                  * expression for all the element in the set. use it to grow
   13661                  * up a new set.
   13662                  */
   13663                 CHECK_TYPE0(XPATH_NODESET);
   13664                 obj = valuePop(ctxt);
   13665                 oldset = obj->nodesetval;
   13666 
   13667                 oldnode = ctxt->context->node;
   13668 		oldDoc = ctxt->context->doc;
   13669                 ctxt->context->node = NULL;
   13670 
   13671                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13672                     ctxt->context->contextSize = 0;
   13673                     ctxt->context->proximityPosition = 0;
   13674 /*
   13675                     if (op->ch2 != -1)
   13676                         total +=
   13677                             xmlXPathCompOpEval(ctxt,
   13678                                                &comp->steps[op->ch2]);
   13679 		    CHECK_ERROR0;
   13680                     res = valuePop(ctxt);
   13681                     if (res != NULL)
   13682                         xmlXPathFreeObject(res);
   13683 */
   13684                     valuePush(ctxt, obj);
   13685                     ctxt->context->node = oldnode;
   13686                     CHECK_ERROR0;
   13687                 } else {
   13688 		    tmp = NULL;
   13689                     /*
   13690                      * Initialize the new set.
   13691 		     * Also set the xpath document in case things like
   13692 		     * key() evaluation are attempted on the predicate
   13693                      */
   13694                     newset = xmlXPathNodeSetCreate(NULL);
   13695 		    /*
   13696 		    * SPEC XPath 1.0:
   13697 		    *  "For each node in the node-set to be filtered, the
   13698 		    *  PredicateExpr is evaluated with that node as the
   13699 		    *  context node, with the number of nodes in the
   13700 		    *  node-set as the context size, and with the proximity
   13701 		    *  position of the node in the node-set with respect to
   13702 		    *  the axis as the context position;"
   13703 		    * @oldset is the node-set" to be filtered.
   13704 		    *
   13705 		    * SPEC XPath 1.0:
   13706 		    *  "only predicates change the context position and
   13707 		    *  context size (see [2.4 Predicates])."
   13708 		    * Example:
   13709 		    *   node-set  context pos
   13710 		    *    nA         1
   13711 		    *    nB         2
   13712 		    *    nC         3
   13713 		    *   After applying predicate [position() > 1] :
   13714 		    *   node-set  context pos
   13715 		    *    nB         1
   13716 		    *    nC         2
   13717 		    *
   13718 		    * removed the first node in the node-set, then
   13719 		    * the context position of the
   13720 		    */
   13721                     for (i = 0; i < oldset->nodeNr; i++) {
   13722                         /*
   13723                          * Run the evaluation with a node list made of
   13724                          * a single item in the nodeset.
   13725                          */
   13726                         ctxt->context->node = oldset->nodeTab[i];
   13727 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13728 			    (oldset->nodeTab[i]->doc != NULL))
   13729 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13730 			if (tmp == NULL) {
   13731 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13732 				ctxt->context->node);
   13733 			} else {
   13734 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13735 				ctxt->context->node);
   13736 			}
   13737                         valuePush(ctxt, tmp);
   13738                         ctxt->context->contextSize = oldset->nodeNr;
   13739                         ctxt->context->proximityPosition = i + 1;
   13740 			/*
   13741 			* Evaluate the predicate against the context node.
   13742 			* Can/should we optimize position() predicates
   13743 			* here (e.g. "[1]")?
   13744 			*/
   13745                         if (op->ch2 != -1)
   13746                             total +=
   13747                                 xmlXPathCompOpEval(ctxt,
   13748                                                    &comp->steps[op->ch2]);
   13749 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13750 			    xmlXPathFreeNodeSet(newset);
   13751 			    xmlXPathFreeObject(obj);
   13752 			    return(0);
   13753 			}
   13754 
   13755                         /*
   13756                          * The result of the evaluation needs to be tested to
   13757                          * decide whether the filter succeeded or not
   13758                          */
   13759 			/*
   13760 			* OPTIMIZE TODO: Can we use
   13761 			* xmlXPathNodeSetAdd*Unique()* instead?
   13762 			*/
   13763                         res = valuePop(ctxt);
   13764                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13765                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13766                         }
   13767 
   13768                         /*
   13769                          * Cleanup
   13770                          */
   13771                         if (res != NULL) {
   13772 			    xmlXPathReleaseObject(ctxt->context, res);
   13773 			}
   13774                         if (ctxt->value == tmp) {
   13775                             valuePop(ctxt);
   13776 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13777 			    /*
   13778 			    * Don't free the temporary nodeset
   13779 			    * in order to avoid massive recreation inside this
   13780 			    * loop.
   13781 			    */
   13782                         } else
   13783 			    tmp = NULL;
   13784                         ctxt->context->node = NULL;
   13785                     }
   13786 		    if (tmp != NULL)
   13787 			xmlXPathReleaseObject(ctxt->context, tmp);
   13788                     /*
   13789                      * The result is used as the new evaluation set.
   13790                      */
   13791 		    xmlXPathReleaseObject(ctxt->context, obj);
   13792                     ctxt->context->node = NULL;
   13793                     ctxt->context->contextSize = -1;
   13794                     ctxt->context->proximityPosition = -1;
   13795 		    /* may want to move this past the '}' later */
   13796 		    ctxt->context->doc = oldDoc;
   13797 		    valuePush(ctxt,
   13798 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13799                 }
   13800                 ctxt->context->node = oldnode;
   13801                 return (total);
   13802             }
   13803         case XPATH_OP_SORT:
   13804             if (op->ch1 != -1)
   13805                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13806 	    CHECK_ERROR0;
   13807             if ((ctxt->value != NULL) &&
   13808                 (ctxt->value->type == XPATH_NODESET) &&
   13809                 (ctxt->value->nodesetval != NULL) &&
   13810 		(ctxt->value->nodesetval->nodeNr > 1))
   13811 	    {
   13812                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13813 	    }
   13814             return (total);
   13815 #ifdef LIBXML_XPTR_ENABLED
   13816         case XPATH_OP_RANGETO:{
   13817                 xmlXPathObjectPtr range;
   13818                 xmlXPathObjectPtr res, obj;
   13819                 xmlXPathObjectPtr tmp;
   13820                 xmlLocationSetPtr newlocset = NULL;
   13821 		    xmlLocationSetPtr oldlocset;
   13822                 xmlNodeSetPtr oldset;
   13823                 int i, j;
   13824 
   13825                 if (op->ch1 != -1)
   13826                     total +=
   13827                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13828                 if (op->ch2 == -1)
   13829                     return (total);
   13830 
   13831                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13832                     /*
   13833                      * Extract the old locset, and then evaluate the result of the
   13834                      * expression for all the element in the locset. use it to grow
   13835                      * up a new locset.
   13836                      */
   13837                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13838                     obj = valuePop(ctxt);
   13839                     oldlocset = obj->user;
   13840 
   13841                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13842 		        ctxt->context->node = NULL;
   13843                         ctxt->context->contextSize = 0;
   13844                         ctxt->context->proximityPosition = 0;
   13845                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   13846                         res = valuePop(ctxt);
   13847                         if (res != NULL) {
   13848 			    xmlXPathReleaseObject(ctxt->context, res);
   13849 			}
   13850                         valuePush(ctxt, obj);
   13851                         CHECK_ERROR0;
   13852                         return (total);
   13853                     }
   13854                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13855 
   13856                     for (i = 0; i < oldlocset->locNr; i++) {
   13857                         /*
   13858                          * Run the evaluation with a node list made of a
   13859                          * single item in the nodelocset.
   13860                          */
   13861                         ctxt->context->node = oldlocset->locTab[i]->user;
   13862                         ctxt->context->contextSize = oldlocset->locNr;
   13863                         ctxt->context->proximityPosition = i + 1;
   13864 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13865 			    ctxt->context->node);
   13866                         valuePush(ctxt, tmp);
   13867 
   13868                         if (op->ch2 != -1)
   13869                             total +=
   13870                                 xmlXPathCompOpEval(ctxt,
   13871                                                    &comp->steps[op->ch2]);
   13872 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13873 			    xmlXPathFreeObject(obj);
   13874 			    return(0);
   13875 			}
   13876 
   13877                         res = valuePop(ctxt);
   13878 			if (res->type == XPATH_LOCATIONSET) {
   13879 			    xmlLocationSetPtr rloc =
   13880 			        (xmlLocationSetPtr)res->user;
   13881 			    for (j=0; j<rloc->locNr; j++) {
   13882 			        range = xmlXPtrNewRange(
   13883 				  oldlocset->locTab[i]->user,
   13884 				  oldlocset->locTab[i]->index,
   13885 				  rloc->locTab[j]->user2,
   13886 				  rloc->locTab[j]->index2);
   13887 				if (range != NULL) {
   13888 				    xmlXPtrLocationSetAdd(newlocset, range);
   13889 				}
   13890 			    }
   13891 			} else {
   13892 			    range = xmlXPtrNewRangeNodeObject(
   13893 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   13894                             if (range != NULL) {
   13895                                 xmlXPtrLocationSetAdd(newlocset,range);
   13896 			    }
   13897                         }
   13898 
   13899                         /*
   13900                          * Cleanup
   13901                          */
   13902                         if (res != NULL) {
   13903 			    xmlXPathReleaseObject(ctxt->context, res);
   13904 			}
   13905                         if (ctxt->value == tmp) {
   13906                             res = valuePop(ctxt);
   13907 			    xmlXPathReleaseObject(ctxt->context, res);
   13908                         }
   13909 
   13910                         ctxt->context->node = NULL;
   13911                     }
   13912 		} else {	/* Not a location set */
   13913                     CHECK_TYPE0(XPATH_NODESET);
   13914                     obj = valuePop(ctxt);
   13915                     oldset = obj->nodesetval;
   13916                     ctxt->context->node = NULL;
   13917 
   13918                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13919 
   13920                     if (oldset != NULL) {
   13921                         for (i = 0; i < oldset->nodeNr; i++) {
   13922                             /*
   13923                              * Run the evaluation with a node list made of a single item
   13924                              * in the nodeset.
   13925                              */
   13926                             ctxt->context->node = oldset->nodeTab[i];
   13927 			    /*
   13928 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   13929 			    */
   13930 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13931 				ctxt->context->node);
   13932                             valuePush(ctxt, tmp);
   13933 
   13934                             if (op->ch2 != -1)
   13935                                 total +=
   13936                                     xmlXPathCompOpEval(ctxt,
   13937                                                    &comp->steps[op->ch2]);
   13938 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13939 				xmlXPathFreeObject(obj);
   13940 				return(0);
   13941 			    }
   13942 
   13943                             res = valuePop(ctxt);
   13944                             range =
   13945                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   13946                                                       res);
   13947                             if (range != NULL) {
   13948                                 xmlXPtrLocationSetAdd(newlocset, range);
   13949                             }
   13950 
   13951                             /*
   13952                              * Cleanup
   13953                              */
   13954                             if (res != NULL) {
   13955 				xmlXPathReleaseObject(ctxt->context, res);
   13956 			    }
   13957                             if (ctxt->value == tmp) {
   13958                                 res = valuePop(ctxt);
   13959 				xmlXPathReleaseObject(ctxt->context, res);
   13960                             }
   13961 
   13962                             ctxt->context->node = NULL;
   13963                         }
   13964                     }
   13965                 }
   13966 
   13967                 /*
   13968                  * The result is used as the new evaluation set.
   13969                  */
   13970 		xmlXPathReleaseObject(ctxt->context, obj);
   13971                 ctxt->context->node = NULL;
   13972                 ctxt->context->contextSize = -1;
   13973                 ctxt->context->proximityPosition = -1;
   13974                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13975                 return (total);
   13976             }
   13977 #endif /* LIBXML_XPTR_ENABLED */
   13978     }
   13979     xmlGenericError(xmlGenericErrorContext,
   13980                     "XPath: unknown precompiled operation %d\n", op->op);
   13981     return (total);
   13982 }
   13983 
   13984 /**
   13985  * xmlXPathCompOpEvalToBoolean:
   13986  * @ctxt:  the XPath parser context
   13987  *
   13988  * Evaluates if the expression evaluates to true.
   13989  *
   13990  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   13991  */
   13992 static int
   13993 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   13994 			    xmlXPathStepOpPtr op,
   13995 			    int isPredicate)
   13996 {
   13997     xmlXPathObjectPtr resObj = NULL;
   13998 
   13999 start:
   14000     /* comp = ctxt->comp; */
   14001     switch (op->op) {
   14002         case XPATH_OP_END:
   14003             return (0);
   14004 	case XPATH_OP_VALUE:
   14005 	    resObj = (xmlXPathObjectPtr) op->value4;
   14006 	    if (isPredicate)
   14007 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14008 	    return(xmlXPathCastToBoolean(resObj));
   14009 	case XPATH_OP_SORT:
   14010 	    /*
   14011 	    * We don't need sorting for boolean results. Skip this one.
   14012 	    */
   14013             if (op->ch1 != -1) {
   14014 		op = &ctxt->comp->steps[op->ch1];
   14015 		goto start;
   14016 	    }
   14017 	    return(0);
   14018 	case XPATH_OP_COLLECT:
   14019 	    if (op->ch1 == -1)
   14020 		return(0);
   14021 
   14022             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14023 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14024 		return(-1);
   14025 
   14026             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14027 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14028 		return(-1);
   14029 
   14030 	    resObj = valuePop(ctxt);
   14031 	    if (resObj == NULL)
   14032 		return(-1);
   14033 	    break;
   14034 	default:
   14035 	    /*
   14036 	    * Fallback to call xmlXPathCompOpEval().
   14037 	    */
   14038 	    xmlXPathCompOpEval(ctxt, op);
   14039 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14040 		return(-1);
   14041 
   14042 	    resObj = valuePop(ctxt);
   14043 	    if (resObj == NULL)
   14044 		return(-1);
   14045 	    break;
   14046     }
   14047 
   14048     if (resObj) {
   14049 	int res;
   14050 
   14051 	if (resObj->type == XPATH_BOOLEAN) {
   14052 	    res = resObj->boolval;
   14053 	} else if (isPredicate) {
   14054 	    /*
   14055 	    * For predicates a result of type "number" is handled
   14056 	    * differently:
   14057 	    * SPEC XPath 1.0:
   14058 	    * "If the result is a number, the result will be converted
   14059 	    *  to true if the number is equal to the context position
   14060 	    *  and will be converted to false otherwise;"
   14061 	    */
   14062 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14063 	} else {
   14064 	    res = xmlXPathCastToBoolean(resObj);
   14065 	}
   14066 	xmlXPathReleaseObject(ctxt->context, resObj);
   14067 	return(res);
   14068     }
   14069 
   14070     return(0);
   14071 }
   14072 
   14073 #ifdef XPATH_STREAMING
   14074 /**
   14075  * xmlXPathRunStreamEval:
   14076  * @ctxt:  the XPath parser context with the compiled expression
   14077  *
   14078  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14079  */
   14080 static int
   14081 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14082 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14083 {
   14084     int max_depth, min_depth;
   14085     int from_root;
   14086     int ret, depth;
   14087     int eval_all_nodes;
   14088     xmlNodePtr cur = NULL, limit = NULL;
   14089     xmlStreamCtxtPtr patstream = NULL;
   14090 
   14091     int nb_nodes = 0;
   14092 
   14093     if ((ctxt == NULL) || (comp == NULL))
   14094         return(-1);
   14095     max_depth = xmlPatternMaxDepth(comp);
   14096     if (max_depth == -1)
   14097         return(-1);
   14098     if (max_depth == -2)
   14099         max_depth = 10000;
   14100     min_depth = xmlPatternMinDepth(comp);
   14101     if (min_depth == -1)
   14102         return(-1);
   14103     from_root = xmlPatternFromRoot(comp);
   14104     if (from_root < 0)
   14105         return(-1);
   14106 #if 0
   14107     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14108 #endif
   14109 
   14110     if (! toBool) {
   14111 	if (resultSeq == NULL)
   14112 	    return(-1);
   14113 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14114 	if (*resultSeq == NULL)
   14115 	    return(-1);
   14116     }
   14117 
   14118     /*
   14119      * handle the special cases of "/" amd "." being matched
   14120      */
   14121     if (min_depth == 0) {
   14122 	if (from_root) {
   14123 	    /* Select "/" */
   14124 	    if (toBool)
   14125 		return(1);
   14126 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14127 		(xmlNodePtr) ctxt->doc);
   14128 	} else {
   14129 	    /* Select "self::node()" */
   14130 	    if (toBool)
   14131 		return(1);
   14132 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14133 	}
   14134     }
   14135     if (max_depth == 0) {
   14136 	return(0);
   14137     }
   14138 
   14139     if (from_root) {
   14140         cur = (xmlNodePtr)ctxt->doc;
   14141     } else if (ctxt->node != NULL) {
   14142         switch (ctxt->node->type) {
   14143             case XML_ELEMENT_NODE:
   14144             case XML_DOCUMENT_NODE:
   14145             case XML_DOCUMENT_FRAG_NODE:
   14146             case XML_HTML_DOCUMENT_NODE:
   14147 #ifdef LIBXML_DOCB_ENABLED
   14148             case XML_DOCB_DOCUMENT_NODE:
   14149 #endif
   14150 	        cur = ctxt->node;
   14151 		break;
   14152             case XML_ATTRIBUTE_NODE:
   14153             case XML_TEXT_NODE:
   14154             case XML_CDATA_SECTION_NODE:
   14155             case XML_ENTITY_REF_NODE:
   14156             case XML_ENTITY_NODE:
   14157             case XML_PI_NODE:
   14158             case XML_COMMENT_NODE:
   14159             case XML_NOTATION_NODE:
   14160             case XML_DTD_NODE:
   14161             case XML_DOCUMENT_TYPE_NODE:
   14162             case XML_ELEMENT_DECL:
   14163             case XML_ATTRIBUTE_DECL:
   14164             case XML_ENTITY_DECL:
   14165             case XML_NAMESPACE_DECL:
   14166             case XML_XINCLUDE_START:
   14167             case XML_XINCLUDE_END:
   14168 		break;
   14169 	}
   14170 	limit = cur;
   14171     }
   14172     if (cur == NULL) {
   14173         return(0);
   14174     }
   14175 
   14176     patstream = xmlPatternGetStreamCtxt(comp);
   14177     if (patstream == NULL) {
   14178 	/*
   14179 	* QUESTION TODO: Is this an error?
   14180 	*/
   14181 	return(0);
   14182     }
   14183 
   14184     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14185 
   14186     if (from_root) {
   14187 	ret = xmlStreamPush(patstream, NULL, NULL);
   14188 	if (ret < 0) {
   14189 	} else if (ret == 1) {
   14190 	    if (toBool)
   14191 		goto return_1;
   14192 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14193 	}
   14194     }
   14195     depth = 0;
   14196     goto scan_children;
   14197 next_node:
   14198     do {
   14199         nb_nodes++;
   14200 
   14201 	switch (cur->type) {
   14202 	    case XML_ELEMENT_NODE:
   14203 	    case XML_TEXT_NODE:
   14204 	    case XML_CDATA_SECTION_NODE:
   14205 	    case XML_COMMENT_NODE:
   14206 	    case XML_PI_NODE:
   14207 		if (cur->type == XML_ELEMENT_NODE) {
   14208 		    ret = xmlStreamPush(patstream, cur->name,
   14209 				(cur->ns ? cur->ns->href : NULL));
   14210 		} else if (eval_all_nodes)
   14211 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14212 		else
   14213 		    break;
   14214 
   14215 		if (ret < 0) {
   14216 		    /* NOP. */
   14217 		} else if (ret == 1) {
   14218 		    if (toBool)
   14219 			goto return_1;
   14220 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14221 		}
   14222 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14223 		    ret = xmlStreamPop(patstream);
   14224 		    while (cur->next != NULL) {
   14225 			cur = cur->next;
   14226 			if ((cur->type != XML_ENTITY_DECL) &&
   14227 			    (cur->type != XML_DTD_NODE))
   14228 			    goto next_node;
   14229 		    }
   14230 		}
   14231 	    default:
   14232 		break;
   14233 	}
   14234 
   14235 scan_children:
   14236 	if ((cur->children != NULL) && (depth < max_depth)) {
   14237 	    /*
   14238 	     * Do not descend on entities declarations
   14239 	     */
   14240 	    if (cur->children->type != XML_ENTITY_DECL) {
   14241 		cur = cur->children;
   14242 		depth++;
   14243 		/*
   14244 		 * Skip DTDs
   14245 		 */
   14246 		if (cur->type != XML_DTD_NODE)
   14247 		    continue;
   14248 	    }
   14249 	}
   14250 
   14251 	if (cur == limit)
   14252 	    break;
   14253 
   14254 	while (cur->next != NULL) {
   14255 	    cur = cur->next;
   14256 	    if ((cur->type != XML_ENTITY_DECL) &&
   14257 		(cur->type != XML_DTD_NODE))
   14258 		goto next_node;
   14259 	}
   14260 
   14261 	do {
   14262 	    cur = cur->parent;
   14263 	    depth--;
   14264 	    if ((cur == NULL) || (cur == limit))
   14265 	        goto done;
   14266 	    if (cur->type == XML_ELEMENT_NODE) {
   14267 		ret = xmlStreamPop(patstream);
   14268 	    } else if ((eval_all_nodes) &&
   14269 		((cur->type == XML_TEXT_NODE) ||
   14270 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14271 		 (cur->type == XML_COMMENT_NODE) ||
   14272 		 (cur->type == XML_PI_NODE)))
   14273 	    {
   14274 		ret = xmlStreamPop(patstream);
   14275 	    }
   14276 	    if (cur->next != NULL) {
   14277 		cur = cur->next;
   14278 		break;
   14279 	    }
   14280 	} while (cur != NULL);
   14281 
   14282     } while ((cur != NULL) && (depth >= 0));
   14283 
   14284 done:
   14285 
   14286 #if 0
   14287     printf("stream eval: checked %d nodes selected %d\n",
   14288            nb_nodes, retObj->nodesetval->nodeNr);
   14289 #endif
   14290 
   14291     if (patstream)
   14292 	xmlFreeStreamCtxt(patstream);
   14293     return(0);
   14294 
   14295 return_1:
   14296     if (patstream)
   14297 	xmlFreeStreamCtxt(patstream);
   14298     return(1);
   14299 }
   14300 #endif /* XPATH_STREAMING */
   14301 
   14302 /**
   14303  * xmlXPathRunEval:
   14304  * @ctxt:  the XPath parser context with the compiled expression
   14305  * @toBool:  evaluate to a boolean result
   14306  *
   14307  * Evaluate the Precompiled XPath expression in the given context.
   14308  */
   14309 static int
   14310 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14311 {
   14312     xmlXPathCompExprPtr comp;
   14313 
   14314     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14315 	return(-1);
   14316 
   14317     if (ctxt->valueTab == NULL) {
   14318 	/* Allocate the value stack */
   14319 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14320 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14321 	if (ctxt->valueTab == NULL) {
   14322 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14323 	    xmlFree(ctxt);
   14324 	}
   14325 	ctxt->valueNr = 0;
   14326 	ctxt->valueMax = 10;
   14327 	ctxt->value = NULL;
   14328     }
   14329 #ifdef XPATH_STREAMING
   14330     if (ctxt->comp->stream) {
   14331 	int res;
   14332 
   14333 	if (toBool) {
   14334 	    /*
   14335 	    * Evaluation to boolean result.
   14336 	    */
   14337 	    res = xmlXPathRunStreamEval(ctxt->context,
   14338 		ctxt->comp->stream, NULL, 1);
   14339 	    if (res != -1)
   14340 		return(res);
   14341 	} else {
   14342 	    xmlXPathObjectPtr resObj = NULL;
   14343 
   14344 	    /*
   14345 	    * Evaluation to a sequence.
   14346 	    */
   14347 	    res = xmlXPathRunStreamEval(ctxt->context,
   14348 		ctxt->comp->stream, &resObj, 0);
   14349 
   14350 	    if ((res != -1) && (resObj != NULL)) {
   14351 		valuePush(ctxt, resObj);
   14352 		return(0);
   14353 	    }
   14354 	    if (resObj != NULL)
   14355 		xmlXPathReleaseObject(ctxt->context, resObj);
   14356 	}
   14357 	/*
   14358 	* QUESTION TODO: This falls back to normal XPath evaluation
   14359 	* if res == -1. Is this intended?
   14360 	*/
   14361     }
   14362 #endif
   14363     comp = ctxt->comp;
   14364     if (comp->last < 0) {
   14365 	xmlGenericError(xmlGenericErrorContext,
   14366 	    "xmlXPathRunEval: last is less than zero\n");
   14367 	return(-1);
   14368     }
   14369     if (toBool)
   14370 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14371 	    &comp->steps[comp->last], 0));
   14372     else
   14373 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14374 
   14375     return(0);
   14376 }
   14377 
   14378 /************************************************************************
   14379  *									*
   14380  *			Public interfaces				*
   14381  *									*
   14382  ************************************************************************/
   14383 
   14384 /**
   14385  * xmlXPathEvalPredicate:
   14386  * @ctxt:  the XPath context
   14387  * @res:  the Predicate Expression evaluation result
   14388  *
   14389  * Evaluate a predicate result for the current node.
   14390  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14391  * the result to a boolean. If the result is a number, the result will
   14392  * be converted to true if the number is equal to the position of the
   14393  * context node in the context node list (as returned by the position
   14394  * function) and will be converted to false otherwise; if the result
   14395  * is not a number, then the result will be converted as if by a call
   14396  * to the boolean function.
   14397  *
   14398  * Returns 1 if predicate is true, 0 otherwise
   14399  */
   14400 int
   14401 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14402     if ((ctxt == NULL) || (res == NULL)) return(0);
   14403     switch (res->type) {
   14404         case XPATH_BOOLEAN:
   14405 	    return(res->boolval);
   14406         case XPATH_NUMBER:
   14407 	    return(res->floatval == ctxt->proximityPosition);
   14408         case XPATH_NODESET:
   14409         case XPATH_XSLT_TREE:
   14410 	    if (res->nodesetval == NULL)
   14411 		return(0);
   14412 	    return(res->nodesetval->nodeNr != 0);
   14413         case XPATH_STRING:
   14414 	    return((res->stringval != NULL) &&
   14415 	           (xmlStrlen(res->stringval) != 0));
   14416         default:
   14417 	    STRANGE
   14418     }
   14419     return(0);
   14420 }
   14421 
   14422 /**
   14423  * xmlXPathEvaluatePredicateResult:
   14424  * @ctxt:  the XPath Parser context
   14425  * @res:  the Predicate Expression evaluation result
   14426  *
   14427  * Evaluate a predicate result for the current node.
   14428  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14429  * the result to a boolean. If the result is a number, the result will
   14430  * be converted to true if the number is equal to the position of the
   14431  * context node in the context node list (as returned by the position
   14432  * function) and will be converted to false otherwise; if the result
   14433  * is not a number, then the result will be converted as if by a call
   14434  * to the boolean function.
   14435  *
   14436  * Returns 1 if predicate is true, 0 otherwise
   14437  */
   14438 int
   14439 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14440                                 xmlXPathObjectPtr res) {
   14441     if ((ctxt == NULL) || (res == NULL)) return(0);
   14442     switch (res->type) {
   14443         case XPATH_BOOLEAN:
   14444 	    return(res->boolval);
   14445         case XPATH_NUMBER:
   14446 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14447 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14448 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14449 #else
   14450 	    return(res->floatval == ctxt->context->proximityPosition);
   14451 #endif
   14452         case XPATH_NODESET:
   14453         case XPATH_XSLT_TREE:
   14454 	    if (res->nodesetval == NULL)
   14455 		return(0);
   14456 	    return(res->nodesetval->nodeNr != 0);
   14457         case XPATH_STRING:
   14458 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14459 #ifdef LIBXML_XPTR_ENABLED
   14460 	case XPATH_LOCATIONSET:{
   14461 	    xmlLocationSetPtr ptr = res->user;
   14462 	    if (ptr == NULL)
   14463 	        return(0);
   14464 	    return (ptr->locNr != 0);
   14465 	    }
   14466 #endif
   14467         default:
   14468 	    STRANGE
   14469     }
   14470     return(0);
   14471 }
   14472 
   14473 #ifdef XPATH_STREAMING
   14474 /**
   14475  * xmlXPathTryStreamCompile:
   14476  * @ctxt: an XPath context
   14477  * @str:  the XPath expression
   14478  *
   14479  * Try to compile the XPath expression as a streamable subset.
   14480  *
   14481  * Returns the compiled expression or NULL if failed to compile.
   14482  */
   14483 static xmlXPathCompExprPtr
   14484 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14485     /*
   14486      * Optimization: use streaming patterns when the XPath expression can
   14487      * be compiled to a stream lookup
   14488      */
   14489     xmlPatternPtr stream;
   14490     xmlXPathCompExprPtr comp;
   14491     xmlDictPtr dict = NULL;
   14492     const xmlChar **namespaces = NULL;
   14493     xmlNsPtr ns;
   14494     int i, j;
   14495 
   14496     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14497         (!xmlStrchr(str, '@'))) {
   14498 	const xmlChar *tmp;
   14499 
   14500 	/*
   14501 	 * We don't try to handle expressions using the verbose axis
   14502 	 * specifiers ("::"), just the simplied form at this point.
   14503 	 * Additionally, if there is no list of namespaces available and
   14504 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14505 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14506 	 *  to have a list of namespaces at compilation time in order to
   14507 	 *  compile prefixed name tests.
   14508 	 */
   14509 	tmp = xmlStrchr(str, ':');
   14510 	if ((tmp != NULL) &&
   14511 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14512 	    return(NULL);
   14513 
   14514 	if (ctxt != NULL) {
   14515 	    dict = ctxt->dict;
   14516 	    if (ctxt->nsNr > 0) {
   14517 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14518 		if (namespaces == NULL) {
   14519 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14520 		    return(NULL);
   14521 		}
   14522 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14523 		    ns = ctxt->namespaces[j];
   14524 		    namespaces[i++] = ns->href;
   14525 		    namespaces[i++] = ns->prefix;
   14526 		}
   14527 		namespaces[i++] = NULL;
   14528 		namespaces[i] = NULL;
   14529 	    }
   14530 	}
   14531 
   14532 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14533 			&namespaces[0]);
   14534 	if (namespaces != NULL) {
   14535 	    xmlFree((xmlChar **)namespaces);
   14536 	}
   14537 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14538 	    comp = xmlXPathNewCompExpr();
   14539 	    if (comp == NULL) {
   14540 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14541 		return(NULL);
   14542 	    }
   14543 	    comp->stream = stream;
   14544 	    comp->dict = dict;
   14545 	    if (comp->dict)
   14546 		xmlDictReference(comp->dict);
   14547 	    return(comp);
   14548 	}
   14549 	xmlFreePattern(stream);
   14550     }
   14551     return(NULL);
   14552 }
   14553 #endif /* XPATH_STREAMING */
   14554 
   14555 static int
   14556 xmlXPathCanRewriteDosExpression(xmlChar *expr)
   14557 {
   14558     if (expr == NULL)
   14559 	return(0);
   14560     do {
   14561         if ((*expr == '/') && (*(++expr) == '/'))
   14562 	    return(1);
   14563     } while (*expr++);
   14564     return(0);
   14565 }
   14566 static void
   14567 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14568 {
   14569     /*
   14570     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14571     * internal representation.
   14572     */
   14573     if (op->ch1 != -1) {
   14574 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14575 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
   14576 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
   14577 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
   14578 	{
   14579 	    /*
   14580 	    * This is a "child::foo"
   14581 	    */
   14582 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14583 
   14584 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14585 		(prevop->ch1 != -1) &&
   14586 		((xmlXPathAxisVal) prevop->value ==
   14587 		    AXIS_DESCENDANT_OR_SELF) &&
   14588 		(prevop->ch2 == -1) &&
   14589 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14590 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
   14591 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
   14592 	    {
   14593 		/*
   14594 		* This is a "/descendant-or-self::node()" without predicates.
   14595 		* Eliminate it.
   14596 		*/
   14597 		op->ch1 = prevop->ch1;
   14598 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
   14599 	    }
   14600 	}
   14601 	if (op->ch1 != -1)
   14602 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
   14603     }
   14604     if (op->ch2 != -1)
   14605 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
   14606 }
   14607 
   14608 /**
   14609  * xmlXPathCtxtCompile:
   14610  * @ctxt: an XPath context
   14611  * @str:  the XPath expression
   14612  *
   14613  * Compile an XPath expression
   14614  *
   14615  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14616  *         the caller has to free the object.
   14617  */
   14618 xmlXPathCompExprPtr
   14619 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14620     xmlXPathParserContextPtr pctxt;
   14621     xmlXPathCompExprPtr comp;
   14622 
   14623 #ifdef XPATH_STREAMING
   14624     comp = xmlXPathTryStreamCompile(ctxt, str);
   14625     if (comp != NULL)
   14626         return(comp);
   14627 #endif
   14628 
   14629     xmlXPathInit();
   14630 
   14631     pctxt = xmlXPathNewParserContext(str, ctxt);
   14632     if (pctxt == NULL)
   14633         return NULL;
   14634     xmlXPathCompileExpr(pctxt, 1);
   14635 
   14636     if( pctxt->error != XPATH_EXPRESSION_OK )
   14637     {
   14638         xmlXPathFreeParserContext(pctxt);
   14639         return(NULL);
   14640     }
   14641 
   14642     if (*pctxt->cur != 0) {
   14643 	/*
   14644 	 * aleksey: in some cases this line prints *second* error message
   14645 	 * (see bug #78858) and probably this should be fixed.
   14646 	 * However, we are not sure that all error messages are printed
   14647 	 * out in other places. It's not critical so we leave it as-is for now
   14648 	 */
   14649 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14650 	comp = NULL;
   14651     } else {
   14652 	comp = pctxt->comp;
   14653 	pctxt->comp = NULL;
   14654     }
   14655     xmlXPathFreeParserContext(pctxt);
   14656 
   14657     if (comp != NULL) {
   14658 	comp->expr = xmlStrdup(str);
   14659 #ifdef DEBUG_EVAL_COUNTS
   14660 	comp->string = xmlStrdup(str);
   14661 	comp->nb = 0;
   14662 #endif
   14663 	if ((comp->expr != NULL) &&
   14664 	    (comp->nbStep > 2) &&
   14665 	    (comp->last >= 0) &&
   14666 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
   14667 	{
   14668 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
   14669 	}
   14670     }
   14671     return(comp);
   14672 }
   14673 
   14674 /**
   14675  * xmlXPathCompile:
   14676  * @str:  the XPath expression
   14677  *
   14678  * Compile an XPath expression
   14679  *
   14680  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14681  *         the caller has to free the object.
   14682  */
   14683 xmlXPathCompExprPtr
   14684 xmlXPathCompile(const xmlChar *str) {
   14685     return(xmlXPathCtxtCompile(NULL, str));
   14686 }
   14687 
   14688 /**
   14689  * xmlXPathCompiledEvalInternal:
   14690  * @comp:  the compiled XPath expression
   14691  * @ctxt:  the XPath context
   14692  * @resObj: the resulting XPath object or NULL
   14693  * @toBool: 1 if only a boolean result is requested
   14694  *
   14695  * Evaluate the Precompiled XPath expression in the given context.
   14696  * The caller has to free @resObj.
   14697  *
   14698  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14699  *         the caller has to free the object.
   14700  */
   14701 static int
   14702 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14703 			     xmlXPathContextPtr ctxt,
   14704 			     xmlXPathObjectPtr *resObj,
   14705 			     int toBool)
   14706 {
   14707     xmlXPathParserContextPtr pctxt;
   14708 #ifndef LIBXML_THREAD_ENABLED
   14709     static int reentance = 0;
   14710 #endif
   14711     int res;
   14712 
   14713     CHECK_CTXT_NEG(ctxt)
   14714 
   14715     if (comp == NULL)
   14716 	return(-1);
   14717     xmlXPathInit();
   14718 
   14719 #ifndef LIBXML_THREAD_ENABLED
   14720     reentance++;
   14721     if (reentance > 1)
   14722 	xmlXPathDisableOptimizer = 1;
   14723 #endif
   14724 
   14725 #ifdef DEBUG_EVAL_COUNTS
   14726     comp->nb++;
   14727     if ((comp->string != NULL) && (comp->nb > 100)) {
   14728 	fprintf(stderr, "100 x %s\n", comp->string);
   14729 	comp->nb = 0;
   14730     }
   14731 #endif
   14732     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14733     res = xmlXPathRunEval(pctxt, toBool);
   14734 
   14735     if (resObj) {
   14736 	if (pctxt->value == NULL) {
   14737 	    xmlGenericError(xmlGenericErrorContext,
   14738 		"xmlXPathCompiledEval: evaluation failed\n");
   14739 	    *resObj = NULL;
   14740 	} else {
   14741 	    *resObj = valuePop(pctxt);
   14742 	}
   14743     }
   14744 
   14745     /*
   14746     * Pop all remaining objects from the stack.
   14747     */
   14748     if (pctxt->valueNr > 0) {
   14749 	xmlXPathObjectPtr tmp;
   14750 	int stack = 0;
   14751 
   14752 	do {
   14753 	    tmp = valuePop(pctxt);
   14754 	    if (tmp != NULL) {
   14755 		stack++;
   14756 		xmlXPathReleaseObject(ctxt, tmp);
   14757 	    }
   14758 	} while (tmp != NULL);
   14759 	if ((stack != 0) &&
   14760 	    ((toBool) || ((resObj) && (*resObj))))
   14761 	{
   14762 	    xmlGenericError(xmlGenericErrorContext,
   14763 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14764 		stack);
   14765 	}
   14766     }
   14767 
   14768     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14769 	xmlXPathFreeObject(*resObj);
   14770 	*resObj = NULL;
   14771     }
   14772     pctxt->comp = NULL;
   14773     xmlXPathFreeParserContext(pctxt);
   14774 #ifndef LIBXML_THREAD_ENABLED
   14775     reentance--;
   14776 #endif
   14777 
   14778     return(res);
   14779 }
   14780 
   14781 /**
   14782  * xmlXPathCompiledEval:
   14783  * @comp:  the compiled XPath expression
   14784  * @ctx:  the XPath context
   14785  *
   14786  * Evaluate the Precompiled XPath expression in the given context.
   14787  *
   14788  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14789  *         the caller has to free the object.
   14790  */
   14791 xmlXPathObjectPtr
   14792 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14793 {
   14794     xmlXPathObjectPtr res = NULL;
   14795 
   14796     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14797     return(res);
   14798 }
   14799 
   14800 /**
   14801  * xmlXPathCompiledEvalToBoolean:
   14802  * @comp:  the compiled XPath expression
   14803  * @ctxt:  the XPath context
   14804  *
   14805  * Applies the XPath boolean() function on the result of the given
   14806  * compiled expression.
   14807  *
   14808  * Returns 1 if the expression evaluated to true, 0 if to false and
   14809  *         -1 in API and internal errors.
   14810  */
   14811 int
   14812 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14813 			      xmlXPathContextPtr ctxt)
   14814 {
   14815     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14816 }
   14817 
   14818 /**
   14819  * xmlXPathEvalExpr:
   14820  * @ctxt:  the XPath Parser context
   14821  *
   14822  * Parse and evaluate an XPath expression in the given context,
   14823  * then push the result on the context stack
   14824  */
   14825 void
   14826 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14827 #ifdef XPATH_STREAMING
   14828     xmlXPathCompExprPtr comp;
   14829 #endif
   14830 
   14831     if (ctxt == NULL) return;
   14832 
   14833 #ifdef XPATH_STREAMING
   14834     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14835     if (comp != NULL) {
   14836         if (ctxt->comp != NULL)
   14837 	    xmlXPathFreeCompExpr(ctxt->comp);
   14838         ctxt->comp = comp;
   14839 	if (ctxt->cur != NULL)
   14840 	    while (*ctxt->cur != 0) ctxt->cur++;
   14841     } else
   14842 #endif
   14843     {
   14844 	xmlXPathCompileExpr(ctxt, 1);
   14845 	/*
   14846 	* In this scenario the expression string will sit in ctxt->base.
   14847 	*/
   14848 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   14849 	    (ctxt->comp != NULL) &&
   14850 	    (ctxt->base != NULL) &&
   14851 	    (ctxt->comp->nbStep > 2) &&
   14852 	    (ctxt->comp->last >= 0) &&
   14853 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
   14854 	{
   14855 	    xmlXPathRewriteDOSExpression(ctxt->comp,
   14856 		&ctxt->comp->steps[ctxt->comp->last]);
   14857 	}
   14858     }
   14859     CHECK_ERROR;
   14860     xmlXPathRunEval(ctxt, 0);
   14861 }
   14862 
   14863 /**
   14864  * xmlXPathEval:
   14865  * @str:  the XPath expression
   14866  * @ctx:  the XPath context
   14867  *
   14868  * Evaluate the XPath Location Path in the given context.
   14869  *
   14870  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14871  *         the caller has to free the object.
   14872  */
   14873 xmlXPathObjectPtr
   14874 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   14875     xmlXPathParserContextPtr ctxt;
   14876     xmlXPathObjectPtr res, tmp, init = NULL;
   14877     int stack = 0;
   14878 
   14879     CHECK_CTXT(ctx)
   14880 
   14881     xmlXPathInit();
   14882 
   14883     ctxt = xmlXPathNewParserContext(str, ctx);
   14884     if (ctxt == NULL)
   14885         return NULL;
   14886     xmlXPathEvalExpr(ctxt);
   14887 
   14888     if (ctxt->value == NULL) {
   14889 	xmlGenericError(xmlGenericErrorContext,
   14890 		"xmlXPathEval: evaluation failed\n");
   14891 	res = NULL;
   14892     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   14893 #ifdef XPATH_STREAMING
   14894             && (ctxt->comp->stream == NULL)
   14895 #endif
   14896 	      ) {
   14897 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14898 	res = NULL;
   14899     } else {
   14900 	res = valuePop(ctxt);
   14901     }
   14902 
   14903     do {
   14904         tmp = valuePop(ctxt);
   14905 	if (tmp != NULL) {
   14906 	    if (tmp != init)
   14907 		stack++;
   14908 	    xmlXPathReleaseObject(ctx, tmp);
   14909         }
   14910     } while (tmp != NULL);
   14911     if ((stack != 0) && (res != NULL)) {
   14912 	xmlGenericError(xmlGenericErrorContext,
   14913 		"xmlXPathEval: %d object left on the stack\n",
   14914 	        stack);
   14915     }
   14916     if (ctxt->error != XPATH_EXPRESSION_OK) {
   14917 	xmlXPathFreeObject(res);
   14918 	res = NULL;
   14919     }
   14920 
   14921     xmlXPathFreeParserContext(ctxt);
   14922     return(res);
   14923 }
   14924 
   14925 /**
   14926  * xmlXPathEvalExpression:
   14927  * @str:  the XPath expression
   14928  * @ctxt:  the XPath context
   14929  *
   14930  * Evaluate the XPath expression in the given context.
   14931  *
   14932  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14933  *         the caller has to free the object.
   14934  */
   14935 xmlXPathObjectPtr
   14936 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   14937     xmlXPathParserContextPtr pctxt;
   14938     xmlXPathObjectPtr res, tmp;
   14939     int stack = 0;
   14940 
   14941     CHECK_CTXT(ctxt)
   14942 
   14943     xmlXPathInit();
   14944 
   14945     pctxt = xmlXPathNewParserContext(str, ctxt);
   14946     if (pctxt == NULL)
   14947         return NULL;
   14948     xmlXPathEvalExpr(pctxt);
   14949 
   14950     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   14951 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14952 	res = NULL;
   14953     } else {
   14954 	res = valuePop(pctxt);
   14955     }
   14956     do {
   14957         tmp = valuePop(pctxt);
   14958 	if (tmp != NULL) {
   14959 	    xmlXPathReleaseObject(ctxt, tmp);
   14960 	    stack++;
   14961 	}
   14962     } while (tmp != NULL);
   14963     if ((stack != 0) && (res != NULL)) {
   14964 	xmlGenericError(xmlGenericErrorContext,
   14965 		"xmlXPathEvalExpression: %d object left on the stack\n",
   14966 	        stack);
   14967     }
   14968     xmlXPathFreeParserContext(pctxt);
   14969     return(res);
   14970 }
   14971 
   14972 /************************************************************************
   14973  *									*
   14974  *	Extra functions not pertaining to the XPath spec		*
   14975  *									*
   14976  ************************************************************************/
   14977 /**
   14978  * xmlXPathEscapeUriFunction:
   14979  * @ctxt:  the XPath Parser context
   14980  * @nargs:  the number of arguments
   14981  *
   14982  * Implement the escape-uri() XPath function
   14983  *    string escape-uri(string $str, bool $escape-reserved)
   14984  *
   14985  * This function applies the URI escaping rules defined in section 2 of [RFC
   14986  * 2396] to the string supplied as $uri-part, which typically represents all
   14987  * or part of a URI. The effect of the function is to replace any special
   14988  * character in the string by an escape sequence of the form %xx%yy...,
   14989  * where xxyy... is the hexadecimal representation of the octets used to
   14990  * represent the character in UTF-8.
   14991  *
   14992  * The set of characters that are escaped depends on the setting of the
   14993  * boolean argument $escape-reserved.
   14994  *
   14995  * If $escape-reserved is true, all characters are escaped other than lower
   14996  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   14997  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   14998  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   14999  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15000  * A-F).
   15001  *
   15002  * If $escape-reserved is false, the behavior differs in that characters
   15003  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15004  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15005  *
   15006  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15007  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15008  * compared using string comparison functions, this function must always use
   15009  * the upper-case letters A-F.
   15010  *
   15011  * Generally, $escape-reserved should be set to true when escaping a string
   15012  * that is to form a single part of a URI, and to false when escaping an
   15013  * entire URI or URI reference.
   15014  *
   15015  * In the case of non-ascii characters, the string is encoded according to
   15016  * utf-8 and then converted according to RFC 2396.
   15017  *
   15018  * Examples
   15019  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15020  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15021  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15022  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15023  *
   15024  */
   15025 static void
   15026 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15027     xmlXPathObjectPtr str;
   15028     int escape_reserved;
   15029     xmlBufferPtr target;
   15030     xmlChar *cptr;
   15031     xmlChar escape[4];
   15032 
   15033     CHECK_ARITY(2);
   15034 
   15035     escape_reserved = xmlXPathPopBoolean(ctxt);
   15036 
   15037     CAST_TO_STRING;
   15038     str = valuePop(ctxt);
   15039 
   15040     target = xmlBufferCreate();
   15041 
   15042     escape[0] = '%';
   15043     escape[3] = 0;
   15044 
   15045     if (target) {
   15046 	for (cptr = str->stringval; *cptr; cptr++) {
   15047 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15048 		(*cptr >= 'a' && *cptr <= 'z') ||
   15049 		(*cptr >= '0' && *cptr <= '9') ||
   15050 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15051 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15052 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15053 		(*cptr == '%' &&
   15054 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15055 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15056 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15057 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15058 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15059 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15060 		(!escape_reserved &&
   15061 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15062 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15063 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15064 		  *cptr == ','))) {
   15065 		xmlBufferAdd(target, cptr, 1);
   15066 	    } else {
   15067 		if ((*cptr >> 4) < 10)
   15068 		    escape[1] = '0' + (*cptr >> 4);
   15069 		else
   15070 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15071 		if ((*cptr & 0xF) < 10)
   15072 		    escape[2] = '0' + (*cptr & 0xF);
   15073 		else
   15074 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15075 
   15076 		xmlBufferAdd(target, &escape[0], 3);
   15077 	    }
   15078 	}
   15079     }
   15080     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15081 	xmlBufferContent(target)));
   15082     xmlBufferFree(target);
   15083     xmlXPathReleaseObject(ctxt->context, str);
   15084 }
   15085 
   15086 /**
   15087  * xmlXPathRegisterAllFunctions:
   15088  * @ctxt:  the XPath context
   15089  *
   15090  * Registers all default XPath functions in this context
   15091  */
   15092 void
   15093 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15094 {
   15095     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15096                          xmlXPathBooleanFunction);
   15097     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15098                          xmlXPathCeilingFunction);
   15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15100                          xmlXPathCountFunction);
   15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15102                          xmlXPathConcatFunction);
   15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15104                          xmlXPathContainsFunction);
   15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15106                          xmlXPathIdFunction);
   15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15108                          xmlXPathFalseFunction);
   15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15110                          xmlXPathFloorFunction);
   15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15112                          xmlXPathLastFunction);
   15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15114                          xmlXPathLangFunction);
   15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15116                          xmlXPathLocalNameFunction);
   15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15118                          xmlXPathNotFunction);
   15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15120                          xmlXPathNameFunction);
   15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15122                          xmlXPathNamespaceURIFunction);
   15123     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15124                          xmlXPathNormalizeFunction);
   15125     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15126                          xmlXPathNumberFunction);
   15127     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15128                          xmlXPathPositionFunction);
   15129     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15130                          xmlXPathRoundFunction);
   15131     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15132                          xmlXPathStringFunction);
   15133     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15134                          xmlXPathStringLengthFunction);
   15135     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15136                          xmlXPathStartsWithFunction);
   15137     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15138                          xmlXPathSubstringFunction);
   15139     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15140                          xmlXPathSubstringBeforeFunction);
   15141     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15142                          xmlXPathSubstringAfterFunction);
   15143     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15144                          xmlXPathSumFunction);
   15145     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15146                          xmlXPathTrueFunction);
   15147     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15148                          xmlXPathTranslateFunction);
   15149 
   15150     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15151 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15152                          xmlXPathEscapeUriFunction);
   15153 }
   15154 
   15155 #endif /* LIBXML_XPATH_ENABLED */
   15156 #define bottom_xpath
   15157 #include "elfgcchack.h"
   15158