Home | History | Annotate | Download | only in libxml2
      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 #include "buf.h"
     59 
     60 #ifdef LIBXML_PATTERN_ENABLED
     61 #define XPATH_STREAMING
     62 #endif
     63 
     64 #define TODO								\
     65     xmlGenericError(xmlGenericErrorContext,				\
     66 	    "Unimplemented block at %s:%d\n",				\
     67             __FILE__, __LINE__);
     68 
     69 /**
     70  * WITH_TIM_SORT:
     71  *
     72  * Use the Timsort algorithm provided in timsort.h to sort
     73  * nodeset as this is a great improvement over the old Shell sort
     74  * used in xmlXPathNodeSetSort()
     75  */
     76 #define WITH_TIM_SORT
     77 
     78 /*
     79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
     80 * If defined, this will use xmlXPathCmpNodesExt() instead of
     81 * xmlXPathCmpNodes(). The new function is optimized comparison of
     82 * non-element nodes; actually it will speed up comparison only if
     83 * xmlXPathOrderDocElems() was called in order to index the elements of
     84 * a tree in document order; Libxslt does such an indexing, thus it will
     85 * benefit from this optimization.
     86 */
     87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
     88 
     89 /*
     90 * XP_OPTIMIZED_FILTER_FIRST:
     91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
     92 * in a way, that it stop evaluation at the first node.
     93 */
     94 #define XP_OPTIMIZED_FILTER_FIRST
     95 
     96 /*
     97 * XP_DEBUG_OBJ_USAGE:
     98 * Internal flag to enable tracking of how much XPath objects have been
     99 * created.
    100 */
    101 /* #define XP_DEBUG_OBJ_USAGE */
    102 
    103 /*
    104  * XPATH_MAX_STEPS:
    105  * when compiling an XPath expression we arbitrary limit the maximum
    106  * number of step operation in the compiled expression. 1000000 is
    107  * an insanely large value which should never be reached under normal
    108  * circumstances
    109  */
    110 #define XPATH_MAX_STEPS 1000000
    111 
    112 /*
    113  * XPATH_MAX_STACK_DEPTH:
    114  * when evaluating an XPath expression we arbitrary limit the maximum
    115  * number of object allowed to be pushed on the stack. 1000000 is
    116  * an insanely large value which should never be reached under normal
    117  * circumstances
    118  */
    119 #define XPATH_MAX_STACK_DEPTH 1000000
    120 
    121 /*
    122  * XPATH_MAX_NODESET_LENGTH:
    123  * when evaluating an XPath expression nodesets are created and we
    124  * arbitrary limit the maximum length of those node set. 10000000 is
    125  * an insanely large value which should never be reached under normal
    126  * circumstances, one would first need to construct an in memory tree
    127  * with more than 10 millions nodes.
    128  */
    129 #define XPATH_MAX_NODESET_LENGTH 10000000
    130 
    131 /*
    132  * TODO:
    133  * There are a few spots where some tests are done which depend upon ascii
    134  * data.  These should be enhanced for full UTF8 support (see particularly
    135  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
    136  */
    137 
    138 /*
    139  * Wrapper for the Timsort argorithm from timsort.h
    140  */
    141 #ifdef WITH_TIM_SORT
    142 #define SORT_NAME libxml_domnode
    143 #define SORT_TYPE xmlNodePtr
    144 /**
    145  * wrap_cmp:
    146  * @x: a node
    147  * @y: another node
    148  *
    149  * Comparison function for the Timsort implementation
    150  *
    151  * Returns -2 in case of error -1 if first point < second point, 0 if
    152  *         it's the same node, +1 otherwise
    153  */
    154 static
    155 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
    156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
    157     static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
    158     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    159     {
    160         int res = xmlXPathCmpNodesExt(x, y);
    161         return res == -2 ? res : -res;
    162     }
    163 #else
    164     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    165     {
    166         int res = xmlXPathCmpNodes(x, y);
    167         return res == -2 ? res : -res;
    168     }
    169 #endif
    170 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
    171 #include "timsort.h"
    172 #endif /* WITH_TIM_SORT */
    173 
    174 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
    175 
    176 /************************************************************************
    177  *									*
    178  *			Floating point stuff				*
    179  *									*
    180  ************************************************************************/
    181 
    182 #ifndef TRIO_REPLACE_STDIO
    183 #define TRIO_PUBLIC static
    184 #endif
    185 #include "trionan.c"
    186 
    187 /*
    188  * The lack of portability of this section of the libc is annoying !
    189  */
    190 double xmlXPathNAN = 0;
    191 double xmlXPathPINF = 1;
    192 double xmlXPathNINF = -1;
    193 static double xmlXPathNZERO = 0; /* not exported from headers */
    194 static int xmlXPathInitialized = 0;
    195 
    196 /**
    197  * xmlXPathInit:
    198  *
    199  * Initialize the XPath environment
    200  */
    201 void
    202 xmlXPathInit(void) {
    203     if (xmlXPathInitialized) return;
    204 
    205     xmlXPathPINF = trio_pinf();
    206     xmlXPathNINF = trio_ninf();
    207     xmlXPathNAN = trio_nan();
    208     xmlXPathNZERO = trio_nzero();
    209 
    210     xmlXPathInitialized = 1;
    211 }
    212 
    213 /**
    214  * xmlXPathIsNaN:
    215  * @val:  a double value
    216  *
    217  * Provides a portable isnan() function to detect whether a double
    218  * is a NotaNumber. Based on trio code
    219  * http://sourceforge.net/projects/ctrio/
    220  *
    221  * Returns 1 if the value is a NaN, 0 otherwise
    222  */
    223 int
    224 xmlXPathIsNaN(double val) {
    225     return(trio_isnan(val));
    226 }
    227 
    228 /**
    229  * xmlXPathIsInf:
    230  * @val:  a double value
    231  *
    232  * Provides a portable isinf() function to detect whether a double
    233  * is a +Infinite or -Infinite. Based on trio code
    234  * http://sourceforge.net/projects/ctrio/
    235  *
    236  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
    237  */
    238 int
    239 xmlXPathIsInf(double val) {
    240     return(trio_isinf(val));
    241 }
    242 
    243 #endif /* SCHEMAS or XPATH */
    244 #ifdef LIBXML_XPATH_ENABLED
    245 /**
    246  * xmlXPathGetSign:
    247  * @val:  a double value
    248  *
    249  * Provides a portable function to detect the sign of a double
    250  * Modified from trio code
    251  * http://sourceforge.net/projects/ctrio/
    252  *
    253  * Returns 1 if the value is Negative, 0 if positive
    254  */
    255 static int
    256 xmlXPathGetSign(double val) {
    257     return(trio_signbit(val));
    258 }
    259 
    260 
    261 /*
    262  * TODO: when compatibility allows remove all "fake node libxslt" strings
    263  *       the test should just be name[0] = ' '
    264  */
    265 #ifdef DEBUG_XPATH_EXPRESSION
    266 #define DEBUG_STEP
    267 #define DEBUG_EXPR
    268 #define DEBUG_EVAL_COUNTS
    269 #endif
    270 
    271 static xmlNs xmlXPathXMLNamespaceStruct = {
    272     NULL,
    273     XML_NAMESPACE_DECL,
    274     XML_XML_NAMESPACE,
    275     BAD_CAST "xml",
    276     NULL,
    277     NULL
    278 };
    279 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    280 #ifndef LIBXML_THREAD_ENABLED
    281 /*
    282  * Optimizer is disabled only when threaded apps are detected while
    283  * the library ain't compiled for thread safety.
    284  */
    285 static int xmlXPathDisableOptimizer = 0;
    286 #endif
    287 
    288 /************************************************************************
    289  *									*
    290  *			Error handling routines				*
    291  *									*
    292  ************************************************************************/
    293 
    294 /**
    295  * XP_ERRORNULL:
    296  * @X:  the error code
    297  *
    298  * Macro to raise an XPath error and return NULL.
    299  */
    300 #define XP_ERRORNULL(X)							\
    301     { xmlXPathErr(ctxt, X); return(NULL); }
    302 
    303 /*
    304  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    305  */
    306 static const char *xmlXPathErrorMessages[] = {
    307     "Ok\n",
    308     "Number encoding\n",
    309     "Unfinished literal\n",
    310     "Start of literal\n",
    311     "Expected $ for variable reference\n",
    312     "Undefined variable\n",
    313     "Invalid predicate\n",
    314     "Invalid expression\n",
    315     "Missing closing curly brace\n",
    316     "Unregistered function\n",
    317     "Invalid operand\n",
    318     "Invalid type\n",
    319     "Invalid number of arguments\n",
    320     "Invalid context size\n",
    321     "Invalid context position\n",
    322     "Memory allocation error\n",
    323     "Syntax error\n",
    324     "Resource error\n",
    325     "Sub resource error\n",
    326     "Undefined namespace prefix\n",
    327     "Encoding error\n",
    328     "Char out of XML range\n",
    329     "Invalid or incomplete context\n",
    330     "Stack usage errror\n",
    331     "Forbidden variable\n",
    332     "?? Unknown error ??\n"	/* Must be last in the list! */
    333 };
    334 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    335 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    336 /**
    337  * xmlXPathErrMemory:
    338  * @ctxt:  an XPath context
    339  * @extra:  extra informations
    340  *
    341  * Handle a redefinition of attribute error
    342  */
    343 static void
    344 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    345 {
    346     if (ctxt != NULL) {
    347         if (extra) {
    348             xmlChar buf[200];
    349 
    350             xmlStrPrintf(buf, 200,
    351                          BAD_CAST "Memory allocation failed : %s\n",
    352                          extra);
    353             ctxt->lastError.message = (char *) xmlStrdup(buf);
    354         } else {
    355             ctxt->lastError.message = (char *)
    356 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    357         }
    358         ctxt->lastError.domain = XML_FROM_XPATH;
    359         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    360 	if (ctxt->error != NULL)
    361 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    362     } else {
    363         if (extra)
    364             __xmlRaiseError(NULL, NULL, NULL,
    365                             NULL, NULL, XML_FROM_XPATH,
    366                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    367                             extra, NULL, NULL, 0, 0,
    368                             "Memory allocation failed : %s\n", extra);
    369         else
    370             __xmlRaiseError(NULL, NULL, NULL,
    371                             NULL, NULL, XML_FROM_XPATH,
    372                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    373                             NULL, NULL, NULL, 0, 0,
    374                             "Memory allocation failed\n");
    375     }
    376 }
    377 
    378 /**
    379  * xmlXPathPErrMemory:
    380  * @ctxt:  an XPath parser context
    381  * @extra:  extra informations
    382  *
    383  * Handle a redefinition of attribute error
    384  */
    385 static void
    386 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    387 {
    388     if (ctxt == NULL)
    389 	xmlXPathErrMemory(NULL, extra);
    390     else {
    391 	ctxt->error = XPATH_MEMORY_ERROR;
    392 	xmlXPathErrMemory(ctxt->context, extra);
    393     }
    394 }
    395 
    396 /**
    397  * xmlXPathErr:
    398  * @ctxt:  a XPath parser context
    399  * @error:  the error code
    400  *
    401  * Handle an XPath error
    402  */
    403 void
    404 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    405 {
    406     if ((error < 0) || (error > MAXERRNO))
    407 	error = MAXERRNO;
    408     if (ctxt == NULL) {
    409 	__xmlRaiseError(NULL, NULL, NULL,
    410 			NULL, NULL, XML_FROM_XPATH,
    411 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    412 			XML_ERR_ERROR, NULL, 0,
    413 			NULL, NULL, NULL, 0, 0,
    414 			"%s", xmlXPathErrorMessages[error]);
    415 	return;
    416     }
    417     ctxt->error = error;
    418     if (ctxt->context == NULL) {
    419 	__xmlRaiseError(NULL, NULL, NULL,
    420 			NULL, NULL, XML_FROM_XPATH,
    421 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    422 			XML_ERR_ERROR, NULL, 0,
    423 			(const char *) ctxt->base, NULL, NULL,
    424 			ctxt->cur - ctxt->base, 0,
    425 			"%s", xmlXPathErrorMessages[error]);
    426 	return;
    427     }
    428 
    429     /* cleanup current last error */
    430     xmlResetError(&ctxt->context->lastError);
    431 
    432     ctxt->context->lastError.domain = XML_FROM_XPATH;
    433     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    434                            XPATH_EXPRESSION_OK;
    435     ctxt->context->lastError.level = XML_ERR_ERROR;
    436     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    437     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    438     ctxt->context->lastError.node = ctxt->context->debugNode;
    439     if (ctxt->context->error != NULL) {
    440 	ctxt->context->error(ctxt->context->userData,
    441 	                     &ctxt->context->lastError);
    442     } else {
    443 	__xmlRaiseError(NULL, NULL, NULL,
    444 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    445 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    446 			XML_ERR_ERROR, NULL, 0,
    447 			(const char *) ctxt->base, NULL, NULL,
    448 			ctxt->cur - ctxt->base, 0,
    449 			"%s", xmlXPathErrorMessages[error]);
    450     }
    451 
    452 }
    453 
    454 /**
    455  * xmlXPatherror:
    456  * @ctxt:  the XPath Parser context
    457  * @file:  the file name
    458  * @line:  the line number
    459  * @no:  the error number
    460  *
    461  * Formats an error message.
    462  */
    463 void
    464 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    465               int line ATTRIBUTE_UNUSED, int no) {
    466     xmlXPathErr(ctxt, no);
    467 }
    468 
    469 /************************************************************************
    470  *									*
    471  *			Utilities					*
    472  *									*
    473  ************************************************************************/
    474 
    475 /**
    476  * xsltPointerList:
    477  *
    478  * Pointer-list for various purposes.
    479  */
    480 typedef struct _xmlPointerList xmlPointerList;
    481 typedef xmlPointerList *xmlPointerListPtr;
    482 struct _xmlPointerList {
    483     void **items;
    484     int number;
    485     int size;
    486 };
    487 /*
    488 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    489 * and here, we should make the functions public.
    490 */
    491 static int
    492 xmlPointerListAddSize(xmlPointerListPtr list,
    493 		       void *item,
    494 		       int initialSize)
    495 {
    496     if (list->items == NULL) {
    497 	if (initialSize <= 0)
    498 	    initialSize = 1;
    499 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
    500 	if (list->items == NULL) {
    501 	    xmlXPathErrMemory(NULL,
    502 		"xmlPointerListCreate: allocating item\n");
    503 	    return(-1);
    504 	}
    505 	list->number = 0;
    506 	list->size = initialSize;
    507     } else if (list->size <= list->number) {
    508         if (list->size > 50000000) {
    509 	    xmlXPathErrMemory(NULL,
    510 		"xmlPointerListAddSize: re-allocating item\n");
    511             return(-1);
    512         }
    513 	list->size *= 2;
    514 	list->items = (void **) xmlRealloc(list->items,
    515 	    list->size * sizeof(void *));
    516 	if (list->items == NULL) {
    517 	    xmlXPathErrMemory(NULL,
    518 		"xmlPointerListAddSize: re-allocating item\n");
    519 	    list->size = 0;
    520 	    return(-1);
    521 	}
    522     }
    523     list->items[list->number++] = item;
    524     return(0);
    525 }
    526 
    527 /**
    528  * xsltPointerListCreate:
    529  *
    530  * Creates an xsltPointerList structure.
    531  *
    532  * Returns a xsltPointerList structure or NULL in case of an error.
    533  */
    534 static xmlPointerListPtr
    535 xmlPointerListCreate(int initialSize)
    536 {
    537     xmlPointerListPtr ret;
    538 
    539     ret = xmlMalloc(sizeof(xmlPointerList));
    540     if (ret == NULL) {
    541 	xmlXPathErrMemory(NULL,
    542 	    "xmlPointerListCreate: allocating item\n");
    543 	return (NULL);
    544     }
    545     memset(ret, 0, sizeof(xmlPointerList));
    546     if (initialSize > 0) {
    547 	xmlPointerListAddSize(ret, NULL, initialSize);
    548 	ret->number = 0;
    549     }
    550     return (ret);
    551 }
    552 
    553 /**
    554  * xsltPointerListFree:
    555  *
    556  * Frees the xsltPointerList structure. This does not free
    557  * the content of the list.
    558  */
    559 static void
    560 xmlPointerListFree(xmlPointerListPtr list)
    561 {
    562     if (list == NULL)
    563 	return;
    564     if (list->items != NULL)
    565 	xmlFree(list->items);
    566     xmlFree(list);
    567 }
    568 
    569 /************************************************************************
    570  *									*
    571  *			Parser Types					*
    572  *									*
    573  ************************************************************************/
    574 
    575 /*
    576  * Types are private:
    577  */
    578 
    579 typedef enum {
    580     XPATH_OP_END=0,
    581     XPATH_OP_AND,
    582     XPATH_OP_OR,
    583     XPATH_OP_EQUAL,
    584     XPATH_OP_CMP,
    585     XPATH_OP_PLUS,
    586     XPATH_OP_MULT,
    587     XPATH_OP_UNION,
    588     XPATH_OP_ROOT,
    589     XPATH_OP_NODE,
    590     XPATH_OP_RESET, /* 10 */
    591     XPATH_OP_COLLECT,
    592     XPATH_OP_VALUE, /* 12 */
    593     XPATH_OP_VARIABLE,
    594     XPATH_OP_FUNCTION,
    595     XPATH_OP_ARG,
    596     XPATH_OP_PREDICATE,
    597     XPATH_OP_FILTER, /* 17 */
    598     XPATH_OP_SORT /* 18 */
    599 #ifdef LIBXML_XPTR_ENABLED
    600     ,XPATH_OP_RANGETO
    601 #endif
    602 } xmlXPathOp;
    603 
    604 typedef enum {
    605     AXIS_ANCESTOR = 1,
    606     AXIS_ANCESTOR_OR_SELF,
    607     AXIS_ATTRIBUTE,
    608     AXIS_CHILD,
    609     AXIS_DESCENDANT,
    610     AXIS_DESCENDANT_OR_SELF,
    611     AXIS_FOLLOWING,
    612     AXIS_FOLLOWING_SIBLING,
    613     AXIS_NAMESPACE,
    614     AXIS_PARENT,
    615     AXIS_PRECEDING,
    616     AXIS_PRECEDING_SIBLING,
    617     AXIS_SELF
    618 } xmlXPathAxisVal;
    619 
    620 typedef enum {
    621     NODE_TEST_NONE = 0,
    622     NODE_TEST_TYPE = 1,
    623     NODE_TEST_PI = 2,
    624     NODE_TEST_ALL = 3,
    625     NODE_TEST_NS = 4,
    626     NODE_TEST_NAME = 5
    627 } xmlXPathTestVal;
    628 
    629 typedef enum {
    630     NODE_TYPE_NODE = 0,
    631     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    632     NODE_TYPE_TEXT = XML_TEXT_NODE,
    633     NODE_TYPE_PI = XML_PI_NODE
    634 } xmlXPathTypeVal;
    635 
    636 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    637 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    638 struct _xmlXPathStepOp {
    639     xmlXPathOp op;		/* The identifier of the operation */
    640     int ch1;			/* First child */
    641     int ch2;			/* Second child */
    642     int value;
    643     int value2;
    644     int value3;
    645     void *value4;
    646     void *value5;
    647     void *cache;
    648     void *cacheURI;
    649 };
    650 
    651 struct _xmlXPathCompExpr {
    652     int nbStep;			/* Number of steps in this expression */
    653     int maxStep;		/* Maximum number of steps allocated */
    654     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    655     int last;			/* index of last step in expression */
    656     xmlChar *expr;		/* the expression being computed */
    657     xmlDictPtr dict;		/* the dictionnary to use if any */
    658 #ifdef DEBUG_EVAL_COUNTS
    659     int nb;
    660     xmlChar *string;
    661 #endif
    662 #ifdef XPATH_STREAMING
    663     xmlPatternPtr stream;
    664 #endif
    665 };
    666 
    667 /************************************************************************
    668  *									*
    669  *			Forward declarations				*
    670  *									*
    671  ************************************************************************/
    672 static void
    673 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    674 static void
    675 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    676 static int
    677 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    678                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    679 static int
    680 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    681 			    xmlXPathStepOpPtr op,
    682 			    int isPredicate);
    683 
    684 /************************************************************************
    685  *									*
    686  *			Parser Type functions				*
    687  *									*
    688  ************************************************************************/
    689 
    690 /**
    691  * xmlXPathNewCompExpr:
    692  *
    693  * Create a new Xpath component
    694  *
    695  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    696  */
    697 static xmlXPathCompExprPtr
    698 xmlXPathNewCompExpr(void) {
    699     xmlXPathCompExprPtr cur;
    700 
    701     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    702     if (cur == NULL) {
    703         xmlXPathErrMemory(NULL, "allocating component\n");
    704 	return(NULL);
    705     }
    706     memset(cur, 0, sizeof(xmlXPathCompExpr));
    707     cur->maxStep = 10;
    708     cur->nbStep = 0;
    709     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    710 	                                   sizeof(xmlXPathStepOp));
    711     if (cur->steps == NULL) {
    712         xmlXPathErrMemory(NULL, "allocating steps\n");
    713 	xmlFree(cur);
    714 	return(NULL);
    715     }
    716     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    717     cur->last = -1;
    718 #ifdef DEBUG_EVAL_COUNTS
    719     cur->nb = 0;
    720 #endif
    721     return(cur);
    722 }
    723 
    724 /**
    725  * xmlXPathFreeCompExpr:
    726  * @comp:  an XPATH comp
    727  *
    728  * Free up the memory allocated by @comp
    729  */
    730 void
    731 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
    732 {
    733     xmlXPathStepOpPtr op;
    734     int i;
    735 
    736     if (comp == NULL)
    737         return;
    738     if (comp->dict == NULL) {
    739 	for (i = 0; i < comp->nbStep; i++) {
    740 	    op = &comp->steps[i];
    741 	    if (op->value4 != NULL) {
    742 		if (op->op == XPATH_OP_VALUE)
    743 		    xmlXPathFreeObject(op->value4);
    744 		else
    745 		    xmlFree(op->value4);
    746 	    }
    747 	    if (op->value5 != NULL)
    748 		xmlFree(op->value5);
    749 	}
    750     } else {
    751 	for (i = 0; i < comp->nbStep; i++) {
    752 	    op = &comp->steps[i];
    753 	    if (op->value4 != NULL) {
    754 		if (op->op == XPATH_OP_VALUE)
    755 		    xmlXPathFreeObject(op->value4);
    756 	    }
    757 	}
    758         xmlDictFree(comp->dict);
    759     }
    760     if (comp->steps != NULL) {
    761         xmlFree(comp->steps);
    762     }
    763 #ifdef DEBUG_EVAL_COUNTS
    764     if (comp->string != NULL) {
    765         xmlFree(comp->string);
    766     }
    767 #endif
    768 #ifdef XPATH_STREAMING
    769     if (comp->stream != NULL) {
    770         xmlFreePatternList(comp->stream);
    771     }
    772 #endif
    773     if (comp->expr != NULL) {
    774         xmlFree(comp->expr);
    775     }
    776 
    777     xmlFree(comp);
    778 }
    779 
    780 /**
    781  * xmlXPathCompExprAdd:
    782  * @comp:  the compiled expression
    783  * @ch1: first child index
    784  * @ch2: second child index
    785  * @op:  an op
    786  * @value:  the first int value
    787  * @value2:  the second int value
    788  * @value3:  the third int value
    789  * @value4:  the first string value
    790  * @value5:  the second string value
    791  *
    792  * Add a step to an XPath Compiled Expression
    793  *
    794  * Returns -1 in case of failure, the index otherwise
    795  */
    796 static int
    797 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
    798    xmlXPathOp op, int value,
    799    int value2, int value3, void *value4, void *value5) {
    800     if (comp->nbStep >= comp->maxStep) {
    801 	xmlXPathStepOp *real;
    802 
    803         if (comp->maxStep >= XPATH_MAX_STEPS) {
    804 	    xmlXPathErrMemory(NULL, "adding step\n");
    805 	    return(-1);
    806         }
    807 	comp->maxStep *= 2;
    808 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
    809 		                      comp->maxStep * sizeof(xmlXPathStepOp));
    810 	if (real == NULL) {
    811 	    comp->maxStep /= 2;
    812 	    xmlXPathErrMemory(NULL, "adding step\n");
    813 	    return(-1);
    814 	}
    815 	comp->steps = real;
    816     }
    817     comp->last = comp->nbStep;
    818     comp->steps[comp->nbStep].ch1 = ch1;
    819     comp->steps[comp->nbStep].ch2 = ch2;
    820     comp->steps[comp->nbStep].op = op;
    821     comp->steps[comp->nbStep].value = value;
    822     comp->steps[comp->nbStep].value2 = value2;
    823     comp->steps[comp->nbStep].value3 = value3;
    824     if ((comp->dict != NULL) &&
    825         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
    826 	 (op == XPATH_OP_COLLECT))) {
    827         if (value4 != NULL) {
    828 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
    829 	        (void *)xmlDictLookup(comp->dict, value4, -1);
    830 	    xmlFree(value4);
    831 	} else
    832 	    comp->steps[comp->nbStep].value4 = NULL;
    833         if (value5 != NULL) {
    834 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
    835 	        (void *)xmlDictLookup(comp->dict, value5, -1);
    836 	    xmlFree(value5);
    837 	} else
    838 	    comp->steps[comp->nbStep].value5 = NULL;
    839     } else {
    840 	comp->steps[comp->nbStep].value4 = value4;
    841 	comp->steps[comp->nbStep].value5 = value5;
    842     }
    843     comp->steps[comp->nbStep].cache = NULL;
    844     return(comp->nbStep++);
    845 }
    846 
    847 /**
    848  * xmlXPathCompSwap:
    849  * @comp:  the compiled expression
    850  * @op: operation index
    851  *
    852  * Swaps 2 operations in the compiled expression
    853  */
    854 static void
    855 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
    856     int tmp;
    857 
    858 #ifndef LIBXML_THREAD_ENABLED
    859     /*
    860      * Since this manipulates possibly shared variables, this is
    861      * disabled if one detects that the library is used in a multithreaded
    862      * application
    863      */
    864     if (xmlXPathDisableOptimizer)
    865 	return;
    866 #endif
    867 
    868     tmp = op->ch1;
    869     op->ch1 = op->ch2;
    870     op->ch2 = tmp;
    871 }
    872 
    873 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
    874     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
    875 	                (op), (val), (val2), (val3), (val4), (val5))
    876 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
    877     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
    878 	                (op), (val), (val2), (val3), (val4), (val5))
    879 
    880 #define PUSH_LEAVE_EXPR(op, val, val2)					\
    881 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
    882 
    883 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
    884 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
    885 
    886 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
    887 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
    888 			(val), (val2), 0 ,NULL ,NULL)
    889 
    890 /************************************************************************
    891  *									*
    892  *		XPath object cache structures				*
    893  *									*
    894  ************************************************************************/
    895 
    896 /* #define XP_DEFAULT_CACHE_ON */
    897 
    898 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
    899 
    900 typedef struct _xmlXPathContextCache xmlXPathContextCache;
    901 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
    902 struct _xmlXPathContextCache {
    903     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
    904     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
    905     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
    906     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
    907     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
    908     int maxNodeset;
    909     int maxString;
    910     int maxBoolean;
    911     int maxNumber;
    912     int maxMisc;
    913 #ifdef XP_DEBUG_OBJ_USAGE
    914     int dbgCachedAll;
    915     int dbgCachedNodeset;
    916     int dbgCachedString;
    917     int dbgCachedBool;
    918     int dbgCachedNumber;
    919     int dbgCachedPoint;
    920     int dbgCachedRange;
    921     int dbgCachedLocset;
    922     int dbgCachedUsers;
    923     int dbgCachedXSLTTree;
    924     int dbgCachedUndefined;
    925 
    926 
    927     int dbgReusedAll;
    928     int dbgReusedNodeset;
    929     int dbgReusedString;
    930     int dbgReusedBool;
    931     int dbgReusedNumber;
    932     int dbgReusedPoint;
    933     int dbgReusedRange;
    934     int dbgReusedLocset;
    935     int dbgReusedUsers;
    936     int dbgReusedXSLTTree;
    937     int dbgReusedUndefined;
    938 
    939 #endif
    940 };
    941 
    942 /************************************************************************
    943  *									*
    944  *		Debugging related functions				*
    945  *									*
    946  ************************************************************************/
    947 
    948 #define STRANGE							\
    949     xmlGenericError(xmlGenericErrorContext,				\
    950 	    "Internal error at %s:%d\n",				\
    951             __FILE__, __LINE__);
    952 
    953 #ifdef LIBXML_DEBUG_ENABLED
    954 static void
    955 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
    956     int i;
    957     char shift[100];
    958 
    959     for (i = 0;((i < depth) && (i < 25));i++)
    960         shift[2 * i] = shift[2 * i + 1] = ' ';
    961     shift[2 * i] = shift[2 * i + 1] = 0;
    962     if (cur == NULL) {
    963 	fprintf(output, "%s", shift);
    964 	fprintf(output, "Node is NULL !\n");
    965 	return;
    966 
    967     }
    968 
    969     if ((cur->type == XML_DOCUMENT_NODE) ||
    970 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
    971 	fprintf(output, "%s", shift);
    972 	fprintf(output, " /\n");
    973     } else if (cur->type == XML_ATTRIBUTE_NODE)
    974 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
    975     else
    976 	xmlDebugDumpOneNode(output, cur, depth);
    977 }
    978 static void
    979 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
    980     xmlNodePtr tmp;
    981     int i;
    982     char shift[100];
    983 
    984     for (i = 0;((i < depth) && (i < 25));i++)
    985         shift[2 * i] = shift[2 * i + 1] = ' ';
    986     shift[2 * i] = shift[2 * i + 1] = 0;
    987     if (cur == NULL) {
    988 	fprintf(output, "%s", shift);
    989 	fprintf(output, "Node is NULL !\n");
    990 	return;
    991 
    992     }
    993 
    994     while (cur != NULL) {
    995 	tmp = cur;
    996 	cur = cur->next;
    997 	xmlDebugDumpOneNode(output, tmp, depth);
    998     }
    999 }
   1000 
   1001 static void
   1002 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
   1003     int i;
   1004     char shift[100];
   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     if (cur == NULL) {
   1011 	fprintf(output, "%s", shift);
   1012 	fprintf(output, "NodeSet is NULL !\n");
   1013 	return;
   1014 
   1015     }
   1016 
   1017     if (cur != NULL) {
   1018 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
   1019 	for (i = 0;i < cur->nodeNr;i++) {
   1020 	    fprintf(output, "%s", shift);
   1021 	    fprintf(output, "%d", i + 1);
   1022 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
   1023 	}
   1024     }
   1025 }
   1026 
   1027 static void
   1028 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
   1029     int i;
   1030     char shift[100];
   1031 
   1032     for (i = 0;((i < depth) && (i < 25));i++)
   1033         shift[2 * i] = shift[2 * i + 1] = ' ';
   1034     shift[2 * i] = shift[2 * i + 1] = 0;
   1035 
   1036     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
   1037 	fprintf(output, "%s", shift);
   1038 	fprintf(output, "Value Tree is NULL !\n");
   1039 	return;
   1040 
   1041     }
   1042 
   1043     fprintf(output, "%s", shift);
   1044     fprintf(output, "%d", i + 1);
   1045     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
   1046 }
   1047 #if defined(LIBXML_XPTR_ENABLED)
   1048 static void
   1049 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
   1050     int i;
   1051     char shift[100];
   1052 
   1053     for (i = 0;((i < depth) && (i < 25));i++)
   1054         shift[2 * i] = shift[2 * i + 1] = ' ';
   1055     shift[2 * i] = shift[2 * i + 1] = 0;
   1056 
   1057     if (cur == NULL) {
   1058 	fprintf(output, "%s", shift);
   1059 	fprintf(output, "LocationSet is NULL !\n");
   1060 	return;
   1061 
   1062     }
   1063 
   1064     for (i = 0;i < cur->locNr;i++) {
   1065 	fprintf(output, "%s", shift);
   1066         fprintf(output, "%d : ", i + 1);
   1067 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
   1068     }
   1069 }
   1070 #endif /* LIBXML_XPTR_ENABLED */
   1071 
   1072 /**
   1073  * xmlXPathDebugDumpObject:
   1074  * @output:  the FILE * to dump the output
   1075  * @cur:  the object to inspect
   1076  * @depth:  indentation level
   1077  *
   1078  * Dump the content of the object for debugging purposes
   1079  */
   1080 void
   1081 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1082     int i;
   1083     char shift[100];
   1084 
   1085     if (output == NULL) return;
   1086 
   1087     for (i = 0;((i < depth) && (i < 25));i++)
   1088         shift[2 * i] = shift[2 * i + 1] = ' ';
   1089     shift[2 * i] = shift[2 * i + 1] = 0;
   1090 
   1091 
   1092     fprintf(output, "%s", shift);
   1093 
   1094     if (cur == NULL) {
   1095         fprintf(output, "Object is empty (NULL)\n");
   1096 	return;
   1097     }
   1098     switch(cur->type) {
   1099         case XPATH_UNDEFINED:
   1100 	    fprintf(output, "Object is uninitialized\n");
   1101 	    break;
   1102         case XPATH_NODESET:
   1103 	    fprintf(output, "Object is a Node Set :\n");
   1104 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1105 	    break;
   1106 	case XPATH_XSLT_TREE:
   1107 	    fprintf(output, "Object is an XSLT value tree :\n");
   1108 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1109 	    break;
   1110         case XPATH_BOOLEAN:
   1111 	    fprintf(output, "Object is a Boolean : ");
   1112 	    if (cur->boolval) fprintf(output, "true\n");
   1113 	    else fprintf(output, "false\n");
   1114 	    break;
   1115         case XPATH_NUMBER:
   1116 	    switch (xmlXPathIsInf(cur->floatval)) {
   1117 	    case 1:
   1118 		fprintf(output, "Object is a number : Infinity\n");
   1119 		break;
   1120 	    case -1:
   1121 		fprintf(output, "Object is a number : -Infinity\n");
   1122 		break;
   1123 	    default:
   1124 		if (xmlXPathIsNaN(cur->floatval)) {
   1125 		    fprintf(output, "Object is a number : NaN\n");
   1126 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1127 		    fprintf(output, "Object is a number : 0\n");
   1128 		} else {
   1129 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1130 		}
   1131 	    }
   1132 	    break;
   1133         case XPATH_STRING:
   1134 	    fprintf(output, "Object is a string : ");
   1135 	    xmlDebugDumpString(output, cur->stringval);
   1136 	    fprintf(output, "\n");
   1137 	    break;
   1138 	case XPATH_POINT:
   1139 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1140 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1141 	    fprintf(output, "\n");
   1142 	    break;
   1143 	case XPATH_RANGE:
   1144 	    if ((cur->user2 == NULL) ||
   1145 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1146 		fprintf(output, "Object is a collapsed range :\n");
   1147 		fprintf(output, "%s", shift);
   1148 		if (cur->index >= 0)
   1149 		    fprintf(output, "index %d in ", cur->index);
   1150 		fprintf(output, "node\n");
   1151 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1152 			              depth + 1);
   1153 	    } else  {
   1154 		fprintf(output, "Object is a range :\n");
   1155 		fprintf(output, "%s", shift);
   1156 		fprintf(output, "From ");
   1157 		if (cur->index >= 0)
   1158 		    fprintf(output, "index %d in ", cur->index);
   1159 		fprintf(output, "node\n");
   1160 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1161 			              depth + 1);
   1162 		fprintf(output, "%s", shift);
   1163 		fprintf(output, "To ");
   1164 		if (cur->index2 >= 0)
   1165 		    fprintf(output, "index %d in ", cur->index2);
   1166 		fprintf(output, "node\n");
   1167 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1168 			              depth + 1);
   1169 		fprintf(output, "\n");
   1170 	    }
   1171 	    break;
   1172 	case XPATH_LOCATIONSET:
   1173 #if defined(LIBXML_XPTR_ENABLED)
   1174 	    fprintf(output, "Object is a Location Set:\n");
   1175 	    xmlXPathDebugDumpLocationSet(output,
   1176 		    (xmlLocationSetPtr) cur->user, depth);
   1177 #endif
   1178 	    break;
   1179 	case XPATH_USERS:
   1180 	    fprintf(output, "Object is user defined\n");
   1181 	    break;
   1182     }
   1183 }
   1184 
   1185 static void
   1186 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1187 	                     xmlXPathStepOpPtr op, int depth) {
   1188     int i;
   1189     char shift[100];
   1190 
   1191     for (i = 0;((i < depth) && (i < 25));i++)
   1192         shift[2 * i] = shift[2 * i + 1] = ' ';
   1193     shift[2 * i] = shift[2 * i + 1] = 0;
   1194 
   1195     fprintf(output, "%s", shift);
   1196     if (op == NULL) {
   1197 	fprintf(output, "Step is NULL\n");
   1198 	return;
   1199     }
   1200     switch (op->op) {
   1201         case XPATH_OP_END:
   1202 	    fprintf(output, "END"); break;
   1203         case XPATH_OP_AND:
   1204 	    fprintf(output, "AND"); break;
   1205         case XPATH_OP_OR:
   1206 	    fprintf(output, "OR"); break;
   1207         case XPATH_OP_EQUAL:
   1208 	     if (op->value)
   1209 		 fprintf(output, "EQUAL =");
   1210 	     else
   1211 		 fprintf(output, "EQUAL !=");
   1212 	     break;
   1213         case XPATH_OP_CMP:
   1214 	     if (op->value)
   1215 		 fprintf(output, "CMP <");
   1216 	     else
   1217 		 fprintf(output, "CMP >");
   1218 	     if (!op->value2)
   1219 		 fprintf(output, "=");
   1220 	     break;
   1221         case XPATH_OP_PLUS:
   1222 	     if (op->value == 0)
   1223 		 fprintf(output, "PLUS -");
   1224 	     else if (op->value == 1)
   1225 		 fprintf(output, "PLUS +");
   1226 	     else if (op->value == 2)
   1227 		 fprintf(output, "PLUS unary -");
   1228 	     else if (op->value == 3)
   1229 		 fprintf(output, "PLUS unary - -");
   1230 	     break;
   1231         case XPATH_OP_MULT:
   1232 	     if (op->value == 0)
   1233 		 fprintf(output, "MULT *");
   1234 	     else if (op->value == 1)
   1235 		 fprintf(output, "MULT div");
   1236 	     else
   1237 		 fprintf(output, "MULT mod");
   1238 	     break;
   1239         case XPATH_OP_UNION:
   1240 	     fprintf(output, "UNION"); break;
   1241         case XPATH_OP_ROOT:
   1242 	     fprintf(output, "ROOT"); break;
   1243         case XPATH_OP_NODE:
   1244 	     fprintf(output, "NODE"); break;
   1245         case XPATH_OP_RESET:
   1246 	     fprintf(output, "RESET"); break;
   1247         case XPATH_OP_SORT:
   1248 	     fprintf(output, "SORT"); break;
   1249         case XPATH_OP_COLLECT: {
   1250 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1251 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1252 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1253 	    const xmlChar *prefix = op->value4;
   1254 	    const xmlChar *name = op->value5;
   1255 
   1256 	    fprintf(output, "COLLECT ");
   1257 	    switch (axis) {
   1258 		case AXIS_ANCESTOR:
   1259 		    fprintf(output, " 'ancestors' "); break;
   1260 		case AXIS_ANCESTOR_OR_SELF:
   1261 		    fprintf(output, " 'ancestors-or-self' "); break;
   1262 		case AXIS_ATTRIBUTE:
   1263 		    fprintf(output, " 'attributes' "); break;
   1264 		case AXIS_CHILD:
   1265 		    fprintf(output, " 'child' "); break;
   1266 		case AXIS_DESCENDANT:
   1267 		    fprintf(output, " 'descendant' "); break;
   1268 		case AXIS_DESCENDANT_OR_SELF:
   1269 		    fprintf(output, " 'descendant-or-self' "); break;
   1270 		case AXIS_FOLLOWING:
   1271 		    fprintf(output, " 'following' "); break;
   1272 		case AXIS_FOLLOWING_SIBLING:
   1273 		    fprintf(output, " 'following-siblings' "); break;
   1274 		case AXIS_NAMESPACE:
   1275 		    fprintf(output, " 'namespace' "); break;
   1276 		case AXIS_PARENT:
   1277 		    fprintf(output, " 'parent' "); break;
   1278 		case AXIS_PRECEDING:
   1279 		    fprintf(output, " 'preceding' "); break;
   1280 		case AXIS_PRECEDING_SIBLING:
   1281 		    fprintf(output, " 'preceding-sibling' "); break;
   1282 		case AXIS_SELF:
   1283 		    fprintf(output, " 'self' "); break;
   1284 	    }
   1285 	    switch (test) {
   1286                 case NODE_TEST_NONE:
   1287 		    fprintf(output, "'none' "); break;
   1288                 case NODE_TEST_TYPE:
   1289 		    fprintf(output, "'type' "); break;
   1290                 case NODE_TEST_PI:
   1291 		    fprintf(output, "'PI' "); break;
   1292                 case NODE_TEST_ALL:
   1293 		    fprintf(output, "'all' "); break;
   1294                 case NODE_TEST_NS:
   1295 		    fprintf(output, "'namespace' "); break;
   1296                 case NODE_TEST_NAME:
   1297 		    fprintf(output, "'name' "); break;
   1298 	    }
   1299 	    switch (type) {
   1300                 case NODE_TYPE_NODE:
   1301 		    fprintf(output, "'node' "); break;
   1302                 case NODE_TYPE_COMMENT:
   1303 		    fprintf(output, "'comment' "); break;
   1304                 case NODE_TYPE_TEXT:
   1305 		    fprintf(output, "'text' "); break;
   1306                 case NODE_TYPE_PI:
   1307 		    fprintf(output, "'PI' "); break;
   1308 	    }
   1309 	    if (prefix != NULL)
   1310 		fprintf(output, "%s:", prefix);
   1311 	    if (name != NULL)
   1312 		fprintf(output, "%s", (const char *) name);
   1313 	    break;
   1314 
   1315         }
   1316 	case XPATH_OP_VALUE: {
   1317 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1318 
   1319 	    fprintf(output, "ELEM ");
   1320 	    xmlXPathDebugDumpObject(output, object, 0);
   1321 	    goto finish;
   1322 	}
   1323 	case XPATH_OP_VARIABLE: {
   1324 	    const xmlChar *prefix = op->value5;
   1325 	    const xmlChar *name = op->value4;
   1326 
   1327 	    if (prefix != NULL)
   1328 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1329 	    else
   1330 		fprintf(output, "VARIABLE %s", name);
   1331 	    break;
   1332 	}
   1333 	case XPATH_OP_FUNCTION: {
   1334 	    int nbargs = op->value;
   1335 	    const xmlChar *prefix = op->value5;
   1336 	    const xmlChar *name = op->value4;
   1337 
   1338 	    if (prefix != NULL)
   1339 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1340 			prefix, name, nbargs);
   1341 	    else
   1342 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1343 	    break;
   1344 	}
   1345         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1346         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1347         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1348 #ifdef LIBXML_XPTR_ENABLED
   1349         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1350 #endif
   1351 	default:
   1352         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1353     }
   1354     fprintf(output, "\n");
   1355 finish:
   1356     if (op->ch1 >= 0)
   1357 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1358     if (op->ch2 >= 0)
   1359 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1360 }
   1361 
   1362 /**
   1363  * xmlXPathDebugDumpCompExpr:
   1364  * @output:  the FILE * for the output
   1365  * @comp:  the precompiled XPath expression
   1366  * @depth:  the indentation level.
   1367  *
   1368  * Dumps the tree of the compiled XPath expression.
   1369  */
   1370 void
   1371 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1372 	                  int depth) {
   1373     int i;
   1374     char shift[100];
   1375 
   1376     if ((output == NULL) || (comp == NULL)) return;
   1377 
   1378     for (i = 0;((i < depth) && (i < 25));i++)
   1379         shift[2 * i] = shift[2 * i + 1] = ' ';
   1380     shift[2 * i] = shift[2 * i + 1] = 0;
   1381 
   1382     fprintf(output, "%s", shift);
   1383 
   1384     fprintf(output, "Compiled Expression : %d elements\n",
   1385 	    comp->nbStep);
   1386     i = comp->last;
   1387     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1388 }
   1389 
   1390 #ifdef XP_DEBUG_OBJ_USAGE
   1391 
   1392 /*
   1393 * XPath object usage related debugging variables.
   1394 */
   1395 static int xmlXPathDebugObjCounterUndefined = 0;
   1396 static int xmlXPathDebugObjCounterNodeset = 0;
   1397 static int xmlXPathDebugObjCounterBool = 0;
   1398 static int xmlXPathDebugObjCounterNumber = 0;
   1399 static int xmlXPathDebugObjCounterString = 0;
   1400 static int xmlXPathDebugObjCounterPoint = 0;
   1401 static int xmlXPathDebugObjCounterRange = 0;
   1402 static int xmlXPathDebugObjCounterLocset = 0;
   1403 static int xmlXPathDebugObjCounterUsers = 0;
   1404 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1405 static int xmlXPathDebugObjCounterAll = 0;
   1406 
   1407 static int xmlXPathDebugObjTotalUndefined = 0;
   1408 static int xmlXPathDebugObjTotalNodeset = 0;
   1409 static int xmlXPathDebugObjTotalBool = 0;
   1410 static int xmlXPathDebugObjTotalNumber = 0;
   1411 static int xmlXPathDebugObjTotalString = 0;
   1412 static int xmlXPathDebugObjTotalPoint = 0;
   1413 static int xmlXPathDebugObjTotalRange = 0;
   1414 static int xmlXPathDebugObjTotalLocset = 0;
   1415 static int xmlXPathDebugObjTotalUsers = 0;
   1416 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1417 static int xmlXPathDebugObjTotalAll = 0;
   1418 
   1419 static int xmlXPathDebugObjMaxUndefined = 0;
   1420 static int xmlXPathDebugObjMaxNodeset = 0;
   1421 static int xmlXPathDebugObjMaxBool = 0;
   1422 static int xmlXPathDebugObjMaxNumber = 0;
   1423 static int xmlXPathDebugObjMaxString = 0;
   1424 static int xmlXPathDebugObjMaxPoint = 0;
   1425 static int xmlXPathDebugObjMaxRange = 0;
   1426 static int xmlXPathDebugObjMaxLocset = 0;
   1427 static int xmlXPathDebugObjMaxUsers = 0;
   1428 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1429 static int xmlXPathDebugObjMaxAll = 0;
   1430 
   1431 /* REVISIT TODO: Make this static when committing */
   1432 static void
   1433 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1434 {
   1435     if (ctxt != NULL) {
   1436 	if (ctxt->cache != NULL) {
   1437 	    xmlXPathContextCachePtr cache =
   1438 		(xmlXPathContextCachePtr) ctxt->cache;
   1439 
   1440 	    cache->dbgCachedAll = 0;
   1441 	    cache->dbgCachedNodeset = 0;
   1442 	    cache->dbgCachedString = 0;
   1443 	    cache->dbgCachedBool = 0;
   1444 	    cache->dbgCachedNumber = 0;
   1445 	    cache->dbgCachedPoint = 0;
   1446 	    cache->dbgCachedRange = 0;
   1447 	    cache->dbgCachedLocset = 0;
   1448 	    cache->dbgCachedUsers = 0;
   1449 	    cache->dbgCachedXSLTTree = 0;
   1450 	    cache->dbgCachedUndefined = 0;
   1451 
   1452 	    cache->dbgReusedAll = 0;
   1453 	    cache->dbgReusedNodeset = 0;
   1454 	    cache->dbgReusedString = 0;
   1455 	    cache->dbgReusedBool = 0;
   1456 	    cache->dbgReusedNumber = 0;
   1457 	    cache->dbgReusedPoint = 0;
   1458 	    cache->dbgReusedRange = 0;
   1459 	    cache->dbgReusedLocset = 0;
   1460 	    cache->dbgReusedUsers = 0;
   1461 	    cache->dbgReusedXSLTTree = 0;
   1462 	    cache->dbgReusedUndefined = 0;
   1463 	}
   1464     }
   1465 
   1466     xmlXPathDebugObjCounterUndefined = 0;
   1467     xmlXPathDebugObjCounterNodeset = 0;
   1468     xmlXPathDebugObjCounterBool = 0;
   1469     xmlXPathDebugObjCounterNumber = 0;
   1470     xmlXPathDebugObjCounterString = 0;
   1471     xmlXPathDebugObjCounterPoint = 0;
   1472     xmlXPathDebugObjCounterRange = 0;
   1473     xmlXPathDebugObjCounterLocset = 0;
   1474     xmlXPathDebugObjCounterUsers = 0;
   1475     xmlXPathDebugObjCounterXSLTTree = 0;
   1476     xmlXPathDebugObjCounterAll = 0;
   1477 
   1478     xmlXPathDebugObjTotalUndefined = 0;
   1479     xmlXPathDebugObjTotalNodeset = 0;
   1480     xmlXPathDebugObjTotalBool = 0;
   1481     xmlXPathDebugObjTotalNumber = 0;
   1482     xmlXPathDebugObjTotalString = 0;
   1483     xmlXPathDebugObjTotalPoint = 0;
   1484     xmlXPathDebugObjTotalRange = 0;
   1485     xmlXPathDebugObjTotalLocset = 0;
   1486     xmlXPathDebugObjTotalUsers = 0;
   1487     xmlXPathDebugObjTotalXSLTTree = 0;
   1488     xmlXPathDebugObjTotalAll = 0;
   1489 
   1490     xmlXPathDebugObjMaxUndefined = 0;
   1491     xmlXPathDebugObjMaxNodeset = 0;
   1492     xmlXPathDebugObjMaxBool = 0;
   1493     xmlXPathDebugObjMaxNumber = 0;
   1494     xmlXPathDebugObjMaxString = 0;
   1495     xmlXPathDebugObjMaxPoint = 0;
   1496     xmlXPathDebugObjMaxRange = 0;
   1497     xmlXPathDebugObjMaxLocset = 0;
   1498     xmlXPathDebugObjMaxUsers = 0;
   1499     xmlXPathDebugObjMaxXSLTTree = 0;
   1500     xmlXPathDebugObjMaxAll = 0;
   1501 
   1502 }
   1503 
   1504 static void
   1505 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1506 			      xmlXPathObjectType objType)
   1507 {
   1508     int isCached = 0;
   1509 
   1510     if (ctxt != NULL) {
   1511 	if (ctxt->cache != NULL) {
   1512 	    xmlXPathContextCachePtr cache =
   1513 		(xmlXPathContextCachePtr) ctxt->cache;
   1514 
   1515 	    isCached = 1;
   1516 
   1517 	    cache->dbgReusedAll++;
   1518 	    switch (objType) {
   1519 		case XPATH_UNDEFINED:
   1520 		    cache->dbgReusedUndefined++;
   1521 		    break;
   1522 		case XPATH_NODESET:
   1523 		    cache->dbgReusedNodeset++;
   1524 		    break;
   1525 		case XPATH_BOOLEAN:
   1526 		    cache->dbgReusedBool++;
   1527 		    break;
   1528 		case XPATH_NUMBER:
   1529 		    cache->dbgReusedNumber++;
   1530 		    break;
   1531 		case XPATH_STRING:
   1532 		    cache->dbgReusedString++;
   1533 		    break;
   1534 		case XPATH_POINT:
   1535 		    cache->dbgReusedPoint++;
   1536 		    break;
   1537 		case XPATH_RANGE:
   1538 		    cache->dbgReusedRange++;
   1539 		    break;
   1540 		case XPATH_LOCATIONSET:
   1541 		    cache->dbgReusedLocset++;
   1542 		    break;
   1543 		case XPATH_USERS:
   1544 		    cache->dbgReusedUsers++;
   1545 		    break;
   1546 		case XPATH_XSLT_TREE:
   1547 		    cache->dbgReusedXSLTTree++;
   1548 		    break;
   1549 		default:
   1550 		    break;
   1551 	    }
   1552 	}
   1553     }
   1554 
   1555     switch (objType) {
   1556 	case XPATH_UNDEFINED:
   1557 	    if (! isCached)
   1558 		xmlXPathDebugObjTotalUndefined++;
   1559 	    xmlXPathDebugObjCounterUndefined++;
   1560 	    if (xmlXPathDebugObjCounterUndefined >
   1561 		xmlXPathDebugObjMaxUndefined)
   1562 		xmlXPathDebugObjMaxUndefined =
   1563 		    xmlXPathDebugObjCounterUndefined;
   1564 	    break;
   1565 	case XPATH_NODESET:
   1566 	    if (! isCached)
   1567 		xmlXPathDebugObjTotalNodeset++;
   1568 	    xmlXPathDebugObjCounterNodeset++;
   1569 	    if (xmlXPathDebugObjCounterNodeset >
   1570 		xmlXPathDebugObjMaxNodeset)
   1571 		xmlXPathDebugObjMaxNodeset =
   1572 		    xmlXPathDebugObjCounterNodeset;
   1573 	    break;
   1574 	case XPATH_BOOLEAN:
   1575 	    if (! isCached)
   1576 		xmlXPathDebugObjTotalBool++;
   1577 	    xmlXPathDebugObjCounterBool++;
   1578 	    if (xmlXPathDebugObjCounterBool >
   1579 		xmlXPathDebugObjMaxBool)
   1580 		xmlXPathDebugObjMaxBool =
   1581 		    xmlXPathDebugObjCounterBool;
   1582 	    break;
   1583 	case XPATH_NUMBER:
   1584 	    if (! isCached)
   1585 		xmlXPathDebugObjTotalNumber++;
   1586 	    xmlXPathDebugObjCounterNumber++;
   1587 	    if (xmlXPathDebugObjCounterNumber >
   1588 		xmlXPathDebugObjMaxNumber)
   1589 		xmlXPathDebugObjMaxNumber =
   1590 		    xmlXPathDebugObjCounterNumber;
   1591 	    break;
   1592 	case XPATH_STRING:
   1593 	    if (! isCached)
   1594 		xmlXPathDebugObjTotalString++;
   1595 	    xmlXPathDebugObjCounterString++;
   1596 	    if (xmlXPathDebugObjCounterString >
   1597 		xmlXPathDebugObjMaxString)
   1598 		xmlXPathDebugObjMaxString =
   1599 		    xmlXPathDebugObjCounterString;
   1600 	    break;
   1601 	case XPATH_POINT:
   1602 	    if (! isCached)
   1603 		xmlXPathDebugObjTotalPoint++;
   1604 	    xmlXPathDebugObjCounterPoint++;
   1605 	    if (xmlXPathDebugObjCounterPoint >
   1606 		xmlXPathDebugObjMaxPoint)
   1607 		xmlXPathDebugObjMaxPoint =
   1608 		    xmlXPathDebugObjCounterPoint;
   1609 	    break;
   1610 	case XPATH_RANGE:
   1611 	    if (! isCached)
   1612 		xmlXPathDebugObjTotalRange++;
   1613 	    xmlXPathDebugObjCounterRange++;
   1614 	    if (xmlXPathDebugObjCounterRange >
   1615 		xmlXPathDebugObjMaxRange)
   1616 		xmlXPathDebugObjMaxRange =
   1617 		    xmlXPathDebugObjCounterRange;
   1618 	    break;
   1619 	case XPATH_LOCATIONSET:
   1620 	    if (! isCached)
   1621 		xmlXPathDebugObjTotalLocset++;
   1622 	    xmlXPathDebugObjCounterLocset++;
   1623 	    if (xmlXPathDebugObjCounterLocset >
   1624 		xmlXPathDebugObjMaxLocset)
   1625 		xmlXPathDebugObjMaxLocset =
   1626 		    xmlXPathDebugObjCounterLocset;
   1627 	    break;
   1628 	case XPATH_USERS:
   1629 	    if (! isCached)
   1630 		xmlXPathDebugObjTotalUsers++;
   1631 	    xmlXPathDebugObjCounterUsers++;
   1632 	    if (xmlXPathDebugObjCounterUsers >
   1633 		xmlXPathDebugObjMaxUsers)
   1634 		xmlXPathDebugObjMaxUsers =
   1635 		    xmlXPathDebugObjCounterUsers;
   1636 	    break;
   1637 	case XPATH_XSLT_TREE:
   1638 	    if (! isCached)
   1639 		xmlXPathDebugObjTotalXSLTTree++;
   1640 	    xmlXPathDebugObjCounterXSLTTree++;
   1641 	    if (xmlXPathDebugObjCounterXSLTTree >
   1642 		xmlXPathDebugObjMaxXSLTTree)
   1643 		xmlXPathDebugObjMaxXSLTTree =
   1644 		    xmlXPathDebugObjCounterXSLTTree;
   1645 	    break;
   1646 	default:
   1647 	    break;
   1648     }
   1649     if (! isCached)
   1650 	xmlXPathDebugObjTotalAll++;
   1651     xmlXPathDebugObjCounterAll++;
   1652     if (xmlXPathDebugObjCounterAll >
   1653 	xmlXPathDebugObjMaxAll)
   1654 	xmlXPathDebugObjMaxAll =
   1655 	    xmlXPathDebugObjCounterAll;
   1656 }
   1657 
   1658 static void
   1659 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1660 			      xmlXPathObjectType objType)
   1661 {
   1662     int isCached = 0;
   1663 
   1664     if (ctxt != NULL) {
   1665 	if (ctxt->cache != NULL) {
   1666 	    xmlXPathContextCachePtr cache =
   1667 		(xmlXPathContextCachePtr) ctxt->cache;
   1668 
   1669 	    isCached = 1;
   1670 
   1671 	    cache->dbgCachedAll++;
   1672 	    switch (objType) {
   1673 		case XPATH_UNDEFINED:
   1674 		    cache->dbgCachedUndefined++;
   1675 		    break;
   1676 		case XPATH_NODESET:
   1677 		    cache->dbgCachedNodeset++;
   1678 		    break;
   1679 		case XPATH_BOOLEAN:
   1680 		    cache->dbgCachedBool++;
   1681 		    break;
   1682 		case XPATH_NUMBER:
   1683 		    cache->dbgCachedNumber++;
   1684 		    break;
   1685 		case XPATH_STRING:
   1686 		    cache->dbgCachedString++;
   1687 		    break;
   1688 		case XPATH_POINT:
   1689 		    cache->dbgCachedPoint++;
   1690 		    break;
   1691 		case XPATH_RANGE:
   1692 		    cache->dbgCachedRange++;
   1693 		    break;
   1694 		case XPATH_LOCATIONSET:
   1695 		    cache->dbgCachedLocset++;
   1696 		    break;
   1697 		case XPATH_USERS:
   1698 		    cache->dbgCachedUsers++;
   1699 		    break;
   1700 		case XPATH_XSLT_TREE:
   1701 		    cache->dbgCachedXSLTTree++;
   1702 		    break;
   1703 		default:
   1704 		    break;
   1705 	    }
   1706 
   1707 	}
   1708     }
   1709     switch (objType) {
   1710 	case XPATH_UNDEFINED:
   1711 	    xmlXPathDebugObjCounterUndefined--;
   1712 	    break;
   1713 	case XPATH_NODESET:
   1714 	    xmlXPathDebugObjCounterNodeset--;
   1715 	    break;
   1716 	case XPATH_BOOLEAN:
   1717 	    xmlXPathDebugObjCounterBool--;
   1718 	    break;
   1719 	case XPATH_NUMBER:
   1720 	    xmlXPathDebugObjCounterNumber--;
   1721 	    break;
   1722 	case XPATH_STRING:
   1723 	    xmlXPathDebugObjCounterString--;
   1724 	    break;
   1725 	case XPATH_POINT:
   1726 	    xmlXPathDebugObjCounterPoint--;
   1727 	    break;
   1728 	case XPATH_RANGE:
   1729 	    xmlXPathDebugObjCounterRange--;
   1730 	    break;
   1731 	case XPATH_LOCATIONSET:
   1732 	    xmlXPathDebugObjCounterLocset--;
   1733 	    break;
   1734 	case XPATH_USERS:
   1735 	    xmlXPathDebugObjCounterUsers--;
   1736 	    break;
   1737 	case XPATH_XSLT_TREE:
   1738 	    xmlXPathDebugObjCounterXSLTTree--;
   1739 	    break;
   1740 	default:
   1741 	    break;
   1742     }
   1743     xmlXPathDebugObjCounterAll--;
   1744 }
   1745 
   1746 /* REVISIT TODO: Make this static when committing */
   1747 static void
   1748 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   1749 {
   1750     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   1751 	reqXSLTTree, reqUndefined;
   1752     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   1753 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   1754     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   1755 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   1756     int leftObjs = xmlXPathDebugObjCounterAll;
   1757 
   1758     reqAll = xmlXPathDebugObjTotalAll;
   1759     reqNodeset = xmlXPathDebugObjTotalNodeset;
   1760     reqString = xmlXPathDebugObjTotalString;
   1761     reqBool = xmlXPathDebugObjTotalBool;
   1762     reqNumber = xmlXPathDebugObjTotalNumber;
   1763     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   1764     reqUndefined = xmlXPathDebugObjTotalUndefined;
   1765 
   1766     printf("# XPath object usage:\n");
   1767 
   1768     if (ctxt != NULL) {
   1769 	if (ctxt->cache != NULL) {
   1770 	    xmlXPathContextCachePtr cache =
   1771 		(xmlXPathContextCachePtr) ctxt->cache;
   1772 
   1773 	    reAll = cache->dbgReusedAll;
   1774 	    reqAll += reAll;
   1775 	    reNodeset = cache->dbgReusedNodeset;
   1776 	    reqNodeset += reNodeset;
   1777 	    reString = cache->dbgReusedString;
   1778 	    reqString += reString;
   1779 	    reBool = cache->dbgReusedBool;
   1780 	    reqBool += reBool;
   1781 	    reNumber = cache->dbgReusedNumber;
   1782 	    reqNumber += reNumber;
   1783 	    reXSLTTree = cache->dbgReusedXSLTTree;
   1784 	    reqXSLTTree += reXSLTTree;
   1785 	    reUndefined = cache->dbgReusedUndefined;
   1786 	    reqUndefined += reUndefined;
   1787 
   1788 	    caAll = cache->dbgCachedAll;
   1789 	    caBool = cache->dbgCachedBool;
   1790 	    caNodeset = cache->dbgCachedNodeset;
   1791 	    caString = cache->dbgCachedString;
   1792 	    caNumber = cache->dbgCachedNumber;
   1793 	    caXSLTTree = cache->dbgCachedXSLTTree;
   1794 	    caUndefined = cache->dbgCachedUndefined;
   1795 
   1796 	    if (cache->nodesetObjs)
   1797 		leftObjs -= cache->nodesetObjs->number;
   1798 	    if (cache->stringObjs)
   1799 		leftObjs -= cache->stringObjs->number;
   1800 	    if (cache->booleanObjs)
   1801 		leftObjs -= cache->booleanObjs->number;
   1802 	    if (cache->numberObjs)
   1803 		leftObjs -= cache->numberObjs->number;
   1804 	    if (cache->miscObjs)
   1805 		leftObjs -= cache->miscObjs->number;
   1806 	}
   1807     }
   1808 
   1809     printf("# all\n");
   1810     printf("#   total  : %d\n", reqAll);
   1811     printf("#   left  : %d\n", leftObjs);
   1812     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   1813     printf("#   reused : %d\n", reAll);
   1814     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   1815 
   1816     printf("# node-sets\n");
   1817     printf("#   total  : %d\n", reqNodeset);
   1818     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   1819     printf("#   reused : %d\n", reNodeset);
   1820     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   1821 
   1822     printf("# strings\n");
   1823     printf("#   total  : %d\n", reqString);
   1824     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   1825     printf("#   reused : %d\n", reString);
   1826     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   1827 
   1828     printf("# booleans\n");
   1829     printf("#   total  : %d\n", reqBool);
   1830     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   1831     printf("#   reused : %d\n", reBool);
   1832     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   1833 
   1834     printf("# numbers\n");
   1835     printf("#   total  : %d\n", reqNumber);
   1836     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   1837     printf("#   reused : %d\n", reNumber);
   1838     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   1839 
   1840     printf("# XSLT result tree fragments\n");
   1841     printf("#   total  : %d\n", reqXSLTTree);
   1842     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   1843     printf("#   reused : %d\n", reXSLTTree);
   1844     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   1845 
   1846     printf("# undefined\n");
   1847     printf("#   total  : %d\n", reqUndefined);
   1848     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   1849     printf("#   reused : %d\n", reUndefined);
   1850     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   1851 
   1852 }
   1853 
   1854 #endif /* XP_DEBUG_OBJ_USAGE */
   1855 
   1856 #endif /* LIBXML_DEBUG_ENABLED */
   1857 
   1858 /************************************************************************
   1859  *									*
   1860  *			XPath object caching				*
   1861  *									*
   1862  ************************************************************************/
   1863 
   1864 /**
   1865  * xmlXPathNewCache:
   1866  *
   1867  * Create a new object cache
   1868  *
   1869  * Returns the xmlXPathCache just allocated.
   1870  */
   1871 static xmlXPathContextCachePtr
   1872 xmlXPathNewCache(void)
   1873 {
   1874     xmlXPathContextCachePtr ret;
   1875 
   1876     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   1877     if (ret == NULL) {
   1878         xmlXPathErrMemory(NULL, "creating object cache\n");
   1879 	return(NULL);
   1880     }
   1881     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   1882     ret->maxNodeset = 100;
   1883     ret->maxString = 100;
   1884     ret->maxBoolean = 100;
   1885     ret->maxNumber = 100;
   1886     ret->maxMisc = 100;
   1887     return(ret);
   1888 }
   1889 
   1890 static void
   1891 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   1892 {
   1893     int i;
   1894     xmlXPathObjectPtr obj;
   1895 
   1896     if (list == NULL)
   1897 	return;
   1898 
   1899     for (i = 0; i < list->number; i++) {
   1900 	obj = list->items[i];
   1901 	/*
   1902 	* Note that it is already assured that we don't need to
   1903 	* look out for namespace nodes in the node-set.
   1904 	*/
   1905 	if (obj->nodesetval != NULL) {
   1906 	    if (obj->nodesetval->nodeTab != NULL)
   1907 		xmlFree(obj->nodesetval->nodeTab);
   1908 	    xmlFree(obj->nodesetval);
   1909 	}
   1910 	xmlFree(obj);
   1911 #ifdef XP_DEBUG_OBJ_USAGE
   1912 	xmlXPathDebugObjCounterAll--;
   1913 #endif
   1914     }
   1915     xmlPointerListFree(list);
   1916 }
   1917 
   1918 static void
   1919 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   1920 {
   1921     if (cache == NULL)
   1922 	return;
   1923     if (cache->nodesetObjs)
   1924 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   1925     if (cache->stringObjs)
   1926 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   1927     if (cache->booleanObjs)
   1928 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   1929     if (cache->numberObjs)
   1930 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   1931     if (cache->miscObjs)
   1932 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   1933     xmlFree(cache);
   1934 }
   1935 
   1936 /**
   1937  * xmlXPathContextSetCache:
   1938  *
   1939  * @ctxt:  the XPath context
   1940  * @active: enables/disables (creates/frees) the cache
   1941  * @value: a value with semantics dependant on @options
   1942  * @options: options (currently only the value 0 is used)
   1943  *
   1944  * Creates/frees an object cache on the XPath context.
   1945  * If activates XPath objects (xmlXPathObject) will be cached internally
   1946  * to be reused.
   1947  * @options:
   1948  *   0: This will set the XPath object caching:
   1949  *      @value:
   1950  *        This will set the maximum number of XPath objects
   1951  *        to be cached per slot
   1952  *        There are 5 slots for: node-set, string, number, boolean, and
   1953  *        misc objects. Use <0 for the default number (100).
   1954  *   Other values for @options have currently no effect.
   1955  *
   1956  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   1957  */
   1958 int
   1959 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   1960 			int active,
   1961 			int value,
   1962 			int options)
   1963 {
   1964     if (ctxt == NULL)
   1965 	return(-1);
   1966     if (active) {
   1967 	xmlXPathContextCachePtr cache;
   1968 
   1969 	if (ctxt->cache == NULL) {
   1970 	    ctxt->cache = xmlXPathNewCache();
   1971 	    if (ctxt->cache == NULL)
   1972 		return(-1);
   1973 	}
   1974 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   1975 	if (options == 0) {
   1976 	    if (value < 0)
   1977 		value = 100;
   1978 	    cache->maxNodeset = value;
   1979 	    cache->maxString = value;
   1980 	    cache->maxNumber = value;
   1981 	    cache->maxBoolean = value;
   1982 	    cache->maxMisc = value;
   1983 	}
   1984     } else if (ctxt->cache != NULL) {
   1985 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   1986 	ctxt->cache = NULL;
   1987     }
   1988     return(0);
   1989 }
   1990 
   1991 /**
   1992  * xmlXPathCacheWrapNodeSet:
   1993  * @ctxt: the XPath context
   1994  * @val:  the NodePtr value
   1995  *
   1996  * This is the cached version of xmlXPathWrapNodeSet().
   1997  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   1998  *
   1999  * Returns the created or reused object.
   2000  */
   2001 static xmlXPathObjectPtr
   2002 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   2003 {
   2004     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2005 	xmlXPathContextCachePtr cache =
   2006 	    (xmlXPathContextCachePtr) ctxt->cache;
   2007 
   2008 	if ((cache->miscObjs != NULL) &&
   2009 	    (cache->miscObjs->number != 0))
   2010 	{
   2011 	    xmlXPathObjectPtr ret;
   2012 
   2013 	    ret = (xmlXPathObjectPtr)
   2014 		cache->miscObjs->items[--cache->miscObjs->number];
   2015 	    ret->type = XPATH_NODESET;
   2016 	    ret->nodesetval = val;
   2017 #ifdef XP_DEBUG_OBJ_USAGE
   2018 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2019 #endif
   2020 	    return(ret);
   2021 	}
   2022     }
   2023 
   2024     return(xmlXPathWrapNodeSet(val));
   2025 
   2026 }
   2027 
   2028 /**
   2029  * xmlXPathCacheWrapString:
   2030  * @ctxt: the XPath context
   2031  * @val:  the xmlChar * value
   2032  *
   2033  * This is the cached version of xmlXPathWrapString().
   2034  * Wraps the @val string into an XPath object.
   2035  *
   2036  * Returns the created or reused object.
   2037  */
   2038 static xmlXPathObjectPtr
   2039 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   2040 {
   2041     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2042 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2043 
   2044 	if ((cache->stringObjs != NULL) &&
   2045 	    (cache->stringObjs->number != 0))
   2046 	{
   2047 
   2048 	    xmlXPathObjectPtr ret;
   2049 
   2050 	    ret = (xmlXPathObjectPtr)
   2051 		cache->stringObjs->items[--cache->stringObjs->number];
   2052 	    ret->type = XPATH_STRING;
   2053 	    ret->stringval = val;
   2054 #ifdef XP_DEBUG_OBJ_USAGE
   2055 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2056 #endif
   2057 	    return(ret);
   2058 	} else if ((cache->miscObjs != NULL) &&
   2059 	    (cache->miscObjs->number != 0))
   2060 	{
   2061 	    xmlXPathObjectPtr ret;
   2062 	    /*
   2063 	    * Fallback to misc-cache.
   2064 	    */
   2065 	    ret = (xmlXPathObjectPtr)
   2066 		cache->miscObjs->items[--cache->miscObjs->number];
   2067 
   2068 	    ret->type = XPATH_STRING;
   2069 	    ret->stringval = val;
   2070 #ifdef XP_DEBUG_OBJ_USAGE
   2071 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2072 #endif
   2073 	    return(ret);
   2074 	}
   2075     }
   2076     return(xmlXPathWrapString(val));
   2077 }
   2078 
   2079 /**
   2080  * xmlXPathCacheNewNodeSet:
   2081  * @ctxt: the XPath context
   2082  * @val:  the NodePtr value
   2083  *
   2084  * This is the cached version of xmlXPathNewNodeSet().
   2085  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2086  * it with the single Node @val
   2087  *
   2088  * Returns the created or reused object.
   2089  */
   2090 static xmlXPathObjectPtr
   2091 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2092 {
   2093     if ((ctxt != NULL) && (ctxt->cache)) {
   2094 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2095 
   2096 	if ((cache->nodesetObjs != NULL) &&
   2097 	    (cache->nodesetObjs->number != 0))
   2098 	{
   2099 	    xmlXPathObjectPtr ret;
   2100 	    /*
   2101 	    * Use the nodset-cache.
   2102 	    */
   2103 	    ret = (xmlXPathObjectPtr)
   2104 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2105 	    ret->type = XPATH_NODESET;
   2106 	    ret->boolval = 0;
   2107 	    if (val) {
   2108 		if ((ret->nodesetval->nodeMax == 0) ||
   2109 		    (val->type == XML_NAMESPACE_DECL))
   2110 		{
   2111 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2112 		} else {
   2113 		    ret->nodesetval->nodeTab[0] = val;
   2114 		    ret->nodesetval->nodeNr = 1;
   2115 		}
   2116 	    }
   2117 #ifdef XP_DEBUG_OBJ_USAGE
   2118 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2119 #endif
   2120 	    return(ret);
   2121 	} else if ((cache->miscObjs != NULL) &&
   2122 	    (cache->miscObjs->number != 0))
   2123 	{
   2124 	    xmlXPathObjectPtr ret;
   2125 	    /*
   2126 	    * Fallback to misc-cache.
   2127 	    */
   2128 
   2129 	    ret = (xmlXPathObjectPtr)
   2130 		cache->miscObjs->items[--cache->miscObjs->number];
   2131 
   2132 	    ret->type = XPATH_NODESET;
   2133 	    ret->boolval = 0;
   2134 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2135 	    if (ret->nodesetval == NULL) {
   2136 		ctxt->lastError.domain = XML_FROM_XPATH;
   2137 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
   2138 		return(NULL);
   2139 	    }
   2140 #ifdef XP_DEBUG_OBJ_USAGE
   2141 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2142 #endif
   2143 	    return(ret);
   2144 	}
   2145     }
   2146     return(xmlXPathNewNodeSet(val));
   2147 }
   2148 
   2149 /**
   2150  * xmlXPathCacheNewCString:
   2151  * @ctxt: the XPath context
   2152  * @val:  the char * value
   2153  *
   2154  * This is the cached version of xmlXPathNewCString().
   2155  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2156  *
   2157  * Returns the created or reused object.
   2158  */
   2159 static xmlXPathObjectPtr
   2160 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2161 {
   2162     if ((ctxt != NULL) && (ctxt->cache)) {
   2163 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2164 
   2165 	if ((cache->stringObjs != NULL) &&
   2166 	    (cache->stringObjs->number != 0))
   2167 	{
   2168 	    xmlXPathObjectPtr ret;
   2169 
   2170 	    ret = (xmlXPathObjectPtr)
   2171 		cache->stringObjs->items[--cache->stringObjs->number];
   2172 
   2173 	    ret->type = XPATH_STRING;
   2174 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2175 #ifdef XP_DEBUG_OBJ_USAGE
   2176 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2177 #endif
   2178 	    return(ret);
   2179 	} else if ((cache->miscObjs != NULL) &&
   2180 	    (cache->miscObjs->number != 0))
   2181 	{
   2182 	    xmlXPathObjectPtr ret;
   2183 
   2184 	    ret = (xmlXPathObjectPtr)
   2185 		cache->miscObjs->items[--cache->miscObjs->number];
   2186 
   2187 	    ret->type = XPATH_STRING;
   2188 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2189 #ifdef XP_DEBUG_OBJ_USAGE
   2190 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2191 #endif
   2192 	    return(ret);
   2193 	}
   2194     }
   2195     return(xmlXPathNewCString(val));
   2196 }
   2197 
   2198 /**
   2199  * xmlXPathCacheNewString:
   2200  * @ctxt: the XPath context
   2201  * @val:  the xmlChar * value
   2202  *
   2203  * This is the cached version of xmlXPathNewString().
   2204  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2205  *
   2206  * Returns the created or reused object.
   2207  */
   2208 static xmlXPathObjectPtr
   2209 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2210 {
   2211     if ((ctxt != NULL) && (ctxt->cache)) {
   2212 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2213 
   2214 	if ((cache->stringObjs != NULL) &&
   2215 	    (cache->stringObjs->number != 0))
   2216 	{
   2217 	    xmlXPathObjectPtr ret;
   2218 
   2219 	    ret = (xmlXPathObjectPtr)
   2220 		cache->stringObjs->items[--cache->stringObjs->number];
   2221 	    ret->type = XPATH_STRING;
   2222 	    if (val != NULL)
   2223 		ret->stringval = xmlStrdup(val);
   2224 	    else
   2225 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2226 #ifdef XP_DEBUG_OBJ_USAGE
   2227 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2228 #endif
   2229 	    return(ret);
   2230 	} else if ((cache->miscObjs != NULL) &&
   2231 	    (cache->miscObjs->number != 0))
   2232 	{
   2233 	    xmlXPathObjectPtr ret;
   2234 
   2235 	    ret = (xmlXPathObjectPtr)
   2236 		cache->miscObjs->items[--cache->miscObjs->number];
   2237 
   2238 	    ret->type = XPATH_STRING;
   2239 	    if (val != NULL)
   2240 		ret->stringval = xmlStrdup(val);
   2241 	    else
   2242 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2243 #ifdef XP_DEBUG_OBJ_USAGE
   2244 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2245 #endif
   2246 	    return(ret);
   2247 	}
   2248     }
   2249     return(xmlXPathNewString(val));
   2250 }
   2251 
   2252 /**
   2253  * xmlXPathCacheNewBoolean:
   2254  * @ctxt: the XPath context
   2255  * @val:  the boolean value
   2256  *
   2257  * This is the cached version of xmlXPathNewBoolean().
   2258  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2259  *
   2260  * Returns the created or reused object.
   2261  */
   2262 static xmlXPathObjectPtr
   2263 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2264 {
   2265     if ((ctxt != NULL) && (ctxt->cache)) {
   2266 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2267 
   2268 	if ((cache->booleanObjs != NULL) &&
   2269 	    (cache->booleanObjs->number != 0))
   2270 	{
   2271 	    xmlXPathObjectPtr ret;
   2272 
   2273 	    ret = (xmlXPathObjectPtr)
   2274 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2275 	    ret->type = XPATH_BOOLEAN;
   2276 	    ret->boolval = (val != 0);
   2277 #ifdef XP_DEBUG_OBJ_USAGE
   2278 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2279 #endif
   2280 	    return(ret);
   2281 	} else if ((cache->miscObjs != NULL) &&
   2282 	    (cache->miscObjs->number != 0))
   2283 	{
   2284 	    xmlXPathObjectPtr ret;
   2285 
   2286 	    ret = (xmlXPathObjectPtr)
   2287 		cache->miscObjs->items[--cache->miscObjs->number];
   2288 
   2289 	    ret->type = XPATH_BOOLEAN;
   2290 	    ret->boolval = (val != 0);
   2291 #ifdef XP_DEBUG_OBJ_USAGE
   2292 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2293 #endif
   2294 	    return(ret);
   2295 	}
   2296     }
   2297     return(xmlXPathNewBoolean(val));
   2298 }
   2299 
   2300 /**
   2301  * xmlXPathCacheNewFloat:
   2302  * @ctxt: the XPath context
   2303  * @val:  the double value
   2304  *
   2305  * This is the cached version of xmlXPathNewFloat().
   2306  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2307  *
   2308  * Returns the created or reused object.
   2309  */
   2310 static xmlXPathObjectPtr
   2311 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2312 {
   2313      if ((ctxt != NULL) && (ctxt->cache)) {
   2314 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2315 
   2316 	if ((cache->numberObjs != NULL) &&
   2317 	    (cache->numberObjs->number != 0))
   2318 	{
   2319 	    xmlXPathObjectPtr ret;
   2320 
   2321 	    ret = (xmlXPathObjectPtr)
   2322 		cache->numberObjs->items[--cache->numberObjs->number];
   2323 	    ret->type = XPATH_NUMBER;
   2324 	    ret->floatval = val;
   2325 #ifdef XP_DEBUG_OBJ_USAGE
   2326 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2327 #endif
   2328 	    return(ret);
   2329 	} else if ((cache->miscObjs != NULL) &&
   2330 	    (cache->miscObjs->number != 0))
   2331 	{
   2332 	    xmlXPathObjectPtr ret;
   2333 
   2334 	    ret = (xmlXPathObjectPtr)
   2335 		cache->miscObjs->items[--cache->miscObjs->number];
   2336 
   2337 	    ret->type = XPATH_NUMBER;
   2338 	    ret->floatval = val;
   2339 #ifdef XP_DEBUG_OBJ_USAGE
   2340 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2341 #endif
   2342 	    return(ret);
   2343 	}
   2344     }
   2345     return(xmlXPathNewFloat(val));
   2346 }
   2347 
   2348 /**
   2349  * xmlXPathCacheConvertString:
   2350  * @ctxt: the XPath context
   2351  * @val:  an XPath object
   2352  *
   2353  * This is the cached version of xmlXPathConvertString().
   2354  * Converts an existing object to its string() equivalent
   2355  *
   2356  * Returns a created or reused object, the old one is freed (cached)
   2357  *         (or the operation is done directly on @val)
   2358  */
   2359 
   2360 static xmlXPathObjectPtr
   2361 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2362     xmlChar *res = NULL;
   2363 
   2364     if (val == NULL)
   2365 	return(xmlXPathCacheNewCString(ctxt, ""));
   2366 
   2367     switch (val->type) {
   2368     case XPATH_UNDEFINED:
   2369 #ifdef DEBUG_EXPR
   2370 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2371 #endif
   2372 	break;
   2373     case XPATH_NODESET:
   2374     case XPATH_XSLT_TREE:
   2375 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2376 	break;
   2377     case XPATH_STRING:
   2378 	return(val);
   2379     case XPATH_BOOLEAN:
   2380 	res = xmlXPathCastBooleanToString(val->boolval);
   2381 	break;
   2382     case XPATH_NUMBER:
   2383 	res = xmlXPathCastNumberToString(val->floatval);
   2384 	break;
   2385     case XPATH_USERS:
   2386     case XPATH_POINT:
   2387     case XPATH_RANGE:
   2388     case XPATH_LOCATIONSET:
   2389 	TODO;
   2390 	break;
   2391     }
   2392     xmlXPathReleaseObject(ctxt, val);
   2393     if (res == NULL)
   2394 	return(xmlXPathCacheNewCString(ctxt, ""));
   2395     return(xmlXPathCacheWrapString(ctxt, res));
   2396 }
   2397 
   2398 /**
   2399  * xmlXPathCacheObjectCopy:
   2400  * @ctxt: the XPath context
   2401  * @val:  the original object
   2402  *
   2403  * This is the cached version of xmlXPathObjectCopy().
   2404  * Acquire a copy of a given object
   2405  *
   2406  * Returns a created or reused created object.
   2407  */
   2408 static xmlXPathObjectPtr
   2409 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2410 {
   2411     if (val == NULL)
   2412 	return(NULL);
   2413 
   2414     if (XP_HAS_CACHE(ctxt)) {
   2415 	switch (val->type) {
   2416 	    case XPATH_NODESET:
   2417 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2418 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2419 	    case XPATH_STRING:
   2420 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2421 	    case XPATH_BOOLEAN:
   2422 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2423 	    case XPATH_NUMBER:
   2424 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2425 	    default:
   2426 		break;
   2427 	}
   2428     }
   2429     return(xmlXPathObjectCopy(val));
   2430 }
   2431 
   2432 /**
   2433  * xmlXPathCacheConvertBoolean:
   2434  * @ctxt: the XPath context
   2435  * @val:  an XPath object
   2436  *
   2437  * This is the cached version of xmlXPathConvertBoolean().
   2438  * Converts an existing object to its boolean() equivalent
   2439  *
   2440  * Returns a created or reused object, the old one is freed (or the operation
   2441  *         is done directly on @val)
   2442  */
   2443 static xmlXPathObjectPtr
   2444 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2445     xmlXPathObjectPtr ret;
   2446 
   2447     if (val == NULL)
   2448 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2449     if (val->type == XPATH_BOOLEAN)
   2450 	return(val);
   2451     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2452     xmlXPathReleaseObject(ctxt, val);
   2453     return(ret);
   2454 }
   2455 
   2456 /**
   2457  * xmlXPathCacheConvertNumber:
   2458  * @ctxt: the XPath context
   2459  * @val:  an XPath object
   2460  *
   2461  * This is the cached version of xmlXPathConvertNumber().
   2462  * Converts an existing object to its number() equivalent
   2463  *
   2464  * Returns a created or reused object, the old one is freed (or the operation
   2465  *         is done directly on @val)
   2466  */
   2467 static xmlXPathObjectPtr
   2468 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2469     xmlXPathObjectPtr ret;
   2470 
   2471     if (val == NULL)
   2472 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2473     if (val->type == XPATH_NUMBER)
   2474 	return(val);
   2475     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2476     xmlXPathReleaseObject(ctxt, val);
   2477     return(ret);
   2478 }
   2479 
   2480 /************************************************************************
   2481  *									*
   2482  *		Parser stacks related functions and macros		*
   2483  *									*
   2484  ************************************************************************/
   2485 
   2486 /**
   2487  * xmlXPathSetFrame:
   2488  * @ctxt: an XPath parser context
   2489  *
   2490  * Set the callee evaluation frame
   2491  *
   2492  * Returns the previous frame value to be restored once done
   2493  */
   2494 static int
   2495 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2496     int ret;
   2497 
   2498     if (ctxt == NULL)
   2499         return(0);
   2500     ret = ctxt->valueFrame;
   2501     ctxt->valueFrame = ctxt->valueNr;
   2502     return(ret);
   2503 }
   2504 
   2505 /**
   2506  * xmlXPathPopFrame:
   2507  * @ctxt: an XPath parser context
   2508  * @frame: the previous frame value
   2509  *
   2510  * Remove the callee evaluation frame
   2511  */
   2512 static void
   2513 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2514     if (ctxt == NULL)
   2515         return;
   2516     if (ctxt->valueNr < ctxt->valueFrame) {
   2517         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2518     }
   2519     ctxt->valueFrame = frame;
   2520 }
   2521 
   2522 /**
   2523  * valuePop:
   2524  * @ctxt: an XPath evaluation context
   2525  *
   2526  * Pops the top XPath object from the value stack
   2527  *
   2528  * Returns the XPath object just removed
   2529  */
   2530 xmlXPathObjectPtr
   2531 valuePop(xmlXPathParserContextPtr ctxt)
   2532 {
   2533     xmlXPathObjectPtr ret;
   2534 
   2535     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2536         return (NULL);
   2537 
   2538     if (ctxt->valueNr <= ctxt->valueFrame) {
   2539         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2540         return (NULL);
   2541     }
   2542 
   2543     ctxt->valueNr--;
   2544     if (ctxt->valueNr > 0)
   2545         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2546     else
   2547         ctxt->value = NULL;
   2548     ret = ctxt->valueTab[ctxt->valueNr];
   2549     ctxt->valueTab[ctxt->valueNr] = NULL;
   2550     return (ret);
   2551 }
   2552 /**
   2553  * valuePush:
   2554  * @ctxt:  an XPath evaluation context
   2555  * @value:  the XPath object
   2556  *
   2557  * Pushes a new XPath object on top of the value stack
   2558  *
   2559  * returns the number of items on the value stack
   2560  */
   2561 int
   2562 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2563 {
   2564     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2565     if (ctxt->valueNr >= ctxt->valueMax) {
   2566         xmlXPathObjectPtr *tmp;
   2567 
   2568         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
   2569             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
   2570             ctxt->error = XPATH_MEMORY_ERROR;
   2571             return (0);
   2572         }
   2573         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2574                                              2 * ctxt->valueMax *
   2575                                              sizeof(ctxt->valueTab[0]));
   2576         if (tmp == NULL) {
   2577             xmlXPathErrMemory(NULL, "pushing value\n");
   2578             ctxt->error = XPATH_MEMORY_ERROR;
   2579             return (0);
   2580         }
   2581         ctxt->valueMax *= 2;
   2582 	ctxt->valueTab = tmp;
   2583     }
   2584     ctxt->valueTab[ctxt->valueNr] = value;
   2585     ctxt->value = value;
   2586     return (ctxt->valueNr++);
   2587 }
   2588 
   2589 /**
   2590  * xmlXPathPopBoolean:
   2591  * @ctxt:  an XPath parser context
   2592  *
   2593  * Pops a boolean from the stack, handling conversion if needed.
   2594  * Check error with #xmlXPathCheckError.
   2595  *
   2596  * Returns the boolean
   2597  */
   2598 int
   2599 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2600     xmlXPathObjectPtr obj;
   2601     int ret;
   2602 
   2603     obj = valuePop(ctxt);
   2604     if (obj == NULL) {
   2605 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2606 	return(0);
   2607     }
   2608     if (obj->type != XPATH_BOOLEAN)
   2609 	ret = xmlXPathCastToBoolean(obj);
   2610     else
   2611         ret = obj->boolval;
   2612     xmlXPathReleaseObject(ctxt->context, obj);
   2613     return(ret);
   2614 }
   2615 
   2616 /**
   2617  * xmlXPathPopNumber:
   2618  * @ctxt:  an XPath parser context
   2619  *
   2620  * Pops a number from the stack, handling conversion if needed.
   2621  * Check error with #xmlXPathCheckError.
   2622  *
   2623  * Returns the number
   2624  */
   2625 double
   2626 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2627     xmlXPathObjectPtr obj;
   2628     double ret;
   2629 
   2630     obj = valuePop(ctxt);
   2631     if (obj == NULL) {
   2632 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2633 	return(0);
   2634     }
   2635     if (obj->type != XPATH_NUMBER)
   2636 	ret = xmlXPathCastToNumber(obj);
   2637     else
   2638         ret = obj->floatval;
   2639     xmlXPathReleaseObject(ctxt->context, obj);
   2640     return(ret);
   2641 }
   2642 
   2643 /**
   2644  * xmlXPathPopString:
   2645  * @ctxt:  an XPath parser context
   2646  *
   2647  * Pops a string from the stack, handling conversion if needed.
   2648  * Check error with #xmlXPathCheckError.
   2649  *
   2650  * Returns the string
   2651  */
   2652 xmlChar *
   2653 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2654     xmlXPathObjectPtr obj;
   2655     xmlChar * ret;
   2656 
   2657     obj = valuePop(ctxt);
   2658     if (obj == NULL) {
   2659 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2660 	return(NULL);
   2661     }
   2662     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2663     /* TODO: needs refactoring somewhere else */
   2664     if (obj->stringval == ret)
   2665 	obj->stringval = NULL;
   2666     xmlXPathReleaseObject(ctxt->context, obj);
   2667     return(ret);
   2668 }
   2669 
   2670 /**
   2671  * xmlXPathPopNodeSet:
   2672  * @ctxt:  an XPath parser context
   2673  *
   2674  * Pops a node-set from the stack, handling conversion if needed.
   2675  * Check error with #xmlXPathCheckError.
   2676  *
   2677  * Returns the node-set
   2678  */
   2679 xmlNodeSetPtr
   2680 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2681     xmlXPathObjectPtr obj;
   2682     xmlNodeSetPtr ret;
   2683 
   2684     if (ctxt == NULL) return(NULL);
   2685     if (ctxt->value == NULL) {
   2686 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2687 	return(NULL);
   2688     }
   2689     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2690 	xmlXPathSetTypeError(ctxt);
   2691 	return(NULL);
   2692     }
   2693     obj = valuePop(ctxt);
   2694     ret = obj->nodesetval;
   2695 #if 0
   2696     /* to fix memory leak of not clearing obj->user */
   2697     if (obj->boolval && obj->user != NULL)
   2698         xmlFreeNodeList((xmlNodePtr) obj->user);
   2699 #endif
   2700     obj->nodesetval = NULL;
   2701     xmlXPathReleaseObject(ctxt->context, obj);
   2702     return(ret);
   2703 }
   2704 
   2705 /**
   2706  * xmlXPathPopExternal:
   2707  * @ctxt:  an XPath parser context
   2708  *
   2709  * Pops an external object from the stack, handling conversion if needed.
   2710  * Check error with #xmlXPathCheckError.
   2711  *
   2712  * Returns the object
   2713  */
   2714 void *
   2715 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   2716     xmlXPathObjectPtr obj;
   2717     void * ret;
   2718 
   2719     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   2720 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2721 	return(NULL);
   2722     }
   2723     if (ctxt->value->type != XPATH_USERS) {
   2724 	xmlXPathSetTypeError(ctxt);
   2725 	return(NULL);
   2726     }
   2727     obj = valuePop(ctxt);
   2728     ret = obj->user;
   2729     obj->user = NULL;
   2730     xmlXPathReleaseObject(ctxt->context, obj);
   2731     return(ret);
   2732 }
   2733 
   2734 /*
   2735  * Macros for accessing the content. Those should be used only by the parser,
   2736  * and not exported.
   2737  *
   2738  * Dirty macros, i.e. one need to make assumption on the context to use them
   2739  *
   2740  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   2741  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   2742  *           in ISO-Latin or UTF-8.
   2743  *           This should be used internally by the parser
   2744  *           only to compare to ASCII values otherwise it would break when
   2745  *           running with UTF-8 encoding.
   2746  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   2747  *           to compare on ASCII based substring.
   2748  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   2749  *           strings within the parser.
   2750  *   CURRENT Returns the current char value, with the full decoding of
   2751  *           UTF-8 if we are using this mode. It returns an int.
   2752  *   NEXT    Skip to the next character, this does the proper decoding
   2753  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   2754  *           It returns the pointer to the current xmlChar.
   2755  */
   2756 
   2757 #define CUR (*ctxt->cur)
   2758 #define SKIP(val) ctxt->cur += (val)
   2759 #define NXT(val) ctxt->cur[(val)]
   2760 #define CUR_PTR ctxt->cur
   2761 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   2762 
   2763 #define COPY_BUF(l,b,i,v)                                              \
   2764     if (l == 1) b[i++] = (xmlChar) v;                                  \
   2765     else i += xmlCopyChar(l,&b[i],v)
   2766 
   2767 #define NEXTL(l)  ctxt->cur += l
   2768 
   2769 #define SKIP_BLANKS							\
   2770     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   2771 
   2772 #define CURRENT (*ctxt->cur)
   2773 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   2774 
   2775 
   2776 #ifndef DBL_DIG
   2777 #define DBL_DIG 16
   2778 #endif
   2779 #ifndef DBL_EPSILON
   2780 #define DBL_EPSILON 1E-9
   2781 #endif
   2782 
   2783 #define UPPER_DOUBLE 1E9
   2784 #define LOWER_DOUBLE 1E-5
   2785 #define	LOWER_DOUBLE_EXP 5
   2786 
   2787 #define INTEGER_DIGITS DBL_DIG
   2788 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   2789 #define EXPONENT_DIGITS (3 + 2)
   2790 
   2791 /**
   2792  * xmlXPathFormatNumber:
   2793  * @number:     number to format
   2794  * @buffer:     output buffer
   2795  * @buffersize: size of output buffer
   2796  *
   2797  * Convert the number into a string representation.
   2798  */
   2799 static void
   2800 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   2801 {
   2802     switch (xmlXPathIsInf(number)) {
   2803     case 1:
   2804 	if (buffersize > (int)sizeof("Infinity"))
   2805 	    snprintf(buffer, buffersize, "Infinity");
   2806 	break;
   2807     case -1:
   2808 	if (buffersize > (int)sizeof("-Infinity"))
   2809 	    snprintf(buffer, buffersize, "-Infinity");
   2810 	break;
   2811     default:
   2812 	if (xmlXPathIsNaN(number)) {
   2813 	    if (buffersize > (int)sizeof("NaN"))
   2814 		snprintf(buffer, buffersize, "NaN");
   2815 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   2816 	    snprintf(buffer, buffersize, "0");
   2817 	} else if (number == ((int) number)) {
   2818 	    char work[30];
   2819 	    char *ptr, *cur;
   2820 	    int value = (int) number;
   2821 
   2822             ptr = &buffer[0];
   2823 	    if (value == 0) {
   2824 		*ptr++ = '0';
   2825 	    } else {
   2826 		snprintf(work, 29, "%d", value);
   2827 		cur = &work[0];
   2828 		while ((*cur) && (ptr - buffer < buffersize)) {
   2829 		    *ptr++ = *cur++;
   2830 		}
   2831 	    }
   2832 	    if (ptr - buffer < buffersize) {
   2833 		*ptr = 0;
   2834 	    } else if (buffersize > 0) {
   2835 		ptr--;
   2836 		*ptr = 0;
   2837 	    }
   2838 	} else {
   2839 	    /*
   2840 	      For the dimension of work,
   2841 	          DBL_DIG is number of significant digits
   2842 		  EXPONENT is only needed for "scientific notation"
   2843 	          3 is sign, decimal point, and terminating zero
   2844 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   2845 	      Note that this dimension is slightly (a few characters)
   2846 	      larger than actually necessary.
   2847 	    */
   2848 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   2849 	    int integer_place, fraction_place;
   2850 	    char *ptr;
   2851 	    char *after_fraction;
   2852 	    double absolute_value;
   2853 	    int size;
   2854 
   2855 	    absolute_value = fabs(number);
   2856 
   2857 	    /*
   2858 	     * First choose format - scientific or regular floating point.
   2859 	     * In either case, result is in work, and after_fraction points
   2860 	     * just past the fractional part.
   2861 	    */
   2862 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   2863 		  (absolute_value < LOWER_DOUBLE)) &&
   2864 		 (absolute_value != 0.0) ) {
   2865 		/* Use scientific notation */
   2866 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   2867 		fraction_place = DBL_DIG - 1;
   2868 		size = snprintf(work, sizeof(work),"%*.*e",
   2869 			 integer_place, fraction_place, number);
   2870 		while ((size > 0) && (work[size] != 'e')) size--;
   2871 
   2872 	    }
   2873 	    else {
   2874 		/* Use regular notation */
   2875 		if (absolute_value > 0.0) {
   2876 		    integer_place = (int)log10(absolute_value);
   2877 		    if (integer_place > 0)
   2878 		        fraction_place = DBL_DIG - integer_place - 1;
   2879 		    else
   2880 		        fraction_place = DBL_DIG - integer_place;
   2881 		} else {
   2882 		    fraction_place = 1;
   2883 		}
   2884 		size = snprintf(work, sizeof(work), "%0.*f",
   2885 				fraction_place, number);
   2886 	    }
   2887 
   2888 	    /* Remove fractional trailing zeroes */
   2889 	    after_fraction = work + size;
   2890 	    ptr = after_fraction;
   2891 	    while (*(--ptr) == '0')
   2892 		;
   2893 	    if (*ptr != '.')
   2894 	        ptr++;
   2895 	    while ((*ptr++ = *after_fraction++) != 0);
   2896 
   2897 	    /* Finally copy result back to caller */
   2898 	    size = strlen(work) + 1;
   2899 	    if (size > buffersize) {
   2900 		work[buffersize - 1] = 0;
   2901 		size = buffersize;
   2902 	    }
   2903 	    memmove(buffer, work, size);
   2904 	}
   2905 	break;
   2906     }
   2907 }
   2908 
   2909 
   2910 /************************************************************************
   2911  *									*
   2912  *			Routines to handle NodeSets			*
   2913  *									*
   2914  ************************************************************************/
   2915 
   2916 /**
   2917  * xmlXPathOrderDocElems:
   2918  * @doc:  an input document
   2919  *
   2920  * Call this routine to speed up XPath computation on static documents.
   2921  * This stamps all the element nodes with the document order
   2922  * Like for line information, the order is kept in the element->content
   2923  * field, the value stored is actually - the node number (starting at -1)
   2924  * to be able to differentiate from line numbers.
   2925  *
   2926  * Returns the number of elements found in the document or -1 in case
   2927  *    of error.
   2928  */
   2929 long
   2930 xmlXPathOrderDocElems(xmlDocPtr doc) {
   2931     long count = 0;
   2932     xmlNodePtr cur;
   2933 
   2934     if (doc == NULL)
   2935 	return(-1);
   2936     cur = doc->children;
   2937     while (cur != NULL) {
   2938 	if (cur->type == XML_ELEMENT_NODE) {
   2939 	    cur->content = (void *) (-(++count));
   2940 	    if (cur->children != NULL) {
   2941 		cur = cur->children;
   2942 		continue;
   2943 	    }
   2944 	}
   2945 	if (cur->next != NULL) {
   2946 	    cur = cur->next;
   2947 	    continue;
   2948 	}
   2949 	do {
   2950 	    cur = cur->parent;
   2951 	    if (cur == NULL)
   2952 		break;
   2953 	    if (cur == (xmlNodePtr) doc) {
   2954 		cur = NULL;
   2955 		break;
   2956 	    }
   2957 	    if (cur->next != NULL) {
   2958 		cur = cur->next;
   2959 		break;
   2960 	    }
   2961 	} while (cur != NULL);
   2962     }
   2963     return(count);
   2964 }
   2965 
   2966 /**
   2967  * xmlXPathCmpNodes:
   2968  * @node1:  the first node
   2969  * @node2:  the second node
   2970  *
   2971  * Compare two nodes w.r.t document order
   2972  *
   2973  * Returns -2 in case of error 1 if first point < second point, 0 if
   2974  *         it's the same node, -1 otherwise
   2975  */
   2976 int
   2977 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   2978     int depth1, depth2;
   2979     int attr1 = 0, attr2 = 0;
   2980     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   2981     xmlNodePtr cur, root;
   2982 
   2983     if ((node1 == NULL) || (node2 == NULL))
   2984 	return(-2);
   2985     /*
   2986      * a couple of optimizations which will avoid computations in most cases
   2987      */
   2988     if (node1 == node2)		/* trivial case */
   2989 	return(0);
   2990     if (node1->type == XML_ATTRIBUTE_NODE) {
   2991 	attr1 = 1;
   2992 	attrNode1 = node1;
   2993 	node1 = node1->parent;
   2994     }
   2995     if (node2->type == XML_ATTRIBUTE_NODE) {
   2996 	attr2 = 1;
   2997 	attrNode2 = node2;
   2998 	node2 = node2->parent;
   2999     }
   3000     if (node1 == node2) {
   3001 	if (attr1 == attr2) {
   3002 	    /* not required, but we keep attributes in order */
   3003 	    if (attr1 != 0) {
   3004 	        cur = attrNode2->prev;
   3005 		while (cur != NULL) {
   3006 		    if (cur == attrNode1)
   3007 		        return (1);
   3008 		    cur = cur->prev;
   3009 		}
   3010 		return (-1);
   3011 	    }
   3012 	    return(0);
   3013 	}
   3014 	if (attr2 == 1)
   3015 	    return(1);
   3016 	return(-1);
   3017     }
   3018     if ((node1->type == XML_NAMESPACE_DECL) ||
   3019         (node2->type == XML_NAMESPACE_DECL))
   3020 	return(1);
   3021     if (node1 == node2->prev)
   3022 	return(1);
   3023     if (node1 == node2->next)
   3024 	return(-1);
   3025 
   3026     /*
   3027      * Speedup using document order if availble.
   3028      */
   3029     if ((node1->type == XML_ELEMENT_NODE) &&
   3030 	(node2->type == XML_ELEMENT_NODE) &&
   3031 	(0 > (long) node1->content) &&
   3032 	(0 > (long) node2->content) &&
   3033 	(node1->doc == node2->doc)) {
   3034 	long l1, l2;
   3035 
   3036 	l1 = -((long) node1->content);
   3037 	l2 = -((long) node2->content);
   3038 	if (l1 < l2)
   3039 	    return(1);
   3040 	if (l1 > l2)
   3041 	    return(-1);
   3042     }
   3043 
   3044     /*
   3045      * compute depth to root
   3046      */
   3047     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3048 	if (cur == node1)
   3049 	    return(1);
   3050 	depth2++;
   3051     }
   3052     root = cur;
   3053     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3054 	if (cur == node2)
   3055 	    return(-1);
   3056 	depth1++;
   3057     }
   3058     /*
   3059      * Distinct document (or distinct entities :-( ) case.
   3060      */
   3061     if (root != cur) {
   3062 	return(-2);
   3063     }
   3064     /*
   3065      * get the nearest common ancestor.
   3066      */
   3067     while (depth1 > depth2) {
   3068 	depth1--;
   3069 	node1 = node1->parent;
   3070     }
   3071     while (depth2 > depth1) {
   3072 	depth2--;
   3073 	node2 = node2->parent;
   3074     }
   3075     while (node1->parent != node2->parent) {
   3076 	node1 = node1->parent;
   3077 	node2 = node2->parent;
   3078 	/* should not happen but just in case ... */
   3079 	if ((node1 == NULL) || (node2 == NULL))
   3080 	    return(-2);
   3081     }
   3082     /*
   3083      * Find who's first.
   3084      */
   3085     if (node1 == node2->prev)
   3086 	return(1);
   3087     if (node1 == node2->next)
   3088 	return(-1);
   3089     /*
   3090      * Speedup using document order if availble.
   3091      */
   3092     if ((node1->type == XML_ELEMENT_NODE) &&
   3093 	(node2->type == XML_ELEMENT_NODE) &&
   3094 	(0 > (long) node1->content) &&
   3095 	(0 > (long) node2->content) &&
   3096 	(node1->doc == node2->doc)) {
   3097 	long l1, l2;
   3098 
   3099 	l1 = -((long) node1->content);
   3100 	l2 = -((long) node2->content);
   3101 	if (l1 < l2)
   3102 	    return(1);
   3103 	if (l1 > l2)
   3104 	    return(-1);
   3105     }
   3106 
   3107     for (cur = node1->next;cur != NULL;cur = cur->next)
   3108 	if (cur == node2)
   3109 	    return(1);
   3110     return(-1); /* assume there is no sibling list corruption */
   3111 }
   3112 
   3113 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3114 /**
   3115  * xmlXPathCmpNodesExt:
   3116  * @node1:  the first node
   3117  * @node2:  the second node
   3118  *
   3119  * Compare two nodes w.r.t document order.
   3120  * This one is optimized for handling of non-element nodes.
   3121  *
   3122  * Returns -2 in case of error 1 if first point < second point, 0 if
   3123  *         it's the same node, -1 otherwise
   3124  */
   3125 static int
   3126 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
   3127     int depth1, depth2;
   3128     int misc = 0, precedence1 = 0, precedence2 = 0;
   3129     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
   3130     xmlNodePtr cur, root;
   3131     long l1, l2;
   3132 
   3133     if ((node1 == NULL) || (node2 == NULL))
   3134 	return(-2);
   3135 
   3136     if (node1 == node2)
   3137 	return(0);
   3138 
   3139     /*
   3140      * a couple of optimizations which will avoid computations in most cases
   3141      */
   3142     switch (node1->type) {
   3143 	case XML_ELEMENT_NODE:
   3144 	    if (node2->type == XML_ELEMENT_NODE) {
   3145 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
   3146 		    (0 > (long) node2->content) &&
   3147 		    (node1->doc == node2->doc))
   3148 		{
   3149 		    l1 = -((long) node1->content);
   3150 		    l2 = -((long) node2->content);
   3151 		    if (l1 < l2)
   3152 			return(1);
   3153 		    if (l1 > l2)
   3154 			return(-1);
   3155 		} else
   3156 		    goto turtle_comparison;
   3157 	    }
   3158 	    break;
   3159 	case XML_ATTRIBUTE_NODE:
   3160 	    precedence1 = 1; /* element is owner */
   3161 	    miscNode1 = node1;
   3162 	    node1 = node1->parent;
   3163 	    misc = 1;
   3164 	    break;
   3165 	case XML_TEXT_NODE:
   3166 	case XML_CDATA_SECTION_NODE:
   3167 	case XML_COMMENT_NODE:
   3168 	case XML_PI_NODE: {
   3169 	    miscNode1 = node1;
   3170 	    /*
   3171 	    * Find nearest element node.
   3172 	    */
   3173 	    if (node1->prev != NULL) {
   3174 		do {
   3175 		    node1 = node1->prev;
   3176 		    if (node1->type == XML_ELEMENT_NODE) {
   3177 			precedence1 = 3; /* element in prev-sibl axis */
   3178 			break;
   3179 		    }
   3180 		    if (node1->prev == NULL) {
   3181 			precedence1 = 2; /* element is parent */
   3182 			/*
   3183 			* URGENT TODO: Are there any cases, where the
   3184 			* parent of such a node is not an element node?
   3185 			*/
   3186 			node1 = node1->parent;
   3187 			break;
   3188 		    }
   3189 		} while (1);
   3190 	    } else {
   3191 		precedence1 = 2; /* element is parent */
   3192 		node1 = node1->parent;
   3193 	    }
   3194 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
   3195 		(0 <= (long) node1->content)) {
   3196 		/*
   3197 		* Fallback for whatever case.
   3198 		*/
   3199 		node1 = miscNode1;
   3200 		precedence1 = 0;
   3201 	    } else
   3202 		misc = 1;
   3203 	}
   3204 	    break;
   3205 	case XML_NAMESPACE_DECL:
   3206 	    /*
   3207 	    * TODO: why do we return 1 for namespace nodes?
   3208 	    */
   3209 	    return(1);
   3210 	default:
   3211 	    break;
   3212     }
   3213     switch (node2->type) {
   3214 	case XML_ELEMENT_NODE:
   3215 	    break;
   3216 	case XML_ATTRIBUTE_NODE:
   3217 	    precedence2 = 1; /* element is owner */
   3218 	    miscNode2 = node2;
   3219 	    node2 = node2->parent;
   3220 	    misc = 1;
   3221 	    break;
   3222 	case XML_TEXT_NODE:
   3223 	case XML_CDATA_SECTION_NODE:
   3224 	case XML_COMMENT_NODE:
   3225 	case XML_PI_NODE: {
   3226 	    miscNode2 = node2;
   3227 	    if (node2->prev != NULL) {
   3228 		do {
   3229 		    node2 = node2->prev;
   3230 		    if (node2->type == XML_ELEMENT_NODE) {
   3231 			precedence2 = 3; /* element in prev-sibl axis */
   3232 			break;
   3233 		    }
   3234 		    if (node2->prev == NULL) {
   3235 			precedence2 = 2; /* element is parent */
   3236 			node2 = node2->parent;
   3237 			break;
   3238 		    }
   3239 		} while (1);
   3240 	    } else {
   3241 		precedence2 = 2; /* element is parent */
   3242 		node2 = node2->parent;
   3243 	    }
   3244 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
   3245 		(0 <= (long) node1->content))
   3246 	    {
   3247 		node2 = miscNode2;
   3248 		precedence2 = 0;
   3249 	    } else
   3250 		misc = 1;
   3251 	}
   3252 	    break;
   3253 	case XML_NAMESPACE_DECL:
   3254 	    return(1);
   3255 	default:
   3256 	    break;
   3257     }
   3258     if (misc) {
   3259 	if (node1 == node2) {
   3260 	    if (precedence1 == precedence2) {
   3261 		/*
   3262 		* The ugly case; but normally there aren't many
   3263 		* adjacent non-element nodes around.
   3264 		*/
   3265 		cur = miscNode2->prev;
   3266 		while (cur != NULL) {
   3267 		    if (cur == miscNode1)
   3268 			return(1);
   3269 		    if (cur->type == XML_ELEMENT_NODE)
   3270 			return(-1);
   3271 		    cur = cur->prev;
   3272 		}
   3273 		return (-1);
   3274 	    } else {
   3275 		/*
   3276 		* Evaluate based on higher precedence wrt to the element.
   3277 		* TODO: This assumes attributes are sorted before content.
   3278 		*   Is this 100% correct?
   3279 		*/
   3280 		if (precedence1 < precedence2)
   3281 		    return(1);
   3282 		else
   3283 		    return(-1);
   3284 	    }
   3285 	}
   3286 	/*
   3287 	* Special case: One of the helper-elements is contained by the other.
   3288 	* <foo>
   3289 	*   <node2>
   3290 	*     <node1>Text-1(precedence1 == 2)</node1>
   3291 	*   </node2>
   3292 	*   Text-6(precedence2 == 3)
   3293 	* </foo>
   3294 	*/
   3295 	if ((precedence2 == 3) && (precedence1 > 1)) {
   3296 	    cur = node1->parent;
   3297 	    while (cur) {
   3298 		if (cur == node2)
   3299 		    return(1);
   3300 		cur = cur->parent;
   3301 	    }
   3302 	}
   3303 	if ((precedence1 == 3) && (precedence2 > 1)) {
   3304 	    cur = node2->parent;
   3305 	    while (cur) {
   3306 		if (cur == node1)
   3307 		    return(-1);
   3308 		cur = cur->parent;
   3309 	    }
   3310 	}
   3311     }
   3312 
   3313     /*
   3314      * Speedup using document order if availble.
   3315      */
   3316     if ((node1->type == XML_ELEMENT_NODE) &&
   3317 	(node2->type == XML_ELEMENT_NODE) &&
   3318 	(0 > (long) node1->content) &&
   3319 	(0 > (long) node2->content) &&
   3320 	(node1->doc == node2->doc)) {
   3321 
   3322 	l1 = -((long) node1->content);
   3323 	l2 = -((long) node2->content);
   3324 	if (l1 < l2)
   3325 	    return(1);
   3326 	if (l1 > l2)
   3327 	    return(-1);
   3328     }
   3329 
   3330 turtle_comparison:
   3331 
   3332     if (node1 == node2->prev)
   3333 	return(1);
   3334     if (node1 == node2->next)
   3335 	return(-1);
   3336     /*
   3337      * compute depth to root
   3338      */
   3339     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3340 	if (cur == node1)
   3341 	    return(1);
   3342 	depth2++;
   3343     }
   3344     root = cur;
   3345     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3346 	if (cur == node2)
   3347 	    return(-1);
   3348 	depth1++;
   3349     }
   3350     /*
   3351      * Distinct document (or distinct entities :-( ) case.
   3352      */
   3353     if (root != cur) {
   3354 	return(-2);
   3355     }
   3356     /*
   3357      * get the nearest common ancestor.
   3358      */
   3359     while (depth1 > depth2) {
   3360 	depth1--;
   3361 	node1 = node1->parent;
   3362     }
   3363     while (depth2 > depth1) {
   3364 	depth2--;
   3365 	node2 = node2->parent;
   3366     }
   3367     while (node1->parent != node2->parent) {
   3368 	node1 = node1->parent;
   3369 	node2 = node2->parent;
   3370 	/* should not happen but just in case ... */
   3371 	if ((node1 == NULL) || (node2 == NULL))
   3372 	    return(-2);
   3373     }
   3374     /*
   3375      * Find who's first.
   3376      */
   3377     if (node1 == node2->prev)
   3378 	return(1);
   3379     if (node1 == node2->next)
   3380 	return(-1);
   3381     /*
   3382      * Speedup using document order if availble.
   3383      */
   3384     if ((node1->type == XML_ELEMENT_NODE) &&
   3385 	(node2->type == XML_ELEMENT_NODE) &&
   3386 	(0 > (long) node1->content) &&
   3387 	(0 > (long) node2->content) &&
   3388 	(node1->doc == node2->doc)) {
   3389 
   3390 	l1 = -((long) node1->content);
   3391 	l2 = -((long) node2->content);
   3392 	if (l1 < l2)
   3393 	    return(1);
   3394 	if (l1 > l2)
   3395 	    return(-1);
   3396     }
   3397 
   3398     for (cur = node1->next;cur != NULL;cur = cur->next)
   3399 	if (cur == node2)
   3400 	    return(1);
   3401     return(-1); /* assume there is no sibling list corruption */
   3402 }
   3403 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
   3404 
   3405 /**
   3406  * xmlXPathNodeSetSort:
   3407  * @set:  the node set
   3408  *
   3409  * Sort the node set in document order
   3410  */
   3411 void
   3412 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3413 #ifndef WITH_TIM_SORT
   3414     int i, j, incr, len;
   3415     xmlNodePtr tmp;
   3416 #endif
   3417 
   3418     if (set == NULL)
   3419 	return;
   3420 
   3421 #ifndef WITH_TIM_SORT
   3422     /*
   3423      * Use the old Shell's sort implementation to sort the node-set
   3424      * Timsort ought to be quite faster
   3425      */
   3426     len = set->nodeNr;
   3427     for (incr = len / 2; incr > 0; incr /= 2) {
   3428 	for (i = incr; i < len; i++) {
   3429 	    j = i - incr;
   3430 	    while (j >= 0) {
   3431 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3432 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3433 			set->nodeTab[j + incr]) == -1)
   3434 #else
   3435 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3436 			set->nodeTab[j + incr]) == -1)
   3437 #endif
   3438 		{
   3439 		    tmp = set->nodeTab[j];
   3440 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3441 		    set->nodeTab[j + incr] = tmp;
   3442 		    j -= incr;
   3443 		} else
   3444 		    break;
   3445 	    }
   3446 	}
   3447     }
   3448 #else /* WITH_TIM_SORT */
   3449     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
   3450 #endif /* WITH_TIM_SORT */
   3451 }
   3452 
   3453 #define XML_NODESET_DEFAULT	10
   3454 /**
   3455  * xmlXPathNodeSetDupNs:
   3456  * @node:  the parent node of the namespace XPath node
   3457  * @ns:  the libxml namespace declaration node.
   3458  *
   3459  * Namespace node in libxml don't match the XPath semantic. In a node set
   3460  * the namespace nodes are duplicated and the next pointer is set to the
   3461  * parent node in the XPath semantic.
   3462  *
   3463  * Returns the newly created object.
   3464  */
   3465 static xmlNodePtr
   3466 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3467     xmlNsPtr cur;
   3468 
   3469     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3470 	return(NULL);
   3471     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3472 	return((xmlNodePtr) ns);
   3473 
   3474     /*
   3475      * Allocate a new Namespace and fill the fields.
   3476      */
   3477     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3478     if (cur == NULL) {
   3479         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3480 	return(NULL);
   3481     }
   3482     memset(cur, 0, sizeof(xmlNs));
   3483     cur->type = XML_NAMESPACE_DECL;
   3484     if (ns->href != NULL)
   3485 	cur->href = xmlStrdup(ns->href);
   3486     if (ns->prefix != NULL)
   3487 	cur->prefix = xmlStrdup(ns->prefix);
   3488     cur->next = (xmlNsPtr) node;
   3489     return((xmlNodePtr) cur);
   3490 }
   3491 
   3492 /**
   3493  * xmlXPathNodeSetFreeNs:
   3494  * @ns:  the XPath namespace node found in a nodeset.
   3495  *
   3496  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3497  * the namespace nodes are duplicated and the next pointer is set to the
   3498  * parent node in the XPath semantic. Check if such a node needs to be freed
   3499  */
   3500 void
   3501 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3502     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3503 	return;
   3504 
   3505     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3506 	if (ns->href != NULL)
   3507 	    xmlFree((xmlChar *)ns->href);
   3508 	if (ns->prefix != NULL)
   3509 	    xmlFree((xmlChar *)ns->prefix);
   3510 	xmlFree(ns);
   3511     }
   3512 }
   3513 
   3514 /**
   3515  * xmlXPathNodeSetCreate:
   3516  * @val:  an initial xmlNodePtr, or NULL
   3517  *
   3518  * Create a new xmlNodeSetPtr of type double and of value @val
   3519  *
   3520  * Returns the newly created object.
   3521  */
   3522 xmlNodeSetPtr
   3523 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3524     xmlNodeSetPtr ret;
   3525 
   3526     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3527     if (ret == NULL) {
   3528         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3529 	return(NULL);
   3530     }
   3531     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3532     if (val != NULL) {
   3533         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3534 					     sizeof(xmlNodePtr));
   3535 	if (ret->nodeTab == NULL) {
   3536 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3537 	    xmlFree(ret);
   3538 	    return(NULL);
   3539 	}
   3540 	memset(ret->nodeTab, 0 ,
   3541 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3542         ret->nodeMax = XML_NODESET_DEFAULT;
   3543 	if (val->type == XML_NAMESPACE_DECL) {
   3544 	    xmlNsPtr ns = (xmlNsPtr) val;
   3545 
   3546 	    ret->nodeTab[ret->nodeNr++] =
   3547 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3548 	} else
   3549 	    ret->nodeTab[ret->nodeNr++] = val;
   3550     }
   3551     return(ret);
   3552 }
   3553 
   3554 /**
   3555  * xmlXPathNodeSetCreateSize:
   3556  * @size:  the initial size of the set
   3557  *
   3558  * Create a new xmlNodeSetPtr of type double and of value @val
   3559  *
   3560  * Returns the newly created object.
   3561  */
   3562 static xmlNodeSetPtr
   3563 xmlXPathNodeSetCreateSize(int size) {
   3564     xmlNodeSetPtr ret;
   3565 
   3566     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3567     if (ret == NULL) {
   3568         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3569 	return(NULL);
   3570     }
   3571     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3572     if (size < XML_NODESET_DEFAULT)
   3573 	size = XML_NODESET_DEFAULT;
   3574     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3575     if (ret->nodeTab == NULL) {
   3576 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3577 	xmlFree(ret);
   3578 	return(NULL);
   3579     }
   3580     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3581     ret->nodeMax = size;
   3582     return(ret);
   3583 }
   3584 
   3585 /**
   3586  * xmlXPathNodeSetContains:
   3587  * @cur:  the node-set
   3588  * @val:  the node
   3589  *
   3590  * checks whether @cur contains @val
   3591  *
   3592  * Returns true (1) if @cur contains @val, false (0) otherwise
   3593  */
   3594 int
   3595 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3596     int i;
   3597 
   3598     if ((cur == NULL) || (val == NULL)) return(0);
   3599     if (val->type == XML_NAMESPACE_DECL) {
   3600 	for (i = 0; i < cur->nodeNr; i++) {
   3601 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3602 		xmlNsPtr ns1, ns2;
   3603 
   3604 		ns1 = (xmlNsPtr) val;
   3605 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3606 		if (ns1 == ns2)
   3607 		    return(1);
   3608 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3609 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3610 		    return(1);
   3611 	    }
   3612 	}
   3613     } else {
   3614 	for (i = 0; i < cur->nodeNr; i++) {
   3615 	    if (cur->nodeTab[i] == val)
   3616 		return(1);
   3617 	}
   3618     }
   3619     return(0);
   3620 }
   3621 
   3622 /**
   3623  * xmlXPathNodeSetAddNs:
   3624  * @cur:  the initial node set
   3625  * @node:  the hosting node
   3626  * @ns:  a the namespace node
   3627  *
   3628  * add a new namespace node to an existing NodeSet
   3629  *
   3630  * Returns 0 in case of success and -1 in case of error
   3631  */
   3632 int
   3633 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3634     int i;
   3635 
   3636 
   3637     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3638         (ns->type != XML_NAMESPACE_DECL) ||
   3639 	(node->type != XML_ELEMENT_NODE))
   3640 	return(-1);
   3641 
   3642     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3643     /*
   3644      * prevent duplicates
   3645      */
   3646     for (i = 0;i < cur->nodeNr;i++) {
   3647         if ((cur->nodeTab[i] != NULL) &&
   3648 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3649 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3650 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3651 	    return(0);
   3652     }
   3653 
   3654     /*
   3655      * grow the nodeTab if needed
   3656      */
   3657     if (cur->nodeMax == 0) {
   3658         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3659 					     sizeof(xmlNodePtr));
   3660 	if (cur->nodeTab == NULL) {
   3661 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3662 	    return(-1);
   3663 	}
   3664 	memset(cur->nodeTab, 0 ,
   3665 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3666         cur->nodeMax = XML_NODESET_DEFAULT;
   3667     } else if (cur->nodeNr == cur->nodeMax) {
   3668         xmlNodePtr *temp;
   3669 
   3670         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3671             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3672             return(-1);
   3673         }
   3674 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3675 				      sizeof(xmlNodePtr));
   3676 	if (temp == NULL) {
   3677 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3678 	    return(-1);
   3679 	}
   3680         cur->nodeMax *= 2;
   3681 	cur->nodeTab = temp;
   3682     }
   3683     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3684     return(0);
   3685 }
   3686 
   3687 /**
   3688  * xmlXPathNodeSetAdd:
   3689  * @cur:  the initial node set
   3690  * @val:  a new xmlNodePtr
   3691  *
   3692  * add a new xmlNodePtr to an existing NodeSet
   3693  *
   3694  * Returns 0 in case of success, and -1 in case of error
   3695  */
   3696 int
   3697 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3698     int i;
   3699 
   3700     if ((cur == NULL) || (val == NULL)) return(-1);
   3701 
   3702     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3703     /*
   3704      * prevent duplcates
   3705      */
   3706     for (i = 0;i < cur->nodeNr;i++)
   3707         if (cur->nodeTab[i] == val) return(0);
   3708 
   3709     /*
   3710      * grow the nodeTab if needed
   3711      */
   3712     if (cur->nodeMax == 0) {
   3713         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3714 					     sizeof(xmlNodePtr));
   3715 	if (cur->nodeTab == NULL) {
   3716 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3717 	    return(-1);
   3718 	}
   3719 	memset(cur->nodeTab, 0 ,
   3720 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3721         cur->nodeMax = XML_NODESET_DEFAULT;
   3722     } else if (cur->nodeNr == cur->nodeMax) {
   3723         xmlNodePtr *temp;
   3724 
   3725         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3726             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3727             return(-1);
   3728         }
   3729 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3730 				      sizeof(xmlNodePtr));
   3731 	if (temp == NULL) {
   3732 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3733 	    return(-1);
   3734 	}
   3735         cur->nodeMax *= 2;
   3736 	cur->nodeTab = temp;
   3737     }
   3738     if (val->type == XML_NAMESPACE_DECL) {
   3739 	xmlNsPtr ns = (xmlNsPtr) val;
   3740 
   3741 	cur->nodeTab[cur->nodeNr++] =
   3742 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3743     } else
   3744 	cur->nodeTab[cur->nodeNr++] = val;
   3745     return(0);
   3746 }
   3747 
   3748 /**
   3749  * xmlXPathNodeSetAddUnique:
   3750  * @cur:  the initial node set
   3751  * @val:  a new xmlNodePtr
   3752  *
   3753  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3754  * when we are sure the node is not already in the set.
   3755  *
   3756  * Returns 0 in case of success and -1 in case of failure
   3757  */
   3758 int
   3759 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3760     if ((cur == NULL) || (val == NULL)) return(-1);
   3761 
   3762     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3763     /*
   3764      * grow the nodeTab if needed
   3765      */
   3766     if (cur->nodeMax == 0) {
   3767         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3768 					     sizeof(xmlNodePtr));
   3769 	if (cur->nodeTab == NULL) {
   3770 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3771 	    return(-1);
   3772 	}
   3773 	memset(cur->nodeTab, 0 ,
   3774 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3775         cur->nodeMax = XML_NODESET_DEFAULT;
   3776     } else if (cur->nodeNr == cur->nodeMax) {
   3777         xmlNodePtr *temp;
   3778 
   3779         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3780             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3781             return(-1);
   3782         }
   3783 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3784 				      sizeof(xmlNodePtr));
   3785 	if (temp == NULL) {
   3786 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3787 	    return(-1);
   3788 	}
   3789 	cur->nodeTab = temp;
   3790         cur->nodeMax *= 2;
   3791     }
   3792     if (val->type == XML_NAMESPACE_DECL) {
   3793 	xmlNsPtr ns = (xmlNsPtr) val;
   3794 
   3795 	cur->nodeTab[cur->nodeNr++] =
   3796 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3797     } else
   3798 	cur->nodeTab[cur->nodeNr++] = val;
   3799     return(0);
   3800 }
   3801 
   3802 /**
   3803  * xmlXPathNodeSetMerge:
   3804  * @val1:  the first NodeSet or NULL
   3805  * @val2:  the second NodeSet
   3806  *
   3807  * Merges two nodesets, all nodes from @val2 are added to @val1
   3808  * if @val1 is NULL, a new set is created and copied from @val2
   3809  *
   3810  * Returns @val1 once extended or NULL in case of error.
   3811  */
   3812 xmlNodeSetPtr
   3813 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3814     int i, j, initNr, skip;
   3815     xmlNodePtr n1, n2;
   3816 
   3817     if (val2 == NULL) return(val1);
   3818     if (val1 == NULL) {
   3819 	val1 = xmlXPathNodeSetCreate(NULL);
   3820     if (val1 == NULL)
   3821         return (NULL);
   3822 #if 0
   3823 	/*
   3824 	* TODO: The optimization won't work in every case, since
   3825 	*  those nasty namespace nodes need to be added with
   3826 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3827 	*  memcpy is not possible.
   3828 	*  If there was a flag on the nodesetval, indicating that
   3829 	*  some temporary nodes are in, that would be helpfull.
   3830 	*/
   3831 	/*
   3832 	* Optimization: Create an equally sized node-set
   3833 	* and memcpy the content.
   3834 	*/
   3835 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3836 	if (val1 == NULL)
   3837 	    return(NULL);
   3838 	if (val2->nodeNr != 0) {
   3839 	    if (val2->nodeNr == 1)
   3840 		*(val1->nodeTab) = *(val2->nodeTab);
   3841 	    else {
   3842 		memcpy(val1->nodeTab, val2->nodeTab,
   3843 		    val2->nodeNr * sizeof(xmlNodePtr));
   3844 	    }
   3845 	    val1->nodeNr = val2->nodeNr;
   3846 	}
   3847 	return(val1);
   3848 #endif
   3849     }
   3850 
   3851     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3852     initNr = val1->nodeNr;
   3853 
   3854     for (i = 0;i < val2->nodeNr;i++) {
   3855 	n2 = val2->nodeTab[i];
   3856 	/*
   3857 	 * check against duplicates
   3858 	 */
   3859 	skip = 0;
   3860 	for (j = 0; j < initNr; j++) {
   3861 	    n1 = val1->nodeTab[j];
   3862 	    if (n1 == n2) {
   3863 		skip = 1;
   3864 		break;
   3865 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3866 		       (n2->type == XML_NAMESPACE_DECL)) {
   3867 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3868 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3869 			((xmlNsPtr) n2)->prefix)))
   3870 		{
   3871 		    skip = 1;
   3872 		    break;
   3873 		}
   3874 	    }
   3875 	}
   3876 	if (skip)
   3877 	    continue;
   3878 
   3879 	/*
   3880 	 * grow the nodeTab if needed
   3881 	 */
   3882 	if (val1->nodeMax == 0) {
   3883 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3884 						    sizeof(xmlNodePtr));
   3885 	    if (val1->nodeTab == NULL) {
   3886 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3887 		return(NULL);
   3888 	    }
   3889 	    memset(val1->nodeTab, 0 ,
   3890 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3891 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3892 	} else if (val1->nodeNr == val1->nodeMax) {
   3893 	    xmlNodePtr *temp;
   3894 
   3895             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3896                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   3897                 return(NULL);
   3898             }
   3899 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3900 					     sizeof(xmlNodePtr));
   3901 	    if (temp == NULL) {
   3902 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3903 		return(NULL);
   3904 	    }
   3905 	    val1->nodeTab = temp;
   3906 	    val1->nodeMax *= 2;
   3907 	}
   3908 	if (n2->type == XML_NAMESPACE_DECL) {
   3909 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3910 
   3911 	    val1->nodeTab[val1->nodeNr++] =
   3912 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3913 	} else
   3914 	    val1->nodeTab[val1->nodeNr++] = n2;
   3915     }
   3916 
   3917     return(val1);
   3918 }
   3919 
   3920 
   3921 /**
   3922  * xmlXPathNodeSetMergeAndClear:
   3923  * @set1:  the first NodeSet or NULL
   3924  * @set2:  the second NodeSet
   3925  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3926  *
   3927  * Merges two nodesets, all nodes from @set2 are added to @set1
   3928  * if @set1 is NULL, a new set is created and copied from @set2.
   3929  * Checks for duplicate nodes. Clears set2.
   3930  *
   3931  * Returns @set1 once extended or NULL in case of error.
   3932  */
   3933 static xmlNodeSetPtr
   3934 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3935 			     int hasNullEntries)
   3936 {
   3937     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3938 	/*
   3939 	* Note that doing a memcpy of the list, namespace nodes are
   3940 	* just assigned to set1, since set2 is cleared anyway.
   3941 	*/
   3942 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3943 	if (set1 == NULL)
   3944 	    return(NULL);
   3945 	if (set2->nodeNr != 0) {
   3946 	    memcpy(set1->nodeTab, set2->nodeTab,
   3947 		set2->nodeNr * sizeof(xmlNodePtr));
   3948 	    set1->nodeNr = set2->nodeNr;
   3949 	}
   3950     } else {
   3951 	int i, j, initNbSet1;
   3952 	xmlNodePtr n1, n2;
   3953 
   3954 	if (set1 == NULL)
   3955             set1 = xmlXPathNodeSetCreate(NULL);
   3956         if (set1 == NULL)
   3957             return (NULL);
   3958 
   3959 	initNbSet1 = set1->nodeNr;
   3960 	for (i = 0;i < set2->nodeNr;i++) {
   3961 	    n2 = set2->nodeTab[i];
   3962 	    /*
   3963 	    * Skip NULLed entries.
   3964 	    */
   3965 	    if (n2 == NULL)
   3966 		continue;
   3967 	    /*
   3968 	    * Skip duplicates.
   3969 	    */
   3970 	    for (j = 0; j < initNbSet1; j++) {
   3971 		n1 = set1->nodeTab[j];
   3972 		if (n1 == n2) {
   3973 		    goto skip_node;
   3974 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3975 		    (n2->type == XML_NAMESPACE_DECL))
   3976 		{
   3977 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3978 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3979 			((xmlNsPtr) n2)->prefix)))
   3980 		    {
   3981 			/*
   3982 			* Free the namespace node.
   3983 			*/
   3984 			set2->nodeTab[i] = NULL;
   3985 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3986 			goto skip_node;
   3987 		    }
   3988 		}
   3989 	    }
   3990 	    /*
   3991 	    * grow the nodeTab if needed
   3992 	    */
   3993 	    if (set1->nodeMax == 0) {
   3994 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3995 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3996 		if (set1->nodeTab == NULL) {
   3997 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3998 		    return(NULL);
   3999 		}
   4000 		memset(set1->nodeTab, 0,
   4001 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4002 		set1->nodeMax = XML_NODESET_DEFAULT;
   4003 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4004 		xmlNodePtr *temp;
   4005 
   4006                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4007                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4008                     return(NULL);
   4009                 }
   4010 		temp = (xmlNodePtr *) xmlRealloc(
   4011 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4012 		if (temp == NULL) {
   4013 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4014 		    return(NULL);
   4015 		}
   4016 		set1->nodeTab = temp;
   4017 		set1->nodeMax *= 2;
   4018 	    }
   4019 	    if (n2->type == XML_NAMESPACE_DECL) {
   4020 		xmlNsPtr ns = (xmlNsPtr) n2;
   4021 
   4022 		set1->nodeTab[set1->nodeNr++] =
   4023 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   4024 	    } else
   4025 		set1->nodeTab[set1->nodeNr++] = n2;
   4026 skip_node:
   4027 	    {}
   4028 	}
   4029     }
   4030     set2->nodeNr = 0;
   4031     return(set1);
   4032 }
   4033 
   4034 /**
   4035  * xmlXPathNodeSetMergeAndClearNoDupls:
   4036  * @set1:  the first NodeSet or NULL
   4037  * @set2:  the second NodeSet
   4038  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   4039  *
   4040  * Merges two nodesets, all nodes from @set2 are added to @set1
   4041  * if @set1 is NULL, a new set is created and copied from @set2.
   4042  * Doesn't chack for duplicate nodes. Clears set2.
   4043  *
   4044  * Returns @set1 once extended or NULL in case of error.
   4045  */
   4046 static xmlNodeSetPtr
   4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   4048 				    int hasNullEntries)
   4049 {
   4050     if (set2 == NULL)
   4051 	return(set1);
   4052     if ((set1 == NULL) && (hasNullEntries == 0)) {
   4053 	/*
   4054 	* Note that doing a memcpy of the list, namespace nodes are
   4055 	* just assigned to set1, since set2 is cleared anyway.
   4056 	*/
   4057 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4058 	if (set1 == NULL)
   4059 	    return(NULL);
   4060 	if (set2->nodeNr != 0) {
   4061 	    memcpy(set1->nodeTab, set2->nodeTab,
   4062 		set2->nodeNr * sizeof(xmlNodePtr));
   4063 	    set1->nodeNr = set2->nodeNr;
   4064 	}
   4065     } else {
   4066 	int i;
   4067 	xmlNodePtr n2;
   4068 
   4069 	if (set1 == NULL)
   4070 	    set1 = xmlXPathNodeSetCreate(NULL);
   4071         if (set1 == NULL)
   4072             return (NULL);
   4073 
   4074 	for (i = 0;i < set2->nodeNr;i++) {
   4075 	    n2 = set2->nodeTab[i];
   4076 	    /*
   4077 	    * Skip NULLed entries.
   4078 	    */
   4079 	    if (n2 == NULL)
   4080 		continue;
   4081 	    if (set1->nodeMax == 0) {
   4082 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4083 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4084 		if (set1->nodeTab == NULL) {
   4085 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4086 		    return(NULL);
   4087 		}
   4088 		memset(set1->nodeTab, 0,
   4089 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4090 		set1->nodeMax = XML_NODESET_DEFAULT;
   4091 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4092 		xmlNodePtr *temp;
   4093 
   4094                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4095                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4096                     return(NULL);
   4097                 }
   4098 		temp = (xmlNodePtr *) xmlRealloc(
   4099 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4100 		if (temp == NULL) {
   4101 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4102 		    return(NULL);
   4103 		}
   4104 		set1->nodeTab = temp;
   4105 		set1->nodeMax *= 2;
   4106 	    }
   4107 	    set1->nodeTab[set1->nodeNr++] = n2;
   4108 	}
   4109     }
   4110     set2->nodeNr = 0;
   4111     return(set1);
   4112 }
   4113 
   4114 /**
   4115  * xmlXPathNodeSetDel:
   4116  * @cur:  the initial node set
   4117  * @val:  an xmlNodePtr
   4118  *
   4119  * Removes an xmlNodePtr from an existing NodeSet
   4120  */
   4121 void
   4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4123     int i;
   4124 
   4125     if (cur == NULL) return;
   4126     if (val == NULL) return;
   4127 
   4128     /*
   4129      * find node in nodeTab
   4130      */
   4131     for (i = 0;i < cur->nodeNr;i++)
   4132         if (cur->nodeTab[i] == val) break;
   4133 
   4134     if (i >= cur->nodeNr) {	/* not found */
   4135 #ifdef DEBUG
   4136         xmlGenericError(xmlGenericErrorContext,
   4137 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4138 		val->name);
   4139 #endif
   4140         return;
   4141     }
   4142     if ((cur->nodeTab[i] != NULL) &&
   4143 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4144 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4145     cur->nodeNr--;
   4146     for (;i < cur->nodeNr;i++)
   4147         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4148     cur->nodeTab[cur->nodeNr] = NULL;
   4149 }
   4150 
   4151 /**
   4152  * xmlXPathNodeSetRemove:
   4153  * @cur:  the initial node set
   4154  * @val:  the index to remove
   4155  *
   4156  * Removes an entry from an existing NodeSet list.
   4157  */
   4158 void
   4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4160     if (cur == NULL) return;
   4161     if (val >= cur->nodeNr) return;
   4162     if ((cur->nodeTab[val] != NULL) &&
   4163 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4164 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4165     cur->nodeNr--;
   4166     for (;val < cur->nodeNr;val++)
   4167         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4168     cur->nodeTab[cur->nodeNr] = NULL;
   4169 }
   4170 
   4171 /**
   4172  * xmlXPathFreeNodeSet:
   4173  * @obj:  the xmlNodeSetPtr to free
   4174  *
   4175  * Free the NodeSet compound (not the actual nodes !).
   4176  */
   4177 void
   4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4179     if (obj == NULL) return;
   4180     if (obj->nodeTab != NULL) {
   4181 	int i;
   4182 
   4183 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4184 	for (i = 0;i < obj->nodeNr;i++)
   4185 	    if ((obj->nodeTab[i] != NULL) &&
   4186 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4187 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4188 	xmlFree(obj->nodeTab);
   4189     }
   4190     xmlFree(obj);
   4191 }
   4192 
   4193 /**
   4194  * xmlXPathNodeSetClear:
   4195  * @set:  the node set to clear
   4196  *
   4197  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4198  * are feed), but does *not* free the list itself. Sets the length of the
   4199  * list to 0.
   4200  */
   4201 static void
   4202 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4203 {
   4204     if ((set == NULL) || (set->nodeNr <= 0))
   4205 	return;
   4206     else if (hasNsNodes) {
   4207 	int i;
   4208 	xmlNodePtr node;
   4209 
   4210 	for (i = 0; i < set->nodeNr; i++) {
   4211 	    node = set->nodeTab[i];
   4212 	    if ((node != NULL) &&
   4213 		(node->type == XML_NAMESPACE_DECL))
   4214 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4215 	}
   4216     }
   4217     set->nodeNr = 0;
   4218 }
   4219 
   4220 /**
   4221  * xmlXPathNodeSetClearFromPos:
   4222  * @set: the node set to be cleared
   4223  * @pos: the start position to clear from
   4224  *
   4225  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4226  * are feed) starting with the entry at @pos, but does *not* free the list
   4227  * itself. Sets the length of the list to @pos.
   4228  */
   4229 static void
   4230 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4231 {
   4232     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4233 	return;
   4234     else if ((hasNsNodes)) {
   4235 	int i;
   4236 	xmlNodePtr node;
   4237 
   4238 	for (i = pos; i < set->nodeNr; i++) {
   4239 	    node = set->nodeTab[i];
   4240 	    if ((node != NULL) &&
   4241 		(node->type == XML_NAMESPACE_DECL))
   4242 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4243 	}
   4244     }
   4245     set->nodeNr = pos;
   4246 }
   4247 
   4248 /**
   4249  * xmlXPathFreeValueTree:
   4250  * @obj:  the xmlNodeSetPtr to free
   4251  *
   4252  * Free the NodeSet compound and the actual tree, this is different
   4253  * from xmlXPathFreeNodeSet()
   4254  */
   4255 static void
   4256 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4257     int i;
   4258 
   4259     if (obj == NULL) return;
   4260 
   4261     if (obj->nodeTab != NULL) {
   4262 	for (i = 0;i < obj->nodeNr;i++) {
   4263 	    if (obj->nodeTab[i] != NULL) {
   4264 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4265 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4266 		} else {
   4267 		    xmlFreeNodeList(obj->nodeTab[i]);
   4268 		}
   4269 	    }
   4270 	}
   4271 	xmlFree(obj->nodeTab);
   4272     }
   4273     xmlFree(obj);
   4274 }
   4275 
   4276 #if defined(DEBUG) || defined(DEBUG_STEP)
   4277 /**
   4278  * xmlGenericErrorContextNodeSet:
   4279  * @output:  a FILE * for the output
   4280  * @obj:  the xmlNodeSetPtr to display
   4281  *
   4282  * Quick display of a NodeSet
   4283  */
   4284 void
   4285 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4286     int i;
   4287 
   4288     if (output == NULL) output = xmlGenericErrorContext;
   4289     if (obj == NULL)  {
   4290         fprintf(output, "NodeSet == NULL !\n");
   4291 	return;
   4292     }
   4293     if (obj->nodeNr == 0) {
   4294         fprintf(output, "NodeSet is empty\n");
   4295 	return;
   4296     }
   4297     if (obj->nodeTab == NULL) {
   4298 	fprintf(output, " nodeTab == NULL !\n");
   4299 	return;
   4300     }
   4301     for (i = 0; i < obj->nodeNr; i++) {
   4302         if (obj->nodeTab[i] == NULL) {
   4303 	    fprintf(output, " NULL !\n");
   4304 	    return;
   4305         }
   4306 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4307 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4308 	    fprintf(output, " /");
   4309 	else if (obj->nodeTab[i]->name == NULL)
   4310 	    fprintf(output, " noname!");
   4311 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4312     }
   4313     fprintf(output, "\n");
   4314 }
   4315 #endif
   4316 
   4317 /**
   4318  * xmlXPathNewNodeSet:
   4319  * @val:  the NodePtr value
   4320  *
   4321  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4322  * it with the single Node @val
   4323  *
   4324  * Returns the newly created object.
   4325  */
   4326 xmlXPathObjectPtr
   4327 xmlXPathNewNodeSet(xmlNodePtr val) {
   4328     xmlXPathObjectPtr ret;
   4329 
   4330     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4331     if (ret == NULL) {
   4332         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4333 	return(NULL);
   4334     }
   4335     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4336     ret->type = XPATH_NODESET;
   4337     ret->boolval = 0;
   4338     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4339     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4340 #ifdef XP_DEBUG_OBJ_USAGE
   4341     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4342 #endif
   4343     return(ret);
   4344 }
   4345 
   4346 /**
   4347  * xmlXPathNewValueTree:
   4348  * @val:  the NodePtr value
   4349  *
   4350  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4351  * it with the tree root @val
   4352  *
   4353  * Returns the newly created object.
   4354  */
   4355 xmlXPathObjectPtr
   4356 xmlXPathNewValueTree(xmlNodePtr val) {
   4357     xmlXPathObjectPtr ret;
   4358 
   4359     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4360     if (ret == NULL) {
   4361         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4362 	return(NULL);
   4363     }
   4364     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4365     ret->type = XPATH_XSLT_TREE;
   4366     ret->boolval = 1;
   4367     ret->user = (void *) val;
   4368     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4369 #ifdef XP_DEBUG_OBJ_USAGE
   4370     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4371 #endif
   4372     return(ret);
   4373 }
   4374 
   4375 /**
   4376  * xmlXPathNewNodeSetList:
   4377  * @val:  an existing NodeSet
   4378  *
   4379  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4380  * it with the Nodeset @val
   4381  *
   4382  * Returns the newly created object.
   4383  */
   4384 xmlXPathObjectPtr
   4385 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4386 {
   4387     xmlXPathObjectPtr ret;
   4388     int i;
   4389 
   4390     if (val == NULL)
   4391         ret = NULL;
   4392     else if (val->nodeTab == NULL)
   4393         ret = xmlXPathNewNodeSet(NULL);
   4394     else {
   4395         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4396         if (ret) {
   4397             for (i = 1; i < val->nodeNr; ++i) {
   4398                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
   4399 		    < 0) break;
   4400 	    }
   4401 	}
   4402     }
   4403 
   4404     return (ret);
   4405 }
   4406 
   4407 /**
   4408  * xmlXPathWrapNodeSet:
   4409  * @val:  the NodePtr value
   4410  *
   4411  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4412  *
   4413  * Returns the newly created object.
   4414  */
   4415 xmlXPathObjectPtr
   4416 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4417     xmlXPathObjectPtr ret;
   4418 
   4419     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4420     if (ret == NULL) {
   4421         xmlXPathErrMemory(NULL, "creating node set object\n");
   4422 	return(NULL);
   4423     }
   4424     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4425     ret->type = XPATH_NODESET;
   4426     ret->nodesetval = val;
   4427 #ifdef XP_DEBUG_OBJ_USAGE
   4428     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4429 #endif
   4430     return(ret);
   4431 }
   4432 
   4433 /**
   4434  * xmlXPathFreeNodeSetList:
   4435  * @obj:  an existing NodeSetList object
   4436  *
   4437  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4438  * the list contrary to xmlXPathFreeObject().
   4439  */
   4440 void
   4441 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4442     if (obj == NULL) return;
   4443 #ifdef XP_DEBUG_OBJ_USAGE
   4444     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4445 #endif
   4446     xmlFree(obj);
   4447 }
   4448 
   4449 /**
   4450  * xmlXPathDifference:
   4451  * @nodes1:  a node-set
   4452  * @nodes2:  a node-set
   4453  *
   4454  * Implements the EXSLT - Sets difference() function:
   4455  *    node-set set:difference (node-set, node-set)
   4456  *
   4457  * Returns the difference between the two node sets, or nodes1 if
   4458  *         nodes2 is empty
   4459  */
   4460 xmlNodeSetPtr
   4461 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4462     xmlNodeSetPtr ret;
   4463     int i, l1;
   4464     xmlNodePtr cur;
   4465 
   4466     if (xmlXPathNodeSetIsEmpty(nodes2))
   4467 	return(nodes1);
   4468 
   4469     ret = xmlXPathNodeSetCreate(NULL);
   4470     if (xmlXPathNodeSetIsEmpty(nodes1))
   4471 	return(ret);
   4472 
   4473     l1 = xmlXPathNodeSetGetLength(nodes1);
   4474 
   4475     for (i = 0; i < l1; i++) {
   4476 	cur = xmlXPathNodeSetItem(nodes1, i);
   4477 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
   4478 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4479 	        break;
   4480 	}
   4481     }
   4482     return(ret);
   4483 }
   4484 
   4485 /**
   4486  * xmlXPathIntersection:
   4487  * @nodes1:  a node-set
   4488  * @nodes2:  a node-set
   4489  *
   4490  * Implements the EXSLT - Sets intersection() function:
   4491  *    node-set set:intersection (node-set, node-set)
   4492  *
   4493  * Returns a node set comprising the nodes that are within both the
   4494  *         node sets passed as arguments
   4495  */
   4496 xmlNodeSetPtr
   4497 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4498     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4499     int i, l1;
   4500     xmlNodePtr cur;
   4501 
   4502     if (ret == NULL)
   4503         return(ret);
   4504     if (xmlXPathNodeSetIsEmpty(nodes1))
   4505 	return(ret);
   4506     if (xmlXPathNodeSetIsEmpty(nodes2))
   4507 	return(ret);
   4508 
   4509     l1 = xmlXPathNodeSetGetLength(nodes1);
   4510 
   4511     for (i = 0; i < l1; i++) {
   4512 	cur = xmlXPathNodeSetItem(nodes1, i);
   4513 	if (xmlXPathNodeSetContains(nodes2, cur)) {
   4514 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4515 	        break;
   4516 	}
   4517     }
   4518     return(ret);
   4519 }
   4520 
   4521 /**
   4522  * xmlXPathDistinctSorted:
   4523  * @nodes:  a node-set, sorted by document order
   4524  *
   4525  * Implements the EXSLT - Sets distinct() function:
   4526  *    node-set set:distinct (node-set)
   4527  *
   4528  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4529  *         it is empty
   4530  */
   4531 xmlNodeSetPtr
   4532 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4533     xmlNodeSetPtr ret;
   4534     xmlHashTablePtr hash;
   4535     int i, l;
   4536     xmlChar * strval;
   4537     xmlNodePtr cur;
   4538 
   4539     if (xmlXPathNodeSetIsEmpty(nodes))
   4540 	return(nodes);
   4541 
   4542     ret = xmlXPathNodeSetCreate(NULL);
   4543     if (ret == NULL)
   4544         return(ret);
   4545     l = xmlXPathNodeSetGetLength(nodes);
   4546     hash = xmlHashCreate (l);
   4547     for (i = 0; i < l; i++) {
   4548 	cur = xmlXPathNodeSetItem(nodes, i);
   4549 	strval = xmlXPathCastNodeToString(cur);
   4550 	if (xmlHashLookup(hash, strval) == NULL) {
   4551 	    xmlHashAddEntry(hash, strval, strval);
   4552 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4553 	        break;
   4554 	} else {
   4555 	    xmlFree(strval);
   4556 	}
   4557     }
   4558     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4559     return(ret);
   4560 }
   4561 
   4562 /**
   4563  * xmlXPathDistinct:
   4564  * @nodes:  a node-set
   4565  *
   4566  * Implements the EXSLT - Sets distinct() function:
   4567  *    node-set set:distinct (node-set)
   4568  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4569  * is called with the sorted node-set
   4570  *
   4571  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4572  *         it is empty
   4573  */
   4574 xmlNodeSetPtr
   4575 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4576     if (xmlXPathNodeSetIsEmpty(nodes))
   4577 	return(nodes);
   4578 
   4579     xmlXPathNodeSetSort(nodes);
   4580     return(xmlXPathDistinctSorted(nodes));
   4581 }
   4582 
   4583 /**
   4584  * xmlXPathHasSameNodes:
   4585  * @nodes1:  a node-set
   4586  * @nodes2:  a node-set
   4587  *
   4588  * Implements the EXSLT - Sets has-same-nodes function:
   4589  *    boolean set:has-same-node(node-set, node-set)
   4590  *
   4591  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4592  *         otherwise
   4593  */
   4594 int
   4595 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4596     int i, l;
   4597     xmlNodePtr cur;
   4598 
   4599     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4600 	xmlXPathNodeSetIsEmpty(nodes2))
   4601 	return(0);
   4602 
   4603     l = xmlXPathNodeSetGetLength(nodes1);
   4604     for (i = 0; i < l; i++) {
   4605 	cur = xmlXPathNodeSetItem(nodes1, i);
   4606 	if (xmlXPathNodeSetContains(nodes2, cur))
   4607 	    return(1);
   4608     }
   4609     return(0);
   4610 }
   4611 
   4612 /**
   4613  * xmlXPathNodeLeadingSorted:
   4614  * @nodes: a node-set, sorted by document order
   4615  * @node: a node
   4616  *
   4617  * Implements the EXSLT - Sets leading() function:
   4618  *    node-set set:leading (node-set, node-set)
   4619  *
   4620  * Returns the nodes in @nodes that precede @node in document order,
   4621  *         @nodes if @node is NULL or an empty node-set if @nodes
   4622  *         doesn't contain @node
   4623  */
   4624 xmlNodeSetPtr
   4625 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4626     int i, l;
   4627     xmlNodePtr cur;
   4628     xmlNodeSetPtr ret;
   4629 
   4630     if (node == NULL)
   4631 	return(nodes);
   4632 
   4633     ret = xmlXPathNodeSetCreate(NULL);
   4634     if (ret == NULL)
   4635         return(ret);
   4636     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4637 	(!xmlXPathNodeSetContains(nodes, node)))
   4638 	return(ret);
   4639 
   4640     l = xmlXPathNodeSetGetLength(nodes);
   4641     for (i = 0; i < l; i++) {
   4642 	cur = xmlXPathNodeSetItem(nodes, i);
   4643 	if (cur == node)
   4644 	    break;
   4645 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4646 	    break;
   4647     }
   4648     return(ret);
   4649 }
   4650 
   4651 /**
   4652  * xmlXPathNodeLeading:
   4653  * @nodes:  a node-set
   4654  * @node:  a node
   4655  *
   4656  * Implements the EXSLT - Sets leading() function:
   4657  *    node-set set:leading (node-set, node-set)
   4658  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4659  * is called.
   4660  *
   4661  * Returns the nodes in @nodes that precede @node in document order,
   4662  *         @nodes if @node is NULL or an empty node-set if @nodes
   4663  *         doesn't contain @node
   4664  */
   4665 xmlNodeSetPtr
   4666 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4667     xmlXPathNodeSetSort(nodes);
   4668     return(xmlXPathNodeLeadingSorted(nodes, node));
   4669 }
   4670 
   4671 /**
   4672  * xmlXPathLeadingSorted:
   4673  * @nodes1:  a node-set, sorted by document order
   4674  * @nodes2:  a node-set, sorted by document order
   4675  *
   4676  * Implements the EXSLT - Sets leading() function:
   4677  *    node-set set:leading (node-set, node-set)
   4678  *
   4679  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4680  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4681  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4682  */
   4683 xmlNodeSetPtr
   4684 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4685     if (xmlXPathNodeSetIsEmpty(nodes2))
   4686 	return(nodes1);
   4687     return(xmlXPathNodeLeadingSorted(nodes1,
   4688 				     xmlXPathNodeSetItem(nodes2, 1)));
   4689 }
   4690 
   4691 /**
   4692  * xmlXPathLeading:
   4693  * @nodes1:  a node-set
   4694  * @nodes2:  a node-set
   4695  *
   4696  * Implements the EXSLT - Sets leading() function:
   4697  *    node-set set:leading (node-set, node-set)
   4698  * @nodes1 and @nodes2 are sorted by document order, then
   4699  * #exslSetsLeadingSorted is called.
   4700  *
   4701  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4702  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4703  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4704  */
   4705 xmlNodeSetPtr
   4706 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4707     if (xmlXPathNodeSetIsEmpty(nodes2))
   4708 	return(nodes1);
   4709     if (xmlXPathNodeSetIsEmpty(nodes1))
   4710 	return(xmlXPathNodeSetCreate(NULL));
   4711     xmlXPathNodeSetSort(nodes1);
   4712     xmlXPathNodeSetSort(nodes2);
   4713     return(xmlXPathNodeLeadingSorted(nodes1,
   4714 				     xmlXPathNodeSetItem(nodes2, 1)));
   4715 }
   4716 
   4717 /**
   4718  * xmlXPathNodeTrailingSorted:
   4719  * @nodes: a node-set, sorted by document order
   4720  * @node: a node
   4721  *
   4722  * Implements the EXSLT - Sets trailing() function:
   4723  *    node-set set:trailing (node-set, node-set)
   4724  *
   4725  * Returns the nodes in @nodes that follow @node in document order,
   4726  *         @nodes if @node is NULL or an empty node-set if @nodes
   4727  *         doesn't contain @node
   4728  */
   4729 xmlNodeSetPtr
   4730 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4731     int i, l;
   4732     xmlNodePtr cur;
   4733     xmlNodeSetPtr ret;
   4734 
   4735     if (node == NULL)
   4736 	return(nodes);
   4737 
   4738     ret = xmlXPathNodeSetCreate(NULL);
   4739     if (ret == NULL)
   4740         return(ret);
   4741     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4742 	(!xmlXPathNodeSetContains(nodes, node)))
   4743 	return(ret);
   4744 
   4745     l = xmlXPathNodeSetGetLength(nodes);
   4746     for (i = l - 1; i >= 0; i--) {
   4747 	cur = xmlXPathNodeSetItem(nodes, i);
   4748 	if (cur == node)
   4749 	    break;
   4750 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4751 	    break;
   4752     }
   4753     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4754     return(ret);
   4755 }
   4756 
   4757 /**
   4758  * xmlXPathNodeTrailing:
   4759  * @nodes:  a node-set
   4760  * @node:  a node
   4761  *
   4762  * Implements the EXSLT - Sets trailing() function:
   4763  *    node-set set:trailing (node-set, node-set)
   4764  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4765  * is called.
   4766  *
   4767  * Returns the nodes in @nodes that follow @node in document order,
   4768  *         @nodes if @node is NULL or an empty node-set if @nodes
   4769  *         doesn't contain @node
   4770  */
   4771 xmlNodeSetPtr
   4772 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4773     xmlXPathNodeSetSort(nodes);
   4774     return(xmlXPathNodeTrailingSorted(nodes, node));
   4775 }
   4776 
   4777 /**
   4778  * xmlXPathTrailingSorted:
   4779  * @nodes1:  a node-set, sorted by document order
   4780  * @nodes2:  a node-set, sorted by document order
   4781  *
   4782  * Implements the EXSLT - Sets trailing() function:
   4783  *    node-set set:trailing (node-set, node-set)
   4784  *
   4785  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4786  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4787  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4788  */
   4789 xmlNodeSetPtr
   4790 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4791     if (xmlXPathNodeSetIsEmpty(nodes2))
   4792 	return(nodes1);
   4793     return(xmlXPathNodeTrailingSorted(nodes1,
   4794 				      xmlXPathNodeSetItem(nodes2, 0)));
   4795 }
   4796 
   4797 /**
   4798  * xmlXPathTrailing:
   4799  * @nodes1:  a node-set
   4800  * @nodes2:  a node-set
   4801  *
   4802  * Implements the EXSLT - Sets trailing() function:
   4803  *    node-set set:trailing (node-set, node-set)
   4804  * @nodes1 and @nodes2 are sorted by document order, then
   4805  * #xmlXPathTrailingSorted is called.
   4806  *
   4807  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4808  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4809  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4810  */
   4811 xmlNodeSetPtr
   4812 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4813     if (xmlXPathNodeSetIsEmpty(nodes2))
   4814 	return(nodes1);
   4815     if (xmlXPathNodeSetIsEmpty(nodes1))
   4816 	return(xmlXPathNodeSetCreate(NULL));
   4817     xmlXPathNodeSetSort(nodes1);
   4818     xmlXPathNodeSetSort(nodes2);
   4819     return(xmlXPathNodeTrailingSorted(nodes1,
   4820 				      xmlXPathNodeSetItem(nodes2, 0)));
   4821 }
   4822 
   4823 /************************************************************************
   4824  *									*
   4825  *		Routines to handle extra functions			*
   4826  *									*
   4827  ************************************************************************/
   4828 
   4829 /**
   4830  * xmlXPathRegisterFunc:
   4831  * @ctxt:  the XPath context
   4832  * @name:  the function name
   4833  * @f:  the function implementation or NULL
   4834  *
   4835  * Register a new function. If @f is NULL it unregisters the function
   4836  *
   4837  * Returns 0 in case of success, -1 in case of error
   4838  */
   4839 int
   4840 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4841 		     xmlXPathFunction f) {
   4842     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4843 }
   4844 
   4845 /**
   4846  * xmlXPathRegisterFuncNS:
   4847  * @ctxt:  the XPath context
   4848  * @name:  the function name
   4849  * @ns_uri:  the function namespace URI
   4850  * @f:  the function implementation or NULL
   4851  *
   4852  * Register a new function. If @f is NULL it unregisters the function
   4853  *
   4854  * Returns 0 in case of success, -1 in case of error
   4855  */
   4856 int
   4857 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4858 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4859     if (ctxt == NULL)
   4860 	return(-1);
   4861     if (name == NULL)
   4862 	return(-1);
   4863 
   4864     if (ctxt->funcHash == NULL)
   4865 	ctxt->funcHash = xmlHashCreate(0);
   4866     if (ctxt->funcHash == NULL)
   4867 	return(-1);
   4868     if (f == NULL)
   4869         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4870     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
   4871 }
   4872 
   4873 /**
   4874  * xmlXPathRegisterFuncLookup:
   4875  * @ctxt:  the XPath context
   4876  * @f:  the lookup function
   4877  * @funcCtxt:  the lookup data
   4878  *
   4879  * Registers an external mechanism to do function lookup.
   4880  */
   4881 void
   4882 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4883 			    xmlXPathFuncLookupFunc f,
   4884 			    void *funcCtxt) {
   4885     if (ctxt == NULL)
   4886 	return;
   4887     ctxt->funcLookupFunc = f;
   4888     ctxt->funcLookupData = funcCtxt;
   4889 }
   4890 
   4891 /**
   4892  * xmlXPathFunctionLookup:
   4893  * @ctxt:  the XPath context
   4894  * @name:  the function name
   4895  *
   4896  * Search in the Function array of the context for the given
   4897  * function.
   4898  *
   4899  * Returns the xmlXPathFunction or NULL if not found
   4900  */
   4901 xmlXPathFunction
   4902 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4903     if (ctxt == NULL)
   4904 	return (NULL);
   4905 
   4906     if (ctxt->funcLookupFunc != NULL) {
   4907 	xmlXPathFunction ret;
   4908 	xmlXPathFuncLookupFunc f;
   4909 
   4910 	f = ctxt->funcLookupFunc;
   4911 	ret = f(ctxt->funcLookupData, name, NULL);
   4912 	if (ret != NULL)
   4913 	    return(ret);
   4914     }
   4915     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4916 }
   4917 
   4918 /**
   4919  * xmlXPathFunctionLookupNS:
   4920  * @ctxt:  the XPath context
   4921  * @name:  the function name
   4922  * @ns_uri:  the function namespace URI
   4923  *
   4924  * Search in the Function array of the context for the given
   4925  * function.
   4926  *
   4927  * Returns the xmlXPathFunction or NULL if not found
   4928  */
   4929 xmlXPathFunction
   4930 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4931 			 const xmlChar *ns_uri) {
   4932     xmlXPathFunction ret;
   4933 
   4934     if (ctxt == NULL)
   4935 	return(NULL);
   4936     if (name == NULL)
   4937 	return(NULL);
   4938 
   4939     if (ctxt->funcLookupFunc != NULL) {
   4940 	xmlXPathFuncLookupFunc f;
   4941 
   4942 	f = ctxt->funcLookupFunc;
   4943 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4944 	if (ret != NULL)
   4945 	    return(ret);
   4946     }
   4947 
   4948     if (ctxt->funcHash == NULL)
   4949 	return(NULL);
   4950 
   4951     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4952     return(ret);
   4953 }
   4954 
   4955 /**
   4956  * xmlXPathRegisteredFuncsCleanup:
   4957  * @ctxt:  the XPath context
   4958  *
   4959  * Cleanup the XPath context data associated to registered functions
   4960  */
   4961 void
   4962 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4963     if (ctxt == NULL)
   4964 	return;
   4965 
   4966     xmlHashFree(ctxt->funcHash, NULL);
   4967     ctxt->funcHash = NULL;
   4968 }
   4969 
   4970 /************************************************************************
   4971  *									*
   4972  *			Routines to handle Variables			*
   4973  *									*
   4974  ************************************************************************/
   4975 
   4976 /**
   4977  * xmlXPathRegisterVariable:
   4978  * @ctxt:  the XPath context
   4979  * @name:  the variable name
   4980  * @value:  the variable value or NULL
   4981  *
   4982  * Register a new variable value. If @value is NULL it unregisters
   4983  * the variable
   4984  *
   4985  * Returns 0 in case of success, -1 in case of error
   4986  */
   4987 int
   4988 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   4989 			 xmlXPathObjectPtr value) {
   4990     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   4991 }
   4992 
   4993 /**
   4994  * xmlXPathRegisterVariableNS:
   4995  * @ctxt:  the XPath context
   4996  * @name:  the variable name
   4997  * @ns_uri:  the variable namespace URI
   4998  * @value:  the variable value or NULL
   4999  *
   5000  * Register a new variable value. If @value is NULL it unregisters
   5001  * the variable
   5002  *
   5003  * Returns 0 in case of success, -1 in case of error
   5004  */
   5005 int
   5006 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5007 			   const xmlChar *ns_uri,
   5008 			   xmlXPathObjectPtr value) {
   5009     if (ctxt == NULL)
   5010 	return(-1);
   5011     if (name == NULL)
   5012 	return(-1);
   5013 
   5014     if (ctxt->varHash == NULL)
   5015 	ctxt->varHash = xmlHashCreate(0);
   5016     if (ctxt->varHash == NULL)
   5017 	return(-1);
   5018     if (value == NULL)
   5019         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   5020 	                           (xmlHashDeallocator)xmlXPathFreeObject));
   5021     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   5022 			       (void *) value,
   5023 			       (xmlHashDeallocator)xmlXPathFreeObject));
   5024 }
   5025 
   5026 /**
   5027  * xmlXPathRegisterVariableLookup:
   5028  * @ctxt:  the XPath context
   5029  * @f:  the lookup function
   5030  * @data:  the lookup data
   5031  *
   5032  * register an external mechanism to do variable lookup
   5033  */
   5034 void
   5035 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   5036 	 xmlXPathVariableLookupFunc f, void *data) {
   5037     if (ctxt == NULL)
   5038 	return;
   5039     ctxt->varLookupFunc = f;
   5040     ctxt->varLookupData = data;
   5041 }
   5042 
   5043 /**
   5044  * xmlXPathVariableLookup:
   5045  * @ctxt:  the XPath context
   5046  * @name:  the variable name
   5047  *
   5048  * Search in the Variable array of the context for the given
   5049  * variable value.
   5050  *
   5051  * Returns a copy of the value or NULL if not found
   5052  */
   5053 xmlXPathObjectPtr
   5054 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   5055     if (ctxt == NULL)
   5056 	return(NULL);
   5057 
   5058     if (ctxt->varLookupFunc != NULL) {
   5059 	xmlXPathObjectPtr ret;
   5060 
   5061 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5062 	        (ctxt->varLookupData, name, NULL);
   5063 	return(ret);
   5064     }
   5065     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   5066 }
   5067 
   5068 /**
   5069  * xmlXPathVariableLookupNS:
   5070  * @ctxt:  the XPath context
   5071  * @name:  the variable name
   5072  * @ns_uri:  the variable namespace URI
   5073  *
   5074  * Search in the Variable array of the context for the given
   5075  * variable value.
   5076  *
   5077  * Returns the a copy of the value or NULL if not found
   5078  */
   5079 xmlXPathObjectPtr
   5080 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5081 			 const xmlChar *ns_uri) {
   5082     if (ctxt == NULL)
   5083 	return(NULL);
   5084 
   5085     if (ctxt->varLookupFunc != NULL) {
   5086 	xmlXPathObjectPtr ret;
   5087 
   5088 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5089 	        (ctxt->varLookupData, name, ns_uri);
   5090 	if (ret != NULL) return(ret);
   5091     }
   5092 
   5093     if (ctxt->varHash == NULL)
   5094 	return(NULL);
   5095     if (name == NULL)
   5096 	return(NULL);
   5097 
   5098     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   5099 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   5100 }
   5101 
   5102 /**
   5103  * xmlXPathRegisteredVariablesCleanup:
   5104  * @ctxt:  the XPath context
   5105  *
   5106  * Cleanup the XPath context data associated to registered variables
   5107  */
   5108 void
   5109 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   5110     if (ctxt == NULL)
   5111 	return;
   5112 
   5113     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
   5114     ctxt->varHash = NULL;
   5115 }
   5116 
   5117 /**
   5118  * xmlXPathRegisterNs:
   5119  * @ctxt:  the XPath context
   5120  * @prefix:  the namespace prefix cannot be NULL or empty string
   5121  * @ns_uri:  the namespace name
   5122  *
   5123  * Register a new namespace. If @ns_uri is NULL it unregisters
   5124  * the namespace
   5125  *
   5126  * Returns 0 in case of success, -1 in case of error
   5127  */
   5128 int
   5129 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5130 			   const xmlChar *ns_uri) {
   5131     if (ctxt == NULL)
   5132 	return(-1);
   5133     if (prefix == NULL)
   5134 	return(-1);
   5135     if (prefix[0] == 0)
   5136 	return(-1);
   5137 
   5138     if (ctxt->nsHash == NULL)
   5139 	ctxt->nsHash = xmlHashCreate(10);
   5140     if (ctxt->nsHash == NULL)
   5141 	return(-1);
   5142     if (ns_uri == NULL)
   5143         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5144 	                          (xmlHashDeallocator)xmlFree));
   5145     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5146 			      (xmlHashDeallocator)xmlFree));
   5147 }
   5148 
   5149 /**
   5150  * xmlXPathNsLookup:
   5151  * @ctxt:  the XPath context
   5152  * @prefix:  the namespace prefix value
   5153  *
   5154  * Search in the namespace declaration array of the context for the given
   5155  * namespace name associated to the given prefix
   5156  *
   5157  * Returns the value or NULL if not found
   5158  */
   5159 const xmlChar *
   5160 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5161     if (ctxt == NULL)
   5162 	return(NULL);
   5163     if (prefix == NULL)
   5164 	return(NULL);
   5165 
   5166 #ifdef XML_XML_NAMESPACE
   5167     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5168 	return(XML_XML_NAMESPACE);
   5169 #endif
   5170 
   5171     if (ctxt->namespaces != NULL) {
   5172 	int i;
   5173 
   5174 	for (i = 0;i < ctxt->nsNr;i++) {
   5175 	    if ((ctxt->namespaces[i] != NULL) &&
   5176 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5177 		return(ctxt->namespaces[i]->href);
   5178 	}
   5179     }
   5180 
   5181     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5182 }
   5183 
   5184 /**
   5185  * xmlXPathRegisteredNsCleanup:
   5186  * @ctxt:  the XPath context
   5187  *
   5188  * Cleanup the XPath context data associated to registered variables
   5189  */
   5190 void
   5191 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5192     if (ctxt == NULL)
   5193 	return;
   5194 
   5195     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
   5196     ctxt->nsHash = NULL;
   5197 }
   5198 
   5199 /************************************************************************
   5200  *									*
   5201  *			Routines to handle Values			*
   5202  *									*
   5203  ************************************************************************/
   5204 
   5205 /* Allocations are terrible, one needs to optimize all this !!! */
   5206 
   5207 /**
   5208  * xmlXPathNewFloat:
   5209  * @val:  the double value
   5210  *
   5211  * Create a new xmlXPathObjectPtr of type double and of value @val
   5212  *
   5213  * Returns the newly created object.
   5214  */
   5215 xmlXPathObjectPtr
   5216 xmlXPathNewFloat(double val) {
   5217     xmlXPathObjectPtr ret;
   5218 
   5219     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5220     if (ret == NULL) {
   5221         xmlXPathErrMemory(NULL, "creating float object\n");
   5222 	return(NULL);
   5223     }
   5224     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5225     ret->type = XPATH_NUMBER;
   5226     ret->floatval = val;
   5227 #ifdef XP_DEBUG_OBJ_USAGE
   5228     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5229 #endif
   5230     return(ret);
   5231 }
   5232 
   5233 /**
   5234  * xmlXPathNewBoolean:
   5235  * @val:  the boolean value
   5236  *
   5237  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5238  *
   5239  * Returns the newly created object.
   5240  */
   5241 xmlXPathObjectPtr
   5242 xmlXPathNewBoolean(int val) {
   5243     xmlXPathObjectPtr ret;
   5244 
   5245     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5246     if (ret == NULL) {
   5247         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5248 	return(NULL);
   5249     }
   5250     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5251     ret->type = XPATH_BOOLEAN;
   5252     ret->boolval = (val != 0);
   5253 #ifdef XP_DEBUG_OBJ_USAGE
   5254     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5255 #endif
   5256     return(ret);
   5257 }
   5258 
   5259 /**
   5260  * xmlXPathNewString:
   5261  * @val:  the xmlChar * value
   5262  *
   5263  * Create a new xmlXPathObjectPtr of type string and of value @val
   5264  *
   5265  * Returns the newly created object.
   5266  */
   5267 xmlXPathObjectPtr
   5268 xmlXPathNewString(const xmlChar *val) {
   5269     xmlXPathObjectPtr ret;
   5270 
   5271     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5272     if (ret == NULL) {
   5273         xmlXPathErrMemory(NULL, "creating string object\n");
   5274 	return(NULL);
   5275     }
   5276     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5277     ret->type = XPATH_STRING;
   5278     if (val != NULL)
   5279 	ret->stringval = xmlStrdup(val);
   5280     else
   5281 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5282 #ifdef XP_DEBUG_OBJ_USAGE
   5283     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5284 #endif
   5285     return(ret);
   5286 }
   5287 
   5288 /**
   5289  * xmlXPathWrapString:
   5290  * @val:  the xmlChar * value
   5291  *
   5292  * Wraps the @val string into an XPath object.
   5293  *
   5294  * Returns the newly created object.
   5295  */
   5296 xmlXPathObjectPtr
   5297 xmlXPathWrapString (xmlChar *val) {
   5298     xmlXPathObjectPtr ret;
   5299 
   5300     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5301     if (ret == NULL) {
   5302         xmlXPathErrMemory(NULL, "creating string object\n");
   5303 	return(NULL);
   5304     }
   5305     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5306     ret->type = XPATH_STRING;
   5307     ret->stringval = val;
   5308 #ifdef XP_DEBUG_OBJ_USAGE
   5309     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5310 #endif
   5311     return(ret);
   5312 }
   5313 
   5314 /**
   5315  * xmlXPathNewCString:
   5316  * @val:  the char * value
   5317  *
   5318  * Create a new xmlXPathObjectPtr of type string and of value @val
   5319  *
   5320  * Returns the newly created object.
   5321  */
   5322 xmlXPathObjectPtr
   5323 xmlXPathNewCString(const char *val) {
   5324     xmlXPathObjectPtr ret;
   5325 
   5326     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5327     if (ret == NULL) {
   5328         xmlXPathErrMemory(NULL, "creating string object\n");
   5329 	return(NULL);
   5330     }
   5331     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5332     ret->type = XPATH_STRING;
   5333     ret->stringval = xmlStrdup(BAD_CAST val);
   5334 #ifdef XP_DEBUG_OBJ_USAGE
   5335     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5336 #endif
   5337     return(ret);
   5338 }
   5339 
   5340 /**
   5341  * xmlXPathWrapCString:
   5342  * @val:  the char * value
   5343  *
   5344  * Wraps a string into an XPath object.
   5345  *
   5346  * Returns the newly created object.
   5347  */
   5348 xmlXPathObjectPtr
   5349 xmlXPathWrapCString (char * val) {
   5350     return(xmlXPathWrapString((xmlChar *)(val)));
   5351 }
   5352 
   5353 /**
   5354  * xmlXPathWrapExternal:
   5355  * @val:  the user data
   5356  *
   5357  * Wraps the @val data into an XPath object.
   5358  *
   5359  * Returns the newly created object.
   5360  */
   5361 xmlXPathObjectPtr
   5362 xmlXPathWrapExternal (void *val) {
   5363     xmlXPathObjectPtr ret;
   5364 
   5365     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5366     if (ret == NULL) {
   5367         xmlXPathErrMemory(NULL, "creating user object\n");
   5368 	return(NULL);
   5369     }
   5370     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5371     ret->type = XPATH_USERS;
   5372     ret->user = val;
   5373 #ifdef XP_DEBUG_OBJ_USAGE
   5374     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5375 #endif
   5376     return(ret);
   5377 }
   5378 
   5379 /**
   5380  * xmlXPathObjectCopy:
   5381  * @val:  the original object
   5382  *
   5383  * allocate a new copy of a given object
   5384  *
   5385  * Returns the newly created object.
   5386  */
   5387 xmlXPathObjectPtr
   5388 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5389     xmlXPathObjectPtr ret;
   5390 
   5391     if (val == NULL)
   5392 	return(NULL);
   5393 
   5394     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5395     if (ret == NULL) {
   5396         xmlXPathErrMemory(NULL, "copying object\n");
   5397 	return(NULL);
   5398     }
   5399     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5400 #ifdef XP_DEBUG_OBJ_USAGE
   5401     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5402 #endif
   5403     switch (val->type) {
   5404 	case XPATH_BOOLEAN:
   5405 	case XPATH_NUMBER:
   5406 	case XPATH_POINT:
   5407 	case XPATH_RANGE:
   5408 	    break;
   5409 	case XPATH_STRING:
   5410 	    ret->stringval = xmlStrdup(val->stringval);
   5411 	    break;
   5412 	case XPATH_XSLT_TREE:
   5413 #if 0
   5414 /*
   5415   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5416   this previous handling is no longer correct, and can cause some serious
   5417   problems (ref. bug 145547)
   5418 */
   5419 	    if ((val->nodesetval != NULL) &&
   5420 		(val->nodesetval->nodeTab != NULL)) {
   5421 		xmlNodePtr cur, tmp;
   5422 		xmlDocPtr top;
   5423 
   5424 		ret->boolval = 1;
   5425 		top =  xmlNewDoc(NULL);
   5426 		top->name = (char *)
   5427 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5428 		ret->user = top;
   5429 		if (top != NULL) {
   5430 		    top->doc = top;
   5431 		    cur = val->nodesetval->nodeTab[0]->children;
   5432 		    while (cur != NULL) {
   5433 			tmp = xmlDocCopyNode(cur, top, 1);
   5434 			xmlAddChild((xmlNodePtr) top, tmp);
   5435 			cur = cur->next;
   5436 		    }
   5437 		}
   5438 
   5439 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5440 	    } else
   5441 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5442 	    /* Deallocate the copied tree value */
   5443 	    break;
   5444 #endif
   5445 	case XPATH_NODESET:
   5446 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5447 	    /* Do not deallocate the copied tree value */
   5448 	    ret->boolval = 0;
   5449 	    break;
   5450 	case XPATH_LOCATIONSET:
   5451 #ifdef LIBXML_XPTR_ENABLED
   5452 	{
   5453 	    xmlLocationSetPtr loc = val->user;
   5454 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5455 	    break;
   5456 	}
   5457 #endif
   5458         case XPATH_USERS:
   5459 	    ret->user = val->user;
   5460 	    break;
   5461         case XPATH_UNDEFINED:
   5462 	    xmlGenericError(xmlGenericErrorContext,
   5463 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5464 		    val->type);
   5465 	    break;
   5466     }
   5467     return(ret);
   5468 }
   5469 
   5470 /**
   5471  * xmlXPathFreeObject:
   5472  * @obj:  the object to free
   5473  *
   5474  * Free up an xmlXPathObjectPtr object.
   5475  */
   5476 void
   5477 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5478     if (obj == NULL) return;
   5479     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5480 	if (obj->boolval) {
   5481 #if 0
   5482 	    if (obj->user != NULL) {
   5483                 xmlXPathFreeNodeSet(obj->nodesetval);
   5484 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5485 	    } else
   5486 #endif
   5487 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5488 	    if (obj->nodesetval != NULL)
   5489 		xmlXPathFreeValueTree(obj->nodesetval);
   5490 	} else {
   5491 	    if (obj->nodesetval != NULL)
   5492 		xmlXPathFreeNodeSet(obj->nodesetval);
   5493 	}
   5494 #ifdef LIBXML_XPTR_ENABLED
   5495     } else if (obj->type == XPATH_LOCATIONSET) {
   5496 	if (obj->user != NULL)
   5497 	    xmlXPtrFreeLocationSet(obj->user);
   5498 #endif
   5499     } else if (obj->type == XPATH_STRING) {
   5500 	if (obj->stringval != NULL)
   5501 	    xmlFree(obj->stringval);
   5502     }
   5503 #ifdef XP_DEBUG_OBJ_USAGE
   5504     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5505 #endif
   5506     xmlFree(obj);
   5507 }
   5508 
   5509 /**
   5510  * xmlXPathReleaseObject:
   5511  * @obj:  the xmlXPathObjectPtr to free or to cache
   5512  *
   5513  * Depending on the state of the cache this frees the given
   5514  * XPath object or stores it in the cache.
   5515  */
   5516 static void
   5517 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5518 {
   5519 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5520 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5521     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5522 
   5523 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5524 
   5525     if (obj == NULL)
   5526 	return;
   5527     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5528 	 xmlXPathFreeObject(obj);
   5529     } else {
   5530 	xmlXPathContextCachePtr cache =
   5531 	    (xmlXPathContextCachePtr) ctxt->cache;
   5532 
   5533 	switch (obj->type) {
   5534 	    case XPATH_NODESET:
   5535 	    case XPATH_XSLT_TREE:
   5536 		if (obj->nodesetval != NULL) {
   5537 		    if (obj->boolval) {
   5538 			/*
   5539 			* It looks like the @boolval is used for
   5540 			* evaluation if this an XSLT Result Tree Fragment.
   5541 			* TODO: Check if this assumption is correct.
   5542 			*/
   5543 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5544 			xmlXPathFreeValueTree(obj->nodesetval);
   5545 			obj->nodesetval = NULL;
   5546 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5547 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5548 					cache->maxNodeset)))
   5549 		    {
   5550 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5551 			goto obj_cached;
   5552 		    } else {
   5553 			xmlXPathFreeNodeSet(obj->nodesetval);
   5554 			obj->nodesetval = NULL;
   5555 		    }
   5556 		}
   5557 		break;
   5558 	    case XPATH_STRING:
   5559 		if (obj->stringval != NULL)
   5560 		    xmlFree(obj->stringval);
   5561 
   5562 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5563 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5564 		    goto obj_cached;
   5565 		}
   5566 		break;
   5567 	    case XPATH_BOOLEAN:
   5568 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5569 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5570 		    goto obj_cached;
   5571 		}
   5572 		break;
   5573 	    case XPATH_NUMBER:
   5574 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5575 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5576 		    goto obj_cached;
   5577 		}
   5578 		break;
   5579 #ifdef LIBXML_XPTR_ENABLED
   5580 	    case XPATH_LOCATIONSET:
   5581 		if (obj->user != NULL) {
   5582 		    xmlXPtrFreeLocationSet(obj->user);
   5583 		}
   5584 		goto free_obj;
   5585 #endif
   5586 	    default:
   5587 		goto free_obj;
   5588 	}
   5589 
   5590 	/*
   5591 	* Fallback to adding to the misc-objects slot.
   5592 	*/
   5593 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5594 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5595 	} else
   5596 	    goto free_obj;
   5597 
   5598 obj_cached:
   5599 
   5600 #ifdef XP_DEBUG_OBJ_USAGE
   5601 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5602 #endif
   5603 
   5604 	if (obj->nodesetval != NULL) {
   5605 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5606 
   5607 	    /*
   5608 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5609 	    *  the list and free the ns-nodes.
   5610 	    * URGENT TODO: Check if it's actually slowing things down.
   5611 	    *  Maybe we shouldn't try to preserve the list.
   5612 	    */
   5613 	    if (tmpset->nodeNr > 1) {
   5614 		int i;
   5615 		xmlNodePtr node;
   5616 
   5617 		for (i = 0; i < tmpset->nodeNr; i++) {
   5618 		    node = tmpset->nodeTab[i];
   5619 		    if ((node != NULL) &&
   5620 			(node->type == XML_NAMESPACE_DECL))
   5621 		    {
   5622 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5623 		    }
   5624 		}
   5625 	    } else if (tmpset->nodeNr == 1) {
   5626 		if ((tmpset->nodeTab[0] != NULL) &&
   5627 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5628 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5629 	    }
   5630 	    tmpset->nodeNr = 0;
   5631 	    memset(obj, 0, sizeof(xmlXPathObject));
   5632 	    obj->nodesetval = tmpset;
   5633 	} else
   5634 	    memset(obj, 0, sizeof(xmlXPathObject));
   5635 
   5636 	return;
   5637 
   5638 free_obj:
   5639 	/*
   5640 	* Cache is full; free the object.
   5641 	*/
   5642 	if (obj->nodesetval != NULL)
   5643 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5644 #ifdef XP_DEBUG_OBJ_USAGE
   5645 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5646 #endif
   5647 	xmlFree(obj);
   5648     }
   5649     return;
   5650 }
   5651 
   5652 
   5653 /************************************************************************
   5654  *									*
   5655  *			Type Casting Routines				*
   5656  *									*
   5657  ************************************************************************/
   5658 
   5659 /**
   5660  * xmlXPathCastBooleanToString:
   5661  * @val:  a boolean
   5662  *
   5663  * Converts a boolean to its string value.
   5664  *
   5665  * Returns a newly allocated string.
   5666  */
   5667 xmlChar *
   5668 xmlXPathCastBooleanToString (int val) {
   5669     xmlChar *ret;
   5670     if (val)
   5671 	ret = xmlStrdup((const xmlChar *) "true");
   5672     else
   5673 	ret = xmlStrdup((const xmlChar *) "false");
   5674     return(ret);
   5675 }
   5676 
   5677 /**
   5678  * xmlXPathCastNumberToString:
   5679  * @val:  a number
   5680  *
   5681  * Converts a number to its string value.
   5682  *
   5683  * Returns a newly allocated string.
   5684  */
   5685 xmlChar *
   5686 xmlXPathCastNumberToString (double val) {
   5687     xmlChar *ret;
   5688     switch (xmlXPathIsInf(val)) {
   5689     case 1:
   5690 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5691 	break;
   5692     case -1:
   5693 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5694 	break;
   5695     default:
   5696 	if (xmlXPathIsNaN(val)) {
   5697 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5698 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
   5699 	    ret = xmlStrdup((const xmlChar *) "0");
   5700 	} else {
   5701 	    /* could be improved */
   5702 	    char buf[100];
   5703 	    xmlXPathFormatNumber(val, buf, 99);
   5704 	    buf[99] = 0;
   5705 	    ret = xmlStrdup((const xmlChar *) buf);
   5706 	}
   5707     }
   5708     return(ret);
   5709 }
   5710 
   5711 /**
   5712  * xmlXPathCastNodeToString:
   5713  * @node:  a node
   5714  *
   5715  * Converts a node to its string value.
   5716  *
   5717  * Returns a newly allocated string.
   5718  */
   5719 xmlChar *
   5720 xmlXPathCastNodeToString (xmlNodePtr node) {
   5721 xmlChar *ret;
   5722     if ((ret = xmlNodeGetContent(node)) == NULL)
   5723 	ret = xmlStrdup((const xmlChar *) "");
   5724     return(ret);
   5725 }
   5726 
   5727 /**
   5728  * xmlXPathCastNodeSetToString:
   5729  * @ns:  a node-set
   5730  *
   5731  * Converts a node-set to its string value.
   5732  *
   5733  * Returns a newly allocated string.
   5734  */
   5735 xmlChar *
   5736 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5737     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5738 	return(xmlStrdup((const xmlChar *) ""));
   5739 
   5740     if (ns->nodeNr > 1)
   5741 	xmlXPathNodeSetSort(ns);
   5742     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5743 }
   5744 
   5745 /**
   5746  * xmlXPathCastToString:
   5747  * @val:  an XPath object
   5748  *
   5749  * Converts an existing object to its string() equivalent
   5750  *
   5751  * Returns the allocated string value of the object, NULL in case of error.
   5752  *         It's up to the caller to free the string memory with xmlFree().
   5753  */
   5754 xmlChar *
   5755 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5756     xmlChar *ret = NULL;
   5757 
   5758     if (val == NULL)
   5759 	return(xmlStrdup((const xmlChar *) ""));
   5760     switch (val->type) {
   5761 	case XPATH_UNDEFINED:
   5762 #ifdef DEBUG_EXPR
   5763 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5764 #endif
   5765 	    ret = xmlStrdup((const xmlChar *) "");
   5766 	    break;
   5767         case XPATH_NODESET:
   5768         case XPATH_XSLT_TREE:
   5769 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5770 	    break;
   5771 	case XPATH_STRING:
   5772 	    return(xmlStrdup(val->stringval));
   5773         case XPATH_BOOLEAN:
   5774 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5775 	    break;
   5776 	case XPATH_NUMBER: {
   5777 	    ret = xmlXPathCastNumberToString(val->floatval);
   5778 	    break;
   5779 	}
   5780 	case XPATH_USERS:
   5781 	case XPATH_POINT:
   5782 	case XPATH_RANGE:
   5783 	case XPATH_LOCATIONSET:
   5784 	    TODO
   5785 	    ret = xmlStrdup((const xmlChar *) "");
   5786 	    break;
   5787     }
   5788     return(ret);
   5789 }
   5790 
   5791 /**
   5792  * xmlXPathConvertString:
   5793  * @val:  an XPath object
   5794  *
   5795  * Converts an existing object to its string() equivalent
   5796  *
   5797  * Returns the new object, the old one is freed (or the operation
   5798  *         is done directly on @val)
   5799  */
   5800 xmlXPathObjectPtr
   5801 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5802     xmlChar *res = NULL;
   5803 
   5804     if (val == NULL)
   5805 	return(xmlXPathNewCString(""));
   5806 
   5807     switch (val->type) {
   5808     case XPATH_UNDEFINED:
   5809 #ifdef DEBUG_EXPR
   5810 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5811 #endif
   5812 	break;
   5813     case XPATH_NODESET:
   5814     case XPATH_XSLT_TREE:
   5815 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5816 	break;
   5817     case XPATH_STRING:
   5818 	return(val);
   5819     case XPATH_BOOLEAN:
   5820 	res = xmlXPathCastBooleanToString(val->boolval);
   5821 	break;
   5822     case XPATH_NUMBER:
   5823 	res = xmlXPathCastNumberToString(val->floatval);
   5824 	break;
   5825     case XPATH_USERS:
   5826     case XPATH_POINT:
   5827     case XPATH_RANGE:
   5828     case XPATH_LOCATIONSET:
   5829 	TODO;
   5830 	break;
   5831     }
   5832     xmlXPathFreeObject(val);
   5833     if (res == NULL)
   5834 	return(xmlXPathNewCString(""));
   5835     return(xmlXPathWrapString(res));
   5836 }
   5837 
   5838 /**
   5839  * xmlXPathCastBooleanToNumber:
   5840  * @val:  a boolean
   5841  *
   5842  * Converts a boolean to its number value
   5843  *
   5844  * Returns the number value
   5845  */
   5846 double
   5847 xmlXPathCastBooleanToNumber(int val) {
   5848     if (val)
   5849 	return(1.0);
   5850     return(0.0);
   5851 }
   5852 
   5853 /**
   5854  * xmlXPathCastStringToNumber:
   5855  * @val:  a string
   5856  *
   5857  * Converts a string to its number value
   5858  *
   5859  * Returns the number value
   5860  */
   5861 double
   5862 xmlXPathCastStringToNumber(const xmlChar * val) {
   5863     return(xmlXPathStringEvalNumber(val));
   5864 }
   5865 
   5866 /**
   5867  * xmlXPathCastNodeToNumber:
   5868  * @node:  a node
   5869  *
   5870  * Converts a node to its number value
   5871  *
   5872  * Returns the number value
   5873  */
   5874 double
   5875 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5876     xmlChar *strval;
   5877     double ret;
   5878 
   5879     if (node == NULL)
   5880 	return(xmlXPathNAN);
   5881     strval = xmlXPathCastNodeToString(node);
   5882     if (strval == NULL)
   5883 	return(xmlXPathNAN);
   5884     ret = xmlXPathCastStringToNumber(strval);
   5885     xmlFree(strval);
   5886 
   5887     return(ret);
   5888 }
   5889 
   5890 /**
   5891  * xmlXPathCastNodeSetToNumber:
   5892  * @ns:  a node-set
   5893  *
   5894  * Converts a node-set to its number value
   5895  *
   5896  * Returns the number value
   5897  */
   5898 double
   5899 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5900     xmlChar *str;
   5901     double ret;
   5902 
   5903     if (ns == NULL)
   5904 	return(xmlXPathNAN);
   5905     str = xmlXPathCastNodeSetToString(ns);
   5906     ret = xmlXPathCastStringToNumber(str);
   5907     xmlFree(str);
   5908     return(ret);
   5909 }
   5910 
   5911 /**
   5912  * xmlXPathCastToNumber:
   5913  * @val:  an XPath object
   5914  *
   5915  * Converts an XPath object to its number value
   5916  *
   5917  * Returns the number value
   5918  */
   5919 double
   5920 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5921     double ret = 0.0;
   5922 
   5923     if (val == NULL)
   5924 	return(xmlXPathNAN);
   5925     switch (val->type) {
   5926     case XPATH_UNDEFINED:
   5927 #ifdef DEGUB_EXPR
   5928 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5929 #endif
   5930 	ret = xmlXPathNAN;
   5931 	break;
   5932     case XPATH_NODESET:
   5933     case XPATH_XSLT_TREE:
   5934 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5935 	break;
   5936     case XPATH_STRING:
   5937 	ret = xmlXPathCastStringToNumber(val->stringval);
   5938 	break;
   5939     case XPATH_NUMBER:
   5940 	ret = val->floatval;
   5941 	break;
   5942     case XPATH_BOOLEAN:
   5943 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5944 	break;
   5945     case XPATH_USERS:
   5946     case XPATH_POINT:
   5947     case XPATH_RANGE:
   5948     case XPATH_LOCATIONSET:
   5949 	TODO;
   5950 	ret = xmlXPathNAN;
   5951 	break;
   5952     }
   5953     return(ret);
   5954 }
   5955 
   5956 /**
   5957  * xmlXPathConvertNumber:
   5958  * @val:  an XPath object
   5959  *
   5960  * Converts an existing object to its number() equivalent
   5961  *
   5962  * Returns the new object, the old one is freed (or the operation
   5963  *         is done directly on @val)
   5964  */
   5965 xmlXPathObjectPtr
   5966 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5967     xmlXPathObjectPtr ret;
   5968 
   5969     if (val == NULL)
   5970 	return(xmlXPathNewFloat(0.0));
   5971     if (val->type == XPATH_NUMBER)
   5972 	return(val);
   5973     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5974     xmlXPathFreeObject(val);
   5975     return(ret);
   5976 }
   5977 
   5978 /**
   5979  * xmlXPathCastNumberToBoolean:
   5980  * @val:  a number
   5981  *
   5982  * Converts a number to its boolean value
   5983  *
   5984  * Returns the boolean value
   5985  */
   5986 int
   5987 xmlXPathCastNumberToBoolean (double val) {
   5988      if (xmlXPathIsNaN(val) || (val == 0.0))
   5989 	 return(0);
   5990      return(1);
   5991 }
   5992 
   5993 /**
   5994  * xmlXPathCastStringToBoolean:
   5995  * @val:  a string
   5996  *
   5997  * Converts a string to its boolean value
   5998  *
   5999  * Returns the boolean value
   6000  */
   6001 int
   6002 xmlXPathCastStringToBoolean (const xmlChar *val) {
   6003     if ((val == NULL) || (xmlStrlen(val) == 0))
   6004 	return(0);
   6005     return(1);
   6006 }
   6007 
   6008 /**
   6009  * xmlXPathCastNodeSetToBoolean:
   6010  * @ns:  a node-set
   6011  *
   6012  * Converts a node-set to its boolean value
   6013  *
   6014  * Returns the boolean value
   6015  */
   6016 int
   6017 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   6018     if ((ns == NULL) || (ns->nodeNr == 0))
   6019 	return(0);
   6020     return(1);
   6021 }
   6022 
   6023 /**
   6024  * xmlXPathCastToBoolean:
   6025  * @val:  an XPath object
   6026  *
   6027  * Converts an XPath object to its boolean value
   6028  *
   6029  * Returns the boolean value
   6030  */
   6031 int
   6032 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   6033     int ret = 0;
   6034 
   6035     if (val == NULL)
   6036 	return(0);
   6037     switch (val->type) {
   6038     case XPATH_UNDEFINED:
   6039 #ifdef DEBUG_EXPR
   6040 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   6041 #endif
   6042 	ret = 0;
   6043 	break;
   6044     case XPATH_NODESET:
   6045     case XPATH_XSLT_TREE:
   6046 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   6047 	break;
   6048     case XPATH_STRING:
   6049 	ret = xmlXPathCastStringToBoolean(val->stringval);
   6050 	break;
   6051     case XPATH_NUMBER:
   6052 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   6053 	break;
   6054     case XPATH_BOOLEAN:
   6055 	ret = val->boolval;
   6056 	break;
   6057     case XPATH_USERS:
   6058     case XPATH_POINT:
   6059     case XPATH_RANGE:
   6060     case XPATH_LOCATIONSET:
   6061 	TODO;
   6062 	ret = 0;
   6063 	break;
   6064     }
   6065     return(ret);
   6066 }
   6067 
   6068 
   6069 /**
   6070  * xmlXPathConvertBoolean:
   6071  * @val:  an XPath object
   6072  *
   6073  * Converts an existing object to its boolean() equivalent
   6074  *
   6075  * Returns the new object, the old one is freed (or the operation
   6076  *         is done directly on @val)
   6077  */
   6078 xmlXPathObjectPtr
   6079 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   6080     xmlXPathObjectPtr ret;
   6081 
   6082     if (val == NULL)
   6083 	return(xmlXPathNewBoolean(0));
   6084     if (val->type == XPATH_BOOLEAN)
   6085 	return(val);
   6086     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   6087     xmlXPathFreeObject(val);
   6088     return(ret);
   6089 }
   6090 
   6091 /************************************************************************
   6092  *									*
   6093  *		Routines to handle XPath contexts			*
   6094  *									*
   6095  ************************************************************************/
   6096 
   6097 /**
   6098  * xmlXPathNewContext:
   6099  * @doc:  the XML document
   6100  *
   6101  * Create a new xmlXPathContext
   6102  *
   6103  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   6104  */
   6105 xmlXPathContextPtr
   6106 xmlXPathNewContext(xmlDocPtr doc) {
   6107     xmlXPathContextPtr ret;
   6108 
   6109     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   6110     if (ret == NULL) {
   6111         xmlXPathErrMemory(NULL, "creating context\n");
   6112 	return(NULL);
   6113     }
   6114     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6115     ret->doc = doc;
   6116     ret->node = NULL;
   6117 
   6118     ret->varHash = NULL;
   6119 
   6120     ret->nb_types = 0;
   6121     ret->max_types = 0;
   6122     ret->types = NULL;
   6123 
   6124     ret->funcHash = xmlHashCreate(0);
   6125 
   6126     ret->nb_axis = 0;
   6127     ret->max_axis = 0;
   6128     ret->axis = NULL;
   6129 
   6130     ret->nsHash = NULL;
   6131     ret->user = NULL;
   6132 
   6133     ret->contextSize = -1;
   6134     ret->proximityPosition = -1;
   6135 
   6136 #ifdef XP_DEFAULT_CACHE_ON
   6137     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6138 	xmlXPathFreeContext(ret);
   6139 	return(NULL);
   6140     }
   6141 #endif
   6142 
   6143     xmlXPathRegisterAllFunctions(ret);
   6144 
   6145     return(ret);
   6146 }
   6147 
   6148 /**
   6149  * xmlXPathFreeContext:
   6150  * @ctxt:  the context to free
   6151  *
   6152  * Free up an xmlXPathContext
   6153  */
   6154 void
   6155 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6156     if (ctxt == NULL) return;
   6157 
   6158     if (ctxt->cache != NULL)
   6159 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6160     xmlXPathRegisteredNsCleanup(ctxt);
   6161     xmlXPathRegisteredFuncsCleanup(ctxt);
   6162     xmlXPathRegisteredVariablesCleanup(ctxt);
   6163     xmlResetError(&ctxt->lastError);
   6164     xmlFree(ctxt);
   6165 }
   6166 
   6167 /************************************************************************
   6168  *									*
   6169  *		Routines to handle XPath parser contexts		*
   6170  *									*
   6171  ************************************************************************/
   6172 
   6173 #define CHECK_CTXT(ctxt)						\
   6174     if (ctxt == NULL) {						\
   6175 	__xmlRaiseError(NULL, NULL, NULL,				\
   6176 		NULL, NULL, XML_FROM_XPATH,				\
   6177 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6178 		__FILE__, __LINE__,					\
   6179 		NULL, NULL, NULL, 0, 0,					\
   6180 		"NULL context pointer\n");				\
   6181 	return(NULL);							\
   6182     }									\
   6183 
   6184 #define CHECK_CTXT_NEG(ctxt)						\
   6185     if (ctxt == NULL) {						\
   6186 	__xmlRaiseError(NULL, NULL, NULL,				\
   6187 		NULL, NULL, XML_FROM_XPATH,				\
   6188 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6189 		__FILE__, __LINE__,					\
   6190 		NULL, NULL, NULL, 0, 0,					\
   6191 		"NULL context pointer\n");				\
   6192 	return(-1);							\
   6193     }									\
   6194 
   6195 
   6196 #define CHECK_CONTEXT(ctxt)						\
   6197     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6198         (ctxt->doc->children == NULL)) {				\
   6199 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6200 	return(NULL);							\
   6201     }
   6202 
   6203 
   6204 /**
   6205  * xmlXPathNewParserContext:
   6206  * @str:  the XPath expression
   6207  * @ctxt:  the XPath context
   6208  *
   6209  * Create a new xmlXPathParserContext
   6210  *
   6211  * Returns the xmlXPathParserContext just allocated.
   6212  */
   6213 xmlXPathParserContextPtr
   6214 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6215     xmlXPathParserContextPtr ret;
   6216 
   6217     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6218     if (ret == NULL) {
   6219         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6220 	return(NULL);
   6221     }
   6222     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6223     ret->cur = ret->base = str;
   6224     ret->context = ctxt;
   6225 
   6226     ret->comp = xmlXPathNewCompExpr();
   6227     if (ret->comp == NULL) {
   6228 	xmlFree(ret->valueTab);
   6229 	xmlFree(ret);
   6230 	return(NULL);
   6231     }
   6232     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6233         ret->comp->dict = ctxt->dict;
   6234 	xmlDictReference(ret->comp->dict);
   6235     }
   6236 
   6237     return(ret);
   6238 }
   6239 
   6240 /**
   6241  * xmlXPathCompParserContext:
   6242  * @comp:  the XPath compiled expression
   6243  * @ctxt:  the XPath context
   6244  *
   6245  * Create a new xmlXPathParserContext when processing a compiled expression
   6246  *
   6247  * Returns the xmlXPathParserContext just allocated.
   6248  */
   6249 static xmlXPathParserContextPtr
   6250 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6251     xmlXPathParserContextPtr ret;
   6252 
   6253     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6254     if (ret == NULL) {
   6255         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6256 	return(NULL);
   6257     }
   6258     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6259 
   6260     /* Allocate the value stack */
   6261     ret->valueTab = (xmlXPathObjectPtr *)
   6262                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6263     if (ret->valueTab == NULL) {
   6264 	xmlFree(ret);
   6265 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6266 	return(NULL);
   6267     }
   6268     ret->valueNr = 0;
   6269     ret->valueMax = 10;
   6270     ret->value = NULL;
   6271     ret->valueFrame = 0;
   6272 
   6273     ret->context = ctxt;
   6274     ret->comp = comp;
   6275 
   6276     return(ret);
   6277 }
   6278 
   6279 /**
   6280  * xmlXPathFreeParserContext:
   6281  * @ctxt:  the context to free
   6282  *
   6283  * Free up an xmlXPathParserContext
   6284  */
   6285 void
   6286 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6287     if (ctxt->valueTab != NULL) {
   6288         xmlFree(ctxt->valueTab);
   6289     }
   6290     if (ctxt->comp != NULL) {
   6291 #ifdef XPATH_STREAMING
   6292 	if (ctxt->comp->stream != NULL) {
   6293 	    xmlFreePatternList(ctxt->comp->stream);
   6294 	    ctxt->comp->stream = NULL;
   6295 	}
   6296 #endif
   6297 	xmlXPathFreeCompExpr(ctxt->comp);
   6298     }
   6299     xmlFree(ctxt);
   6300 }
   6301 
   6302 /************************************************************************
   6303  *									*
   6304  *		The implicit core function library			*
   6305  *									*
   6306  ************************************************************************/
   6307 
   6308 /**
   6309  * xmlXPathNodeValHash:
   6310  * @node:  a node pointer
   6311  *
   6312  * Function computing the beginning of the string value of the node,
   6313  * used to speed up comparisons
   6314  *
   6315  * Returns an int usable as a hash
   6316  */
   6317 static unsigned int
   6318 xmlXPathNodeValHash(xmlNodePtr node) {
   6319     int len = 2;
   6320     const xmlChar * string = NULL;
   6321     xmlNodePtr tmp = NULL;
   6322     unsigned int ret = 0;
   6323 
   6324     if (node == NULL)
   6325 	return(0);
   6326 
   6327     if (node->type == XML_DOCUMENT_NODE) {
   6328 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6329 	if (tmp == NULL)
   6330 	    node = node->children;
   6331 	else
   6332 	    node = tmp;
   6333 
   6334 	if (node == NULL)
   6335 	    return(0);
   6336     }
   6337 
   6338     switch (node->type) {
   6339 	case XML_COMMENT_NODE:
   6340 	case XML_PI_NODE:
   6341 	case XML_CDATA_SECTION_NODE:
   6342 	case XML_TEXT_NODE:
   6343 	    string = node->content;
   6344 	    if (string == NULL)
   6345 		return(0);
   6346 	    if (string[0] == 0)
   6347 		return(0);
   6348 	    return(((unsigned int) string[0]) +
   6349 		   (((unsigned int) string[1]) << 8));
   6350 	case XML_NAMESPACE_DECL:
   6351 	    string = ((xmlNsPtr)node)->href;
   6352 	    if (string == NULL)
   6353 		return(0);
   6354 	    if (string[0] == 0)
   6355 		return(0);
   6356 	    return(((unsigned int) string[0]) +
   6357 		   (((unsigned int) string[1]) << 8));
   6358 	case XML_ATTRIBUTE_NODE:
   6359 	    tmp = ((xmlAttrPtr) node)->children;
   6360 	    break;
   6361 	case XML_ELEMENT_NODE:
   6362 	    tmp = node->children;
   6363 	    break;
   6364 	default:
   6365 	    return(0);
   6366     }
   6367     while (tmp != NULL) {
   6368 	switch (tmp->type) {
   6369 	    case XML_COMMENT_NODE:
   6370 	    case XML_PI_NODE:
   6371 	    case XML_CDATA_SECTION_NODE:
   6372 	    case XML_TEXT_NODE:
   6373 		string = tmp->content;
   6374 		break;
   6375 	    case XML_NAMESPACE_DECL:
   6376 		string = ((xmlNsPtr)tmp)->href;
   6377 		break;
   6378 	    default:
   6379 		break;
   6380 	}
   6381 	if ((string != NULL) && (string[0] != 0)) {
   6382 	    if (len == 1) {
   6383 		return(ret + (((unsigned int) string[0]) << 8));
   6384 	    }
   6385 	    if (string[1] == 0) {
   6386 		len = 1;
   6387 		ret = (unsigned int) string[0];
   6388 	    } else {
   6389 		return(((unsigned int) string[0]) +
   6390 		       (((unsigned int) string[1]) << 8));
   6391 	    }
   6392 	}
   6393 	/*
   6394 	 * Skip to next node
   6395 	 */
   6396 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6397 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6398 		tmp = tmp->children;
   6399 		continue;
   6400 	    }
   6401 	}
   6402 	if (tmp == node)
   6403 	    break;
   6404 
   6405 	if (tmp->next != NULL) {
   6406 	    tmp = tmp->next;
   6407 	    continue;
   6408 	}
   6409 
   6410 	do {
   6411 	    tmp = tmp->parent;
   6412 	    if (tmp == NULL)
   6413 		break;
   6414 	    if (tmp == node) {
   6415 		tmp = NULL;
   6416 		break;
   6417 	    }
   6418 	    if (tmp->next != NULL) {
   6419 		tmp = tmp->next;
   6420 		break;
   6421 	    }
   6422 	} while (tmp != NULL);
   6423     }
   6424     return(ret);
   6425 }
   6426 
   6427 /**
   6428  * xmlXPathStringHash:
   6429  * @string:  a string
   6430  *
   6431  * Function computing the beginning of the string value of the node,
   6432  * used to speed up comparisons
   6433  *
   6434  * Returns an int usable as a hash
   6435  */
   6436 static unsigned int
   6437 xmlXPathStringHash(const xmlChar * string) {
   6438     if (string == NULL)
   6439 	return((unsigned int) 0);
   6440     if (string[0] == 0)
   6441 	return(0);
   6442     return(((unsigned int) string[0]) +
   6443 	   (((unsigned int) string[1]) << 8));
   6444 }
   6445 
   6446 /**
   6447  * xmlXPathCompareNodeSetFloat:
   6448  * @ctxt:  the XPath Parser context
   6449  * @inf:  less than (1) or greater than (0)
   6450  * @strict:  is the comparison strict
   6451  * @arg:  the node set
   6452  * @f:  the value
   6453  *
   6454  * Implement the compare operation between a nodeset and a number
   6455  *     @ns < @val    (1, 1, ...
   6456  *     @ns <= @val   (1, 0, ...
   6457  *     @ns > @val    (0, 1, ...
   6458  *     @ns >= @val   (0, 0, ...
   6459  *
   6460  * If one object to be compared is a node-set and the other is a number,
   6461  * then the comparison will be true if and only if there is a node in the
   6462  * node-set such that the result of performing the comparison on the number
   6463  * to be compared and on the result of converting the string-value of that
   6464  * node to a number using the number function is true.
   6465  *
   6466  * Returns 0 or 1 depending on the results of the test.
   6467  */
   6468 static int
   6469 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6470 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6471     int i, ret = 0;
   6472     xmlNodeSetPtr ns;
   6473     xmlChar *str2;
   6474 
   6475     if ((f == NULL) || (arg == NULL) ||
   6476 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6477 	xmlXPathReleaseObject(ctxt->context, arg);
   6478 	xmlXPathReleaseObject(ctxt->context, f);
   6479         return(0);
   6480     }
   6481     ns = arg->nodesetval;
   6482     if (ns != NULL) {
   6483 	for (i = 0;i < ns->nodeNr;i++) {
   6484 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6485 	     if (str2 != NULL) {
   6486 		 valuePush(ctxt,
   6487 			   xmlXPathCacheNewString(ctxt->context, str2));
   6488 		 xmlFree(str2);
   6489 		 xmlXPathNumberFunction(ctxt, 1);
   6490 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6491 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6492 		 if (ret)
   6493 		     break;
   6494 	     }
   6495 	}
   6496     }
   6497     xmlXPathReleaseObject(ctxt->context, arg);
   6498     xmlXPathReleaseObject(ctxt->context, f);
   6499     return(ret);
   6500 }
   6501 
   6502 /**
   6503  * xmlXPathCompareNodeSetString:
   6504  * @ctxt:  the XPath Parser context
   6505  * @inf:  less than (1) or greater than (0)
   6506  * @strict:  is the comparison strict
   6507  * @arg:  the node set
   6508  * @s:  the value
   6509  *
   6510  * Implement the compare operation between a nodeset and a string
   6511  *     @ns < @val    (1, 1, ...
   6512  *     @ns <= @val   (1, 0, ...
   6513  *     @ns > @val    (0, 1, ...
   6514  *     @ns >= @val   (0, 0, ...
   6515  *
   6516  * If one object to be compared is a node-set and the other is a string,
   6517  * then the comparison will be true if and only if there is a node in
   6518  * the node-set such that the result of performing the comparison on the
   6519  * string-value of the node and the other string is true.
   6520  *
   6521  * Returns 0 or 1 depending on the results of the test.
   6522  */
   6523 static int
   6524 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6525 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6526     int i, ret = 0;
   6527     xmlNodeSetPtr ns;
   6528     xmlChar *str2;
   6529 
   6530     if ((s == NULL) || (arg == NULL) ||
   6531 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6532 	xmlXPathReleaseObject(ctxt->context, arg);
   6533 	xmlXPathReleaseObject(ctxt->context, s);
   6534         return(0);
   6535     }
   6536     ns = arg->nodesetval;
   6537     if (ns != NULL) {
   6538 	for (i = 0;i < ns->nodeNr;i++) {
   6539 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6540 	     if (str2 != NULL) {
   6541 		 valuePush(ctxt,
   6542 			   xmlXPathCacheNewString(ctxt->context, str2));
   6543 		 xmlFree(str2);
   6544 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6545 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6546 		 if (ret)
   6547 		     break;
   6548 	     }
   6549 	}
   6550     }
   6551     xmlXPathReleaseObject(ctxt->context, arg);
   6552     xmlXPathReleaseObject(ctxt->context, s);
   6553     return(ret);
   6554 }
   6555 
   6556 /**
   6557  * xmlXPathCompareNodeSets:
   6558  * @inf:  less than (1) or greater than (0)
   6559  * @strict:  is the comparison strict
   6560  * @arg1:  the first node set object
   6561  * @arg2:  the second node set object
   6562  *
   6563  * Implement the compare operation on nodesets:
   6564  *
   6565  * If both objects to be compared are node-sets, then the comparison
   6566  * will be true if and only if there is a node in the first node-set
   6567  * and a node in the second node-set such that the result of performing
   6568  * the comparison on the string-values of the two nodes is true.
   6569  * ....
   6570  * When neither object to be compared is a node-set and the operator
   6571  * is <=, <, >= or >, then the objects are compared by converting both
   6572  * objects to numbers and comparing the numbers according to IEEE 754.
   6573  * ....
   6574  * The number function converts its argument to a number as follows:
   6575  *  - a string that consists of optional whitespace followed by an
   6576  *    optional minus sign followed by a Number followed by whitespace
   6577  *    is converted to the IEEE 754 number that is nearest (according
   6578  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6579  *    represented by the string; any other string is converted to NaN
   6580  *
   6581  * Conclusion all nodes need to be converted first to their string value
   6582  * and then the comparison must be done when possible
   6583  */
   6584 static int
   6585 xmlXPathCompareNodeSets(int inf, int strict,
   6586 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6587     int i, j, init = 0;
   6588     double val1;
   6589     double *values2;
   6590     int ret = 0;
   6591     xmlNodeSetPtr ns1;
   6592     xmlNodeSetPtr ns2;
   6593 
   6594     if ((arg1 == NULL) ||
   6595 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6596 	xmlXPathFreeObject(arg2);
   6597         return(0);
   6598     }
   6599     if ((arg2 == NULL) ||
   6600 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6601 	xmlXPathFreeObject(arg1);
   6602 	xmlXPathFreeObject(arg2);
   6603         return(0);
   6604     }
   6605 
   6606     ns1 = arg1->nodesetval;
   6607     ns2 = arg2->nodesetval;
   6608 
   6609     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6610 	xmlXPathFreeObject(arg1);
   6611 	xmlXPathFreeObject(arg2);
   6612 	return(0);
   6613     }
   6614     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6615 	xmlXPathFreeObject(arg1);
   6616 	xmlXPathFreeObject(arg2);
   6617 	return(0);
   6618     }
   6619 
   6620     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6621     if (values2 == NULL) {
   6622         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6623 	xmlXPathFreeObject(arg1);
   6624 	xmlXPathFreeObject(arg2);
   6625 	return(0);
   6626     }
   6627     for (i = 0;i < ns1->nodeNr;i++) {
   6628 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6629 	if (xmlXPathIsNaN(val1))
   6630 	    continue;
   6631 	for (j = 0;j < ns2->nodeNr;j++) {
   6632 	    if (init == 0) {
   6633 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6634 	    }
   6635 	    if (xmlXPathIsNaN(values2[j]))
   6636 		continue;
   6637 	    if (inf && strict)
   6638 		ret = (val1 < values2[j]);
   6639 	    else if (inf && !strict)
   6640 		ret = (val1 <= values2[j]);
   6641 	    else if (!inf && strict)
   6642 		ret = (val1 > values2[j]);
   6643 	    else if (!inf && !strict)
   6644 		ret = (val1 >= values2[j]);
   6645 	    if (ret)
   6646 		break;
   6647 	}
   6648 	if (ret)
   6649 	    break;
   6650 	init = 1;
   6651     }
   6652     xmlFree(values2);
   6653     xmlXPathFreeObject(arg1);
   6654     xmlXPathFreeObject(arg2);
   6655     return(ret);
   6656 }
   6657 
   6658 /**
   6659  * xmlXPathCompareNodeSetValue:
   6660  * @ctxt:  the XPath Parser context
   6661  * @inf:  less than (1) or greater than (0)
   6662  * @strict:  is the comparison strict
   6663  * @arg:  the node set
   6664  * @val:  the value
   6665  *
   6666  * Implement the compare operation between a nodeset and a value
   6667  *     @ns < @val    (1, 1, ...
   6668  *     @ns <= @val   (1, 0, ...
   6669  *     @ns > @val    (0, 1, ...
   6670  *     @ns >= @val   (0, 0, ...
   6671  *
   6672  * If one object to be compared is a node-set and the other is a boolean,
   6673  * then the comparison will be true if and only if the result of performing
   6674  * the comparison on the boolean and on the result of converting
   6675  * the node-set to a boolean using the boolean function is true.
   6676  *
   6677  * Returns 0 or 1 depending on the results of the test.
   6678  */
   6679 static int
   6680 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6681 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6682     if ((val == NULL) || (arg == NULL) ||
   6683 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6684         return(0);
   6685 
   6686     switch(val->type) {
   6687         case XPATH_NUMBER:
   6688 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6689         case XPATH_NODESET:
   6690         case XPATH_XSLT_TREE:
   6691 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6692         case XPATH_STRING:
   6693 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6694         case XPATH_BOOLEAN:
   6695 	    valuePush(ctxt, arg);
   6696 	    xmlXPathBooleanFunction(ctxt, 1);
   6697 	    valuePush(ctxt, val);
   6698 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6699 	default:
   6700 	    TODO
   6701     }
   6702     return(0);
   6703 }
   6704 
   6705 /**
   6706  * xmlXPathEqualNodeSetString:
   6707  * @arg:  the nodeset object argument
   6708  * @str:  the string to compare to.
   6709  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6710  *
   6711  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6712  * If one object to be compared is a node-set and the other is a string,
   6713  * then the comparison will be true if and only if there is a node in
   6714  * the node-set such that the result of performing the comparison on the
   6715  * string-value of the node and the other string is true.
   6716  *
   6717  * Returns 0 or 1 depending on the results of the test.
   6718  */
   6719 static int
   6720 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6721 {
   6722     int i;
   6723     xmlNodeSetPtr ns;
   6724     xmlChar *str2;
   6725     unsigned int hash;
   6726 
   6727     if ((str == NULL) || (arg == NULL) ||
   6728         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6729         return (0);
   6730     ns = arg->nodesetval;
   6731     /*
   6732      * A NULL nodeset compared with a string is always false
   6733      * (since there is no node equal, and no node not equal)
   6734      */
   6735     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6736         return (0);
   6737     hash = xmlXPathStringHash(str);
   6738     for (i = 0; i < ns->nodeNr; i++) {
   6739         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6740             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6741             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6742                 xmlFree(str2);
   6743 		if (neq)
   6744 		    continue;
   6745                 return (1);
   6746 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6747 		if (neq)
   6748 		    continue;
   6749                 return (1);
   6750             } else if (neq) {
   6751 		if (str2 != NULL)
   6752 		    xmlFree(str2);
   6753 		return (1);
   6754 	    }
   6755             if (str2 != NULL)
   6756                 xmlFree(str2);
   6757         } else if (neq)
   6758 	    return (1);
   6759     }
   6760     return (0);
   6761 }
   6762 
   6763 /**
   6764  * xmlXPathEqualNodeSetFloat:
   6765  * @arg:  the nodeset object argument
   6766  * @f:  the float to compare to
   6767  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6768  *
   6769  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6770  * If one object to be compared is a node-set and the other is a number,
   6771  * then the comparison will be true if and only if there is a node in
   6772  * the node-set such that the result of performing the comparison on the
   6773  * number to be compared and on the result of converting the string-value
   6774  * of that node to a number using the number function is true.
   6775  *
   6776  * Returns 0 or 1 depending on the results of the test.
   6777  */
   6778 static int
   6779 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6780     xmlXPathObjectPtr arg, double f, int neq) {
   6781   int i, ret=0;
   6782   xmlNodeSetPtr ns;
   6783   xmlChar *str2;
   6784   xmlXPathObjectPtr val;
   6785   double v;
   6786 
   6787     if ((arg == NULL) ||
   6788 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6789         return(0);
   6790 
   6791     ns = arg->nodesetval;
   6792     if (ns != NULL) {
   6793 	for (i=0;i<ns->nodeNr;i++) {
   6794 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6795 	    if (str2 != NULL) {
   6796 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6797 		xmlFree(str2);
   6798 		xmlXPathNumberFunction(ctxt, 1);
   6799 		val = valuePop(ctxt);
   6800 		v = val->floatval;
   6801 		xmlXPathReleaseObject(ctxt->context, val);
   6802 		if (!xmlXPathIsNaN(v)) {
   6803 		    if ((!neq) && (v==f)) {
   6804 			ret = 1;
   6805 			break;
   6806 		    } else if ((neq) && (v!=f)) {
   6807 			ret = 1;
   6808 			break;
   6809 		    }
   6810 		} else {	/* NaN is unequal to any value */
   6811 		    if (neq)
   6812 			ret = 1;
   6813 		}
   6814 	    }
   6815 	}
   6816     }
   6817 
   6818     return(ret);
   6819 }
   6820 
   6821 
   6822 /**
   6823  * xmlXPathEqualNodeSets:
   6824  * @arg1:  first nodeset object argument
   6825  * @arg2:  second nodeset object argument
   6826  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6827  *
   6828  * Implement the equal / not equal operation on XPath nodesets:
   6829  * @arg1 == @arg2  or  @arg1 != @arg2
   6830  * If both objects to be compared are node-sets, then the comparison
   6831  * will be true if and only if there is a node in the first node-set and
   6832  * a node in the second node-set such that the result of performing the
   6833  * comparison on the string-values of the two nodes is true.
   6834  *
   6835  * (needless to say, this is a costly operation)
   6836  *
   6837  * Returns 0 or 1 depending on the results of the test.
   6838  */
   6839 static int
   6840 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6841     int i, j;
   6842     unsigned int *hashs1;
   6843     unsigned int *hashs2;
   6844     xmlChar **values1;
   6845     xmlChar **values2;
   6846     int ret = 0;
   6847     xmlNodeSetPtr ns1;
   6848     xmlNodeSetPtr ns2;
   6849 
   6850     if ((arg1 == NULL) ||
   6851 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6852         return(0);
   6853     if ((arg2 == NULL) ||
   6854 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6855         return(0);
   6856 
   6857     ns1 = arg1->nodesetval;
   6858     ns2 = arg2->nodesetval;
   6859 
   6860     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6861 	return(0);
   6862     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6863 	return(0);
   6864 
   6865     /*
   6866      * for equal, check if there is a node pertaining to both sets
   6867      */
   6868     if (neq == 0)
   6869 	for (i = 0;i < ns1->nodeNr;i++)
   6870 	    for (j = 0;j < ns2->nodeNr;j++)
   6871 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6872 		    return(1);
   6873 
   6874     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6875     if (values1 == NULL) {
   6876         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6877 	return(0);
   6878     }
   6879     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6880     if (hashs1 == NULL) {
   6881         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6882 	xmlFree(values1);
   6883 	return(0);
   6884     }
   6885     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6886     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6887     if (values2 == NULL) {
   6888         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6889 	xmlFree(hashs1);
   6890 	xmlFree(values1);
   6891 	return(0);
   6892     }
   6893     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6894     if (hashs2 == NULL) {
   6895         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6896 	xmlFree(hashs1);
   6897 	xmlFree(values1);
   6898 	xmlFree(values2);
   6899 	return(0);
   6900     }
   6901     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6902     for (i = 0;i < ns1->nodeNr;i++) {
   6903 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6904 	for (j = 0;j < ns2->nodeNr;j++) {
   6905 	    if (i == 0)
   6906 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6907 	    if (hashs1[i] != hashs2[j]) {
   6908 		if (neq) {
   6909 		    ret = 1;
   6910 		    break;
   6911 		}
   6912 	    }
   6913 	    else {
   6914 		if (values1[i] == NULL)
   6915 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6916 		if (values2[j] == NULL)
   6917 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6918 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6919 		if (ret)
   6920 		    break;
   6921 	    }
   6922 	}
   6923 	if (ret)
   6924 	    break;
   6925     }
   6926     for (i = 0;i < ns1->nodeNr;i++)
   6927 	if (values1[i] != NULL)
   6928 	    xmlFree(values1[i]);
   6929     for (j = 0;j < ns2->nodeNr;j++)
   6930 	if (values2[j] != NULL)
   6931 	    xmlFree(values2[j]);
   6932     xmlFree(values1);
   6933     xmlFree(values2);
   6934     xmlFree(hashs1);
   6935     xmlFree(hashs2);
   6936     return(ret);
   6937 }
   6938 
   6939 static int
   6940 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6941   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6942     int ret = 0;
   6943     /*
   6944      *At this point we are assured neither arg1 nor arg2
   6945      *is a nodeset, so we can just pick the appropriate routine.
   6946      */
   6947     switch (arg1->type) {
   6948         case XPATH_UNDEFINED:
   6949 #ifdef DEBUG_EXPR
   6950 	    xmlGenericError(xmlGenericErrorContext,
   6951 		    "Equal: undefined\n");
   6952 #endif
   6953 	    break;
   6954         case XPATH_BOOLEAN:
   6955 	    switch (arg2->type) {
   6956 	        case XPATH_UNDEFINED:
   6957 #ifdef DEBUG_EXPR
   6958 		    xmlGenericError(xmlGenericErrorContext,
   6959 			    "Equal: undefined\n");
   6960 #endif
   6961 		    break;
   6962 		case XPATH_BOOLEAN:
   6963 #ifdef DEBUG_EXPR
   6964 		    xmlGenericError(xmlGenericErrorContext,
   6965 			    "Equal: %d boolean %d \n",
   6966 			    arg1->boolval, arg2->boolval);
   6967 #endif
   6968 		    ret = (arg1->boolval == arg2->boolval);
   6969 		    break;
   6970 		case XPATH_NUMBER:
   6971 		    ret = (arg1->boolval ==
   6972 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   6973 		    break;
   6974 		case XPATH_STRING:
   6975 		    if ((arg2->stringval == NULL) ||
   6976 			(arg2->stringval[0] == 0)) ret = 0;
   6977 		    else
   6978 			ret = 1;
   6979 		    ret = (arg1->boolval == ret);
   6980 		    break;
   6981 		case XPATH_USERS:
   6982 		case XPATH_POINT:
   6983 		case XPATH_RANGE:
   6984 		case XPATH_LOCATIONSET:
   6985 		    TODO
   6986 		    break;
   6987 		case XPATH_NODESET:
   6988 		case XPATH_XSLT_TREE:
   6989 		    break;
   6990 	    }
   6991 	    break;
   6992         case XPATH_NUMBER:
   6993 	    switch (arg2->type) {
   6994 	        case XPATH_UNDEFINED:
   6995 #ifdef DEBUG_EXPR
   6996 		    xmlGenericError(xmlGenericErrorContext,
   6997 			    "Equal: undefined\n");
   6998 #endif
   6999 		    break;
   7000 		case XPATH_BOOLEAN:
   7001 		    ret = (arg2->boolval==
   7002 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   7003 		    break;
   7004 		case XPATH_STRING:
   7005 		    valuePush(ctxt, arg2);
   7006 		    xmlXPathNumberFunction(ctxt, 1);
   7007 		    arg2 = valuePop(ctxt);
   7008 		    /* no break on purpose */
   7009 		case XPATH_NUMBER:
   7010 		    /* Hand check NaN and Infinity equalities */
   7011 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7012 			    xmlXPathIsNaN(arg2->floatval)) {
   7013 		        ret = 0;
   7014 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7015 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   7016 			    ret = 1;
   7017 			else
   7018 			    ret = 0;
   7019 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7020 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7021 			    ret = 1;
   7022 			else
   7023 			    ret = 0;
   7024 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7025 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7026 			    ret = 1;
   7027 			else
   7028 			    ret = 0;
   7029 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7030 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7031 			    ret = 1;
   7032 			else
   7033 			    ret = 0;
   7034 		    } else {
   7035 		        ret = (arg1->floatval == arg2->floatval);
   7036 		    }
   7037 		    break;
   7038 		case XPATH_USERS:
   7039 		case XPATH_POINT:
   7040 		case XPATH_RANGE:
   7041 		case XPATH_LOCATIONSET:
   7042 		    TODO
   7043 		    break;
   7044 		case XPATH_NODESET:
   7045 		case XPATH_XSLT_TREE:
   7046 		    break;
   7047 	    }
   7048 	    break;
   7049         case XPATH_STRING:
   7050 	    switch (arg2->type) {
   7051 	        case XPATH_UNDEFINED:
   7052 #ifdef DEBUG_EXPR
   7053 		    xmlGenericError(xmlGenericErrorContext,
   7054 			    "Equal: undefined\n");
   7055 #endif
   7056 		    break;
   7057 		case XPATH_BOOLEAN:
   7058 		    if ((arg1->stringval == NULL) ||
   7059 			(arg1->stringval[0] == 0)) ret = 0;
   7060 		    else
   7061 			ret = 1;
   7062 		    ret = (arg2->boolval == ret);
   7063 		    break;
   7064 		case XPATH_STRING:
   7065 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   7066 		    break;
   7067 		case XPATH_NUMBER:
   7068 		    valuePush(ctxt, arg1);
   7069 		    xmlXPathNumberFunction(ctxt, 1);
   7070 		    arg1 = valuePop(ctxt);
   7071 		    /* Hand check NaN and Infinity equalities */
   7072 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7073 			    xmlXPathIsNaN(arg2->floatval)) {
   7074 		        ret = 0;
   7075 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7076 			if (xmlXPathIsInf(arg2->floatval) == 1)
   7077 			    ret = 1;
   7078 			else
   7079 			    ret = 0;
   7080 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7081 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7082 			    ret = 1;
   7083 			else
   7084 			    ret = 0;
   7085 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7086 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7087 			    ret = 1;
   7088 			else
   7089 			    ret = 0;
   7090 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7091 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7092 			    ret = 1;
   7093 			else
   7094 			    ret = 0;
   7095 		    } else {
   7096 		        ret = (arg1->floatval == arg2->floatval);
   7097 		    }
   7098 		    break;
   7099 		case XPATH_USERS:
   7100 		case XPATH_POINT:
   7101 		case XPATH_RANGE:
   7102 		case XPATH_LOCATIONSET:
   7103 		    TODO
   7104 		    break;
   7105 		case XPATH_NODESET:
   7106 		case XPATH_XSLT_TREE:
   7107 		    break;
   7108 	    }
   7109 	    break;
   7110         case XPATH_USERS:
   7111 	case XPATH_POINT:
   7112 	case XPATH_RANGE:
   7113 	case XPATH_LOCATIONSET:
   7114 	    TODO
   7115 	    break;
   7116 	case XPATH_NODESET:
   7117 	case XPATH_XSLT_TREE:
   7118 	    break;
   7119     }
   7120     xmlXPathReleaseObject(ctxt->context, arg1);
   7121     xmlXPathReleaseObject(ctxt->context, arg2);
   7122     return(ret);
   7123 }
   7124 
   7125 /**
   7126  * xmlXPathEqualValues:
   7127  * @ctxt:  the XPath Parser context
   7128  *
   7129  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7130  *
   7131  * Returns 0 or 1 depending on the results of the test.
   7132  */
   7133 int
   7134 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7135     xmlXPathObjectPtr arg1, arg2, argtmp;
   7136     int ret = 0;
   7137 
   7138     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7139     arg2 = valuePop(ctxt);
   7140     arg1 = valuePop(ctxt);
   7141     if ((arg1 == NULL) || (arg2 == NULL)) {
   7142 	if (arg1 != NULL)
   7143 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7144 	else
   7145 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7146 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7147     }
   7148 
   7149     if (arg1 == arg2) {
   7150 #ifdef DEBUG_EXPR
   7151         xmlGenericError(xmlGenericErrorContext,
   7152 		"Equal: by pointer\n");
   7153 #endif
   7154 	xmlXPathFreeObject(arg1);
   7155         return(1);
   7156     }
   7157 
   7158     /*
   7159      *If either argument is a nodeset, it's a 'special case'
   7160      */
   7161     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7162       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7163 	/*
   7164 	 *Hack it to assure arg1 is the nodeset
   7165 	 */
   7166 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7167 		argtmp = arg2;
   7168 		arg2 = arg1;
   7169 		arg1 = argtmp;
   7170 	}
   7171 	switch (arg2->type) {
   7172 	    case XPATH_UNDEFINED:
   7173 #ifdef DEBUG_EXPR
   7174 		xmlGenericError(xmlGenericErrorContext,
   7175 			"Equal: undefined\n");
   7176 #endif
   7177 		break;
   7178 	    case XPATH_NODESET:
   7179 	    case XPATH_XSLT_TREE:
   7180 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7181 		break;
   7182 	    case XPATH_BOOLEAN:
   7183 		if ((arg1->nodesetval == NULL) ||
   7184 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7185 		else
   7186 		    ret = 1;
   7187 		ret = (ret == arg2->boolval);
   7188 		break;
   7189 	    case XPATH_NUMBER:
   7190 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7191 		break;
   7192 	    case XPATH_STRING:
   7193 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7194 		break;
   7195 	    case XPATH_USERS:
   7196 	    case XPATH_POINT:
   7197 	    case XPATH_RANGE:
   7198 	    case XPATH_LOCATIONSET:
   7199 		TODO
   7200 		break;
   7201 	}
   7202 	xmlXPathReleaseObject(ctxt->context, arg1);
   7203 	xmlXPathReleaseObject(ctxt->context, arg2);
   7204 	return(ret);
   7205     }
   7206 
   7207     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7208 }
   7209 
   7210 /**
   7211  * xmlXPathNotEqualValues:
   7212  * @ctxt:  the XPath Parser context
   7213  *
   7214  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7215  *
   7216  * Returns 0 or 1 depending on the results of the test.
   7217  */
   7218 int
   7219 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7220     xmlXPathObjectPtr arg1, arg2, argtmp;
   7221     int ret = 0;
   7222 
   7223     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7224     arg2 = valuePop(ctxt);
   7225     arg1 = valuePop(ctxt);
   7226     if ((arg1 == NULL) || (arg2 == NULL)) {
   7227 	if (arg1 != NULL)
   7228 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7229 	else
   7230 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7231 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7232     }
   7233 
   7234     if (arg1 == arg2) {
   7235 #ifdef DEBUG_EXPR
   7236         xmlGenericError(xmlGenericErrorContext,
   7237 		"NotEqual: by pointer\n");
   7238 #endif
   7239 	xmlXPathReleaseObject(ctxt->context, arg1);
   7240         return(0);
   7241     }
   7242 
   7243     /*
   7244      *If either argument is a nodeset, it's a 'special case'
   7245      */
   7246     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7247       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7248 	/*
   7249 	 *Hack it to assure arg1 is the nodeset
   7250 	 */
   7251 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7252 		argtmp = arg2;
   7253 		arg2 = arg1;
   7254 		arg1 = argtmp;
   7255 	}
   7256 	switch (arg2->type) {
   7257 	    case XPATH_UNDEFINED:
   7258 #ifdef DEBUG_EXPR
   7259 		xmlGenericError(xmlGenericErrorContext,
   7260 			"NotEqual: undefined\n");
   7261 #endif
   7262 		break;
   7263 	    case XPATH_NODESET:
   7264 	    case XPATH_XSLT_TREE:
   7265 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7266 		break;
   7267 	    case XPATH_BOOLEAN:
   7268 		if ((arg1->nodesetval == NULL) ||
   7269 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7270 		else
   7271 		    ret = 1;
   7272 		ret = (ret != arg2->boolval);
   7273 		break;
   7274 	    case XPATH_NUMBER:
   7275 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7276 		break;
   7277 	    case XPATH_STRING:
   7278 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7279 		break;
   7280 	    case XPATH_USERS:
   7281 	    case XPATH_POINT:
   7282 	    case XPATH_RANGE:
   7283 	    case XPATH_LOCATIONSET:
   7284 		TODO
   7285 		break;
   7286 	}
   7287 	xmlXPathReleaseObject(ctxt->context, arg1);
   7288 	xmlXPathReleaseObject(ctxt->context, arg2);
   7289 	return(ret);
   7290     }
   7291 
   7292     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7293 }
   7294 
   7295 /**
   7296  * xmlXPathCompareValues:
   7297  * @ctxt:  the XPath Parser context
   7298  * @inf:  less than (1) or greater than (0)
   7299  * @strict:  is the comparison strict
   7300  *
   7301  * Implement the compare operation on XPath objects:
   7302  *     @arg1 < @arg2    (1, 1, ...
   7303  *     @arg1 <= @arg2   (1, 0, ...
   7304  *     @arg1 > @arg2    (0, 1, ...
   7305  *     @arg1 >= @arg2   (0, 0, ...
   7306  *
   7307  * When neither object to be compared is a node-set and the operator is
   7308  * <=, <, >=, >, then the objects are compared by converted both objects
   7309  * to numbers and comparing the numbers according to IEEE 754. The <
   7310  * comparison will be true if and only if the first number is less than the
   7311  * second number. The <= comparison will be true if and only if the first
   7312  * number is less than or equal to the second number. The > comparison
   7313  * will be true if and only if the first number is greater than the second
   7314  * number. The >= comparison will be true if and only if the first number
   7315  * is greater than or equal to the second number.
   7316  *
   7317  * Returns 1 if the comparison succeeded, 0 if it failed
   7318  */
   7319 int
   7320 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7321     int ret = 0, arg1i = 0, arg2i = 0;
   7322     xmlXPathObjectPtr arg1, arg2;
   7323 
   7324     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7325     arg2 = valuePop(ctxt);
   7326     arg1 = valuePop(ctxt);
   7327     if ((arg1 == NULL) || (arg2 == NULL)) {
   7328 	if (arg1 != NULL)
   7329 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7330 	else
   7331 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7332 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7333     }
   7334 
   7335     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7336       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7337 	/*
   7338 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7339 	 * are not freed from within this routine; they will be freed from the
   7340 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7341 	 */
   7342 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7343 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7344 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7345 	} else {
   7346 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7347 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7348 			                          arg1, arg2);
   7349 	    } else {
   7350 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7351 			                          arg2, arg1);
   7352 	    }
   7353 	}
   7354 	return(ret);
   7355     }
   7356 
   7357     if (arg1->type != XPATH_NUMBER) {
   7358 	valuePush(ctxt, arg1);
   7359 	xmlXPathNumberFunction(ctxt, 1);
   7360 	arg1 = valuePop(ctxt);
   7361     }
   7362     if (arg1->type != XPATH_NUMBER) {
   7363 	xmlXPathFreeObject(arg1);
   7364 	xmlXPathFreeObject(arg2);
   7365 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7366     }
   7367     if (arg2->type != XPATH_NUMBER) {
   7368 	valuePush(ctxt, arg2);
   7369 	xmlXPathNumberFunction(ctxt, 1);
   7370 	arg2 = valuePop(ctxt);
   7371     }
   7372     if (arg2->type != XPATH_NUMBER) {
   7373 	xmlXPathReleaseObject(ctxt->context, arg1);
   7374 	xmlXPathReleaseObject(ctxt->context, arg2);
   7375 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7376     }
   7377     /*
   7378      * Add tests for infinity and nan
   7379      * => feedback on 3.4 for Inf and NaN
   7380      */
   7381     /* Hand check NaN and Infinity comparisons */
   7382     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7383 	ret=0;
   7384     } else {
   7385 	arg1i=xmlXPathIsInf(arg1->floatval);
   7386 	arg2i=xmlXPathIsInf(arg2->floatval);
   7387 	if (inf && strict) {
   7388 	    if ((arg1i == -1 && arg2i != -1) ||
   7389 		(arg2i == 1 && arg1i != 1)) {
   7390 		ret = 1;
   7391 	    } else if (arg1i == 0 && arg2i == 0) {
   7392 		ret = (arg1->floatval < arg2->floatval);
   7393 	    } else {
   7394 		ret = 0;
   7395 	    }
   7396 	}
   7397 	else if (inf && !strict) {
   7398 	    if (arg1i == -1 || arg2i == 1) {
   7399 		ret = 1;
   7400 	    } else if (arg1i == 0 && arg2i == 0) {
   7401 		ret = (arg1->floatval <= arg2->floatval);
   7402 	    } else {
   7403 		ret = 0;
   7404 	    }
   7405 	}
   7406 	else if (!inf && strict) {
   7407 	    if ((arg1i == 1 && arg2i != 1) ||
   7408 		(arg2i == -1 && arg1i != -1)) {
   7409 		ret = 1;
   7410 	    } else if (arg1i == 0 && arg2i == 0) {
   7411 		ret = (arg1->floatval > arg2->floatval);
   7412 	    } else {
   7413 		ret = 0;
   7414 	    }
   7415 	}
   7416 	else if (!inf && !strict) {
   7417 	    if (arg1i == 1 || arg2i == -1) {
   7418 		ret = 1;
   7419 	    } else if (arg1i == 0 && arg2i == 0) {
   7420 		ret = (arg1->floatval >= arg2->floatval);
   7421 	    } else {
   7422 		ret = 0;
   7423 	    }
   7424 	}
   7425     }
   7426     xmlXPathReleaseObject(ctxt->context, arg1);
   7427     xmlXPathReleaseObject(ctxt->context, arg2);
   7428     return(ret);
   7429 }
   7430 
   7431 /**
   7432  * xmlXPathValueFlipSign:
   7433  * @ctxt:  the XPath Parser context
   7434  *
   7435  * Implement the unary - operation on an XPath object
   7436  * The numeric operators convert their operands to numbers as if
   7437  * by calling the number function.
   7438  */
   7439 void
   7440 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7441     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7442     CAST_TO_NUMBER;
   7443     CHECK_TYPE(XPATH_NUMBER);
   7444     if (xmlXPathIsNaN(ctxt->value->floatval))
   7445         ctxt->value->floatval=xmlXPathNAN;
   7446     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
   7447         ctxt->value->floatval=xmlXPathNINF;
   7448     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
   7449         ctxt->value->floatval=xmlXPathPINF;
   7450     else if (ctxt->value->floatval == 0) {
   7451         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
   7452 	    ctxt->value->floatval = xmlXPathNZERO;
   7453 	else
   7454 	    ctxt->value->floatval = 0;
   7455     }
   7456     else
   7457         ctxt->value->floatval = - ctxt->value->floatval;
   7458 }
   7459 
   7460 /**
   7461  * xmlXPathAddValues:
   7462  * @ctxt:  the XPath Parser context
   7463  *
   7464  * Implement the add operation on XPath objects:
   7465  * The numeric operators convert their operands to numbers as if
   7466  * by calling the number function.
   7467  */
   7468 void
   7469 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7470     xmlXPathObjectPtr arg;
   7471     double val;
   7472 
   7473     arg = valuePop(ctxt);
   7474     if (arg == NULL)
   7475 	XP_ERROR(XPATH_INVALID_OPERAND);
   7476     val = xmlXPathCastToNumber(arg);
   7477     xmlXPathReleaseObject(ctxt->context, arg);
   7478     CAST_TO_NUMBER;
   7479     CHECK_TYPE(XPATH_NUMBER);
   7480     ctxt->value->floatval += val;
   7481 }
   7482 
   7483 /**
   7484  * xmlXPathSubValues:
   7485  * @ctxt:  the XPath Parser context
   7486  *
   7487  * Implement the subtraction operation on XPath objects:
   7488  * The numeric operators convert their operands to numbers as if
   7489  * by calling the number function.
   7490  */
   7491 void
   7492 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7493     xmlXPathObjectPtr arg;
   7494     double val;
   7495 
   7496     arg = valuePop(ctxt);
   7497     if (arg == NULL)
   7498 	XP_ERROR(XPATH_INVALID_OPERAND);
   7499     val = xmlXPathCastToNumber(arg);
   7500     xmlXPathReleaseObject(ctxt->context, arg);
   7501     CAST_TO_NUMBER;
   7502     CHECK_TYPE(XPATH_NUMBER);
   7503     ctxt->value->floatval -= val;
   7504 }
   7505 
   7506 /**
   7507  * xmlXPathMultValues:
   7508  * @ctxt:  the XPath Parser context
   7509  *
   7510  * Implement the multiply operation on XPath objects:
   7511  * The numeric operators convert their operands to numbers as if
   7512  * by calling the number function.
   7513  */
   7514 void
   7515 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7516     xmlXPathObjectPtr arg;
   7517     double val;
   7518 
   7519     arg = valuePop(ctxt);
   7520     if (arg == NULL)
   7521 	XP_ERROR(XPATH_INVALID_OPERAND);
   7522     val = xmlXPathCastToNumber(arg);
   7523     xmlXPathReleaseObject(ctxt->context, arg);
   7524     CAST_TO_NUMBER;
   7525     CHECK_TYPE(XPATH_NUMBER);
   7526     ctxt->value->floatval *= val;
   7527 }
   7528 
   7529 /**
   7530  * xmlXPathDivValues:
   7531  * @ctxt:  the XPath Parser context
   7532  *
   7533  * Implement the div operation on XPath objects @arg1 / @arg2:
   7534  * The numeric operators convert their operands to numbers as if
   7535  * by calling the number function.
   7536  */
   7537 void
   7538 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7539     xmlXPathObjectPtr arg;
   7540     double val;
   7541 
   7542     arg = valuePop(ctxt);
   7543     if (arg == NULL)
   7544 	XP_ERROR(XPATH_INVALID_OPERAND);
   7545     val = xmlXPathCastToNumber(arg);
   7546     xmlXPathReleaseObject(ctxt->context, arg);
   7547     CAST_TO_NUMBER;
   7548     CHECK_TYPE(XPATH_NUMBER);
   7549     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
   7550 	ctxt->value->floatval = xmlXPathNAN;
   7551     else if (val == 0 && xmlXPathGetSign(val) != 0) {
   7552 	if (ctxt->value->floatval == 0)
   7553 	    ctxt->value->floatval = xmlXPathNAN;
   7554 	else if (ctxt->value->floatval > 0)
   7555 	    ctxt->value->floatval = xmlXPathNINF;
   7556 	else if (ctxt->value->floatval < 0)
   7557 	    ctxt->value->floatval = xmlXPathPINF;
   7558     }
   7559     else if (val == 0) {
   7560 	if (ctxt->value->floatval == 0)
   7561 	    ctxt->value->floatval = xmlXPathNAN;
   7562 	else if (ctxt->value->floatval > 0)
   7563 	    ctxt->value->floatval = xmlXPathPINF;
   7564 	else if (ctxt->value->floatval < 0)
   7565 	    ctxt->value->floatval = xmlXPathNINF;
   7566     } else
   7567 	ctxt->value->floatval /= val;
   7568 }
   7569 
   7570 /**
   7571  * xmlXPathModValues:
   7572  * @ctxt:  the XPath Parser context
   7573  *
   7574  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7575  * The numeric operators convert their operands to numbers as if
   7576  * by calling the number function.
   7577  */
   7578 void
   7579 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7580     xmlXPathObjectPtr arg;
   7581     double arg1, arg2;
   7582 
   7583     arg = valuePop(ctxt);
   7584     if (arg == NULL)
   7585 	XP_ERROR(XPATH_INVALID_OPERAND);
   7586     arg2 = xmlXPathCastToNumber(arg);
   7587     xmlXPathReleaseObject(ctxt->context, arg);
   7588     CAST_TO_NUMBER;
   7589     CHECK_TYPE(XPATH_NUMBER);
   7590     arg1 = ctxt->value->floatval;
   7591     if (arg2 == 0)
   7592 	ctxt->value->floatval = xmlXPathNAN;
   7593     else {
   7594 	ctxt->value->floatval = fmod(arg1, arg2);
   7595     }
   7596 }
   7597 
   7598 /************************************************************************
   7599  *									*
   7600  *		The traversal functions					*
   7601  *									*
   7602  ************************************************************************/
   7603 
   7604 /*
   7605  * A traversal function enumerates nodes along an axis.
   7606  * Initially it must be called with NULL, and it indicates
   7607  * termination on the axis by returning NULL.
   7608  */
   7609 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7610                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7611 
   7612 /*
   7613  * xmlXPathTraversalFunctionExt:
   7614  * A traversal function enumerates nodes along an axis.
   7615  * Initially it must be called with NULL, and it indicates
   7616  * termination on the axis by returning NULL.
   7617  * The context node of the traversal is specified via @contextNode.
   7618  */
   7619 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7620                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7621 
   7622 /*
   7623  * xmlXPathNodeSetMergeFunction:
   7624  * Used for merging node sets in xmlXPathCollectAndTest().
   7625  */
   7626 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7627 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7628 
   7629 
   7630 /**
   7631  * xmlXPathNextSelf:
   7632  * @ctxt:  the XPath Parser context
   7633  * @cur:  the current node in the traversal
   7634  *
   7635  * Traversal function for the "self" direction
   7636  * The self axis contains just the context node itself
   7637  *
   7638  * Returns the next element following that axis
   7639  */
   7640 xmlNodePtr
   7641 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7642     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7643     if (cur == NULL)
   7644         return(ctxt->context->node);
   7645     return(NULL);
   7646 }
   7647 
   7648 /**
   7649  * xmlXPathNextChild:
   7650  * @ctxt:  the XPath Parser context
   7651  * @cur:  the current node in the traversal
   7652  *
   7653  * Traversal function for the "child" direction
   7654  * The child axis contains the children of the context node in document order.
   7655  *
   7656  * Returns the next element following that axis
   7657  */
   7658 xmlNodePtr
   7659 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7660     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7661     if (cur == NULL) {
   7662 	if (ctxt->context->node == NULL) return(NULL);
   7663 	switch (ctxt->context->node->type) {
   7664             case XML_ELEMENT_NODE:
   7665             case XML_TEXT_NODE:
   7666             case XML_CDATA_SECTION_NODE:
   7667             case XML_ENTITY_REF_NODE:
   7668             case XML_ENTITY_NODE:
   7669             case XML_PI_NODE:
   7670             case XML_COMMENT_NODE:
   7671             case XML_NOTATION_NODE:
   7672             case XML_DTD_NODE:
   7673 		return(ctxt->context->node->children);
   7674             case XML_DOCUMENT_NODE:
   7675             case XML_DOCUMENT_TYPE_NODE:
   7676             case XML_DOCUMENT_FRAG_NODE:
   7677             case XML_HTML_DOCUMENT_NODE:
   7678 #ifdef LIBXML_DOCB_ENABLED
   7679 	    case XML_DOCB_DOCUMENT_NODE:
   7680 #endif
   7681 		return(((xmlDocPtr) ctxt->context->node)->children);
   7682 	    case XML_ELEMENT_DECL:
   7683 	    case XML_ATTRIBUTE_DECL:
   7684 	    case XML_ENTITY_DECL:
   7685             case XML_ATTRIBUTE_NODE:
   7686 	    case XML_NAMESPACE_DECL:
   7687 	    case XML_XINCLUDE_START:
   7688 	    case XML_XINCLUDE_END:
   7689 		return(NULL);
   7690 	}
   7691 	return(NULL);
   7692     }
   7693     if ((cur->type == XML_DOCUMENT_NODE) ||
   7694         (cur->type == XML_HTML_DOCUMENT_NODE))
   7695 	return(NULL);
   7696     return(cur->next);
   7697 }
   7698 
   7699 /**
   7700  * xmlXPathNextChildElement:
   7701  * @ctxt:  the XPath Parser context
   7702  * @cur:  the current node in the traversal
   7703  *
   7704  * Traversal function for the "child" direction and nodes of type element.
   7705  * The child axis contains the children of the context node in document order.
   7706  *
   7707  * Returns the next element following that axis
   7708  */
   7709 static xmlNodePtr
   7710 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7711     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7712     if (cur == NULL) {
   7713 	cur = ctxt->context->node;
   7714 	if (cur == NULL) return(NULL);
   7715 	/*
   7716 	* Get the first element child.
   7717 	*/
   7718 	switch (cur->type) {
   7719             case XML_ELEMENT_NODE:
   7720 	    case XML_DOCUMENT_FRAG_NODE:
   7721 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7722             case XML_ENTITY_NODE:
   7723 		cur = cur->children;
   7724 		if (cur != NULL) {
   7725 		    if (cur->type == XML_ELEMENT_NODE)
   7726 			return(cur);
   7727 		    do {
   7728 			cur = cur->next;
   7729 		    } while ((cur != NULL) &&
   7730 			(cur->type != XML_ELEMENT_NODE));
   7731 		    return(cur);
   7732 		}
   7733 		return(NULL);
   7734             case XML_DOCUMENT_NODE:
   7735             case XML_HTML_DOCUMENT_NODE:
   7736 #ifdef LIBXML_DOCB_ENABLED
   7737 	    case XML_DOCB_DOCUMENT_NODE:
   7738 #endif
   7739 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7740 	    default:
   7741 		return(NULL);
   7742 	}
   7743 	return(NULL);
   7744     }
   7745     /*
   7746     * Get the next sibling element node.
   7747     */
   7748     switch (cur->type) {
   7749 	case XML_ELEMENT_NODE:
   7750 	case XML_TEXT_NODE:
   7751 	case XML_ENTITY_REF_NODE:
   7752 	case XML_ENTITY_NODE:
   7753 	case XML_CDATA_SECTION_NODE:
   7754 	case XML_PI_NODE:
   7755 	case XML_COMMENT_NODE:
   7756 	case XML_XINCLUDE_END:
   7757 	    break;
   7758 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7759 	default:
   7760 	    return(NULL);
   7761     }
   7762     if (cur->next != NULL) {
   7763 	if (cur->next->type == XML_ELEMENT_NODE)
   7764 	    return(cur->next);
   7765 	cur = cur->next;
   7766 	do {
   7767 	    cur = cur->next;
   7768 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7769 	return(cur);
   7770     }
   7771     return(NULL);
   7772 }
   7773 
   7774 #if 0
   7775 /**
   7776  * xmlXPathNextDescendantOrSelfElemParent:
   7777  * @ctxt:  the XPath Parser context
   7778  * @cur:  the current node in the traversal
   7779  *
   7780  * Traversal function for the "descendant-or-self" axis.
   7781  * Additionally it returns only nodes which can be parents of
   7782  * element nodes.
   7783  *
   7784  *
   7785  * Returns the next element following that axis
   7786  */
   7787 static xmlNodePtr
   7788 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7789 				       xmlNodePtr contextNode)
   7790 {
   7791     if (cur == NULL) {
   7792 	if (contextNode == NULL)
   7793 	    return(NULL);
   7794 	switch (contextNode->type) {
   7795 	    case XML_ELEMENT_NODE:
   7796 	    case XML_XINCLUDE_START:
   7797 	    case XML_DOCUMENT_FRAG_NODE:
   7798 	    case XML_DOCUMENT_NODE:
   7799 #ifdef LIBXML_DOCB_ENABLED
   7800 	    case XML_DOCB_DOCUMENT_NODE:
   7801 #endif
   7802 	    case XML_HTML_DOCUMENT_NODE:
   7803 		return(contextNode);
   7804 	    default:
   7805 		return(NULL);
   7806 	}
   7807 	return(NULL);
   7808     } else {
   7809 	xmlNodePtr start = cur;
   7810 
   7811 	while (cur != NULL) {
   7812 	    switch (cur->type) {
   7813 		case XML_ELEMENT_NODE:
   7814 		/* TODO: OK to have XInclude here? */
   7815 		case XML_XINCLUDE_START:
   7816 		case XML_DOCUMENT_FRAG_NODE:
   7817 		    if (cur != start)
   7818 			return(cur);
   7819 		    if (cur->children != NULL) {
   7820 			cur = cur->children;
   7821 			continue;
   7822 		    }
   7823 		    break;
   7824 		/* Not sure if we need those here. */
   7825 		case XML_DOCUMENT_NODE:
   7826 #ifdef LIBXML_DOCB_ENABLED
   7827 		case XML_DOCB_DOCUMENT_NODE:
   7828 #endif
   7829 		case XML_HTML_DOCUMENT_NODE:
   7830 		    if (cur != start)
   7831 			return(cur);
   7832 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7833 		default:
   7834 		    break;
   7835 	    }
   7836 
   7837 next_sibling:
   7838 	    if ((cur == NULL) || (cur == contextNode))
   7839 		return(NULL);
   7840 	    if (cur->next != NULL) {
   7841 		cur = cur->next;
   7842 	    } else {
   7843 		cur = cur->parent;
   7844 		goto next_sibling;
   7845 	    }
   7846 	}
   7847     }
   7848     return(NULL);
   7849 }
   7850 #endif
   7851 
   7852 /**
   7853  * xmlXPathNextDescendant:
   7854  * @ctxt:  the XPath Parser context
   7855  * @cur:  the current node in the traversal
   7856  *
   7857  * Traversal function for the "descendant" direction
   7858  * the descendant axis contains the descendants of the context node in document
   7859  * order; a descendant is a child or a child of a child and so on.
   7860  *
   7861  * Returns the next element following that axis
   7862  */
   7863 xmlNodePtr
   7864 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7865     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7866     if (cur == NULL) {
   7867 	if (ctxt->context->node == NULL)
   7868 	    return(NULL);
   7869 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7870 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7871 	    return(NULL);
   7872 
   7873         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7874 	    return(ctxt->context->doc->children);
   7875         return(ctxt->context->node->children);
   7876     }
   7877 
   7878     if (cur->type == XML_NAMESPACE_DECL)
   7879         return(NULL);
   7880     if (cur->children != NULL) {
   7881 	/*
   7882 	 * Do not descend on entities declarations
   7883 	 */
   7884 	if (cur->children->type != XML_ENTITY_DECL) {
   7885 	    cur = cur->children;
   7886 	    /*
   7887 	     * Skip DTDs
   7888 	     */
   7889 	    if (cur->type != XML_DTD_NODE)
   7890 		return(cur);
   7891 	}
   7892     }
   7893 
   7894     if (cur == ctxt->context->node) return(NULL);
   7895 
   7896     while (cur->next != NULL) {
   7897 	cur = cur->next;
   7898 	if ((cur->type != XML_ENTITY_DECL) &&
   7899 	    (cur->type != XML_DTD_NODE))
   7900 	    return(cur);
   7901     }
   7902 
   7903     do {
   7904         cur = cur->parent;
   7905 	if (cur == NULL) break;
   7906 	if (cur == ctxt->context->node) return(NULL);
   7907 	if (cur->next != NULL) {
   7908 	    cur = cur->next;
   7909 	    return(cur);
   7910 	}
   7911     } while (cur != NULL);
   7912     return(cur);
   7913 }
   7914 
   7915 /**
   7916  * xmlXPathNextDescendantOrSelf:
   7917  * @ctxt:  the XPath Parser context
   7918  * @cur:  the current node in the traversal
   7919  *
   7920  * Traversal function for the "descendant-or-self" direction
   7921  * the descendant-or-self axis contains the context node and the descendants
   7922  * of the context node in document order; thus the context node is the first
   7923  * node on the axis, and the first child of the context node is the second node
   7924  * on the axis
   7925  *
   7926  * Returns the next element following that axis
   7927  */
   7928 xmlNodePtr
   7929 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7930     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7931     if (cur == NULL) {
   7932 	if (ctxt->context->node == NULL)
   7933 	    return(NULL);
   7934 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7935 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7936 	    return(NULL);
   7937         return(ctxt->context->node);
   7938     }
   7939 
   7940     return(xmlXPathNextDescendant(ctxt, cur));
   7941 }
   7942 
   7943 /**
   7944  * xmlXPathNextParent:
   7945  * @ctxt:  the XPath Parser context
   7946  * @cur:  the current node in the traversal
   7947  *
   7948  * Traversal function for the "parent" direction
   7949  * The parent axis contains the parent of the context node, if there is one.
   7950  *
   7951  * Returns the next element following that axis
   7952  */
   7953 xmlNodePtr
   7954 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7955     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7956     /*
   7957      * the parent of an attribute or namespace node is the element
   7958      * to which the attribute or namespace node is attached
   7959      * Namespace handling !!!
   7960      */
   7961     if (cur == NULL) {
   7962 	if (ctxt->context->node == NULL) return(NULL);
   7963 	switch (ctxt->context->node->type) {
   7964             case XML_ELEMENT_NODE:
   7965             case XML_TEXT_NODE:
   7966             case XML_CDATA_SECTION_NODE:
   7967             case XML_ENTITY_REF_NODE:
   7968             case XML_ENTITY_NODE:
   7969             case XML_PI_NODE:
   7970             case XML_COMMENT_NODE:
   7971             case XML_NOTATION_NODE:
   7972             case XML_DTD_NODE:
   7973 	    case XML_ELEMENT_DECL:
   7974 	    case XML_ATTRIBUTE_DECL:
   7975 	    case XML_XINCLUDE_START:
   7976 	    case XML_XINCLUDE_END:
   7977 	    case XML_ENTITY_DECL:
   7978 		if (ctxt->context->node->parent == NULL)
   7979 		    return((xmlNodePtr) ctxt->context->doc);
   7980 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7981 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7982 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7983 				 BAD_CAST "fake node libxslt"))))
   7984 		    return(NULL);
   7985 		return(ctxt->context->node->parent);
   7986             case XML_ATTRIBUTE_NODE: {
   7987 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7988 
   7989 		return(att->parent);
   7990 	    }
   7991             case XML_DOCUMENT_NODE:
   7992             case XML_DOCUMENT_TYPE_NODE:
   7993             case XML_DOCUMENT_FRAG_NODE:
   7994             case XML_HTML_DOCUMENT_NODE:
   7995 #ifdef LIBXML_DOCB_ENABLED
   7996 	    case XML_DOCB_DOCUMENT_NODE:
   7997 #endif
   7998                 return(NULL);
   7999 	    case XML_NAMESPACE_DECL: {
   8000 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8001 
   8002 		if ((ns->next != NULL) &&
   8003 		    (ns->next->type != XML_NAMESPACE_DECL))
   8004 		    return((xmlNodePtr) ns->next);
   8005                 return(NULL);
   8006 	    }
   8007 	}
   8008     }
   8009     return(NULL);
   8010 }
   8011 
   8012 /**
   8013  * xmlXPathNextAncestor:
   8014  * @ctxt:  the XPath Parser context
   8015  * @cur:  the current node in the traversal
   8016  *
   8017  * Traversal function for the "ancestor" direction
   8018  * the ancestor axis contains the ancestors of the context node; the ancestors
   8019  * of the context node consist of the parent of context node and the parent's
   8020  * parent and so on; the nodes are ordered in reverse document order; thus the
   8021  * parent is the first node on the axis, and the parent's parent is the second
   8022  * node on the axis
   8023  *
   8024  * Returns the next element following that axis
   8025  */
   8026 xmlNodePtr
   8027 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8028     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8029     /*
   8030      * the parent of an attribute or namespace node is the element
   8031      * to which the attribute or namespace node is attached
   8032      * !!!!!!!!!!!!!
   8033      */
   8034     if (cur == NULL) {
   8035 	if (ctxt->context->node == NULL) return(NULL);
   8036 	switch (ctxt->context->node->type) {
   8037             case XML_ELEMENT_NODE:
   8038             case XML_TEXT_NODE:
   8039             case XML_CDATA_SECTION_NODE:
   8040             case XML_ENTITY_REF_NODE:
   8041             case XML_ENTITY_NODE:
   8042             case XML_PI_NODE:
   8043             case XML_COMMENT_NODE:
   8044 	    case XML_DTD_NODE:
   8045 	    case XML_ELEMENT_DECL:
   8046 	    case XML_ATTRIBUTE_DECL:
   8047 	    case XML_ENTITY_DECL:
   8048             case XML_NOTATION_NODE:
   8049 	    case XML_XINCLUDE_START:
   8050 	    case XML_XINCLUDE_END:
   8051 		if (ctxt->context->node->parent == NULL)
   8052 		    return((xmlNodePtr) ctxt->context->doc);
   8053 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   8054 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   8055 		     (xmlStrEqual(ctxt->context->node->parent->name,
   8056 				 BAD_CAST "fake node libxslt"))))
   8057 		    return(NULL);
   8058 		return(ctxt->context->node->parent);
   8059             case XML_ATTRIBUTE_NODE: {
   8060 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   8061 
   8062 		return(tmp->parent);
   8063 	    }
   8064             case XML_DOCUMENT_NODE:
   8065             case XML_DOCUMENT_TYPE_NODE:
   8066             case XML_DOCUMENT_FRAG_NODE:
   8067             case XML_HTML_DOCUMENT_NODE:
   8068 #ifdef LIBXML_DOCB_ENABLED
   8069 	    case XML_DOCB_DOCUMENT_NODE:
   8070 #endif
   8071                 return(NULL);
   8072 	    case XML_NAMESPACE_DECL: {
   8073 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8074 
   8075 		if ((ns->next != NULL) &&
   8076 		    (ns->next->type != XML_NAMESPACE_DECL))
   8077 		    return((xmlNodePtr) ns->next);
   8078 		/* Bad, how did that namespace end up here ? */
   8079                 return(NULL);
   8080 	    }
   8081 	}
   8082 	return(NULL);
   8083     }
   8084     if (cur == ctxt->context->doc->children)
   8085 	return((xmlNodePtr) ctxt->context->doc);
   8086     if (cur == (xmlNodePtr) ctxt->context->doc)
   8087 	return(NULL);
   8088     switch (cur->type) {
   8089 	case XML_ELEMENT_NODE:
   8090 	case XML_TEXT_NODE:
   8091 	case XML_CDATA_SECTION_NODE:
   8092 	case XML_ENTITY_REF_NODE:
   8093 	case XML_ENTITY_NODE:
   8094 	case XML_PI_NODE:
   8095 	case XML_COMMENT_NODE:
   8096 	case XML_NOTATION_NODE:
   8097 	case XML_DTD_NODE:
   8098         case XML_ELEMENT_DECL:
   8099         case XML_ATTRIBUTE_DECL:
   8100         case XML_ENTITY_DECL:
   8101 	case XML_XINCLUDE_START:
   8102 	case XML_XINCLUDE_END:
   8103 	    if (cur->parent == NULL)
   8104 		return(NULL);
   8105 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   8106 		((cur->parent->name[0] == ' ') ||
   8107 		 (xmlStrEqual(cur->parent->name,
   8108 			      BAD_CAST "fake node libxslt"))))
   8109 		return(NULL);
   8110 	    return(cur->parent);
   8111 	case XML_ATTRIBUTE_NODE: {
   8112 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   8113 
   8114 	    return(att->parent);
   8115 	}
   8116 	case XML_NAMESPACE_DECL: {
   8117 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8118 
   8119 	    if ((ns->next != NULL) &&
   8120 	        (ns->next->type != XML_NAMESPACE_DECL))
   8121 	        return((xmlNodePtr) ns->next);
   8122 	    /* Bad, how did that namespace end up here ? */
   8123             return(NULL);
   8124 	}
   8125 	case XML_DOCUMENT_NODE:
   8126 	case XML_DOCUMENT_TYPE_NODE:
   8127 	case XML_DOCUMENT_FRAG_NODE:
   8128 	case XML_HTML_DOCUMENT_NODE:
   8129 #ifdef LIBXML_DOCB_ENABLED
   8130 	case XML_DOCB_DOCUMENT_NODE:
   8131 #endif
   8132 	    return(NULL);
   8133     }
   8134     return(NULL);
   8135 }
   8136 
   8137 /**
   8138  * xmlXPathNextAncestorOrSelf:
   8139  * @ctxt:  the XPath Parser context
   8140  * @cur:  the current node in the traversal
   8141  *
   8142  * Traversal function for the "ancestor-or-self" direction
   8143  * he ancestor-or-self axis contains the context node and ancestors of
   8144  * the context node in reverse document order; thus the context node is
   8145  * the first node on the axis, and the context node's parent the second;
   8146  * parent here is defined the same as with the parent axis.
   8147  *
   8148  * Returns the next element following that axis
   8149  */
   8150 xmlNodePtr
   8151 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8152     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8153     if (cur == NULL)
   8154         return(ctxt->context->node);
   8155     return(xmlXPathNextAncestor(ctxt, cur));
   8156 }
   8157 
   8158 /**
   8159  * xmlXPathNextFollowingSibling:
   8160  * @ctxt:  the XPath Parser context
   8161  * @cur:  the current node in the traversal
   8162  *
   8163  * Traversal function for the "following-sibling" direction
   8164  * The following-sibling axis contains the following siblings of the context
   8165  * node in document order.
   8166  *
   8167  * Returns the next element following that axis
   8168  */
   8169 xmlNodePtr
   8170 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8171     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8172     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8173 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8174 	return(NULL);
   8175     if (cur == (xmlNodePtr) ctxt->context->doc)
   8176         return(NULL);
   8177     if (cur == NULL)
   8178         return(ctxt->context->node->next);
   8179     return(cur->next);
   8180 }
   8181 
   8182 /**
   8183  * xmlXPathNextPrecedingSibling:
   8184  * @ctxt:  the XPath Parser context
   8185  * @cur:  the current node in the traversal
   8186  *
   8187  * Traversal function for the "preceding-sibling" direction
   8188  * The preceding-sibling axis contains the preceding siblings of the context
   8189  * node in reverse document order; the first preceding sibling is first on the
   8190  * axis; the sibling preceding that node is the second on the axis and so on.
   8191  *
   8192  * Returns the next element following that axis
   8193  */
   8194 xmlNodePtr
   8195 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8196     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8197     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8198 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8199 	return(NULL);
   8200     if (cur == (xmlNodePtr) ctxt->context->doc)
   8201         return(NULL);
   8202     if (cur == NULL)
   8203         return(ctxt->context->node->prev);
   8204     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8205 	cur = cur->prev;
   8206 	if (cur == NULL)
   8207 	    return(ctxt->context->node->prev);
   8208     }
   8209     return(cur->prev);
   8210 }
   8211 
   8212 /**
   8213  * xmlXPathNextFollowing:
   8214  * @ctxt:  the XPath Parser context
   8215  * @cur:  the current node in the traversal
   8216  *
   8217  * Traversal function for the "following" direction
   8218  * The following axis contains all nodes in the same document as the context
   8219  * node that are after the context node in document order, excluding any
   8220  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8221  * are ordered in document order
   8222  *
   8223  * Returns the next element following that axis
   8224  */
   8225 xmlNodePtr
   8226 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8227     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8228     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8229         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8230         return(cur->children);
   8231 
   8232     if (cur == NULL) {
   8233         cur = ctxt->context->node;
   8234         if (cur->type == XML_NAMESPACE_DECL)
   8235             return(NULL);
   8236         if (cur->type == XML_ATTRIBUTE_NODE)
   8237             cur = cur->parent;
   8238     }
   8239     if (cur == NULL) return(NULL) ; /* ERROR */
   8240     if (cur->next != NULL) return(cur->next) ;
   8241     do {
   8242         cur = cur->parent;
   8243         if (cur == NULL) break;
   8244         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8245         if (cur->next != NULL) return(cur->next);
   8246     } while (cur != NULL);
   8247     return(cur);
   8248 }
   8249 
   8250 /*
   8251  * xmlXPathIsAncestor:
   8252  * @ancestor:  the ancestor node
   8253  * @node:  the current node
   8254  *
   8255  * Check that @ancestor is a @node's ancestor
   8256  *
   8257  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8258  */
   8259 static int
   8260 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8261     if ((ancestor == NULL) || (node == NULL)) return(0);
   8262     if (node->type == XML_NAMESPACE_DECL)
   8263         return(0);
   8264     if (ancestor->type == XML_NAMESPACE_DECL)
   8265         return(0);
   8266     /* nodes need to be in the same document */
   8267     if (ancestor->doc != node->doc) return(0);
   8268     /* avoid searching if ancestor or node is the root node */
   8269     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8270     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8271     while (node->parent != NULL) {
   8272         if (node->parent == ancestor)
   8273             return(1);
   8274 	node = node->parent;
   8275     }
   8276     return(0);
   8277 }
   8278 
   8279 /**
   8280  * xmlXPathNextPreceding:
   8281  * @ctxt:  the XPath Parser context
   8282  * @cur:  the current node in the traversal
   8283  *
   8284  * Traversal function for the "preceding" direction
   8285  * the preceding axis contains all nodes in the same document as the context
   8286  * node that are before the context node in document order, excluding any
   8287  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8288  * ordered in reverse document order
   8289  *
   8290  * Returns the next element following that axis
   8291  */
   8292 xmlNodePtr
   8293 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8294 {
   8295     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8296     if (cur == NULL) {
   8297         cur = ctxt->context->node;
   8298         if (cur->type == XML_NAMESPACE_DECL)
   8299             return(NULL);
   8300         if (cur->type == XML_ATTRIBUTE_NODE)
   8301             return(cur->parent);
   8302     }
   8303     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
   8304 	return (NULL);
   8305     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8306 	cur = cur->prev;
   8307     do {
   8308         if (cur->prev != NULL) {
   8309             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8310             return (cur);
   8311         }
   8312 
   8313         cur = cur->parent;
   8314         if (cur == NULL)
   8315             return (NULL);
   8316         if (cur == ctxt->context->doc->children)
   8317             return (NULL);
   8318     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8319     return (cur);
   8320 }
   8321 
   8322 /**
   8323  * xmlXPathNextPrecedingInternal:
   8324  * @ctxt:  the XPath Parser context
   8325  * @cur:  the current node in the traversal
   8326  *
   8327  * Traversal function for the "preceding" direction
   8328  * the preceding axis contains all nodes in the same document as the context
   8329  * node that are before the context node in document order, excluding any
   8330  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8331  * ordered in reverse document order
   8332  * This is a faster implementation but internal only since it requires a
   8333  * state kept in the parser context: ctxt->ancestor.
   8334  *
   8335  * Returns the next element following that axis
   8336  */
   8337 static xmlNodePtr
   8338 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8339                               xmlNodePtr cur)
   8340 {
   8341     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8342     if (cur == NULL) {
   8343         cur = ctxt->context->node;
   8344         if (cur == NULL)
   8345             return (NULL);
   8346         if (cur->type == XML_NAMESPACE_DECL)
   8347             return (NULL);
   8348         ctxt->ancestor = cur->parent;
   8349     }
   8350     if (cur->type == XML_NAMESPACE_DECL)
   8351         return(NULL);
   8352     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8353 	cur = cur->prev;
   8354     while (cur->prev == NULL) {
   8355         cur = cur->parent;
   8356         if (cur == NULL)
   8357             return (NULL);
   8358         if (cur == ctxt->context->doc->children)
   8359             return (NULL);
   8360         if (cur != ctxt->ancestor)
   8361             return (cur);
   8362         ctxt->ancestor = cur->parent;
   8363     }
   8364     cur = cur->prev;
   8365     while (cur->last != NULL)
   8366         cur = cur->last;
   8367     return (cur);
   8368 }
   8369 
   8370 /**
   8371  * xmlXPathNextNamespace:
   8372  * @ctxt:  the XPath Parser context
   8373  * @cur:  the current attribute in the traversal
   8374  *
   8375  * Traversal function for the "namespace" direction
   8376  * the namespace axis contains the namespace nodes of the context node;
   8377  * the order of nodes on this axis is implementation-defined; the axis will
   8378  * be empty unless the context node is an element
   8379  *
   8380  * We keep the XML namespace node at the end of the list.
   8381  *
   8382  * Returns the next element following that axis
   8383  */
   8384 xmlNodePtr
   8385 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8386     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8387     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8388     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
   8389         if (ctxt->context->tmpNsList != NULL)
   8390 	    xmlFree(ctxt->context->tmpNsList);
   8391 	ctxt->context->tmpNsList =
   8392 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8393 	ctxt->context->tmpNsNr = 0;
   8394 	if (ctxt->context->tmpNsList != NULL) {
   8395 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8396 		ctxt->context->tmpNsNr++;
   8397 	    }
   8398 	}
   8399 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8400     }
   8401     if (ctxt->context->tmpNsNr > 0) {
   8402 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8403     } else {
   8404 	if (ctxt->context->tmpNsList != NULL)
   8405 	    xmlFree(ctxt->context->tmpNsList);
   8406 	ctxt->context->tmpNsList = NULL;
   8407 	return(NULL);
   8408     }
   8409 }
   8410 
   8411 /**
   8412  * xmlXPathNextAttribute:
   8413  * @ctxt:  the XPath Parser context
   8414  * @cur:  the current attribute in the traversal
   8415  *
   8416  * Traversal function for the "attribute" direction
   8417  * TODO: support DTD inherited default attributes
   8418  *
   8419  * Returns the next element following that axis
   8420  */
   8421 xmlNodePtr
   8422 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8423     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8424     if (ctxt->context->node == NULL)
   8425 	return(NULL);
   8426     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8427 	return(NULL);
   8428     if (cur == NULL) {
   8429         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8430 	    return(NULL);
   8431         return((xmlNodePtr)ctxt->context->node->properties);
   8432     }
   8433     return((xmlNodePtr)cur->next);
   8434 }
   8435 
   8436 /************************************************************************
   8437  *									*
   8438  *		NodeTest Functions					*
   8439  *									*
   8440  ************************************************************************/
   8441 
   8442 #define IS_FUNCTION			200
   8443 
   8444 
   8445 /************************************************************************
   8446  *									*
   8447  *		Implicit tree core function library			*
   8448  *									*
   8449  ************************************************************************/
   8450 
   8451 /**
   8452  * xmlXPathRoot:
   8453  * @ctxt:  the XPath Parser context
   8454  *
   8455  * Initialize the context to the root of the document
   8456  */
   8457 void
   8458 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8459     if ((ctxt == NULL) || (ctxt->context == NULL))
   8460 	return;
   8461     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8462     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8463 	ctxt->context->node));
   8464 }
   8465 
   8466 /************************************************************************
   8467  *									*
   8468  *		The explicit core function library			*
   8469  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8470  *									*
   8471  ************************************************************************/
   8472 
   8473 
   8474 /**
   8475  * xmlXPathLastFunction:
   8476  * @ctxt:  the XPath Parser context
   8477  * @nargs:  the number of arguments
   8478  *
   8479  * Implement the last() XPath function
   8480  *    number last()
   8481  * The last function returns the number of nodes in the context node list.
   8482  */
   8483 void
   8484 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8485     CHECK_ARITY(0);
   8486     if (ctxt->context->contextSize >= 0) {
   8487 	valuePush(ctxt,
   8488 	    xmlXPathCacheNewFloat(ctxt->context,
   8489 		(double) ctxt->context->contextSize));
   8490 #ifdef DEBUG_EXPR
   8491 	xmlGenericError(xmlGenericErrorContext,
   8492 		"last() : %d\n", ctxt->context->contextSize);
   8493 #endif
   8494     } else {
   8495 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8496     }
   8497 }
   8498 
   8499 /**
   8500  * xmlXPathPositionFunction:
   8501  * @ctxt:  the XPath Parser context
   8502  * @nargs:  the number of arguments
   8503  *
   8504  * Implement the position() XPath function
   8505  *    number position()
   8506  * The position function returns the position of the context node in the
   8507  * context node list. The first position is 1, and so the last position
   8508  * will be equal to last().
   8509  */
   8510 void
   8511 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8512     CHECK_ARITY(0);
   8513     if (ctxt->context->proximityPosition >= 0) {
   8514 	valuePush(ctxt,
   8515 	      xmlXPathCacheNewFloat(ctxt->context,
   8516 		(double) ctxt->context->proximityPosition));
   8517 #ifdef DEBUG_EXPR
   8518 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8519 		ctxt->context->proximityPosition);
   8520 #endif
   8521     } else {
   8522 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8523     }
   8524 }
   8525 
   8526 /**
   8527  * xmlXPathCountFunction:
   8528  * @ctxt:  the XPath Parser context
   8529  * @nargs:  the number of arguments
   8530  *
   8531  * Implement the count() XPath function
   8532  *    number count(node-set)
   8533  */
   8534 void
   8535 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8536     xmlXPathObjectPtr cur;
   8537 
   8538     CHECK_ARITY(1);
   8539     if ((ctxt->value == NULL) ||
   8540 	((ctxt->value->type != XPATH_NODESET) &&
   8541 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8542 	XP_ERROR(XPATH_INVALID_TYPE);
   8543     cur = valuePop(ctxt);
   8544 
   8545     if ((cur == NULL) || (cur->nodesetval == NULL))
   8546 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8547     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8548 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8549 	    (double) cur->nodesetval->nodeNr));
   8550     } else {
   8551 	if ((cur->nodesetval->nodeNr != 1) ||
   8552 	    (cur->nodesetval->nodeTab == NULL)) {
   8553 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8554 	} else {
   8555 	    xmlNodePtr tmp;
   8556 	    int i = 0;
   8557 
   8558 	    tmp = cur->nodesetval->nodeTab[0];
   8559 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
   8560 		tmp = tmp->children;
   8561 		while (tmp != NULL) {
   8562 		    tmp = tmp->next;
   8563 		    i++;
   8564 		}
   8565 	    }
   8566 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8567 	}
   8568     }
   8569     xmlXPathReleaseObject(ctxt->context, cur);
   8570 }
   8571 
   8572 /**
   8573  * xmlXPathGetElementsByIds:
   8574  * @doc:  the document
   8575  * @ids:  a whitespace separated list of IDs
   8576  *
   8577  * Selects elements by their unique ID.
   8578  *
   8579  * Returns a node-set of selected elements.
   8580  */
   8581 static xmlNodeSetPtr
   8582 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8583     xmlNodeSetPtr ret;
   8584     const xmlChar *cur = ids;
   8585     xmlChar *ID;
   8586     xmlAttrPtr attr;
   8587     xmlNodePtr elem = NULL;
   8588 
   8589     if (ids == NULL) return(NULL);
   8590 
   8591     ret = xmlXPathNodeSetCreate(NULL);
   8592     if (ret == NULL)
   8593         return(ret);
   8594 
   8595     while (IS_BLANK_CH(*cur)) cur++;
   8596     while (*cur != 0) {
   8597 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8598 	    cur++;
   8599 
   8600         ID = xmlStrndup(ids, cur - ids);
   8601 	if (ID != NULL) {
   8602 	    /*
   8603 	     * We used to check the fact that the value passed
   8604 	     * was an NCName, but this generated much troubles for
   8605 	     * me and Aleksey Sanin, people blatantly violated that
   8606 	     * constaint, like Visa3D spec.
   8607 	     * if (xmlValidateNCName(ID, 1) == 0)
   8608 	     */
   8609 	    attr = xmlGetID(doc, ID);
   8610 	    if (attr != NULL) {
   8611 		if (attr->type == XML_ATTRIBUTE_NODE)
   8612 		    elem = attr->parent;
   8613 		else if (attr->type == XML_ELEMENT_NODE)
   8614 		    elem = (xmlNodePtr) attr;
   8615 		else
   8616 		    elem = NULL;
   8617 		if (elem != NULL)
   8618 		    xmlXPathNodeSetAdd(ret, elem);
   8619 	    }
   8620 	    xmlFree(ID);
   8621 	}
   8622 
   8623 	while (IS_BLANK_CH(*cur)) cur++;
   8624 	ids = cur;
   8625     }
   8626     return(ret);
   8627 }
   8628 
   8629 /**
   8630  * xmlXPathIdFunction:
   8631  * @ctxt:  the XPath Parser context
   8632  * @nargs:  the number of arguments
   8633  *
   8634  * Implement the id() XPath function
   8635  *    node-set id(object)
   8636  * The id function selects elements by their unique ID
   8637  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8638  * then the result is the union of the result of applying id to the
   8639  * string value of each of the nodes in the argument node-set. When the
   8640  * argument to id is of any other type, the argument is converted to a
   8641  * string as if by a call to the string function; the string is split
   8642  * into a whitespace-separated list of tokens (whitespace is any sequence
   8643  * of characters matching the production S); the result is a node-set
   8644  * containing the elements in the same document as the context node that
   8645  * have a unique ID equal to any of the tokens in the list.
   8646  */
   8647 void
   8648 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8649     xmlChar *tokens;
   8650     xmlNodeSetPtr ret;
   8651     xmlXPathObjectPtr obj;
   8652 
   8653     CHECK_ARITY(1);
   8654     obj = valuePop(ctxt);
   8655     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8656     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8657 	xmlNodeSetPtr ns;
   8658 	int i;
   8659 
   8660 	ret = xmlXPathNodeSetCreate(NULL);
   8661         /*
   8662          * FIXME -- in an out-of-memory condition this will behave badly.
   8663          * The solution is not clear -- we already popped an item from
   8664          * ctxt, so the object is in a corrupt state.
   8665          */
   8666 
   8667 	if (obj->nodesetval != NULL) {
   8668 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8669 		tokens =
   8670 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8671 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8672 		ret = xmlXPathNodeSetMerge(ret, ns);
   8673 		xmlXPathFreeNodeSet(ns);
   8674 		if (tokens != NULL)
   8675 		    xmlFree(tokens);
   8676 	    }
   8677 	}
   8678 	xmlXPathReleaseObject(ctxt->context, obj);
   8679 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8680 	return;
   8681     }
   8682     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8683     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8684     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8685     xmlXPathReleaseObject(ctxt->context, obj);
   8686     return;
   8687 }
   8688 
   8689 /**
   8690  * xmlXPathLocalNameFunction:
   8691  * @ctxt:  the XPath Parser context
   8692  * @nargs:  the number of arguments
   8693  *
   8694  * Implement the local-name() XPath function
   8695  *    string local-name(node-set?)
   8696  * The local-name function returns a string containing the local part
   8697  * of the name of the node in the argument node-set that is first in
   8698  * document order. If the node-set is empty or the first node has no
   8699  * name, an empty string is returned. If the argument is omitted it
   8700  * defaults to the context node.
   8701  */
   8702 void
   8703 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8704     xmlXPathObjectPtr cur;
   8705 
   8706     if (ctxt == NULL) return;
   8707 
   8708     if (nargs == 0) {
   8709 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8710 	    ctxt->context->node));
   8711 	nargs = 1;
   8712     }
   8713 
   8714     CHECK_ARITY(1);
   8715     if ((ctxt->value == NULL) ||
   8716 	((ctxt->value->type != XPATH_NODESET) &&
   8717 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8718 	XP_ERROR(XPATH_INVALID_TYPE);
   8719     cur = valuePop(ctxt);
   8720 
   8721     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8722 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8723     } else {
   8724 	int i = 0; /* Should be first in document order !!!!! */
   8725 	switch (cur->nodesetval->nodeTab[i]->type) {
   8726 	case XML_ELEMENT_NODE:
   8727 	case XML_ATTRIBUTE_NODE:
   8728 	case XML_PI_NODE:
   8729 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8730 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8731 	    else
   8732 		valuePush(ctxt,
   8733 		      xmlXPathCacheNewString(ctxt->context,
   8734 			cur->nodesetval->nodeTab[i]->name));
   8735 	    break;
   8736 	case XML_NAMESPACE_DECL:
   8737 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8738 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8739 	    break;
   8740 	default:
   8741 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8742 	}
   8743     }
   8744     xmlXPathReleaseObject(ctxt->context, cur);
   8745 }
   8746 
   8747 /**
   8748  * xmlXPathNamespaceURIFunction:
   8749  * @ctxt:  the XPath Parser context
   8750  * @nargs:  the number of arguments
   8751  *
   8752  * Implement the namespace-uri() XPath function
   8753  *    string namespace-uri(node-set?)
   8754  * The namespace-uri function returns a string containing the
   8755  * namespace URI of the expanded name of the node in the argument
   8756  * node-set that is first in document order. If the node-set is empty,
   8757  * the first node has no name, or the expanded name has no namespace
   8758  * URI, an empty string is returned. If the argument is omitted it
   8759  * defaults to the context node.
   8760  */
   8761 void
   8762 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8763     xmlXPathObjectPtr cur;
   8764 
   8765     if (ctxt == NULL) return;
   8766 
   8767     if (nargs == 0) {
   8768 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8769 	    ctxt->context->node));
   8770 	nargs = 1;
   8771     }
   8772     CHECK_ARITY(1);
   8773     if ((ctxt->value == NULL) ||
   8774 	((ctxt->value->type != XPATH_NODESET) &&
   8775 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8776 	XP_ERROR(XPATH_INVALID_TYPE);
   8777     cur = valuePop(ctxt);
   8778 
   8779     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8780 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8781     } else {
   8782 	int i = 0; /* Should be first in document order !!!!! */
   8783 	switch (cur->nodesetval->nodeTab[i]->type) {
   8784 	case XML_ELEMENT_NODE:
   8785 	case XML_ATTRIBUTE_NODE:
   8786 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8787 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8788 	    else
   8789 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8790 			  cur->nodesetval->nodeTab[i]->ns->href));
   8791 	    break;
   8792 	default:
   8793 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8794 	}
   8795     }
   8796     xmlXPathReleaseObject(ctxt->context, cur);
   8797 }
   8798 
   8799 /**
   8800  * xmlXPathNameFunction:
   8801  * @ctxt:  the XPath Parser context
   8802  * @nargs:  the number of arguments
   8803  *
   8804  * Implement the name() XPath function
   8805  *    string name(node-set?)
   8806  * The name function returns a string containing a QName representing
   8807  * the name of the node in the argument node-set that is first in document
   8808  * order. The QName must represent the name with respect to the namespace
   8809  * declarations in effect on the node whose name is being represented.
   8810  * Typically, this will be the form in which the name occurred in the XML
   8811  * source. This need not be the case if there are namespace declarations
   8812  * in effect on the node that associate multiple prefixes with the same
   8813  * namespace. However, an implementation may include information about
   8814  * the original prefix in its representation of nodes; in this case, an
   8815  * implementation can ensure that the returned string is always the same
   8816  * as the QName used in the XML source. If the argument it omitted it
   8817  * defaults to the context node.
   8818  * Libxml keep the original prefix so the "real qualified name" used is
   8819  * returned.
   8820  */
   8821 static void
   8822 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8823 {
   8824     xmlXPathObjectPtr cur;
   8825 
   8826     if (nargs == 0) {
   8827 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8828 	    ctxt->context->node));
   8829         nargs = 1;
   8830     }
   8831 
   8832     CHECK_ARITY(1);
   8833     if ((ctxt->value == NULL) ||
   8834         ((ctxt->value->type != XPATH_NODESET) &&
   8835          (ctxt->value->type != XPATH_XSLT_TREE)))
   8836         XP_ERROR(XPATH_INVALID_TYPE);
   8837     cur = valuePop(ctxt);
   8838 
   8839     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8840         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8841     } else {
   8842         int i = 0;              /* Should be first in document order !!!!! */
   8843 
   8844         switch (cur->nodesetval->nodeTab[i]->type) {
   8845             case XML_ELEMENT_NODE:
   8846             case XML_ATTRIBUTE_NODE:
   8847 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8848 		    valuePush(ctxt,
   8849 			xmlXPathCacheNewCString(ctxt->context, ""));
   8850 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8851                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8852 		    valuePush(ctxt,
   8853 		        xmlXPathCacheNewString(ctxt->context,
   8854 			    cur->nodesetval->nodeTab[i]->name));
   8855 		} else {
   8856 		    xmlChar *fullname;
   8857 
   8858 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8859 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8860 				     NULL, 0);
   8861 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8862 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8863 		    if (fullname == NULL) {
   8864 			XP_ERROR(XPATH_MEMORY_ERROR);
   8865 		    }
   8866 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8867 			ctxt->context, fullname));
   8868                 }
   8869                 break;
   8870             default:
   8871 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8872 		    cur->nodesetval->nodeTab[i]));
   8873                 xmlXPathLocalNameFunction(ctxt, 1);
   8874         }
   8875     }
   8876     xmlXPathReleaseObject(ctxt->context, cur);
   8877 }
   8878 
   8879 
   8880 /**
   8881  * xmlXPathStringFunction:
   8882  * @ctxt:  the XPath Parser context
   8883  * @nargs:  the number of arguments
   8884  *
   8885  * Implement the string() XPath function
   8886  *    string string(object?)
   8887  * The string function converts an object to a string as follows:
   8888  *    - A node-set is converted to a string by returning the value of
   8889  *      the node in the node-set that is first in document order.
   8890  *      If the node-set is empty, an empty string is returned.
   8891  *    - A number is converted to a string as follows
   8892  *      + NaN is converted to the string NaN
   8893  *      + positive zero is converted to the string 0
   8894  *      + negative zero is converted to the string 0
   8895  *      + positive infinity is converted to the string Infinity
   8896  *      + negative infinity is converted to the string -Infinity
   8897  *      + if the number is an integer, the number is represented in
   8898  *        decimal form as a Number with no decimal point and no leading
   8899  *        zeros, preceded by a minus sign (-) if the number is negative
   8900  *      + otherwise, the number is represented in decimal form as a
   8901  *        Number including a decimal point with at least one digit
   8902  *        before the decimal point and at least one digit after the
   8903  *        decimal point, preceded by a minus sign (-) if the number
   8904  *        is negative; there must be no leading zeros before the decimal
   8905  *        point apart possibly from the one required digit immediately
   8906  *        before the decimal point; beyond the one required digit
   8907  *        after the decimal point there must be as many, but only as
   8908  *        many, more digits as are needed to uniquely distinguish the
   8909  *        number from all other IEEE 754 numeric values.
   8910  *    - The boolean false value is converted to the string false.
   8911  *      The boolean true value is converted to the string true.
   8912  *
   8913  * If the argument is omitted, it defaults to a node-set with the
   8914  * context node as its only member.
   8915  */
   8916 void
   8917 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8918     xmlXPathObjectPtr cur;
   8919 
   8920     if (ctxt == NULL) return;
   8921     if (nargs == 0) {
   8922     valuePush(ctxt,
   8923 	xmlXPathCacheWrapString(ctxt->context,
   8924 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8925 	return;
   8926     }
   8927 
   8928     CHECK_ARITY(1);
   8929     cur = valuePop(ctxt);
   8930     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8931     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8932 }
   8933 
   8934 /**
   8935  * xmlXPathStringLengthFunction:
   8936  * @ctxt:  the XPath Parser context
   8937  * @nargs:  the number of arguments
   8938  *
   8939  * Implement the string-length() XPath function
   8940  *    number string-length(string?)
   8941  * The string-length returns the number of characters in the string
   8942  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8943  * the context node converted to a string, in other words the value
   8944  * of the context node.
   8945  */
   8946 void
   8947 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8948     xmlXPathObjectPtr cur;
   8949 
   8950     if (nargs == 0) {
   8951         if ((ctxt == NULL) || (ctxt->context == NULL))
   8952 	    return;
   8953 	if (ctxt->context->node == NULL) {
   8954 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8955 	} else {
   8956 	    xmlChar *content;
   8957 
   8958 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8959 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8960 		xmlUTF8Strlen(content)));
   8961 	    xmlFree(content);
   8962 	}
   8963 	return;
   8964     }
   8965     CHECK_ARITY(1);
   8966     CAST_TO_STRING;
   8967     CHECK_TYPE(XPATH_STRING);
   8968     cur = valuePop(ctxt);
   8969     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8970 	xmlUTF8Strlen(cur->stringval)));
   8971     xmlXPathReleaseObject(ctxt->context, cur);
   8972 }
   8973 
   8974 /**
   8975  * xmlXPathConcatFunction:
   8976  * @ctxt:  the XPath Parser context
   8977  * @nargs:  the number of arguments
   8978  *
   8979  * Implement the concat() XPath function
   8980  *    string concat(string, string, string*)
   8981  * The concat function returns the concatenation of its arguments.
   8982  */
   8983 void
   8984 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8985     xmlXPathObjectPtr cur, newobj;
   8986     xmlChar *tmp;
   8987 
   8988     if (ctxt == NULL) return;
   8989     if (nargs < 2) {
   8990 	CHECK_ARITY(2);
   8991     }
   8992 
   8993     CAST_TO_STRING;
   8994     cur = valuePop(ctxt);
   8995     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   8996 	xmlXPathReleaseObject(ctxt->context, cur);
   8997 	return;
   8998     }
   8999     nargs--;
   9000 
   9001     while (nargs > 0) {
   9002 	CAST_TO_STRING;
   9003 	newobj = valuePop(ctxt);
   9004 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   9005 	    xmlXPathReleaseObject(ctxt->context, newobj);
   9006 	    xmlXPathReleaseObject(ctxt->context, cur);
   9007 	    XP_ERROR(XPATH_INVALID_TYPE);
   9008 	}
   9009 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   9010 	newobj->stringval = cur->stringval;
   9011 	cur->stringval = tmp;
   9012 	xmlXPathReleaseObject(ctxt->context, newobj);
   9013 	nargs--;
   9014     }
   9015     valuePush(ctxt, cur);
   9016 }
   9017 
   9018 /**
   9019  * xmlXPathContainsFunction:
   9020  * @ctxt:  the XPath Parser context
   9021  * @nargs:  the number of arguments
   9022  *
   9023  * Implement the contains() XPath function
   9024  *    boolean contains(string, string)
   9025  * The contains function returns true if the first argument string
   9026  * contains the second argument string, and otherwise returns false.
   9027  */
   9028 void
   9029 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9030     xmlXPathObjectPtr hay, needle;
   9031 
   9032     CHECK_ARITY(2);
   9033     CAST_TO_STRING;
   9034     CHECK_TYPE(XPATH_STRING);
   9035     needle = valuePop(ctxt);
   9036     CAST_TO_STRING;
   9037     hay = valuePop(ctxt);
   9038 
   9039     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9040 	xmlXPathReleaseObject(ctxt->context, hay);
   9041 	xmlXPathReleaseObject(ctxt->context, needle);
   9042 	XP_ERROR(XPATH_INVALID_TYPE);
   9043     }
   9044     if (xmlStrstr(hay->stringval, needle->stringval))
   9045 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9046     else
   9047 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9048     xmlXPathReleaseObject(ctxt->context, hay);
   9049     xmlXPathReleaseObject(ctxt->context, needle);
   9050 }
   9051 
   9052 /**
   9053  * xmlXPathStartsWithFunction:
   9054  * @ctxt:  the XPath Parser context
   9055  * @nargs:  the number of arguments
   9056  *
   9057  * Implement the starts-with() XPath function
   9058  *    boolean starts-with(string, string)
   9059  * The starts-with function returns true if the first argument string
   9060  * starts with the second argument string, and otherwise returns false.
   9061  */
   9062 void
   9063 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9064     xmlXPathObjectPtr hay, needle;
   9065     int n;
   9066 
   9067     CHECK_ARITY(2);
   9068     CAST_TO_STRING;
   9069     CHECK_TYPE(XPATH_STRING);
   9070     needle = valuePop(ctxt);
   9071     CAST_TO_STRING;
   9072     hay = valuePop(ctxt);
   9073 
   9074     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9075 	xmlXPathReleaseObject(ctxt->context, hay);
   9076 	xmlXPathReleaseObject(ctxt->context, needle);
   9077 	XP_ERROR(XPATH_INVALID_TYPE);
   9078     }
   9079     n = xmlStrlen(needle->stringval);
   9080     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   9081         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9082     else
   9083         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9084     xmlXPathReleaseObject(ctxt->context, hay);
   9085     xmlXPathReleaseObject(ctxt->context, needle);
   9086 }
   9087 
   9088 /**
   9089  * xmlXPathSubstringFunction:
   9090  * @ctxt:  the XPath Parser context
   9091  * @nargs:  the number of arguments
   9092  *
   9093  * Implement the substring() XPath function
   9094  *    string substring(string, number, number?)
   9095  * The substring function returns the substring of the first argument
   9096  * starting at the position specified in the second argument with
   9097  * length specified in the third argument. For example,
   9098  * substring("12345",2,3) returns "234". If the third argument is not
   9099  * specified, it returns the substring starting at the position specified
   9100  * in the second argument and continuing to the end of the string. For
   9101  * example, substring("12345",2) returns "2345".  More precisely, each
   9102  * character in the string (see [3.6 Strings]) is considered to have a
   9103  * numeric position: the position of the first character is 1, the position
   9104  * of the second character is 2 and so on. The returned substring contains
   9105  * those characters for which the position of the character is greater than
   9106  * or equal to the second argument and, if the third argument is specified,
   9107  * less than the sum of the second and third arguments; the comparisons
   9108  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   9109  *  - substring("12345", 1.5, 2.6) returns "234"
   9110  *  - substring("12345", 0, 3) returns "12"
   9111  *  - substring("12345", 0 div 0, 3) returns ""
   9112  *  - substring("12345", 1, 0 div 0) returns ""
   9113  *  - substring("12345", -42, 1 div 0) returns "12345"
   9114  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   9115  */
   9116 void
   9117 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9118     xmlXPathObjectPtr str, start, len;
   9119     double le=0, in;
   9120     int i, l, m;
   9121     xmlChar *ret;
   9122 
   9123     if (nargs < 2) {
   9124 	CHECK_ARITY(2);
   9125     }
   9126     if (nargs > 3) {
   9127 	CHECK_ARITY(3);
   9128     }
   9129     /*
   9130      * take care of possible last (position) argument
   9131     */
   9132     if (nargs == 3) {
   9133 	CAST_TO_NUMBER;
   9134 	CHECK_TYPE(XPATH_NUMBER);
   9135 	len = valuePop(ctxt);
   9136 	le = len->floatval;
   9137 	xmlXPathReleaseObject(ctxt->context, len);
   9138     }
   9139 
   9140     CAST_TO_NUMBER;
   9141     CHECK_TYPE(XPATH_NUMBER);
   9142     start = valuePop(ctxt);
   9143     in = start->floatval;
   9144     xmlXPathReleaseObject(ctxt->context, start);
   9145     CAST_TO_STRING;
   9146     CHECK_TYPE(XPATH_STRING);
   9147     str = valuePop(ctxt);
   9148     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9149 
   9150     /*
   9151      * If last pos not present, calculate last position
   9152     */
   9153     if (nargs != 3) {
   9154 	le = (double)m;
   9155 	if (in < 1.0)
   9156 	    in = 1.0;
   9157     }
   9158 
   9159     /* Need to check for the special cases where either
   9160      * the index is NaN, the length is NaN, or both
   9161      * arguments are infinity (relying on Inf + -Inf = NaN)
   9162      */
   9163     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9164         /*
   9165          * To meet the requirements of the spec, the arguments
   9166 	 * must be converted to integer format before
   9167 	 * initial index calculations are done
   9168          *
   9169          * First we go to integer form, rounding up
   9170 	 * and checking for special cases
   9171          */
   9172         i = (int) in;
   9173         if (((double)i)+0.5 <= in) i++;
   9174 
   9175 	if (xmlXPathIsInf(le) == 1) {
   9176 	    l = m;
   9177 	    if (i < 1)
   9178 		i = 1;
   9179 	}
   9180 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9181 	    l = 0;
   9182 	else {
   9183 	    l = (int) le;
   9184 	    if (((double)l)+0.5 <= le) l++;
   9185 	}
   9186 
   9187 	/* Now we normalize inidices */
   9188         i -= 1;
   9189         l += i;
   9190         if (i < 0)
   9191             i = 0;
   9192         if (l > m)
   9193             l = m;
   9194 
   9195         /* number of chars to copy */
   9196         l -= i;
   9197 
   9198         ret = xmlUTF8Strsub(str->stringval, i, l);
   9199     }
   9200     else {
   9201         ret = NULL;
   9202     }
   9203     if (ret == NULL)
   9204 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9205     else {
   9206 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9207 	xmlFree(ret);
   9208     }
   9209     xmlXPathReleaseObject(ctxt->context, str);
   9210 }
   9211 
   9212 /**
   9213  * xmlXPathSubstringBeforeFunction:
   9214  * @ctxt:  the XPath Parser context
   9215  * @nargs:  the number of arguments
   9216  *
   9217  * Implement the substring-before() XPath function
   9218  *    string substring-before(string, string)
   9219  * The substring-before function returns the substring of the first
   9220  * argument string that precedes the first occurrence of the second
   9221  * argument string in the first argument string, or the empty string
   9222  * if the first argument string does not contain the second argument
   9223  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9224  */
   9225 void
   9226 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9227   xmlXPathObjectPtr str;
   9228   xmlXPathObjectPtr find;
   9229   xmlBufPtr target;
   9230   const xmlChar *point;
   9231   int offset;
   9232 
   9233   CHECK_ARITY(2);
   9234   CAST_TO_STRING;
   9235   find = valuePop(ctxt);
   9236   CAST_TO_STRING;
   9237   str = valuePop(ctxt);
   9238 
   9239   target = xmlBufCreate();
   9240   if (target) {
   9241     point = xmlStrstr(str->stringval, find->stringval);
   9242     if (point) {
   9243       offset = (int)(point - str->stringval);
   9244       xmlBufAdd(target, str->stringval, offset);
   9245     }
   9246     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9247 	xmlBufContent(target)));
   9248     xmlBufFree(target);
   9249   }
   9250   xmlXPathReleaseObject(ctxt->context, str);
   9251   xmlXPathReleaseObject(ctxt->context, find);
   9252 }
   9253 
   9254 /**
   9255  * xmlXPathSubstringAfterFunction:
   9256  * @ctxt:  the XPath Parser context
   9257  * @nargs:  the number of arguments
   9258  *
   9259  * Implement the substring-after() XPath function
   9260  *    string substring-after(string, string)
   9261  * The substring-after function returns the substring of the first
   9262  * argument string that follows the first occurrence of the second
   9263  * argument string in the first argument string, or the empty stringi
   9264  * if the first argument string does not contain the second argument
   9265  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9266  * and substring-after("1999/04/01","19") returns 99/04/01.
   9267  */
   9268 void
   9269 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9270   xmlXPathObjectPtr str;
   9271   xmlXPathObjectPtr find;
   9272   xmlBufPtr target;
   9273   const xmlChar *point;
   9274   int offset;
   9275 
   9276   CHECK_ARITY(2);
   9277   CAST_TO_STRING;
   9278   find = valuePop(ctxt);
   9279   CAST_TO_STRING;
   9280   str = valuePop(ctxt);
   9281 
   9282   target = xmlBufCreate();
   9283   if (target) {
   9284     point = xmlStrstr(str->stringval, find->stringval);
   9285     if (point) {
   9286       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9287       xmlBufAdd(target, &str->stringval[offset],
   9288 		   xmlStrlen(str->stringval) - offset);
   9289     }
   9290     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9291 	xmlBufContent(target)));
   9292     xmlBufFree(target);
   9293   }
   9294   xmlXPathReleaseObject(ctxt->context, str);
   9295   xmlXPathReleaseObject(ctxt->context, find);
   9296 }
   9297 
   9298 /**
   9299  * xmlXPathNormalizeFunction:
   9300  * @ctxt:  the XPath Parser context
   9301  * @nargs:  the number of arguments
   9302  *
   9303  * Implement the normalize-space() XPath function
   9304  *    string normalize-space(string?)
   9305  * The normalize-space function returns the argument string with white
   9306  * space normalized by stripping leading and trailing whitespace
   9307  * and replacing sequences of whitespace characters by a single
   9308  * space. Whitespace characters are the same allowed by the S production
   9309  * in XML. If the argument is omitted, it defaults to the context
   9310  * node converted to a string, in other words the value of the context node.
   9311  */
   9312 void
   9313 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9314   xmlXPathObjectPtr obj = NULL;
   9315   xmlChar *source = NULL;
   9316   xmlBufPtr target;
   9317   xmlChar blank;
   9318 
   9319   if (ctxt == NULL) return;
   9320   if (nargs == 0) {
   9321     /* Use current context node */
   9322       valuePush(ctxt,
   9323 	  xmlXPathCacheWrapString(ctxt->context,
   9324 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9325     nargs = 1;
   9326   }
   9327 
   9328   CHECK_ARITY(1);
   9329   CAST_TO_STRING;
   9330   CHECK_TYPE(XPATH_STRING);
   9331   obj = valuePop(ctxt);
   9332   source = obj->stringval;
   9333 
   9334   target = xmlBufCreate();
   9335   if (target && source) {
   9336 
   9337     /* Skip leading whitespaces */
   9338     while (IS_BLANK_CH(*source))
   9339       source++;
   9340 
   9341     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9342     blank = 0;
   9343     while (*source) {
   9344       if (IS_BLANK_CH(*source)) {
   9345 	blank = 0x20;
   9346       } else {
   9347 	if (blank) {
   9348 	  xmlBufAdd(target, &blank, 1);
   9349 	  blank = 0;
   9350 	}
   9351 	xmlBufAdd(target, source, 1);
   9352       }
   9353       source++;
   9354     }
   9355     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9356 	xmlBufContent(target)));
   9357     xmlBufFree(target);
   9358   }
   9359   xmlXPathReleaseObject(ctxt->context, obj);
   9360 }
   9361 
   9362 /**
   9363  * xmlXPathTranslateFunction:
   9364  * @ctxt:  the XPath Parser context
   9365  * @nargs:  the number of arguments
   9366  *
   9367  * Implement the translate() XPath function
   9368  *    string translate(string, string, string)
   9369  * The translate function returns the first argument string with
   9370  * occurrences of characters in the second argument string replaced
   9371  * by the character at the corresponding position in the third argument
   9372  * string. For example, translate("bar","abc","ABC") returns the string
   9373  * BAr. If there is a character in the second argument string with no
   9374  * character at a corresponding position in the third argument string
   9375  * (because the second argument string is longer than the third argument
   9376  * string), then occurrences of that character in the first argument
   9377  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9378  * returns "AAA". If a character occurs more than once in second
   9379  * argument string, then the first occurrence determines the replacement
   9380  * character. If the third argument string is longer than the second
   9381  * argument string, then excess characters are ignored.
   9382  */
   9383 void
   9384 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9385     xmlXPathObjectPtr str;
   9386     xmlXPathObjectPtr from;
   9387     xmlXPathObjectPtr to;
   9388     xmlBufPtr target;
   9389     int offset, max;
   9390     xmlChar ch;
   9391     const xmlChar *point;
   9392     xmlChar *cptr;
   9393 
   9394     CHECK_ARITY(3);
   9395 
   9396     CAST_TO_STRING;
   9397     to = valuePop(ctxt);
   9398     CAST_TO_STRING;
   9399     from = valuePop(ctxt);
   9400     CAST_TO_STRING;
   9401     str = valuePop(ctxt);
   9402 
   9403     target = xmlBufCreate();
   9404     if (target) {
   9405 	max = xmlUTF8Strlen(to->stringval);
   9406 	for (cptr = str->stringval; (ch=*cptr); ) {
   9407 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9408 	    if (offset >= 0) {
   9409 		if (offset < max) {
   9410 		    point = xmlUTF8Strpos(to->stringval, offset);
   9411 		    if (point)
   9412 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
   9413 		}
   9414 	    } else
   9415 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9416 
   9417 	    /* Step to next character in input */
   9418 	    cptr++;
   9419 	    if ( ch & 0x80 ) {
   9420 		/* if not simple ascii, verify proper format */
   9421 		if ( (ch & 0xc0) != 0xc0 ) {
   9422 		    xmlGenericError(xmlGenericErrorContext,
   9423 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9424                     /* not asserting an XPath error is probably better */
   9425 		    break;
   9426 		}
   9427 		/* then skip over remaining bytes for this char */
   9428 		while ( (ch <<= 1) & 0x80 )
   9429 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9430 			xmlGenericError(xmlGenericErrorContext,
   9431 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9432                         /* not asserting an XPath error is probably better */
   9433 			break;
   9434 		    }
   9435 		if (ch & 0x80) /* must have had error encountered */
   9436 		    break;
   9437 	    }
   9438 	}
   9439     }
   9440     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9441 	xmlBufContent(target)));
   9442     xmlBufFree(target);
   9443     xmlXPathReleaseObject(ctxt->context, str);
   9444     xmlXPathReleaseObject(ctxt->context, from);
   9445     xmlXPathReleaseObject(ctxt->context, to);
   9446 }
   9447 
   9448 /**
   9449  * xmlXPathBooleanFunction:
   9450  * @ctxt:  the XPath Parser context
   9451  * @nargs:  the number of arguments
   9452  *
   9453  * Implement the boolean() XPath function
   9454  *    boolean boolean(object)
   9455  * The boolean function converts its argument to a boolean as follows:
   9456  *    - a number is true if and only if it is neither positive or
   9457  *      negative zero nor NaN
   9458  *    - a node-set is true if and only if it is non-empty
   9459  *    - a string is true if and only if its length is non-zero
   9460  */
   9461 void
   9462 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9463     xmlXPathObjectPtr cur;
   9464 
   9465     CHECK_ARITY(1);
   9466     cur = valuePop(ctxt);
   9467     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9468     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9469     valuePush(ctxt, cur);
   9470 }
   9471 
   9472 /**
   9473  * xmlXPathNotFunction:
   9474  * @ctxt:  the XPath Parser context
   9475  * @nargs:  the number of arguments
   9476  *
   9477  * Implement the not() XPath function
   9478  *    boolean not(boolean)
   9479  * The not function returns true if its argument is false,
   9480  * and false otherwise.
   9481  */
   9482 void
   9483 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9484     CHECK_ARITY(1);
   9485     CAST_TO_BOOLEAN;
   9486     CHECK_TYPE(XPATH_BOOLEAN);
   9487     ctxt->value->boolval = ! ctxt->value->boolval;
   9488 }
   9489 
   9490 /**
   9491  * xmlXPathTrueFunction:
   9492  * @ctxt:  the XPath Parser context
   9493  * @nargs:  the number of arguments
   9494  *
   9495  * Implement the true() XPath function
   9496  *    boolean true()
   9497  */
   9498 void
   9499 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9500     CHECK_ARITY(0);
   9501     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9502 }
   9503 
   9504 /**
   9505  * xmlXPathFalseFunction:
   9506  * @ctxt:  the XPath Parser context
   9507  * @nargs:  the number of arguments
   9508  *
   9509  * Implement the false() XPath function
   9510  *    boolean false()
   9511  */
   9512 void
   9513 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9514     CHECK_ARITY(0);
   9515     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9516 }
   9517 
   9518 /**
   9519  * xmlXPathLangFunction:
   9520  * @ctxt:  the XPath Parser context
   9521  * @nargs:  the number of arguments
   9522  *
   9523  * Implement the lang() XPath function
   9524  *    boolean lang(string)
   9525  * The lang function returns true or false depending on whether the
   9526  * language of the context node as specified by xml:lang attributes
   9527  * is the same as or is a sublanguage of the language specified by
   9528  * the argument string. The language of the context node is determined
   9529  * by the value of the xml:lang attribute on the context node, or, if
   9530  * the context node has no xml:lang attribute, by the value of the
   9531  * xml:lang attribute on the nearest ancestor of the context node that
   9532  * has an xml:lang attribute. If there is no such attribute, then lang
   9533  * returns false. If there is such an attribute, then lang returns
   9534  * true if the attribute value is equal to the argument ignoring case,
   9535  * or if there is some suffix starting with - such that the attribute
   9536  * value is equal to the argument ignoring that suffix of the attribute
   9537  * value and ignoring case.
   9538  */
   9539 void
   9540 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9541     xmlXPathObjectPtr val = NULL;
   9542     const xmlChar *theLang = NULL;
   9543     const xmlChar *lang;
   9544     int ret = 0;
   9545     int i;
   9546 
   9547     CHECK_ARITY(1);
   9548     CAST_TO_STRING;
   9549     CHECK_TYPE(XPATH_STRING);
   9550     val = valuePop(ctxt);
   9551     lang = val->stringval;
   9552     theLang = xmlNodeGetLang(ctxt->context->node);
   9553     if ((theLang != NULL) && (lang != NULL)) {
   9554         for (i = 0;lang[i] != 0;i++)
   9555 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9556 	        goto not_equal;
   9557 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9558 	    ret = 1;
   9559     }
   9560 not_equal:
   9561     if (theLang != NULL)
   9562 	xmlFree((void *)theLang);
   9563 
   9564     xmlXPathReleaseObject(ctxt->context, val);
   9565     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9566 }
   9567 
   9568 /**
   9569  * xmlXPathNumberFunction:
   9570  * @ctxt:  the XPath Parser context
   9571  * @nargs:  the number of arguments
   9572  *
   9573  * Implement the number() XPath function
   9574  *    number number(object?)
   9575  */
   9576 void
   9577 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9578     xmlXPathObjectPtr cur;
   9579     double res;
   9580 
   9581     if (ctxt == NULL) return;
   9582     if (nargs == 0) {
   9583 	if (ctxt->context->node == NULL) {
   9584 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9585 	} else {
   9586 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9587 
   9588 	    res = xmlXPathStringEvalNumber(content);
   9589 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9590 	    xmlFree(content);
   9591 	}
   9592 	return;
   9593     }
   9594 
   9595     CHECK_ARITY(1);
   9596     cur = valuePop(ctxt);
   9597     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9598 }
   9599 
   9600 /**
   9601  * xmlXPathSumFunction:
   9602  * @ctxt:  the XPath Parser context
   9603  * @nargs:  the number of arguments
   9604  *
   9605  * Implement the sum() XPath function
   9606  *    number sum(node-set)
   9607  * The sum function returns the sum of the values of the nodes in
   9608  * the argument node-set.
   9609  */
   9610 void
   9611 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9612     xmlXPathObjectPtr cur;
   9613     int i;
   9614     double res = 0.0;
   9615 
   9616     CHECK_ARITY(1);
   9617     if ((ctxt->value == NULL) ||
   9618 	((ctxt->value->type != XPATH_NODESET) &&
   9619 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9620 	XP_ERROR(XPATH_INVALID_TYPE);
   9621     cur = valuePop(ctxt);
   9622 
   9623     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9624 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9625 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9626 	}
   9627     }
   9628     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9629     xmlXPathReleaseObject(ctxt->context, cur);
   9630 }
   9631 
   9632 /*
   9633  * To assure working code on multiple platforms, we want to only depend
   9634  * upon the characteristic truncation of converting a floating point value
   9635  * to an integer.  Unfortunately, because of the different storage sizes
   9636  * of our internal floating point value (double) and integer (int), we
   9637  * can't directly convert (see bug 301162).  This macro is a messy
   9638  * 'workaround'
   9639  */
   9640 #define XTRUNC(f, v)            \
   9641     f = fmod((v), INT_MAX);     \
   9642     f = (v) - (f) + (double)((int)(f));
   9643 
   9644 /**
   9645  * xmlXPathFloorFunction:
   9646  * @ctxt:  the XPath Parser context
   9647  * @nargs:  the number of arguments
   9648  *
   9649  * Implement the floor() XPath function
   9650  *    number floor(number)
   9651  * The floor function returns the largest (closest to positive infinity)
   9652  * number that is not greater than the argument and that is an integer.
   9653  */
   9654 void
   9655 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9656     double f;
   9657 
   9658     CHECK_ARITY(1);
   9659     CAST_TO_NUMBER;
   9660     CHECK_TYPE(XPATH_NUMBER);
   9661 
   9662     XTRUNC(f, ctxt->value->floatval);
   9663     if (f != ctxt->value->floatval) {
   9664 	if (ctxt->value->floatval > 0)
   9665 	    ctxt->value->floatval = f;
   9666 	else
   9667 	    ctxt->value->floatval = f - 1;
   9668     }
   9669 }
   9670 
   9671 /**
   9672  * xmlXPathCeilingFunction:
   9673  * @ctxt:  the XPath Parser context
   9674  * @nargs:  the number of arguments
   9675  *
   9676  * Implement the ceiling() XPath function
   9677  *    number ceiling(number)
   9678  * The ceiling function returns the smallest (closest to negative infinity)
   9679  * number that is not less than the argument and that is an integer.
   9680  */
   9681 void
   9682 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9683     double f;
   9684 
   9685     CHECK_ARITY(1);
   9686     CAST_TO_NUMBER;
   9687     CHECK_TYPE(XPATH_NUMBER);
   9688 
   9689 #if 0
   9690     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9691 #else
   9692     XTRUNC(f, ctxt->value->floatval);
   9693     if (f != ctxt->value->floatval) {
   9694 	if (ctxt->value->floatval > 0)
   9695 	    ctxt->value->floatval = f + 1;
   9696 	else {
   9697 	    if (ctxt->value->floatval < 0 && f == 0)
   9698 	        ctxt->value->floatval = xmlXPathNZERO;
   9699 	    else
   9700 	        ctxt->value->floatval = f;
   9701 	}
   9702 
   9703     }
   9704 #endif
   9705 }
   9706 
   9707 /**
   9708  * xmlXPathRoundFunction:
   9709  * @ctxt:  the XPath Parser context
   9710  * @nargs:  the number of arguments
   9711  *
   9712  * Implement the round() XPath function
   9713  *    number round(number)
   9714  * The round function returns the number that is closest to the
   9715  * argument and that is an integer. If there are two such numbers,
   9716  * then the one that is even is returned.
   9717  */
   9718 void
   9719 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9720     double f;
   9721 
   9722     CHECK_ARITY(1);
   9723     CAST_TO_NUMBER;
   9724     CHECK_TYPE(XPATH_NUMBER);
   9725 
   9726     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
   9727 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
   9728 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
   9729 	(ctxt->value->floatval == 0.0))
   9730 	return;
   9731 
   9732     XTRUNC(f, ctxt->value->floatval);
   9733     if (ctxt->value->floatval < 0) {
   9734 	if (ctxt->value->floatval < f - 0.5)
   9735 	    ctxt->value->floatval = f - 1;
   9736 	else
   9737 	    ctxt->value->floatval = f;
   9738 	if (ctxt->value->floatval == 0)
   9739 	    ctxt->value->floatval = xmlXPathNZERO;
   9740     } else {
   9741 	if (ctxt->value->floatval < f + 0.5)
   9742 	    ctxt->value->floatval = f;
   9743 	else
   9744 	    ctxt->value->floatval = f + 1;
   9745     }
   9746 }
   9747 
   9748 /************************************************************************
   9749  *									*
   9750  *			The Parser					*
   9751  *									*
   9752  ************************************************************************/
   9753 
   9754 /*
   9755  * a few forward declarations since we use a recursive call based
   9756  * implementation.
   9757  */
   9758 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9759 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9760 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9761 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9762 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9763 	                                  int qualified);
   9764 
   9765 /**
   9766  * xmlXPathCurrentChar:
   9767  * @ctxt:  the XPath parser context
   9768  * @cur:  pointer to the beginning of the char
   9769  * @len:  pointer to the length of the char read
   9770  *
   9771  * The current char value, if using UTF-8 this may actually span multiple
   9772  * bytes in the input buffer.
   9773  *
   9774  * Returns the current char value and its length
   9775  */
   9776 
   9777 static int
   9778 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9779     unsigned char c;
   9780     unsigned int val;
   9781     const xmlChar *cur;
   9782 
   9783     if (ctxt == NULL)
   9784 	return(0);
   9785     cur = ctxt->cur;
   9786 
   9787     /*
   9788      * We are supposed to handle UTF8, check it's valid
   9789      * From rfc2044: encoding of the Unicode values on UTF-8:
   9790      *
   9791      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9792      * 0000 0000-0000 007F   0xxxxxxx
   9793      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9794      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9795      *
   9796      * Check for the 0x110000 limit too
   9797      */
   9798     c = *cur;
   9799     if (c & 0x80) {
   9800 	if ((cur[1] & 0xc0) != 0x80)
   9801 	    goto encoding_error;
   9802 	if ((c & 0xe0) == 0xe0) {
   9803 
   9804 	    if ((cur[2] & 0xc0) != 0x80)
   9805 		goto encoding_error;
   9806 	    if ((c & 0xf0) == 0xf0) {
   9807 		if (((c & 0xf8) != 0xf0) ||
   9808 		    ((cur[3] & 0xc0) != 0x80))
   9809 		    goto encoding_error;
   9810 		/* 4-byte code */
   9811 		*len = 4;
   9812 		val = (cur[0] & 0x7) << 18;
   9813 		val |= (cur[1] & 0x3f) << 12;
   9814 		val |= (cur[2] & 0x3f) << 6;
   9815 		val |= cur[3] & 0x3f;
   9816 	    } else {
   9817 	      /* 3-byte code */
   9818 		*len = 3;
   9819 		val = (cur[0] & 0xf) << 12;
   9820 		val |= (cur[1] & 0x3f) << 6;
   9821 		val |= cur[2] & 0x3f;
   9822 	    }
   9823 	} else {
   9824 	  /* 2-byte code */
   9825 	    *len = 2;
   9826 	    val = (cur[0] & 0x1f) << 6;
   9827 	    val |= cur[1] & 0x3f;
   9828 	}
   9829 	if (!IS_CHAR(val)) {
   9830 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9831 	}
   9832 	return(val);
   9833     } else {
   9834 	/* 1-byte code */
   9835 	*len = 1;
   9836 	return((int) *cur);
   9837     }
   9838 encoding_error:
   9839     /*
   9840      * If we detect an UTF8 error that probably means that the
   9841      * input encoding didn't get properly advertised in the
   9842      * declaration header. Report the error and switch the encoding
   9843      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9844      * encoding !)
   9845      */
   9846     *len = 0;
   9847     XP_ERROR0(XPATH_ENCODING_ERROR);
   9848 }
   9849 
   9850 /**
   9851  * xmlXPathParseNCName:
   9852  * @ctxt:  the XPath Parser context
   9853  *
   9854  * parse an XML namespace non qualified name.
   9855  *
   9856  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9857  *
   9858  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9859  *                       CombiningChar | Extender
   9860  *
   9861  * Returns the namespace name or NULL
   9862  */
   9863 
   9864 xmlChar *
   9865 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9866     const xmlChar *in;
   9867     xmlChar *ret;
   9868     int count = 0;
   9869 
   9870     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9871     /*
   9872      * Accelerator for simple ASCII names
   9873      */
   9874     in = ctxt->cur;
   9875     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9876 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9877 	(*in == '_')) {
   9878 	in++;
   9879 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9880 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9881 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9882 	       (*in == '_') || (*in == '.') ||
   9883 	       (*in == '-'))
   9884 	    in++;
   9885 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9886             (*in == '[') || (*in == ']') || (*in == ':') ||
   9887             (*in == '@') || (*in == '*')) {
   9888 	    count = in - ctxt->cur;
   9889 	    if (count == 0)
   9890 		return(NULL);
   9891 	    ret = xmlStrndup(ctxt->cur, count);
   9892 	    ctxt->cur = in;
   9893 	    return(ret);
   9894 	}
   9895     }
   9896     return(xmlXPathParseNameComplex(ctxt, 0));
   9897 }
   9898 
   9899 
   9900 /**
   9901  * xmlXPathParseQName:
   9902  * @ctxt:  the XPath Parser context
   9903  * @prefix:  a xmlChar **
   9904  *
   9905  * parse an XML qualified name
   9906  *
   9907  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9908  *
   9909  * [NS 6] Prefix ::= NCName
   9910  *
   9911  * [NS 7] LocalPart ::= NCName
   9912  *
   9913  * Returns the function returns the local part, and prefix is updated
   9914  *   to get the Prefix if any.
   9915  */
   9916 
   9917 static xmlChar *
   9918 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9919     xmlChar *ret = NULL;
   9920 
   9921     *prefix = NULL;
   9922     ret = xmlXPathParseNCName(ctxt);
   9923     if (ret && CUR == ':') {
   9924         *prefix = ret;
   9925 	NEXT;
   9926 	ret = xmlXPathParseNCName(ctxt);
   9927     }
   9928     return(ret);
   9929 }
   9930 
   9931 /**
   9932  * xmlXPathParseName:
   9933  * @ctxt:  the XPath Parser context
   9934  *
   9935  * parse an XML name
   9936  *
   9937  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9938  *                  CombiningChar | Extender
   9939  *
   9940  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9941  *
   9942  * Returns the namespace name or NULL
   9943  */
   9944 
   9945 xmlChar *
   9946 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9947     const xmlChar *in;
   9948     xmlChar *ret;
   9949     size_t count = 0;
   9950 
   9951     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9952     /*
   9953      * Accelerator for simple ASCII names
   9954      */
   9955     in = ctxt->cur;
   9956     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9957 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9958 	(*in == '_') || (*in == ':')) {
   9959 	in++;
   9960 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9961 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9962 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9963 	       (*in == '_') || (*in == '-') ||
   9964 	       (*in == ':') || (*in == '.'))
   9965 	    in++;
   9966 	if ((*in > 0) && (*in < 0x80)) {
   9967 	    count = in - ctxt->cur;
   9968             if (count > XML_MAX_NAME_LENGTH) {
   9969                 ctxt->cur = in;
   9970                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9971             }
   9972 	    ret = xmlStrndup(ctxt->cur, count);
   9973 	    ctxt->cur = in;
   9974 	    return(ret);
   9975 	}
   9976     }
   9977     return(xmlXPathParseNameComplex(ctxt, 1));
   9978 }
   9979 
   9980 static xmlChar *
   9981 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9982     xmlChar buf[XML_MAX_NAMELEN + 5];
   9983     int len = 0, l;
   9984     int c;
   9985 
   9986     /*
   9987      * Handler for more complex cases
   9988      */
   9989     c = CUR_CHAR(l);
   9990     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9991         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9992         (c == '*') || /* accelerators */
   9993 	(!IS_LETTER(c) && (c != '_') &&
   9994          ((qualified) && (c != ':')))) {
   9995 	return(NULL);
   9996     }
   9997 
   9998     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9999 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10000             (c == '.') || (c == '-') ||
   10001 	    (c == '_') || ((qualified) && (c == ':')) ||
   10002 	    (IS_COMBINING(c)) ||
   10003 	    (IS_EXTENDER(c)))) {
   10004 	COPY_BUF(l,buf,len,c);
   10005 	NEXTL(l);
   10006 	c = CUR_CHAR(l);
   10007 	if (len >= XML_MAX_NAMELEN) {
   10008 	    /*
   10009 	     * Okay someone managed to make a huge name, so he's ready to pay
   10010 	     * for the processing speed.
   10011 	     */
   10012 	    xmlChar *buffer;
   10013 	    int max = len * 2;
   10014 
   10015             if (len > XML_MAX_NAME_LENGTH) {
   10016                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   10017             }
   10018 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   10019 	    if (buffer == NULL) {
   10020 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10021 	    }
   10022 	    memcpy(buffer, buf, len);
   10023 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   10024 		   (c == '.') || (c == '-') ||
   10025 		   (c == '_') || ((qualified) && (c == ':')) ||
   10026 		   (IS_COMBINING(c)) ||
   10027 		   (IS_EXTENDER(c))) {
   10028 		if (len + 10 > max) {
   10029                     if (max > XML_MAX_NAME_LENGTH) {
   10030                         XP_ERRORNULL(XPATH_EXPR_ERROR);
   10031                     }
   10032 		    max *= 2;
   10033 		    buffer = (xmlChar *) xmlRealloc(buffer,
   10034 			                            max * sizeof(xmlChar));
   10035 		    if (buffer == NULL) {
   10036 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10037 		    }
   10038 		}
   10039 		COPY_BUF(l,buffer,len,c);
   10040 		NEXTL(l);
   10041 		c = CUR_CHAR(l);
   10042 	    }
   10043 	    buffer[len] = 0;
   10044 	    return(buffer);
   10045 	}
   10046     }
   10047     if (len == 0)
   10048 	return(NULL);
   10049     return(xmlStrndup(buf, len));
   10050 }
   10051 
   10052 #define MAX_FRAC 20
   10053 
   10054 /*
   10055  * These are used as divisors for the fractional part of a number.
   10056  * Since the table includes 1.0 (representing '0' fractional digits),
   10057  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
   10058  */
   10059 static double my_pow10[MAX_FRAC+1] = {
   10060     1.0, 10.0, 100.0, 1000.0, 10000.0,
   10061     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
   10062     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
   10063     100000000000000.0,
   10064     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
   10065     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
   10066 };
   10067 
   10068 /**
   10069  * xmlXPathStringEvalNumber:
   10070  * @str:  A string to scan
   10071  *
   10072  *  [30a]  Float  ::= Number ('e' Digits?)?
   10073  *
   10074  *  [30]   Number ::=   Digits ('.' Digits?)?
   10075  *                    | '.' Digits
   10076  *  [31]   Digits ::=   [0-9]+
   10077  *
   10078  * Compile a Number in the string
   10079  * In complement of the Number expression, this function also handles
   10080  * negative values : '-' Number.
   10081  *
   10082  * Returns the double value.
   10083  */
   10084 double
   10085 xmlXPathStringEvalNumber(const xmlChar *str) {
   10086     const xmlChar *cur = str;
   10087     double ret;
   10088     int ok = 0;
   10089     int isneg = 0;
   10090     int exponent = 0;
   10091     int is_exponent_negative = 0;
   10092 #ifdef __GNUC__
   10093     unsigned long tmp = 0;
   10094     double temp;
   10095 #endif
   10096     if (cur == NULL) return(0);
   10097     while (IS_BLANK_CH(*cur)) cur++;
   10098     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   10099         return(xmlXPathNAN);
   10100     }
   10101     if (*cur == '-') {
   10102 	isneg = 1;
   10103 	cur++;
   10104     }
   10105 
   10106 #ifdef __GNUC__
   10107     /*
   10108      * tmp/temp is a workaround against a gcc compiler bug
   10109      * http://veillard.com/gcc.bug
   10110      */
   10111     ret = 0;
   10112     while ((*cur >= '0') && (*cur <= '9')) {
   10113 	ret = ret * 10;
   10114 	tmp = (*cur - '0');
   10115 	ok = 1;
   10116 	cur++;
   10117 	temp = (double) tmp;
   10118 	ret = ret + temp;
   10119     }
   10120 #else
   10121     ret = 0;
   10122     while ((*cur >= '0') && (*cur <= '9')) {
   10123 	ret = ret * 10 + (*cur - '0');
   10124 	ok = 1;
   10125 	cur++;
   10126     }
   10127 #endif
   10128 
   10129     if (*cur == '.') {
   10130 	int v, frac = 0;
   10131 	double fraction = 0;
   10132 
   10133         cur++;
   10134 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   10135 	    return(xmlXPathNAN);
   10136 	}
   10137 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
   10138 	    v = (*cur - '0');
   10139 	    fraction = fraction * 10 + v;
   10140 	    frac = frac + 1;
   10141 	    cur++;
   10142 	}
   10143 	fraction /= my_pow10[frac];
   10144 	ret = ret + fraction;
   10145 	while ((*cur >= '0') && (*cur <= '9'))
   10146 	    cur++;
   10147     }
   10148     if ((*cur == 'e') || (*cur == 'E')) {
   10149       cur++;
   10150       if (*cur == '-') {
   10151 	is_exponent_negative = 1;
   10152 	cur++;
   10153       } else if (*cur == '+') {
   10154         cur++;
   10155       }
   10156       while ((*cur >= '0') && (*cur <= '9')) {
   10157 	exponent = exponent * 10 + (*cur - '0');
   10158 	cur++;
   10159       }
   10160     }
   10161     while (IS_BLANK_CH(*cur)) cur++;
   10162     if (*cur != 0) return(xmlXPathNAN);
   10163     if (isneg) ret = -ret;
   10164     if (is_exponent_negative) exponent = -exponent;
   10165     ret *= pow(10.0, (double)exponent);
   10166     return(ret);
   10167 }
   10168 
   10169 /**
   10170  * xmlXPathCompNumber:
   10171  * @ctxt:  the XPath Parser context
   10172  *
   10173  *  [30]   Number ::=   Digits ('.' Digits?)?
   10174  *                    | '.' Digits
   10175  *  [31]   Digits ::=   [0-9]+
   10176  *
   10177  * Compile a Number, then push it on the stack
   10178  *
   10179  */
   10180 static void
   10181 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10182 {
   10183     double ret = 0.0;
   10184     int ok = 0;
   10185     int exponent = 0;
   10186     int is_exponent_negative = 0;
   10187 #ifdef __GNUC__
   10188     unsigned long tmp = 0;
   10189     double temp;
   10190 #endif
   10191 
   10192     CHECK_ERROR;
   10193     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10194         XP_ERROR(XPATH_NUMBER_ERROR);
   10195     }
   10196 #ifdef __GNUC__
   10197     /*
   10198      * tmp/temp is a workaround against a gcc compiler bug
   10199      * http://veillard.com/gcc.bug
   10200      */
   10201     ret = 0;
   10202     while ((CUR >= '0') && (CUR <= '9')) {
   10203 	ret = ret * 10;
   10204 	tmp = (CUR - '0');
   10205         ok = 1;
   10206         NEXT;
   10207 	temp = (double) tmp;
   10208 	ret = ret + temp;
   10209     }
   10210 #else
   10211     ret = 0;
   10212     while ((CUR >= '0') && (CUR <= '9')) {
   10213 	ret = ret * 10 + (CUR - '0');
   10214 	ok = 1;
   10215 	NEXT;
   10216     }
   10217 #endif
   10218     if (CUR == '.') {
   10219 	int v, frac = 0;
   10220 	double fraction = 0;
   10221 
   10222         NEXT;
   10223         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10224             XP_ERROR(XPATH_NUMBER_ERROR);
   10225         }
   10226         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
   10227 	    v = (CUR - '0');
   10228 	    fraction = fraction * 10 + v;
   10229 	    frac = frac + 1;
   10230             NEXT;
   10231         }
   10232         fraction /= my_pow10[frac];
   10233         ret = ret + fraction;
   10234         while ((CUR >= '0') && (CUR <= '9'))
   10235             NEXT;
   10236     }
   10237     if ((CUR == 'e') || (CUR == 'E')) {
   10238         NEXT;
   10239         if (CUR == '-') {
   10240             is_exponent_negative = 1;
   10241             NEXT;
   10242         } else if (CUR == '+') {
   10243 	    NEXT;
   10244 	}
   10245         while ((CUR >= '0') && (CUR <= '9')) {
   10246             exponent = exponent * 10 + (CUR - '0');
   10247             NEXT;
   10248         }
   10249         if (is_exponent_negative)
   10250             exponent = -exponent;
   10251         ret *= pow(10.0, (double) exponent);
   10252     }
   10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10254                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10255 }
   10256 
   10257 /**
   10258  * xmlXPathParseLiteral:
   10259  * @ctxt:  the XPath Parser context
   10260  *
   10261  * Parse a Literal
   10262  *
   10263  *  [29]   Literal ::=   '"' [^"]* '"'
   10264  *                    | "'" [^']* "'"
   10265  *
   10266  * Returns the value found or NULL in case of error
   10267  */
   10268 static xmlChar *
   10269 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10270     const xmlChar *q;
   10271     xmlChar *ret = NULL;
   10272 
   10273     if (CUR == '"') {
   10274         NEXT;
   10275 	q = CUR_PTR;
   10276 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10277 	    NEXT;
   10278 	if (!IS_CHAR_CH(CUR)) {
   10279 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10280 	} else {
   10281 	    ret = xmlStrndup(q, CUR_PTR - q);
   10282 	    NEXT;
   10283         }
   10284     } else if (CUR == '\'') {
   10285         NEXT;
   10286 	q = CUR_PTR;
   10287 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10288 	    NEXT;
   10289 	if (!IS_CHAR_CH(CUR)) {
   10290 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10291 	} else {
   10292 	    ret = xmlStrndup(q, CUR_PTR - q);
   10293 	    NEXT;
   10294         }
   10295     } else {
   10296 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10297     }
   10298     return(ret);
   10299 }
   10300 
   10301 /**
   10302  * xmlXPathCompLiteral:
   10303  * @ctxt:  the XPath Parser context
   10304  *
   10305  * Parse a Literal and push it on the stack.
   10306  *
   10307  *  [29]   Literal ::=   '"' [^"]* '"'
   10308  *                    | "'" [^']* "'"
   10309  *
   10310  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10311  */
   10312 static void
   10313 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10314     const xmlChar *q;
   10315     xmlChar *ret = NULL;
   10316 
   10317     if (CUR == '"') {
   10318         NEXT;
   10319 	q = CUR_PTR;
   10320 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10321 	    NEXT;
   10322 	if (!IS_CHAR_CH(CUR)) {
   10323 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10324 	} else {
   10325 	    ret = xmlStrndup(q, CUR_PTR - q);
   10326 	    NEXT;
   10327         }
   10328     } else if (CUR == '\'') {
   10329         NEXT;
   10330 	q = CUR_PTR;
   10331 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10332 	    NEXT;
   10333 	if (!IS_CHAR_CH(CUR)) {
   10334 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10335 	} else {
   10336 	    ret = xmlStrndup(q, CUR_PTR - q);
   10337 	    NEXT;
   10338         }
   10339     } else {
   10340 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10341     }
   10342     if (ret == NULL) return;
   10343     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10344 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10345     xmlFree(ret);
   10346 }
   10347 
   10348 /**
   10349  * xmlXPathCompVariableReference:
   10350  * @ctxt:  the XPath Parser context
   10351  *
   10352  * Parse a VariableReference, evaluate it and push it on the stack.
   10353  *
   10354  * The variable bindings consist of a mapping from variable names
   10355  * to variable values. The value of a variable is an object, which can be
   10356  * of any of the types that are possible for the value of an expression,
   10357  * and may also be of additional types not specified here.
   10358  *
   10359  * Early evaluation is possible since:
   10360  * The variable bindings [...] used to evaluate a subexpression are
   10361  * always the same as those used to evaluate the containing expression.
   10362  *
   10363  *  [36]   VariableReference ::=   '$' QName
   10364  */
   10365 static void
   10366 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10367     xmlChar *name;
   10368     xmlChar *prefix;
   10369 
   10370     SKIP_BLANKS;
   10371     if (CUR != '$') {
   10372 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10373     }
   10374     NEXT;
   10375     name = xmlXPathParseQName(ctxt, &prefix);
   10376     if (name == NULL) {
   10377 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10378     }
   10379     ctxt->comp->last = -1;
   10380     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10381 	           name, prefix);
   10382     SKIP_BLANKS;
   10383     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10384 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
   10385     }
   10386 }
   10387 
   10388 /**
   10389  * xmlXPathIsNodeType:
   10390  * @name:  a name string
   10391  *
   10392  * Is the name given a NodeType one.
   10393  *
   10394  *  [38]   NodeType ::=   'comment'
   10395  *                    | 'text'
   10396  *                    | 'processing-instruction'
   10397  *                    | 'node'
   10398  *
   10399  * Returns 1 if true 0 otherwise
   10400  */
   10401 int
   10402 xmlXPathIsNodeType(const xmlChar *name) {
   10403     if (name == NULL)
   10404 	return(0);
   10405 
   10406     if (xmlStrEqual(name, BAD_CAST "node"))
   10407 	return(1);
   10408     if (xmlStrEqual(name, BAD_CAST "text"))
   10409 	return(1);
   10410     if (xmlStrEqual(name, BAD_CAST "comment"))
   10411 	return(1);
   10412     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10413 	return(1);
   10414     return(0);
   10415 }
   10416 
   10417 /**
   10418  * xmlXPathCompFunctionCall:
   10419  * @ctxt:  the XPath Parser context
   10420  *
   10421  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10422  *  [17]   Argument ::=   Expr
   10423  *
   10424  * Compile a function call, the evaluation of all arguments are
   10425  * pushed on the stack
   10426  */
   10427 static void
   10428 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10429     xmlChar *name;
   10430     xmlChar *prefix;
   10431     int nbargs = 0;
   10432     int sort = 1;
   10433 
   10434     name = xmlXPathParseQName(ctxt, &prefix);
   10435     if (name == NULL) {
   10436 	xmlFree(prefix);
   10437 	XP_ERROR(XPATH_EXPR_ERROR);
   10438     }
   10439     SKIP_BLANKS;
   10440 #ifdef DEBUG_EXPR
   10441     if (prefix == NULL)
   10442 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10443 			name);
   10444     else
   10445 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10446 			prefix, name);
   10447 #endif
   10448 
   10449     if (CUR != '(') {
   10450 	XP_ERROR(XPATH_EXPR_ERROR);
   10451     }
   10452     NEXT;
   10453     SKIP_BLANKS;
   10454 
   10455     /*
   10456     * Optimization for count(): we don't need the node-set to be sorted.
   10457     */
   10458     if ((prefix == NULL) && (name[0] == 'c') &&
   10459 	xmlStrEqual(name, BAD_CAST "count"))
   10460     {
   10461 	sort = 0;
   10462     }
   10463     ctxt->comp->last = -1;
   10464     if (CUR != ')') {
   10465 	while (CUR != 0) {
   10466 	    int op1 = ctxt->comp->last;
   10467 	    ctxt->comp->last = -1;
   10468 	    xmlXPathCompileExpr(ctxt, sort);
   10469 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10470 		xmlFree(name);
   10471 		xmlFree(prefix);
   10472 		return;
   10473 	    }
   10474 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10475 	    nbargs++;
   10476 	    if (CUR == ')') break;
   10477 	    if (CUR != ',') {
   10478 		XP_ERROR(XPATH_EXPR_ERROR);
   10479 	    }
   10480 	    NEXT;
   10481 	    SKIP_BLANKS;
   10482 	}
   10483     }
   10484     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10485 	           name, prefix);
   10486     NEXT;
   10487     SKIP_BLANKS;
   10488 }
   10489 
   10490 /**
   10491  * xmlXPathCompPrimaryExpr:
   10492  * @ctxt:  the XPath Parser context
   10493  *
   10494  *  [15]   PrimaryExpr ::=   VariableReference
   10495  *                | '(' Expr ')'
   10496  *                | Literal
   10497  *                | Number
   10498  *                | FunctionCall
   10499  *
   10500  * Compile a primary expression.
   10501  */
   10502 static void
   10503 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10504     SKIP_BLANKS;
   10505     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10506     else if (CUR == '(') {
   10507 	NEXT;
   10508 	SKIP_BLANKS;
   10509 	xmlXPathCompileExpr(ctxt, 1);
   10510 	CHECK_ERROR;
   10511 	if (CUR != ')') {
   10512 	    XP_ERROR(XPATH_EXPR_ERROR);
   10513 	}
   10514 	NEXT;
   10515 	SKIP_BLANKS;
   10516     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10517 	xmlXPathCompNumber(ctxt);
   10518     } else if ((CUR == '\'') || (CUR == '"')) {
   10519 	xmlXPathCompLiteral(ctxt);
   10520     } else {
   10521 	xmlXPathCompFunctionCall(ctxt);
   10522     }
   10523     SKIP_BLANKS;
   10524 }
   10525 
   10526 /**
   10527  * xmlXPathCompFilterExpr:
   10528  * @ctxt:  the XPath Parser context
   10529  *
   10530  *  [20]   FilterExpr ::=   PrimaryExpr
   10531  *               | FilterExpr Predicate
   10532  *
   10533  * Compile a filter expression.
   10534  * Square brackets are used to filter expressions in the same way that
   10535  * they are used in location paths. It is an error if the expression to
   10536  * be filtered does not evaluate to a node-set. The context node list
   10537  * used for evaluating the expression in square brackets is the node-set
   10538  * to be filtered listed in document order.
   10539  */
   10540 
   10541 static void
   10542 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10543     xmlXPathCompPrimaryExpr(ctxt);
   10544     CHECK_ERROR;
   10545     SKIP_BLANKS;
   10546 
   10547     while (CUR == '[') {
   10548 	xmlXPathCompPredicate(ctxt, 1);
   10549 	SKIP_BLANKS;
   10550     }
   10551 
   10552 
   10553 }
   10554 
   10555 /**
   10556  * xmlXPathScanName:
   10557  * @ctxt:  the XPath Parser context
   10558  *
   10559  * Trickery: parse an XML name but without consuming the input flow
   10560  * Needed to avoid insanity in the parser state.
   10561  *
   10562  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10563  *                  CombiningChar | Extender
   10564  *
   10565  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10566  *
   10567  * [6] Names ::= Name (S Name)*
   10568  *
   10569  * Returns the Name parsed or NULL
   10570  */
   10571 
   10572 static xmlChar *
   10573 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10574     int len = 0, l;
   10575     int c;
   10576     const xmlChar *cur;
   10577     xmlChar *ret;
   10578 
   10579     cur = ctxt->cur;
   10580 
   10581     c = CUR_CHAR(l);
   10582     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10583 	(!IS_LETTER(c) && (c != '_') &&
   10584          (c != ':'))) {
   10585 	return(NULL);
   10586     }
   10587 
   10588     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10589 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10590             (c == '.') || (c == '-') ||
   10591 	    (c == '_') || (c == ':') ||
   10592 	    (IS_COMBINING(c)) ||
   10593 	    (IS_EXTENDER(c)))) {
   10594 	len += l;
   10595 	NEXTL(l);
   10596 	c = CUR_CHAR(l);
   10597     }
   10598     ret = xmlStrndup(cur, ctxt->cur - cur);
   10599     ctxt->cur = cur;
   10600     return(ret);
   10601 }
   10602 
   10603 /**
   10604  * xmlXPathCompPathExpr:
   10605  * @ctxt:  the XPath Parser context
   10606  *
   10607  *  [19]   PathExpr ::=   LocationPath
   10608  *               | FilterExpr
   10609  *               | FilterExpr '/' RelativeLocationPath
   10610  *               | FilterExpr '//' RelativeLocationPath
   10611  *
   10612  * Compile a path expression.
   10613  * The / operator and // operators combine an arbitrary expression
   10614  * and a relative location path. It is an error if the expression
   10615  * does not evaluate to a node-set.
   10616  * The / operator does composition in the same way as when / is
   10617  * used in a location path. As in location paths, // is short for
   10618  * /descendant-or-self::node()/.
   10619  */
   10620 
   10621 static void
   10622 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10623     int lc = 1;           /* Should we branch to LocationPath ?         */
   10624     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10625 
   10626     SKIP_BLANKS;
   10627     if ((CUR == '$') || (CUR == '(') ||
   10628 	(IS_ASCII_DIGIT(CUR)) ||
   10629         (CUR == '\'') || (CUR == '"') ||
   10630 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10631 	lc = 0;
   10632     } else if (CUR == '*') {
   10633 	/* relative or absolute location path */
   10634 	lc = 1;
   10635     } else if (CUR == '/') {
   10636 	/* relative or absolute location path */
   10637 	lc = 1;
   10638     } else if (CUR == '@') {
   10639 	/* relative abbreviated attribute location path */
   10640 	lc = 1;
   10641     } else if (CUR == '.') {
   10642 	/* relative abbreviated attribute location path */
   10643 	lc = 1;
   10644     } else {
   10645 	/*
   10646 	 * Problem is finding if we have a name here whether it's:
   10647 	 *   - a nodetype
   10648 	 *   - a function call in which case it's followed by '('
   10649 	 *   - an axis in which case it's followed by ':'
   10650 	 *   - a element name
   10651 	 * We do an a priori analysis here rather than having to
   10652 	 * maintain parsed token content through the recursive function
   10653 	 * calls. This looks uglier but makes the code easier to
   10654 	 * read/write/debug.
   10655 	 */
   10656 	SKIP_BLANKS;
   10657 	name = xmlXPathScanName(ctxt);
   10658 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10659 #ifdef DEBUG_STEP
   10660 	    xmlGenericError(xmlGenericErrorContext,
   10661 		    "PathExpr: Axis\n");
   10662 #endif
   10663 	    lc = 1;
   10664 	    xmlFree(name);
   10665 	} else if (name != NULL) {
   10666 	    int len =xmlStrlen(name);
   10667 
   10668 
   10669 	    while (NXT(len) != 0) {
   10670 		if (NXT(len) == '/') {
   10671 		    /* element name */
   10672 #ifdef DEBUG_STEP
   10673 		    xmlGenericError(xmlGenericErrorContext,
   10674 			    "PathExpr: AbbrRelLocation\n");
   10675 #endif
   10676 		    lc = 1;
   10677 		    break;
   10678 		} else if (IS_BLANK_CH(NXT(len))) {
   10679 		    /* ignore blanks */
   10680 		    ;
   10681 		} else if (NXT(len) == ':') {
   10682 #ifdef DEBUG_STEP
   10683 		    xmlGenericError(xmlGenericErrorContext,
   10684 			    "PathExpr: AbbrRelLocation\n");
   10685 #endif
   10686 		    lc = 1;
   10687 		    break;
   10688 		} else if ((NXT(len) == '(')) {
   10689 		    /* Note Type or Function */
   10690 		    if (xmlXPathIsNodeType(name)) {
   10691 #ifdef DEBUG_STEP
   10692 		        xmlGenericError(xmlGenericErrorContext,
   10693 				"PathExpr: Type search\n");
   10694 #endif
   10695 			lc = 1;
   10696 		    } else {
   10697 #ifdef DEBUG_STEP
   10698 		        xmlGenericError(xmlGenericErrorContext,
   10699 				"PathExpr: function call\n");
   10700 #endif
   10701 			lc = 0;
   10702 		    }
   10703                     break;
   10704 		} else if ((NXT(len) == '[')) {
   10705 		    /* element name */
   10706 #ifdef DEBUG_STEP
   10707 		    xmlGenericError(xmlGenericErrorContext,
   10708 			    "PathExpr: AbbrRelLocation\n");
   10709 #endif
   10710 		    lc = 1;
   10711 		    break;
   10712 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10713 			   (NXT(len) == '=')) {
   10714 		    lc = 1;
   10715 		    break;
   10716 		} else {
   10717 		    lc = 1;
   10718 		    break;
   10719 		}
   10720 		len++;
   10721 	    }
   10722 	    if (NXT(len) == 0) {
   10723 #ifdef DEBUG_STEP
   10724 		xmlGenericError(xmlGenericErrorContext,
   10725 			"PathExpr: AbbrRelLocation\n");
   10726 #endif
   10727 		/* element name */
   10728 		lc = 1;
   10729 	    }
   10730 	    xmlFree(name);
   10731 	} else {
   10732 	    /* make sure all cases are covered explicitly */
   10733 	    XP_ERROR(XPATH_EXPR_ERROR);
   10734 	}
   10735     }
   10736 
   10737     if (lc) {
   10738 	if (CUR == '/') {
   10739 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10740 	} else {
   10741 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10742 	}
   10743 	xmlXPathCompLocationPath(ctxt);
   10744     } else {
   10745 	xmlXPathCompFilterExpr(ctxt);
   10746 	CHECK_ERROR;
   10747 	if ((CUR == '/') && (NXT(1) == '/')) {
   10748 	    SKIP(2);
   10749 	    SKIP_BLANKS;
   10750 
   10751 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10752 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10753 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10754 
   10755 	    xmlXPathCompRelativeLocationPath(ctxt);
   10756 	} else if (CUR == '/') {
   10757 	    xmlXPathCompRelativeLocationPath(ctxt);
   10758 	}
   10759     }
   10760     SKIP_BLANKS;
   10761 }
   10762 
   10763 /**
   10764  * xmlXPathCompUnionExpr:
   10765  * @ctxt:  the XPath Parser context
   10766  *
   10767  *  [18]   UnionExpr ::=   PathExpr
   10768  *               | UnionExpr '|' PathExpr
   10769  *
   10770  * Compile an union expression.
   10771  */
   10772 
   10773 static void
   10774 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10775     xmlXPathCompPathExpr(ctxt);
   10776     CHECK_ERROR;
   10777     SKIP_BLANKS;
   10778     while (CUR == '|') {
   10779 	int op1 = ctxt->comp->last;
   10780 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10781 
   10782 	NEXT;
   10783 	SKIP_BLANKS;
   10784 	xmlXPathCompPathExpr(ctxt);
   10785 
   10786 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10787 
   10788 	SKIP_BLANKS;
   10789     }
   10790 }
   10791 
   10792 /**
   10793  * xmlXPathCompUnaryExpr:
   10794  * @ctxt:  the XPath Parser context
   10795  *
   10796  *  [27]   UnaryExpr ::=   UnionExpr
   10797  *                   | '-' UnaryExpr
   10798  *
   10799  * Compile an unary expression.
   10800  */
   10801 
   10802 static void
   10803 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10804     int minus = 0;
   10805     int found = 0;
   10806 
   10807     SKIP_BLANKS;
   10808     while (CUR == '-') {
   10809         minus = 1 - minus;
   10810 	found = 1;
   10811 	NEXT;
   10812 	SKIP_BLANKS;
   10813     }
   10814 
   10815     xmlXPathCompUnionExpr(ctxt);
   10816     CHECK_ERROR;
   10817     if (found) {
   10818 	if (minus)
   10819 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10820 	else
   10821 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10822     }
   10823 }
   10824 
   10825 /**
   10826  * xmlXPathCompMultiplicativeExpr:
   10827  * @ctxt:  the XPath Parser context
   10828  *
   10829  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10830  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10831  *                   | MultiplicativeExpr 'div' UnaryExpr
   10832  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10833  *  [34]   MultiplyOperator ::=   '*'
   10834  *
   10835  * Compile an Additive expression.
   10836  */
   10837 
   10838 static void
   10839 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10840     xmlXPathCompUnaryExpr(ctxt);
   10841     CHECK_ERROR;
   10842     SKIP_BLANKS;
   10843     while ((CUR == '*') ||
   10844            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10845            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10846 	int op = -1;
   10847 	int op1 = ctxt->comp->last;
   10848 
   10849         if (CUR == '*') {
   10850 	    op = 0;
   10851 	    NEXT;
   10852 	} else if (CUR == 'd') {
   10853 	    op = 1;
   10854 	    SKIP(3);
   10855 	} else if (CUR == 'm') {
   10856 	    op = 2;
   10857 	    SKIP(3);
   10858 	}
   10859 	SKIP_BLANKS;
   10860         xmlXPathCompUnaryExpr(ctxt);
   10861 	CHECK_ERROR;
   10862 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10863 	SKIP_BLANKS;
   10864     }
   10865 }
   10866 
   10867 /**
   10868  * xmlXPathCompAdditiveExpr:
   10869  * @ctxt:  the XPath Parser context
   10870  *
   10871  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10872  *                   | AdditiveExpr '+' MultiplicativeExpr
   10873  *                   | AdditiveExpr '-' MultiplicativeExpr
   10874  *
   10875  * Compile an Additive expression.
   10876  */
   10877 
   10878 static void
   10879 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10880 
   10881     xmlXPathCompMultiplicativeExpr(ctxt);
   10882     CHECK_ERROR;
   10883     SKIP_BLANKS;
   10884     while ((CUR == '+') || (CUR == '-')) {
   10885 	int plus;
   10886 	int op1 = ctxt->comp->last;
   10887 
   10888         if (CUR == '+') plus = 1;
   10889 	else plus = 0;
   10890 	NEXT;
   10891 	SKIP_BLANKS;
   10892         xmlXPathCompMultiplicativeExpr(ctxt);
   10893 	CHECK_ERROR;
   10894 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10895 	SKIP_BLANKS;
   10896     }
   10897 }
   10898 
   10899 /**
   10900  * xmlXPathCompRelationalExpr:
   10901  * @ctxt:  the XPath Parser context
   10902  *
   10903  *  [24]   RelationalExpr ::=   AdditiveExpr
   10904  *                 | RelationalExpr '<' AdditiveExpr
   10905  *                 | RelationalExpr '>' AdditiveExpr
   10906  *                 | RelationalExpr '<=' AdditiveExpr
   10907  *                 | RelationalExpr '>=' AdditiveExpr
   10908  *
   10909  *  A <= B > C is allowed ? Answer from James, yes with
   10910  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10911  *  which is basically what got implemented.
   10912  *
   10913  * Compile a Relational expression, then push the result
   10914  * on the stack
   10915  */
   10916 
   10917 static void
   10918 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10919     xmlXPathCompAdditiveExpr(ctxt);
   10920     CHECK_ERROR;
   10921     SKIP_BLANKS;
   10922     while ((CUR == '<') ||
   10923            (CUR == '>') ||
   10924            ((CUR == '<') && (NXT(1) == '=')) ||
   10925            ((CUR == '>') && (NXT(1) == '='))) {
   10926 	int inf, strict;
   10927 	int op1 = ctxt->comp->last;
   10928 
   10929         if (CUR == '<') inf = 1;
   10930 	else inf = 0;
   10931 	if (NXT(1) == '=') strict = 0;
   10932 	else strict = 1;
   10933 	NEXT;
   10934 	if (!strict) NEXT;
   10935 	SKIP_BLANKS;
   10936         xmlXPathCompAdditiveExpr(ctxt);
   10937 	CHECK_ERROR;
   10938 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10939 	SKIP_BLANKS;
   10940     }
   10941 }
   10942 
   10943 /**
   10944  * xmlXPathCompEqualityExpr:
   10945  * @ctxt:  the XPath Parser context
   10946  *
   10947  *  [23]   EqualityExpr ::=   RelationalExpr
   10948  *                 | EqualityExpr '=' RelationalExpr
   10949  *                 | EqualityExpr '!=' RelationalExpr
   10950  *
   10951  *  A != B != C is allowed ? Answer from James, yes with
   10952  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10953  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10954  *  which is basically what got implemented.
   10955  *
   10956  * Compile an Equality expression.
   10957  *
   10958  */
   10959 static void
   10960 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10961     xmlXPathCompRelationalExpr(ctxt);
   10962     CHECK_ERROR;
   10963     SKIP_BLANKS;
   10964     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10965 	int eq;
   10966 	int op1 = ctxt->comp->last;
   10967 
   10968         if (CUR == '=') eq = 1;
   10969 	else eq = 0;
   10970 	NEXT;
   10971 	if (!eq) NEXT;
   10972 	SKIP_BLANKS;
   10973         xmlXPathCompRelationalExpr(ctxt);
   10974 	CHECK_ERROR;
   10975 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10976 	SKIP_BLANKS;
   10977     }
   10978 }
   10979 
   10980 /**
   10981  * xmlXPathCompAndExpr:
   10982  * @ctxt:  the XPath Parser context
   10983  *
   10984  *  [22]   AndExpr ::=   EqualityExpr
   10985  *                 | AndExpr 'and' EqualityExpr
   10986  *
   10987  * Compile an AND expression.
   10988  *
   10989  */
   10990 static void
   10991 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10992     xmlXPathCompEqualityExpr(ctxt);
   10993     CHECK_ERROR;
   10994     SKIP_BLANKS;
   10995     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10996 	int op1 = ctxt->comp->last;
   10997         SKIP(3);
   10998 	SKIP_BLANKS;
   10999         xmlXPathCompEqualityExpr(ctxt);
   11000 	CHECK_ERROR;
   11001 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   11002 	SKIP_BLANKS;
   11003     }
   11004 }
   11005 
   11006 /**
   11007  * xmlXPathCompileExpr:
   11008  * @ctxt:  the XPath Parser context
   11009  *
   11010  *  [14]   Expr ::=   OrExpr
   11011  *  [21]   OrExpr ::=   AndExpr
   11012  *                 | OrExpr 'or' AndExpr
   11013  *
   11014  * Parse and compile an expression
   11015  */
   11016 static void
   11017 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   11018     xmlXPathCompAndExpr(ctxt);
   11019     CHECK_ERROR;
   11020     SKIP_BLANKS;
   11021     while ((CUR == 'o') && (NXT(1) == 'r')) {
   11022 	int op1 = ctxt->comp->last;
   11023         SKIP(2);
   11024 	SKIP_BLANKS;
   11025         xmlXPathCompAndExpr(ctxt);
   11026 	CHECK_ERROR;
   11027 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   11028 	SKIP_BLANKS;
   11029     }
   11030     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   11031 	/* more ops could be optimized too */
   11032 	/*
   11033 	* This is the main place to eliminate sorting for
   11034 	* operations which don't require a sorted node-set.
   11035 	* E.g. count().
   11036 	*/
   11037 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   11038     }
   11039 }
   11040 
   11041 /**
   11042  * xmlXPathCompPredicate:
   11043  * @ctxt:  the XPath Parser context
   11044  * @filter:  act as a filter
   11045  *
   11046  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   11047  *  [9]   PredicateExpr ::=   Expr
   11048  *
   11049  * Compile a predicate expression
   11050  */
   11051 static void
   11052 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   11053     int op1 = ctxt->comp->last;
   11054 
   11055     SKIP_BLANKS;
   11056     if (CUR != '[') {
   11057 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11058     }
   11059     NEXT;
   11060     SKIP_BLANKS;
   11061 
   11062     ctxt->comp->last = -1;
   11063     /*
   11064     * This call to xmlXPathCompileExpr() will deactivate sorting
   11065     * of the predicate result.
   11066     * TODO: Sorting is still activated for filters, since I'm not
   11067     *  sure if needed. Normally sorting should not be needed, since
   11068     *  a filter can only diminish the number of items in a sequence,
   11069     *  but won't change its order; so if the initial sequence is sorted,
   11070     *  subsequent sorting is not needed.
   11071     */
   11072     if (! filter)
   11073 	xmlXPathCompileExpr(ctxt, 0);
   11074     else
   11075 	xmlXPathCompileExpr(ctxt, 1);
   11076     CHECK_ERROR;
   11077 
   11078     if (CUR != ']') {
   11079 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11080     }
   11081 
   11082     if (filter)
   11083 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   11084     else
   11085 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   11086 
   11087     NEXT;
   11088     SKIP_BLANKS;
   11089 }
   11090 
   11091 /**
   11092  * xmlXPathCompNodeTest:
   11093  * @ctxt:  the XPath Parser context
   11094  * @test:  pointer to a xmlXPathTestVal
   11095  * @type:  pointer to a xmlXPathTypeVal
   11096  * @prefix:  placeholder for a possible name prefix
   11097  *
   11098  * [7] NodeTest ::=   NameTest
   11099  *		    | NodeType '(' ')'
   11100  *		    | 'processing-instruction' '(' Literal ')'
   11101  *
   11102  * [37] NameTest ::=  '*'
   11103  *		    | NCName ':' '*'
   11104  *		    | QName
   11105  * [38] NodeType ::= 'comment'
   11106  *		   | 'text'
   11107  *		   | 'processing-instruction'
   11108  *		   | 'node'
   11109  *
   11110  * Returns the name found and updates @test, @type and @prefix appropriately
   11111  */
   11112 static xmlChar *
   11113 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11114 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11115 		     xmlChar *name) {
   11116     int blanks;
   11117 
   11118     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11119 	STRANGE;
   11120 	return(NULL);
   11121     }
   11122     *type = (xmlXPathTypeVal) 0;
   11123     *test = (xmlXPathTestVal) 0;
   11124     *prefix = NULL;
   11125     SKIP_BLANKS;
   11126 
   11127     if ((name == NULL) && (CUR == '*')) {
   11128 	/*
   11129 	 * All elements
   11130 	 */
   11131 	NEXT;
   11132 	*test = NODE_TEST_ALL;
   11133 	return(NULL);
   11134     }
   11135 
   11136     if (name == NULL)
   11137 	name = xmlXPathParseNCName(ctxt);
   11138     if (name == NULL) {
   11139 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11140     }
   11141 
   11142     blanks = IS_BLANK_CH(CUR);
   11143     SKIP_BLANKS;
   11144     if (CUR == '(') {
   11145 	NEXT;
   11146 	/*
   11147 	 * NodeType or PI search
   11148 	 */
   11149 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11150 	    *type = NODE_TYPE_COMMENT;
   11151 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11152 	    *type = NODE_TYPE_NODE;
   11153 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11154 	    *type = NODE_TYPE_PI;
   11155 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11156 	    *type = NODE_TYPE_TEXT;
   11157 	else {
   11158 	    if (name != NULL)
   11159 		xmlFree(name);
   11160 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11161 	}
   11162 
   11163 	*test = NODE_TEST_TYPE;
   11164 
   11165 	SKIP_BLANKS;
   11166 	if (*type == NODE_TYPE_PI) {
   11167 	    /*
   11168 	     * Specific case: search a PI by name.
   11169 	     */
   11170 	    if (name != NULL)
   11171 		xmlFree(name);
   11172 	    name = NULL;
   11173 	    if (CUR != ')') {
   11174 		name = xmlXPathParseLiteral(ctxt);
   11175 		CHECK_ERROR NULL;
   11176 		*test = NODE_TEST_PI;
   11177 		SKIP_BLANKS;
   11178 	    }
   11179 	}
   11180 	if (CUR != ')') {
   11181 	    if (name != NULL)
   11182 		xmlFree(name);
   11183 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11184 	}
   11185 	NEXT;
   11186 	return(name);
   11187     }
   11188     *test = NODE_TEST_NAME;
   11189     if ((!blanks) && (CUR == ':')) {
   11190 	NEXT;
   11191 
   11192 	/*
   11193 	 * Since currently the parser context don't have a
   11194 	 * namespace list associated:
   11195 	 * The namespace name for this prefix can be computed
   11196 	 * only at evaluation time. The compilation is done
   11197 	 * outside of any context.
   11198 	 */
   11199 #if 0
   11200 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11201 	if (name != NULL)
   11202 	    xmlFree(name);
   11203 	if (*prefix == NULL) {
   11204 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11205 	}
   11206 #else
   11207 	*prefix = name;
   11208 #endif
   11209 
   11210 	if (CUR == '*') {
   11211 	    /*
   11212 	     * All elements
   11213 	     */
   11214 	    NEXT;
   11215 	    *test = NODE_TEST_ALL;
   11216 	    return(NULL);
   11217 	}
   11218 
   11219 	name = xmlXPathParseNCName(ctxt);
   11220 	if (name == NULL) {
   11221 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11222 	}
   11223     }
   11224     return(name);
   11225 }
   11226 
   11227 /**
   11228  * xmlXPathIsAxisName:
   11229  * @name:  a preparsed name token
   11230  *
   11231  * [6] AxisName ::=   'ancestor'
   11232  *                  | 'ancestor-or-self'
   11233  *                  | 'attribute'
   11234  *                  | 'child'
   11235  *                  | 'descendant'
   11236  *                  | 'descendant-or-self'
   11237  *                  | 'following'
   11238  *                  | 'following-sibling'
   11239  *                  | 'namespace'
   11240  *                  | 'parent'
   11241  *                  | 'preceding'
   11242  *                  | 'preceding-sibling'
   11243  *                  | 'self'
   11244  *
   11245  * Returns the axis or 0
   11246  */
   11247 static xmlXPathAxisVal
   11248 xmlXPathIsAxisName(const xmlChar *name) {
   11249     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11250     switch (name[0]) {
   11251 	case 'a':
   11252 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11253 		ret = AXIS_ANCESTOR;
   11254 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11255 		ret = AXIS_ANCESTOR_OR_SELF;
   11256 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11257 		ret = AXIS_ATTRIBUTE;
   11258 	    break;
   11259 	case 'c':
   11260 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11261 		ret = AXIS_CHILD;
   11262 	    break;
   11263 	case 'd':
   11264 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11265 		ret = AXIS_DESCENDANT;
   11266 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11267 		ret = AXIS_DESCENDANT_OR_SELF;
   11268 	    break;
   11269 	case 'f':
   11270 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11271 		ret = AXIS_FOLLOWING;
   11272 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11273 		ret = AXIS_FOLLOWING_SIBLING;
   11274 	    break;
   11275 	case 'n':
   11276 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11277 		ret = AXIS_NAMESPACE;
   11278 	    break;
   11279 	case 'p':
   11280 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11281 		ret = AXIS_PARENT;
   11282 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11283 		ret = AXIS_PRECEDING;
   11284 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11285 		ret = AXIS_PRECEDING_SIBLING;
   11286 	    break;
   11287 	case 's':
   11288 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11289 		ret = AXIS_SELF;
   11290 	    break;
   11291     }
   11292     return(ret);
   11293 }
   11294 
   11295 /**
   11296  * xmlXPathCompStep:
   11297  * @ctxt:  the XPath Parser context
   11298  *
   11299  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11300  *                  | AbbreviatedStep
   11301  *
   11302  * [12] AbbreviatedStep ::=   '.' | '..'
   11303  *
   11304  * [5] AxisSpecifier ::= AxisName '::'
   11305  *                  | AbbreviatedAxisSpecifier
   11306  *
   11307  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11308  *
   11309  * Modified for XPtr range support as:
   11310  *
   11311  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11312  *                     | AbbreviatedStep
   11313  *                     | 'range-to' '(' Expr ')' Predicate*
   11314  *
   11315  * Compile one step in a Location Path
   11316  * A location step of . is short for self::node(). This is
   11317  * particularly useful in conjunction with //. For example, the
   11318  * location path .//para is short for
   11319  * self::node()/descendant-or-self::node()/child::para
   11320  * and so will select all para descendant elements of the context
   11321  * node.
   11322  * Similarly, a location step of .. is short for parent::node().
   11323  * For example, ../title is short for parent::node()/child::title
   11324  * and so will select the title children of the parent of the context
   11325  * node.
   11326  */
   11327 static void
   11328 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11329 #ifdef LIBXML_XPTR_ENABLED
   11330     int rangeto = 0;
   11331     int op2 = -1;
   11332 #endif
   11333 
   11334     SKIP_BLANKS;
   11335     if ((CUR == '.') && (NXT(1) == '.')) {
   11336 	SKIP(2);
   11337 	SKIP_BLANKS;
   11338 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11339 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11340     } else if (CUR == '.') {
   11341 	NEXT;
   11342 	SKIP_BLANKS;
   11343     } else {
   11344 	xmlChar *name = NULL;
   11345 	const xmlChar *prefix = NULL;
   11346 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11347 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11348 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11349 	int op1;
   11350 
   11351 	/*
   11352 	 * The modification needed for XPointer change to the production
   11353 	 */
   11354 #ifdef LIBXML_XPTR_ENABLED
   11355 	if (ctxt->xptr) {
   11356 	    name = xmlXPathParseNCName(ctxt);
   11357 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11358                 op2 = ctxt->comp->last;
   11359 		xmlFree(name);
   11360 		SKIP_BLANKS;
   11361 		if (CUR != '(') {
   11362 		    XP_ERROR(XPATH_EXPR_ERROR);
   11363 		}
   11364 		NEXT;
   11365 		SKIP_BLANKS;
   11366 
   11367 		xmlXPathCompileExpr(ctxt, 1);
   11368 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11369 		CHECK_ERROR;
   11370 
   11371 		SKIP_BLANKS;
   11372 		if (CUR != ')') {
   11373 		    XP_ERROR(XPATH_EXPR_ERROR);
   11374 		}
   11375 		NEXT;
   11376 		rangeto = 1;
   11377 		goto eval_predicates;
   11378 	    }
   11379 	}
   11380 #endif
   11381 	if (CUR == '*') {
   11382 	    axis = AXIS_CHILD;
   11383 	} else {
   11384 	    if (name == NULL)
   11385 		name = xmlXPathParseNCName(ctxt);
   11386 	    if (name != NULL) {
   11387 		axis = xmlXPathIsAxisName(name);
   11388 		if (axis != 0) {
   11389 		    SKIP_BLANKS;
   11390 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11391 			SKIP(2);
   11392 			xmlFree(name);
   11393 			name = NULL;
   11394 		    } else {
   11395 			/* an element name can conflict with an axis one :-\ */
   11396 			axis = AXIS_CHILD;
   11397 		    }
   11398 		} else {
   11399 		    axis = AXIS_CHILD;
   11400 		}
   11401 	    } else if (CUR == '@') {
   11402 		NEXT;
   11403 		axis = AXIS_ATTRIBUTE;
   11404 	    } else {
   11405 		axis = AXIS_CHILD;
   11406 	    }
   11407 	}
   11408 
   11409         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11410             xmlFree(name);
   11411             return;
   11412         }
   11413 
   11414 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11415 	if (test == 0)
   11416 	    return;
   11417 
   11418         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11419 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11420 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11421 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11422 	    }
   11423 	}
   11424 #ifdef DEBUG_STEP
   11425 	xmlGenericError(xmlGenericErrorContext,
   11426 		"Basis : computing new set\n");
   11427 #endif
   11428 
   11429 #ifdef DEBUG_STEP
   11430 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11431 	if (ctxt->value == NULL)
   11432 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11433 	else if (ctxt->value->nodesetval == NULL)
   11434 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11435 	else
   11436 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11437 #endif
   11438 
   11439 #ifdef LIBXML_XPTR_ENABLED
   11440 eval_predicates:
   11441 #endif
   11442 	op1 = ctxt->comp->last;
   11443 	ctxt->comp->last = -1;
   11444 
   11445 	SKIP_BLANKS;
   11446 	while (CUR == '[') {
   11447 	    xmlXPathCompPredicate(ctxt, 0);
   11448 	}
   11449 
   11450 #ifdef LIBXML_XPTR_ENABLED
   11451 	if (rangeto) {
   11452 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11453 	} else
   11454 #endif
   11455 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11456 			   test, type, (void *)prefix, (void *)name);
   11457 
   11458     }
   11459 #ifdef DEBUG_STEP
   11460     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11461     if (ctxt->value == NULL)
   11462 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11463     else if (ctxt->value->nodesetval == NULL)
   11464 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11465     else
   11466 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11467 		ctxt->value->nodesetval);
   11468 #endif
   11469 }
   11470 
   11471 /**
   11472  * xmlXPathCompRelativeLocationPath:
   11473  * @ctxt:  the XPath Parser context
   11474  *
   11475  *  [3]   RelativeLocationPath ::=   Step
   11476  *                     | RelativeLocationPath '/' Step
   11477  *                     | AbbreviatedRelativeLocationPath
   11478  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11479  *
   11480  * Compile a relative location path.
   11481  */
   11482 static void
   11483 xmlXPathCompRelativeLocationPath
   11484 (xmlXPathParserContextPtr ctxt) {
   11485     SKIP_BLANKS;
   11486     if ((CUR == '/') && (NXT(1) == '/')) {
   11487 	SKIP(2);
   11488 	SKIP_BLANKS;
   11489 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11490 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11491     } else if (CUR == '/') {
   11492 	    NEXT;
   11493 	SKIP_BLANKS;
   11494     }
   11495     xmlXPathCompStep(ctxt);
   11496     CHECK_ERROR;
   11497     SKIP_BLANKS;
   11498     while (CUR == '/') {
   11499 	if ((CUR == '/') && (NXT(1) == '/')) {
   11500 	    SKIP(2);
   11501 	    SKIP_BLANKS;
   11502 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11503 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11504 	    xmlXPathCompStep(ctxt);
   11505 	} else if (CUR == '/') {
   11506 	    NEXT;
   11507 	    SKIP_BLANKS;
   11508 	    xmlXPathCompStep(ctxt);
   11509 	}
   11510 	SKIP_BLANKS;
   11511     }
   11512 }
   11513 
   11514 /**
   11515  * xmlXPathCompLocationPath:
   11516  * @ctxt:  the XPath Parser context
   11517  *
   11518  *  [1]   LocationPath ::=   RelativeLocationPath
   11519  *                     | AbsoluteLocationPath
   11520  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11521  *                     | AbbreviatedAbsoluteLocationPath
   11522  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11523  *                           '//' RelativeLocationPath
   11524  *
   11525  * Compile a location path
   11526  *
   11527  * // is short for /descendant-or-self::node()/. For example,
   11528  * //para is short for /descendant-or-self::node()/child::para and
   11529  * so will select any para element in the document (even a para element
   11530  * that is a document element will be selected by //para since the
   11531  * document element node is a child of the root node); div//para is
   11532  * short for div/descendant-or-self::node()/child::para and so will
   11533  * select all para descendants of div children.
   11534  */
   11535 static void
   11536 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11537     SKIP_BLANKS;
   11538     if (CUR != '/') {
   11539         xmlXPathCompRelativeLocationPath(ctxt);
   11540     } else {
   11541 	while (CUR == '/') {
   11542 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11543 		SKIP(2);
   11544 		SKIP_BLANKS;
   11545 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11546 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11547 		xmlXPathCompRelativeLocationPath(ctxt);
   11548 	    } else if (CUR == '/') {
   11549 		NEXT;
   11550 		SKIP_BLANKS;
   11551 		if ((CUR != 0 ) &&
   11552 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11553 		     (CUR == '@') || (CUR == '*')))
   11554 		    xmlXPathCompRelativeLocationPath(ctxt);
   11555 	    }
   11556 	    CHECK_ERROR;
   11557 	}
   11558     }
   11559 }
   11560 
   11561 /************************************************************************
   11562  *									*
   11563  *		XPath precompiled expression evaluation			*
   11564  *									*
   11565  ************************************************************************/
   11566 
   11567 static int
   11568 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11569 
   11570 #ifdef DEBUG_STEP
   11571 static void
   11572 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11573 			  int nbNodes)
   11574 {
   11575     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11576     switch (op->value) {
   11577         case AXIS_ANCESTOR:
   11578             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11579             break;
   11580         case AXIS_ANCESTOR_OR_SELF:
   11581             xmlGenericError(xmlGenericErrorContext,
   11582                             "axis 'ancestors-or-self' ");
   11583             break;
   11584         case AXIS_ATTRIBUTE:
   11585             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11586             break;
   11587         case AXIS_CHILD:
   11588             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11589             break;
   11590         case AXIS_DESCENDANT:
   11591             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11592             break;
   11593         case AXIS_DESCENDANT_OR_SELF:
   11594             xmlGenericError(xmlGenericErrorContext,
   11595                             "axis 'descendant-or-self' ");
   11596             break;
   11597         case AXIS_FOLLOWING:
   11598             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11599             break;
   11600         case AXIS_FOLLOWING_SIBLING:
   11601             xmlGenericError(xmlGenericErrorContext,
   11602                             "axis 'following-siblings' ");
   11603             break;
   11604         case AXIS_NAMESPACE:
   11605             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11606             break;
   11607         case AXIS_PARENT:
   11608             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11609             break;
   11610         case AXIS_PRECEDING:
   11611             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11612             break;
   11613         case AXIS_PRECEDING_SIBLING:
   11614             xmlGenericError(xmlGenericErrorContext,
   11615                             "axis 'preceding-sibling' ");
   11616             break;
   11617         case AXIS_SELF:
   11618             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11619             break;
   11620     }
   11621     xmlGenericError(xmlGenericErrorContext,
   11622 	" context contains %d nodes\n", nbNodes);
   11623     switch (op->value2) {
   11624         case NODE_TEST_NONE:
   11625             xmlGenericError(xmlGenericErrorContext,
   11626                             "           searching for none !!!\n");
   11627             break;
   11628         case NODE_TEST_TYPE:
   11629             xmlGenericError(xmlGenericErrorContext,
   11630                             "           searching for type %d\n", op->value3);
   11631             break;
   11632         case NODE_TEST_PI:
   11633             xmlGenericError(xmlGenericErrorContext,
   11634                             "           searching for PI !!!\n");
   11635             break;
   11636         case NODE_TEST_ALL:
   11637             xmlGenericError(xmlGenericErrorContext,
   11638                             "           searching for *\n");
   11639             break;
   11640         case NODE_TEST_NS:
   11641             xmlGenericError(xmlGenericErrorContext,
   11642                             "           searching for namespace %s\n",
   11643                             op->value5);
   11644             break;
   11645         case NODE_TEST_NAME:
   11646             xmlGenericError(xmlGenericErrorContext,
   11647                             "           searching for name %s\n", op->value5);
   11648             if (op->value4)
   11649                 xmlGenericError(xmlGenericErrorContext,
   11650                                 "           with namespace %s\n", op->value4);
   11651             break;
   11652     }
   11653     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11654 }
   11655 #endif /* DEBUG_STEP */
   11656 
   11657 static int
   11658 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11659 			    xmlXPathStepOpPtr op,
   11660 			    xmlNodeSetPtr set,
   11661 			    int contextSize,
   11662 			    int hasNsNodes)
   11663 {
   11664     if (op->ch1 != -1) {
   11665 	xmlXPathCompExprPtr comp = ctxt->comp;
   11666 	/*
   11667 	* Process inner predicates first.
   11668 	*/
   11669 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11670 	    /*
   11671 	    * TODO: raise an internal error.
   11672 	    */
   11673 	}
   11674 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11675 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11676 	CHECK_ERROR0;
   11677 	if (contextSize <= 0)
   11678 	    return(0);
   11679     }
   11680     if (op->ch2 != -1) {
   11681 	xmlXPathContextPtr xpctxt = ctxt->context;
   11682 	xmlNodePtr contextNode, oldContextNode;
   11683 	xmlDocPtr oldContextDoc;
   11684 	int i, res, contextPos = 0, newContextSize;
   11685 	xmlXPathStepOpPtr exprOp;
   11686 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11687 
   11688 #ifdef LIBXML_XPTR_ENABLED
   11689 	/*
   11690 	* URGENT TODO: Check the following:
   11691 	*  We don't expect location sets if evaluating prediates, right?
   11692 	*  Only filters should expect location sets, right?
   11693 	*/
   11694 #endif
   11695 	/*
   11696 	* SPEC XPath 1.0:
   11697 	*  "For each node in the node-set to be filtered, the
   11698 	*  PredicateExpr is evaluated with that node as the
   11699 	*  context node, with the number of nodes in the
   11700 	*  node-set as the context size, and with the proximity
   11701 	*  position of the node in the node-set with respect to
   11702 	*  the axis as the context position;"
   11703 	* @oldset is the node-set" to be filtered.
   11704 	*
   11705 	* SPEC XPath 1.0:
   11706 	*  "only predicates change the context position and
   11707 	*  context size (see [2.4 Predicates])."
   11708 	* Example:
   11709 	*   node-set  context pos
   11710 	*    nA         1
   11711 	*    nB         2
   11712 	*    nC         3
   11713 	*   After applying predicate [position() > 1] :
   11714 	*   node-set  context pos
   11715 	*    nB         1
   11716 	*    nC         2
   11717 	*/
   11718 	oldContextNode = xpctxt->node;
   11719 	oldContextDoc = xpctxt->doc;
   11720 	/*
   11721 	* Get the expression of this predicate.
   11722 	*/
   11723 	exprOp = &ctxt->comp->steps[op->ch2];
   11724 	newContextSize = 0;
   11725 	for (i = 0; i < set->nodeNr; i++) {
   11726 	    if (set->nodeTab[i] == NULL)
   11727 		continue;
   11728 
   11729 	    contextNode = set->nodeTab[i];
   11730 	    xpctxt->node = contextNode;
   11731 	    xpctxt->contextSize = contextSize;
   11732 	    xpctxt->proximityPosition = ++contextPos;
   11733 
   11734 	    /*
   11735 	    * Also set the xpath document in case things like
   11736 	    * key() are evaluated in the predicate.
   11737 	    */
   11738 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11739 		(contextNode->doc != NULL))
   11740 		xpctxt->doc = contextNode->doc;
   11741 	    /*
   11742 	    * Evaluate the predicate expression with 1 context node
   11743 	    * at a time; this node is packaged into a node set; this
   11744 	    * node set is handed over to the evaluation mechanism.
   11745 	    */
   11746 	    if (contextObj == NULL)
   11747 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11748 	    else {
   11749 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11750 		    contextNode) < 0) {
   11751 		    ctxt->error = XPATH_MEMORY_ERROR;
   11752 		    goto evaluation_exit;
   11753 		}
   11754 	    }
   11755 
   11756 	    valuePush(ctxt, contextObj);
   11757 
   11758 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11759 
   11760 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11761 		xmlXPathNodeSetClear(set, hasNsNodes);
   11762 		newContextSize = 0;
   11763 		goto evaluation_exit;
   11764 	    }
   11765 
   11766 	    if (res != 0) {
   11767 		newContextSize++;
   11768 	    } else {
   11769 		/*
   11770 		* Remove the entry from the initial node set.
   11771 		*/
   11772 		set->nodeTab[i] = NULL;
   11773 		if (contextNode->type == XML_NAMESPACE_DECL)
   11774 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11775 	    }
   11776 	    if (ctxt->value == contextObj) {
   11777 		/*
   11778 		* Don't free the temporary XPath object holding the
   11779 		* context node, in order to avoid massive recreation
   11780 		* inside this loop.
   11781 		*/
   11782 		valuePop(ctxt);
   11783 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11784 	    } else {
   11785 		/*
   11786 		* TODO: The object was lost in the evaluation machinery.
   11787 		*  Can this happen? Maybe in internal-error cases.
   11788 		*/
   11789 		contextObj = NULL;
   11790 	    }
   11791 	}
   11792 
   11793 	if (contextObj != NULL) {
   11794 	    if (ctxt->value == contextObj)
   11795 		valuePop(ctxt);
   11796 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11797 	}
   11798 evaluation_exit:
   11799 	if (exprRes != NULL)
   11800 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11801 	/*
   11802 	* Reset/invalidate the context.
   11803 	*/
   11804 	xpctxt->node = oldContextNode;
   11805 	xpctxt->doc = oldContextDoc;
   11806 	xpctxt->contextSize = -1;
   11807 	xpctxt->proximityPosition = -1;
   11808 	return(newContextSize);
   11809     }
   11810     return(contextSize);
   11811 }
   11812 
   11813 static int
   11814 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11815 				      xmlXPathStepOpPtr op,
   11816 				      xmlNodeSetPtr set,
   11817 				      int contextSize,
   11818 				      int minPos,
   11819 				      int maxPos,
   11820 				      int hasNsNodes)
   11821 {
   11822     if (op->ch1 != -1) {
   11823 	xmlXPathCompExprPtr comp = ctxt->comp;
   11824 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11825 	    /*
   11826 	    * TODO: raise an internal error.
   11827 	    */
   11828 	}
   11829 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11830 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11831 	CHECK_ERROR0;
   11832 	if (contextSize <= 0)
   11833 	    return(0);
   11834     }
   11835     /*
   11836     * Check if the node set contains a sufficient number of nodes for
   11837     * the requested range.
   11838     */
   11839     if (contextSize < minPos) {
   11840 	xmlXPathNodeSetClear(set, hasNsNodes);
   11841 	return(0);
   11842     }
   11843     if (op->ch2 == -1) {
   11844 	/*
   11845 	* TODO: Can this ever happen?
   11846 	*/
   11847 	return (contextSize);
   11848     } else {
   11849 	xmlDocPtr oldContextDoc;
   11850 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11851 	xmlXPathStepOpPtr exprOp;
   11852 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11853 	xmlNodePtr oldContextNode, contextNode = NULL;
   11854 	xmlXPathContextPtr xpctxt = ctxt->context;
   11855         int frame;
   11856 
   11857 #ifdef LIBXML_XPTR_ENABLED
   11858 	    /*
   11859 	    * URGENT TODO: Check the following:
   11860 	    *  We don't expect location sets if evaluating prediates, right?
   11861 	    *  Only filters should expect location sets, right?
   11862 	*/
   11863 #endif /* LIBXML_XPTR_ENABLED */
   11864 
   11865 	/*
   11866 	* Save old context.
   11867 	*/
   11868 	oldContextNode = xpctxt->node;
   11869 	oldContextDoc = xpctxt->doc;
   11870 	/*
   11871 	* Get the expression of this predicate.
   11872 	*/
   11873 	exprOp = &ctxt->comp->steps[op->ch2];
   11874 	for (i = 0; i < set->nodeNr; i++) {
   11875             xmlXPathObjectPtr tmp;
   11876 
   11877 	    if (set->nodeTab[i] == NULL)
   11878 		continue;
   11879 
   11880 	    contextNode = set->nodeTab[i];
   11881 	    xpctxt->node = contextNode;
   11882 	    xpctxt->contextSize = contextSize;
   11883 	    xpctxt->proximityPosition = ++contextPos;
   11884 
   11885 	    /*
   11886 	    * Initialize the new set.
   11887 	    * Also set the xpath document in case things like
   11888 	    * key() evaluation are attempted on the predicate
   11889 	    */
   11890 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11891 		(contextNode->doc != NULL))
   11892 		xpctxt->doc = contextNode->doc;
   11893 	    /*
   11894 	    * Evaluate the predicate expression with 1 context node
   11895 	    * at a time; this node is packaged into a node set; this
   11896 	    * node set is handed over to the evaluation mechanism.
   11897 	    */
   11898 	    if (contextObj == NULL)
   11899 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11900 	    else {
   11901 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11902 		    contextNode) < 0) {
   11903 		    ctxt->error = XPATH_MEMORY_ERROR;
   11904 		    goto evaluation_exit;
   11905 		}
   11906 	    }
   11907 
   11908             frame = xmlXPathSetFrame(ctxt);
   11909 	    valuePush(ctxt, contextObj);
   11910 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11911             tmp = valuePop(ctxt);
   11912             xmlXPathPopFrame(ctxt, frame);
   11913 
   11914 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11915                 while (tmp != contextObj) {
   11916                     /*
   11917                      * Free up the result
   11918                      * then pop off contextObj, which will be freed later
   11919                      */
   11920                     xmlXPathReleaseObject(xpctxt, tmp);
   11921                     tmp = valuePop(ctxt);
   11922                 }
   11923 		goto evaluation_error;
   11924 	    }
   11925             /* push the result back onto the stack */
   11926             valuePush(ctxt, tmp);
   11927 
   11928 	    if (res)
   11929 		pos++;
   11930 
   11931 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11932 		/*
   11933 		* Fits in the requested range.
   11934 		*/
   11935 		newContextSize++;
   11936 		if (minPos == maxPos) {
   11937 		    /*
   11938 		    * Only 1 node was requested.
   11939 		    */
   11940 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11941 			/*
   11942 			* As always: take care of those nasty
   11943 			* namespace nodes.
   11944 			*/
   11945 			set->nodeTab[i] = NULL;
   11946 		    }
   11947 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11948 		    set->nodeNr = 1;
   11949 		    set->nodeTab[0] = contextNode;
   11950 		    goto evaluation_exit;
   11951 		}
   11952 		if (pos == maxPos) {
   11953 		    /*
   11954 		    * We are done.
   11955 		    */
   11956 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11957 		    goto evaluation_exit;
   11958 		}
   11959 	    } else {
   11960 		/*
   11961 		* Remove the entry from the initial node set.
   11962 		*/
   11963 		set->nodeTab[i] = NULL;
   11964 		if (contextNode->type == XML_NAMESPACE_DECL)
   11965 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11966 	    }
   11967 	    if (exprRes != NULL) {
   11968 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11969 		exprRes = NULL;
   11970 	    }
   11971 	    if (ctxt->value == contextObj) {
   11972 		/*
   11973 		* Don't free the temporary XPath object holding the
   11974 		* context node, in order to avoid massive recreation
   11975 		* inside this loop.
   11976 		*/
   11977 		valuePop(ctxt);
   11978 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11979 	    } else {
   11980 		/*
   11981 		* The object was lost in the evaluation machinery.
   11982 		* Can this happen? Maybe in case of internal-errors.
   11983 		*/
   11984 		contextObj = NULL;
   11985 	    }
   11986 	}
   11987 	goto evaluation_exit;
   11988 
   11989 evaluation_error:
   11990 	xmlXPathNodeSetClear(set, hasNsNodes);
   11991 	newContextSize = 0;
   11992 
   11993 evaluation_exit:
   11994 	if (contextObj != NULL) {
   11995 	    if (ctxt->value == contextObj)
   11996 		valuePop(ctxt);
   11997 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11998 	}
   11999 	if (exprRes != NULL)
   12000 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   12001 	/*
   12002 	* Reset/invalidate the context.
   12003 	*/
   12004 	xpctxt->node = oldContextNode;
   12005 	xpctxt->doc = oldContextDoc;
   12006 	xpctxt->contextSize = -1;
   12007 	xpctxt->proximityPosition = -1;
   12008 	return(newContextSize);
   12009     }
   12010     return(contextSize);
   12011 }
   12012 
   12013 static int
   12014 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   12015 			    xmlXPathStepOpPtr op,
   12016 			    int *maxPos)
   12017 {
   12018 
   12019     xmlXPathStepOpPtr exprOp;
   12020 
   12021     /*
   12022     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   12023     */
   12024 
   12025     /*
   12026     * If not -1, then ch1 will point to:
   12027     * 1) For predicates (XPATH_OP_PREDICATE):
   12028     *    - an inner predicate operator
   12029     * 2) For filters (XPATH_OP_FILTER):
   12030     *    - an inner filter operater OR
   12031     *    - an expression selecting the node set.
   12032     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   12033     */
   12034     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   12035 	return(0);
   12036 
   12037     if (op->ch2 != -1) {
   12038 	exprOp = &ctxt->comp->steps[op->ch2];
   12039     } else
   12040 	return(0);
   12041 
   12042     if ((exprOp != NULL) &&
   12043 	(exprOp->op == XPATH_OP_VALUE) &&
   12044 	(exprOp->value4 != NULL) &&
   12045 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   12046     {
   12047 	/*
   12048 	* We have a "[n]" predicate here.
   12049 	* TODO: Unfortunately this simplistic test here is not
   12050 	* able to detect a position() predicate in compound
   12051 	* expressions like "[@attr = 'a" and position() = 1],
   12052 	* and even not the usage of position() in
   12053 	* "[position() = 1]"; thus - obviously - a position-range,
   12054 	* like it "[position() < 5]", is also not detected.
   12055 	* Maybe we could rewrite the AST to ease the optimization.
   12056 	*/
   12057 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   12058 
   12059 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   12060 	    (float) *maxPos)
   12061 	{
   12062 	    return(1);
   12063 	}
   12064     }
   12065     return(0);
   12066 }
   12067 
   12068 static int
   12069 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   12070                            xmlXPathStepOpPtr op,
   12071 			   xmlNodePtr * first, xmlNodePtr * last,
   12072 			   int toBool)
   12073 {
   12074 
   12075 #define XP_TEST_HIT \
   12076     if (hasAxisRange != 0) { \
   12077 	if (++pos == maxPos) { \
   12078 	    if (addNode(seq, cur) < 0) \
   12079 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12080 	    goto axis_range_end; } \
   12081     } else { \
   12082 	if (addNode(seq, cur) < 0) \
   12083 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12084 	if (breakOnFirstHit) goto first_hit; }
   12085 
   12086 #define XP_TEST_HIT_NS \
   12087     if (hasAxisRange != 0) { \
   12088 	if (++pos == maxPos) { \
   12089 	    hasNsNodes = 1; \
   12090 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12091 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12092 	goto axis_range_end; } \
   12093     } else { \
   12094 	hasNsNodes = 1; \
   12095 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12096 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12097 	if (breakOnFirstHit) goto first_hit; }
   12098 
   12099     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   12100     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12101     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12102     const xmlChar *prefix = op->value4;
   12103     const xmlChar *name = op->value5;
   12104     const xmlChar *URI = NULL;
   12105 
   12106 #ifdef DEBUG_STEP
   12107     int nbMatches = 0, prevMatches = 0;
   12108 #endif
   12109     int total = 0, hasNsNodes = 0;
   12110     /* The popped object holding the context nodes */
   12111     xmlXPathObjectPtr obj;
   12112     /* The set of context nodes for the node tests */
   12113     xmlNodeSetPtr contextSeq;
   12114     int contextIdx;
   12115     xmlNodePtr contextNode;
   12116     /* The final resulting node set wrt to all context nodes */
   12117     xmlNodeSetPtr outSeq;
   12118     /*
   12119     * The temporary resulting node set wrt 1 context node.
   12120     * Used to feed predicate evaluation.
   12121     */
   12122     xmlNodeSetPtr seq;
   12123     xmlNodePtr cur;
   12124     /* First predicate operator */
   12125     xmlXPathStepOpPtr predOp;
   12126     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12127     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12128     int breakOnFirstHit;
   12129 
   12130     xmlXPathTraversalFunction next = NULL;
   12131     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12132     xmlXPathNodeSetMergeFunction mergeAndClear;
   12133     xmlNodePtr oldContextNode;
   12134     xmlXPathContextPtr xpctxt = ctxt->context;
   12135 
   12136 
   12137     CHECK_TYPE0(XPATH_NODESET);
   12138     obj = valuePop(ctxt);
   12139     /*
   12140     * Setup namespaces.
   12141     */
   12142     if (prefix != NULL) {
   12143         URI = xmlXPathNsLookup(xpctxt, prefix);
   12144         if (URI == NULL) {
   12145 	    xmlXPathReleaseObject(xpctxt, obj);
   12146             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12147 	}
   12148     }
   12149     /*
   12150     * Setup axis.
   12151     *
   12152     * MAYBE FUTURE TODO: merging optimizations:
   12153     * - If the nodes to be traversed wrt to the initial nodes and
   12154     *   the current axis cannot overlap, then we could avoid searching
   12155     *   for duplicates during the merge.
   12156     *   But the question is how/when to evaluate if they cannot overlap.
   12157     *   Example: if we know that for two initial nodes, the one is
   12158     *   not in the ancestor-or-self axis of the other, then we could safely
   12159     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12160     *   the descendant-or-self axis.
   12161     */
   12162     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12163     switch (axis) {
   12164         case AXIS_ANCESTOR:
   12165             first = NULL;
   12166             next = xmlXPathNextAncestor;
   12167             break;
   12168         case AXIS_ANCESTOR_OR_SELF:
   12169             first = NULL;
   12170             next = xmlXPathNextAncestorOrSelf;
   12171             break;
   12172         case AXIS_ATTRIBUTE:
   12173             first = NULL;
   12174 	    last = NULL;
   12175             next = xmlXPathNextAttribute;
   12176 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12177             break;
   12178         case AXIS_CHILD:
   12179 	    last = NULL;
   12180 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12181 		(type == NODE_TYPE_NODE))
   12182 	    {
   12183 		/*
   12184 		* Optimization if an element node type is 'element'.
   12185 		*/
   12186 		next = xmlXPathNextChildElement;
   12187 	    } else
   12188 		next = xmlXPathNextChild;
   12189 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12190             break;
   12191         case AXIS_DESCENDANT:
   12192 	    last = NULL;
   12193             next = xmlXPathNextDescendant;
   12194             break;
   12195         case AXIS_DESCENDANT_OR_SELF:
   12196 	    last = NULL;
   12197             next = xmlXPathNextDescendantOrSelf;
   12198             break;
   12199         case AXIS_FOLLOWING:
   12200 	    last = NULL;
   12201             next = xmlXPathNextFollowing;
   12202             break;
   12203         case AXIS_FOLLOWING_SIBLING:
   12204 	    last = NULL;
   12205             next = xmlXPathNextFollowingSibling;
   12206             break;
   12207         case AXIS_NAMESPACE:
   12208             first = NULL;
   12209 	    last = NULL;
   12210             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12211 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12212             break;
   12213         case AXIS_PARENT:
   12214             first = NULL;
   12215             next = xmlXPathNextParent;
   12216             break;
   12217         case AXIS_PRECEDING:
   12218             first = NULL;
   12219             next = xmlXPathNextPrecedingInternal;
   12220             break;
   12221         case AXIS_PRECEDING_SIBLING:
   12222             first = NULL;
   12223             next = xmlXPathNextPrecedingSibling;
   12224             break;
   12225         case AXIS_SELF:
   12226             first = NULL;
   12227 	    last = NULL;
   12228             next = xmlXPathNextSelf;
   12229 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12230             break;
   12231     }
   12232 
   12233 #ifdef DEBUG_STEP
   12234     xmlXPathDebugDumpStepAxis(op,
   12235 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12236 #endif
   12237 
   12238     if (next == NULL) {
   12239 	xmlXPathReleaseObject(xpctxt, obj);
   12240         return(0);
   12241     }
   12242     contextSeq = obj->nodesetval;
   12243     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12244 	xmlXPathReleaseObject(xpctxt, obj);
   12245         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12246         return(0);
   12247     }
   12248     /*
   12249     * Predicate optimization ---------------------------------------------
   12250     * If this step has a last predicate, which contains a position(),
   12251     * then we'll optimize (although not exactly "position()", but only
   12252     * the  short-hand form, i.e., "[n]".
   12253     *
   12254     * Example - expression "/foo[parent::bar][1]":
   12255     *
   12256     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12257     *   ROOT                               -- op->ch1
   12258     *   PREDICATE                          -- op->ch2 (predOp)
   12259     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12260     *       SORT
   12261     *         COLLECT  'parent' 'name' 'node' bar
   12262     *           NODE
   12263     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12264     *
   12265     */
   12266     maxPos = 0;
   12267     predOp = NULL;
   12268     hasPredicateRange = 0;
   12269     hasAxisRange = 0;
   12270     if (op->ch2 != -1) {
   12271 	/*
   12272 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12273 	*/
   12274 	predOp = &ctxt->comp->steps[op->ch2];
   12275 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12276 	    if (predOp->ch1 != -1) {
   12277 		/*
   12278 		* Use the next inner predicate operator.
   12279 		*/
   12280 		predOp = &ctxt->comp->steps[predOp->ch1];
   12281 		hasPredicateRange = 1;
   12282 	    } else {
   12283 		/*
   12284 		* There's no other predicate than the [n] predicate.
   12285 		*/
   12286 		predOp = NULL;
   12287 		hasAxisRange = 1;
   12288 	    }
   12289 	}
   12290     }
   12291     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12292     /*
   12293     * Axis traversal -----------------------------------------------------
   12294     */
   12295     /*
   12296      * 2.3 Node Tests
   12297      *  - For the attribute axis, the principal node type is attribute.
   12298      *  - For the namespace axis, the principal node type is namespace.
   12299      *  - For other axes, the principal node type is element.
   12300      *
   12301      * A node test * is true for any node of the
   12302      * principal node type. For example, child::* will
   12303      * select all element children of the context node
   12304      */
   12305     oldContextNode = xpctxt->node;
   12306     addNode = xmlXPathNodeSetAddUnique;
   12307     outSeq = NULL;
   12308     seq = NULL;
   12309     contextNode = NULL;
   12310     contextIdx = 0;
   12311 
   12312 
   12313     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
   12314            (ctxt->error == XPATH_EXPRESSION_OK)) {
   12315 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12316 
   12317 	if (seq == NULL) {
   12318 	    seq = xmlXPathNodeSetCreate(NULL);
   12319 	    if (seq == NULL) {
   12320 		total = 0;
   12321 		goto error;
   12322 	    }
   12323 	}
   12324 	/*
   12325 	* Traverse the axis and test the nodes.
   12326 	*/
   12327 	pos = 0;
   12328 	cur = NULL;
   12329 	hasNsNodes = 0;
   12330         do {
   12331             cur = next(ctxt, cur);
   12332             if (cur == NULL)
   12333                 break;
   12334 
   12335 	    /*
   12336 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12337 	    */
   12338             if ((first != NULL) && (*first != NULL)) {
   12339 		if (*first == cur)
   12340 		    break;
   12341 		if (((total % 256) == 0) &&
   12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12343 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12344 #else
   12345 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12346 #endif
   12347 		{
   12348 		    break;
   12349 		}
   12350 	    }
   12351 	    if ((last != NULL) && (*last != NULL)) {
   12352 		if (*last == cur)
   12353 		    break;
   12354 		if (((total % 256) == 0) &&
   12355 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12356 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12357 #else
   12358 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12359 #endif
   12360 		{
   12361 		    break;
   12362 		}
   12363 	    }
   12364 
   12365             total++;
   12366 
   12367 #ifdef DEBUG_STEP
   12368             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12369 #endif
   12370 
   12371 	    switch (test) {
   12372                 case NODE_TEST_NONE:
   12373 		    total = 0;
   12374                     STRANGE
   12375 		    goto error;
   12376                 case NODE_TEST_TYPE:
   12377 		    /*
   12378 		    * TODO: Don't we need to use
   12379 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12380 		    *  Surprisingly, some c14n tests fail, if we do this.
   12381 		    */
   12382 		    if (type == NODE_TYPE_NODE) {
   12383 			switch (cur->type) {
   12384 			    case XML_DOCUMENT_NODE:
   12385 			    case XML_HTML_DOCUMENT_NODE:
   12386 #ifdef LIBXML_DOCB_ENABLED
   12387 			    case XML_DOCB_DOCUMENT_NODE:
   12388 #endif
   12389 			    case XML_ELEMENT_NODE:
   12390 			    case XML_ATTRIBUTE_NODE:
   12391 			    case XML_PI_NODE:
   12392 			    case XML_COMMENT_NODE:
   12393 			    case XML_CDATA_SECTION_NODE:
   12394 			    case XML_TEXT_NODE:
   12395 			    case XML_NAMESPACE_DECL:
   12396 				XP_TEST_HIT
   12397 				break;
   12398 			    default:
   12399 				break;
   12400 			}
   12401 		    } else if (cur->type == type) {
   12402 			if (cur->type == XML_NAMESPACE_DECL)
   12403 			    XP_TEST_HIT_NS
   12404 			else
   12405 			    XP_TEST_HIT
   12406 		    } else if ((type == NODE_TYPE_TEXT) &&
   12407 			 (cur->type == XML_CDATA_SECTION_NODE))
   12408 		    {
   12409 			XP_TEST_HIT
   12410 		    }
   12411 		    break;
   12412                 case NODE_TEST_PI:
   12413                     if ((cur->type == XML_PI_NODE) &&
   12414                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12415 		    {
   12416 			XP_TEST_HIT
   12417                     }
   12418                     break;
   12419                 case NODE_TEST_ALL:
   12420                     if (axis == AXIS_ATTRIBUTE) {
   12421                         if (cur->type == XML_ATTRIBUTE_NODE)
   12422 			{
   12423 			    XP_TEST_HIT
   12424                         }
   12425                     } else if (axis == AXIS_NAMESPACE) {
   12426                         if (cur->type == XML_NAMESPACE_DECL)
   12427 			{
   12428 			    XP_TEST_HIT_NS
   12429                         }
   12430                     } else {
   12431                         if (cur->type == XML_ELEMENT_NODE) {
   12432                             if (prefix == NULL)
   12433 			    {
   12434 				XP_TEST_HIT
   12435 
   12436                             } else if ((cur->ns != NULL) &&
   12437 				(xmlStrEqual(URI, cur->ns->href)))
   12438 			    {
   12439 				XP_TEST_HIT
   12440                             }
   12441                         }
   12442                     }
   12443                     break;
   12444                 case NODE_TEST_NS:{
   12445                         TODO;
   12446                         break;
   12447                     }
   12448                 case NODE_TEST_NAME:
   12449                     if (axis == AXIS_ATTRIBUTE) {
   12450                         if (cur->type != XML_ATTRIBUTE_NODE)
   12451 			    break;
   12452 		    } else if (axis == AXIS_NAMESPACE) {
   12453                         if (cur->type != XML_NAMESPACE_DECL)
   12454 			    break;
   12455 		    } else {
   12456 		        if (cur->type != XML_ELEMENT_NODE)
   12457 			    break;
   12458 		    }
   12459                     switch (cur->type) {
   12460                         case XML_ELEMENT_NODE:
   12461                             if (xmlStrEqual(name, cur->name)) {
   12462                                 if (prefix == NULL) {
   12463                                     if (cur->ns == NULL)
   12464 				    {
   12465 					XP_TEST_HIT
   12466                                     }
   12467                                 } else {
   12468                                     if ((cur->ns != NULL) &&
   12469                                         (xmlStrEqual(URI, cur->ns->href)))
   12470 				    {
   12471 					XP_TEST_HIT
   12472                                     }
   12473                                 }
   12474                             }
   12475                             break;
   12476                         case XML_ATTRIBUTE_NODE:{
   12477                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12478 
   12479                                 if (xmlStrEqual(name, attr->name)) {
   12480                                     if (prefix == NULL) {
   12481                                         if ((attr->ns == NULL) ||
   12482                                             (attr->ns->prefix == NULL))
   12483 					{
   12484 					    XP_TEST_HIT
   12485                                         }
   12486                                     } else {
   12487                                         if ((attr->ns != NULL) &&
   12488                                             (xmlStrEqual(URI,
   12489 					      attr->ns->href)))
   12490 					{
   12491 					    XP_TEST_HIT
   12492                                         }
   12493                                     }
   12494                                 }
   12495                                 break;
   12496                             }
   12497                         case XML_NAMESPACE_DECL:
   12498                             if (cur->type == XML_NAMESPACE_DECL) {
   12499                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12500 
   12501                                 if ((ns->prefix != NULL) && (name != NULL)
   12502                                     && (xmlStrEqual(ns->prefix, name)))
   12503 				{
   12504 				    XP_TEST_HIT_NS
   12505                                 }
   12506                             }
   12507                             break;
   12508                         default:
   12509                             break;
   12510                     }
   12511                     break;
   12512 	    } /* switch(test) */
   12513         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
   12514 
   12515 	goto apply_predicates;
   12516 
   12517 axis_range_end: /* ----------------------------------------------------- */
   12518 	/*
   12519 	* We have a "/foo[n]", and position() = n was reached.
   12520 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12521 	* a duplicate-aware merge is still needed.
   12522 	* Merge with the result.
   12523 	*/
   12524 	if (outSeq == NULL) {
   12525 	    outSeq = seq;
   12526 	    seq = NULL;
   12527 	} else
   12528 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12529 	/*
   12530 	* Break if only a true/false result was requested.
   12531 	*/
   12532 	if (toBool)
   12533 	    break;
   12534 	continue;
   12535 
   12536 first_hit: /* ---------------------------------------------------------- */
   12537 	/*
   12538 	* Break if only a true/false result was requested and
   12539 	* no predicates existed and a node test succeeded.
   12540 	*/
   12541 	if (outSeq == NULL) {
   12542 	    outSeq = seq;
   12543 	    seq = NULL;
   12544 	} else
   12545 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12546 	break;
   12547 
   12548 #ifdef DEBUG_STEP
   12549 	if (seq != NULL)
   12550 	    nbMatches += seq->nodeNr;
   12551 #endif
   12552 
   12553 apply_predicates: /* --------------------------------------------------- */
   12554         if (ctxt->error != XPATH_EXPRESSION_OK)
   12555 	    goto error;
   12556 
   12557         /*
   12558 	* Apply predicates.
   12559 	*/
   12560         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12561 	    /*
   12562 	    * E.g. when we have a "/foo[some expression][n]".
   12563 	    */
   12564 	    /*
   12565 	    * QUESTION TODO: The old predicate evaluation took into
   12566 	    *  account location-sets.
   12567 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12568 	    *  Do we expect such a set here?
   12569 	    *  All what I learned now from the evaluation semantics
   12570 	    *  does not indicate that a location-set will be processed
   12571 	    *  here, so this looks OK.
   12572 	    */
   12573 	    /*
   12574 	    * Iterate over all predicates, starting with the outermost
   12575 	    * predicate.
   12576 	    * TODO: Problem: we cannot execute the inner predicates first
   12577 	    *  since we cannot go back *up* the operator tree!
   12578 	    *  Options we have:
   12579 	    *  1) Use of recursive functions (like is it currently done
   12580 	    *     via xmlXPathCompOpEval())
   12581 	    *  2) Add a predicate evaluation information stack to the
   12582 	    *     context struct
   12583 	    *  3) Change the way the operators are linked; we need a
   12584 	    *     "parent" field on xmlXPathStepOp
   12585 	    *
   12586 	    * For the moment, I'll try to solve this with a recursive
   12587 	    * function: xmlXPathCompOpEvalPredicate().
   12588 	    */
   12589 	    size = seq->nodeNr;
   12590 	    if (hasPredicateRange != 0)
   12591 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12592 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12593 	    else
   12594 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12595 		    predOp, seq, size, hasNsNodes);
   12596 
   12597 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12598 		total = 0;
   12599 		goto error;
   12600 	    }
   12601 	    /*
   12602 	    * Add the filtered set of nodes to the result node set.
   12603 	    */
   12604 	    if (newSize == 0) {
   12605 		/*
   12606 		* The predicates filtered all nodes out.
   12607 		*/
   12608 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12609 	    } else if (seq->nodeNr > 0) {
   12610 		/*
   12611 		* Add to result set.
   12612 		*/
   12613 		if (outSeq == NULL) {
   12614 		    if (size != newSize) {
   12615 			/*
   12616 			* We need to merge and clear here, since
   12617 			* the sequence will contained NULLed entries.
   12618 			*/
   12619 			outSeq = mergeAndClear(NULL, seq, 1);
   12620 		    } else {
   12621 			outSeq = seq;
   12622 			seq = NULL;
   12623 		    }
   12624 		} else
   12625 		    outSeq = mergeAndClear(outSeq, seq,
   12626 			(size != newSize) ? 1: 0);
   12627 		/*
   12628 		* Break if only a true/false result was requested.
   12629 		*/
   12630 		if (toBool)
   12631 		    break;
   12632 	    }
   12633         } else if (seq->nodeNr > 0) {
   12634 	    /*
   12635 	    * Add to result set.
   12636 	    */
   12637 	    if (outSeq == NULL) {
   12638 		outSeq = seq;
   12639 		seq = NULL;
   12640 	    } else {
   12641 		outSeq = mergeAndClear(outSeq, seq, 0);
   12642 	    }
   12643 	}
   12644     }
   12645 
   12646 error:
   12647     if ((obj->boolval) && (obj->user != NULL)) {
   12648 	/*
   12649 	* QUESTION TODO: What does this do and why?
   12650 	* TODO: Do we have to do this also for the "error"
   12651 	* cleanup further down?
   12652 	*/
   12653 	ctxt->value->boolval = 1;
   12654 	ctxt->value->user = obj->user;
   12655 	obj->user = NULL;
   12656 	obj->boolval = 0;
   12657     }
   12658     xmlXPathReleaseObject(xpctxt, obj);
   12659 
   12660     /*
   12661     * Ensure we return at least an emtpy set.
   12662     */
   12663     if (outSeq == NULL) {
   12664 	if ((seq != NULL) && (seq->nodeNr == 0))
   12665 	    outSeq = seq;
   12666 	else
   12667 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12668         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12669     }
   12670     if ((seq != NULL) && (seq != outSeq)) {
   12671 	 xmlXPathFreeNodeSet(seq);
   12672     }
   12673     /*
   12674     * Hand over the result. Better to push the set also in
   12675     * case of errors.
   12676     */
   12677     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12678     /*
   12679     * Reset the context node.
   12680     */
   12681     xpctxt->node = oldContextNode;
   12682 
   12683 #ifdef DEBUG_STEP
   12684     xmlGenericError(xmlGenericErrorContext,
   12685 	"\nExamined %d nodes, found %d nodes at that step\n",
   12686 	total, nbMatches);
   12687 #endif
   12688 
   12689     return(total);
   12690 }
   12691 
   12692 static int
   12693 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12694 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12695 
   12696 /**
   12697  * xmlXPathCompOpEvalFirst:
   12698  * @ctxt:  the XPath parser context with the compiled expression
   12699  * @op:  an XPath compiled operation
   12700  * @first:  the first elem found so far
   12701  *
   12702  * Evaluate the Precompiled XPath operation searching only the first
   12703  * element in document order
   12704  *
   12705  * Returns the number of examined objects.
   12706  */
   12707 static int
   12708 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12709                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12710 {
   12711     int total = 0, cur;
   12712     xmlXPathCompExprPtr comp;
   12713     xmlXPathObjectPtr arg1, arg2;
   12714 
   12715     CHECK_ERROR0;
   12716     comp = ctxt->comp;
   12717     switch (op->op) {
   12718         case XPATH_OP_END:
   12719             return (0);
   12720         case XPATH_OP_UNION:
   12721             total =
   12722                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12723                                         first);
   12724 	    CHECK_ERROR0;
   12725             if ((ctxt->value != NULL)
   12726                 && (ctxt->value->type == XPATH_NODESET)
   12727                 && (ctxt->value->nodesetval != NULL)
   12728                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12729                 /*
   12730                  * limit tree traversing to first node in the result
   12731                  */
   12732 		/*
   12733 		* OPTIMIZE TODO: This implicitely sorts
   12734 		*  the result, even if not needed. E.g. if the argument
   12735 		*  of the count() function, no sorting is needed.
   12736 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12737 		*  aready sorted?
   12738 		*/
   12739 		if (ctxt->value->nodesetval->nodeNr > 1)
   12740 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12741                 *first = ctxt->value->nodesetval->nodeTab[0];
   12742             }
   12743             cur =
   12744                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12745                                         first);
   12746 	    CHECK_ERROR0;
   12747             CHECK_TYPE0(XPATH_NODESET);
   12748             arg2 = valuePop(ctxt);
   12749 
   12750             CHECK_TYPE0(XPATH_NODESET);
   12751             arg1 = valuePop(ctxt);
   12752 
   12753             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12754                                                     arg2->nodesetval);
   12755             valuePush(ctxt, arg1);
   12756 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12757             /* optimizer */
   12758 	    if (total > cur)
   12759 		xmlXPathCompSwap(op);
   12760             return (total + cur);
   12761         case XPATH_OP_ROOT:
   12762             xmlXPathRoot(ctxt);
   12763             return (0);
   12764         case XPATH_OP_NODE:
   12765             if (op->ch1 != -1)
   12766                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12767 	    CHECK_ERROR0;
   12768             if (op->ch2 != -1)
   12769                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12770 	    CHECK_ERROR0;
   12771 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12772 		ctxt->context->node));
   12773             return (total);
   12774         case XPATH_OP_RESET:
   12775             if (op->ch1 != -1)
   12776                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12777 	    CHECK_ERROR0;
   12778             if (op->ch2 != -1)
   12779                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12780 	    CHECK_ERROR0;
   12781             ctxt->context->node = NULL;
   12782             return (total);
   12783         case XPATH_OP_COLLECT:{
   12784                 if (op->ch1 == -1)
   12785                     return (total);
   12786 
   12787                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12788 		CHECK_ERROR0;
   12789 
   12790                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12791                 return (total);
   12792             }
   12793         case XPATH_OP_VALUE:
   12794             valuePush(ctxt,
   12795                       xmlXPathCacheObjectCopy(ctxt->context,
   12796 			(xmlXPathObjectPtr) op->value4));
   12797             return (0);
   12798         case XPATH_OP_SORT:
   12799             if (op->ch1 != -1)
   12800                 total +=
   12801                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12802                                             first);
   12803 	    CHECK_ERROR0;
   12804             if ((ctxt->value != NULL)
   12805                 && (ctxt->value->type == XPATH_NODESET)
   12806                 && (ctxt->value->nodesetval != NULL)
   12807 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12809             return (total);
   12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12811 	case XPATH_OP_FILTER:
   12812                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12813             return (total);
   12814 #endif
   12815         default:
   12816             return (xmlXPathCompOpEval(ctxt, op));
   12817     }
   12818 }
   12819 
   12820 /**
   12821  * xmlXPathCompOpEvalLast:
   12822  * @ctxt:  the XPath parser context with the compiled expression
   12823  * @op:  an XPath compiled operation
   12824  * @last:  the last elem found so far
   12825  *
   12826  * Evaluate the Precompiled XPath operation searching only the last
   12827  * element in document order
   12828  *
   12829  * Returns the number of nodes traversed
   12830  */
   12831 static int
   12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12833                        xmlNodePtr * last)
   12834 {
   12835     int total = 0, cur;
   12836     xmlXPathCompExprPtr comp;
   12837     xmlXPathObjectPtr arg1, arg2;
   12838     xmlNodePtr bak;
   12839     xmlDocPtr bakd;
   12840     int pp;
   12841     int cs;
   12842 
   12843     CHECK_ERROR0;
   12844     comp = ctxt->comp;
   12845     switch (op->op) {
   12846         case XPATH_OP_END:
   12847             return (0);
   12848         case XPATH_OP_UNION:
   12849 	    bakd = ctxt->context->doc;
   12850 	    bak = ctxt->context->node;
   12851 	    pp = ctxt->context->proximityPosition;
   12852 	    cs = ctxt->context->contextSize;
   12853             total =
   12854                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12855 	    CHECK_ERROR0;
   12856             if ((ctxt->value != NULL)
   12857                 && (ctxt->value->type == XPATH_NODESET)
   12858                 && (ctxt->value->nodesetval != NULL)
   12859                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12860                 /*
   12861                  * limit tree traversing to first node in the result
   12862                  */
   12863 		if (ctxt->value->nodesetval->nodeNr > 1)
   12864 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12865                 *last =
   12866                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12867                                                      nodesetval->nodeNr -
   12868                                                      1];
   12869             }
   12870 	    ctxt->context->doc = bakd;
   12871 	    ctxt->context->node = bak;
   12872 	    ctxt->context->proximityPosition = pp;
   12873 	    ctxt->context->contextSize = cs;
   12874             cur =
   12875                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12876 	    CHECK_ERROR0;
   12877             if ((ctxt->value != NULL)
   12878                 && (ctxt->value->type == XPATH_NODESET)
   12879                 && (ctxt->value->nodesetval != NULL)
   12880                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12881             }
   12882             CHECK_TYPE0(XPATH_NODESET);
   12883             arg2 = valuePop(ctxt);
   12884 
   12885             CHECK_TYPE0(XPATH_NODESET);
   12886             arg1 = valuePop(ctxt);
   12887 
   12888             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12889                                                     arg2->nodesetval);
   12890             valuePush(ctxt, arg1);
   12891 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12892             /* optimizer */
   12893 	    if (total > cur)
   12894 		xmlXPathCompSwap(op);
   12895             return (total + cur);
   12896         case XPATH_OP_ROOT:
   12897             xmlXPathRoot(ctxt);
   12898             return (0);
   12899         case XPATH_OP_NODE:
   12900             if (op->ch1 != -1)
   12901                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12902 	    CHECK_ERROR0;
   12903             if (op->ch2 != -1)
   12904                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12905 	    CHECK_ERROR0;
   12906 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12907 		ctxt->context->node));
   12908             return (total);
   12909         case XPATH_OP_RESET:
   12910             if (op->ch1 != -1)
   12911                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12912 	    CHECK_ERROR0;
   12913             if (op->ch2 != -1)
   12914                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12915 	    CHECK_ERROR0;
   12916             ctxt->context->node = NULL;
   12917             return (total);
   12918         case XPATH_OP_COLLECT:{
   12919                 if (op->ch1 == -1)
   12920                     return (0);
   12921 
   12922                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12923 		CHECK_ERROR0;
   12924 
   12925                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12926                 return (total);
   12927             }
   12928         case XPATH_OP_VALUE:
   12929             valuePush(ctxt,
   12930                       xmlXPathCacheObjectCopy(ctxt->context,
   12931 			(xmlXPathObjectPtr) op->value4));
   12932             return (0);
   12933         case XPATH_OP_SORT:
   12934             if (op->ch1 != -1)
   12935                 total +=
   12936                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12937                                            last);
   12938 	    CHECK_ERROR0;
   12939             if ((ctxt->value != NULL)
   12940                 && (ctxt->value->type == XPATH_NODESET)
   12941                 && (ctxt->value->nodesetval != NULL)
   12942 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12943                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12944             return (total);
   12945         default:
   12946             return (xmlXPathCompOpEval(ctxt, op));
   12947     }
   12948 }
   12949 
   12950 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12951 static int
   12952 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12953 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12954 {
   12955     int total = 0;
   12956     xmlXPathCompExprPtr comp;
   12957     xmlXPathObjectPtr res;
   12958     xmlXPathObjectPtr obj;
   12959     xmlNodeSetPtr oldset;
   12960     xmlNodePtr oldnode;
   12961     xmlDocPtr oldDoc;
   12962     int i;
   12963 
   12964     CHECK_ERROR0;
   12965     comp = ctxt->comp;
   12966     /*
   12967     * Optimization for ()[last()] selection i.e. the last elem
   12968     */
   12969     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12970 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12971 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12972 	int f = comp->steps[op->ch2].ch1;
   12973 
   12974 	if ((f != -1) &&
   12975 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12976 	    (comp->steps[f].value5 == NULL) &&
   12977 	    (comp->steps[f].value == 0) &&
   12978 	    (comp->steps[f].value4 != NULL) &&
   12979 	    (xmlStrEqual
   12980 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12981 	    xmlNodePtr last = NULL;
   12982 
   12983 	    total +=
   12984 		xmlXPathCompOpEvalLast(ctxt,
   12985 		    &comp->steps[op->ch1],
   12986 		    &last);
   12987 	    CHECK_ERROR0;
   12988 	    /*
   12989 	    * The nodeset should be in document order,
   12990 	    * Keep only the last value
   12991 	    */
   12992 	    if ((ctxt->value != NULL) &&
   12993 		(ctxt->value->type == XPATH_NODESET) &&
   12994 		(ctxt->value->nodesetval != NULL) &&
   12995 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12996 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12997 		ctxt->value->nodesetval->nodeTab[0] =
   12998 		    ctxt->value->nodesetval->nodeTab[ctxt->
   12999 		    value->
   13000 		    nodesetval->
   13001 		    nodeNr -
   13002 		    1];
   13003 		ctxt->value->nodesetval->nodeNr = 1;
   13004 		*first = *(ctxt->value->nodesetval->nodeTab);
   13005 	    }
   13006 	    return (total);
   13007 	}
   13008     }
   13009 
   13010     if (op->ch1 != -1)
   13011 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13012     CHECK_ERROR0;
   13013     if (op->ch2 == -1)
   13014 	return (total);
   13015     if (ctxt->value == NULL)
   13016 	return (total);
   13017 
   13018 #ifdef LIBXML_XPTR_ENABLED
   13019     oldnode = ctxt->context->node;
   13020     /*
   13021     * Hum are we filtering the result of an XPointer expression
   13022     */
   13023     if (ctxt->value->type == XPATH_LOCATIONSET) {
   13024 	xmlXPathObjectPtr tmp = NULL;
   13025 	xmlLocationSetPtr newlocset = NULL;
   13026 	xmlLocationSetPtr oldlocset;
   13027 
   13028 	/*
   13029 	* Extract the old locset, and then evaluate the result of the
   13030 	* expression for all the element in the locset. use it to grow
   13031 	* up a new locset.
   13032 	*/
   13033 	CHECK_TYPE0(XPATH_LOCATIONSET);
   13034 	obj = valuePop(ctxt);
   13035 	oldlocset = obj->user;
   13036 	ctxt->context->node = NULL;
   13037 
   13038 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13039 	    ctxt->context->contextSize = 0;
   13040 	    ctxt->context->proximityPosition = 0;
   13041 	    if (op->ch2 != -1)
   13042 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13043 	    res = valuePop(ctxt);
   13044 	    if (res != NULL) {
   13045 		xmlXPathReleaseObject(ctxt->context, res);
   13046 	    }
   13047 	    valuePush(ctxt, obj);
   13048 	    CHECK_ERROR0;
   13049 	    return (total);
   13050 	}
   13051 	newlocset = xmlXPtrLocationSetCreate(NULL);
   13052 
   13053 	for (i = 0; i < oldlocset->locNr; i++) {
   13054 	    /*
   13055 	    * Run the evaluation with a node list made of a
   13056 	    * single item in the nodelocset.
   13057 	    */
   13058 	    ctxt->context->node = oldlocset->locTab[i]->user;
   13059 	    ctxt->context->contextSize = oldlocset->locNr;
   13060 	    ctxt->context->proximityPosition = i + 1;
   13061 	    if (tmp == NULL) {
   13062 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13063 		    ctxt->context->node);
   13064 	    } else {
   13065 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13066 		                             ctxt->context->node) < 0) {
   13067 		    ctxt->error = XPATH_MEMORY_ERROR;
   13068 		}
   13069 	    }
   13070 	    valuePush(ctxt, tmp);
   13071 	    if (op->ch2 != -1)
   13072 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13073 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13074 		xmlXPathFreeObject(obj);
   13075 		return(0);
   13076 	    }
   13077 	    /*
   13078 	    * The result of the evaluation need to be tested to
   13079 	    * decided whether the filter succeeded or not
   13080 	    */
   13081 	    res = valuePop(ctxt);
   13082 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13083 		xmlXPtrLocationSetAdd(newlocset,
   13084 		    xmlXPathCacheObjectCopy(ctxt->context,
   13085 			oldlocset->locTab[i]));
   13086 	    }
   13087 	    /*
   13088 	    * Cleanup
   13089 	    */
   13090 	    if (res != NULL) {
   13091 		xmlXPathReleaseObject(ctxt->context, res);
   13092 	    }
   13093 	    if (ctxt->value == tmp) {
   13094 		valuePop(ctxt);
   13095 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13096 		/*
   13097 		* REVISIT TODO: Don't create a temporary nodeset
   13098 		* for everly iteration.
   13099 		*/
   13100 		/* OLD: xmlXPathFreeObject(res); */
   13101 	    } else
   13102 		tmp = NULL;
   13103 	    ctxt->context->node = NULL;
   13104 	    /*
   13105 	    * Only put the first node in the result, then leave.
   13106 	    */
   13107 	    if (newlocset->locNr > 0) {
   13108 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13109 		break;
   13110 	    }
   13111 	}
   13112 	if (tmp != NULL) {
   13113 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13114 	}
   13115 	/*
   13116 	* The result is used as the new evaluation locset.
   13117 	*/
   13118 	xmlXPathReleaseObject(ctxt->context, obj);
   13119 	ctxt->context->node = NULL;
   13120 	ctxt->context->contextSize = -1;
   13121 	ctxt->context->proximityPosition = -1;
   13122 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13123 	ctxt->context->node = oldnode;
   13124 	return (total);
   13125     }
   13126 #endif /* LIBXML_XPTR_ENABLED */
   13127 
   13128     /*
   13129     * Extract the old set, and then evaluate the result of the
   13130     * expression for all the element in the set. use it to grow
   13131     * up a new set.
   13132     */
   13133     CHECK_TYPE0(XPATH_NODESET);
   13134     obj = valuePop(ctxt);
   13135     oldset = obj->nodesetval;
   13136 
   13137     oldnode = ctxt->context->node;
   13138     oldDoc = ctxt->context->doc;
   13139     ctxt->context->node = NULL;
   13140 
   13141     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13142 	ctxt->context->contextSize = 0;
   13143 	ctxt->context->proximityPosition = 0;
   13144 	/* QUESTION TODO: Why was this code commented out?
   13145 	    if (op->ch2 != -1)
   13146 		total +=
   13147 		    xmlXPathCompOpEval(ctxt,
   13148 			&comp->steps[op->ch2]);
   13149 	    CHECK_ERROR0;
   13150 	    res = valuePop(ctxt);
   13151 	    if (res != NULL)
   13152 		xmlXPathFreeObject(res);
   13153 	*/
   13154 	valuePush(ctxt, obj);
   13155 	ctxt->context->node = oldnode;
   13156 	CHECK_ERROR0;
   13157     } else {
   13158 	xmlNodeSetPtr newset;
   13159 	xmlXPathObjectPtr tmp = NULL;
   13160 	/*
   13161 	* Initialize the new set.
   13162 	* Also set the xpath document in case things like
   13163 	* key() evaluation are attempted on the predicate
   13164 	*/
   13165 	newset = xmlXPathNodeSetCreate(NULL);
   13166         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13167 
   13168 	for (i = 0; i < oldset->nodeNr; i++) {
   13169 	    /*
   13170 	    * Run the evaluation with a node list made of
   13171 	    * a single item in the nodeset.
   13172 	    */
   13173 	    ctxt->context->node = oldset->nodeTab[i];
   13174 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13175 		(oldset->nodeTab[i]->doc != NULL))
   13176 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13177 	    if (tmp == NULL) {
   13178 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13179 		    ctxt->context->node);
   13180 	    } else {
   13181 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13182 		                             ctxt->context->node) < 0) {
   13183 		    ctxt->error = XPATH_MEMORY_ERROR;
   13184 		}
   13185 	    }
   13186 	    valuePush(ctxt, tmp);
   13187 	    ctxt->context->contextSize = oldset->nodeNr;
   13188 	    ctxt->context->proximityPosition = i + 1;
   13189 	    if (op->ch2 != -1)
   13190 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13191 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13192 		xmlXPathFreeNodeSet(newset);
   13193 		xmlXPathFreeObject(obj);
   13194 		return(0);
   13195 	    }
   13196 	    /*
   13197 	    * The result of the evaluation needs to be tested to
   13198 	    * decide whether the filter succeeded or not
   13199 	    */
   13200 	    res = valuePop(ctxt);
   13201 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13202 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
   13203 		    ctxt->error = XPATH_MEMORY_ERROR;
   13204 	    }
   13205 	    /*
   13206 	    * Cleanup
   13207 	    */
   13208 	    if (res != NULL) {
   13209 		xmlXPathReleaseObject(ctxt->context, res);
   13210 	    }
   13211 	    if (ctxt->value == tmp) {
   13212 		valuePop(ctxt);
   13213 		/*
   13214 		* Don't free the temporary nodeset
   13215 		* in order to avoid massive recreation inside this
   13216 		* loop.
   13217 		*/
   13218 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13219 	    } else
   13220 		tmp = NULL;
   13221 	    ctxt->context->node = NULL;
   13222 	    /*
   13223 	    * Only put the first node in the result, then leave.
   13224 	    */
   13225 	    if (newset->nodeNr > 0) {
   13226 		*first = *(newset->nodeTab);
   13227 		break;
   13228 	    }
   13229 	}
   13230 	if (tmp != NULL) {
   13231 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13232 	}
   13233 	/*
   13234 	* The result is used as the new evaluation set.
   13235 	*/
   13236 	xmlXPathReleaseObject(ctxt->context, obj);
   13237 	ctxt->context->node = NULL;
   13238 	ctxt->context->contextSize = -1;
   13239 	ctxt->context->proximityPosition = -1;
   13240 	/* may want to move this past the '}' later */
   13241 	ctxt->context->doc = oldDoc;
   13242 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13243     }
   13244     ctxt->context->node = oldnode;
   13245     return(total);
   13246 }
   13247 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13248 
   13249 /**
   13250  * xmlXPathCompOpEval:
   13251  * @ctxt:  the XPath parser context with the compiled expression
   13252  * @op:  an XPath compiled operation
   13253  *
   13254  * Evaluate the Precompiled XPath operation
   13255  * Returns the number of nodes traversed
   13256  */
   13257 static int
   13258 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13259 {
   13260     int total = 0;
   13261     int equal, ret;
   13262     xmlXPathCompExprPtr comp;
   13263     xmlXPathObjectPtr arg1, arg2;
   13264     xmlNodePtr bak;
   13265     xmlDocPtr bakd;
   13266     int pp;
   13267     int cs;
   13268 
   13269     CHECK_ERROR0;
   13270     comp = ctxt->comp;
   13271     switch (op->op) {
   13272         case XPATH_OP_END:
   13273             return (0);
   13274         case XPATH_OP_AND:
   13275 	    bakd = ctxt->context->doc;
   13276 	    bak = ctxt->context->node;
   13277 	    pp = ctxt->context->proximityPosition;
   13278 	    cs = ctxt->context->contextSize;
   13279             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13280 	    CHECK_ERROR0;
   13281             xmlXPathBooleanFunction(ctxt, 1);
   13282             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13283                 return (total);
   13284             arg2 = valuePop(ctxt);
   13285 	    ctxt->context->doc = bakd;
   13286 	    ctxt->context->node = bak;
   13287 	    ctxt->context->proximityPosition = pp;
   13288 	    ctxt->context->contextSize = cs;
   13289             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13290 	    if (ctxt->error) {
   13291 		xmlXPathFreeObject(arg2);
   13292 		return(0);
   13293 	    }
   13294             xmlXPathBooleanFunction(ctxt, 1);
   13295             arg1 = valuePop(ctxt);
   13296             arg1->boolval &= arg2->boolval;
   13297             valuePush(ctxt, arg1);
   13298 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13299             return (total);
   13300         case XPATH_OP_OR:
   13301 	    bakd = ctxt->context->doc;
   13302 	    bak = ctxt->context->node;
   13303 	    pp = ctxt->context->proximityPosition;
   13304 	    cs = ctxt->context->contextSize;
   13305             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13306 	    CHECK_ERROR0;
   13307             xmlXPathBooleanFunction(ctxt, 1);
   13308             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13309                 return (total);
   13310             arg2 = valuePop(ctxt);
   13311 	    ctxt->context->doc = bakd;
   13312 	    ctxt->context->node = bak;
   13313 	    ctxt->context->proximityPosition = pp;
   13314 	    ctxt->context->contextSize = cs;
   13315             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13316 	    if (ctxt->error) {
   13317 		xmlXPathFreeObject(arg2);
   13318 		return(0);
   13319 	    }
   13320             xmlXPathBooleanFunction(ctxt, 1);
   13321             arg1 = valuePop(ctxt);
   13322             arg1->boolval |= arg2->boolval;
   13323             valuePush(ctxt, arg1);
   13324 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13325             return (total);
   13326         case XPATH_OP_EQUAL:
   13327 	    bakd = ctxt->context->doc;
   13328 	    bak = ctxt->context->node;
   13329 	    pp = ctxt->context->proximityPosition;
   13330 	    cs = ctxt->context->contextSize;
   13331             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13332 	    CHECK_ERROR0;
   13333 	    ctxt->context->doc = bakd;
   13334 	    ctxt->context->node = bak;
   13335 	    ctxt->context->proximityPosition = pp;
   13336 	    ctxt->context->contextSize = cs;
   13337             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13338 	    CHECK_ERROR0;
   13339 	    if (op->value)
   13340 		equal = xmlXPathEqualValues(ctxt);
   13341 	    else
   13342 		equal = xmlXPathNotEqualValues(ctxt);
   13343 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13344             return (total);
   13345         case XPATH_OP_CMP:
   13346 	    bakd = ctxt->context->doc;
   13347 	    bak = ctxt->context->node;
   13348 	    pp = ctxt->context->proximityPosition;
   13349 	    cs = ctxt->context->contextSize;
   13350             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13351 	    CHECK_ERROR0;
   13352 	    ctxt->context->doc = bakd;
   13353 	    ctxt->context->node = bak;
   13354 	    ctxt->context->proximityPosition = pp;
   13355 	    ctxt->context->contextSize = cs;
   13356             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13357 	    CHECK_ERROR0;
   13358             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13359 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13360             return (total);
   13361         case XPATH_OP_PLUS:
   13362 	    bakd = ctxt->context->doc;
   13363 	    bak = ctxt->context->node;
   13364 	    pp = ctxt->context->proximityPosition;
   13365 	    cs = ctxt->context->contextSize;
   13366             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13367 	    CHECK_ERROR0;
   13368             if (op->ch2 != -1) {
   13369 		ctxt->context->doc = bakd;
   13370 		ctxt->context->node = bak;
   13371 		ctxt->context->proximityPosition = pp;
   13372 		ctxt->context->contextSize = cs;
   13373                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13374 	    }
   13375 	    CHECK_ERROR0;
   13376             if (op->value == 0)
   13377                 xmlXPathSubValues(ctxt);
   13378             else if (op->value == 1)
   13379                 xmlXPathAddValues(ctxt);
   13380             else if (op->value == 2)
   13381                 xmlXPathValueFlipSign(ctxt);
   13382             else if (op->value == 3) {
   13383                 CAST_TO_NUMBER;
   13384                 CHECK_TYPE0(XPATH_NUMBER);
   13385             }
   13386             return (total);
   13387         case XPATH_OP_MULT:
   13388 	    bakd = ctxt->context->doc;
   13389 	    bak = ctxt->context->node;
   13390 	    pp = ctxt->context->proximityPosition;
   13391 	    cs = ctxt->context->contextSize;
   13392             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13393 	    CHECK_ERROR0;
   13394 	    ctxt->context->doc = bakd;
   13395 	    ctxt->context->node = bak;
   13396 	    ctxt->context->proximityPosition = pp;
   13397 	    ctxt->context->contextSize = cs;
   13398             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13399 	    CHECK_ERROR0;
   13400             if (op->value == 0)
   13401                 xmlXPathMultValues(ctxt);
   13402             else if (op->value == 1)
   13403                 xmlXPathDivValues(ctxt);
   13404             else if (op->value == 2)
   13405                 xmlXPathModValues(ctxt);
   13406             return (total);
   13407         case XPATH_OP_UNION:
   13408 	    bakd = ctxt->context->doc;
   13409 	    bak = ctxt->context->node;
   13410 	    pp = ctxt->context->proximityPosition;
   13411 	    cs = ctxt->context->contextSize;
   13412             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13413 	    CHECK_ERROR0;
   13414 	    ctxt->context->doc = bakd;
   13415 	    ctxt->context->node = bak;
   13416 	    ctxt->context->proximityPosition = pp;
   13417 	    ctxt->context->contextSize = cs;
   13418             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13419 	    CHECK_ERROR0;
   13420             CHECK_TYPE0(XPATH_NODESET);
   13421             arg2 = valuePop(ctxt);
   13422 
   13423             CHECK_TYPE0(XPATH_NODESET);
   13424             arg1 = valuePop(ctxt);
   13425 
   13426 	    if ((arg1->nodesetval == NULL) ||
   13427 		((arg2->nodesetval != NULL) &&
   13428 		 (arg2->nodesetval->nodeNr != 0)))
   13429 	    {
   13430 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13431 							arg2->nodesetval);
   13432 	    }
   13433 
   13434             valuePush(ctxt, arg1);
   13435 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13436             return (total);
   13437         case XPATH_OP_ROOT:
   13438             xmlXPathRoot(ctxt);
   13439             return (total);
   13440         case XPATH_OP_NODE:
   13441             if (op->ch1 != -1)
   13442                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13443 	    CHECK_ERROR0;
   13444             if (op->ch2 != -1)
   13445                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13446 	    CHECK_ERROR0;
   13447 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13448 		ctxt->context->node));
   13449             return (total);
   13450         case XPATH_OP_RESET:
   13451             if (op->ch1 != -1)
   13452                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13453 	    CHECK_ERROR0;
   13454             if (op->ch2 != -1)
   13455                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13456 	    CHECK_ERROR0;
   13457             ctxt->context->node = NULL;
   13458             return (total);
   13459         case XPATH_OP_COLLECT:{
   13460                 if (op->ch1 == -1)
   13461                     return (total);
   13462 
   13463                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13464 		CHECK_ERROR0;
   13465 
   13466                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13467                 return (total);
   13468             }
   13469         case XPATH_OP_VALUE:
   13470             valuePush(ctxt,
   13471                       xmlXPathCacheObjectCopy(ctxt->context,
   13472 			(xmlXPathObjectPtr) op->value4));
   13473             return (total);
   13474         case XPATH_OP_VARIABLE:{
   13475 		xmlXPathObjectPtr val;
   13476 
   13477                 if (op->ch1 != -1)
   13478                     total +=
   13479                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13480                 if (op->value5 == NULL) {
   13481 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13482 		    if (val == NULL) {
   13483 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13484 			return(0);
   13485 		    }
   13486                     valuePush(ctxt, val);
   13487 		} else {
   13488                     const xmlChar *URI;
   13489 
   13490                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13491                     if (URI == NULL) {
   13492                         xmlGenericError(xmlGenericErrorContext,
   13493             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13494                                     (char *) op->value4, (char *)op->value5);
   13495                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13496                         return (total);
   13497                     }
   13498 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13499                                                        op->value4, URI);
   13500 		    if (val == NULL) {
   13501 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13502 			return(0);
   13503 		    }
   13504                     valuePush(ctxt, val);
   13505                 }
   13506                 return (total);
   13507             }
   13508         case XPATH_OP_FUNCTION:{
   13509                 xmlXPathFunction func;
   13510                 const xmlChar *oldFunc, *oldFuncURI;
   13511 		int i;
   13512                 int frame;
   13513 
   13514                 frame = xmlXPathSetFrame(ctxt);
   13515                 if (op->ch1 != -1)
   13516                     total +=
   13517                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13518 		if (ctxt->valueNr < op->value) {
   13519 		    xmlGenericError(xmlGenericErrorContext,
   13520 			    "xmlXPathCompOpEval: parameter error\n");
   13521 		    ctxt->error = XPATH_INVALID_OPERAND;
   13522                     xmlXPathPopFrame(ctxt, frame);
   13523 		    return (total);
   13524 		}
   13525 		for (i = 0; i < op->value; i++) {
   13526 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13527 			xmlGenericError(xmlGenericErrorContext,
   13528 				"xmlXPathCompOpEval: parameter error\n");
   13529 			ctxt->error = XPATH_INVALID_OPERAND;
   13530                         xmlXPathPopFrame(ctxt, frame);
   13531 			return (total);
   13532 		    }
   13533                 }
   13534                 if (op->cache != NULL)
   13535                     XML_CAST_FPTR(func) = op->cache;
   13536                 else {
   13537                     const xmlChar *URI = NULL;
   13538 
   13539                     if (op->value5 == NULL)
   13540                         func =
   13541                             xmlXPathFunctionLookup(ctxt->context,
   13542                                                    op->value4);
   13543                     else {
   13544                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13545                         if (URI == NULL) {
   13546                             xmlGenericError(xmlGenericErrorContext,
   13547             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13548                                     (char *)op->value4, (char *)op->value5);
   13549                             xmlXPathPopFrame(ctxt, frame);
   13550                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13551                             return (total);
   13552                         }
   13553                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13554                                                         op->value4, URI);
   13555                     }
   13556                     if (func == NULL) {
   13557                         xmlGenericError(xmlGenericErrorContext,
   13558                                 "xmlXPathCompOpEval: function %s not found\n",
   13559                                         (char *)op->value4);
   13560                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13561                     }
   13562                     op->cache = XML_CAST_FPTR(func);
   13563                     op->cacheURI = (void *) URI;
   13564                 }
   13565                 oldFunc = ctxt->context->function;
   13566                 oldFuncURI = ctxt->context->functionURI;
   13567                 ctxt->context->function = op->value4;
   13568                 ctxt->context->functionURI = op->cacheURI;
   13569                 func(ctxt, op->value);
   13570                 ctxt->context->function = oldFunc;
   13571                 ctxt->context->functionURI = oldFuncURI;
   13572                 xmlXPathPopFrame(ctxt, frame);
   13573                 return (total);
   13574             }
   13575         case XPATH_OP_ARG:
   13576 	    bakd = ctxt->context->doc;
   13577 	    bak = ctxt->context->node;
   13578 	    pp = ctxt->context->proximityPosition;
   13579 	    cs = ctxt->context->contextSize;
   13580             if (op->ch1 != -1)
   13581                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13582 	    ctxt->context->contextSize = cs;
   13583 	    ctxt->context->proximityPosition = pp;
   13584 	    ctxt->context->node = bak;
   13585 	    ctxt->context->doc = bakd;
   13586 	    CHECK_ERROR0;
   13587             if (op->ch2 != -1) {
   13588                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13589 	        ctxt->context->doc = bakd;
   13590 	        ctxt->context->node = bak;
   13591 	        CHECK_ERROR0;
   13592 	    }
   13593             return (total);
   13594         case XPATH_OP_PREDICATE:
   13595         case XPATH_OP_FILTER:{
   13596                 xmlXPathObjectPtr res;
   13597                 xmlXPathObjectPtr obj, tmp;
   13598                 xmlNodeSetPtr newset = NULL;
   13599                 xmlNodeSetPtr oldset;
   13600                 xmlNodePtr oldnode;
   13601 		xmlDocPtr oldDoc;
   13602                 int i;
   13603 
   13604                 /*
   13605                  * Optimization for ()[1] selection i.e. the first elem
   13606                  */
   13607                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13608 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13609 		    /*
   13610 		    * FILTER TODO: Can we assume that the inner processing
   13611 		    *  will result in an ordered list if we have an
   13612 		    *  XPATH_OP_FILTER?
   13613 		    *  What about an additional field or flag on
   13614 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13615 		    *  to assume anything, so it would be more robust and
   13616 		    *  easier to optimize.
   13617 		    */
   13618                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13619 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13620 #else
   13621 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13622 #endif
   13623                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13624                     xmlXPathObjectPtr val;
   13625 
   13626                     val = comp->steps[op->ch2].value4;
   13627                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13628                         (val->floatval == 1.0)) {
   13629                         xmlNodePtr first = NULL;
   13630 
   13631                         total +=
   13632                             xmlXPathCompOpEvalFirst(ctxt,
   13633                                                     &comp->steps[op->ch1],
   13634                                                     &first);
   13635 			CHECK_ERROR0;
   13636                         /*
   13637                          * The nodeset should be in document order,
   13638                          * Keep only the first value
   13639                          */
   13640                         if ((ctxt->value != NULL) &&
   13641                             (ctxt->value->type == XPATH_NODESET) &&
   13642                             (ctxt->value->nodesetval != NULL) &&
   13643                             (ctxt->value->nodesetval->nodeNr > 1))
   13644                             ctxt->value->nodesetval->nodeNr = 1;
   13645                         return (total);
   13646                     }
   13647                 }
   13648                 /*
   13649                  * Optimization for ()[last()] selection i.e. the last elem
   13650                  */
   13651                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13652                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13653                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13654                     int f = comp->steps[op->ch2].ch1;
   13655 
   13656                     if ((f != -1) &&
   13657                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13658                         (comp->steps[f].value5 == NULL) &&
   13659                         (comp->steps[f].value == 0) &&
   13660                         (comp->steps[f].value4 != NULL) &&
   13661                         (xmlStrEqual
   13662                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13663                         xmlNodePtr last = NULL;
   13664 
   13665                         total +=
   13666                             xmlXPathCompOpEvalLast(ctxt,
   13667                                                    &comp->steps[op->ch1],
   13668                                                    &last);
   13669 			CHECK_ERROR0;
   13670                         /*
   13671                          * The nodeset should be in document order,
   13672                          * Keep only the last value
   13673                          */
   13674                         if ((ctxt->value != NULL) &&
   13675                             (ctxt->value->type == XPATH_NODESET) &&
   13676                             (ctxt->value->nodesetval != NULL) &&
   13677                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13678                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13679                             ctxt->value->nodesetval->nodeTab[0] =
   13680                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13681                                                                  value->
   13682                                                                  nodesetval->
   13683                                                                  nodeNr -
   13684                                                                  1];
   13685                             ctxt->value->nodesetval->nodeNr = 1;
   13686                         }
   13687                         return (total);
   13688                     }
   13689                 }
   13690 		/*
   13691 		* Process inner predicates first.
   13692 		* Example "index[parent::book][1]":
   13693 		* ...
   13694 		*   PREDICATE   <-- we are here "[1]"
   13695 		*     PREDICATE <-- process "[parent::book]" first
   13696 		*       SORT
   13697 		*         COLLECT  'parent' 'name' 'node' book
   13698 		*           NODE
   13699 		*     ELEM Object is a number : 1
   13700 		*/
   13701                 if (op->ch1 != -1)
   13702                     total +=
   13703                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13704 		CHECK_ERROR0;
   13705                 if (op->ch2 == -1)
   13706                     return (total);
   13707                 if (ctxt->value == NULL)
   13708                     return (total);
   13709 
   13710                 oldnode = ctxt->context->node;
   13711 
   13712 #ifdef LIBXML_XPTR_ENABLED
   13713                 /*
   13714                  * Hum are we filtering the result of an XPointer expression
   13715                  */
   13716                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13717                     xmlLocationSetPtr newlocset = NULL;
   13718                     xmlLocationSetPtr oldlocset;
   13719 
   13720                     /*
   13721                      * Extract the old locset, and then evaluate the result of the
   13722                      * expression for all the element in the locset. use it to grow
   13723                      * up a new locset.
   13724                      */
   13725                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13726                     obj = valuePop(ctxt);
   13727                     oldlocset = obj->user;
   13728                     ctxt->context->node = NULL;
   13729 
   13730                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13731                         ctxt->context->contextSize = 0;
   13732                         ctxt->context->proximityPosition = 0;
   13733                         if (op->ch2 != -1)
   13734                             total +=
   13735                                 xmlXPathCompOpEval(ctxt,
   13736                                                    &comp->steps[op->ch2]);
   13737                         res = valuePop(ctxt);
   13738                         if (res != NULL) {
   13739 			    xmlXPathReleaseObject(ctxt->context, res);
   13740 			}
   13741                         valuePush(ctxt, obj);
   13742                         CHECK_ERROR0;
   13743                         return (total);
   13744                     }
   13745                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13746 
   13747                     for (i = 0; i < oldlocset->locNr; i++) {
   13748                         /*
   13749                          * Run the evaluation with a node list made of a
   13750                          * single item in the nodelocset.
   13751                          */
   13752                         ctxt->context->node = oldlocset->locTab[i]->user;
   13753                         ctxt->context->contextSize = oldlocset->locNr;
   13754                         ctxt->context->proximityPosition = i + 1;
   13755 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13756 			    ctxt->context->node);
   13757                         valuePush(ctxt, tmp);
   13758 
   13759                         if (op->ch2 != -1)
   13760                             total +=
   13761                                 xmlXPathCompOpEval(ctxt,
   13762                                                    &comp->steps[op->ch2]);
   13763 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13764 			    xmlXPathFreeObject(obj);
   13765 			    return(0);
   13766 			}
   13767 
   13768                         /*
   13769                          * The result of the evaluation need to be tested to
   13770                          * decided whether the filter succeeded or not
   13771                          */
   13772                         res = valuePop(ctxt);
   13773                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13774                             xmlXPtrLocationSetAdd(newlocset,
   13775                                                   xmlXPathObjectCopy
   13776                                                   (oldlocset->locTab[i]));
   13777                         }
   13778 
   13779                         /*
   13780                          * Cleanup
   13781                          */
   13782                         if (res != NULL) {
   13783 			    xmlXPathReleaseObject(ctxt->context, res);
   13784 			}
   13785                         if (ctxt->value == tmp) {
   13786                             res = valuePop(ctxt);
   13787 			    xmlXPathReleaseObject(ctxt->context, res);
   13788                         }
   13789 
   13790                         ctxt->context->node = NULL;
   13791                     }
   13792 
   13793                     /*
   13794                      * The result is used as the new evaluation locset.
   13795                      */
   13796 		    xmlXPathReleaseObject(ctxt->context, obj);
   13797                     ctxt->context->node = NULL;
   13798                     ctxt->context->contextSize = -1;
   13799                     ctxt->context->proximityPosition = -1;
   13800                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13801                     ctxt->context->node = oldnode;
   13802                     return (total);
   13803                 }
   13804 #endif /* LIBXML_XPTR_ENABLED */
   13805 
   13806                 /*
   13807                  * Extract the old set, and then evaluate the result of the
   13808                  * expression for all the element in the set. use it to grow
   13809                  * up a new set.
   13810                  */
   13811                 CHECK_TYPE0(XPATH_NODESET);
   13812                 obj = valuePop(ctxt);
   13813                 oldset = obj->nodesetval;
   13814 
   13815                 oldnode = ctxt->context->node;
   13816 		oldDoc = ctxt->context->doc;
   13817                 ctxt->context->node = NULL;
   13818 
   13819                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13820                     ctxt->context->contextSize = 0;
   13821                     ctxt->context->proximityPosition = 0;
   13822 /*
   13823                     if (op->ch2 != -1)
   13824                         total +=
   13825                             xmlXPathCompOpEval(ctxt,
   13826                                                &comp->steps[op->ch2]);
   13827 		    CHECK_ERROR0;
   13828                     res = valuePop(ctxt);
   13829                     if (res != NULL)
   13830                         xmlXPathFreeObject(res);
   13831 */
   13832                     valuePush(ctxt, obj);
   13833                     ctxt->context->node = oldnode;
   13834                     CHECK_ERROR0;
   13835                 } else {
   13836 		    tmp = NULL;
   13837                     /*
   13838                      * Initialize the new set.
   13839 		     * Also set the xpath document in case things like
   13840 		     * key() evaluation are attempted on the predicate
   13841                      */
   13842                     newset = xmlXPathNodeSetCreate(NULL);
   13843 		    /*
   13844 		    * SPEC XPath 1.0:
   13845 		    *  "For each node in the node-set to be filtered, the
   13846 		    *  PredicateExpr is evaluated with that node as the
   13847 		    *  context node, with the number of nodes in the
   13848 		    *  node-set as the context size, and with the proximity
   13849 		    *  position of the node in the node-set with respect to
   13850 		    *  the axis as the context position;"
   13851 		    * @oldset is the node-set" to be filtered.
   13852 		    *
   13853 		    * SPEC XPath 1.0:
   13854 		    *  "only predicates change the context position and
   13855 		    *  context size (see [2.4 Predicates])."
   13856 		    * Example:
   13857 		    *   node-set  context pos
   13858 		    *    nA         1
   13859 		    *    nB         2
   13860 		    *    nC         3
   13861 		    *   After applying predicate [position() > 1] :
   13862 		    *   node-set  context pos
   13863 		    *    nB         1
   13864 		    *    nC         2
   13865 		    *
   13866 		    * removed the first node in the node-set, then
   13867 		    * the context position of the
   13868 		    */
   13869                     for (i = 0; i < oldset->nodeNr; i++) {
   13870                         /*
   13871                          * Run the evaluation with a node list made of
   13872                          * a single item in the nodeset.
   13873                          */
   13874                         ctxt->context->node = oldset->nodeTab[i];
   13875 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13876 			    (oldset->nodeTab[i]->doc != NULL))
   13877 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13878 			if (tmp == NULL) {
   13879 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13880 				ctxt->context->node);
   13881 			} else {
   13882 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13883 				               ctxt->context->node) < 0) {
   13884 				ctxt->error = XPATH_MEMORY_ERROR;
   13885 			    }
   13886 			}
   13887                         valuePush(ctxt, tmp);
   13888                         ctxt->context->contextSize = oldset->nodeNr;
   13889                         ctxt->context->proximityPosition = i + 1;
   13890 			/*
   13891 			* Evaluate the predicate against the context node.
   13892 			* Can/should we optimize position() predicates
   13893 			* here (e.g. "[1]")?
   13894 			*/
   13895                         if (op->ch2 != -1)
   13896                             total +=
   13897                                 xmlXPathCompOpEval(ctxt,
   13898                                                    &comp->steps[op->ch2]);
   13899 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13900 			    xmlXPathFreeNodeSet(newset);
   13901 			    xmlXPathFreeObject(obj);
   13902 			    return(0);
   13903 			}
   13904 
   13905                         /*
   13906                          * The result of the evaluation needs to be tested to
   13907                          * decide whether the filter succeeded or not
   13908                          */
   13909 			/*
   13910 			* OPTIMIZE TODO: Can we use
   13911 			* xmlXPathNodeSetAdd*Unique()* instead?
   13912 			*/
   13913                         res = valuePop(ctxt);
   13914                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13915                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
   13916 			        < 0)
   13917 				ctxt->error = XPATH_MEMORY_ERROR;
   13918                         }
   13919 
   13920                         /*
   13921                          * Cleanup
   13922                          */
   13923                         if (res != NULL) {
   13924 			    xmlXPathReleaseObject(ctxt->context, res);
   13925 			}
   13926                         if (ctxt->value == tmp) {
   13927                             valuePop(ctxt);
   13928 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13929 			    /*
   13930 			    * Don't free the temporary nodeset
   13931 			    * in order to avoid massive recreation inside this
   13932 			    * loop.
   13933 			    */
   13934                         } else
   13935 			    tmp = NULL;
   13936                         ctxt->context->node = NULL;
   13937                     }
   13938 		    if (tmp != NULL)
   13939 			xmlXPathReleaseObject(ctxt->context, tmp);
   13940                     /*
   13941                      * The result is used as the new evaluation set.
   13942                      */
   13943 		    xmlXPathReleaseObject(ctxt->context, obj);
   13944                     ctxt->context->node = NULL;
   13945                     ctxt->context->contextSize = -1;
   13946                     ctxt->context->proximityPosition = -1;
   13947 		    /* may want to move this past the '}' later */
   13948 		    ctxt->context->doc = oldDoc;
   13949 		    valuePush(ctxt,
   13950 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13951                 }
   13952                 ctxt->context->node = oldnode;
   13953                 return (total);
   13954             }
   13955         case XPATH_OP_SORT:
   13956             if (op->ch1 != -1)
   13957                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13958 	    CHECK_ERROR0;
   13959             if ((ctxt->value != NULL) &&
   13960                 (ctxt->value->type == XPATH_NODESET) &&
   13961                 (ctxt->value->nodesetval != NULL) &&
   13962 		(ctxt->value->nodesetval->nodeNr > 1))
   13963 	    {
   13964                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13965 	    }
   13966             return (total);
   13967 #ifdef LIBXML_XPTR_ENABLED
   13968         case XPATH_OP_RANGETO:{
   13969                 xmlXPathObjectPtr range;
   13970                 xmlXPathObjectPtr res, obj;
   13971                 xmlXPathObjectPtr tmp;
   13972                 xmlLocationSetPtr newlocset = NULL;
   13973 		    xmlLocationSetPtr oldlocset;
   13974                 xmlNodeSetPtr oldset;
   13975                 int i, j;
   13976 
   13977                 if (op->ch1 != -1)
   13978                     total +=
   13979                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13980                 if (op->ch2 == -1)
   13981                     return (total);
   13982 
   13983                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13984                     /*
   13985                      * Extract the old locset, and then evaluate the result of the
   13986                      * expression for all the element in the locset. use it to grow
   13987                      * up a new locset.
   13988                      */
   13989                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13990                     obj = valuePop(ctxt);
   13991                     oldlocset = obj->user;
   13992 
   13993                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13994 		        ctxt->context->node = NULL;
   13995                         ctxt->context->contextSize = 0;
   13996                         ctxt->context->proximityPosition = 0;
   13997                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   13998                         res = valuePop(ctxt);
   13999                         if (res != NULL) {
   14000 			    xmlXPathReleaseObject(ctxt->context, res);
   14001 			}
   14002                         valuePush(ctxt, obj);
   14003                         CHECK_ERROR0;
   14004                         return (total);
   14005                     }
   14006                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14007 
   14008                     for (i = 0; i < oldlocset->locNr; i++) {
   14009                         /*
   14010                          * Run the evaluation with a node list made of a
   14011                          * single item in the nodelocset.
   14012                          */
   14013                         ctxt->context->node = oldlocset->locTab[i]->user;
   14014                         ctxt->context->contextSize = oldlocset->locNr;
   14015                         ctxt->context->proximityPosition = i + 1;
   14016 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14017 			    ctxt->context->node);
   14018                         valuePush(ctxt, tmp);
   14019 
   14020                         if (op->ch2 != -1)
   14021                             total +=
   14022                                 xmlXPathCompOpEval(ctxt,
   14023                                                    &comp->steps[op->ch2]);
   14024 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   14025 			    xmlXPathFreeObject(obj);
   14026 			    return(0);
   14027 			}
   14028 
   14029                         res = valuePop(ctxt);
   14030 			if (res->type == XPATH_LOCATIONSET) {
   14031 			    xmlLocationSetPtr rloc =
   14032 			        (xmlLocationSetPtr)res->user;
   14033 			    for (j=0; j<rloc->locNr; j++) {
   14034 			        range = xmlXPtrNewRange(
   14035 				  oldlocset->locTab[i]->user,
   14036 				  oldlocset->locTab[i]->index,
   14037 				  rloc->locTab[j]->user2,
   14038 				  rloc->locTab[j]->index2);
   14039 				if (range != NULL) {
   14040 				    xmlXPtrLocationSetAdd(newlocset, range);
   14041 				}
   14042 			    }
   14043 			} else {
   14044 			    range = xmlXPtrNewRangeNodeObject(
   14045 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   14046                             if (range != NULL) {
   14047                                 xmlXPtrLocationSetAdd(newlocset,range);
   14048 			    }
   14049                         }
   14050 
   14051                         /*
   14052                          * Cleanup
   14053                          */
   14054                         if (res != NULL) {
   14055 			    xmlXPathReleaseObject(ctxt->context, res);
   14056 			}
   14057                         if (ctxt->value == tmp) {
   14058                             res = valuePop(ctxt);
   14059 			    xmlXPathReleaseObject(ctxt->context, res);
   14060                         }
   14061 
   14062                         ctxt->context->node = NULL;
   14063                     }
   14064 		} else {	/* Not a location set */
   14065                     CHECK_TYPE0(XPATH_NODESET);
   14066                     obj = valuePop(ctxt);
   14067                     oldset = obj->nodesetval;
   14068                     ctxt->context->node = NULL;
   14069 
   14070                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14071 
   14072                     if (oldset != NULL) {
   14073                         for (i = 0; i < oldset->nodeNr; i++) {
   14074                             /*
   14075                              * Run the evaluation with a node list made of a single item
   14076                              * in the nodeset.
   14077                              */
   14078                             ctxt->context->node = oldset->nodeTab[i];
   14079 			    /*
   14080 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   14081 			    */
   14082 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14083 				ctxt->context->node);
   14084                             valuePush(ctxt, tmp);
   14085 
   14086                             if (op->ch2 != -1)
   14087                                 total +=
   14088                                     xmlXPathCompOpEval(ctxt,
   14089                                                    &comp->steps[op->ch2]);
   14090 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   14091 				xmlXPathFreeObject(obj);
   14092 				return(0);
   14093 			    }
   14094 
   14095                             res = valuePop(ctxt);
   14096                             range =
   14097                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   14098                                                       res);
   14099                             if (range != NULL) {
   14100                                 xmlXPtrLocationSetAdd(newlocset, range);
   14101                             }
   14102 
   14103                             /*
   14104                              * Cleanup
   14105                              */
   14106                             if (res != NULL) {
   14107 				xmlXPathReleaseObject(ctxt->context, res);
   14108 			    }
   14109                             if (ctxt->value == tmp) {
   14110                                 res = valuePop(ctxt);
   14111 				xmlXPathReleaseObject(ctxt->context, res);
   14112                             }
   14113 
   14114                             ctxt->context->node = NULL;
   14115                         }
   14116                     }
   14117                 }
   14118 
   14119                 /*
   14120                  * The result is used as the new evaluation set.
   14121                  */
   14122 		xmlXPathReleaseObject(ctxt->context, obj);
   14123                 ctxt->context->node = NULL;
   14124                 ctxt->context->contextSize = -1;
   14125                 ctxt->context->proximityPosition = -1;
   14126                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   14127                 return (total);
   14128             }
   14129 #endif /* LIBXML_XPTR_ENABLED */
   14130     }
   14131     xmlGenericError(xmlGenericErrorContext,
   14132                     "XPath: unknown precompiled operation %d\n", op->op);
   14133     ctxt->error = XPATH_INVALID_OPERAND;
   14134     return (total);
   14135 }
   14136 
   14137 /**
   14138  * xmlXPathCompOpEvalToBoolean:
   14139  * @ctxt:  the XPath parser context
   14140  *
   14141  * Evaluates if the expression evaluates to true.
   14142  *
   14143  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   14144  */
   14145 static int
   14146 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   14147 			    xmlXPathStepOpPtr op,
   14148 			    int isPredicate)
   14149 {
   14150     xmlXPathObjectPtr resObj = NULL;
   14151 
   14152 start:
   14153     /* comp = ctxt->comp; */
   14154     switch (op->op) {
   14155         case XPATH_OP_END:
   14156             return (0);
   14157 	case XPATH_OP_VALUE:
   14158 	    resObj = (xmlXPathObjectPtr) op->value4;
   14159 	    if (isPredicate)
   14160 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14161 	    return(xmlXPathCastToBoolean(resObj));
   14162 	case XPATH_OP_SORT:
   14163 	    /*
   14164 	    * We don't need sorting for boolean results. Skip this one.
   14165 	    */
   14166             if (op->ch1 != -1) {
   14167 		op = &ctxt->comp->steps[op->ch1];
   14168 		goto start;
   14169 	    }
   14170 	    return(0);
   14171 	case XPATH_OP_COLLECT:
   14172 	    if (op->ch1 == -1)
   14173 		return(0);
   14174 
   14175             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14176 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14177 		return(-1);
   14178 
   14179             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14180 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14181 		return(-1);
   14182 
   14183 	    resObj = valuePop(ctxt);
   14184 	    if (resObj == NULL)
   14185 		return(-1);
   14186 	    break;
   14187 	default:
   14188 	    /*
   14189 	    * Fallback to call xmlXPathCompOpEval().
   14190 	    */
   14191 	    xmlXPathCompOpEval(ctxt, op);
   14192 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14193 		return(-1);
   14194 
   14195 	    resObj = valuePop(ctxt);
   14196 	    if (resObj == NULL)
   14197 		return(-1);
   14198 	    break;
   14199     }
   14200 
   14201     if (resObj) {
   14202 	int res;
   14203 
   14204 	if (resObj->type == XPATH_BOOLEAN) {
   14205 	    res = resObj->boolval;
   14206 	} else if (isPredicate) {
   14207 	    /*
   14208 	    * For predicates a result of type "number" is handled
   14209 	    * differently:
   14210 	    * SPEC XPath 1.0:
   14211 	    * "If the result is a number, the result will be converted
   14212 	    *  to true if the number is equal to the context position
   14213 	    *  and will be converted to false otherwise;"
   14214 	    */
   14215 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14216 	} else {
   14217 	    res = xmlXPathCastToBoolean(resObj);
   14218 	}
   14219 	xmlXPathReleaseObject(ctxt->context, resObj);
   14220 	return(res);
   14221     }
   14222 
   14223     return(0);
   14224 }
   14225 
   14226 #ifdef XPATH_STREAMING
   14227 /**
   14228  * xmlXPathRunStreamEval:
   14229  * @ctxt:  the XPath parser context with the compiled expression
   14230  *
   14231  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14232  */
   14233 static int
   14234 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14235 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14236 {
   14237     int max_depth, min_depth;
   14238     int from_root;
   14239     int ret, depth;
   14240     int eval_all_nodes;
   14241     xmlNodePtr cur = NULL, limit = NULL;
   14242     xmlStreamCtxtPtr patstream = NULL;
   14243 
   14244     int nb_nodes = 0;
   14245 
   14246     if ((ctxt == NULL) || (comp == NULL))
   14247         return(-1);
   14248     max_depth = xmlPatternMaxDepth(comp);
   14249     if (max_depth == -1)
   14250         return(-1);
   14251     if (max_depth == -2)
   14252         max_depth = 10000;
   14253     min_depth = xmlPatternMinDepth(comp);
   14254     if (min_depth == -1)
   14255         return(-1);
   14256     from_root = xmlPatternFromRoot(comp);
   14257     if (from_root < 0)
   14258         return(-1);
   14259 #if 0
   14260     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14261 #endif
   14262 
   14263     if (! toBool) {
   14264 	if (resultSeq == NULL)
   14265 	    return(-1);
   14266 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14267 	if (*resultSeq == NULL)
   14268 	    return(-1);
   14269     }
   14270 
   14271     /*
   14272      * handle the special cases of "/" amd "." being matched
   14273      */
   14274     if (min_depth == 0) {
   14275 	if (from_root) {
   14276 	    /* Select "/" */
   14277 	    if (toBool)
   14278 		return(1);
   14279 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14280 		                     (xmlNodePtr) ctxt->doc);
   14281 	} else {
   14282 	    /* Select "self::node()" */
   14283 	    if (toBool)
   14284 		return(1);
   14285 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14286 	}
   14287     }
   14288     if (max_depth == 0) {
   14289 	return(0);
   14290     }
   14291 
   14292     if (from_root) {
   14293         cur = (xmlNodePtr)ctxt->doc;
   14294     } else if (ctxt->node != NULL) {
   14295         switch (ctxt->node->type) {
   14296             case XML_ELEMENT_NODE:
   14297             case XML_DOCUMENT_NODE:
   14298             case XML_DOCUMENT_FRAG_NODE:
   14299             case XML_HTML_DOCUMENT_NODE:
   14300 #ifdef LIBXML_DOCB_ENABLED
   14301             case XML_DOCB_DOCUMENT_NODE:
   14302 #endif
   14303 	        cur = ctxt->node;
   14304 		break;
   14305             case XML_ATTRIBUTE_NODE:
   14306             case XML_TEXT_NODE:
   14307             case XML_CDATA_SECTION_NODE:
   14308             case XML_ENTITY_REF_NODE:
   14309             case XML_ENTITY_NODE:
   14310             case XML_PI_NODE:
   14311             case XML_COMMENT_NODE:
   14312             case XML_NOTATION_NODE:
   14313             case XML_DTD_NODE:
   14314             case XML_DOCUMENT_TYPE_NODE:
   14315             case XML_ELEMENT_DECL:
   14316             case XML_ATTRIBUTE_DECL:
   14317             case XML_ENTITY_DECL:
   14318             case XML_NAMESPACE_DECL:
   14319             case XML_XINCLUDE_START:
   14320             case XML_XINCLUDE_END:
   14321 		break;
   14322 	}
   14323 	limit = cur;
   14324     }
   14325     if (cur == NULL) {
   14326         return(0);
   14327     }
   14328 
   14329     patstream = xmlPatternGetStreamCtxt(comp);
   14330     if (patstream == NULL) {
   14331 	/*
   14332 	* QUESTION TODO: Is this an error?
   14333 	*/
   14334 	return(0);
   14335     }
   14336 
   14337     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14338 
   14339     if (from_root) {
   14340 	ret = xmlStreamPush(patstream, NULL, NULL);
   14341 	if (ret < 0) {
   14342 	} else if (ret == 1) {
   14343 	    if (toBool)
   14344 		goto return_1;
   14345 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14346 	}
   14347     }
   14348     depth = 0;
   14349     goto scan_children;
   14350 next_node:
   14351     do {
   14352         nb_nodes++;
   14353 
   14354 	switch (cur->type) {
   14355 	    case XML_ELEMENT_NODE:
   14356 	    case XML_TEXT_NODE:
   14357 	    case XML_CDATA_SECTION_NODE:
   14358 	    case XML_COMMENT_NODE:
   14359 	    case XML_PI_NODE:
   14360 		if (cur->type == XML_ELEMENT_NODE) {
   14361 		    ret = xmlStreamPush(patstream, cur->name,
   14362 				(cur->ns ? cur->ns->href : NULL));
   14363 		} else if (eval_all_nodes)
   14364 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14365 		else
   14366 		    break;
   14367 
   14368 		if (ret < 0) {
   14369 		    /* NOP. */
   14370 		} else if (ret == 1) {
   14371 		    if (toBool)
   14372 			goto return_1;
   14373 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
   14374 		        < 0) {
   14375 			ctxt->lastError.domain = XML_FROM_XPATH;
   14376 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
   14377 		    }
   14378 		}
   14379 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14380 		    ret = xmlStreamPop(patstream);
   14381 		    while (cur->next != NULL) {
   14382 			cur = cur->next;
   14383 			if ((cur->type != XML_ENTITY_DECL) &&
   14384 			    (cur->type != XML_DTD_NODE))
   14385 			    goto next_node;
   14386 		    }
   14387 		}
   14388 	    default:
   14389 		break;
   14390 	}
   14391 
   14392 scan_children:
   14393 	if (cur->type == XML_NAMESPACE_DECL) break;
   14394 	if ((cur->children != NULL) && (depth < max_depth)) {
   14395 	    /*
   14396 	     * Do not descend on entities declarations
   14397 	     */
   14398 	    if (cur->children->type != XML_ENTITY_DECL) {
   14399 		cur = cur->children;
   14400 		depth++;
   14401 		/*
   14402 		 * Skip DTDs
   14403 		 */
   14404 		if (cur->type != XML_DTD_NODE)
   14405 		    continue;
   14406 	    }
   14407 	}
   14408 
   14409 	if (cur == limit)
   14410 	    break;
   14411 
   14412 	while (cur->next != NULL) {
   14413 	    cur = cur->next;
   14414 	    if ((cur->type != XML_ENTITY_DECL) &&
   14415 		(cur->type != XML_DTD_NODE))
   14416 		goto next_node;
   14417 	}
   14418 
   14419 	do {
   14420 	    cur = cur->parent;
   14421 	    depth--;
   14422 	    if ((cur == NULL) || (cur == limit))
   14423 	        goto done;
   14424 	    if (cur->type == XML_ELEMENT_NODE) {
   14425 		ret = xmlStreamPop(patstream);
   14426 	    } else if ((eval_all_nodes) &&
   14427 		((cur->type == XML_TEXT_NODE) ||
   14428 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14429 		 (cur->type == XML_COMMENT_NODE) ||
   14430 		 (cur->type == XML_PI_NODE)))
   14431 	    {
   14432 		ret = xmlStreamPop(patstream);
   14433 	    }
   14434 	    if (cur->next != NULL) {
   14435 		cur = cur->next;
   14436 		break;
   14437 	    }
   14438 	} while (cur != NULL);
   14439 
   14440     } while ((cur != NULL) && (depth >= 0));
   14441 
   14442 done:
   14443 
   14444 #if 0
   14445     printf("stream eval: checked %d nodes selected %d\n",
   14446            nb_nodes, retObj->nodesetval->nodeNr);
   14447 #endif
   14448 
   14449     if (patstream)
   14450 	xmlFreeStreamCtxt(patstream);
   14451     return(0);
   14452 
   14453 return_1:
   14454     if (patstream)
   14455 	xmlFreeStreamCtxt(patstream);
   14456     return(1);
   14457 }
   14458 #endif /* XPATH_STREAMING */
   14459 
   14460 /**
   14461  * xmlXPathRunEval:
   14462  * @ctxt:  the XPath parser context with the compiled expression
   14463  * @toBool:  evaluate to a boolean result
   14464  *
   14465  * Evaluate the Precompiled XPath expression in the given context.
   14466  */
   14467 static int
   14468 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14469 {
   14470     xmlXPathCompExprPtr comp;
   14471 
   14472     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14473 	return(-1);
   14474 
   14475     if (ctxt->valueTab == NULL) {
   14476 	/* Allocate the value stack */
   14477 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14478 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14479 	if (ctxt->valueTab == NULL) {
   14480 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14481 	    xmlFree(ctxt);
   14482 	}
   14483 	ctxt->valueNr = 0;
   14484 	ctxt->valueMax = 10;
   14485 	ctxt->value = NULL;
   14486         ctxt->valueFrame = 0;
   14487     }
   14488 #ifdef XPATH_STREAMING
   14489     if (ctxt->comp->stream) {
   14490 	int res;
   14491 
   14492 	if (toBool) {
   14493 	    /*
   14494 	    * Evaluation to boolean result.
   14495 	    */
   14496 	    res = xmlXPathRunStreamEval(ctxt->context,
   14497 		ctxt->comp->stream, NULL, 1);
   14498 	    if (res != -1)
   14499 		return(res);
   14500 	} else {
   14501 	    xmlXPathObjectPtr resObj = NULL;
   14502 
   14503 	    /*
   14504 	    * Evaluation to a sequence.
   14505 	    */
   14506 	    res = xmlXPathRunStreamEval(ctxt->context,
   14507 		ctxt->comp->stream, &resObj, 0);
   14508 
   14509 	    if ((res != -1) && (resObj != NULL)) {
   14510 		valuePush(ctxt, resObj);
   14511 		return(0);
   14512 	    }
   14513 	    if (resObj != NULL)
   14514 		xmlXPathReleaseObject(ctxt->context, resObj);
   14515 	}
   14516 	/*
   14517 	* QUESTION TODO: This falls back to normal XPath evaluation
   14518 	* if res == -1. Is this intended?
   14519 	*/
   14520     }
   14521 #endif
   14522     comp = ctxt->comp;
   14523     if (comp->last < 0) {
   14524 	xmlGenericError(xmlGenericErrorContext,
   14525 	    "xmlXPathRunEval: last is less than zero\n");
   14526 	return(-1);
   14527     }
   14528     if (toBool)
   14529 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14530 	    &comp->steps[comp->last], 0));
   14531     else
   14532 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14533 
   14534     return(0);
   14535 }
   14536 
   14537 /************************************************************************
   14538  *									*
   14539  *			Public interfaces				*
   14540  *									*
   14541  ************************************************************************/
   14542 
   14543 /**
   14544  * xmlXPathEvalPredicate:
   14545  * @ctxt:  the XPath context
   14546  * @res:  the Predicate Expression evaluation result
   14547  *
   14548  * Evaluate a predicate result for the current node.
   14549  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14550  * the result to a boolean. If the result is a number, the result will
   14551  * be converted to true if the number is equal to the position of the
   14552  * context node in the context node list (as returned by the position
   14553  * function) and will be converted to false otherwise; if the result
   14554  * is not a number, then the result will be converted as if by a call
   14555  * to the boolean function.
   14556  *
   14557  * Returns 1 if predicate is true, 0 otherwise
   14558  */
   14559 int
   14560 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14561     if ((ctxt == NULL) || (res == NULL)) return(0);
   14562     switch (res->type) {
   14563         case XPATH_BOOLEAN:
   14564 	    return(res->boolval);
   14565         case XPATH_NUMBER:
   14566 	    return(res->floatval == ctxt->proximityPosition);
   14567         case XPATH_NODESET:
   14568         case XPATH_XSLT_TREE:
   14569 	    if (res->nodesetval == NULL)
   14570 		return(0);
   14571 	    return(res->nodesetval->nodeNr != 0);
   14572         case XPATH_STRING:
   14573 	    return((res->stringval != NULL) &&
   14574 	           (xmlStrlen(res->stringval) != 0));
   14575         default:
   14576 	    STRANGE
   14577     }
   14578     return(0);
   14579 }
   14580 
   14581 /**
   14582  * xmlXPathEvaluatePredicateResult:
   14583  * @ctxt:  the XPath Parser context
   14584  * @res:  the Predicate Expression evaluation result
   14585  *
   14586  * Evaluate a predicate result for the current node.
   14587  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14588  * the result to a boolean. If the result is a number, the result will
   14589  * be converted to true if the number is equal to the position of the
   14590  * context node in the context node list (as returned by the position
   14591  * function) and will be converted to false otherwise; if the result
   14592  * is not a number, then the result will be converted as if by a call
   14593  * to the boolean function.
   14594  *
   14595  * Returns 1 if predicate is true, 0 otherwise
   14596  */
   14597 int
   14598 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14599                                 xmlXPathObjectPtr res) {
   14600     if ((ctxt == NULL) || (res == NULL)) return(0);
   14601     switch (res->type) {
   14602         case XPATH_BOOLEAN:
   14603 	    return(res->boolval);
   14604         case XPATH_NUMBER:
   14605 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14606 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14607 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14608 #else
   14609 	    return(res->floatval == ctxt->context->proximityPosition);
   14610 #endif
   14611         case XPATH_NODESET:
   14612         case XPATH_XSLT_TREE:
   14613 	    if (res->nodesetval == NULL)
   14614 		return(0);
   14615 	    return(res->nodesetval->nodeNr != 0);
   14616         case XPATH_STRING:
   14617 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14618 #ifdef LIBXML_XPTR_ENABLED
   14619 	case XPATH_LOCATIONSET:{
   14620 	    xmlLocationSetPtr ptr = res->user;
   14621 	    if (ptr == NULL)
   14622 	        return(0);
   14623 	    return (ptr->locNr != 0);
   14624 	    }
   14625 #endif
   14626         default:
   14627 	    STRANGE
   14628     }
   14629     return(0);
   14630 }
   14631 
   14632 #ifdef XPATH_STREAMING
   14633 /**
   14634  * xmlXPathTryStreamCompile:
   14635  * @ctxt: an XPath context
   14636  * @str:  the XPath expression
   14637  *
   14638  * Try to compile the XPath expression as a streamable subset.
   14639  *
   14640  * Returns the compiled expression or NULL if failed to compile.
   14641  */
   14642 static xmlXPathCompExprPtr
   14643 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14644     /*
   14645      * Optimization: use streaming patterns when the XPath expression can
   14646      * be compiled to a stream lookup
   14647      */
   14648     xmlPatternPtr stream;
   14649     xmlXPathCompExprPtr comp;
   14650     xmlDictPtr dict = NULL;
   14651     const xmlChar **namespaces = NULL;
   14652     xmlNsPtr ns;
   14653     int i, j;
   14654 
   14655     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14656         (!xmlStrchr(str, '@'))) {
   14657 	const xmlChar *tmp;
   14658 
   14659 	/*
   14660 	 * We don't try to handle expressions using the verbose axis
   14661 	 * specifiers ("::"), just the simplied form at this point.
   14662 	 * Additionally, if there is no list of namespaces available and
   14663 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14664 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14665 	 *  to have a list of namespaces at compilation time in order to
   14666 	 *  compile prefixed name tests.
   14667 	 */
   14668 	tmp = xmlStrchr(str, ':');
   14669 	if ((tmp != NULL) &&
   14670 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14671 	    return(NULL);
   14672 
   14673 	if (ctxt != NULL) {
   14674 	    dict = ctxt->dict;
   14675 	    if (ctxt->nsNr > 0) {
   14676 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14677 		if (namespaces == NULL) {
   14678 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14679 		    return(NULL);
   14680 		}
   14681 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14682 		    ns = ctxt->namespaces[j];
   14683 		    namespaces[i++] = ns->href;
   14684 		    namespaces[i++] = ns->prefix;
   14685 		}
   14686 		namespaces[i++] = NULL;
   14687 		namespaces[i] = NULL;
   14688 	    }
   14689 	}
   14690 
   14691 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14692 			&namespaces[0]);
   14693 	if (namespaces != NULL) {
   14694 	    xmlFree((xmlChar **)namespaces);
   14695 	}
   14696 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14697 	    comp = xmlXPathNewCompExpr();
   14698 	    if (comp == NULL) {
   14699 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14700 		return(NULL);
   14701 	    }
   14702 	    comp->stream = stream;
   14703 	    comp->dict = dict;
   14704 	    if (comp->dict)
   14705 		xmlDictReference(comp->dict);
   14706 	    return(comp);
   14707 	}
   14708 	xmlFreePattern(stream);
   14709     }
   14710     return(NULL);
   14711 }
   14712 #endif /* XPATH_STREAMING */
   14713 
   14714 static void
   14715 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14716 {
   14717     /*
   14718     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14719     * internal representation.
   14720     */
   14721 
   14722     if ((op->ch1 != -1) &&
   14723         (op->op == XPATH_OP_COLLECT /* 11 */))
   14724     {
   14725         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14726 
   14727         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14728             ((xmlXPathAxisVal) prevop->value ==
   14729                 AXIS_DESCENDANT_OR_SELF) &&
   14730             (prevop->ch2 == -1) &&
   14731             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14732             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
   14733         {
   14734             /*
   14735             * This is a "descendant-or-self::node()" without predicates.
   14736             * Try to eliminate it.
   14737             */
   14738 
   14739             switch ((xmlXPathAxisVal) op->value) {
   14740                 case AXIS_CHILD:
   14741                 case AXIS_DESCENDANT:
   14742                     /*
   14743                     * Convert "descendant-or-self::node()/child::" or
   14744                     * "descendant-or-self::node()/descendant::" to
   14745                     * "descendant::"
   14746                     */
   14747                     op->ch1   = prevop->ch1;
   14748                     op->value = AXIS_DESCENDANT;
   14749                     break;
   14750                 case AXIS_SELF:
   14751                 case AXIS_DESCENDANT_OR_SELF:
   14752                     /*
   14753                     * Convert "descendant-or-self::node()/self::" or
   14754                     * "descendant-or-self::node()/descendant-or-self::" to
   14755                     * to "descendant-or-self::"
   14756                     */
   14757                     op->ch1   = prevop->ch1;
   14758                     op->value = AXIS_DESCENDANT_OR_SELF;
   14759                     break;
   14760                 default:
   14761                     break;
   14762             }
   14763 	}
   14764     }
   14765 
   14766     /* Recurse */
   14767     if (op->ch1 != -1)
   14768         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
   14769     if (op->ch2 != -1)
   14770 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
   14771 }
   14772 
   14773 /**
   14774  * xmlXPathCtxtCompile:
   14775  * @ctxt: an XPath context
   14776  * @str:  the XPath expression
   14777  *
   14778  * Compile an XPath expression
   14779  *
   14780  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14781  *         the caller has to free the object.
   14782  */
   14783 xmlXPathCompExprPtr
   14784 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14785     xmlXPathParserContextPtr pctxt;
   14786     xmlXPathCompExprPtr comp;
   14787 
   14788 #ifdef XPATH_STREAMING
   14789     comp = xmlXPathTryStreamCompile(ctxt, str);
   14790     if (comp != NULL)
   14791         return(comp);
   14792 #endif
   14793 
   14794     xmlXPathInit();
   14795 
   14796     pctxt = xmlXPathNewParserContext(str, ctxt);
   14797     if (pctxt == NULL)
   14798         return NULL;
   14799     xmlXPathCompileExpr(pctxt, 1);
   14800 
   14801     if( pctxt->error != XPATH_EXPRESSION_OK )
   14802     {
   14803         xmlXPathFreeParserContext(pctxt);
   14804         return(NULL);
   14805     }
   14806 
   14807     if (*pctxt->cur != 0) {
   14808 	/*
   14809 	 * aleksey: in some cases this line prints *second* error message
   14810 	 * (see bug #78858) and probably this should be fixed.
   14811 	 * However, we are not sure that all error messages are printed
   14812 	 * out in other places. It's not critical so we leave it as-is for now
   14813 	 */
   14814 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14815 	comp = NULL;
   14816     } else {
   14817 	comp = pctxt->comp;
   14818 	pctxt->comp = NULL;
   14819     }
   14820     xmlXPathFreeParserContext(pctxt);
   14821 
   14822     if (comp != NULL) {
   14823 	comp->expr = xmlStrdup(str);
   14824 #ifdef DEBUG_EVAL_COUNTS
   14825 	comp->string = xmlStrdup(str);
   14826 	comp->nb = 0;
   14827 #endif
   14828 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
   14829 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
   14830 	}
   14831     }
   14832     return(comp);
   14833 }
   14834 
   14835 /**
   14836  * xmlXPathCompile:
   14837  * @str:  the XPath expression
   14838  *
   14839  * Compile an XPath expression
   14840  *
   14841  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14842  *         the caller has to free the object.
   14843  */
   14844 xmlXPathCompExprPtr
   14845 xmlXPathCompile(const xmlChar *str) {
   14846     return(xmlXPathCtxtCompile(NULL, str));
   14847 }
   14848 
   14849 /**
   14850  * xmlXPathCompiledEvalInternal:
   14851  * @comp:  the compiled XPath expression
   14852  * @ctxt:  the XPath context
   14853  * @resObj: the resulting XPath object or NULL
   14854  * @toBool: 1 if only a boolean result is requested
   14855  *
   14856  * Evaluate the Precompiled XPath expression in the given context.
   14857  * The caller has to free @resObj.
   14858  *
   14859  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14860  *         the caller has to free the object.
   14861  */
   14862 static int
   14863 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14864 			     xmlXPathContextPtr ctxt,
   14865 			     xmlXPathObjectPtr *resObj,
   14866 			     int toBool)
   14867 {
   14868     xmlXPathParserContextPtr pctxt;
   14869 #ifndef LIBXML_THREAD_ENABLED
   14870     static int reentance = 0;
   14871 #endif
   14872     int res;
   14873 
   14874     CHECK_CTXT_NEG(ctxt)
   14875 
   14876     if (comp == NULL)
   14877 	return(-1);
   14878     xmlXPathInit();
   14879 
   14880 #ifndef LIBXML_THREAD_ENABLED
   14881     reentance++;
   14882     if (reentance > 1)
   14883 	xmlXPathDisableOptimizer = 1;
   14884 #endif
   14885 
   14886 #ifdef DEBUG_EVAL_COUNTS
   14887     comp->nb++;
   14888     if ((comp->string != NULL) && (comp->nb > 100)) {
   14889 	fprintf(stderr, "100 x %s\n", comp->string);
   14890 	comp->nb = 0;
   14891     }
   14892 #endif
   14893     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14894     res = xmlXPathRunEval(pctxt, toBool);
   14895 
   14896     if (resObj) {
   14897 	if (pctxt->value == NULL) {
   14898 	    xmlGenericError(xmlGenericErrorContext,
   14899 		"xmlXPathCompiledEval: evaluation failed\n");
   14900 	    *resObj = NULL;
   14901 	} else {
   14902 	    *resObj = valuePop(pctxt);
   14903 	}
   14904     }
   14905 
   14906     /*
   14907     * Pop all remaining objects from the stack.
   14908     */
   14909     if (pctxt->valueNr > 0) {
   14910 	xmlXPathObjectPtr tmp;
   14911 	int stack = 0;
   14912 
   14913 	do {
   14914 	    tmp = valuePop(pctxt);
   14915 	    if (tmp != NULL) {
   14916 		stack++;
   14917 		xmlXPathReleaseObject(ctxt, tmp);
   14918 	    }
   14919 	} while (tmp != NULL);
   14920 	if ((stack != 0) &&
   14921 	    ((toBool) || ((resObj) && (*resObj))))
   14922 	{
   14923 	    xmlGenericError(xmlGenericErrorContext,
   14924 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14925 		stack);
   14926 	}
   14927     }
   14928 
   14929     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14930 	xmlXPathFreeObject(*resObj);
   14931 	*resObj = NULL;
   14932     }
   14933     pctxt->comp = NULL;
   14934     xmlXPathFreeParserContext(pctxt);
   14935 #ifndef LIBXML_THREAD_ENABLED
   14936     reentance--;
   14937 #endif
   14938 
   14939     return(res);
   14940 }
   14941 
   14942 /**
   14943  * xmlXPathCompiledEval:
   14944  * @comp:  the compiled XPath expression
   14945  * @ctx:  the XPath context
   14946  *
   14947  * Evaluate the Precompiled XPath expression in the given context.
   14948  *
   14949  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14950  *         the caller has to free the object.
   14951  */
   14952 xmlXPathObjectPtr
   14953 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14954 {
   14955     xmlXPathObjectPtr res = NULL;
   14956 
   14957     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14958     return(res);
   14959 }
   14960 
   14961 /**
   14962  * xmlXPathCompiledEvalToBoolean:
   14963  * @comp:  the compiled XPath expression
   14964  * @ctxt:  the XPath context
   14965  *
   14966  * Applies the XPath boolean() function on the result of the given
   14967  * compiled expression.
   14968  *
   14969  * Returns 1 if the expression evaluated to true, 0 if to false and
   14970  *         -1 in API and internal errors.
   14971  */
   14972 int
   14973 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14974 			      xmlXPathContextPtr ctxt)
   14975 {
   14976     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14977 }
   14978 
   14979 /**
   14980  * xmlXPathEvalExpr:
   14981  * @ctxt:  the XPath Parser context
   14982  *
   14983  * Parse and evaluate an XPath expression in the given context,
   14984  * then push the result on the context stack
   14985  */
   14986 void
   14987 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14988 #ifdef XPATH_STREAMING
   14989     xmlXPathCompExprPtr comp;
   14990 #endif
   14991 
   14992     if (ctxt == NULL) return;
   14993 
   14994 #ifdef XPATH_STREAMING
   14995     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14996     if (comp != NULL) {
   14997         if (ctxt->comp != NULL)
   14998 	    xmlXPathFreeCompExpr(ctxt->comp);
   14999         ctxt->comp = comp;
   15000 	if (ctxt->cur != NULL)
   15001 	    while (*ctxt->cur != 0) ctxt->cur++;
   15002     } else
   15003 #endif
   15004     {
   15005 	xmlXPathCompileExpr(ctxt, 1);
   15006 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   15007 	    (ctxt->comp != NULL) &&
   15008 	    (ctxt->comp->nbStep > 1) &&
   15009 	    (ctxt->comp->last >= 0))
   15010 	{
   15011 	    xmlXPathOptimizeExpression(ctxt->comp,
   15012 		&ctxt->comp->steps[ctxt->comp->last]);
   15013 	}
   15014     }
   15015     CHECK_ERROR;
   15016     xmlXPathRunEval(ctxt, 0);
   15017 }
   15018 
   15019 /**
   15020  * xmlXPathEval:
   15021  * @str:  the XPath expression
   15022  * @ctx:  the XPath context
   15023  *
   15024  * Evaluate the XPath Location Path in the given context.
   15025  *
   15026  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15027  *         the caller has to free the object.
   15028  */
   15029 xmlXPathObjectPtr
   15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   15031     xmlXPathParserContextPtr ctxt;
   15032     xmlXPathObjectPtr res, tmp, init = NULL;
   15033     int stack = 0;
   15034 
   15035     CHECK_CTXT(ctx)
   15036 
   15037     xmlXPathInit();
   15038 
   15039     ctxt = xmlXPathNewParserContext(str, ctx);
   15040     if (ctxt == NULL)
   15041         return NULL;
   15042     xmlXPathEvalExpr(ctxt);
   15043 
   15044     if (ctxt->value == NULL) {
   15045 	xmlGenericError(xmlGenericErrorContext,
   15046 		"xmlXPathEval: evaluation failed\n");
   15047 	res = NULL;
   15048     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   15049 #ifdef XPATH_STREAMING
   15050             && (ctxt->comp->stream == NULL)
   15051 #endif
   15052 	      ) {
   15053 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15054 	res = NULL;
   15055     } else {
   15056 	res = valuePop(ctxt);
   15057     }
   15058 
   15059     do {
   15060         tmp = valuePop(ctxt);
   15061 	if (tmp != NULL) {
   15062 	    if (tmp != init)
   15063 		stack++;
   15064 	    xmlXPathReleaseObject(ctx, tmp);
   15065         }
   15066     } while (tmp != NULL);
   15067     if ((stack != 0) && (res != NULL)) {
   15068 	xmlGenericError(xmlGenericErrorContext,
   15069 		"xmlXPathEval: %d object left on the stack\n",
   15070 	        stack);
   15071     }
   15072     if (ctxt->error != XPATH_EXPRESSION_OK) {
   15073 	xmlXPathFreeObject(res);
   15074 	res = NULL;
   15075     }
   15076 
   15077     xmlXPathFreeParserContext(ctxt);
   15078     return(res);
   15079 }
   15080 
   15081 /**
   15082  * xmlXPathSetContextNode:
   15083  * @node: the node to to use as the context node
   15084  * @ctx:  the XPath context
   15085  *
   15086  * Sets 'node' as the context node. The node must be in the same
   15087  * document as that associated with the context.
   15088  *
   15089  * Returns -1 in case of error or 0 if successful
   15090  */
   15091 int
   15092 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
   15093     if ((node == NULL) || (ctx == NULL))
   15094         return(-1);
   15095 
   15096     if (node->doc == ctx->doc) {
   15097         ctx->node = node;
   15098 	return(0);
   15099     }
   15100     return(-1);
   15101 }
   15102 
   15103 /**
   15104  * xmlXPathNodeEval:
   15105  * @node: the node to to use as the context node
   15106  * @str:  the XPath expression
   15107  * @ctx:  the XPath context
   15108  *
   15109  * Evaluate the XPath Location Path in the given context. The node 'node'
   15110  * is set as the context node. The context node is not restored.
   15111  *
   15112  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15113  *         the caller has to free the object.
   15114  */
   15115 xmlXPathObjectPtr
   15116 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
   15117     if (str == NULL)
   15118         return(NULL);
   15119     if (xmlXPathSetContextNode(node, ctx) < 0)
   15120         return(NULL);
   15121     return(xmlXPathEval(str, ctx));
   15122 }
   15123 
   15124 /**
   15125  * xmlXPathEvalExpression:
   15126  * @str:  the XPath expression
   15127  * @ctxt:  the XPath context
   15128  *
   15129  * Evaluate the XPath expression in the given context.
   15130  *
   15131  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15132  *         the caller has to free the object.
   15133  */
   15134 xmlXPathObjectPtr
   15135 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   15136     xmlXPathParserContextPtr pctxt;
   15137     xmlXPathObjectPtr res, tmp;
   15138     int stack = 0;
   15139 
   15140     CHECK_CTXT(ctxt)
   15141 
   15142     xmlXPathInit();
   15143 
   15144     pctxt = xmlXPathNewParserContext(str, ctxt);
   15145     if (pctxt == NULL)
   15146         return NULL;
   15147     xmlXPathEvalExpr(pctxt);
   15148 
   15149     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   15150 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15151 	res = NULL;
   15152     } else {
   15153 	res = valuePop(pctxt);
   15154     }
   15155     do {
   15156         tmp = valuePop(pctxt);
   15157 	if (tmp != NULL) {
   15158 	    xmlXPathReleaseObject(ctxt, tmp);
   15159 	    stack++;
   15160 	}
   15161     } while (tmp != NULL);
   15162     if ((stack != 0) && (res != NULL)) {
   15163 	xmlGenericError(xmlGenericErrorContext,
   15164 		"xmlXPathEvalExpression: %d object left on the stack\n",
   15165 	        stack);
   15166     }
   15167     xmlXPathFreeParserContext(pctxt);
   15168     return(res);
   15169 }
   15170 
   15171 /************************************************************************
   15172  *									*
   15173  *	Extra functions not pertaining to the XPath spec		*
   15174  *									*
   15175  ************************************************************************/
   15176 /**
   15177  * xmlXPathEscapeUriFunction:
   15178  * @ctxt:  the XPath Parser context
   15179  * @nargs:  the number of arguments
   15180  *
   15181  * Implement the escape-uri() XPath function
   15182  *    string escape-uri(string $str, bool $escape-reserved)
   15183  *
   15184  * This function applies the URI escaping rules defined in section 2 of [RFC
   15185  * 2396] to the string supplied as $uri-part, which typically represents all
   15186  * or part of a URI. The effect of the function is to replace any special
   15187  * character in the string by an escape sequence of the form %xx%yy...,
   15188  * where xxyy... is the hexadecimal representation of the octets used to
   15189  * represent the character in UTF-8.
   15190  *
   15191  * The set of characters that are escaped depends on the setting of the
   15192  * boolean argument $escape-reserved.
   15193  *
   15194  * If $escape-reserved is true, all characters are escaped other than lower
   15195  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   15196  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   15197  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   15198  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15199  * A-F).
   15200  *
   15201  * If $escape-reserved is false, the behavior differs in that characters
   15202  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15203  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15204  *
   15205  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15206  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15207  * compared using string comparison functions, this function must always use
   15208  * the upper-case letters A-F.
   15209  *
   15210  * Generally, $escape-reserved should be set to true when escaping a string
   15211  * that is to form a single part of a URI, and to false when escaping an
   15212  * entire URI or URI reference.
   15213  *
   15214  * In the case of non-ascii characters, the string is encoded according to
   15215  * utf-8 and then converted according to RFC 2396.
   15216  *
   15217  * Examples
   15218  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15219  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15220  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15221  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15222  *
   15223  */
   15224 static void
   15225 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15226     xmlXPathObjectPtr str;
   15227     int escape_reserved;
   15228     xmlBufPtr target;
   15229     xmlChar *cptr;
   15230     xmlChar escape[4];
   15231 
   15232     CHECK_ARITY(2);
   15233 
   15234     escape_reserved = xmlXPathPopBoolean(ctxt);
   15235 
   15236     CAST_TO_STRING;
   15237     str = valuePop(ctxt);
   15238 
   15239     target = xmlBufCreate();
   15240 
   15241     escape[0] = '%';
   15242     escape[3] = 0;
   15243 
   15244     if (target) {
   15245 	for (cptr = str->stringval; *cptr; cptr++) {
   15246 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15247 		(*cptr >= 'a' && *cptr <= 'z') ||
   15248 		(*cptr >= '0' && *cptr <= '9') ||
   15249 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15250 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15251 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15252 		(*cptr == '%' &&
   15253 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15254 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15255 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15256 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15257 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15258 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15259 		(!escape_reserved &&
   15260 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15261 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15262 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15263 		  *cptr == ','))) {
   15264 		xmlBufAdd(target, cptr, 1);
   15265 	    } else {
   15266 		if ((*cptr >> 4) < 10)
   15267 		    escape[1] = '0' + (*cptr >> 4);
   15268 		else
   15269 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15270 		if ((*cptr & 0xF) < 10)
   15271 		    escape[2] = '0' + (*cptr & 0xF);
   15272 		else
   15273 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15274 
   15275 		xmlBufAdd(target, &escape[0], 3);
   15276 	    }
   15277 	}
   15278     }
   15279     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15280 	xmlBufContent(target)));
   15281     xmlBufFree(target);
   15282     xmlXPathReleaseObject(ctxt->context, str);
   15283 }
   15284 
   15285 /**
   15286  * xmlXPathRegisterAllFunctions:
   15287  * @ctxt:  the XPath context
   15288  *
   15289  * Registers all default XPath functions in this context
   15290  */
   15291 void
   15292 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15293 {
   15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15295                          xmlXPathBooleanFunction);
   15296     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15297                          xmlXPathCeilingFunction);
   15298     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15299                          xmlXPathCountFunction);
   15300     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15301                          xmlXPathConcatFunction);
   15302     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15303                          xmlXPathContainsFunction);
   15304     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15305                          xmlXPathIdFunction);
   15306     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15307                          xmlXPathFalseFunction);
   15308     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15309                          xmlXPathFloorFunction);
   15310     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15311                          xmlXPathLastFunction);
   15312     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15313                          xmlXPathLangFunction);
   15314     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15315                          xmlXPathLocalNameFunction);
   15316     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15317                          xmlXPathNotFunction);
   15318     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15319                          xmlXPathNameFunction);
   15320     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15321                          xmlXPathNamespaceURIFunction);
   15322     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15323                          xmlXPathNormalizeFunction);
   15324     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15325                          xmlXPathNumberFunction);
   15326     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15327                          xmlXPathPositionFunction);
   15328     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15329                          xmlXPathRoundFunction);
   15330     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15331                          xmlXPathStringFunction);
   15332     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15333                          xmlXPathStringLengthFunction);
   15334     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15335                          xmlXPathStartsWithFunction);
   15336     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15337                          xmlXPathSubstringFunction);
   15338     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15339                          xmlXPathSubstringBeforeFunction);
   15340     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15341                          xmlXPathSubstringAfterFunction);
   15342     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15343                          xmlXPathSumFunction);
   15344     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15345                          xmlXPathTrueFunction);
   15346     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15347                          xmlXPathTranslateFunction);
   15348 
   15349     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15350 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15351                          xmlXPathEscapeUriFunction);
   15352 }
   15353 
   15354 #endif /* LIBXML_XPATH_ENABLED */
   15355 #define bottom_xpath
   15356 #include "elfgcchack.h"
   15357