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 #ifdef LIBXML_PATTERN_ENABLED
     59 #define XPATH_STREAMING
     60 #endif
     61 
     62 #define TODO								\
     63     xmlGenericError(xmlGenericErrorContext,				\
     64 	    "Unimplemented block at %s:%d\n",				\
     65             __FILE__, __LINE__);
     66 
     67 /*
     68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
     69 * If defined, this will use xmlXPathCmpNodesExt() instead of
     70 * xmlXPathCmpNodes(). The new function is optimized comparison of
     71 * non-element nodes; actually it will speed up comparison only if
     72 * xmlXPathOrderDocElems() was called in order to index the elements of
     73 * a tree in document order; Libxslt does such an indexing, thus it will
     74 * benefit from this optimization.
     75 */
     76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
     77 
     78 /*
     79 * XP_OPTIMIZED_FILTER_FIRST:
     80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
     81 * in a way, that it stop evaluation at the first node.
     82 */
     83 #define XP_OPTIMIZED_FILTER_FIRST
     84 
     85 /*
     86 * XP_DEBUG_OBJ_USAGE:
     87 * Internal flag to enable tracking of how much XPath objects have been
     88 * created.
     89 */
     90 /* #define XP_DEBUG_OBJ_USAGE */
     91 
     92 /*
     93  * TODO:
     94  * There are a few spots where some tests are done which depend upon ascii
     95  * data.  These should be enhanced for full UTF8 support (see particularly
     96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
     97  */
     98 
     99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
    100 
    101 /************************************************************************
    102  *									*
    103  *			Floating point stuff				*
    104  *									*
    105  ************************************************************************/
    106 
    107 #ifndef TRIO_REPLACE_STDIO
    108 #define TRIO_PUBLIC static
    109 #endif
    110 #include "trionan.c"
    111 
    112 /*
    113  * The lack of portability of this section of the libc is annoying !
    114  */
    115 double xmlXPathNAN = 0;
    116 double xmlXPathPINF = 1;
    117 double xmlXPathNINF = -1;
    118 static double xmlXPathNZERO = 0; /* not exported from headers */
    119 static int xmlXPathInitialized = 0;
    120 
    121 /**
    122  * xmlXPathInit:
    123  *
    124  * Initialize the XPath environment
    125  */
    126 void
    127 xmlXPathInit(void) {
    128     if (xmlXPathInitialized) return;
    129 
    130     xmlXPathPINF = trio_pinf();
    131     xmlXPathNINF = trio_ninf();
    132     xmlXPathNAN = trio_nan();
    133     xmlXPathNZERO = trio_nzero();
    134 
    135     xmlXPathInitialized = 1;
    136 }
    137 
    138 /**
    139  * xmlXPathIsNaN:
    140  * @val:  a double value
    141  *
    142  * Provides a portable isnan() function to detect whether a double
    143  * is a NotaNumber. Based on trio code
    144  * http://sourceforge.net/projects/ctrio/
    145  *
    146  * Returns 1 if the value is a NaN, 0 otherwise
    147  */
    148 int
    149 xmlXPathIsNaN(double val) {
    150     return(trio_isnan(val));
    151 }
    152 
    153 /**
    154  * xmlXPathIsInf:
    155  * @val:  a double value
    156  *
    157  * Provides a portable isinf() function to detect whether a double
    158  * is a +Infinite or -Infinite. Based on trio code
    159  * http://sourceforge.net/projects/ctrio/
    160  *
    161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
    162  */
    163 int
    164 xmlXPathIsInf(double val) {
    165     return(trio_isinf(val));
    166 }
    167 
    168 #endif /* SCHEMAS or XPATH */
    169 #ifdef LIBXML_XPATH_ENABLED
    170 /**
    171  * xmlXPathGetSign:
    172  * @val:  a double value
    173  *
    174  * Provides a portable function to detect the sign of a double
    175  * Modified from trio code
    176  * http://sourceforge.net/projects/ctrio/
    177  *
    178  * Returns 1 if the value is Negative, 0 if positive
    179  */
    180 static int
    181 xmlXPathGetSign(double val) {
    182     return(trio_signbit(val));
    183 }
    184 
    185 
    186 /*
    187  * TODO: when compatibility allows remove all "fake node libxslt" strings
    188  *       the test should just be name[0] = ' '
    189  */
    190 #ifdef DEBUG_XPATH_EXPRESSION
    191 #define DEBUG_STEP
    192 #define DEBUG_EXPR
    193 #define DEBUG_EVAL_COUNTS
    194 #endif
    195 
    196 static xmlNs xmlXPathXMLNamespaceStruct = {
    197     NULL,
    198     XML_NAMESPACE_DECL,
    199     XML_XML_NAMESPACE,
    200     BAD_CAST "xml",
    201     NULL,
    202     NULL
    203 };
    204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    205 #ifndef LIBXML_THREAD_ENABLED
    206 /*
    207  * Optimizer is disabled only when threaded apps are detected while
    208  * the library ain't compiled for thread safety.
    209  */
    210 static int xmlXPathDisableOptimizer = 0;
    211 #endif
    212 
    213 /************************************************************************
    214  *									*
    215  *			Error handling routines				*
    216  *									*
    217  ************************************************************************/
    218 
    219 /**
    220  * XP_ERRORNULL:
    221  * @X:  the error code
    222  *
    223  * Macro to raise an XPath error and return NULL.
    224  */
    225 #define XP_ERRORNULL(X)							\
    226     { xmlXPathErr(ctxt, X); return(NULL); }
    227 
    228 /*
    229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    230  */
    231 static const char *xmlXPathErrorMessages[] = {
    232     "Ok\n",
    233     "Number encoding\n",
    234     "Unfinished literal\n",
    235     "Start of literal\n",
    236     "Expected $ for variable reference\n",
    237     "Undefined variable\n",
    238     "Invalid predicate\n",
    239     "Invalid expression\n",
    240     "Missing closing curly brace\n",
    241     "Unregistered function\n",
    242     "Invalid operand\n",
    243     "Invalid type\n",
    244     "Invalid number of arguments\n",
    245     "Invalid context size\n",
    246     "Invalid context position\n",
    247     "Memory allocation error\n",
    248     "Syntax error\n",
    249     "Resource error\n",
    250     "Sub resource error\n",
    251     "Undefined namespace prefix\n",
    252     "Encoding error\n",
    253     "Char out of XML range\n",
    254     "Invalid or incomplete context\n",
    255     "Stack usage errror\n",
    256     "?? Unknown error ??\n"	/* Must be last in the list! */
    257 };
    258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    259 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    260 /**
    261  * xmlXPathErrMemory:
    262  * @ctxt:  an XPath context
    263  * @extra:  extra informations
    264  *
    265  * Handle a redefinition of attribute error
    266  */
    267 static void
    268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    269 {
    270     if (ctxt != NULL) {
    271         if (extra) {
    272             xmlChar buf[200];
    273 
    274             xmlStrPrintf(buf, 200,
    275                          BAD_CAST "Memory allocation failed : %s\n",
    276                          extra);
    277             ctxt->lastError.message = (char *) xmlStrdup(buf);
    278         } else {
    279             ctxt->lastError.message = (char *)
    280 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    281         }
    282         ctxt->lastError.domain = XML_FROM_XPATH;
    283         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    284 	if (ctxt->error != NULL)
    285 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    286     } else {
    287         if (extra)
    288             __xmlRaiseError(NULL, NULL, NULL,
    289                             NULL, NULL, XML_FROM_XPATH,
    290                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    291                             extra, NULL, NULL, 0, 0,
    292                             "Memory allocation failed : %s\n", extra);
    293         else
    294             __xmlRaiseError(NULL, NULL, NULL,
    295                             NULL, NULL, XML_FROM_XPATH,
    296                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    297                             NULL, NULL, NULL, 0, 0,
    298                             "Memory allocation failed\n");
    299     }
    300 }
    301 
    302 /**
    303  * xmlXPathPErrMemory:
    304  * @ctxt:  an XPath parser context
    305  * @extra:  extra informations
    306  *
    307  * Handle a redefinition of attribute error
    308  */
    309 static void
    310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    311 {
    312     if (ctxt == NULL)
    313 	xmlXPathErrMemory(NULL, extra);
    314     else {
    315 	ctxt->error = XPATH_MEMORY_ERROR;
    316 	xmlXPathErrMemory(ctxt->context, extra);
    317     }
    318 }
    319 
    320 /**
    321  * xmlXPathErr:
    322  * @ctxt:  a XPath parser context
    323  * @error:  the error code
    324  *
    325  * Handle an XPath error
    326  */
    327 void
    328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    329 {
    330     if ((error < 0) || (error > MAXERRNO))
    331 	error = MAXERRNO;
    332     if (ctxt == NULL) {
    333 	__xmlRaiseError(NULL, NULL, NULL,
    334 			NULL, NULL, XML_FROM_XPATH,
    335 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    336 			XML_ERR_ERROR, NULL, 0,
    337 			NULL, NULL, NULL, 0, 0,
    338 			"%s", xmlXPathErrorMessages[error]);
    339 	return;
    340     }
    341     ctxt->error = error;
    342     if (ctxt->context == NULL) {
    343 	__xmlRaiseError(NULL, NULL, NULL,
    344 			NULL, NULL, XML_FROM_XPATH,
    345 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    346 			XML_ERR_ERROR, NULL, 0,
    347 			(const char *) ctxt->base, NULL, NULL,
    348 			ctxt->cur - ctxt->base, 0,
    349 			"%s", xmlXPathErrorMessages[error]);
    350 	return;
    351     }
    352 
    353     /* cleanup current last error */
    354     xmlResetError(&ctxt->context->lastError);
    355 
    356     ctxt->context->lastError.domain = XML_FROM_XPATH;
    357     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    358                            XPATH_EXPRESSION_OK;
    359     ctxt->context->lastError.level = XML_ERR_ERROR;
    360     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    361     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    362     ctxt->context->lastError.node = ctxt->context->debugNode;
    363     if (ctxt->context->error != NULL) {
    364 	ctxt->context->error(ctxt->context->userData,
    365 	                     &ctxt->context->lastError);
    366     } else {
    367 	__xmlRaiseError(NULL, NULL, NULL,
    368 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    369 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    370 			XML_ERR_ERROR, NULL, 0,
    371 			(const char *) ctxt->base, NULL, NULL,
    372 			ctxt->cur - ctxt->base, 0,
    373 			"%s", xmlXPathErrorMessages[error]);
    374     }
    375 
    376 }
    377 
    378 /**
    379  * xmlXPatherror:
    380  * @ctxt:  the XPath Parser context
    381  * @file:  the file name
    382  * @line:  the line number
    383  * @no:  the error number
    384  *
    385  * Formats an error message.
    386  */
    387 void
    388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    389               int line ATTRIBUTE_UNUSED, int no) {
    390     xmlXPathErr(ctxt, no);
    391 }
    392 
    393 /************************************************************************
    394  *									*
    395  *			Utilities					*
    396  *									*
    397  ************************************************************************/
    398 
    399 /**
    400  * xsltPointerList:
    401  *
    402  * Pointer-list for various purposes.
    403  */
    404 typedef struct _xmlPointerList xmlPointerList;
    405 typedef xmlPointerList *xmlPointerListPtr;
    406 struct _xmlPointerList {
    407     void **items;
    408     int number;
    409     int size;
    410 };
    411 /*
    412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    413 * and here, we should make the functions public.
    414 */
    415 static int
    416 xmlPointerListAddSize(xmlPointerListPtr list,
    417 		       void *item,
    418 		       int initialSize)
    419 {
    420     if (list->items == NULL) {
    421 	if (initialSize <= 0)
    422 	    initialSize = 1;
    423 	list->items = (void **) xmlMalloc(
    424 	    initialSize * sizeof(void *));
    425 	if (list->items == NULL) {
    426 	    xmlXPathErrMemory(NULL,
    427 		"xmlPointerListCreate: allocating item\n");
    428 	    return(-1);
    429 	}
    430 	list->number = 0;
    431 	list->size = initialSize;
    432     } else if (list->size <= list->number) {
    433 	list->size *= 2;
    434 	list->items = (void **) xmlRealloc(list->items,
    435 	    list->size * sizeof(void *));
    436 	if (list->items == NULL) {
    437 	    xmlXPathErrMemory(NULL,
    438 		"xmlPointerListCreate: re-allocating item\n");
    439 	    list->size = 0;
    440 	    return(-1);
    441 	}
    442     }
    443     list->items[list->number++] = item;
    444     return(0);
    445 }
    446 
    447 /**
    448  * xsltPointerListCreate:
    449  *
    450  * Creates an xsltPointerList structure.
    451  *
    452  * Returns a xsltPointerList structure or NULL in case of an error.
    453  */
    454 static xmlPointerListPtr
    455 xmlPointerListCreate(int initialSize)
    456 {
    457     xmlPointerListPtr ret;
    458 
    459     ret = xmlMalloc(sizeof(xmlPointerList));
    460     if (ret == NULL) {
    461 	xmlXPathErrMemory(NULL,
    462 	    "xmlPointerListCreate: allocating item\n");
    463 	return (NULL);
    464     }
    465     memset(ret, 0, sizeof(xmlPointerList));
    466     if (initialSize > 0) {
    467 	xmlPointerListAddSize(ret, NULL, initialSize);
    468 	ret->number = 0;
    469     }
    470     return (ret);
    471 }
    472 
    473 /**
    474  * xsltPointerListFree:
    475  *
    476  * Frees the xsltPointerList structure. This does not free
    477  * the content of the list.
    478  */
    479 static void
    480 xmlPointerListFree(xmlPointerListPtr list)
    481 {
    482     if (list == NULL)
    483 	return;
    484     if (list->items != NULL)
    485 	xmlFree(list->items);
    486     xmlFree(list);
    487 }
    488 
    489 /************************************************************************
    490  *									*
    491  *			Parser Types					*
    492  *									*
    493  ************************************************************************/
    494 
    495 /*
    496  * Types are private:
    497  */
    498 
    499 typedef enum {
    500     XPATH_OP_END=0,
    501     XPATH_OP_AND,
    502     XPATH_OP_OR,
    503     XPATH_OP_EQUAL,
    504     XPATH_OP_CMP,
    505     XPATH_OP_PLUS,
    506     XPATH_OP_MULT,
    507     XPATH_OP_UNION,
    508     XPATH_OP_ROOT,
    509     XPATH_OP_NODE,
    510     XPATH_OP_RESET, /* 10 */
    511     XPATH_OP_COLLECT,
    512     XPATH_OP_VALUE, /* 12 */
    513     XPATH_OP_VARIABLE,
    514     XPATH_OP_FUNCTION,
    515     XPATH_OP_ARG,
    516     XPATH_OP_PREDICATE,
    517     XPATH_OP_FILTER, /* 17 */
    518     XPATH_OP_SORT /* 18 */
    519 #ifdef LIBXML_XPTR_ENABLED
    520     ,XPATH_OP_RANGETO
    521 #endif
    522 } xmlXPathOp;
    523 
    524 typedef enum {
    525     AXIS_ANCESTOR = 1,
    526     AXIS_ANCESTOR_OR_SELF,
    527     AXIS_ATTRIBUTE,
    528     AXIS_CHILD,
    529     AXIS_DESCENDANT,
    530     AXIS_DESCENDANT_OR_SELF,
    531     AXIS_FOLLOWING,
    532     AXIS_FOLLOWING_SIBLING,
    533     AXIS_NAMESPACE,
    534     AXIS_PARENT,
    535     AXIS_PRECEDING,
    536     AXIS_PRECEDING_SIBLING,
    537     AXIS_SELF
    538 } xmlXPathAxisVal;
    539 
    540 typedef enum {
    541     NODE_TEST_NONE = 0,
    542     NODE_TEST_TYPE = 1,
    543     NODE_TEST_PI = 2,
    544     NODE_TEST_ALL = 3,
    545     NODE_TEST_NS = 4,
    546     NODE_TEST_NAME = 5
    547 } xmlXPathTestVal;
    548 
    549 typedef enum {
    550     NODE_TYPE_NODE = 0,
    551     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    552     NODE_TYPE_TEXT = XML_TEXT_NODE,
    553     NODE_TYPE_PI = XML_PI_NODE
    554 } xmlXPathTypeVal;
    555 
    556 #define XP_REWRITE_DOS_CHILD_ELEM 1
    557 
    558 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    559 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    560 struct _xmlXPathStepOp {
    561     xmlXPathOp op;		/* The identifier of the operation */
    562     int ch1;			/* First child */
    563     int ch2;			/* Second child */
    564     int value;
    565     int value2;
    566     int value3;
    567     void *value4;
    568     void *value5;
    569     void *cache;
    570     void *cacheURI;
    571     int rewriteType;
    572 };
    573 
    574 struct _xmlXPathCompExpr {
    575     int nbStep;			/* Number of steps in this expression */
    576     int maxStep;		/* Maximum number of steps allocated */
    577     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    578     int last;			/* index of last step in expression */
    579     xmlChar *expr;		/* the expression being computed */
    580     xmlDictPtr dict;		/* the dictionnary to use if any */
    581 #ifdef DEBUG_EVAL_COUNTS
    582     int nb;
    583     xmlChar *string;
    584 #endif
    585 #ifdef XPATH_STREAMING
    586     xmlPatternPtr stream;
    587 #endif
    588 };
    589 
    590 /************************************************************************
    591  *									*
    592  *			Forward declarations				*
    593  *									*
    594  ************************************************************************/
    595 static void
    596 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    597 static void
    598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    599 static int
    600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    601                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    602 static int
    603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    604 			    xmlXPathStepOpPtr op,
    605 			    int isPredicate);
    606 
    607 /************************************************************************
    608  *									*
    609  *			Parser Type functions				*
    610  *									*
    611  ************************************************************************/
    612 
    613 /**
    614  * xmlXPathNewCompExpr:
    615  *
    616  * Create a new Xpath component
    617  *
    618  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    619  */
    620 static xmlXPathCompExprPtr
    621 xmlXPathNewCompExpr(void) {
    622     xmlXPathCompExprPtr cur;
    623 
    624     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    625     if (cur == NULL) {
    626         xmlXPathErrMemory(NULL, "allocating component\n");
    627 	return(NULL);
    628     }
    629     memset(cur, 0, sizeof(xmlXPathCompExpr));
    630     cur->maxStep = 10;
    631     cur->nbStep = 0;
    632     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    633 	                                   sizeof(xmlXPathStepOp));
    634     if (cur->steps == NULL) {
    635         xmlXPathErrMemory(NULL, "allocating steps\n");
    636 	xmlFree(cur);
    637 	return(NULL);
    638     }
    639     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    640     cur->last = -1;
    641 #ifdef DEBUG_EVAL_COUNTS
    642     cur->nb = 0;
    643 #endif
    644     return(cur);
    645 }
    646 
    647 /**
    648  * xmlXPathFreeCompExpr:
    649  * @comp:  an XPATH comp
    650  *
    651  * Free up the memory allocated by @comp
    652  */
    653 void
    654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
    655 {
    656     xmlXPathStepOpPtr op;
    657     int i;
    658 
    659     if (comp == NULL)
    660         return;
    661     if (comp->dict == NULL) {
    662 	for (i = 0; i < comp->nbStep; i++) {
    663 	    op = &comp->steps[i];
    664 	    if (op->value4 != NULL) {
    665 		if (op->op == XPATH_OP_VALUE)
    666 		    xmlXPathFreeObject(op->value4);
    667 		else
    668 		    xmlFree(op->value4);
    669 	    }
    670 	    if (op->value5 != NULL)
    671 		xmlFree(op->value5);
    672 	}
    673     } else {
    674 	for (i = 0; i < comp->nbStep; i++) {
    675 	    op = &comp->steps[i];
    676 	    if (op->value4 != NULL) {
    677 		if (op->op == XPATH_OP_VALUE)
    678 		    xmlXPathFreeObject(op->value4);
    679 	    }
    680 	}
    681         xmlDictFree(comp->dict);
    682     }
    683     if (comp->steps != NULL) {
    684         xmlFree(comp->steps);
    685     }
    686 #ifdef DEBUG_EVAL_COUNTS
    687     if (comp->string != NULL) {
    688         xmlFree(comp->string);
    689     }
    690 #endif
    691 #ifdef XPATH_STREAMING
    692     if (comp->stream != NULL) {
    693         xmlFreePatternList(comp->stream);
    694     }
    695 #endif
    696     if (comp->expr != NULL) {
    697         xmlFree(comp->expr);
    698     }
    699 
    700     xmlFree(comp);
    701 }
    702 
    703 /**
    704  * xmlXPathCompExprAdd:
    705  * @comp:  the compiled expression
    706  * @ch1: first child index
    707  * @ch2: second child index
    708  * @op:  an op
    709  * @value:  the first int value
    710  * @value2:  the second int value
    711  * @value3:  the third int value
    712  * @value4:  the first string value
    713  * @value5:  the second string value
    714  *
    715  * Add a step to an XPath Compiled Expression
    716  *
    717  * Returns -1 in case of failure, the index otherwise
    718  */
    719 static int
    720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
    721    xmlXPathOp op, int value,
    722    int value2, int value3, void *value4, void *value5) {
    723     if (comp->nbStep >= comp->maxStep) {
    724 	xmlXPathStepOp *real;
    725 
    726 	comp->maxStep *= 2;
    727 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
    728 		                      comp->maxStep * sizeof(xmlXPathStepOp));
    729 	if (real == NULL) {
    730 	    comp->maxStep /= 2;
    731 	    xmlXPathErrMemory(NULL, "adding step\n");
    732 	    return(-1);
    733 	}
    734 	comp->steps = real;
    735     }
    736     comp->last = comp->nbStep;
    737     comp->steps[comp->nbStep].rewriteType = 0;
    738     comp->steps[comp->nbStep].ch1 = ch1;
    739     comp->steps[comp->nbStep].ch2 = ch2;
    740     comp->steps[comp->nbStep].op = op;
    741     comp->steps[comp->nbStep].value = value;
    742     comp->steps[comp->nbStep].value2 = value2;
    743     comp->steps[comp->nbStep].value3 = value3;
    744     if ((comp->dict != NULL) &&
    745         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
    746 	 (op == XPATH_OP_COLLECT))) {
    747         if (value4 != NULL) {
    748 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
    749 	        (void *)xmlDictLookup(comp->dict, value4, -1);
    750 	    xmlFree(value4);
    751 	} else
    752 	    comp->steps[comp->nbStep].value4 = NULL;
    753         if (value5 != NULL) {
    754 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
    755 	        (void *)xmlDictLookup(comp->dict, value5, -1);
    756 	    xmlFree(value5);
    757 	} else
    758 	    comp->steps[comp->nbStep].value5 = NULL;
    759     } else {
    760 	comp->steps[comp->nbStep].value4 = value4;
    761 	comp->steps[comp->nbStep].value5 = value5;
    762     }
    763     comp->steps[comp->nbStep].cache = NULL;
    764     return(comp->nbStep++);
    765 }
    766 
    767 /**
    768  * xmlXPathCompSwap:
    769  * @comp:  the compiled expression
    770  * @op: operation index
    771  *
    772  * Swaps 2 operations in the compiled expression
    773  */
    774 static void
    775 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
    776     int tmp;
    777 
    778 #ifndef LIBXML_THREAD_ENABLED
    779     /*
    780      * Since this manipulates possibly shared variables, this is
    781      * disabled if one detects that the library is used in a multithreaded
    782      * application
    783      */
    784     if (xmlXPathDisableOptimizer)
    785 	return;
    786 #endif
    787 
    788     tmp = op->ch1;
    789     op->ch1 = op->ch2;
    790     op->ch2 = tmp;
    791 }
    792 
    793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
    794     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
    795 	                (op), (val), (val2), (val3), (val4), (val5))
    796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
    797     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
    798 	                (op), (val), (val2), (val3), (val4), (val5))
    799 
    800 #define PUSH_LEAVE_EXPR(op, val, val2)					\
    801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
    802 
    803 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
    804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
    805 
    806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
    807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
    808 			(val), (val2), 0 ,NULL ,NULL)
    809 
    810 /************************************************************************
    811  *									*
    812  *		XPath object cache structures				*
    813  *									*
    814  ************************************************************************/
    815 
    816 /* #define XP_DEFAULT_CACHE_ON */
    817 
    818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
    819 
    820 typedef struct _xmlXPathContextCache xmlXPathContextCache;
    821 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
    822 struct _xmlXPathContextCache {
    823     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
    824     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
    825     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
    826     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
    827     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
    828     int maxNodeset;
    829     int maxString;
    830     int maxBoolean;
    831     int maxNumber;
    832     int maxMisc;
    833 #ifdef XP_DEBUG_OBJ_USAGE
    834     int dbgCachedAll;
    835     int dbgCachedNodeset;
    836     int dbgCachedString;
    837     int dbgCachedBool;
    838     int dbgCachedNumber;
    839     int dbgCachedPoint;
    840     int dbgCachedRange;
    841     int dbgCachedLocset;
    842     int dbgCachedUsers;
    843     int dbgCachedXSLTTree;
    844     int dbgCachedUndefined;
    845 
    846 
    847     int dbgReusedAll;
    848     int dbgReusedNodeset;
    849     int dbgReusedString;
    850     int dbgReusedBool;
    851     int dbgReusedNumber;
    852     int dbgReusedPoint;
    853     int dbgReusedRange;
    854     int dbgReusedLocset;
    855     int dbgReusedUsers;
    856     int dbgReusedXSLTTree;
    857     int dbgReusedUndefined;
    858 
    859 #endif
    860 };
    861 
    862 /************************************************************************
    863  *									*
    864  *		Debugging related functions				*
    865  *									*
    866  ************************************************************************/
    867 
    868 #define STRANGE							\
    869     xmlGenericError(xmlGenericErrorContext,				\
    870 	    "Internal error at %s:%d\n",				\
    871             __FILE__, __LINE__);
    872 
    873 #ifdef LIBXML_DEBUG_ENABLED
    874 static void
    875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
    876     int i;
    877     char shift[100];
    878 
    879     for (i = 0;((i < depth) && (i < 25));i++)
    880         shift[2 * i] = shift[2 * i + 1] = ' ';
    881     shift[2 * i] = shift[2 * i + 1] = 0;
    882     if (cur == NULL) {
    883 	fprintf(output, "%s", shift);
    884 	fprintf(output, "Node is NULL !\n");
    885 	return;
    886 
    887     }
    888 
    889     if ((cur->type == XML_DOCUMENT_NODE) ||
    890 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
    891 	fprintf(output, "%s", shift);
    892 	fprintf(output, " /\n");
    893     } else if (cur->type == XML_ATTRIBUTE_NODE)
    894 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
    895     else
    896 	xmlDebugDumpOneNode(output, cur, depth);
    897 }
    898 static void
    899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
    900     xmlNodePtr tmp;
    901     int i;
    902     char shift[100];
    903 
    904     for (i = 0;((i < depth) && (i < 25));i++)
    905         shift[2 * i] = shift[2 * i + 1] = ' ';
    906     shift[2 * i] = shift[2 * i + 1] = 0;
    907     if (cur == NULL) {
    908 	fprintf(output, "%s", shift);
    909 	fprintf(output, "Node is NULL !\n");
    910 	return;
    911 
    912     }
    913 
    914     while (cur != NULL) {
    915 	tmp = cur;
    916 	cur = cur->next;
    917 	xmlDebugDumpOneNode(output, tmp, depth);
    918     }
    919 }
    920 
    921 static void
    922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
    923     int i;
    924     char shift[100];
    925 
    926     for (i = 0;((i < depth) && (i < 25));i++)
    927         shift[2 * i] = shift[2 * i + 1] = ' ';
    928     shift[2 * i] = shift[2 * i + 1] = 0;
    929 
    930     if (cur == NULL) {
    931 	fprintf(output, "%s", shift);
    932 	fprintf(output, "NodeSet is NULL !\n");
    933 	return;
    934 
    935     }
    936 
    937     if (cur != NULL) {
    938 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
    939 	for (i = 0;i < cur->nodeNr;i++) {
    940 	    fprintf(output, "%s", shift);
    941 	    fprintf(output, "%d", i + 1);
    942 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
    943 	}
    944     }
    945 }
    946 
    947 static void
    948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
    949     int i;
    950     char shift[100];
    951 
    952     for (i = 0;((i < depth) && (i < 25));i++)
    953         shift[2 * i] = shift[2 * i + 1] = ' ';
    954     shift[2 * i] = shift[2 * i + 1] = 0;
    955 
    956     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
    957 	fprintf(output, "%s", shift);
    958 	fprintf(output, "Value Tree is NULL !\n");
    959 	return;
    960 
    961     }
    962 
    963     fprintf(output, "%s", shift);
    964     fprintf(output, "%d", i + 1);
    965     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
    966 }
    967 #if defined(LIBXML_XPTR_ENABLED)
    968 static void
    969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
    970     int i;
    971     char shift[100];
    972 
    973     for (i = 0;((i < depth) && (i < 25));i++)
    974         shift[2 * i] = shift[2 * i + 1] = ' ';
    975     shift[2 * i] = shift[2 * i + 1] = 0;
    976 
    977     if (cur == NULL) {
    978 	fprintf(output, "%s", shift);
    979 	fprintf(output, "LocationSet is NULL !\n");
    980 	return;
    981 
    982     }
    983 
    984     for (i = 0;i < cur->locNr;i++) {
    985 	fprintf(output, "%s", shift);
    986         fprintf(output, "%d : ", i + 1);
    987 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
    988     }
    989 }
    990 #endif /* LIBXML_XPTR_ENABLED */
    991 
    992 /**
    993  * xmlXPathDebugDumpObject:
    994  * @output:  the FILE * to dump the output
    995  * @cur:  the object to inspect
    996  * @depth:  indentation level
    997  *
    998  * Dump the content of the object for debugging purposes
    999  */
   1000 void
   1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1002     int i;
   1003     char shift[100];
   1004 
   1005     if (output == NULL) return;
   1006 
   1007     for (i = 0;((i < depth) && (i < 25));i++)
   1008         shift[2 * i] = shift[2 * i + 1] = ' ';
   1009     shift[2 * i] = shift[2 * i + 1] = 0;
   1010 
   1011 
   1012     fprintf(output, "%s", shift);
   1013 
   1014     if (cur == NULL) {
   1015         fprintf(output, "Object is empty (NULL)\n");
   1016 	return;
   1017     }
   1018     switch(cur->type) {
   1019         case XPATH_UNDEFINED:
   1020 	    fprintf(output, "Object is uninitialized\n");
   1021 	    break;
   1022         case XPATH_NODESET:
   1023 	    fprintf(output, "Object is a Node Set :\n");
   1024 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1025 	    break;
   1026 	case XPATH_XSLT_TREE:
   1027 	    fprintf(output, "Object is an XSLT value tree :\n");
   1028 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1029 	    break;
   1030         case XPATH_BOOLEAN:
   1031 	    fprintf(output, "Object is a Boolean : ");
   1032 	    if (cur->boolval) fprintf(output, "true\n");
   1033 	    else fprintf(output, "false\n");
   1034 	    break;
   1035         case XPATH_NUMBER:
   1036 	    switch (xmlXPathIsInf(cur->floatval)) {
   1037 	    case 1:
   1038 		fprintf(output, "Object is a number : Infinity\n");
   1039 		break;
   1040 	    case -1:
   1041 		fprintf(output, "Object is a number : -Infinity\n");
   1042 		break;
   1043 	    default:
   1044 		if (xmlXPathIsNaN(cur->floatval)) {
   1045 		    fprintf(output, "Object is a number : NaN\n");
   1046 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1047 		    fprintf(output, "Object is a number : 0\n");
   1048 		} else {
   1049 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1050 		}
   1051 	    }
   1052 	    break;
   1053         case XPATH_STRING:
   1054 	    fprintf(output, "Object is a string : ");
   1055 	    xmlDebugDumpString(output, cur->stringval);
   1056 	    fprintf(output, "\n");
   1057 	    break;
   1058 	case XPATH_POINT:
   1059 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1060 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1061 	    fprintf(output, "\n");
   1062 	    break;
   1063 	case XPATH_RANGE:
   1064 	    if ((cur->user2 == NULL) ||
   1065 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1066 		fprintf(output, "Object is a collapsed range :\n");
   1067 		fprintf(output, "%s", shift);
   1068 		if (cur->index >= 0)
   1069 		    fprintf(output, "index %d in ", cur->index);
   1070 		fprintf(output, "node\n");
   1071 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1072 			              depth + 1);
   1073 	    } else  {
   1074 		fprintf(output, "Object is a range :\n");
   1075 		fprintf(output, "%s", shift);
   1076 		fprintf(output, "From ");
   1077 		if (cur->index >= 0)
   1078 		    fprintf(output, "index %d in ", cur->index);
   1079 		fprintf(output, "node\n");
   1080 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1081 			              depth + 1);
   1082 		fprintf(output, "%s", shift);
   1083 		fprintf(output, "To ");
   1084 		if (cur->index2 >= 0)
   1085 		    fprintf(output, "index %d in ", cur->index2);
   1086 		fprintf(output, "node\n");
   1087 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1088 			              depth + 1);
   1089 		fprintf(output, "\n");
   1090 	    }
   1091 	    break;
   1092 	case XPATH_LOCATIONSET:
   1093 #if defined(LIBXML_XPTR_ENABLED)
   1094 	    fprintf(output, "Object is a Location Set:\n");
   1095 	    xmlXPathDebugDumpLocationSet(output,
   1096 		    (xmlLocationSetPtr) cur->user, depth);
   1097 #endif
   1098 	    break;
   1099 	case XPATH_USERS:
   1100 	    fprintf(output, "Object is user defined\n");
   1101 	    break;
   1102     }
   1103 }
   1104 
   1105 static void
   1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1107 	                     xmlXPathStepOpPtr op, int depth) {
   1108     int i;
   1109     char shift[100];
   1110 
   1111     for (i = 0;((i < depth) && (i < 25));i++)
   1112         shift[2 * i] = shift[2 * i + 1] = ' ';
   1113     shift[2 * i] = shift[2 * i + 1] = 0;
   1114 
   1115     fprintf(output, "%s", shift);
   1116     if (op == NULL) {
   1117 	fprintf(output, "Step is NULL\n");
   1118 	return;
   1119     }
   1120     switch (op->op) {
   1121         case XPATH_OP_END:
   1122 	    fprintf(output, "END"); break;
   1123         case XPATH_OP_AND:
   1124 	    fprintf(output, "AND"); break;
   1125         case XPATH_OP_OR:
   1126 	    fprintf(output, "OR"); break;
   1127         case XPATH_OP_EQUAL:
   1128 	     if (op->value)
   1129 		 fprintf(output, "EQUAL =");
   1130 	     else
   1131 		 fprintf(output, "EQUAL !=");
   1132 	     break;
   1133         case XPATH_OP_CMP:
   1134 	     if (op->value)
   1135 		 fprintf(output, "CMP <");
   1136 	     else
   1137 		 fprintf(output, "CMP >");
   1138 	     if (!op->value2)
   1139 		 fprintf(output, "=");
   1140 	     break;
   1141         case XPATH_OP_PLUS:
   1142 	     if (op->value == 0)
   1143 		 fprintf(output, "PLUS -");
   1144 	     else if (op->value == 1)
   1145 		 fprintf(output, "PLUS +");
   1146 	     else if (op->value == 2)
   1147 		 fprintf(output, "PLUS unary -");
   1148 	     else if (op->value == 3)
   1149 		 fprintf(output, "PLUS unary - -");
   1150 	     break;
   1151         case XPATH_OP_MULT:
   1152 	     if (op->value == 0)
   1153 		 fprintf(output, "MULT *");
   1154 	     else if (op->value == 1)
   1155 		 fprintf(output, "MULT div");
   1156 	     else
   1157 		 fprintf(output, "MULT mod");
   1158 	     break;
   1159         case XPATH_OP_UNION:
   1160 	     fprintf(output, "UNION"); break;
   1161         case XPATH_OP_ROOT:
   1162 	     fprintf(output, "ROOT"); break;
   1163         case XPATH_OP_NODE:
   1164 	     fprintf(output, "NODE"); break;
   1165         case XPATH_OP_RESET:
   1166 	     fprintf(output, "RESET"); break;
   1167         case XPATH_OP_SORT:
   1168 	     fprintf(output, "SORT"); break;
   1169         case XPATH_OP_COLLECT: {
   1170 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1171 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1172 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1173 	    const xmlChar *prefix = op->value4;
   1174 	    const xmlChar *name = op->value5;
   1175 
   1176 	    fprintf(output, "COLLECT ");
   1177 	    switch (axis) {
   1178 		case AXIS_ANCESTOR:
   1179 		    fprintf(output, " 'ancestors' "); break;
   1180 		case AXIS_ANCESTOR_OR_SELF:
   1181 		    fprintf(output, " 'ancestors-or-self' "); break;
   1182 		case AXIS_ATTRIBUTE:
   1183 		    fprintf(output, " 'attributes' "); break;
   1184 		case AXIS_CHILD:
   1185 		    fprintf(output, " 'child' "); break;
   1186 		case AXIS_DESCENDANT:
   1187 		    fprintf(output, " 'descendant' "); break;
   1188 		case AXIS_DESCENDANT_OR_SELF:
   1189 		    fprintf(output, " 'descendant-or-self' "); break;
   1190 		case AXIS_FOLLOWING:
   1191 		    fprintf(output, " 'following' "); break;
   1192 		case AXIS_FOLLOWING_SIBLING:
   1193 		    fprintf(output, " 'following-siblings' "); break;
   1194 		case AXIS_NAMESPACE:
   1195 		    fprintf(output, " 'namespace' "); break;
   1196 		case AXIS_PARENT:
   1197 		    fprintf(output, " 'parent' "); break;
   1198 		case AXIS_PRECEDING:
   1199 		    fprintf(output, " 'preceding' "); break;
   1200 		case AXIS_PRECEDING_SIBLING:
   1201 		    fprintf(output, " 'preceding-sibling' "); break;
   1202 		case AXIS_SELF:
   1203 		    fprintf(output, " 'self' "); break;
   1204 	    }
   1205 	    switch (test) {
   1206                 case NODE_TEST_NONE:
   1207 		    fprintf(output, "'none' "); break;
   1208                 case NODE_TEST_TYPE:
   1209 		    fprintf(output, "'type' "); break;
   1210                 case NODE_TEST_PI:
   1211 		    fprintf(output, "'PI' "); break;
   1212                 case NODE_TEST_ALL:
   1213 		    fprintf(output, "'all' "); break;
   1214                 case NODE_TEST_NS:
   1215 		    fprintf(output, "'namespace' "); break;
   1216                 case NODE_TEST_NAME:
   1217 		    fprintf(output, "'name' "); break;
   1218 	    }
   1219 	    switch (type) {
   1220                 case NODE_TYPE_NODE:
   1221 		    fprintf(output, "'node' "); break;
   1222                 case NODE_TYPE_COMMENT:
   1223 		    fprintf(output, "'comment' "); break;
   1224                 case NODE_TYPE_TEXT:
   1225 		    fprintf(output, "'text' "); break;
   1226                 case NODE_TYPE_PI:
   1227 		    fprintf(output, "'PI' "); break;
   1228 	    }
   1229 	    if (prefix != NULL)
   1230 		fprintf(output, "%s:", prefix);
   1231 	    if (name != NULL)
   1232 		fprintf(output, "%s", (const char *) name);
   1233 	    break;
   1234 
   1235         }
   1236 	case XPATH_OP_VALUE: {
   1237 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1238 
   1239 	    fprintf(output, "ELEM ");
   1240 	    xmlXPathDebugDumpObject(output, object, 0);
   1241 	    goto finish;
   1242 	}
   1243 	case XPATH_OP_VARIABLE: {
   1244 	    const xmlChar *prefix = op->value5;
   1245 	    const xmlChar *name = op->value4;
   1246 
   1247 	    if (prefix != NULL)
   1248 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1249 	    else
   1250 		fprintf(output, "VARIABLE %s", name);
   1251 	    break;
   1252 	}
   1253 	case XPATH_OP_FUNCTION: {
   1254 	    int nbargs = op->value;
   1255 	    const xmlChar *prefix = op->value5;
   1256 	    const xmlChar *name = op->value4;
   1257 
   1258 	    if (prefix != NULL)
   1259 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1260 			prefix, name, nbargs);
   1261 	    else
   1262 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1263 	    break;
   1264 	}
   1265         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1266         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1267         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1268 #ifdef LIBXML_XPTR_ENABLED
   1269         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1270 #endif
   1271 	default:
   1272         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1273     }
   1274     fprintf(output, "\n");
   1275 finish:
   1276     if (op->ch1 >= 0)
   1277 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1278     if (op->ch2 >= 0)
   1279 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1280 }
   1281 
   1282 /**
   1283  * xmlXPathDebugDumpCompExpr:
   1284  * @output:  the FILE * for the output
   1285  * @comp:  the precompiled XPath expression
   1286  * @depth:  the indentation level.
   1287  *
   1288  * Dumps the tree of the compiled XPath expression.
   1289  */
   1290 void
   1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1292 	                  int depth) {
   1293     int i;
   1294     char shift[100];
   1295 
   1296     if ((output == NULL) || (comp == NULL)) return;
   1297 
   1298     for (i = 0;((i < depth) && (i < 25));i++)
   1299         shift[2 * i] = shift[2 * i + 1] = ' ';
   1300     shift[2 * i] = shift[2 * i + 1] = 0;
   1301 
   1302     fprintf(output, "%s", shift);
   1303 
   1304     fprintf(output, "Compiled Expression : %d elements\n",
   1305 	    comp->nbStep);
   1306     i = comp->last;
   1307     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1308 }
   1309 
   1310 #ifdef XP_DEBUG_OBJ_USAGE
   1311 
   1312 /*
   1313 * XPath object usage related debugging variables.
   1314 */
   1315 static int xmlXPathDebugObjCounterUndefined = 0;
   1316 static int xmlXPathDebugObjCounterNodeset = 0;
   1317 static int xmlXPathDebugObjCounterBool = 0;
   1318 static int xmlXPathDebugObjCounterNumber = 0;
   1319 static int xmlXPathDebugObjCounterString = 0;
   1320 static int xmlXPathDebugObjCounterPoint = 0;
   1321 static int xmlXPathDebugObjCounterRange = 0;
   1322 static int xmlXPathDebugObjCounterLocset = 0;
   1323 static int xmlXPathDebugObjCounterUsers = 0;
   1324 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1325 static int xmlXPathDebugObjCounterAll = 0;
   1326 
   1327 static int xmlXPathDebugObjTotalUndefined = 0;
   1328 static int xmlXPathDebugObjTotalNodeset = 0;
   1329 static int xmlXPathDebugObjTotalBool = 0;
   1330 static int xmlXPathDebugObjTotalNumber = 0;
   1331 static int xmlXPathDebugObjTotalString = 0;
   1332 static int xmlXPathDebugObjTotalPoint = 0;
   1333 static int xmlXPathDebugObjTotalRange = 0;
   1334 static int xmlXPathDebugObjTotalLocset = 0;
   1335 static int xmlXPathDebugObjTotalUsers = 0;
   1336 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1337 static int xmlXPathDebugObjTotalAll = 0;
   1338 
   1339 static int xmlXPathDebugObjMaxUndefined = 0;
   1340 static int xmlXPathDebugObjMaxNodeset = 0;
   1341 static int xmlXPathDebugObjMaxBool = 0;
   1342 static int xmlXPathDebugObjMaxNumber = 0;
   1343 static int xmlXPathDebugObjMaxString = 0;
   1344 static int xmlXPathDebugObjMaxPoint = 0;
   1345 static int xmlXPathDebugObjMaxRange = 0;
   1346 static int xmlXPathDebugObjMaxLocset = 0;
   1347 static int xmlXPathDebugObjMaxUsers = 0;
   1348 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1349 static int xmlXPathDebugObjMaxAll = 0;
   1350 
   1351 /* REVISIT TODO: Make this static when committing */
   1352 static void
   1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1354 {
   1355     if (ctxt != NULL) {
   1356 	if (ctxt->cache != NULL) {
   1357 	    xmlXPathContextCachePtr cache =
   1358 		(xmlXPathContextCachePtr) ctxt->cache;
   1359 
   1360 	    cache->dbgCachedAll = 0;
   1361 	    cache->dbgCachedNodeset = 0;
   1362 	    cache->dbgCachedString = 0;
   1363 	    cache->dbgCachedBool = 0;
   1364 	    cache->dbgCachedNumber = 0;
   1365 	    cache->dbgCachedPoint = 0;
   1366 	    cache->dbgCachedRange = 0;
   1367 	    cache->dbgCachedLocset = 0;
   1368 	    cache->dbgCachedUsers = 0;
   1369 	    cache->dbgCachedXSLTTree = 0;
   1370 	    cache->dbgCachedUndefined = 0;
   1371 
   1372 	    cache->dbgReusedAll = 0;
   1373 	    cache->dbgReusedNodeset = 0;
   1374 	    cache->dbgReusedString = 0;
   1375 	    cache->dbgReusedBool = 0;
   1376 	    cache->dbgReusedNumber = 0;
   1377 	    cache->dbgReusedPoint = 0;
   1378 	    cache->dbgReusedRange = 0;
   1379 	    cache->dbgReusedLocset = 0;
   1380 	    cache->dbgReusedUsers = 0;
   1381 	    cache->dbgReusedXSLTTree = 0;
   1382 	    cache->dbgReusedUndefined = 0;
   1383 	}
   1384     }
   1385 
   1386     xmlXPathDebugObjCounterUndefined = 0;
   1387     xmlXPathDebugObjCounterNodeset = 0;
   1388     xmlXPathDebugObjCounterBool = 0;
   1389     xmlXPathDebugObjCounterNumber = 0;
   1390     xmlXPathDebugObjCounterString = 0;
   1391     xmlXPathDebugObjCounterPoint = 0;
   1392     xmlXPathDebugObjCounterRange = 0;
   1393     xmlXPathDebugObjCounterLocset = 0;
   1394     xmlXPathDebugObjCounterUsers = 0;
   1395     xmlXPathDebugObjCounterXSLTTree = 0;
   1396     xmlXPathDebugObjCounterAll = 0;
   1397 
   1398     xmlXPathDebugObjTotalUndefined = 0;
   1399     xmlXPathDebugObjTotalNodeset = 0;
   1400     xmlXPathDebugObjTotalBool = 0;
   1401     xmlXPathDebugObjTotalNumber = 0;
   1402     xmlXPathDebugObjTotalString = 0;
   1403     xmlXPathDebugObjTotalPoint = 0;
   1404     xmlXPathDebugObjTotalRange = 0;
   1405     xmlXPathDebugObjTotalLocset = 0;
   1406     xmlXPathDebugObjTotalUsers = 0;
   1407     xmlXPathDebugObjTotalXSLTTree = 0;
   1408     xmlXPathDebugObjTotalAll = 0;
   1409 
   1410     xmlXPathDebugObjMaxUndefined = 0;
   1411     xmlXPathDebugObjMaxNodeset = 0;
   1412     xmlXPathDebugObjMaxBool = 0;
   1413     xmlXPathDebugObjMaxNumber = 0;
   1414     xmlXPathDebugObjMaxString = 0;
   1415     xmlXPathDebugObjMaxPoint = 0;
   1416     xmlXPathDebugObjMaxRange = 0;
   1417     xmlXPathDebugObjMaxLocset = 0;
   1418     xmlXPathDebugObjMaxUsers = 0;
   1419     xmlXPathDebugObjMaxXSLTTree = 0;
   1420     xmlXPathDebugObjMaxAll = 0;
   1421 
   1422 }
   1423 
   1424 static void
   1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1426 			      xmlXPathObjectType objType)
   1427 {
   1428     int isCached = 0;
   1429 
   1430     if (ctxt != NULL) {
   1431 	if (ctxt->cache != NULL) {
   1432 	    xmlXPathContextCachePtr cache =
   1433 		(xmlXPathContextCachePtr) ctxt->cache;
   1434 
   1435 	    isCached = 1;
   1436 
   1437 	    cache->dbgReusedAll++;
   1438 	    switch (objType) {
   1439 		case XPATH_UNDEFINED:
   1440 		    cache->dbgReusedUndefined++;
   1441 		    break;
   1442 		case XPATH_NODESET:
   1443 		    cache->dbgReusedNodeset++;
   1444 		    break;
   1445 		case XPATH_BOOLEAN:
   1446 		    cache->dbgReusedBool++;
   1447 		    break;
   1448 		case XPATH_NUMBER:
   1449 		    cache->dbgReusedNumber++;
   1450 		    break;
   1451 		case XPATH_STRING:
   1452 		    cache->dbgReusedString++;
   1453 		    break;
   1454 		case XPATH_POINT:
   1455 		    cache->dbgReusedPoint++;
   1456 		    break;
   1457 		case XPATH_RANGE:
   1458 		    cache->dbgReusedRange++;
   1459 		    break;
   1460 		case XPATH_LOCATIONSET:
   1461 		    cache->dbgReusedLocset++;
   1462 		    break;
   1463 		case XPATH_USERS:
   1464 		    cache->dbgReusedUsers++;
   1465 		    break;
   1466 		case XPATH_XSLT_TREE:
   1467 		    cache->dbgReusedXSLTTree++;
   1468 		    break;
   1469 		default:
   1470 		    break;
   1471 	    }
   1472 	}
   1473     }
   1474 
   1475     switch (objType) {
   1476 	case XPATH_UNDEFINED:
   1477 	    if (! isCached)
   1478 		xmlXPathDebugObjTotalUndefined++;
   1479 	    xmlXPathDebugObjCounterUndefined++;
   1480 	    if (xmlXPathDebugObjCounterUndefined >
   1481 		xmlXPathDebugObjMaxUndefined)
   1482 		xmlXPathDebugObjMaxUndefined =
   1483 		    xmlXPathDebugObjCounterUndefined;
   1484 	    break;
   1485 	case XPATH_NODESET:
   1486 	    if (! isCached)
   1487 		xmlXPathDebugObjTotalNodeset++;
   1488 	    xmlXPathDebugObjCounterNodeset++;
   1489 	    if (xmlXPathDebugObjCounterNodeset >
   1490 		xmlXPathDebugObjMaxNodeset)
   1491 		xmlXPathDebugObjMaxNodeset =
   1492 		    xmlXPathDebugObjCounterNodeset;
   1493 	    break;
   1494 	case XPATH_BOOLEAN:
   1495 	    if (! isCached)
   1496 		xmlXPathDebugObjTotalBool++;
   1497 	    xmlXPathDebugObjCounterBool++;
   1498 	    if (xmlXPathDebugObjCounterBool >
   1499 		xmlXPathDebugObjMaxBool)
   1500 		xmlXPathDebugObjMaxBool =
   1501 		    xmlXPathDebugObjCounterBool;
   1502 	    break;
   1503 	case XPATH_NUMBER:
   1504 	    if (! isCached)
   1505 		xmlXPathDebugObjTotalNumber++;
   1506 	    xmlXPathDebugObjCounterNumber++;
   1507 	    if (xmlXPathDebugObjCounterNumber >
   1508 		xmlXPathDebugObjMaxNumber)
   1509 		xmlXPathDebugObjMaxNumber =
   1510 		    xmlXPathDebugObjCounterNumber;
   1511 	    break;
   1512 	case XPATH_STRING:
   1513 	    if (! isCached)
   1514 		xmlXPathDebugObjTotalString++;
   1515 	    xmlXPathDebugObjCounterString++;
   1516 	    if (xmlXPathDebugObjCounterString >
   1517 		xmlXPathDebugObjMaxString)
   1518 		xmlXPathDebugObjMaxString =
   1519 		    xmlXPathDebugObjCounterString;
   1520 	    break;
   1521 	case XPATH_POINT:
   1522 	    if (! isCached)
   1523 		xmlXPathDebugObjTotalPoint++;
   1524 	    xmlXPathDebugObjCounterPoint++;
   1525 	    if (xmlXPathDebugObjCounterPoint >
   1526 		xmlXPathDebugObjMaxPoint)
   1527 		xmlXPathDebugObjMaxPoint =
   1528 		    xmlXPathDebugObjCounterPoint;
   1529 	    break;
   1530 	case XPATH_RANGE:
   1531 	    if (! isCached)
   1532 		xmlXPathDebugObjTotalRange++;
   1533 	    xmlXPathDebugObjCounterRange++;
   1534 	    if (xmlXPathDebugObjCounterRange >
   1535 		xmlXPathDebugObjMaxRange)
   1536 		xmlXPathDebugObjMaxRange =
   1537 		    xmlXPathDebugObjCounterRange;
   1538 	    break;
   1539 	case XPATH_LOCATIONSET:
   1540 	    if (! isCached)
   1541 		xmlXPathDebugObjTotalLocset++;
   1542 	    xmlXPathDebugObjCounterLocset++;
   1543 	    if (xmlXPathDebugObjCounterLocset >
   1544 		xmlXPathDebugObjMaxLocset)
   1545 		xmlXPathDebugObjMaxLocset =
   1546 		    xmlXPathDebugObjCounterLocset;
   1547 	    break;
   1548 	case XPATH_USERS:
   1549 	    if (! isCached)
   1550 		xmlXPathDebugObjTotalUsers++;
   1551 	    xmlXPathDebugObjCounterUsers++;
   1552 	    if (xmlXPathDebugObjCounterUsers >
   1553 		xmlXPathDebugObjMaxUsers)
   1554 		xmlXPathDebugObjMaxUsers =
   1555 		    xmlXPathDebugObjCounterUsers;
   1556 	    break;
   1557 	case XPATH_XSLT_TREE:
   1558 	    if (! isCached)
   1559 		xmlXPathDebugObjTotalXSLTTree++;
   1560 	    xmlXPathDebugObjCounterXSLTTree++;
   1561 	    if (xmlXPathDebugObjCounterXSLTTree >
   1562 		xmlXPathDebugObjMaxXSLTTree)
   1563 		xmlXPathDebugObjMaxXSLTTree =
   1564 		    xmlXPathDebugObjCounterXSLTTree;
   1565 	    break;
   1566 	default:
   1567 	    break;
   1568     }
   1569     if (! isCached)
   1570 	xmlXPathDebugObjTotalAll++;
   1571     xmlXPathDebugObjCounterAll++;
   1572     if (xmlXPathDebugObjCounterAll >
   1573 	xmlXPathDebugObjMaxAll)
   1574 	xmlXPathDebugObjMaxAll =
   1575 	    xmlXPathDebugObjCounterAll;
   1576 }
   1577 
   1578 static void
   1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1580 			      xmlXPathObjectType objType)
   1581 {
   1582     int isCached = 0;
   1583 
   1584     if (ctxt != NULL) {
   1585 	if (ctxt->cache != NULL) {
   1586 	    xmlXPathContextCachePtr cache =
   1587 		(xmlXPathContextCachePtr) ctxt->cache;
   1588 
   1589 	    isCached = 1;
   1590 
   1591 	    cache->dbgCachedAll++;
   1592 	    switch (objType) {
   1593 		case XPATH_UNDEFINED:
   1594 		    cache->dbgCachedUndefined++;
   1595 		    break;
   1596 		case XPATH_NODESET:
   1597 		    cache->dbgCachedNodeset++;
   1598 		    break;
   1599 		case XPATH_BOOLEAN:
   1600 		    cache->dbgCachedBool++;
   1601 		    break;
   1602 		case XPATH_NUMBER:
   1603 		    cache->dbgCachedNumber++;
   1604 		    break;
   1605 		case XPATH_STRING:
   1606 		    cache->dbgCachedString++;
   1607 		    break;
   1608 		case XPATH_POINT:
   1609 		    cache->dbgCachedPoint++;
   1610 		    break;
   1611 		case XPATH_RANGE:
   1612 		    cache->dbgCachedRange++;
   1613 		    break;
   1614 		case XPATH_LOCATIONSET:
   1615 		    cache->dbgCachedLocset++;
   1616 		    break;
   1617 		case XPATH_USERS:
   1618 		    cache->dbgCachedUsers++;
   1619 		    break;
   1620 		case XPATH_XSLT_TREE:
   1621 		    cache->dbgCachedXSLTTree++;
   1622 		    break;
   1623 		default:
   1624 		    break;
   1625 	    }
   1626 
   1627 	}
   1628     }
   1629     switch (objType) {
   1630 	case XPATH_UNDEFINED:
   1631 	    xmlXPathDebugObjCounterUndefined--;
   1632 	    break;
   1633 	case XPATH_NODESET:
   1634 	    xmlXPathDebugObjCounterNodeset--;
   1635 	    break;
   1636 	case XPATH_BOOLEAN:
   1637 	    xmlXPathDebugObjCounterBool--;
   1638 	    break;
   1639 	case XPATH_NUMBER:
   1640 	    xmlXPathDebugObjCounterNumber--;
   1641 	    break;
   1642 	case XPATH_STRING:
   1643 	    xmlXPathDebugObjCounterString--;
   1644 	    break;
   1645 	case XPATH_POINT:
   1646 	    xmlXPathDebugObjCounterPoint--;
   1647 	    break;
   1648 	case XPATH_RANGE:
   1649 	    xmlXPathDebugObjCounterRange--;
   1650 	    break;
   1651 	case XPATH_LOCATIONSET:
   1652 	    xmlXPathDebugObjCounterLocset--;
   1653 	    break;
   1654 	case XPATH_USERS:
   1655 	    xmlXPathDebugObjCounterUsers--;
   1656 	    break;
   1657 	case XPATH_XSLT_TREE:
   1658 	    xmlXPathDebugObjCounterXSLTTree--;
   1659 	    break;
   1660 	default:
   1661 	    break;
   1662     }
   1663     xmlXPathDebugObjCounterAll--;
   1664 }
   1665 
   1666 /* REVISIT TODO: Make this static when committing */
   1667 static void
   1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   1669 {
   1670     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   1671 	reqXSLTTree, reqUndefined;
   1672     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   1673 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   1674     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   1675 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   1676     int leftObjs = xmlXPathDebugObjCounterAll;
   1677 
   1678     reqAll = xmlXPathDebugObjTotalAll;
   1679     reqNodeset = xmlXPathDebugObjTotalNodeset;
   1680     reqString = xmlXPathDebugObjTotalString;
   1681     reqBool = xmlXPathDebugObjTotalBool;
   1682     reqNumber = xmlXPathDebugObjTotalNumber;
   1683     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   1684     reqUndefined = xmlXPathDebugObjTotalUndefined;
   1685 
   1686     printf("# XPath object usage:\n");
   1687 
   1688     if (ctxt != NULL) {
   1689 	if (ctxt->cache != NULL) {
   1690 	    xmlXPathContextCachePtr cache =
   1691 		(xmlXPathContextCachePtr) ctxt->cache;
   1692 
   1693 	    reAll = cache->dbgReusedAll;
   1694 	    reqAll += reAll;
   1695 	    reNodeset = cache->dbgReusedNodeset;
   1696 	    reqNodeset += reNodeset;
   1697 	    reString = cache->dbgReusedString;
   1698 	    reqString += reString;
   1699 	    reBool = cache->dbgReusedBool;
   1700 	    reqBool += reBool;
   1701 	    reNumber = cache->dbgReusedNumber;
   1702 	    reqNumber += reNumber;
   1703 	    reXSLTTree = cache->dbgReusedXSLTTree;
   1704 	    reqXSLTTree += reXSLTTree;
   1705 	    reUndefined = cache->dbgReusedUndefined;
   1706 	    reqUndefined += reUndefined;
   1707 
   1708 	    caAll = cache->dbgCachedAll;
   1709 	    caBool = cache->dbgCachedBool;
   1710 	    caNodeset = cache->dbgCachedNodeset;
   1711 	    caString = cache->dbgCachedString;
   1712 	    caNumber = cache->dbgCachedNumber;
   1713 	    caXSLTTree = cache->dbgCachedXSLTTree;
   1714 	    caUndefined = cache->dbgCachedUndefined;
   1715 
   1716 	    if (cache->nodesetObjs)
   1717 		leftObjs -= cache->nodesetObjs->number;
   1718 	    if (cache->stringObjs)
   1719 		leftObjs -= cache->stringObjs->number;
   1720 	    if (cache->booleanObjs)
   1721 		leftObjs -= cache->booleanObjs->number;
   1722 	    if (cache->numberObjs)
   1723 		leftObjs -= cache->numberObjs->number;
   1724 	    if (cache->miscObjs)
   1725 		leftObjs -= cache->miscObjs->number;
   1726 	}
   1727     }
   1728 
   1729     printf("# all\n");
   1730     printf("#   total  : %d\n", reqAll);
   1731     printf("#   left  : %d\n", leftObjs);
   1732     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   1733     printf("#   reused : %d\n", reAll);
   1734     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   1735 
   1736     printf("# node-sets\n");
   1737     printf("#   total  : %d\n", reqNodeset);
   1738     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   1739     printf("#   reused : %d\n", reNodeset);
   1740     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   1741 
   1742     printf("# strings\n");
   1743     printf("#   total  : %d\n", reqString);
   1744     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   1745     printf("#   reused : %d\n", reString);
   1746     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   1747 
   1748     printf("# booleans\n");
   1749     printf("#   total  : %d\n", reqBool);
   1750     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   1751     printf("#   reused : %d\n", reBool);
   1752     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   1753 
   1754     printf("# numbers\n");
   1755     printf("#   total  : %d\n", reqNumber);
   1756     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   1757     printf("#   reused : %d\n", reNumber);
   1758     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   1759 
   1760     printf("# XSLT result tree fragments\n");
   1761     printf("#   total  : %d\n", reqXSLTTree);
   1762     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   1763     printf("#   reused : %d\n", reXSLTTree);
   1764     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   1765 
   1766     printf("# undefined\n");
   1767     printf("#   total  : %d\n", reqUndefined);
   1768     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   1769     printf("#   reused : %d\n", reUndefined);
   1770     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   1771 
   1772 }
   1773 
   1774 #endif /* XP_DEBUG_OBJ_USAGE */
   1775 
   1776 #endif /* LIBXML_DEBUG_ENABLED */
   1777 
   1778 /************************************************************************
   1779  *									*
   1780  *			XPath object caching				*
   1781  *									*
   1782  ************************************************************************/
   1783 
   1784 /**
   1785  * xmlXPathNewCache:
   1786  *
   1787  * Create a new object cache
   1788  *
   1789  * Returns the xmlXPathCache just allocated.
   1790  */
   1791 static xmlXPathContextCachePtr
   1792 xmlXPathNewCache(void)
   1793 {
   1794     xmlXPathContextCachePtr ret;
   1795 
   1796     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   1797     if (ret == NULL) {
   1798         xmlXPathErrMemory(NULL, "creating object cache\n");
   1799 	return(NULL);
   1800     }
   1801     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   1802     ret->maxNodeset = 100;
   1803     ret->maxString = 100;
   1804     ret->maxBoolean = 100;
   1805     ret->maxNumber = 100;
   1806     ret->maxMisc = 100;
   1807     return(ret);
   1808 }
   1809 
   1810 static void
   1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   1812 {
   1813     int i;
   1814     xmlXPathObjectPtr obj;
   1815 
   1816     if (list == NULL)
   1817 	return;
   1818 
   1819     for (i = 0; i < list->number; i++) {
   1820 	obj = list->items[i];
   1821 	/*
   1822 	* Note that it is already assured that we don't need to
   1823 	* look out for namespace nodes in the node-set.
   1824 	*/
   1825 	if (obj->nodesetval != NULL) {
   1826 	    if (obj->nodesetval->nodeTab != NULL)
   1827 		xmlFree(obj->nodesetval->nodeTab);
   1828 	    xmlFree(obj->nodesetval);
   1829 	}
   1830 	xmlFree(obj);
   1831 #ifdef XP_DEBUG_OBJ_USAGE
   1832 	xmlXPathDebugObjCounterAll--;
   1833 #endif
   1834     }
   1835     xmlPointerListFree(list);
   1836 }
   1837 
   1838 static void
   1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   1840 {
   1841     if (cache == NULL)
   1842 	return;
   1843     if (cache->nodesetObjs)
   1844 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   1845     if (cache->stringObjs)
   1846 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   1847     if (cache->booleanObjs)
   1848 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   1849     if (cache->numberObjs)
   1850 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   1851     if (cache->miscObjs)
   1852 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   1853     xmlFree(cache);
   1854 }
   1855 
   1856 /**
   1857  * xmlXPathContextSetCache:
   1858  *
   1859  * @ctxt:  the XPath context
   1860  * @active: enables/disables (creates/frees) the cache
   1861  * @value: a value with semantics dependant on @options
   1862  * @options: options (currently only the value 0 is used)
   1863  *
   1864  * Creates/frees an object cache on the XPath context.
   1865  * If activates XPath objects (xmlXPathObject) will be cached internally
   1866  * to be reused.
   1867  * @options:
   1868  *   0: This will set the XPath object caching:
   1869  *      @value:
   1870  *        This will set the maximum number of XPath objects
   1871  *        to be cached per slot
   1872  *        There are 5 slots for: node-set, string, number, boolean, and
   1873  *        misc objects. Use <0 for the default number (100).
   1874  *   Other values for @options have currently no effect.
   1875  *
   1876  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   1877  */
   1878 int
   1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   1880 			int active,
   1881 			int value,
   1882 			int options)
   1883 {
   1884     if (ctxt == NULL)
   1885 	return(-1);
   1886     if (active) {
   1887 	xmlXPathContextCachePtr cache;
   1888 
   1889 	if (ctxt->cache == NULL) {
   1890 	    ctxt->cache = xmlXPathNewCache();
   1891 	    if (ctxt->cache == NULL)
   1892 		return(-1);
   1893 	}
   1894 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   1895 	if (options == 0) {
   1896 	    if (value < 0)
   1897 		value = 100;
   1898 	    cache->maxNodeset = value;
   1899 	    cache->maxString = value;
   1900 	    cache->maxNumber = value;
   1901 	    cache->maxBoolean = value;
   1902 	    cache->maxMisc = value;
   1903 	}
   1904     } else if (ctxt->cache != NULL) {
   1905 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   1906 	ctxt->cache = NULL;
   1907     }
   1908     return(0);
   1909 }
   1910 
   1911 /**
   1912  * xmlXPathCacheWrapNodeSet:
   1913  * @ctxt: the XPath context
   1914  * @val:  the NodePtr value
   1915  *
   1916  * This is the cached version of xmlXPathWrapNodeSet().
   1917  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   1918  *
   1919  * Returns the created or reused object.
   1920  */
   1921 static xmlXPathObjectPtr
   1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   1923 {
   1924     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1925 	xmlXPathContextCachePtr cache =
   1926 	    (xmlXPathContextCachePtr) ctxt->cache;
   1927 
   1928 	if ((cache->miscObjs != NULL) &&
   1929 	    (cache->miscObjs->number != 0))
   1930 	{
   1931 	    xmlXPathObjectPtr ret;
   1932 
   1933 	    ret = (xmlXPathObjectPtr)
   1934 		cache->miscObjs->items[--cache->miscObjs->number];
   1935 	    ret->type = XPATH_NODESET;
   1936 	    ret->nodesetval = val;
   1937 #ifdef XP_DEBUG_OBJ_USAGE
   1938 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   1939 #endif
   1940 	    return(ret);
   1941 	}
   1942     }
   1943 
   1944     return(xmlXPathWrapNodeSet(val));
   1945 
   1946 }
   1947 
   1948 /**
   1949  * xmlXPathCacheWrapString:
   1950  * @ctxt: the XPath context
   1951  * @val:  the xmlChar * value
   1952  *
   1953  * This is the cached version of xmlXPathWrapString().
   1954  * Wraps the @val string into an XPath object.
   1955  *
   1956  * Returns the created or reused object.
   1957  */
   1958 static xmlXPathObjectPtr
   1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   1960 {
   1961     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1962 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   1963 
   1964 	if ((cache->stringObjs != NULL) &&
   1965 	    (cache->stringObjs->number != 0))
   1966 	{
   1967 
   1968 	    xmlXPathObjectPtr ret;
   1969 
   1970 	    ret = (xmlXPathObjectPtr)
   1971 		cache->stringObjs->items[--cache->stringObjs->number];
   1972 	    ret->type = XPATH_STRING;
   1973 	    ret->stringval = val;
   1974 #ifdef XP_DEBUG_OBJ_USAGE
   1975 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1976 #endif
   1977 	    return(ret);
   1978 	} else if ((cache->miscObjs != NULL) &&
   1979 	    (cache->miscObjs->number != 0))
   1980 	{
   1981 	    xmlXPathObjectPtr ret;
   1982 	    /*
   1983 	    * Fallback to misc-cache.
   1984 	    */
   1985 	    ret = (xmlXPathObjectPtr)
   1986 		cache->miscObjs->items[--cache->miscObjs->number];
   1987 
   1988 	    ret->type = XPATH_STRING;
   1989 	    ret->stringval = val;
   1990 #ifdef XP_DEBUG_OBJ_USAGE
   1991 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1992 #endif
   1993 	    return(ret);
   1994 	}
   1995     }
   1996     return(xmlXPathWrapString(val));
   1997 }
   1998 
   1999 /**
   2000  * xmlXPathCacheNewNodeSet:
   2001  * @ctxt: the XPath context
   2002  * @val:  the NodePtr value
   2003  *
   2004  * This is the cached version of xmlXPathNewNodeSet().
   2005  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2006  * it with the single Node @val
   2007  *
   2008  * Returns the created or reused object.
   2009  */
   2010 static xmlXPathObjectPtr
   2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2012 {
   2013     if ((ctxt != NULL) && (ctxt->cache)) {
   2014 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2015 
   2016 	if ((cache->nodesetObjs != NULL) &&
   2017 	    (cache->nodesetObjs->number != 0))
   2018 	{
   2019 	    xmlXPathObjectPtr ret;
   2020 	    /*
   2021 	    * Use the nodset-cache.
   2022 	    */
   2023 	    ret = (xmlXPathObjectPtr)
   2024 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2025 	    ret->type = XPATH_NODESET;
   2026 	    ret->boolval = 0;
   2027 	    if (val) {
   2028 		if ((ret->nodesetval->nodeMax == 0) ||
   2029 		    (val->type == XML_NAMESPACE_DECL))
   2030 		{
   2031 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2032 		} else {
   2033 		    ret->nodesetval->nodeTab[0] = val;
   2034 		    ret->nodesetval->nodeNr = 1;
   2035 		}
   2036 	    }
   2037 #ifdef XP_DEBUG_OBJ_USAGE
   2038 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2039 #endif
   2040 	    return(ret);
   2041 	} else if ((cache->miscObjs != NULL) &&
   2042 	    (cache->miscObjs->number != 0))
   2043 	{
   2044 	    xmlXPathObjectPtr ret;
   2045 	    /*
   2046 	    * Fallback to misc-cache.
   2047 	    */
   2048 
   2049 	    ret = (xmlXPathObjectPtr)
   2050 		cache->miscObjs->items[--cache->miscObjs->number];
   2051 
   2052 	    ret->type = XPATH_NODESET;
   2053 	    ret->boolval = 0;
   2054 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2055 #ifdef XP_DEBUG_OBJ_USAGE
   2056 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2057 #endif
   2058 	    return(ret);
   2059 	}
   2060     }
   2061     return(xmlXPathNewNodeSet(val));
   2062 }
   2063 
   2064 /**
   2065  * xmlXPathCacheNewCString:
   2066  * @ctxt: the XPath context
   2067  * @val:  the char * value
   2068  *
   2069  * This is the cached version of xmlXPathNewCString().
   2070  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2071  *
   2072  * Returns the created or reused object.
   2073  */
   2074 static xmlXPathObjectPtr
   2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2076 {
   2077     if ((ctxt != NULL) && (ctxt->cache)) {
   2078 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2079 
   2080 	if ((cache->stringObjs != NULL) &&
   2081 	    (cache->stringObjs->number != 0))
   2082 	{
   2083 	    xmlXPathObjectPtr ret;
   2084 
   2085 	    ret = (xmlXPathObjectPtr)
   2086 		cache->stringObjs->items[--cache->stringObjs->number];
   2087 
   2088 	    ret->type = XPATH_STRING;
   2089 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2090 #ifdef XP_DEBUG_OBJ_USAGE
   2091 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2092 #endif
   2093 	    return(ret);
   2094 	} else if ((cache->miscObjs != NULL) &&
   2095 	    (cache->miscObjs->number != 0))
   2096 	{
   2097 	    xmlXPathObjectPtr ret;
   2098 
   2099 	    ret = (xmlXPathObjectPtr)
   2100 		cache->miscObjs->items[--cache->miscObjs->number];
   2101 
   2102 	    ret->type = XPATH_STRING;
   2103 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2104 #ifdef XP_DEBUG_OBJ_USAGE
   2105 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2106 #endif
   2107 	    return(ret);
   2108 	}
   2109     }
   2110     return(xmlXPathNewCString(val));
   2111 }
   2112 
   2113 /**
   2114  * xmlXPathCacheNewString:
   2115  * @ctxt: the XPath context
   2116  * @val:  the xmlChar * value
   2117  *
   2118  * This is the cached version of xmlXPathNewString().
   2119  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2120  *
   2121  * Returns the created or reused object.
   2122  */
   2123 static xmlXPathObjectPtr
   2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2125 {
   2126     if ((ctxt != NULL) && (ctxt->cache)) {
   2127 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2128 
   2129 	if ((cache->stringObjs != NULL) &&
   2130 	    (cache->stringObjs->number != 0))
   2131 	{
   2132 	    xmlXPathObjectPtr ret;
   2133 
   2134 	    ret = (xmlXPathObjectPtr)
   2135 		cache->stringObjs->items[--cache->stringObjs->number];
   2136 	    ret->type = XPATH_STRING;
   2137 	    if (val != NULL)
   2138 		ret->stringval = xmlStrdup(val);
   2139 	    else
   2140 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2141 #ifdef XP_DEBUG_OBJ_USAGE
   2142 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2143 #endif
   2144 	    return(ret);
   2145 	} else if ((cache->miscObjs != NULL) &&
   2146 	    (cache->miscObjs->number != 0))
   2147 	{
   2148 	    xmlXPathObjectPtr ret;
   2149 
   2150 	    ret = (xmlXPathObjectPtr)
   2151 		cache->miscObjs->items[--cache->miscObjs->number];
   2152 
   2153 	    ret->type = XPATH_STRING;
   2154 	    if (val != NULL)
   2155 		ret->stringval = xmlStrdup(val);
   2156 	    else
   2157 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2158 #ifdef XP_DEBUG_OBJ_USAGE
   2159 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2160 #endif
   2161 	    return(ret);
   2162 	}
   2163     }
   2164     return(xmlXPathNewString(val));
   2165 }
   2166 
   2167 /**
   2168  * xmlXPathCacheNewBoolean:
   2169  * @ctxt: the XPath context
   2170  * @val:  the boolean value
   2171  *
   2172  * This is the cached version of xmlXPathNewBoolean().
   2173  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2174  *
   2175  * Returns the created or reused object.
   2176  */
   2177 static xmlXPathObjectPtr
   2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2179 {
   2180     if ((ctxt != NULL) && (ctxt->cache)) {
   2181 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2182 
   2183 	if ((cache->booleanObjs != NULL) &&
   2184 	    (cache->booleanObjs->number != 0))
   2185 	{
   2186 	    xmlXPathObjectPtr ret;
   2187 
   2188 	    ret = (xmlXPathObjectPtr)
   2189 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2190 	    ret->type = XPATH_BOOLEAN;
   2191 	    ret->boolval = (val != 0);
   2192 #ifdef XP_DEBUG_OBJ_USAGE
   2193 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2194 #endif
   2195 	    return(ret);
   2196 	} else if ((cache->miscObjs != NULL) &&
   2197 	    (cache->miscObjs->number != 0))
   2198 	{
   2199 	    xmlXPathObjectPtr ret;
   2200 
   2201 	    ret = (xmlXPathObjectPtr)
   2202 		cache->miscObjs->items[--cache->miscObjs->number];
   2203 
   2204 	    ret->type = XPATH_BOOLEAN;
   2205 	    ret->boolval = (val != 0);
   2206 #ifdef XP_DEBUG_OBJ_USAGE
   2207 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2208 #endif
   2209 	    return(ret);
   2210 	}
   2211     }
   2212     return(xmlXPathNewBoolean(val));
   2213 }
   2214 
   2215 /**
   2216  * xmlXPathCacheNewFloat:
   2217  * @ctxt: the XPath context
   2218  * @val:  the double value
   2219  *
   2220  * This is the cached version of xmlXPathNewFloat().
   2221  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2222  *
   2223  * Returns the created or reused object.
   2224  */
   2225 static xmlXPathObjectPtr
   2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2227 {
   2228      if ((ctxt != NULL) && (ctxt->cache)) {
   2229 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2230 
   2231 	if ((cache->numberObjs != NULL) &&
   2232 	    (cache->numberObjs->number != 0))
   2233 	{
   2234 	    xmlXPathObjectPtr ret;
   2235 
   2236 	    ret = (xmlXPathObjectPtr)
   2237 		cache->numberObjs->items[--cache->numberObjs->number];
   2238 	    ret->type = XPATH_NUMBER;
   2239 	    ret->floatval = val;
   2240 #ifdef XP_DEBUG_OBJ_USAGE
   2241 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2242 #endif
   2243 	    return(ret);
   2244 	} else if ((cache->miscObjs != NULL) &&
   2245 	    (cache->miscObjs->number != 0))
   2246 	{
   2247 	    xmlXPathObjectPtr ret;
   2248 
   2249 	    ret = (xmlXPathObjectPtr)
   2250 		cache->miscObjs->items[--cache->miscObjs->number];
   2251 
   2252 	    ret->type = XPATH_NUMBER;
   2253 	    ret->floatval = val;
   2254 #ifdef XP_DEBUG_OBJ_USAGE
   2255 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2256 #endif
   2257 	    return(ret);
   2258 	}
   2259     }
   2260     return(xmlXPathNewFloat(val));
   2261 }
   2262 
   2263 /**
   2264  * xmlXPathCacheConvertString:
   2265  * @ctxt: the XPath context
   2266  * @val:  an XPath object
   2267  *
   2268  * This is the cached version of xmlXPathConvertString().
   2269  * Converts an existing object to its string() equivalent
   2270  *
   2271  * Returns a created or reused object, the old one is freed (cached)
   2272  *         (or the operation is done directly on @val)
   2273  */
   2274 
   2275 static xmlXPathObjectPtr
   2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2277     xmlChar *res = NULL;
   2278 
   2279     if (val == NULL)
   2280 	return(xmlXPathCacheNewCString(ctxt, ""));
   2281 
   2282     switch (val->type) {
   2283     case XPATH_UNDEFINED:
   2284 #ifdef DEBUG_EXPR
   2285 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2286 #endif
   2287 	break;
   2288     case XPATH_NODESET:
   2289     case XPATH_XSLT_TREE:
   2290 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2291 	break;
   2292     case XPATH_STRING:
   2293 	return(val);
   2294     case XPATH_BOOLEAN:
   2295 	res = xmlXPathCastBooleanToString(val->boolval);
   2296 	break;
   2297     case XPATH_NUMBER:
   2298 	res = xmlXPathCastNumberToString(val->floatval);
   2299 	break;
   2300     case XPATH_USERS:
   2301     case XPATH_POINT:
   2302     case XPATH_RANGE:
   2303     case XPATH_LOCATIONSET:
   2304 	TODO;
   2305 	break;
   2306     }
   2307     xmlXPathReleaseObject(ctxt, val);
   2308     if (res == NULL)
   2309 	return(xmlXPathCacheNewCString(ctxt, ""));
   2310     return(xmlXPathCacheWrapString(ctxt, res));
   2311 }
   2312 
   2313 /**
   2314  * xmlXPathCacheObjectCopy:
   2315  * @ctxt: the XPath context
   2316  * @val:  the original object
   2317  *
   2318  * This is the cached version of xmlXPathObjectCopy().
   2319  * Acquire a copy of a given object
   2320  *
   2321  * Returns a created or reused created object.
   2322  */
   2323 static xmlXPathObjectPtr
   2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2325 {
   2326     if (val == NULL)
   2327 	return(NULL);
   2328 
   2329     if (XP_HAS_CACHE(ctxt)) {
   2330 	switch (val->type) {
   2331 	    case XPATH_NODESET:
   2332 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2333 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2334 	    case XPATH_STRING:
   2335 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2336 	    case XPATH_BOOLEAN:
   2337 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2338 	    case XPATH_NUMBER:
   2339 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2340 	    default:
   2341 		break;
   2342 	}
   2343     }
   2344     return(xmlXPathObjectCopy(val));
   2345 }
   2346 
   2347 /**
   2348  * xmlXPathCacheConvertBoolean:
   2349  * @ctxt: the XPath context
   2350  * @val:  an XPath object
   2351  *
   2352  * This is the cached version of xmlXPathConvertBoolean().
   2353  * Converts an existing object to its boolean() equivalent
   2354  *
   2355  * Returns a created or reused object, the old one is freed (or the operation
   2356  *         is done directly on @val)
   2357  */
   2358 static xmlXPathObjectPtr
   2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2360     xmlXPathObjectPtr ret;
   2361 
   2362     if (val == NULL)
   2363 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2364     if (val->type == XPATH_BOOLEAN)
   2365 	return(val);
   2366     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2367     xmlXPathReleaseObject(ctxt, val);
   2368     return(ret);
   2369 }
   2370 
   2371 /**
   2372  * xmlXPathCacheConvertNumber:
   2373  * @ctxt: the XPath context
   2374  * @val:  an XPath object
   2375  *
   2376  * This is the cached version of xmlXPathConvertNumber().
   2377  * Converts an existing object to its number() equivalent
   2378  *
   2379  * Returns a created or reused object, the old one is freed (or the operation
   2380  *         is done directly on @val)
   2381  */
   2382 static xmlXPathObjectPtr
   2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2384     xmlXPathObjectPtr ret;
   2385 
   2386     if (val == NULL)
   2387 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2388     if (val->type == XPATH_NUMBER)
   2389 	return(val);
   2390     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2391     xmlXPathReleaseObject(ctxt, val);
   2392     return(ret);
   2393 }
   2394 
   2395 /************************************************************************
   2396  *									*
   2397  *		Parser stacks related functions and macros		*
   2398  *									*
   2399  ************************************************************************/
   2400 
   2401 /**
   2402  * xmlXPathSetFrame:
   2403  * @ctxt: an XPath parser context
   2404  *
   2405  * Set the callee evaluation frame
   2406  *
   2407  * Returns the previous frame value to be restored once done
   2408  */
   2409 static int
   2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2411     int ret;
   2412 
   2413     if (ctxt == NULL)
   2414         return(0);
   2415     ret = ctxt->valueFrame;
   2416     ctxt->valueFrame = ctxt->valueNr;
   2417     return(ret);
   2418 }
   2419 
   2420 /**
   2421  * xmlXPathPopFrame:
   2422  * @ctxt: an XPath parser context
   2423  * @frame: the previous frame value
   2424  *
   2425  * Remove the callee evaluation frame
   2426  */
   2427 static void
   2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2429     if (ctxt == NULL)
   2430         return;
   2431     if (ctxt->valueNr < ctxt->valueFrame) {
   2432         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2433     }
   2434     ctxt->valueFrame = frame;
   2435 }
   2436 
   2437 /**
   2438  * valuePop:
   2439  * @ctxt: an XPath evaluation context
   2440  *
   2441  * Pops the top XPath object from the value stack
   2442  *
   2443  * Returns the XPath object just removed
   2444  */
   2445 xmlXPathObjectPtr
   2446 valuePop(xmlXPathParserContextPtr ctxt)
   2447 {
   2448     xmlXPathObjectPtr ret;
   2449 
   2450     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2451         return (NULL);
   2452 
   2453     if (ctxt->valueNr <= ctxt->valueFrame) {
   2454         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2455         return (NULL);
   2456     }
   2457 
   2458     ctxt->valueNr--;
   2459     if (ctxt->valueNr > 0)
   2460         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2461     else
   2462         ctxt->value = NULL;
   2463     ret = ctxt->valueTab[ctxt->valueNr];
   2464     ctxt->valueTab[ctxt->valueNr] = NULL;
   2465     return (ret);
   2466 }
   2467 /**
   2468  * valuePush:
   2469  * @ctxt:  an XPath evaluation context
   2470  * @value:  the XPath object
   2471  *
   2472  * Pushes a new XPath object on top of the value stack
   2473  *
   2474  * returns the number of items on the value stack
   2475  */
   2476 int
   2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2478 {
   2479     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2480     if (ctxt->valueNr >= ctxt->valueMax) {
   2481         xmlXPathObjectPtr *tmp;
   2482 
   2483         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2484                                              2 * ctxt->valueMax *
   2485                                              sizeof(ctxt->valueTab[0]));
   2486         if (tmp == NULL) {
   2487             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
   2488             ctxt->error = XPATH_MEMORY_ERROR;
   2489             return (0);
   2490         }
   2491         ctxt->valueMax *= 2;
   2492 	ctxt->valueTab = tmp;
   2493     }
   2494     ctxt->valueTab[ctxt->valueNr] = value;
   2495     ctxt->value = value;
   2496     return (ctxt->valueNr++);
   2497 }
   2498 
   2499 /**
   2500  * xmlXPathPopBoolean:
   2501  * @ctxt:  an XPath parser context
   2502  *
   2503  * Pops a boolean from the stack, handling conversion if needed.
   2504  * Check error with #xmlXPathCheckError.
   2505  *
   2506  * Returns the boolean
   2507  */
   2508 int
   2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2510     xmlXPathObjectPtr obj;
   2511     int ret;
   2512 
   2513     obj = valuePop(ctxt);
   2514     if (obj == NULL) {
   2515 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2516 	return(0);
   2517     }
   2518     if (obj->type != XPATH_BOOLEAN)
   2519 	ret = xmlXPathCastToBoolean(obj);
   2520     else
   2521         ret = obj->boolval;
   2522     xmlXPathReleaseObject(ctxt->context, obj);
   2523     return(ret);
   2524 }
   2525 
   2526 /**
   2527  * xmlXPathPopNumber:
   2528  * @ctxt:  an XPath parser context
   2529  *
   2530  * Pops a number from the stack, handling conversion if needed.
   2531  * Check error with #xmlXPathCheckError.
   2532  *
   2533  * Returns the number
   2534  */
   2535 double
   2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2537     xmlXPathObjectPtr obj;
   2538     double ret;
   2539 
   2540     obj = valuePop(ctxt);
   2541     if (obj == NULL) {
   2542 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2543 	return(0);
   2544     }
   2545     if (obj->type != XPATH_NUMBER)
   2546 	ret = xmlXPathCastToNumber(obj);
   2547     else
   2548         ret = obj->floatval;
   2549     xmlXPathReleaseObject(ctxt->context, obj);
   2550     return(ret);
   2551 }
   2552 
   2553 /**
   2554  * xmlXPathPopString:
   2555  * @ctxt:  an XPath parser context
   2556  *
   2557  * Pops a string from the stack, handling conversion if needed.
   2558  * Check error with #xmlXPathCheckError.
   2559  *
   2560  * Returns the string
   2561  */
   2562 xmlChar *
   2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2564     xmlXPathObjectPtr obj;
   2565     xmlChar * ret;
   2566 
   2567     obj = valuePop(ctxt);
   2568     if (obj == NULL) {
   2569 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2570 	return(NULL);
   2571     }
   2572     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2573     /* TODO: needs refactoring somewhere else */
   2574     if (obj->stringval == ret)
   2575 	obj->stringval = NULL;
   2576     xmlXPathReleaseObject(ctxt->context, obj);
   2577     return(ret);
   2578 }
   2579 
   2580 /**
   2581  * xmlXPathPopNodeSet:
   2582  * @ctxt:  an XPath parser context
   2583  *
   2584  * Pops a node-set from the stack, handling conversion if needed.
   2585  * Check error with #xmlXPathCheckError.
   2586  *
   2587  * Returns the node-set
   2588  */
   2589 xmlNodeSetPtr
   2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2591     xmlXPathObjectPtr obj;
   2592     xmlNodeSetPtr ret;
   2593 
   2594     if (ctxt == NULL) return(NULL);
   2595     if (ctxt->value == NULL) {
   2596 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2597 	return(NULL);
   2598     }
   2599     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2600 	xmlXPathSetTypeError(ctxt);
   2601 	return(NULL);
   2602     }
   2603     obj = valuePop(ctxt);
   2604     ret = obj->nodesetval;
   2605 #if 0
   2606     /* to fix memory leak of not clearing obj->user */
   2607     if (obj->boolval && obj->user != NULL)
   2608         xmlFreeNodeList((xmlNodePtr) obj->user);
   2609 #endif
   2610     obj->nodesetval = NULL;
   2611     xmlXPathReleaseObject(ctxt->context, obj);
   2612     return(ret);
   2613 }
   2614 
   2615 /**
   2616  * xmlXPathPopExternal:
   2617  * @ctxt:  an XPath parser context
   2618  *
   2619  * Pops an external object from the stack, handling conversion if needed.
   2620  * Check error with #xmlXPathCheckError.
   2621  *
   2622  * Returns the object
   2623  */
   2624 void *
   2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   2626     xmlXPathObjectPtr obj;
   2627     void * ret;
   2628 
   2629     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   2630 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2631 	return(NULL);
   2632     }
   2633     if (ctxt->value->type != XPATH_USERS) {
   2634 	xmlXPathSetTypeError(ctxt);
   2635 	return(NULL);
   2636     }
   2637     obj = valuePop(ctxt);
   2638     ret = obj->user;
   2639     obj->user = NULL;
   2640     xmlXPathReleaseObject(ctxt->context, obj);
   2641     return(ret);
   2642 }
   2643 
   2644 /*
   2645  * Macros for accessing the content. Those should be used only by the parser,
   2646  * and not exported.
   2647  *
   2648  * Dirty macros, i.e. one need to make assumption on the context to use them
   2649  *
   2650  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   2651  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   2652  *           in ISO-Latin or UTF-8.
   2653  *           This should be used internally by the parser
   2654  *           only to compare to ASCII values otherwise it would break when
   2655  *           running with UTF-8 encoding.
   2656  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   2657  *           to compare on ASCII based substring.
   2658  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   2659  *           strings within the parser.
   2660  *   CURRENT Returns the current char value, with the full decoding of
   2661  *           UTF-8 if we are using this mode. It returns an int.
   2662  *   NEXT    Skip to the next character, this does the proper decoding
   2663  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   2664  *           It returns the pointer to the current xmlChar.
   2665  */
   2666 
   2667 #define CUR (*ctxt->cur)
   2668 #define SKIP(val) ctxt->cur += (val)
   2669 #define NXT(val) ctxt->cur[(val)]
   2670 #define CUR_PTR ctxt->cur
   2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   2672 
   2673 #define COPY_BUF(l,b,i,v)                                              \
   2674     if (l == 1) b[i++] = (xmlChar) v;                                  \
   2675     else i += xmlCopyChar(l,&b[i],v)
   2676 
   2677 #define NEXTL(l)  ctxt->cur += l
   2678 
   2679 #define SKIP_BLANKS							\
   2680     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   2681 
   2682 #define CURRENT (*ctxt->cur)
   2683 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   2684 
   2685 
   2686 #ifndef DBL_DIG
   2687 #define DBL_DIG 16
   2688 #endif
   2689 #ifndef DBL_EPSILON
   2690 #define DBL_EPSILON 1E-9
   2691 #endif
   2692 
   2693 #define UPPER_DOUBLE 1E9
   2694 #define LOWER_DOUBLE 1E-5
   2695 #define	LOWER_DOUBLE_EXP 5
   2696 
   2697 #define INTEGER_DIGITS DBL_DIG
   2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   2699 #define EXPONENT_DIGITS (3 + 2)
   2700 
   2701 /**
   2702  * xmlXPathFormatNumber:
   2703  * @number:     number to format
   2704  * @buffer:     output buffer
   2705  * @buffersize: size of output buffer
   2706  *
   2707  * Convert the number into a string representation.
   2708  */
   2709 static void
   2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   2711 {
   2712     switch (xmlXPathIsInf(number)) {
   2713     case 1:
   2714 	if (buffersize > (int)sizeof("Infinity"))
   2715 	    snprintf(buffer, buffersize, "Infinity");
   2716 	break;
   2717     case -1:
   2718 	if (buffersize > (int)sizeof("-Infinity"))
   2719 	    snprintf(buffer, buffersize, "-Infinity");
   2720 	break;
   2721     default:
   2722 	if (xmlXPathIsNaN(number)) {
   2723 	    if (buffersize > (int)sizeof("NaN"))
   2724 		snprintf(buffer, buffersize, "NaN");
   2725 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   2726 	    snprintf(buffer, buffersize, "0");
   2727 	} else if (number == ((int) number)) {
   2728 	    char work[30];
   2729 	    char *ptr, *cur;
   2730 	    int value = (int) number;
   2731 
   2732             ptr = &buffer[0];
   2733 	    if (value == 0) {
   2734 		*ptr++ = '0';
   2735 	    } else {
   2736 		snprintf(work, 29, "%d", value);
   2737 		cur = &work[0];
   2738 		while ((*cur) && (ptr - buffer < buffersize)) {
   2739 		    *ptr++ = *cur++;
   2740 		}
   2741 	    }
   2742 	    if (ptr - buffer < buffersize) {
   2743 		*ptr = 0;
   2744 	    } else if (buffersize > 0) {
   2745 		ptr--;
   2746 		*ptr = 0;
   2747 	    }
   2748 	} else {
   2749 	    /*
   2750 	      For the dimension of work,
   2751 	          DBL_DIG is number of significant digits
   2752 		  EXPONENT is only needed for "scientific notation"
   2753 	          3 is sign, decimal point, and terminating zero
   2754 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   2755 	      Note that this dimension is slightly (a few characters)
   2756 	      larger than actually necessary.
   2757 	    */
   2758 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   2759 	    int integer_place, fraction_place;
   2760 	    char *ptr;
   2761 	    char *after_fraction;
   2762 	    double absolute_value;
   2763 	    int size;
   2764 
   2765 	    absolute_value = fabs(number);
   2766 
   2767 	    /*
   2768 	     * First choose format - scientific or regular floating point.
   2769 	     * In either case, result is in work, and after_fraction points
   2770 	     * just past the fractional part.
   2771 	    */
   2772 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   2773 		  (absolute_value < LOWER_DOUBLE)) &&
   2774 		 (absolute_value != 0.0) ) {
   2775 		/* Use scientific notation */
   2776 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   2777 		fraction_place = DBL_DIG - 1;
   2778 		size = snprintf(work, sizeof(work),"%*.*e",
   2779 			 integer_place, fraction_place, number);
   2780 		while ((size > 0) && (work[size] != 'e')) size--;
   2781 
   2782 	    }
   2783 	    else {
   2784 		/* Use regular notation */
   2785 		if (absolute_value > 0.0) {
   2786 		    integer_place = (int)log10(absolute_value);
   2787 		    if (integer_place > 0)
   2788 		        fraction_place = DBL_DIG - integer_place - 1;
   2789 		    else
   2790 		        fraction_place = DBL_DIG - integer_place;
   2791 		} else {
   2792 		    fraction_place = 1;
   2793 		}
   2794 		size = snprintf(work, sizeof(work), "%0.*f",
   2795 				fraction_place, number);
   2796 	    }
   2797 
   2798 	    /* Remove fractional trailing zeroes */
   2799 	    after_fraction = work + size;
   2800 	    ptr = after_fraction;
   2801 	    while (*(--ptr) == '0')
   2802 		;
   2803 	    if (*ptr != '.')
   2804 	        ptr++;
   2805 	    while ((*ptr++ = *after_fraction++) != 0);
   2806 
   2807 	    /* Finally copy result back to caller */
   2808 	    size = strlen(work) + 1;
   2809 	    if (size > buffersize && buffersize <= (int)sizeof(work)) {
   2810 		work[buffersize - 1] = 0;
   2811 		size = buffersize;
   2812 	    }
   2813 	    memmove(buffer, work, size);
   2814 	}
   2815 	break;
   2816     }
   2817 }
   2818 
   2819 
   2820 /************************************************************************
   2821  *									*
   2822  *			Routines to handle NodeSets			*
   2823  *									*
   2824  ************************************************************************/
   2825 
   2826 /**
   2827  * xmlXPathOrderDocElems:
   2828  * @doc:  an input document
   2829  *
   2830  * Call this routine to speed up XPath computation on static documents.
   2831  * This stamps all the element nodes with the document order
   2832  * Like for line information, the order is kept in the element->content
   2833  * field, the value stored is actually - the node number (starting at -1)
   2834  * to be able to differentiate from line numbers.
   2835  *
   2836  * Returns the number of elements found in the document or -1 in case
   2837  *    of error.
   2838  */
   2839 long
   2840 xmlXPathOrderDocElems(xmlDocPtr doc) {
   2841     long count = 0;
   2842     xmlNodePtr cur;
   2843 
   2844     if (doc == NULL)
   2845 	return(-1);
   2846     cur = doc->children;
   2847     while (cur != NULL) {
   2848 	if (cur->type == XML_ELEMENT_NODE) {
   2849 	    cur->content = (void *) (-(++count));
   2850 	    if (cur->children != NULL) {
   2851 		cur = cur->children;
   2852 		continue;
   2853 	    }
   2854 	}
   2855 	if (cur->next != NULL) {
   2856 	    cur = cur->next;
   2857 	    continue;
   2858 	}
   2859 	do {
   2860 	    cur = cur->parent;
   2861 	    if (cur == NULL)
   2862 		break;
   2863 	    if (cur == (xmlNodePtr) doc) {
   2864 		cur = NULL;
   2865 		break;
   2866 	    }
   2867 	    if (cur->next != NULL) {
   2868 		cur = cur->next;
   2869 		break;
   2870 	    }
   2871 	} while (cur != NULL);
   2872     }
   2873     return(count);
   2874 }
   2875 
   2876 /**
   2877  * xmlXPathCmpNodes:
   2878  * @node1:  the first node
   2879  * @node2:  the second node
   2880  *
   2881  * Compare two nodes w.r.t document order
   2882  *
   2883  * Returns -2 in case of error 1 if first point < second point, 0 if
   2884  *         it's the same node, -1 otherwise
   2885  */
   2886 int
   2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   2888     int depth1, depth2;
   2889     int attr1 = 0, attr2 = 0;
   2890     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   2891     xmlNodePtr cur, root;
   2892 
   2893     if ((node1 == NULL) || (node2 == NULL))
   2894 	return(-2);
   2895     /*
   2896      * a couple of optimizations which will avoid computations in most cases
   2897      */
   2898     if (node1 == node2)		/* trivial case */
   2899 	return(0);
   2900     if (node1->type == XML_ATTRIBUTE_NODE) {
   2901 	attr1 = 1;
   2902 	attrNode1 = node1;
   2903 	node1 = node1->parent;
   2904     }
   2905     if (node2->type == XML_ATTRIBUTE_NODE) {
   2906 	attr2 = 1;
   2907 	attrNode2 = node2;
   2908 	node2 = node2->parent;
   2909     }
   2910     if (node1 == node2) {
   2911 	if (attr1 == attr2) {
   2912 	    /* not required, but we keep attributes in order */
   2913 	    if (attr1 != 0) {
   2914 	        cur = attrNode2->prev;
   2915 		while (cur != NULL) {
   2916 		    if (cur == attrNode1)
   2917 		        return (1);
   2918 		    cur = cur->prev;
   2919 		}
   2920 		return (-1);
   2921 	    }
   2922 	    return(0);
   2923 	}
   2924 	if (attr2 == 1)
   2925 	    return(1);
   2926 	return(-1);
   2927     }
   2928     if ((node1->type == XML_NAMESPACE_DECL) ||
   2929         (node2->type == XML_NAMESPACE_DECL))
   2930 	return(1);
   2931     if (node1 == node2->prev)
   2932 	return(1);
   2933     if (node1 == node2->next)
   2934 	return(-1);
   2935 
   2936     /*
   2937      * Speedup using document order if availble.
   2938      */
   2939     if ((node1->type == XML_ELEMENT_NODE) &&
   2940 	(node2->type == XML_ELEMENT_NODE) &&
   2941 	(0 > (long) node1->content) &&
   2942 	(0 > (long) node2->content) &&
   2943 	(node1->doc == node2->doc)) {
   2944 	long l1, l2;
   2945 
   2946 	l1 = -((long) node1->content);
   2947 	l2 = -((long) node2->content);
   2948 	if (l1 < l2)
   2949 	    return(1);
   2950 	if (l1 > l2)
   2951 	    return(-1);
   2952     }
   2953 
   2954     /*
   2955      * compute depth to root
   2956      */
   2957     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   2958 	if (cur == node1)
   2959 	    return(1);
   2960 	depth2++;
   2961     }
   2962     root = cur;
   2963     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   2964 	if (cur == node2)
   2965 	    return(-1);
   2966 	depth1++;
   2967     }
   2968     /*
   2969      * Distinct document (or distinct entities :-( ) case.
   2970      */
   2971     if (root != cur) {
   2972 	return(-2);
   2973     }
   2974     /*
   2975      * get the nearest common ancestor.
   2976      */
   2977     while (depth1 > depth2) {
   2978 	depth1--;
   2979 	node1 = node1->parent;
   2980     }
   2981     while (depth2 > depth1) {
   2982 	depth2--;
   2983 	node2 = node2->parent;
   2984     }
   2985     while (node1->parent != node2->parent) {
   2986 	node1 = node1->parent;
   2987 	node2 = node2->parent;
   2988 	/* should not happen but just in case ... */
   2989 	if ((node1 == NULL) || (node2 == NULL))
   2990 	    return(-2);
   2991     }
   2992     /*
   2993      * Find who's first.
   2994      */
   2995     if (node1 == node2->prev)
   2996 	return(1);
   2997     if (node1 == node2->next)
   2998 	return(-1);
   2999     /*
   3000      * Speedup using document order if availble.
   3001      */
   3002     if ((node1->type == XML_ELEMENT_NODE) &&
   3003 	(node2->type == XML_ELEMENT_NODE) &&
   3004 	(0 > (long) node1->content) &&
   3005 	(0 > (long) node2->content) &&
   3006 	(node1->doc == node2->doc)) {
   3007 	long l1, l2;
   3008 
   3009 	l1 = -((long) node1->content);
   3010 	l2 = -((long) node2->content);
   3011 	if (l1 < l2)
   3012 	    return(1);
   3013 	if (l1 > l2)
   3014 	    return(-1);
   3015     }
   3016 
   3017     for (cur = node1->next;cur != NULL;cur = cur->next)
   3018 	if (cur == node2)
   3019 	    return(1);
   3020     return(-1); /* assume there is no sibling list corruption */
   3021 }
   3022 
   3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3024 /**
   3025  * xmlXPathCmpNodesExt:
   3026  * @node1:  the first node
   3027  * @node2:  the second node
   3028  *
   3029  * Compare two nodes w.r.t document order.
   3030  * This one is optimized for handling of non-element nodes.
   3031  *
   3032  * Returns -2 in case of error 1 if first point < second point, 0 if
   3033  *         it's the same node, -1 otherwise
   3034  */
   3035 static int
   3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
   3037     int depth1, depth2;
   3038     int misc = 0, precedence1 = 0, precedence2 = 0;
   3039     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
   3040     xmlNodePtr cur, root;
   3041     long l1, l2;
   3042 
   3043     if ((node1 == NULL) || (node2 == NULL))
   3044 	return(-2);
   3045 
   3046     if (node1 == node2)
   3047 	return(0);
   3048 
   3049     /*
   3050      * a couple of optimizations which will avoid computations in most cases
   3051      */
   3052     switch (node1->type) {
   3053 	case XML_ELEMENT_NODE:
   3054 	    if (node2->type == XML_ELEMENT_NODE) {
   3055 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
   3056 		    (0 > (long) node2->content) &&
   3057 		    (node1->doc == node2->doc))
   3058 		{
   3059 		    l1 = -((long) node1->content);
   3060 		    l2 = -((long) node2->content);
   3061 		    if (l1 < l2)
   3062 			return(1);
   3063 		    if (l1 > l2)
   3064 			return(-1);
   3065 		} else
   3066 		    goto turtle_comparison;
   3067 	    }
   3068 	    break;
   3069 	case XML_ATTRIBUTE_NODE:
   3070 	    precedence1 = 1; /* element is owner */
   3071 	    miscNode1 = node1;
   3072 	    node1 = node1->parent;
   3073 	    misc = 1;
   3074 	    break;
   3075 	case XML_TEXT_NODE:
   3076 	case XML_CDATA_SECTION_NODE:
   3077 	case XML_COMMENT_NODE:
   3078 	case XML_PI_NODE: {
   3079 	    miscNode1 = node1;
   3080 	    /*
   3081 	    * Find nearest element node.
   3082 	    */
   3083 	    if (node1->prev != NULL) {
   3084 		do {
   3085 		    node1 = node1->prev;
   3086 		    if (node1->type == XML_ELEMENT_NODE) {
   3087 			precedence1 = 3; /* element in prev-sibl axis */
   3088 			break;
   3089 		    }
   3090 		    if (node1->prev == NULL) {
   3091 			precedence1 = 2; /* element is parent */
   3092 			/*
   3093 			* URGENT TODO: Are there any cases, where the
   3094 			* parent of such a node is not an element node?
   3095 			*/
   3096 			node1 = node1->parent;
   3097 			break;
   3098 		    }
   3099 		} while (1);
   3100 	    } else {
   3101 		precedence1 = 2; /* element is parent */
   3102 		node1 = node1->parent;
   3103 	    }
   3104 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
   3105 		(0 <= (long) node1->content)) {
   3106 		/*
   3107 		* Fallback for whatever case.
   3108 		*/
   3109 		node1 = miscNode1;
   3110 		precedence1 = 0;
   3111 	    } else
   3112 		misc = 1;
   3113 	}
   3114 	    break;
   3115 	case XML_NAMESPACE_DECL:
   3116 	    /*
   3117 	    * TODO: why do we return 1 for namespace nodes?
   3118 	    */
   3119 	    return(1);
   3120 	default:
   3121 	    break;
   3122     }
   3123     switch (node2->type) {
   3124 	case XML_ELEMENT_NODE:
   3125 	    break;
   3126 	case XML_ATTRIBUTE_NODE:
   3127 	    precedence2 = 1; /* element is owner */
   3128 	    miscNode2 = node2;
   3129 	    node2 = node2->parent;
   3130 	    misc = 1;
   3131 	    break;
   3132 	case XML_TEXT_NODE:
   3133 	case XML_CDATA_SECTION_NODE:
   3134 	case XML_COMMENT_NODE:
   3135 	case XML_PI_NODE: {
   3136 	    miscNode2 = node2;
   3137 	    if (node2->prev != NULL) {
   3138 		do {
   3139 		    node2 = node2->prev;
   3140 		    if (node2->type == XML_ELEMENT_NODE) {
   3141 			precedence2 = 3; /* element in prev-sibl axis */
   3142 			break;
   3143 		    }
   3144 		    if (node2->prev == NULL) {
   3145 			precedence2 = 2; /* element is parent */
   3146 			node2 = node2->parent;
   3147 			break;
   3148 		    }
   3149 		} while (1);
   3150 	    } else {
   3151 		precedence2 = 2; /* element is parent */
   3152 		node2 = node2->parent;
   3153 	    }
   3154 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
   3155 		(0 <= (long) node1->content))
   3156 	    {
   3157 		node2 = miscNode2;
   3158 		precedence2 = 0;
   3159 	    } else
   3160 		misc = 1;
   3161 	}
   3162 	    break;
   3163 	case XML_NAMESPACE_DECL:
   3164 	    return(1);
   3165 	default:
   3166 	    break;
   3167     }
   3168     if (misc) {
   3169 	if (node1 == node2) {
   3170 	    if (precedence1 == precedence2) {
   3171 		/*
   3172 		* The ugly case; but normally there aren't many
   3173 		* adjacent non-element nodes around.
   3174 		*/
   3175 		cur = miscNode2->prev;
   3176 		while (cur != NULL) {
   3177 		    if (cur == miscNode1)
   3178 			return(1);
   3179 		    if (cur->type == XML_ELEMENT_NODE)
   3180 			return(-1);
   3181 		    cur = cur->prev;
   3182 		}
   3183 		return (-1);
   3184 	    } else {
   3185 		/*
   3186 		* Evaluate based on higher precedence wrt to the element.
   3187 		* TODO: This assumes attributes are sorted before content.
   3188 		*   Is this 100% correct?
   3189 		*/
   3190 		if (precedence1 < precedence2)
   3191 		    return(1);
   3192 		else
   3193 		    return(-1);
   3194 	    }
   3195 	}
   3196 	/*
   3197 	* Special case: One of the helper-elements is contained by the other.
   3198 	* <foo>
   3199 	*   <node2>
   3200 	*     <node1>Text-1(precedence1 == 2)</node1>
   3201 	*   </node2>
   3202 	*   Text-6(precedence2 == 3)
   3203 	* </foo>
   3204 	*/
   3205 	if ((precedence2 == 3) && (precedence1 > 1)) {
   3206 	    cur = node1->parent;
   3207 	    while (cur) {
   3208 		if (cur == node2)
   3209 		    return(1);
   3210 		cur = cur->parent;
   3211 	    }
   3212 	}
   3213 	if ((precedence1 == 3) && (precedence2 > 1)) {
   3214 	    cur = node2->parent;
   3215 	    while (cur) {
   3216 		if (cur == node1)
   3217 		    return(-1);
   3218 		cur = cur->parent;
   3219 	    }
   3220 	}
   3221     }
   3222 
   3223     /*
   3224      * Speedup using document order if availble.
   3225      */
   3226     if ((node1->type == XML_ELEMENT_NODE) &&
   3227 	(node2->type == XML_ELEMENT_NODE) &&
   3228 	(0 > (long) node1->content) &&
   3229 	(0 > (long) node2->content) &&
   3230 	(node1->doc == node2->doc)) {
   3231 
   3232 	l1 = -((long) node1->content);
   3233 	l2 = -((long) node2->content);
   3234 	if (l1 < l2)
   3235 	    return(1);
   3236 	if (l1 > l2)
   3237 	    return(-1);
   3238     }
   3239 
   3240 turtle_comparison:
   3241 
   3242     if (node1 == node2->prev)
   3243 	return(1);
   3244     if (node1 == node2->next)
   3245 	return(-1);
   3246     /*
   3247      * compute depth to root
   3248      */
   3249     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3250 	if (cur == node1)
   3251 	    return(1);
   3252 	depth2++;
   3253     }
   3254     root = cur;
   3255     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3256 	if (cur == node2)
   3257 	    return(-1);
   3258 	depth1++;
   3259     }
   3260     /*
   3261      * Distinct document (or distinct entities :-( ) case.
   3262      */
   3263     if (root != cur) {
   3264 	return(-2);
   3265     }
   3266     /*
   3267      * get the nearest common ancestor.
   3268      */
   3269     while (depth1 > depth2) {
   3270 	depth1--;
   3271 	node1 = node1->parent;
   3272     }
   3273     while (depth2 > depth1) {
   3274 	depth2--;
   3275 	node2 = node2->parent;
   3276     }
   3277     while (node1->parent != node2->parent) {
   3278 	node1 = node1->parent;
   3279 	node2 = node2->parent;
   3280 	/* should not happen but just in case ... */
   3281 	if ((node1 == NULL) || (node2 == NULL))
   3282 	    return(-2);
   3283     }
   3284     /*
   3285      * Find who's first.
   3286      */
   3287     if (node1 == node2->prev)
   3288 	return(1);
   3289     if (node1 == node2->next)
   3290 	return(-1);
   3291     /*
   3292      * Speedup using document order if availble.
   3293      */
   3294     if ((node1->type == XML_ELEMENT_NODE) &&
   3295 	(node2->type == XML_ELEMENT_NODE) &&
   3296 	(0 > (long) node1->content) &&
   3297 	(0 > (long) node2->content) &&
   3298 	(node1->doc == node2->doc)) {
   3299 
   3300 	l1 = -((long) node1->content);
   3301 	l2 = -((long) node2->content);
   3302 	if (l1 < l2)
   3303 	    return(1);
   3304 	if (l1 > l2)
   3305 	    return(-1);
   3306     }
   3307 
   3308     for (cur = node1->next;cur != NULL;cur = cur->next)
   3309 	if (cur == node2)
   3310 	    return(1);
   3311     return(-1); /* assume there is no sibling list corruption */
   3312 }
   3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
   3314 
   3315 /**
   3316  * xmlXPathNodeSetSort:
   3317  * @set:  the node set
   3318  *
   3319  * Sort the node set in document order
   3320  */
   3321 void
   3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3323     int i, j, incr, len;
   3324     xmlNodePtr tmp;
   3325 
   3326     if (set == NULL)
   3327 	return;
   3328 
   3329     /* Use Shell's sort to sort the node-set */
   3330     len = set->nodeNr;
   3331     for (incr = len / 2; incr > 0; incr /= 2) {
   3332 	for (i = incr; i < len; i++) {
   3333 	    j = i - incr;
   3334 	    while (j >= 0) {
   3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3336 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3337 			set->nodeTab[j + incr]) == -1)
   3338 #else
   3339 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3340 			set->nodeTab[j + incr]) == -1)
   3341 #endif
   3342 		{
   3343 		    tmp = set->nodeTab[j];
   3344 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3345 		    set->nodeTab[j + incr] = tmp;
   3346 		    j -= incr;
   3347 		} else
   3348 		    break;
   3349 	    }
   3350 	}
   3351     }
   3352 }
   3353 
   3354 #define XML_NODESET_DEFAULT	10
   3355 /**
   3356  * xmlXPathNodeSetDupNs:
   3357  * @node:  the parent node of the namespace XPath node
   3358  * @ns:  the libxml namespace declaration node.
   3359  *
   3360  * Namespace node in libxml don't match the XPath semantic. In a node set
   3361  * the namespace nodes are duplicated and the next pointer is set to the
   3362  * parent node in the XPath semantic.
   3363  *
   3364  * Returns the newly created object.
   3365  */
   3366 static xmlNodePtr
   3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3368     xmlNsPtr cur;
   3369 
   3370     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3371 	return(NULL);
   3372     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3373 	return((xmlNodePtr) ns);
   3374 
   3375     /*
   3376      * Allocate a new Namespace and fill the fields.
   3377      */
   3378     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3379     if (cur == NULL) {
   3380         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3381 	return(NULL);
   3382     }
   3383     memset(cur, 0, sizeof(xmlNs));
   3384     cur->type = XML_NAMESPACE_DECL;
   3385     if (ns->href != NULL)
   3386 	cur->href = xmlStrdup(ns->href);
   3387     if (ns->prefix != NULL)
   3388 	cur->prefix = xmlStrdup(ns->prefix);
   3389     cur->next = (xmlNsPtr) node;
   3390     return((xmlNodePtr) cur);
   3391 }
   3392 
   3393 /**
   3394  * xmlXPathNodeSetFreeNs:
   3395  * @ns:  the XPath namespace node found in a nodeset.
   3396  *
   3397  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3398  * the namespace nodes are duplicated and the next pointer is set to the
   3399  * parent node in the XPath semantic. Check if such a node needs to be freed
   3400  */
   3401 void
   3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3403     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3404 	return;
   3405 
   3406     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3407 	if (ns->href != NULL)
   3408 	    xmlFree((xmlChar *)ns->href);
   3409 	if (ns->prefix != NULL)
   3410 	    xmlFree((xmlChar *)ns->prefix);
   3411 	xmlFree(ns);
   3412     }
   3413 }
   3414 
   3415 /**
   3416  * xmlXPathNodeSetCreate:
   3417  * @val:  an initial xmlNodePtr, or NULL
   3418  *
   3419  * Create a new xmlNodeSetPtr of type double and of value @val
   3420  *
   3421  * Returns the newly created object.
   3422  */
   3423 xmlNodeSetPtr
   3424 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3425     xmlNodeSetPtr ret;
   3426 
   3427     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3428     if (ret == NULL) {
   3429         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3430 	return(NULL);
   3431     }
   3432     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3433     if (val != NULL) {
   3434         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3435 					     sizeof(xmlNodePtr));
   3436 	if (ret->nodeTab == NULL) {
   3437 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3438 	    xmlFree(ret);
   3439 	    return(NULL);
   3440 	}
   3441 	memset(ret->nodeTab, 0 ,
   3442 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3443         ret->nodeMax = XML_NODESET_DEFAULT;
   3444 	if (val->type == XML_NAMESPACE_DECL) {
   3445 	    xmlNsPtr ns = (xmlNsPtr) val;
   3446 
   3447 	    ret->nodeTab[ret->nodeNr++] =
   3448 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3449 	} else
   3450 	    ret->nodeTab[ret->nodeNr++] = val;
   3451     }
   3452     return(ret);
   3453 }
   3454 
   3455 /**
   3456  * xmlXPathNodeSetCreateSize:
   3457  * @size:  the initial size of the set
   3458  *
   3459  * Create a new xmlNodeSetPtr of type double and of value @val
   3460  *
   3461  * Returns the newly created object.
   3462  */
   3463 static xmlNodeSetPtr
   3464 xmlXPathNodeSetCreateSize(int size) {
   3465     xmlNodeSetPtr ret;
   3466 
   3467     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3468     if (ret == NULL) {
   3469         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3470 	return(NULL);
   3471     }
   3472     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3473     if (size < XML_NODESET_DEFAULT)
   3474 	size = XML_NODESET_DEFAULT;
   3475     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3476     if (ret->nodeTab == NULL) {
   3477 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3478 	xmlFree(ret);
   3479 	return(NULL);
   3480     }
   3481     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3482     ret->nodeMax = size;
   3483     return(ret);
   3484 }
   3485 
   3486 /**
   3487  * xmlXPathNodeSetContains:
   3488  * @cur:  the node-set
   3489  * @val:  the node
   3490  *
   3491  * checks whether @cur contains @val
   3492  *
   3493  * Returns true (1) if @cur contains @val, false (0) otherwise
   3494  */
   3495 int
   3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3497     int i;
   3498 
   3499     if ((cur == NULL) || (val == NULL)) return(0);
   3500     if (val->type == XML_NAMESPACE_DECL) {
   3501 	for (i = 0; i < cur->nodeNr; i++) {
   3502 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3503 		xmlNsPtr ns1, ns2;
   3504 
   3505 		ns1 = (xmlNsPtr) val;
   3506 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3507 		if (ns1 == ns2)
   3508 		    return(1);
   3509 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3510 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3511 		    return(1);
   3512 	    }
   3513 	}
   3514     } else {
   3515 	for (i = 0; i < cur->nodeNr; i++) {
   3516 	    if (cur->nodeTab[i] == val)
   3517 		return(1);
   3518 	}
   3519     }
   3520     return(0);
   3521 }
   3522 
   3523 /**
   3524  * xmlXPathNodeSetAddNs:
   3525  * @cur:  the initial node set
   3526  * @node:  the hosting node
   3527  * @ns:  a the namespace node
   3528  *
   3529  * add a new namespace node to an existing NodeSet
   3530  */
   3531 void
   3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3533     int i;
   3534 
   3535 
   3536     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3537         (ns->type != XML_NAMESPACE_DECL) ||
   3538 	(node->type != XML_ELEMENT_NODE))
   3539 	return;
   3540 
   3541     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3542     /*
   3543      * prevent duplicates
   3544      */
   3545     for (i = 0;i < cur->nodeNr;i++) {
   3546         if ((cur->nodeTab[i] != NULL) &&
   3547 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3548 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3549 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3550 	    return;
   3551     }
   3552 
   3553     /*
   3554      * grow the nodeTab if needed
   3555      */
   3556     if (cur->nodeMax == 0) {
   3557         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3558 					     sizeof(xmlNodePtr));
   3559 	if (cur->nodeTab == NULL) {
   3560 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3561 	    return;
   3562 	}
   3563 	memset(cur->nodeTab, 0 ,
   3564 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3565         cur->nodeMax = XML_NODESET_DEFAULT;
   3566     } else if (cur->nodeNr == cur->nodeMax) {
   3567         xmlNodePtr *temp;
   3568 
   3569 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3570 				      sizeof(xmlNodePtr));
   3571 	if (temp == NULL) {
   3572 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3573 	    return;
   3574 	}
   3575         cur->nodeMax *= 2;
   3576 	cur->nodeTab = temp;
   3577     }
   3578     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3579 }
   3580 
   3581 /**
   3582  * xmlXPathNodeSetAdd:
   3583  * @cur:  the initial node set
   3584  * @val:  a new xmlNodePtr
   3585  *
   3586  * add a new xmlNodePtr to an existing NodeSet
   3587  */
   3588 void
   3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3590     int i;
   3591 
   3592     if ((cur == NULL) || (val == NULL)) return;
   3593 
   3594 #if 0
   3595     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3596 	return;	/* an XSLT fake node */
   3597 #endif
   3598 
   3599     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3600     /*
   3601      * prevent duplcates
   3602      */
   3603     for (i = 0;i < cur->nodeNr;i++)
   3604         if (cur->nodeTab[i] == val) return;
   3605 
   3606     /*
   3607      * grow the nodeTab if needed
   3608      */
   3609     if (cur->nodeMax == 0) {
   3610         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3611 					     sizeof(xmlNodePtr));
   3612 	if (cur->nodeTab == NULL) {
   3613 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3614 	    return;
   3615 	}
   3616 	memset(cur->nodeTab, 0 ,
   3617 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3618         cur->nodeMax = XML_NODESET_DEFAULT;
   3619     } else if (cur->nodeNr == cur->nodeMax) {
   3620         xmlNodePtr *temp;
   3621 
   3622 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3623 				      sizeof(xmlNodePtr));
   3624 	if (temp == NULL) {
   3625 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3626 	    return;
   3627 	}
   3628         cur->nodeMax *= 2;
   3629 	cur->nodeTab = temp;
   3630     }
   3631     if (val->type == XML_NAMESPACE_DECL) {
   3632 	xmlNsPtr ns = (xmlNsPtr) val;
   3633 
   3634 	cur->nodeTab[cur->nodeNr++] =
   3635 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3636     } else
   3637 	cur->nodeTab[cur->nodeNr++] = val;
   3638 }
   3639 
   3640 /**
   3641  * xmlXPathNodeSetAddUnique:
   3642  * @cur:  the initial node set
   3643  * @val:  a new xmlNodePtr
   3644  *
   3645  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3646  * when we are sure the node is not already in the set.
   3647  */
   3648 void
   3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3650     if ((cur == NULL) || (val == NULL)) return;
   3651 
   3652 #if 0
   3653     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3654 	return;	/* an XSLT fake node */
   3655 #endif
   3656 
   3657     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3658     /*
   3659      * grow the nodeTab if needed
   3660      */
   3661     if (cur->nodeMax == 0) {
   3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3663 					     sizeof(xmlNodePtr));
   3664 	if (cur->nodeTab == NULL) {
   3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3666 	    return;
   3667 	}
   3668 	memset(cur->nodeTab, 0 ,
   3669 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3670         cur->nodeMax = XML_NODESET_DEFAULT;
   3671     } else if (cur->nodeNr == cur->nodeMax) {
   3672         xmlNodePtr *temp;
   3673 
   3674 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3675 				      sizeof(xmlNodePtr));
   3676 	if (temp == NULL) {
   3677 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3678 	    return;
   3679 	}
   3680 	cur->nodeTab = temp;
   3681         cur->nodeMax *= 2;
   3682     }
   3683     if (val->type == XML_NAMESPACE_DECL) {
   3684 	xmlNsPtr ns = (xmlNsPtr) val;
   3685 
   3686 	cur->nodeTab[cur->nodeNr++] =
   3687 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3688     } else
   3689 	cur->nodeTab[cur->nodeNr++] = val;
   3690 }
   3691 
   3692 /**
   3693  * xmlXPathNodeSetMerge:
   3694  * @val1:  the first NodeSet or NULL
   3695  * @val2:  the second NodeSet
   3696  *
   3697  * Merges two nodesets, all nodes from @val2 are added to @val1
   3698  * if @val1 is NULL, a new set is created and copied from @val2
   3699  *
   3700  * Returns @val1 once extended or NULL in case of error.
   3701  */
   3702 xmlNodeSetPtr
   3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3704     int i, j, initNr, skip;
   3705     xmlNodePtr n1, n2;
   3706 
   3707     if (val2 == NULL) return(val1);
   3708     if (val1 == NULL) {
   3709 	val1 = xmlXPathNodeSetCreate(NULL);
   3710     if (val1 == NULL)
   3711         return (NULL);
   3712 #if 0
   3713 	/*
   3714 	* TODO: The optimization won't work in every case, since
   3715 	*  those nasty namespace nodes need to be added with
   3716 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3717 	*  memcpy is not possible.
   3718 	*  If there was a flag on the nodesetval, indicating that
   3719 	*  some temporary nodes are in, that would be helpfull.
   3720 	*/
   3721 	/*
   3722 	* Optimization: Create an equally sized node-set
   3723 	* and memcpy the content.
   3724 	*/
   3725 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3726 	if (val1 == NULL)
   3727 	    return(NULL);
   3728 	if (val2->nodeNr != 0) {
   3729 	    if (val2->nodeNr == 1)
   3730 		*(val1->nodeTab) = *(val2->nodeTab);
   3731 	    else {
   3732 		memcpy(val1->nodeTab, val2->nodeTab,
   3733 		    val2->nodeNr * sizeof(xmlNodePtr));
   3734 	    }
   3735 	    val1->nodeNr = val2->nodeNr;
   3736 	}
   3737 	return(val1);
   3738 #endif
   3739     }
   3740 
   3741     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3742     initNr = val1->nodeNr;
   3743 
   3744     for (i = 0;i < val2->nodeNr;i++) {
   3745 	n2 = val2->nodeTab[i];
   3746 	/*
   3747 	 * check against duplicates
   3748 	 */
   3749 	skip = 0;
   3750 	for (j = 0; j < initNr; j++) {
   3751 	    n1 = val1->nodeTab[j];
   3752 	    if (n1 == n2) {
   3753 		skip = 1;
   3754 		break;
   3755 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3756 		       (n2->type == XML_NAMESPACE_DECL)) {
   3757 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3758 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3759 			((xmlNsPtr) n2)->prefix)))
   3760 		{
   3761 		    skip = 1;
   3762 		    break;
   3763 		}
   3764 	    }
   3765 	}
   3766 	if (skip)
   3767 	    continue;
   3768 
   3769 	/*
   3770 	 * grow the nodeTab if needed
   3771 	 */
   3772 	if (val1->nodeMax == 0) {
   3773 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3774 						    sizeof(xmlNodePtr));
   3775 	    if (val1->nodeTab == NULL) {
   3776 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3777 		return(NULL);
   3778 	    }
   3779 	    memset(val1->nodeTab, 0 ,
   3780 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3781 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3782 	} else if (val1->nodeNr == val1->nodeMax) {
   3783 	    xmlNodePtr *temp;
   3784 
   3785 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3786 					     sizeof(xmlNodePtr));
   3787 	    if (temp == NULL) {
   3788 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3789 		return(NULL);
   3790 	    }
   3791 	    val1->nodeTab = temp;
   3792 	    val1->nodeMax *= 2;
   3793 	}
   3794 	if (n2->type == XML_NAMESPACE_DECL) {
   3795 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3796 
   3797 	    val1->nodeTab[val1->nodeNr++] =
   3798 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3799 	} else
   3800 	    val1->nodeTab[val1->nodeNr++] = n2;
   3801     }
   3802 
   3803     return(val1);
   3804 }
   3805 
   3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3807 /**
   3808  * xmlXPathNodeSetMergeUnique:
   3809  * @val1:  the first NodeSet or NULL
   3810  * @val2:  the second NodeSet
   3811  *
   3812  * Merges two nodesets, all nodes from @val2 are added to @val1
   3813  * if @val1 is NULL, a new set is created and copied from @val2
   3814  *
   3815  * Returns @val1 once extended or NULL in case of error.
   3816  */
   3817 static xmlNodeSetPtr
   3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3819     int i;
   3820 
   3821     if (val2 == NULL) return(val1);
   3822     if (val1 == NULL) {
   3823 	val1 = xmlXPathNodeSetCreate(NULL);
   3824     }
   3825     if (val1 == NULL)
   3826         return (NULL);
   3827 
   3828     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3829 
   3830     for (i = 0;i < val2->nodeNr;i++) {
   3831 	/*
   3832 	 * grow the nodeTab if needed
   3833 	 */
   3834 	if (val1->nodeMax == 0) {
   3835 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3836 						    sizeof(xmlNodePtr));
   3837 	    if (val1->nodeTab == NULL) {
   3838 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3839 		return(NULL);
   3840 	    }
   3841 	    memset(val1->nodeTab, 0 ,
   3842 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3843 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3844 	} else if (val1->nodeNr == val1->nodeMax) {
   3845 	    xmlNodePtr *temp;
   3846 
   3847 	    val1->nodeMax *= 2;
   3848 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3849 					     sizeof(xmlNodePtr));
   3850 	    if (temp == NULL) {
   3851 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3852 		return(NULL);
   3853 	    }
   3854 	    val1->nodeTab = temp;
   3855 	}
   3856 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3857 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
   3858 
   3859 	    val1->nodeTab[val1->nodeNr++] =
   3860 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3861 	} else
   3862 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
   3863     }
   3864 
   3865     return(val1);
   3866 }
   3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3868 
   3869 /**
   3870  * xmlXPathNodeSetMergeAndClear:
   3871  * @set1:  the first NodeSet or NULL
   3872  * @set2:  the second NodeSet
   3873  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3874  *
   3875  * Merges two nodesets, all nodes from @set2 are added to @set1
   3876  * if @set1 is NULL, a new set is created and copied from @set2.
   3877  * Checks for duplicate nodes. Clears set2.
   3878  *
   3879  * Returns @set1 once extended or NULL in case of error.
   3880  */
   3881 static xmlNodeSetPtr
   3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3883 			     int hasNullEntries)
   3884 {
   3885     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3886 	/*
   3887 	* Note that doing a memcpy of the list, namespace nodes are
   3888 	* just assigned to set1, since set2 is cleared anyway.
   3889 	*/
   3890 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3891 	if (set1 == NULL)
   3892 	    return(NULL);
   3893 	if (set2->nodeNr != 0) {
   3894 	    memcpy(set1->nodeTab, set2->nodeTab,
   3895 		set2->nodeNr * sizeof(xmlNodePtr));
   3896 	    set1->nodeNr = set2->nodeNr;
   3897 	}
   3898     } else {
   3899 	int i, j, initNbSet1;
   3900 	xmlNodePtr n1, n2;
   3901 
   3902 	if (set1 == NULL)
   3903             set1 = xmlXPathNodeSetCreate(NULL);
   3904         if (set1 == NULL)
   3905             return (NULL);
   3906 
   3907 	initNbSet1 = set1->nodeNr;
   3908 	for (i = 0;i < set2->nodeNr;i++) {
   3909 	    n2 = set2->nodeTab[i];
   3910 	    /*
   3911 	    * Skip NULLed entries.
   3912 	    */
   3913 	    if (n2 == NULL)
   3914 		continue;
   3915 	    /*
   3916 	    * Skip duplicates.
   3917 	    */
   3918 	    for (j = 0; j < initNbSet1; j++) {
   3919 		n1 = set1->nodeTab[j];
   3920 		if (n1 == n2) {
   3921 		    goto skip_node;
   3922 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3923 		    (n2->type == XML_NAMESPACE_DECL))
   3924 		{
   3925 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3926 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3927 			((xmlNsPtr) n2)->prefix)))
   3928 		    {
   3929 			/*
   3930 			* Free the namespace node.
   3931 			*/
   3932 			set2->nodeTab[i] = NULL;
   3933 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3934 			goto skip_node;
   3935 		    }
   3936 		}
   3937 	    }
   3938 	    /*
   3939 	    * grow the nodeTab if needed
   3940 	    */
   3941 	    if (set1->nodeMax == 0) {
   3942 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3943 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3944 		if (set1->nodeTab == NULL) {
   3945 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3946 		    return(NULL);
   3947 		}
   3948 		memset(set1->nodeTab, 0,
   3949 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3950 		set1->nodeMax = XML_NODESET_DEFAULT;
   3951 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3952 		xmlNodePtr *temp;
   3953 
   3954 		temp = (xmlNodePtr *) xmlRealloc(
   3955 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   3956 		if (temp == NULL) {
   3957 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3958 		    return(NULL);
   3959 		}
   3960 		set1->nodeTab = temp;
   3961 		set1->nodeMax *= 2;
   3962 	    }
   3963 	    if (n2->type == XML_NAMESPACE_DECL) {
   3964 		xmlNsPtr ns = (xmlNsPtr) n2;
   3965 
   3966 		set1->nodeTab[set1->nodeNr++] =
   3967 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3968 	    } else
   3969 		set1->nodeTab[set1->nodeNr++] = n2;
   3970 skip_node:
   3971 	    {}
   3972 	}
   3973     }
   3974     set2->nodeNr = 0;
   3975     return(set1);
   3976 }
   3977 
   3978 /**
   3979  * xmlXPathNodeSetMergeAndClearNoDupls:
   3980  * @set1:  the first NodeSet or NULL
   3981  * @set2:  the second NodeSet
   3982  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3983  *
   3984  * Merges two nodesets, all nodes from @set2 are added to @set1
   3985  * if @set1 is NULL, a new set is created and copied from @set2.
   3986  * Doesn't chack for duplicate nodes. Clears set2.
   3987  *
   3988  * Returns @set1 once extended or NULL in case of error.
   3989  */
   3990 static xmlNodeSetPtr
   3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3992 				    int hasNullEntries)
   3993 {
   3994     if (set2 == NULL)
   3995 	return(set1);
   3996     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3997 	/*
   3998 	* Note that doing a memcpy of the list, namespace nodes are
   3999 	* just assigned to set1, since set2 is cleared anyway.
   4000 	*/
   4001 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4002 	if (set1 == NULL)
   4003 	    return(NULL);
   4004 	if (set2->nodeNr != 0) {
   4005 	    memcpy(set1->nodeTab, set2->nodeTab,
   4006 		set2->nodeNr * sizeof(xmlNodePtr));
   4007 	    set1->nodeNr = set2->nodeNr;
   4008 	}
   4009     } else {
   4010 	int i;
   4011 	xmlNodePtr n2;
   4012 
   4013 	if (set1 == NULL)
   4014 	    set1 = xmlXPathNodeSetCreate(NULL);
   4015         if (set1 == NULL)
   4016             return (NULL);
   4017 
   4018 	for (i = 0;i < set2->nodeNr;i++) {
   4019 	    n2 = set2->nodeTab[i];
   4020 	    /*
   4021 	    * Skip NULLed entries.
   4022 	    */
   4023 	    if (n2 == NULL)
   4024 		continue;
   4025 	    if (set1->nodeMax == 0) {
   4026 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4027 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4028 		if (set1->nodeTab == NULL) {
   4029 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4030 		    return(NULL);
   4031 		}
   4032 		memset(set1->nodeTab, 0,
   4033 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4034 		set1->nodeMax = XML_NODESET_DEFAULT;
   4035 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4036 		xmlNodePtr *temp;
   4037 
   4038 		temp = (xmlNodePtr *) xmlRealloc(
   4039 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4040 		if (temp == NULL) {
   4041 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4042 		    return(NULL);
   4043 		}
   4044 		set1->nodeTab = temp;
   4045 		set1->nodeMax *= 2;
   4046 	    }
   4047 	    set1->nodeTab[set1->nodeNr++] = n2;
   4048 	}
   4049     }
   4050     set2->nodeNr = 0;
   4051     return(set1);
   4052 }
   4053 
   4054 /**
   4055  * xmlXPathNodeSetDel:
   4056  * @cur:  the initial node set
   4057  * @val:  an xmlNodePtr
   4058  *
   4059  * Removes an xmlNodePtr from an existing NodeSet
   4060  */
   4061 void
   4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4063     int i;
   4064 
   4065     if (cur == NULL) return;
   4066     if (val == NULL) return;
   4067 
   4068     /*
   4069      * find node in nodeTab
   4070      */
   4071     for (i = 0;i < cur->nodeNr;i++)
   4072         if (cur->nodeTab[i] == val) break;
   4073 
   4074     if (i >= cur->nodeNr) {	/* not found */
   4075 #ifdef DEBUG
   4076         xmlGenericError(xmlGenericErrorContext,
   4077 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4078 		val->name);
   4079 #endif
   4080         return;
   4081     }
   4082     if ((cur->nodeTab[i] != NULL) &&
   4083 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4084 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4085     cur->nodeNr--;
   4086     for (;i < cur->nodeNr;i++)
   4087         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4088     cur->nodeTab[cur->nodeNr] = NULL;
   4089 }
   4090 
   4091 /**
   4092  * xmlXPathNodeSetRemove:
   4093  * @cur:  the initial node set
   4094  * @val:  the index to remove
   4095  *
   4096  * Removes an entry from an existing NodeSet list.
   4097  */
   4098 void
   4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4100     if (cur == NULL) return;
   4101     if (val >= cur->nodeNr) return;
   4102     if ((cur->nodeTab[val] != NULL) &&
   4103 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4104 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4105     cur->nodeNr--;
   4106     for (;val < cur->nodeNr;val++)
   4107         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4108     cur->nodeTab[cur->nodeNr] = NULL;
   4109 }
   4110 
   4111 /**
   4112  * xmlXPathFreeNodeSet:
   4113  * @obj:  the xmlNodeSetPtr to free
   4114  *
   4115  * Free the NodeSet compound (not the actual nodes !).
   4116  */
   4117 void
   4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4119     if (obj == NULL) return;
   4120     if (obj->nodeTab != NULL) {
   4121 	int i;
   4122 
   4123 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4124 	for (i = 0;i < obj->nodeNr;i++)
   4125 	    if ((obj->nodeTab[i] != NULL) &&
   4126 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4127 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4128 	xmlFree(obj->nodeTab);
   4129     }
   4130     xmlFree(obj);
   4131 }
   4132 
   4133 /**
   4134  * xmlXPathNodeSetClear:
   4135  * @set:  the node set to clear
   4136  *
   4137  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4138  * are feed), but does *not* free the list itself. Sets the length of the
   4139  * list to 0.
   4140  */
   4141 static void
   4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4143 {
   4144     if ((set == NULL) || (set->nodeNr <= 0))
   4145 	return;
   4146     else if (hasNsNodes) {
   4147 	int i;
   4148 	xmlNodePtr node;
   4149 
   4150 	for (i = 0; i < set->nodeNr; i++) {
   4151 	    node = set->nodeTab[i];
   4152 	    if ((node != NULL) &&
   4153 		(node->type == XML_NAMESPACE_DECL))
   4154 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4155 	}
   4156     }
   4157     set->nodeNr = 0;
   4158 }
   4159 
   4160 /**
   4161  * xmlXPathNodeSetClearFromPos:
   4162  * @set: the node set to be cleared
   4163  * @pos: the start position to clear from
   4164  *
   4165  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4166  * are feed) starting with the entry at @pos, but does *not* free the list
   4167  * itself. Sets the length of the list to @pos.
   4168  */
   4169 static void
   4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4171 {
   4172     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4173 	return;
   4174     else if ((hasNsNodes)) {
   4175 	int i;
   4176 	xmlNodePtr node;
   4177 
   4178 	for (i = pos; i < set->nodeNr; i++) {
   4179 	    node = set->nodeTab[i];
   4180 	    if ((node != NULL) &&
   4181 		(node->type == XML_NAMESPACE_DECL))
   4182 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4183 	}
   4184     }
   4185     set->nodeNr = pos;
   4186 }
   4187 
   4188 /**
   4189  * xmlXPathFreeValueTree:
   4190  * @obj:  the xmlNodeSetPtr to free
   4191  *
   4192  * Free the NodeSet compound and the actual tree, this is different
   4193  * from xmlXPathFreeNodeSet()
   4194  */
   4195 static void
   4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4197     int i;
   4198 
   4199     if (obj == NULL) return;
   4200 
   4201     if (obj->nodeTab != NULL) {
   4202 	for (i = 0;i < obj->nodeNr;i++) {
   4203 	    if (obj->nodeTab[i] != NULL) {
   4204 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4205 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4206 		} else {
   4207 		    xmlFreeNodeList(obj->nodeTab[i]);
   4208 		}
   4209 	    }
   4210 	}
   4211 	xmlFree(obj->nodeTab);
   4212     }
   4213     xmlFree(obj);
   4214 }
   4215 
   4216 #if defined(DEBUG) || defined(DEBUG_STEP)
   4217 /**
   4218  * xmlGenericErrorContextNodeSet:
   4219  * @output:  a FILE * for the output
   4220  * @obj:  the xmlNodeSetPtr to display
   4221  *
   4222  * Quick display of a NodeSet
   4223  */
   4224 void
   4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4226     int i;
   4227 
   4228     if (output == NULL) output = xmlGenericErrorContext;
   4229     if (obj == NULL)  {
   4230         fprintf(output, "NodeSet == NULL !\n");
   4231 	return;
   4232     }
   4233     if (obj->nodeNr == 0) {
   4234         fprintf(output, "NodeSet is empty\n");
   4235 	return;
   4236     }
   4237     if (obj->nodeTab == NULL) {
   4238 	fprintf(output, " nodeTab == NULL !\n");
   4239 	return;
   4240     }
   4241     for (i = 0; i < obj->nodeNr; i++) {
   4242         if (obj->nodeTab[i] == NULL) {
   4243 	    fprintf(output, " NULL !\n");
   4244 	    return;
   4245         }
   4246 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4247 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4248 	    fprintf(output, " /");
   4249 	else if (obj->nodeTab[i]->name == NULL)
   4250 	    fprintf(output, " noname!");
   4251 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4252     }
   4253     fprintf(output, "\n");
   4254 }
   4255 #endif
   4256 
   4257 /**
   4258  * xmlXPathNewNodeSet:
   4259  * @val:  the NodePtr value
   4260  *
   4261  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4262  * it with the single Node @val
   4263  *
   4264  * Returns the newly created object.
   4265  */
   4266 xmlXPathObjectPtr
   4267 xmlXPathNewNodeSet(xmlNodePtr val) {
   4268     xmlXPathObjectPtr ret;
   4269 
   4270     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4271     if (ret == NULL) {
   4272         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4273 	return(NULL);
   4274     }
   4275     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4276     ret->type = XPATH_NODESET;
   4277     ret->boolval = 0;
   4278     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4279     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4280 #ifdef XP_DEBUG_OBJ_USAGE
   4281     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4282 #endif
   4283     return(ret);
   4284 }
   4285 
   4286 /**
   4287  * xmlXPathNewValueTree:
   4288  * @val:  the NodePtr value
   4289  *
   4290  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4291  * it with the tree root @val
   4292  *
   4293  * Returns the newly created object.
   4294  */
   4295 xmlXPathObjectPtr
   4296 xmlXPathNewValueTree(xmlNodePtr val) {
   4297     xmlXPathObjectPtr ret;
   4298 
   4299     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4300     if (ret == NULL) {
   4301         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4302 	return(NULL);
   4303     }
   4304     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4305     ret->type = XPATH_XSLT_TREE;
   4306     ret->boolval = 1;
   4307     ret->user = (void *) val;
   4308     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4309 #ifdef XP_DEBUG_OBJ_USAGE
   4310     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4311 #endif
   4312     return(ret);
   4313 }
   4314 
   4315 /**
   4316  * xmlXPathNewNodeSetList:
   4317  * @val:  an existing NodeSet
   4318  *
   4319  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4320  * it with the Nodeset @val
   4321  *
   4322  * Returns the newly created object.
   4323  */
   4324 xmlXPathObjectPtr
   4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4326 {
   4327     xmlXPathObjectPtr ret;
   4328     int i;
   4329 
   4330     if (val == NULL)
   4331         ret = NULL;
   4332     else if (val->nodeTab == NULL)
   4333         ret = xmlXPathNewNodeSet(NULL);
   4334     else {
   4335         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4336         if (ret)
   4337             for (i = 1; i < val->nodeNr; ++i)
   4338                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
   4339     }
   4340 
   4341     return (ret);
   4342 }
   4343 
   4344 /**
   4345  * xmlXPathWrapNodeSet:
   4346  * @val:  the NodePtr value
   4347  *
   4348  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4349  *
   4350  * Returns the newly created object.
   4351  */
   4352 xmlXPathObjectPtr
   4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4354     xmlXPathObjectPtr ret;
   4355 
   4356     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4357     if (ret == NULL) {
   4358         xmlXPathErrMemory(NULL, "creating node set object\n");
   4359 	return(NULL);
   4360     }
   4361     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4362     ret->type = XPATH_NODESET;
   4363     ret->nodesetval = val;
   4364 #ifdef XP_DEBUG_OBJ_USAGE
   4365     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4366 #endif
   4367     return(ret);
   4368 }
   4369 
   4370 /**
   4371  * xmlXPathFreeNodeSetList:
   4372  * @obj:  an existing NodeSetList object
   4373  *
   4374  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4375  * the list contrary to xmlXPathFreeObject().
   4376  */
   4377 void
   4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4379     if (obj == NULL) return;
   4380 #ifdef XP_DEBUG_OBJ_USAGE
   4381     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4382 #endif
   4383     xmlFree(obj);
   4384 }
   4385 
   4386 /**
   4387  * xmlXPathDifference:
   4388  * @nodes1:  a node-set
   4389  * @nodes2:  a node-set
   4390  *
   4391  * Implements the EXSLT - Sets difference() function:
   4392  *    node-set set:difference (node-set, node-set)
   4393  *
   4394  * Returns the difference between the two node sets, or nodes1 if
   4395  *         nodes2 is empty
   4396  */
   4397 xmlNodeSetPtr
   4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4399     xmlNodeSetPtr ret;
   4400     int i, l1;
   4401     xmlNodePtr cur;
   4402 
   4403     if (xmlXPathNodeSetIsEmpty(nodes2))
   4404 	return(nodes1);
   4405 
   4406     ret = xmlXPathNodeSetCreate(NULL);
   4407     if (xmlXPathNodeSetIsEmpty(nodes1))
   4408 	return(ret);
   4409 
   4410     l1 = xmlXPathNodeSetGetLength(nodes1);
   4411 
   4412     for (i = 0; i < l1; i++) {
   4413 	cur = xmlXPathNodeSetItem(nodes1, i);
   4414 	if (!xmlXPathNodeSetContains(nodes2, cur))
   4415 	    xmlXPathNodeSetAddUnique(ret, cur);
   4416     }
   4417     return(ret);
   4418 }
   4419 
   4420 /**
   4421  * xmlXPathIntersection:
   4422  * @nodes1:  a node-set
   4423  * @nodes2:  a node-set
   4424  *
   4425  * Implements the EXSLT - Sets intersection() function:
   4426  *    node-set set:intersection (node-set, node-set)
   4427  *
   4428  * Returns a node set comprising the nodes that are within both the
   4429  *         node sets passed as arguments
   4430  */
   4431 xmlNodeSetPtr
   4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4433     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4434     int i, l1;
   4435     xmlNodePtr cur;
   4436 
   4437     if (ret == NULL)
   4438         return(ret);
   4439     if (xmlXPathNodeSetIsEmpty(nodes1))
   4440 	return(ret);
   4441     if (xmlXPathNodeSetIsEmpty(nodes2))
   4442 	return(ret);
   4443 
   4444     l1 = xmlXPathNodeSetGetLength(nodes1);
   4445 
   4446     for (i = 0; i < l1; i++) {
   4447 	cur = xmlXPathNodeSetItem(nodes1, i);
   4448 	if (xmlXPathNodeSetContains(nodes2, cur))
   4449 	    xmlXPathNodeSetAddUnique(ret, cur);
   4450     }
   4451     return(ret);
   4452 }
   4453 
   4454 /**
   4455  * xmlXPathDistinctSorted:
   4456  * @nodes:  a node-set, sorted by document order
   4457  *
   4458  * Implements the EXSLT - Sets distinct() function:
   4459  *    node-set set:distinct (node-set)
   4460  *
   4461  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4462  *         it is empty
   4463  */
   4464 xmlNodeSetPtr
   4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4466     xmlNodeSetPtr ret;
   4467     xmlHashTablePtr hash;
   4468     int i, l;
   4469     xmlChar * strval;
   4470     xmlNodePtr cur;
   4471 
   4472     if (xmlXPathNodeSetIsEmpty(nodes))
   4473 	return(nodes);
   4474 
   4475     ret = xmlXPathNodeSetCreate(NULL);
   4476     if (ret == NULL)
   4477         return(ret);
   4478     l = xmlXPathNodeSetGetLength(nodes);
   4479     hash = xmlHashCreate (l);
   4480     for (i = 0; i < l; i++) {
   4481 	cur = xmlXPathNodeSetItem(nodes, i);
   4482 	strval = xmlXPathCastNodeToString(cur);
   4483 	if (xmlHashLookup(hash, strval) == NULL) {
   4484 	    xmlHashAddEntry(hash, strval, strval);
   4485 	    xmlXPathNodeSetAddUnique(ret, cur);
   4486 	} else {
   4487 	    xmlFree(strval);
   4488 	}
   4489     }
   4490     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4491     return(ret);
   4492 }
   4493 
   4494 /**
   4495  * xmlXPathDistinct:
   4496  * @nodes:  a node-set
   4497  *
   4498  * Implements the EXSLT - Sets distinct() function:
   4499  *    node-set set:distinct (node-set)
   4500  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4501  * is called with the sorted node-set
   4502  *
   4503  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4504  *         it is empty
   4505  */
   4506 xmlNodeSetPtr
   4507 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4508     if (xmlXPathNodeSetIsEmpty(nodes))
   4509 	return(nodes);
   4510 
   4511     xmlXPathNodeSetSort(nodes);
   4512     return(xmlXPathDistinctSorted(nodes));
   4513 }
   4514 
   4515 /**
   4516  * xmlXPathHasSameNodes:
   4517  * @nodes1:  a node-set
   4518  * @nodes2:  a node-set
   4519  *
   4520  * Implements the EXSLT - Sets has-same-nodes function:
   4521  *    boolean set:has-same-node(node-set, node-set)
   4522  *
   4523  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4524  *         otherwise
   4525  */
   4526 int
   4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4528     int i, l;
   4529     xmlNodePtr cur;
   4530 
   4531     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4532 	xmlXPathNodeSetIsEmpty(nodes2))
   4533 	return(0);
   4534 
   4535     l = xmlXPathNodeSetGetLength(nodes1);
   4536     for (i = 0; i < l; i++) {
   4537 	cur = xmlXPathNodeSetItem(nodes1, i);
   4538 	if (xmlXPathNodeSetContains(nodes2, cur))
   4539 	    return(1);
   4540     }
   4541     return(0);
   4542 }
   4543 
   4544 /**
   4545  * xmlXPathNodeLeadingSorted:
   4546  * @nodes: a node-set, sorted by document order
   4547  * @node: a node
   4548  *
   4549  * Implements the EXSLT - Sets leading() function:
   4550  *    node-set set:leading (node-set, node-set)
   4551  *
   4552  * Returns the nodes in @nodes that precede @node in document order,
   4553  *         @nodes if @node is NULL or an empty node-set if @nodes
   4554  *         doesn't contain @node
   4555  */
   4556 xmlNodeSetPtr
   4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4558     int i, l;
   4559     xmlNodePtr cur;
   4560     xmlNodeSetPtr ret;
   4561 
   4562     if (node == NULL)
   4563 	return(nodes);
   4564 
   4565     ret = xmlXPathNodeSetCreate(NULL);
   4566     if (ret == NULL)
   4567         return(ret);
   4568     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4569 	(!xmlXPathNodeSetContains(nodes, node)))
   4570 	return(ret);
   4571 
   4572     l = xmlXPathNodeSetGetLength(nodes);
   4573     for (i = 0; i < l; i++) {
   4574 	cur = xmlXPathNodeSetItem(nodes, i);
   4575 	if (cur == node)
   4576 	    break;
   4577 	xmlXPathNodeSetAddUnique(ret, cur);
   4578     }
   4579     return(ret);
   4580 }
   4581 
   4582 /**
   4583  * xmlXPathNodeLeading:
   4584  * @nodes:  a node-set
   4585  * @node:  a node
   4586  *
   4587  * Implements the EXSLT - Sets leading() function:
   4588  *    node-set set:leading (node-set, node-set)
   4589  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4590  * is called.
   4591  *
   4592  * Returns the nodes in @nodes that precede @node in document order,
   4593  *         @nodes if @node is NULL or an empty node-set if @nodes
   4594  *         doesn't contain @node
   4595  */
   4596 xmlNodeSetPtr
   4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4598     xmlXPathNodeSetSort(nodes);
   4599     return(xmlXPathNodeLeadingSorted(nodes, node));
   4600 }
   4601 
   4602 /**
   4603  * xmlXPathLeadingSorted:
   4604  * @nodes1:  a node-set, sorted by document order
   4605  * @nodes2:  a node-set, sorted by document order
   4606  *
   4607  * Implements the EXSLT - Sets leading() function:
   4608  *    node-set set:leading (node-set, node-set)
   4609  *
   4610  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4611  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4612  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4613  */
   4614 xmlNodeSetPtr
   4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4616     if (xmlXPathNodeSetIsEmpty(nodes2))
   4617 	return(nodes1);
   4618     return(xmlXPathNodeLeadingSorted(nodes1,
   4619 				     xmlXPathNodeSetItem(nodes2, 1)));
   4620 }
   4621 
   4622 /**
   4623  * xmlXPathLeading:
   4624  * @nodes1:  a node-set
   4625  * @nodes2:  a node-set
   4626  *
   4627  * Implements the EXSLT - Sets leading() function:
   4628  *    node-set set:leading (node-set, node-set)
   4629  * @nodes1 and @nodes2 are sorted by document order, then
   4630  * #exslSetsLeadingSorted is called.
   4631  *
   4632  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4633  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4634  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4635  */
   4636 xmlNodeSetPtr
   4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4638     if (xmlXPathNodeSetIsEmpty(nodes2))
   4639 	return(nodes1);
   4640     if (xmlXPathNodeSetIsEmpty(nodes1))
   4641 	return(xmlXPathNodeSetCreate(NULL));
   4642     xmlXPathNodeSetSort(nodes1);
   4643     xmlXPathNodeSetSort(nodes2);
   4644     return(xmlXPathNodeLeadingSorted(nodes1,
   4645 				     xmlXPathNodeSetItem(nodes2, 1)));
   4646 }
   4647 
   4648 /**
   4649  * xmlXPathNodeTrailingSorted:
   4650  * @nodes: a node-set, sorted by document order
   4651  * @node: a node
   4652  *
   4653  * Implements the EXSLT - Sets trailing() function:
   4654  *    node-set set:trailing (node-set, node-set)
   4655  *
   4656  * Returns the nodes in @nodes that follow @node in document order,
   4657  *         @nodes if @node is NULL or an empty node-set if @nodes
   4658  *         doesn't contain @node
   4659  */
   4660 xmlNodeSetPtr
   4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4662     int i, l;
   4663     xmlNodePtr cur;
   4664     xmlNodeSetPtr ret;
   4665 
   4666     if (node == NULL)
   4667 	return(nodes);
   4668 
   4669     ret = xmlXPathNodeSetCreate(NULL);
   4670     if (ret == NULL)
   4671         return(ret);
   4672     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4673 	(!xmlXPathNodeSetContains(nodes, node)))
   4674 	return(ret);
   4675 
   4676     l = xmlXPathNodeSetGetLength(nodes);
   4677     for (i = l - 1; i >= 0; i--) {
   4678 	cur = xmlXPathNodeSetItem(nodes, i);
   4679 	if (cur == node)
   4680 	    break;
   4681 	xmlXPathNodeSetAddUnique(ret, cur);
   4682     }
   4683     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4684     return(ret);
   4685 }
   4686 
   4687 /**
   4688  * xmlXPathNodeTrailing:
   4689  * @nodes:  a node-set
   4690  * @node:  a node
   4691  *
   4692  * Implements the EXSLT - Sets trailing() function:
   4693  *    node-set set:trailing (node-set, node-set)
   4694  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4695  * is called.
   4696  *
   4697  * Returns the nodes in @nodes that follow @node in document order,
   4698  *         @nodes if @node is NULL or an empty node-set if @nodes
   4699  *         doesn't contain @node
   4700  */
   4701 xmlNodeSetPtr
   4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4703     xmlXPathNodeSetSort(nodes);
   4704     return(xmlXPathNodeTrailingSorted(nodes, node));
   4705 }
   4706 
   4707 /**
   4708  * xmlXPathTrailingSorted:
   4709  * @nodes1:  a node-set, sorted by document order
   4710  * @nodes2:  a node-set, sorted by document order
   4711  *
   4712  * Implements the EXSLT - Sets trailing() function:
   4713  *    node-set set:trailing (node-set, node-set)
   4714  *
   4715  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4716  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4717  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4718  */
   4719 xmlNodeSetPtr
   4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4721     if (xmlXPathNodeSetIsEmpty(nodes2))
   4722 	return(nodes1);
   4723     return(xmlXPathNodeTrailingSorted(nodes1,
   4724 				      xmlXPathNodeSetItem(nodes2, 0)));
   4725 }
   4726 
   4727 /**
   4728  * xmlXPathTrailing:
   4729  * @nodes1:  a node-set
   4730  * @nodes2:  a node-set
   4731  *
   4732  * Implements the EXSLT - Sets trailing() function:
   4733  *    node-set set:trailing (node-set, node-set)
   4734  * @nodes1 and @nodes2 are sorted by document order, then
   4735  * #xmlXPathTrailingSorted is called.
   4736  *
   4737  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4738  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4739  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4740  */
   4741 xmlNodeSetPtr
   4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4743     if (xmlXPathNodeSetIsEmpty(nodes2))
   4744 	return(nodes1);
   4745     if (xmlXPathNodeSetIsEmpty(nodes1))
   4746 	return(xmlXPathNodeSetCreate(NULL));
   4747     xmlXPathNodeSetSort(nodes1);
   4748     xmlXPathNodeSetSort(nodes2);
   4749     return(xmlXPathNodeTrailingSorted(nodes1,
   4750 				      xmlXPathNodeSetItem(nodes2, 0)));
   4751 }
   4752 
   4753 /************************************************************************
   4754  *									*
   4755  *		Routines to handle extra functions			*
   4756  *									*
   4757  ************************************************************************/
   4758 
   4759 /**
   4760  * xmlXPathRegisterFunc:
   4761  * @ctxt:  the XPath context
   4762  * @name:  the function name
   4763  * @f:  the function implementation or NULL
   4764  *
   4765  * Register a new function. If @f is NULL it unregisters the function
   4766  *
   4767  * Returns 0 in case of success, -1 in case of error
   4768  */
   4769 int
   4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4771 		     xmlXPathFunction f) {
   4772     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4773 }
   4774 
   4775 /**
   4776  * xmlXPathRegisterFuncNS:
   4777  * @ctxt:  the XPath context
   4778  * @name:  the function name
   4779  * @ns_uri:  the function namespace URI
   4780  * @f:  the function implementation or NULL
   4781  *
   4782  * Register a new function. If @f is NULL it unregisters the function
   4783  *
   4784  * Returns 0 in case of success, -1 in case of error
   4785  */
   4786 int
   4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4788 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4789     if (ctxt == NULL)
   4790 	return(-1);
   4791     if (name == NULL)
   4792 	return(-1);
   4793 
   4794     if (ctxt->funcHash == NULL)
   4795 	ctxt->funcHash = xmlHashCreate(0);
   4796     if (ctxt->funcHash == NULL)
   4797 	return(-1);
   4798     if (f == NULL)
   4799         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4800     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
   4801 }
   4802 
   4803 /**
   4804  * xmlXPathRegisterFuncLookup:
   4805  * @ctxt:  the XPath context
   4806  * @f:  the lookup function
   4807  * @funcCtxt:  the lookup data
   4808  *
   4809  * Registers an external mechanism to do function lookup.
   4810  */
   4811 void
   4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4813 			    xmlXPathFuncLookupFunc f,
   4814 			    void *funcCtxt) {
   4815     if (ctxt == NULL)
   4816 	return;
   4817     ctxt->funcLookupFunc = f;
   4818     ctxt->funcLookupData = funcCtxt;
   4819 }
   4820 
   4821 /**
   4822  * xmlXPathFunctionLookup:
   4823  * @ctxt:  the XPath context
   4824  * @name:  the function name
   4825  *
   4826  * Search in the Function array of the context for the given
   4827  * function.
   4828  *
   4829  * Returns the xmlXPathFunction or NULL if not found
   4830  */
   4831 xmlXPathFunction
   4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4833     if (ctxt == NULL)
   4834 	return (NULL);
   4835 
   4836     if (ctxt->funcLookupFunc != NULL) {
   4837 	xmlXPathFunction ret;
   4838 	xmlXPathFuncLookupFunc f;
   4839 
   4840 	f = ctxt->funcLookupFunc;
   4841 	ret = f(ctxt->funcLookupData, name, NULL);
   4842 	if (ret != NULL)
   4843 	    return(ret);
   4844     }
   4845     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4846 }
   4847 
   4848 /**
   4849  * xmlXPathFunctionLookupNS:
   4850  * @ctxt:  the XPath context
   4851  * @name:  the function name
   4852  * @ns_uri:  the function namespace URI
   4853  *
   4854  * Search in the Function array of the context for the given
   4855  * function.
   4856  *
   4857  * Returns the xmlXPathFunction or NULL if not found
   4858  */
   4859 xmlXPathFunction
   4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4861 			 const xmlChar *ns_uri) {
   4862     xmlXPathFunction ret;
   4863 
   4864     if (ctxt == NULL)
   4865 	return(NULL);
   4866     if (name == NULL)
   4867 	return(NULL);
   4868 
   4869     if (ctxt->funcLookupFunc != NULL) {
   4870 	xmlXPathFuncLookupFunc f;
   4871 
   4872 	f = ctxt->funcLookupFunc;
   4873 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4874 	if (ret != NULL)
   4875 	    return(ret);
   4876     }
   4877 
   4878     if (ctxt->funcHash == NULL)
   4879 	return(NULL);
   4880 
   4881     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4882     return(ret);
   4883 }
   4884 
   4885 /**
   4886  * xmlXPathRegisteredFuncsCleanup:
   4887  * @ctxt:  the XPath context
   4888  *
   4889  * Cleanup the XPath context data associated to registered functions
   4890  */
   4891 void
   4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4893     if (ctxt == NULL)
   4894 	return;
   4895 
   4896     xmlHashFree(ctxt->funcHash, NULL);
   4897     ctxt->funcHash = NULL;
   4898 }
   4899 
   4900 /************************************************************************
   4901  *									*
   4902  *			Routines to handle Variables			*
   4903  *									*
   4904  ************************************************************************/
   4905 
   4906 /**
   4907  * xmlXPathRegisterVariable:
   4908  * @ctxt:  the XPath context
   4909  * @name:  the variable name
   4910  * @value:  the variable value or NULL
   4911  *
   4912  * Register a new variable value. If @value is NULL it unregisters
   4913  * the variable
   4914  *
   4915  * Returns 0 in case of success, -1 in case of error
   4916  */
   4917 int
   4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   4919 			 xmlXPathObjectPtr value) {
   4920     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   4921 }
   4922 
   4923 /**
   4924  * xmlXPathRegisterVariableNS:
   4925  * @ctxt:  the XPath context
   4926  * @name:  the variable name
   4927  * @ns_uri:  the variable namespace URI
   4928  * @value:  the variable value or NULL
   4929  *
   4930  * Register a new variable value. If @value is NULL it unregisters
   4931  * the variable
   4932  *
   4933  * Returns 0 in case of success, -1 in case of error
   4934  */
   4935 int
   4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4937 			   const xmlChar *ns_uri,
   4938 			   xmlXPathObjectPtr value) {
   4939     if (ctxt == NULL)
   4940 	return(-1);
   4941     if (name == NULL)
   4942 	return(-1);
   4943 
   4944     if (ctxt->varHash == NULL)
   4945 	ctxt->varHash = xmlHashCreate(0);
   4946     if (ctxt->varHash == NULL)
   4947 	return(-1);
   4948     if (value == NULL)
   4949         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   4950 	                           (xmlHashDeallocator)xmlXPathFreeObject));
   4951     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   4952 			       (void *) value,
   4953 			       (xmlHashDeallocator)xmlXPathFreeObject));
   4954 }
   4955 
   4956 /**
   4957  * xmlXPathRegisterVariableLookup:
   4958  * @ctxt:  the XPath context
   4959  * @f:  the lookup function
   4960  * @data:  the lookup data
   4961  *
   4962  * register an external mechanism to do variable lookup
   4963  */
   4964 void
   4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   4966 	 xmlXPathVariableLookupFunc f, void *data) {
   4967     if (ctxt == NULL)
   4968 	return;
   4969     ctxt->varLookupFunc = f;
   4970     ctxt->varLookupData = data;
   4971 }
   4972 
   4973 /**
   4974  * xmlXPathVariableLookup:
   4975  * @ctxt:  the XPath context
   4976  * @name:  the variable name
   4977  *
   4978  * Search in the Variable array of the context for the given
   4979  * variable value.
   4980  *
   4981  * Returns a copy of the value or NULL if not found
   4982  */
   4983 xmlXPathObjectPtr
   4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4985     if (ctxt == NULL)
   4986 	return(NULL);
   4987 
   4988     if (ctxt->varLookupFunc != NULL) {
   4989 	xmlXPathObjectPtr ret;
   4990 
   4991 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   4992 	        (ctxt->varLookupData, name, NULL);
   4993 	return(ret);
   4994     }
   4995     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   4996 }
   4997 
   4998 /**
   4999  * xmlXPathVariableLookupNS:
   5000  * @ctxt:  the XPath context
   5001  * @name:  the variable name
   5002  * @ns_uri:  the variable namespace URI
   5003  *
   5004  * Search in the Variable array of the context for the given
   5005  * variable value.
   5006  *
   5007  * Returns the a copy of the value or NULL if not found
   5008  */
   5009 xmlXPathObjectPtr
   5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5011 			 const xmlChar *ns_uri) {
   5012     if (ctxt == NULL)
   5013 	return(NULL);
   5014 
   5015     if (ctxt->varLookupFunc != NULL) {
   5016 	xmlXPathObjectPtr ret;
   5017 
   5018 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5019 	        (ctxt->varLookupData, name, ns_uri);
   5020 	if (ret != NULL) return(ret);
   5021     }
   5022 
   5023     if (ctxt->varHash == NULL)
   5024 	return(NULL);
   5025     if (name == NULL)
   5026 	return(NULL);
   5027 
   5028     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   5029 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   5030 }
   5031 
   5032 /**
   5033  * xmlXPathRegisteredVariablesCleanup:
   5034  * @ctxt:  the XPath context
   5035  *
   5036  * Cleanup the XPath context data associated to registered variables
   5037  */
   5038 void
   5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   5040     if (ctxt == NULL)
   5041 	return;
   5042 
   5043     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
   5044     ctxt->varHash = NULL;
   5045 }
   5046 
   5047 /**
   5048  * xmlXPathRegisterNs:
   5049  * @ctxt:  the XPath context
   5050  * @prefix:  the namespace prefix cannot be NULL or empty string
   5051  * @ns_uri:  the namespace name
   5052  *
   5053  * Register a new namespace. If @ns_uri is NULL it unregisters
   5054  * the namespace
   5055  *
   5056  * Returns 0 in case of success, -1 in case of error
   5057  */
   5058 int
   5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5060 			   const xmlChar *ns_uri) {
   5061     if (ctxt == NULL)
   5062 	return(-1);
   5063     if (prefix == NULL)
   5064 	return(-1);
   5065     if (prefix[0] == 0)
   5066 	return(-1);
   5067 
   5068     if (ctxt->nsHash == NULL)
   5069 	ctxt->nsHash = xmlHashCreate(10);
   5070     if (ctxt->nsHash == NULL)
   5071 	return(-1);
   5072     if (ns_uri == NULL)
   5073         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5074 	                          (xmlHashDeallocator)xmlFree));
   5075     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5076 			      (xmlHashDeallocator)xmlFree));
   5077 }
   5078 
   5079 /**
   5080  * xmlXPathNsLookup:
   5081  * @ctxt:  the XPath context
   5082  * @prefix:  the namespace prefix value
   5083  *
   5084  * Search in the namespace declaration array of the context for the given
   5085  * namespace name associated to the given prefix
   5086  *
   5087  * Returns the value or NULL if not found
   5088  */
   5089 const xmlChar *
   5090 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5091     if (ctxt == NULL)
   5092 	return(NULL);
   5093     if (prefix == NULL)
   5094 	return(NULL);
   5095 
   5096 #ifdef XML_XML_NAMESPACE
   5097     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5098 	return(XML_XML_NAMESPACE);
   5099 #endif
   5100 
   5101     if (ctxt->namespaces != NULL) {
   5102 	int i;
   5103 
   5104 	for (i = 0;i < ctxt->nsNr;i++) {
   5105 	    if ((ctxt->namespaces[i] != NULL) &&
   5106 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5107 		return(ctxt->namespaces[i]->href);
   5108 	}
   5109     }
   5110 
   5111     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5112 }
   5113 
   5114 /**
   5115  * xmlXPathRegisteredNsCleanup:
   5116  * @ctxt:  the XPath context
   5117  *
   5118  * Cleanup the XPath context data associated to registered variables
   5119  */
   5120 void
   5121 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5122     if (ctxt == NULL)
   5123 	return;
   5124 
   5125     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
   5126     ctxt->nsHash = NULL;
   5127 }
   5128 
   5129 /************************************************************************
   5130  *									*
   5131  *			Routines to handle Values			*
   5132  *									*
   5133  ************************************************************************/
   5134 
   5135 /* Allocations are terrible, one needs to optimize all this !!! */
   5136 
   5137 /**
   5138  * xmlXPathNewFloat:
   5139  * @val:  the double value
   5140  *
   5141  * Create a new xmlXPathObjectPtr of type double and of value @val
   5142  *
   5143  * Returns the newly created object.
   5144  */
   5145 xmlXPathObjectPtr
   5146 xmlXPathNewFloat(double val) {
   5147     xmlXPathObjectPtr ret;
   5148 
   5149     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5150     if (ret == NULL) {
   5151         xmlXPathErrMemory(NULL, "creating float object\n");
   5152 	return(NULL);
   5153     }
   5154     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5155     ret->type = XPATH_NUMBER;
   5156     ret->floatval = val;
   5157 #ifdef XP_DEBUG_OBJ_USAGE
   5158     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5159 #endif
   5160     return(ret);
   5161 }
   5162 
   5163 /**
   5164  * xmlXPathNewBoolean:
   5165  * @val:  the boolean value
   5166  *
   5167  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5168  *
   5169  * Returns the newly created object.
   5170  */
   5171 xmlXPathObjectPtr
   5172 xmlXPathNewBoolean(int val) {
   5173     xmlXPathObjectPtr ret;
   5174 
   5175     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5176     if (ret == NULL) {
   5177         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5178 	return(NULL);
   5179     }
   5180     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5181     ret->type = XPATH_BOOLEAN;
   5182     ret->boolval = (val != 0);
   5183 #ifdef XP_DEBUG_OBJ_USAGE
   5184     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5185 #endif
   5186     return(ret);
   5187 }
   5188 
   5189 /**
   5190  * xmlXPathNewString:
   5191  * @val:  the xmlChar * value
   5192  *
   5193  * Create a new xmlXPathObjectPtr of type string and of value @val
   5194  *
   5195  * Returns the newly created object.
   5196  */
   5197 xmlXPathObjectPtr
   5198 xmlXPathNewString(const xmlChar *val) {
   5199     xmlXPathObjectPtr ret;
   5200 
   5201     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5202     if (ret == NULL) {
   5203         xmlXPathErrMemory(NULL, "creating string object\n");
   5204 	return(NULL);
   5205     }
   5206     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5207     ret->type = XPATH_STRING;
   5208     if (val != NULL)
   5209 	ret->stringval = xmlStrdup(val);
   5210     else
   5211 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5212 #ifdef XP_DEBUG_OBJ_USAGE
   5213     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5214 #endif
   5215     return(ret);
   5216 }
   5217 
   5218 /**
   5219  * xmlXPathWrapString:
   5220  * @val:  the xmlChar * value
   5221  *
   5222  * Wraps the @val string into an XPath object.
   5223  *
   5224  * Returns the newly created object.
   5225  */
   5226 xmlXPathObjectPtr
   5227 xmlXPathWrapString (xmlChar *val) {
   5228     xmlXPathObjectPtr ret;
   5229 
   5230     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5231     if (ret == NULL) {
   5232         xmlXPathErrMemory(NULL, "creating string object\n");
   5233 	return(NULL);
   5234     }
   5235     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5236     ret->type = XPATH_STRING;
   5237     ret->stringval = val;
   5238 #ifdef XP_DEBUG_OBJ_USAGE
   5239     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5240 #endif
   5241     return(ret);
   5242 }
   5243 
   5244 /**
   5245  * xmlXPathNewCString:
   5246  * @val:  the char * value
   5247  *
   5248  * Create a new xmlXPathObjectPtr of type string and of value @val
   5249  *
   5250  * Returns the newly created object.
   5251  */
   5252 xmlXPathObjectPtr
   5253 xmlXPathNewCString(const char *val) {
   5254     xmlXPathObjectPtr ret;
   5255 
   5256     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5257     if (ret == NULL) {
   5258         xmlXPathErrMemory(NULL, "creating string object\n");
   5259 	return(NULL);
   5260     }
   5261     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5262     ret->type = XPATH_STRING;
   5263     ret->stringval = xmlStrdup(BAD_CAST val);
   5264 #ifdef XP_DEBUG_OBJ_USAGE
   5265     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5266 #endif
   5267     return(ret);
   5268 }
   5269 
   5270 /**
   5271  * xmlXPathWrapCString:
   5272  * @val:  the char * value
   5273  *
   5274  * Wraps a string into an XPath object.
   5275  *
   5276  * Returns the newly created object.
   5277  */
   5278 xmlXPathObjectPtr
   5279 xmlXPathWrapCString (char * val) {
   5280     return(xmlXPathWrapString((xmlChar *)(val)));
   5281 }
   5282 
   5283 /**
   5284  * xmlXPathWrapExternal:
   5285  * @val:  the user data
   5286  *
   5287  * Wraps the @val data into an XPath object.
   5288  *
   5289  * Returns the newly created object.
   5290  */
   5291 xmlXPathObjectPtr
   5292 xmlXPathWrapExternal (void *val) {
   5293     xmlXPathObjectPtr ret;
   5294 
   5295     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5296     if (ret == NULL) {
   5297         xmlXPathErrMemory(NULL, "creating user object\n");
   5298 	return(NULL);
   5299     }
   5300     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5301     ret->type = XPATH_USERS;
   5302     ret->user = val;
   5303 #ifdef XP_DEBUG_OBJ_USAGE
   5304     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5305 #endif
   5306     return(ret);
   5307 }
   5308 
   5309 /**
   5310  * xmlXPathObjectCopy:
   5311  * @val:  the original object
   5312  *
   5313  * allocate a new copy of a given object
   5314  *
   5315  * Returns the newly created object.
   5316  */
   5317 xmlXPathObjectPtr
   5318 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5319     xmlXPathObjectPtr ret;
   5320 
   5321     if (val == NULL)
   5322 	return(NULL);
   5323 
   5324     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5325     if (ret == NULL) {
   5326         xmlXPathErrMemory(NULL, "copying object\n");
   5327 	return(NULL);
   5328     }
   5329     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5330 #ifdef XP_DEBUG_OBJ_USAGE
   5331     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5332 #endif
   5333     switch (val->type) {
   5334 	case XPATH_BOOLEAN:
   5335 	case XPATH_NUMBER:
   5336 	case XPATH_POINT:
   5337 	case XPATH_RANGE:
   5338 	    break;
   5339 	case XPATH_STRING:
   5340 	    ret->stringval = xmlStrdup(val->stringval);
   5341 	    break;
   5342 	case XPATH_XSLT_TREE:
   5343 #if 0
   5344 /*
   5345   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5346   this previous handling is no longer correct, and can cause some serious
   5347   problems (ref. bug 145547)
   5348 */
   5349 	    if ((val->nodesetval != NULL) &&
   5350 		(val->nodesetval->nodeTab != NULL)) {
   5351 		xmlNodePtr cur, tmp;
   5352 		xmlDocPtr top;
   5353 
   5354 		ret->boolval = 1;
   5355 		top =  xmlNewDoc(NULL);
   5356 		top->name = (char *)
   5357 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5358 		ret->user = top;
   5359 		if (top != NULL) {
   5360 		    top->doc = top;
   5361 		    cur = val->nodesetval->nodeTab[0]->children;
   5362 		    while (cur != NULL) {
   5363 			tmp = xmlDocCopyNode(cur, top, 1);
   5364 			xmlAddChild((xmlNodePtr) top, tmp);
   5365 			cur = cur->next;
   5366 		    }
   5367 		}
   5368 
   5369 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5370 	    } else
   5371 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5372 	    /* Deallocate the copied tree value */
   5373 	    break;
   5374 #endif
   5375 	case XPATH_NODESET:
   5376 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5377 	    /* Do not deallocate the copied tree value */
   5378 	    ret->boolval = 0;
   5379 	    break;
   5380 	case XPATH_LOCATIONSET:
   5381 #ifdef LIBXML_XPTR_ENABLED
   5382 	{
   5383 	    xmlLocationSetPtr loc = val->user;
   5384 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5385 	    break;
   5386 	}
   5387 #endif
   5388         case XPATH_USERS:
   5389 	    ret->user = val->user;
   5390 	    break;
   5391         case XPATH_UNDEFINED:
   5392 	    xmlGenericError(xmlGenericErrorContext,
   5393 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5394 		    val->type);
   5395 	    break;
   5396     }
   5397     return(ret);
   5398 }
   5399 
   5400 /**
   5401  * xmlXPathFreeObject:
   5402  * @obj:  the object to free
   5403  *
   5404  * Free up an xmlXPathObjectPtr object.
   5405  */
   5406 void
   5407 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5408     if (obj == NULL) return;
   5409     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5410 	if (obj->boolval) {
   5411 #if 0
   5412 	    if (obj->user != NULL) {
   5413                 xmlXPathFreeNodeSet(obj->nodesetval);
   5414 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5415 	    } else
   5416 #endif
   5417 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5418 	    if (obj->nodesetval != NULL)
   5419 		xmlXPathFreeValueTree(obj->nodesetval);
   5420 	} else {
   5421 	    if (obj->nodesetval != NULL)
   5422 		xmlXPathFreeNodeSet(obj->nodesetval);
   5423 	}
   5424 #ifdef LIBXML_XPTR_ENABLED
   5425     } else if (obj->type == XPATH_LOCATIONSET) {
   5426 	if (obj->user != NULL)
   5427 	    xmlXPtrFreeLocationSet(obj->user);
   5428 #endif
   5429     } else if (obj->type == XPATH_STRING) {
   5430 	if (obj->stringval != NULL)
   5431 	    xmlFree(obj->stringval);
   5432     }
   5433 #ifdef XP_DEBUG_OBJ_USAGE
   5434     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5435 #endif
   5436     xmlFree(obj);
   5437 }
   5438 
   5439 /**
   5440  * xmlXPathReleaseObject:
   5441  * @obj:  the xmlXPathObjectPtr to free or to cache
   5442  *
   5443  * Depending on the state of the cache this frees the given
   5444  * XPath object or stores it in the cache.
   5445  */
   5446 static void
   5447 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5448 {
   5449 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5450 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5451     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5452 
   5453 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5454 
   5455     if (obj == NULL)
   5456 	return;
   5457     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5458 	 xmlXPathFreeObject(obj);
   5459     } else {
   5460 	xmlXPathContextCachePtr cache =
   5461 	    (xmlXPathContextCachePtr) ctxt->cache;
   5462 
   5463 	switch (obj->type) {
   5464 	    case XPATH_NODESET:
   5465 	    case XPATH_XSLT_TREE:
   5466 		if (obj->nodesetval != NULL) {
   5467 		    if (obj->boolval) {
   5468 			/*
   5469 			* It looks like the @boolval is used for
   5470 			* evaluation if this an XSLT Result Tree Fragment.
   5471 			* TODO: Check if this assumption is correct.
   5472 			*/
   5473 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5474 			xmlXPathFreeValueTree(obj->nodesetval);
   5475 			obj->nodesetval = NULL;
   5476 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5477 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5478 					cache->maxNodeset)))
   5479 		    {
   5480 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5481 			goto obj_cached;
   5482 		    } else {
   5483 			xmlXPathFreeNodeSet(obj->nodesetval);
   5484 			obj->nodesetval = NULL;
   5485 		    }
   5486 		}
   5487 		break;
   5488 	    case XPATH_STRING:
   5489 		if (obj->stringval != NULL)
   5490 		    xmlFree(obj->stringval);
   5491 
   5492 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5493 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5494 		    goto obj_cached;
   5495 		}
   5496 		break;
   5497 	    case XPATH_BOOLEAN:
   5498 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5499 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5500 		    goto obj_cached;
   5501 		}
   5502 		break;
   5503 	    case XPATH_NUMBER:
   5504 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5505 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5506 		    goto obj_cached;
   5507 		}
   5508 		break;
   5509 #ifdef LIBXML_XPTR_ENABLED
   5510 	    case XPATH_LOCATIONSET:
   5511 		if (obj->user != NULL) {
   5512 		    xmlXPtrFreeLocationSet(obj->user);
   5513 		}
   5514 		goto free_obj;
   5515 #endif
   5516 	    default:
   5517 		goto free_obj;
   5518 	}
   5519 
   5520 	/*
   5521 	* Fallback to adding to the misc-objects slot.
   5522 	*/
   5523 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5524 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5525 	} else
   5526 	    goto free_obj;
   5527 
   5528 obj_cached:
   5529 
   5530 #ifdef XP_DEBUG_OBJ_USAGE
   5531 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5532 #endif
   5533 
   5534 	if (obj->nodesetval != NULL) {
   5535 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5536 
   5537 	    /*
   5538 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5539 	    *  the list and free the ns-nodes.
   5540 	    * URGENT TODO: Check if it's actually slowing things down.
   5541 	    *  Maybe we shouldn't try to preserve the list.
   5542 	    */
   5543 	    if (tmpset->nodeNr > 1) {
   5544 		int i;
   5545 		xmlNodePtr node;
   5546 
   5547 		for (i = 0; i < tmpset->nodeNr; i++) {
   5548 		    node = tmpset->nodeTab[i];
   5549 		    if ((node != NULL) &&
   5550 			(node->type == XML_NAMESPACE_DECL))
   5551 		    {
   5552 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5553 		    }
   5554 		}
   5555 	    } else if (tmpset->nodeNr == 1) {
   5556 		if ((tmpset->nodeTab[0] != NULL) &&
   5557 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5558 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5559 	    }
   5560 	    tmpset->nodeNr = 0;
   5561 	    memset(obj, 0, sizeof(xmlXPathObject));
   5562 	    obj->nodesetval = tmpset;
   5563 	} else
   5564 	    memset(obj, 0, sizeof(xmlXPathObject));
   5565 
   5566 	return;
   5567 
   5568 free_obj:
   5569 	/*
   5570 	* Cache is full; free the object.
   5571 	*/
   5572 	if (obj->nodesetval != NULL)
   5573 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5574 #ifdef XP_DEBUG_OBJ_USAGE
   5575 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5576 #endif
   5577 	xmlFree(obj);
   5578     }
   5579     return;
   5580 }
   5581 
   5582 
   5583 /************************************************************************
   5584  *									*
   5585  *			Type Casting Routines				*
   5586  *									*
   5587  ************************************************************************/
   5588 
   5589 /**
   5590  * xmlXPathCastBooleanToString:
   5591  * @val:  a boolean
   5592  *
   5593  * Converts a boolean to its string value.
   5594  *
   5595  * Returns a newly allocated string.
   5596  */
   5597 xmlChar *
   5598 xmlXPathCastBooleanToString (int val) {
   5599     xmlChar *ret;
   5600     if (val)
   5601 	ret = xmlStrdup((const xmlChar *) "true");
   5602     else
   5603 	ret = xmlStrdup((const xmlChar *) "false");
   5604     return(ret);
   5605 }
   5606 
   5607 /**
   5608  * xmlXPathCastNumberToString:
   5609  * @val:  a number
   5610  *
   5611  * Converts a number to its string value.
   5612  *
   5613  * Returns a newly allocated string.
   5614  */
   5615 xmlChar *
   5616 xmlXPathCastNumberToString (double val) {
   5617     xmlChar *ret;
   5618     switch (xmlXPathIsInf(val)) {
   5619     case 1:
   5620 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5621 	break;
   5622     case -1:
   5623 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5624 	break;
   5625     default:
   5626 	if (xmlXPathIsNaN(val)) {
   5627 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5628 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
   5629 	    ret = xmlStrdup((const xmlChar *) "0");
   5630 	} else {
   5631 	    /* could be improved */
   5632 	    char buf[100];
   5633 	    xmlXPathFormatNumber(val, buf, 99);
   5634 	    buf[99] = 0;
   5635 	    ret = xmlStrdup((const xmlChar *) buf);
   5636 	}
   5637     }
   5638     return(ret);
   5639 }
   5640 
   5641 /**
   5642  * xmlXPathCastNodeToString:
   5643  * @node:  a node
   5644  *
   5645  * Converts a node to its string value.
   5646  *
   5647  * Returns a newly allocated string.
   5648  */
   5649 xmlChar *
   5650 xmlXPathCastNodeToString (xmlNodePtr node) {
   5651 xmlChar *ret;
   5652     if ((ret = xmlNodeGetContent(node)) == NULL)
   5653 	ret = xmlStrdup((const xmlChar *) "");
   5654     return(ret);
   5655 }
   5656 
   5657 /**
   5658  * xmlXPathCastNodeSetToString:
   5659  * @ns:  a node-set
   5660  *
   5661  * Converts a node-set to its string value.
   5662  *
   5663  * Returns a newly allocated string.
   5664  */
   5665 xmlChar *
   5666 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5667     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5668 	return(xmlStrdup((const xmlChar *) ""));
   5669 
   5670     if (ns->nodeNr > 1)
   5671 	xmlXPathNodeSetSort(ns);
   5672     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5673 }
   5674 
   5675 /**
   5676  * xmlXPathCastToString:
   5677  * @val:  an XPath object
   5678  *
   5679  * Converts an existing object to its string() equivalent
   5680  *
   5681  * Returns the allocated string value of the object, NULL in case of error.
   5682  *         It's up to the caller to free the string memory with xmlFree().
   5683  */
   5684 xmlChar *
   5685 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5686     xmlChar *ret = NULL;
   5687 
   5688     if (val == NULL)
   5689 	return(xmlStrdup((const xmlChar *) ""));
   5690     switch (val->type) {
   5691 	case XPATH_UNDEFINED:
   5692 #ifdef DEBUG_EXPR
   5693 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5694 #endif
   5695 	    ret = xmlStrdup((const xmlChar *) "");
   5696 	    break;
   5697         case XPATH_NODESET:
   5698         case XPATH_XSLT_TREE:
   5699 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5700 	    break;
   5701 	case XPATH_STRING:
   5702 	    return(xmlStrdup(val->stringval));
   5703         case XPATH_BOOLEAN:
   5704 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5705 	    break;
   5706 	case XPATH_NUMBER: {
   5707 	    ret = xmlXPathCastNumberToString(val->floatval);
   5708 	    break;
   5709 	}
   5710 	case XPATH_USERS:
   5711 	case XPATH_POINT:
   5712 	case XPATH_RANGE:
   5713 	case XPATH_LOCATIONSET:
   5714 	    TODO
   5715 	    ret = xmlStrdup((const xmlChar *) "");
   5716 	    break;
   5717     }
   5718     return(ret);
   5719 }
   5720 
   5721 /**
   5722  * xmlXPathConvertString:
   5723  * @val:  an XPath object
   5724  *
   5725  * Converts an existing object to its string() equivalent
   5726  *
   5727  * Returns the new object, the old one is freed (or the operation
   5728  *         is done directly on @val)
   5729  */
   5730 xmlXPathObjectPtr
   5731 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5732     xmlChar *res = NULL;
   5733 
   5734     if (val == NULL)
   5735 	return(xmlXPathNewCString(""));
   5736 
   5737     switch (val->type) {
   5738     case XPATH_UNDEFINED:
   5739 #ifdef DEBUG_EXPR
   5740 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5741 #endif
   5742 	break;
   5743     case XPATH_NODESET:
   5744     case XPATH_XSLT_TREE:
   5745 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5746 	break;
   5747     case XPATH_STRING:
   5748 	return(val);
   5749     case XPATH_BOOLEAN:
   5750 	res = xmlXPathCastBooleanToString(val->boolval);
   5751 	break;
   5752     case XPATH_NUMBER:
   5753 	res = xmlXPathCastNumberToString(val->floatval);
   5754 	break;
   5755     case XPATH_USERS:
   5756     case XPATH_POINT:
   5757     case XPATH_RANGE:
   5758     case XPATH_LOCATIONSET:
   5759 	TODO;
   5760 	break;
   5761     }
   5762     xmlXPathFreeObject(val);
   5763     if (res == NULL)
   5764 	return(xmlXPathNewCString(""));
   5765     return(xmlXPathWrapString(res));
   5766 }
   5767 
   5768 /**
   5769  * xmlXPathCastBooleanToNumber:
   5770  * @val:  a boolean
   5771  *
   5772  * Converts a boolean to its number value
   5773  *
   5774  * Returns the number value
   5775  */
   5776 double
   5777 xmlXPathCastBooleanToNumber(int val) {
   5778     if (val)
   5779 	return(1.0);
   5780     return(0.0);
   5781 }
   5782 
   5783 /**
   5784  * xmlXPathCastStringToNumber:
   5785  * @val:  a string
   5786  *
   5787  * Converts a string to its number value
   5788  *
   5789  * Returns the number value
   5790  */
   5791 double
   5792 xmlXPathCastStringToNumber(const xmlChar * val) {
   5793     return(xmlXPathStringEvalNumber(val));
   5794 }
   5795 
   5796 /**
   5797  * xmlXPathCastNodeToNumber:
   5798  * @node:  a node
   5799  *
   5800  * Converts a node to its number value
   5801  *
   5802  * Returns the number value
   5803  */
   5804 double
   5805 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5806     xmlChar *strval;
   5807     double ret;
   5808 
   5809     if (node == NULL)
   5810 	return(xmlXPathNAN);
   5811     strval = xmlXPathCastNodeToString(node);
   5812     if (strval == NULL)
   5813 	return(xmlXPathNAN);
   5814     ret = xmlXPathCastStringToNumber(strval);
   5815     xmlFree(strval);
   5816 
   5817     return(ret);
   5818 }
   5819 
   5820 /**
   5821  * xmlXPathCastNodeSetToNumber:
   5822  * @ns:  a node-set
   5823  *
   5824  * Converts a node-set to its number value
   5825  *
   5826  * Returns the number value
   5827  */
   5828 double
   5829 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5830     xmlChar *str;
   5831     double ret;
   5832 
   5833     if (ns == NULL)
   5834 	return(xmlXPathNAN);
   5835     str = xmlXPathCastNodeSetToString(ns);
   5836     ret = xmlXPathCastStringToNumber(str);
   5837     xmlFree(str);
   5838     return(ret);
   5839 }
   5840 
   5841 /**
   5842  * xmlXPathCastToNumber:
   5843  * @val:  an XPath object
   5844  *
   5845  * Converts an XPath object to its number value
   5846  *
   5847  * Returns the number value
   5848  */
   5849 double
   5850 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5851     double ret = 0.0;
   5852 
   5853     if (val == NULL)
   5854 	return(xmlXPathNAN);
   5855     switch (val->type) {
   5856     case XPATH_UNDEFINED:
   5857 #ifdef DEGUB_EXPR
   5858 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5859 #endif
   5860 	ret = xmlXPathNAN;
   5861 	break;
   5862     case XPATH_NODESET:
   5863     case XPATH_XSLT_TREE:
   5864 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5865 	break;
   5866     case XPATH_STRING:
   5867 	ret = xmlXPathCastStringToNumber(val->stringval);
   5868 	break;
   5869     case XPATH_NUMBER:
   5870 	ret = val->floatval;
   5871 	break;
   5872     case XPATH_BOOLEAN:
   5873 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5874 	break;
   5875     case XPATH_USERS:
   5876     case XPATH_POINT:
   5877     case XPATH_RANGE:
   5878     case XPATH_LOCATIONSET:
   5879 	TODO;
   5880 	ret = xmlXPathNAN;
   5881 	break;
   5882     }
   5883     return(ret);
   5884 }
   5885 
   5886 /**
   5887  * xmlXPathConvertNumber:
   5888  * @val:  an XPath object
   5889  *
   5890  * Converts an existing object to its number() equivalent
   5891  *
   5892  * Returns the new object, the old one is freed (or the operation
   5893  *         is done directly on @val)
   5894  */
   5895 xmlXPathObjectPtr
   5896 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5897     xmlXPathObjectPtr ret;
   5898 
   5899     if (val == NULL)
   5900 	return(xmlXPathNewFloat(0.0));
   5901     if (val->type == XPATH_NUMBER)
   5902 	return(val);
   5903     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5904     xmlXPathFreeObject(val);
   5905     return(ret);
   5906 }
   5907 
   5908 /**
   5909  * xmlXPathCastNumberToBoolean:
   5910  * @val:  a number
   5911  *
   5912  * Converts a number to its boolean value
   5913  *
   5914  * Returns the boolean value
   5915  */
   5916 int
   5917 xmlXPathCastNumberToBoolean (double val) {
   5918      if (xmlXPathIsNaN(val) || (val == 0.0))
   5919 	 return(0);
   5920      return(1);
   5921 }
   5922 
   5923 /**
   5924  * xmlXPathCastStringToBoolean:
   5925  * @val:  a string
   5926  *
   5927  * Converts a string to its boolean value
   5928  *
   5929  * Returns the boolean value
   5930  */
   5931 int
   5932 xmlXPathCastStringToBoolean (const xmlChar *val) {
   5933     if ((val == NULL) || (xmlStrlen(val) == 0))
   5934 	return(0);
   5935     return(1);
   5936 }
   5937 
   5938 /**
   5939  * xmlXPathCastNodeSetToBoolean:
   5940  * @ns:  a node-set
   5941  *
   5942  * Converts a node-set to its boolean value
   5943  *
   5944  * Returns the boolean value
   5945  */
   5946 int
   5947 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   5948     if ((ns == NULL) || (ns->nodeNr == 0))
   5949 	return(0);
   5950     return(1);
   5951 }
   5952 
   5953 /**
   5954  * xmlXPathCastToBoolean:
   5955  * @val:  an XPath object
   5956  *
   5957  * Converts an XPath object to its boolean value
   5958  *
   5959  * Returns the boolean value
   5960  */
   5961 int
   5962 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   5963     int ret = 0;
   5964 
   5965     if (val == NULL)
   5966 	return(0);
   5967     switch (val->type) {
   5968     case XPATH_UNDEFINED:
   5969 #ifdef DEBUG_EXPR
   5970 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   5971 #endif
   5972 	ret = 0;
   5973 	break;
   5974     case XPATH_NODESET:
   5975     case XPATH_XSLT_TREE:
   5976 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   5977 	break;
   5978     case XPATH_STRING:
   5979 	ret = xmlXPathCastStringToBoolean(val->stringval);
   5980 	break;
   5981     case XPATH_NUMBER:
   5982 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   5983 	break;
   5984     case XPATH_BOOLEAN:
   5985 	ret = val->boolval;
   5986 	break;
   5987     case XPATH_USERS:
   5988     case XPATH_POINT:
   5989     case XPATH_RANGE:
   5990     case XPATH_LOCATIONSET:
   5991 	TODO;
   5992 	ret = 0;
   5993 	break;
   5994     }
   5995     return(ret);
   5996 }
   5997 
   5998 
   5999 /**
   6000  * xmlXPathConvertBoolean:
   6001  * @val:  an XPath object
   6002  *
   6003  * Converts an existing object to its boolean() equivalent
   6004  *
   6005  * Returns the new object, the old one is freed (or the operation
   6006  *         is done directly on @val)
   6007  */
   6008 xmlXPathObjectPtr
   6009 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   6010     xmlXPathObjectPtr ret;
   6011 
   6012     if (val == NULL)
   6013 	return(xmlXPathNewBoolean(0));
   6014     if (val->type == XPATH_BOOLEAN)
   6015 	return(val);
   6016     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   6017     xmlXPathFreeObject(val);
   6018     return(ret);
   6019 }
   6020 
   6021 /************************************************************************
   6022  *									*
   6023  *		Routines to handle XPath contexts			*
   6024  *									*
   6025  ************************************************************************/
   6026 
   6027 /**
   6028  * xmlXPathNewContext:
   6029  * @doc:  the XML document
   6030  *
   6031  * Create a new xmlXPathContext
   6032  *
   6033  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   6034  */
   6035 xmlXPathContextPtr
   6036 xmlXPathNewContext(xmlDocPtr doc) {
   6037     xmlXPathContextPtr ret;
   6038 
   6039     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   6040     if (ret == NULL) {
   6041         xmlXPathErrMemory(NULL, "creating context\n");
   6042 	return(NULL);
   6043     }
   6044     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6045     ret->doc = doc;
   6046     ret->node = NULL;
   6047 
   6048     ret->varHash = NULL;
   6049 
   6050     ret->nb_types = 0;
   6051     ret->max_types = 0;
   6052     ret->types = NULL;
   6053 
   6054     ret->funcHash = xmlHashCreate(0);
   6055 
   6056     ret->nb_axis = 0;
   6057     ret->max_axis = 0;
   6058     ret->axis = NULL;
   6059 
   6060     ret->nsHash = NULL;
   6061     ret->user = NULL;
   6062 
   6063     ret->contextSize = -1;
   6064     ret->proximityPosition = -1;
   6065 
   6066 #ifdef XP_DEFAULT_CACHE_ON
   6067     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6068 	xmlXPathFreeContext(ret);
   6069 	return(NULL);
   6070     }
   6071 #endif
   6072 
   6073     xmlXPathRegisterAllFunctions(ret);
   6074 
   6075     return(ret);
   6076 }
   6077 
   6078 /**
   6079  * xmlXPathFreeContext:
   6080  * @ctxt:  the context to free
   6081  *
   6082  * Free up an xmlXPathContext
   6083  */
   6084 void
   6085 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6086     if (ctxt == NULL) return;
   6087 
   6088     if (ctxt->cache != NULL)
   6089 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6090     xmlXPathRegisteredNsCleanup(ctxt);
   6091     xmlXPathRegisteredFuncsCleanup(ctxt);
   6092     xmlXPathRegisteredVariablesCleanup(ctxt);
   6093     xmlResetError(&ctxt->lastError);
   6094     xmlFree(ctxt);
   6095 }
   6096 
   6097 /************************************************************************
   6098  *									*
   6099  *		Routines to handle XPath parser contexts		*
   6100  *									*
   6101  ************************************************************************/
   6102 
   6103 #define CHECK_CTXT(ctxt)						\
   6104     if (ctxt == NULL) {						\
   6105 	__xmlRaiseError(NULL, NULL, NULL,				\
   6106 		NULL, NULL, XML_FROM_XPATH,				\
   6107 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6108 		__FILE__, __LINE__,					\
   6109 		NULL, NULL, NULL, 0, 0,					\
   6110 		"NULL context pointer\n");				\
   6111 	return(NULL);							\
   6112     }									\
   6113 
   6114 #define CHECK_CTXT_NEG(ctxt)						\
   6115     if (ctxt == NULL) {						\
   6116 	__xmlRaiseError(NULL, NULL, NULL,				\
   6117 		NULL, NULL, XML_FROM_XPATH,				\
   6118 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6119 		__FILE__, __LINE__,					\
   6120 		NULL, NULL, NULL, 0, 0,					\
   6121 		"NULL context pointer\n");				\
   6122 	return(-1);							\
   6123     }									\
   6124 
   6125 
   6126 #define CHECK_CONTEXT(ctxt)						\
   6127     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6128         (ctxt->doc->children == NULL)) {				\
   6129 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6130 	return(NULL);							\
   6131     }
   6132 
   6133 
   6134 /**
   6135  * xmlXPathNewParserContext:
   6136  * @str:  the XPath expression
   6137  * @ctxt:  the XPath context
   6138  *
   6139  * Create a new xmlXPathParserContext
   6140  *
   6141  * Returns the xmlXPathParserContext just allocated.
   6142  */
   6143 xmlXPathParserContextPtr
   6144 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6145     xmlXPathParserContextPtr ret;
   6146 
   6147     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6148     if (ret == NULL) {
   6149         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6150 	return(NULL);
   6151     }
   6152     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6153     ret->cur = ret->base = str;
   6154     ret->context = ctxt;
   6155 
   6156     ret->comp = xmlXPathNewCompExpr();
   6157     if (ret->comp == NULL) {
   6158 	xmlFree(ret->valueTab);
   6159 	xmlFree(ret);
   6160 	return(NULL);
   6161     }
   6162     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6163         ret->comp->dict = ctxt->dict;
   6164 	xmlDictReference(ret->comp->dict);
   6165     }
   6166 
   6167     return(ret);
   6168 }
   6169 
   6170 /**
   6171  * xmlXPathCompParserContext:
   6172  * @comp:  the XPath compiled expression
   6173  * @ctxt:  the XPath context
   6174  *
   6175  * Create a new xmlXPathParserContext when processing a compiled expression
   6176  *
   6177  * Returns the xmlXPathParserContext just allocated.
   6178  */
   6179 static xmlXPathParserContextPtr
   6180 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6181     xmlXPathParserContextPtr ret;
   6182 
   6183     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6184     if (ret == NULL) {
   6185         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6186 	return(NULL);
   6187     }
   6188     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6189 
   6190     /* Allocate the value stack */
   6191     ret->valueTab = (xmlXPathObjectPtr *)
   6192                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6193     if (ret->valueTab == NULL) {
   6194 	xmlFree(ret);
   6195 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6196 	return(NULL);
   6197     }
   6198     ret->valueNr = 0;
   6199     ret->valueMax = 10;
   6200     ret->value = NULL;
   6201     ret->valueFrame = 0;
   6202 
   6203     ret->context = ctxt;
   6204     ret->comp = comp;
   6205 
   6206     return(ret);
   6207 }
   6208 
   6209 /**
   6210  * xmlXPathFreeParserContext:
   6211  * @ctxt:  the context to free
   6212  *
   6213  * Free up an xmlXPathParserContext
   6214  */
   6215 void
   6216 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6217     if (ctxt->valueTab != NULL) {
   6218         xmlFree(ctxt->valueTab);
   6219     }
   6220     if (ctxt->comp != NULL) {
   6221 #ifdef XPATH_STREAMING
   6222 	if (ctxt->comp->stream != NULL) {
   6223 	    xmlFreePatternList(ctxt->comp->stream);
   6224 	    ctxt->comp->stream = NULL;
   6225 	}
   6226 #endif
   6227 	xmlXPathFreeCompExpr(ctxt->comp);
   6228     }
   6229     xmlFree(ctxt);
   6230 }
   6231 
   6232 /************************************************************************
   6233  *									*
   6234  *		The implicit core function library			*
   6235  *									*
   6236  ************************************************************************/
   6237 
   6238 /**
   6239  * xmlXPathNodeValHash:
   6240  * @node:  a node pointer
   6241  *
   6242  * Function computing the beginning of the string value of the node,
   6243  * used to speed up comparisons
   6244  *
   6245  * Returns an int usable as a hash
   6246  */
   6247 static unsigned int
   6248 xmlXPathNodeValHash(xmlNodePtr node) {
   6249     int len = 2;
   6250     const xmlChar * string = NULL;
   6251     xmlNodePtr tmp = NULL;
   6252     unsigned int ret = 0;
   6253 
   6254     if (node == NULL)
   6255 	return(0);
   6256 
   6257     if (node->type == XML_DOCUMENT_NODE) {
   6258 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6259 	if (tmp == NULL)
   6260 	    node = node->children;
   6261 	else
   6262 	    node = tmp;
   6263 
   6264 	if (node == NULL)
   6265 	    return(0);
   6266     }
   6267 
   6268     switch (node->type) {
   6269 	case XML_COMMENT_NODE:
   6270 	case XML_PI_NODE:
   6271 	case XML_CDATA_SECTION_NODE:
   6272 	case XML_TEXT_NODE:
   6273 	    string = node->content;
   6274 	    if (string == NULL)
   6275 		return(0);
   6276 	    if (string[0] == 0)
   6277 		return(0);
   6278 	    return(((unsigned int) string[0]) +
   6279 		   (((unsigned int) string[1]) << 8));
   6280 	case XML_NAMESPACE_DECL:
   6281 	    string = ((xmlNsPtr)node)->href;
   6282 	    if (string == NULL)
   6283 		return(0);
   6284 	    if (string[0] == 0)
   6285 		return(0);
   6286 	    return(((unsigned int) string[0]) +
   6287 		   (((unsigned int) string[1]) << 8));
   6288 	case XML_ATTRIBUTE_NODE:
   6289 	    tmp = ((xmlAttrPtr) node)->children;
   6290 	    break;
   6291 	case XML_ELEMENT_NODE:
   6292 	    tmp = node->children;
   6293 	    break;
   6294 	default:
   6295 	    return(0);
   6296     }
   6297     while (tmp != NULL) {
   6298 	switch (tmp->type) {
   6299 	    case XML_COMMENT_NODE:
   6300 	    case XML_PI_NODE:
   6301 	    case XML_CDATA_SECTION_NODE:
   6302 	    case XML_TEXT_NODE:
   6303 		string = tmp->content;
   6304 		break;
   6305 	    case XML_NAMESPACE_DECL:
   6306 		string = ((xmlNsPtr)tmp)->href;
   6307 		break;
   6308 	    default:
   6309 		break;
   6310 	}
   6311 	if ((string != NULL) && (string[0] != 0)) {
   6312 	    if (len == 1) {
   6313 		return(ret + (((unsigned int) string[0]) << 8));
   6314 	    }
   6315 	    if (string[1] == 0) {
   6316 		len = 1;
   6317 		ret = (unsigned int) string[0];
   6318 	    } else {
   6319 		return(((unsigned int) string[0]) +
   6320 		       (((unsigned int) string[1]) << 8));
   6321 	    }
   6322 	}
   6323 	/*
   6324 	 * Skip to next node
   6325 	 */
   6326 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6327 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6328 		tmp = tmp->children;
   6329 		continue;
   6330 	    }
   6331 	}
   6332 	if (tmp == node)
   6333 	    break;
   6334 
   6335 	if (tmp->next != NULL) {
   6336 	    tmp = tmp->next;
   6337 	    continue;
   6338 	}
   6339 
   6340 	do {
   6341 	    tmp = tmp->parent;
   6342 	    if (tmp == NULL)
   6343 		break;
   6344 	    if (tmp == node) {
   6345 		tmp = NULL;
   6346 		break;
   6347 	    }
   6348 	    if (tmp->next != NULL) {
   6349 		tmp = tmp->next;
   6350 		break;
   6351 	    }
   6352 	} while (tmp != NULL);
   6353     }
   6354     return(ret);
   6355 }
   6356 
   6357 /**
   6358  * xmlXPathStringHash:
   6359  * @string:  a string
   6360  *
   6361  * Function computing the beginning of the string value of the node,
   6362  * used to speed up comparisons
   6363  *
   6364  * Returns an int usable as a hash
   6365  */
   6366 static unsigned int
   6367 xmlXPathStringHash(const xmlChar * string) {
   6368     if (string == NULL)
   6369 	return((unsigned int) 0);
   6370     if (string[0] == 0)
   6371 	return(0);
   6372     return(((unsigned int) string[0]) +
   6373 	   (((unsigned int) string[1]) << 8));
   6374 }
   6375 
   6376 /**
   6377  * xmlXPathCompareNodeSetFloat:
   6378  * @ctxt:  the XPath Parser context
   6379  * @inf:  less than (1) or greater than (0)
   6380  * @strict:  is the comparison strict
   6381  * @arg:  the node set
   6382  * @f:  the value
   6383  *
   6384  * Implement the compare operation between a nodeset and a number
   6385  *     @ns < @val    (1, 1, ...
   6386  *     @ns <= @val   (1, 0, ...
   6387  *     @ns > @val    (0, 1, ...
   6388  *     @ns >= @val   (0, 0, ...
   6389  *
   6390  * If one object to be compared is a node-set and the other is a number,
   6391  * then the comparison will be true if and only if there is a node in the
   6392  * node-set such that the result of performing the comparison on the number
   6393  * to be compared and on the result of converting the string-value of that
   6394  * node to a number using the number function is true.
   6395  *
   6396  * Returns 0 or 1 depending on the results of the test.
   6397  */
   6398 static int
   6399 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6400 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6401     int i, ret = 0;
   6402     xmlNodeSetPtr ns;
   6403     xmlChar *str2;
   6404 
   6405     if ((f == NULL) || (arg == NULL) ||
   6406 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6407 	xmlXPathReleaseObject(ctxt->context, arg);
   6408 	xmlXPathReleaseObject(ctxt->context, f);
   6409         return(0);
   6410     }
   6411     ns = arg->nodesetval;
   6412     if (ns != NULL) {
   6413 	for (i = 0;i < ns->nodeNr;i++) {
   6414 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6415 	     if (str2 != NULL) {
   6416 		 valuePush(ctxt,
   6417 			   xmlXPathCacheNewString(ctxt->context, str2));
   6418 		 xmlFree(str2);
   6419 		 xmlXPathNumberFunction(ctxt, 1);
   6420 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6421 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6422 		 if (ret)
   6423 		     break;
   6424 	     }
   6425 	}
   6426     }
   6427     xmlXPathReleaseObject(ctxt->context, arg);
   6428     xmlXPathReleaseObject(ctxt->context, f);
   6429     return(ret);
   6430 }
   6431 
   6432 /**
   6433  * xmlXPathCompareNodeSetString:
   6434  * @ctxt:  the XPath Parser context
   6435  * @inf:  less than (1) or greater than (0)
   6436  * @strict:  is the comparison strict
   6437  * @arg:  the node set
   6438  * @s:  the value
   6439  *
   6440  * Implement the compare operation between a nodeset and a string
   6441  *     @ns < @val    (1, 1, ...
   6442  *     @ns <= @val   (1, 0, ...
   6443  *     @ns > @val    (0, 1, ...
   6444  *     @ns >= @val   (0, 0, ...
   6445  *
   6446  * If one object to be compared is a node-set and the other is a string,
   6447  * then the comparison will be true if and only if there is a node in
   6448  * the node-set such that the result of performing the comparison on the
   6449  * string-value of the node and the other string is true.
   6450  *
   6451  * Returns 0 or 1 depending on the results of the test.
   6452  */
   6453 static int
   6454 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6455 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6456     int i, ret = 0;
   6457     xmlNodeSetPtr ns;
   6458     xmlChar *str2;
   6459 
   6460     if ((s == NULL) || (arg == NULL) ||
   6461 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6462 	xmlXPathReleaseObject(ctxt->context, arg);
   6463 	xmlXPathReleaseObject(ctxt->context, s);
   6464         return(0);
   6465     }
   6466     ns = arg->nodesetval;
   6467     if (ns != NULL) {
   6468 	for (i = 0;i < ns->nodeNr;i++) {
   6469 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6470 	     if (str2 != NULL) {
   6471 		 valuePush(ctxt,
   6472 			   xmlXPathCacheNewString(ctxt->context, str2));
   6473 		 xmlFree(str2);
   6474 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6475 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6476 		 if (ret)
   6477 		     break;
   6478 	     }
   6479 	}
   6480     }
   6481     xmlXPathReleaseObject(ctxt->context, arg);
   6482     xmlXPathReleaseObject(ctxt->context, s);
   6483     return(ret);
   6484 }
   6485 
   6486 /**
   6487  * xmlXPathCompareNodeSets:
   6488  * @inf:  less than (1) or greater than (0)
   6489  * @strict:  is the comparison strict
   6490  * @arg1:  the first node set object
   6491  * @arg2:  the second node set object
   6492  *
   6493  * Implement the compare operation on nodesets:
   6494  *
   6495  * If both objects to be compared are node-sets, then the comparison
   6496  * will be true if and only if there is a node in the first node-set
   6497  * and a node in the second node-set such that the result of performing
   6498  * the comparison on the string-values of the two nodes is true.
   6499  * ....
   6500  * When neither object to be compared is a node-set and the operator
   6501  * is <=, <, >= or >, then the objects are compared by converting both
   6502  * objects to numbers and comparing the numbers according to IEEE 754.
   6503  * ....
   6504  * The number function converts its argument to a number as follows:
   6505  *  - a string that consists of optional whitespace followed by an
   6506  *    optional minus sign followed by a Number followed by whitespace
   6507  *    is converted to the IEEE 754 number that is nearest (according
   6508  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6509  *    represented by the string; any other string is converted to NaN
   6510  *
   6511  * Conclusion all nodes need to be converted first to their string value
   6512  * and then the comparison must be done when possible
   6513  */
   6514 static int
   6515 xmlXPathCompareNodeSets(int inf, int strict,
   6516 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6517     int i, j, init = 0;
   6518     double val1;
   6519     double *values2;
   6520     int ret = 0;
   6521     xmlNodeSetPtr ns1;
   6522     xmlNodeSetPtr ns2;
   6523 
   6524     if ((arg1 == NULL) ||
   6525 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6526 	xmlXPathFreeObject(arg2);
   6527         return(0);
   6528     }
   6529     if ((arg2 == NULL) ||
   6530 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6531 	xmlXPathFreeObject(arg1);
   6532 	xmlXPathFreeObject(arg2);
   6533         return(0);
   6534     }
   6535 
   6536     ns1 = arg1->nodesetval;
   6537     ns2 = arg2->nodesetval;
   6538 
   6539     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6540 	xmlXPathFreeObject(arg1);
   6541 	xmlXPathFreeObject(arg2);
   6542 	return(0);
   6543     }
   6544     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6545 	xmlXPathFreeObject(arg1);
   6546 	xmlXPathFreeObject(arg2);
   6547 	return(0);
   6548     }
   6549 
   6550     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6551     if (values2 == NULL) {
   6552         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6553 	xmlXPathFreeObject(arg1);
   6554 	xmlXPathFreeObject(arg2);
   6555 	return(0);
   6556     }
   6557     for (i = 0;i < ns1->nodeNr;i++) {
   6558 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6559 	if (xmlXPathIsNaN(val1))
   6560 	    continue;
   6561 	for (j = 0;j < ns2->nodeNr;j++) {
   6562 	    if (init == 0) {
   6563 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6564 	    }
   6565 	    if (xmlXPathIsNaN(values2[j]))
   6566 		continue;
   6567 	    if (inf && strict)
   6568 		ret = (val1 < values2[j]);
   6569 	    else if (inf && !strict)
   6570 		ret = (val1 <= values2[j]);
   6571 	    else if (!inf && strict)
   6572 		ret = (val1 > values2[j]);
   6573 	    else if (!inf && !strict)
   6574 		ret = (val1 >= values2[j]);
   6575 	    if (ret)
   6576 		break;
   6577 	}
   6578 	if (ret)
   6579 	    break;
   6580 	init = 1;
   6581     }
   6582     xmlFree(values2);
   6583     xmlXPathFreeObject(arg1);
   6584     xmlXPathFreeObject(arg2);
   6585     return(ret);
   6586 }
   6587 
   6588 /**
   6589  * xmlXPathCompareNodeSetValue:
   6590  * @ctxt:  the XPath Parser context
   6591  * @inf:  less than (1) or greater than (0)
   6592  * @strict:  is the comparison strict
   6593  * @arg:  the node set
   6594  * @val:  the value
   6595  *
   6596  * Implement the compare operation between a nodeset and a value
   6597  *     @ns < @val    (1, 1, ...
   6598  *     @ns <= @val   (1, 0, ...
   6599  *     @ns > @val    (0, 1, ...
   6600  *     @ns >= @val   (0, 0, ...
   6601  *
   6602  * If one object to be compared is a node-set and the other is a boolean,
   6603  * then the comparison will be true if and only if the result of performing
   6604  * the comparison on the boolean and on the result of converting
   6605  * the node-set to a boolean using the boolean function is true.
   6606  *
   6607  * Returns 0 or 1 depending on the results of the test.
   6608  */
   6609 static int
   6610 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6611 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6612     if ((val == NULL) || (arg == NULL) ||
   6613 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6614         return(0);
   6615 
   6616     switch(val->type) {
   6617         case XPATH_NUMBER:
   6618 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6619         case XPATH_NODESET:
   6620         case XPATH_XSLT_TREE:
   6621 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6622         case XPATH_STRING:
   6623 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6624         case XPATH_BOOLEAN:
   6625 	    valuePush(ctxt, arg);
   6626 	    xmlXPathBooleanFunction(ctxt, 1);
   6627 	    valuePush(ctxt, val);
   6628 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6629 	default:
   6630 	    TODO
   6631     }
   6632     return(0);
   6633 }
   6634 
   6635 /**
   6636  * xmlXPathEqualNodeSetString:
   6637  * @arg:  the nodeset object argument
   6638  * @str:  the string to compare to.
   6639  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6640  *
   6641  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6642  * If one object to be compared is a node-set and the other is a string,
   6643  * then the comparison will be true if and only if there is a node in
   6644  * the node-set such that the result of performing the comparison on the
   6645  * string-value of the node and the other string is true.
   6646  *
   6647  * Returns 0 or 1 depending on the results of the test.
   6648  */
   6649 static int
   6650 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6651 {
   6652     int i;
   6653     xmlNodeSetPtr ns;
   6654     xmlChar *str2;
   6655     unsigned int hash;
   6656 
   6657     if ((str == NULL) || (arg == NULL) ||
   6658         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6659         return (0);
   6660     ns = arg->nodesetval;
   6661     /*
   6662      * A NULL nodeset compared with a string is always false
   6663      * (since there is no node equal, and no node not equal)
   6664      */
   6665     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6666         return (0);
   6667     hash = xmlXPathStringHash(str);
   6668     for (i = 0; i < ns->nodeNr; i++) {
   6669         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6670             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6671             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6672                 xmlFree(str2);
   6673 		if (neq)
   6674 		    continue;
   6675                 return (1);
   6676 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6677 		if (neq)
   6678 		    continue;
   6679                 return (1);
   6680             } else if (neq) {
   6681 		if (str2 != NULL)
   6682 		    xmlFree(str2);
   6683 		return (1);
   6684 	    }
   6685             if (str2 != NULL)
   6686                 xmlFree(str2);
   6687         } else if (neq)
   6688 	    return (1);
   6689     }
   6690     return (0);
   6691 }
   6692 
   6693 /**
   6694  * xmlXPathEqualNodeSetFloat:
   6695  * @arg:  the nodeset object argument
   6696  * @f:  the float to compare to
   6697  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6698  *
   6699  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6700  * If one object to be compared is a node-set and the other is a number,
   6701  * then the comparison will be true if and only if there is a node in
   6702  * the node-set such that the result of performing the comparison on the
   6703  * number to be compared and on the result of converting the string-value
   6704  * of that node to a number using the number function is true.
   6705  *
   6706  * Returns 0 or 1 depending on the results of the test.
   6707  */
   6708 static int
   6709 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6710     xmlXPathObjectPtr arg, double f, int neq) {
   6711   int i, ret=0;
   6712   xmlNodeSetPtr ns;
   6713   xmlChar *str2;
   6714   xmlXPathObjectPtr val;
   6715   double v;
   6716 
   6717     if ((arg == NULL) ||
   6718 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6719         return(0);
   6720 
   6721     ns = arg->nodesetval;
   6722     if (ns != NULL) {
   6723 	for (i=0;i<ns->nodeNr;i++) {
   6724 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6725 	    if (str2 != NULL) {
   6726 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6727 		xmlFree(str2);
   6728 		xmlXPathNumberFunction(ctxt, 1);
   6729 		val = valuePop(ctxt);
   6730 		v = val->floatval;
   6731 		xmlXPathReleaseObject(ctxt->context, val);
   6732 		if (!xmlXPathIsNaN(v)) {
   6733 		    if ((!neq) && (v==f)) {
   6734 			ret = 1;
   6735 			break;
   6736 		    } else if ((neq) && (v!=f)) {
   6737 			ret = 1;
   6738 			break;
   6739 		    }
   6740 		} else {	/* NaN is unequal to any value */
   6741 		    if (neq)
   6742 			ret = 1;
   6743 		}
   6744 	    }
   6745 	}
   6746     }
   6747 
   6748     return(ret);
   6749 }
   6750 
   6751 
   6752 /**
   6753  * xmlXPathEqualNodeSets:
   6754  * @arg1:  first nodeset object argument
   6755  * @arg2:  second nodeset object argument
   6756  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6757  *
   6758  * Implement the equal / not equal operation on XPath nodesets:
   6759  * @arg1 == @arg2  or  @arg1 != @arg2
   6760  * If both objects to be compared are node-sets, then the comparison
   6761  * will be true if and only if there is a node in the first node-set and
   6762  * a node in the second node-set such that the result of performing the
   6763  * comparison on the string-values of the two nodes is true.
   6764  *
   6765  * (needless to say, this is a costly operation)
   6766  *
   6767  * Returns 0 or 1 depending on the results of the test.
   6768  */
   6769 static int
   6770 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6771     int i, j;
   6772     unsigned int *hashs1;
   6773     unsigned int *hashs2;
   6774     xmlChar **values1;
   6775     xmlChar **values2;
   6776     int ret = 0;
   6777     xmlNodeSetPtr ns1;
   6778     xmlNodeSetPtr ns2;
   6779 
   6780     if ((arg1 == NULL) ||
   6781 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6782         return(0);
   6783     if ((arg2 == NULL) ||
   6784 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6785         return(0);
   6786 
   6787     ns1 = arg1->nodesetval;
   6788     ns2 = arg2->nodesetval;
   6789 
   6790     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6791 	return(0);
   6792     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6793 	return(0);
   6794 
   6795     /*
   6796      * for equal, check if there is a node pertaining to both sets
   6797      */
   6798     if (neq == 0)
   6799 	for (i = 0;i < ns1->nodeNr;i++)
   6800 	    for (j = 0;j < ns2->nodeNr;j++)
   6801 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6802 		    return(1);
   6803 
   6804     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6805     if (values1 == NULL) {
   6806         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6807 	return(0);
   6808     }
   6809     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6810     if (hashs1 == NULL) {
   6811         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6812 	xmlFree(values1);
   6813 	return(0);
   6814     }
   6815     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6816     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6817     if (values2 == NULL) {
   6818         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6819 	xmlFree(hashs1);
   6820 	xmlFree(values1);
   6821 	return(0);
   6822     }
   6823     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6824     if (hashs2 == NULL) {
   6825         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6826 	xmlFree(hashs1);
   6827 	xmlFree(values1);
   6828 	xmlFree(values2);
   6829 	return(0);
   6830     }
   6831     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6832     for (i = 0;i < ns1->nodeNr;i++) {
   6833 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6834 	for (j = 0;j < ns2->nodeNr;j++) {
   6835 	    if (i == 0)
   6836 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6837 	    if (hashs1[i] != hashs2[j]) {
   6838 		if (neq) {
   6839 		    ret = 1;
   6840 		    break;
   6841 		}
   6842 	    }
   6843 	    else {
   6844 		if (values1[i] == NULL)
   6845 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6846 		if (values2[j] == NULL)
   6847 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6848 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6849 		if (ret)
   6850 		    break;
   6851 	    }
   6852 	}
   6853 	if (ret)
   6854 	    break;
   6855     }
   6856     for (i = 0;i < ns1->nodeNr;i++)
   6857 	if (values1[i] != NULL)
   6858 	    xmlFree(values1[i]);
   6859     for (j = 0;j < ns2->nodeNr;j++)
   6860 	if (values2[j] != NULL)
   6861 	    xmlFree(values2[j]);
   6862     xmlFree(values1);
   6863     xmlFree(values2);
   6864     xmlFree(hashs1);
   6865     xmlFree(hashs2);
   6866     return(ret);
   6867 }
   6868 
   6869 static int
   6870 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6871   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6872     int ret = 0;
   6873     /*
   6874      *At this point we are assured neither arg1 nor arg2
   6875      *is a nodeset, so we can just pick the appropriate routine.
   6876      */
   6877     switch (arg1->type) {
   6878         case XPATH_UNDEFINED:
   6879 #ifdef DEBUG_EXPR
   6880 	    xmlGenericError(xmlGenericErrorContext,
   6881 		    "Equal: undefined\n");
   6882 #endif
   6883 	    break;
   6884         case XPATH_BOOLEAN:
   6885 	    switch (arg2->type) {
   6886 	        case XPATH_UNDEFINED:
   6887 #ifdef DEBUG_EXPR
   6888 		    xmlGenericError(xmlGenericErrorContext,
   6889 			    "Equal: undefined\n");
   6890 #endif
   6891 		    break;
   6892 		case XPATH_BOOLEAN:
   6893 #ifdef DEBUG_EXPR
   6894 		    xmlGenericError(xmlGenericErrorContext,
   6895 			    "Equal: %d boolean %d \n",
   6896 			    arg1->boolval, arg2->boolval);
   6897 #endif
   6898 		    ret = (arg1->boolval == arg2->boolval);
   6899 		    break;
   6900 		case XPATH_NUMBER:
   6901 		    ret = (arg1->boolval ==
   6902 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   6903 		    break;
   6904 		case XPATH_STRING:
   6905 		    if ((arg2->stringval == NULL) ||
   6906 			(arg2->stringval[0] == 0)) ret = 0;
   6907 		    else
   6908 			ret = 1;
   6909 		    ret = (arg1->boolval == ret);
   6910 		    break;
   6911 		case XPATH_USERS:
   6912 		case XPATH_POINT:
   6913 		case XPATH_RANGE:
   6914 		case XPATH_LOCATIONSET:
   6915 		    TODO
   6916 		    break;
   6917 		case XPATH_NODESET:
   6918 		case XPATH_XSLT_TREE:
   6919 		    break;
   6920 	    }
   6921 	    break;
   6922         case XPATH_NUMBER:
   6923 	    switch (arg2->type) {
   6924 	        case XPATH_UNDEFINED:
   6925 #ifdef DEBUG_EXPR
   6926 		    xmlGenericError(xmlGenericErrorContext,
   6927 			    "Equal: undefined\n");
   6928 #endif
   6929 		    break;
   6930 		case XPATH_BOOLEAN:
   6931 		    ret = (arg2->boolval==
   6932 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   6933 		    break;
   6934 		case XPATH_STRING:
   6935 		    valuePush(ctxt, arg2);
   6936 		    xmlXPathNumberFunction(ctxt, 1);
   6937 		    arg2 = valuePop(ctxt);
   6938 		    /* no break on purpose */
   6939 		case XPATH_NUMBER:
   6940 		    /* Hand check NaN and Infinity equalities */
   6941 		    if (xmlXPathIsNaN(arg1->floatval) ||
   6942 			    xmlXPathIsNaN(arg2->floatval)) {
   6943 		        ret = 0;
   6944 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   6945 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   6946 			    ret = 1;
   6947 			else
   6948 			    ret = 0;
   6949 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   6950 			if (xmlXPathIsInf(arg2->floatval) == -1)
   6951 			    ret = 1;
   6952 			else
   6953 			    ret = 0;
   6954 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   6955 			if (xmlXPathIsInf(arg1->floatval) == 1)
   6956 			    ret = 1;
   6957 			else
   6958 			    ret = 0;
   6959 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   6960 			if (xmlXPathIsInf(arg1->floatval) == -1)
   6961 			    ret = 1;
   6962 			else
   6963 			    ret = 0;
   6964 		    } else {
   6965 		        ret = (arg1->floatval == arg2->floatval);
   6966 		    }
   6967 		    break;
   6968 		case XPATH_USERS:
   6969 		case XPATH_POINT:
   6970 		case XPATH_RANGE:
   6971 		case XPATH_LOCATIONSET:
   6972 		    TODO
   6973 		    break;
   6974 		case XPATH_NODESET:
   6975 		case XPATH_XSLT_TREE:
   6976 		    break;
   6977 	    }
   6978 	    break;
   6979         case XPATH_STRING:
   6980 	    switch (arg2->type) {
   6981 	        case XPATH_UNDEFINED:
   6982 #ifdef DEBUG_EXPR
   6983 		    xmlGenericError(xmlGenericErrorContext,
   6984 			    "Equal: undefined\n");
   6985 #endif
   6986 		    break;
   6987 		case XPATH_BOOLEAN:
   6988 		    if ((arg1->stringval == NULL) ||
   6989 			(arg1->stringval[0] == 0)) ret = 0;
   6990 		    else
   6991 			ret = 1;
   6992 		    ret = (arg2->boolval == ret);
   6993 		    break;
   6994 		case XPATH_STRING:
   6995 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   6996 		    break;
   6997 		case XPATH_NUMBER:
   6998 		    valuePush(ctxt, arg1);
   6999 		    xmlXPathNumberFunction(ctxt, 1);
   7000 		    arg1 = valuePop(ctxt);
   7001 		    /* Hand check NaN and Infinity equalities */
   7002 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7003 			    xmlXPathIsNaN(arg2->floatval)) {
   7004 		        ret = 0;
   7005 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7006 			if (xmlXPathIsInf(arg2->floatval) == 1)
   7007 			    ret = 1;
   7008 			else
   7009 			    ret = 0;
   7010 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7011 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7012 			    ret = 1;
   7013 			else
   7014 			    ret = 0;
   7015 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7016 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7017 			    ret = 1;
   7018 			else
   7019 			    ret = 0;
   7020 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7021 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7022 			    ret = 1;
   7023 			else
   7024 			    ret = 0;
   7025 		    } else {
   7026 		        ret = (arg1->floatval == arg2->floatval);
   7027 		    }
   7028 		    break;
   7029 		case XPATH_USERS:
   7030 		case XPATH_POINT:
   7031 		case XPATH_RANGE:
   7032 		case XPATH_LOCATIONSET:
   7033 		    TODO
   7034 		    break;
   7035 		case XPATH_NODESET:
   7036 		case XPATH_XSLT_TREE:
   7037 		    break;
   7038 	    }
   7039 	    break;
   7040         case XPATH_USERS:
   7041 	case XPATH_POINT:
   7042 	case XPATH_RANGE:
   7043 	case XPATH_LOCATIONSET:
   7044 	    TODO
   7045 	    break;
   7046 	case XPATH_NODESET:
   7047 	case XPATH_XSLT_TREE:
   7048 	    break;
   7049     }
   7050     xmlXPathReleaseObject(ctxt->context, arg1);
   7051     xmlXPathReleaseObject(ctxt->context, arg2);
   7052     return(ret);
   7053 }
   7054 
   7055 /**
   7056  * xmlXPathEqualValues:
   7057  * @ctxt:  the XPath Parser context
   7058  *
   7059  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7060  *
   7061  * Returns 0 or 1 depending on the results of the test.
   7062  */
   7063 int
   7064 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7065     xmlXPathObjectPtr arg1, arg2, argtmp;
   7066     int ret = 0;
   7067 
   7068     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7069     arg2 = valuePop(ctxt);
   7070     arg1 = valuePop(ctxt);
   7071     if ((arg1 == NULL) || (arg2 == NULL)) {
   7072 	if (arg1 != NULL)
   7073 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7074 	else
   7075 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7076 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7077     }
   7078 
   7079     if (arg1 == arg2) {
   7080 #ifdef DEBUG_EXPR
   7081         xmlGenericError(xmlGenericErrorContext,
   7082 		"Equal: by pointer\n");
   7083 #endif
   7084 	xmlXPathFreeObject(arg1);
   7085         return(1);
   7086     }
   7087 
   7088     /*
   7089      *If either argument is a nodeset, it's a 'special case'
   7090      */
   7091     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7092       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7093 	/*
   7094 	 *Hack it to assure arg1 is the nodeset
   7095 	 */
   7096 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7097 		argtmp = arg2;
   7098 		arg2 = arg1;
   7099 		arg1 = argtmp;
   7100 	}
   7101 	switch (arg2->type) {
   7102 	    case XPATH_UNDEFINED:
   7103 #ifdef DEBUG_EXPR
   7104 		xmlGenericError(xmlGenericErrorContext,
   7105 			"Equal: undefined\n");
   7106 #endif
   7107 		break;
   7108 	    case XPATH_NODESET:
   7109 	    case XPATH_XSLT_TREE:
   7110 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7111 		break;
   7112 	    case XPATH_BOOLEAN:
   7113 		if ((arg1->nodesetval == NULL) ||
   7114 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7115 		else
   7116 		    ret = 1;
   7117 		ret = (ret == arg2->boolval);
   7118 		break;
   7119 	    case XPATH_NUMBER:
   7120 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7121 		break;
   7122 	    case XPATH_STRING:
   7123 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7124 		break;
   7125 	    case XPATH_USERS:
   7126 	    case XPATH_POINT:
   7127 	    case XPATH_RANGE:
   7128 	    case XPATH_LOCATIONSET:
   7129 		TODO
   7130 		break;
   7131 	}
   7132 	xmlXPathReleaseObject(ctxt->context, arg1);
   7133 	xmlXPathReleaseObject(ctxt->context, arg2);
   7134 	return(ret);
   7135     }
   7136 
   7137     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7138 }
   7139 
   7140 /**
   7141  * xmlXPathNotEqualValues:
   7142  * @ctxt:  the XPath Parser context
   7143  *
   7144  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7145  *
   7146  * Returns 0 or 1 depending on the results of the test.
   7147  */
   7148 int
   7149 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7150     xmlXPathObjectPtr arg1, arg2, argtmp;
   7151     int ret = 0;
   7152 
   7153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7154     arg2 = valuePop(ctxt);
   7155     arg1 = valuePop(ctxt);
   7156     if ((arg1 == NULL) || (arg2 == NULL)) {
   7157 	if (arg1 != NULL)
   7158 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7159 	else
   7160 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7161 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7162     }
   7163 
   7164     if (arg1 == arg2) {
   7165 #ifdef DEBUG_EXPR
   7166         xmlGenericError(xmlGenericErrorContext,
   7167 		"NotEqual: by pointer\n");
   7168 #endif
   7169 	xmlXPathReleaseObject(ctxt->context, arg1);
   7170         return(0);
   7171     }
   7172 
   7173     /*
   7174      *If either argument is a nodeset, it's a 'special case'
   7175      */
   7176     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7177       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7178 	/*
   7179 	 *Hack it to assure arg1 is the nodeset
   7180 	 */
   7181 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7182 		argtmp = arg2;
   7183 		arg2 = arg1;
   7184 		arg1 = argtmp;
   7185 	}
   7186 	switch (arg2->type) {
   7187 	    case XPATH_UNDEFINED:
   7188 #ifdef DEBUG_EXPR
   7189 		xmlGenericError(xmlGenericErrorContext,
   7190 			"NotEqual: undefined\n");
   7191 #endif
   7192 		break;
   7193 	    case XPATH_NODESET:
   7194 	    case XPATH_XSLT_TREE:
   7195 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7196 		break;
   7197 	    case XPATH_BOOLEAN:
   7198 		if ((arg1->nodesetval == NULL) ||
   7199 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7200 		else
   7201 		    ret = 1;
   7202 		ret = (ret != arg2->boolval);
   7203 		break;
   7204 	    case XPATH_NUMBER:
   7205 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7206 		break;
   7207 	    case XPATH_STRING:
   7208 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7209 		break;
   7210 	    case XPATH_USERS:
   7211 	    case XPATH_POINT:
   7212 	    case XPATH_RANGE:
   7213 	    case XPATH_LOCATIONSET:
   7214 		TODO
   7215 		break;
   7216 	}
   7217 	xmlXPathReleaseObject(ctxt->context, arg1);
   7218 	xmlXPathReleaseObject(ctxt->context, arg2);
   7219 	return(ret);
   7220     }
   7221 
   7222     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7223 }
   7224 
   7225 /**
   7226  * xmlXPathCompareValues:
   7227  * @ctxt:  the XPath Parser context
   7228  * @inf:  less than (1) or greater than (0)
   7229  * @strict:  is the comparison strict
   7230  *
   7231  * Implement the compare operation on XPath objects:
   7232  *     @arg1 < @arg2    (1, 1, ...
   7233  *     @arg1 <= @arg2   (1, 0, ...
   7234  *     @arg1 > @arg2    (0, 1, ...
   7235  *     @arg1 >= @arg2   (0, 0, ...
   7236  *
   7237  * When neither object to be compared is a node-set and the operator is
   7238  * <=, <, >=, >, then the objects are compared by converted both objects
   7239  * to numbers and comparing the numbers according to IEEE 754. The <
   7240  * comparison will be true if and only if the first number is less than the
   7241  * second number. The <= comparison will be true if and only if the first
   7242  * number is less than or equal to the second number. The > comparison
   7243  * will be true if and only if the first number is greater than the second
   7244  * number. The >= comparison will be true if and only if the first number
   7245  * is greater than or equal to the second number.
   7246  *
   7247  * Returns 1 if the comparison succeeded, 0 if it failed
   7248  */
   7249 int
   7250 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7251     int ret = 0, arg1i = 0, arg2i = 0;
   7252     xmlXPathObjectPtr arg1, arg2;
   7253 
   7254     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7255     arg2 = valuePop(ctxt);
   7256     arg1 = valuePop(ctxt);
   7257     if ((arg1 == NULL) || (arg2 == NULL)) {
   7258 	if (arg1 != NULL)
   7259 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7260 	else
   7261 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7262 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7263     }
   7264 
   7265     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7266       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7267 	/*
   7268 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7269 	 * are not freed from within this routine; they will be freed from the
   7270 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7271 	 */
   7272 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7273 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7274 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7275 	} else {
   7276 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7277 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7278 			                          arg1, arg2);
   7279 	    } else {
   7280 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7281 			                          arg2, arg1);
   7282 	    }
   7283 	}
   7284 	return(ret);
   7285     }
   7286 
   7287     if (arg1->type != XPATH_NUMBER) {
   7288 	valuePush(ctxt, arg1);
   7289 	xmlXPathNumberFunction(ctxt, 1);
   7290 	arg1 = valuePop(ctxt);
   7291     }
   7292     if (arg1->type != XPATH_NUMBER) {
   7293 	xmlXPathFreeObject(arg1);
   7294 	xmlXPathFreeObject(arg2);
   7295 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7296     }
   7297     if (arg2->type != XPATH_NUMBER) {
   7298 	valuePush(ctxt, arg2);
   7299 	xmlXPathNumberFunction(ctxt, 1);
   7300 	arg2 = valuePop(ctxt);
   7301     }
   7302     if (arg2->type != XPATH_NUMBER) {
   7303 	xmlXPathReleaseObject(ctxt->context, arg1);
   7304 	xmlXPathReleaseObject(ctxt->context, arg2);
   7305 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7306     }
   7307     /*
   7308      * Add tests for infinity and nan
   7309      * => feedback on 3.4 for Inf and NaN
   7310      */
   7311     /* Hand check NaN and Infinity comparisons */
   7312     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7313 	ret=0;
   7314     } else {
   7315 	arg1i=xmlXPathIsInf(arg1->floatval);
   7316 	arg2i=xmlXPathIsInf(arg2->floatval);
   7317 	if (inf && strict) {
   7318 	    if ((arg1i == -1 && arg2i != -1) ||
   7319 		(arg2i == 1 && arg1i != 1)) {
   7320 		ret = 1;
   7321 	    } else if (arg1i == 0 && arg2i == 0) {
   7322 		ret = (arg1->floatval < arg2->floatval);
   7323 	    } else {
   7324 		ret = 0;
   7325 	    }
   7326 	}
   7327 	else if (inf && !strict) {
   7328 	    if (arg1i == -1 || arg2i == 1) {
   7329 		ret = 1;
   7330 	    } else if (arg1i == 0 && arg2i == 0) {
   7331 		ret = (arg1->floatval <= arg2->floatval);
   7332 	    } else {
   7333 		ret = 0;
   7334 	    }
   7335 	}
   7336 	else if (!inf && strict) {
   7337 	    if ((arg1i == 1 && arg2i != 1) ||
   7338 		(arg2i == -1 && arg1i != -1)) {
   7339 		ret = 1;
   7340 	    } else if (arg1i == 0 && arg2i == 0) {
   7341 		ret = (arg1->floatval > arg2->floatval);
   7342 	    } else {
   7343 		ret = 0;
   7344 	    }
   7345 	}
   7346 	else if (!inf && !strict) {
   7347 	    if (arg1i == 1 || arg2i == -1) {
   7348 		ret = 1;
   7349 	    } else if (arg1i == 0 && arg2i == 0) {
   7350 		ret = (arg1->floatval >= arg2->floatval);
   7351 	    } else {
   7352 		ret = 0;
   7353 	    }
   7354 	}
   7355     }
   7356     xmlXPathReleaseObject(ctxt->context, arg1);
   7357     xmlXPathReleaseObject(ctxt->context, arg2);
   7358     return(ret);
   7359 }
   7360 
   7361 /**
   7362  * xmlXPathValueFlipSign:
   7363  * @ctxt:  the XPath Parser context
   7364  *
   7365  * Implement the unary - operation on an XPath object
   7366  * The numeric operators convert their operands to numbers as if
   7367  * by calling the number function.
   7368  */
   7369 void
   7370 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7371     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7372     CAST_TO_NUMBER;
   7373     CHECK_TYPE(XPATH_NUMBER);
   7374     if (xmlXPathIsNaN(ctxt->value->floatval))
   7375         ctxt->value->floatval=xmlXPathNAN;
   7376     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
   7377         ctxt->value->floatval=xmlXPathNINF;
   7378     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
   7379         ctxt->value->floatval=xmlXPathPINF;
   7380     else if (ctxt->value->floatval == 0) {
   7381         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
   7382 	    ctxt->value->floatval = xmlXPathNZERO;
   7383 	else
   7384 	    ctxt->value->floatval = 0;
   7385     }
   7386     else
   7387         ctxt->value->floatval = - ctxt->value->floatval;
   7388 }
   7389 
   7390 /**
   7391  * xmlXPathAddValues:
   7392  * @ctxt:  the XPath Parser context
   7393  *
   7394  * Implement the add operation on XPath objects:
   7395  * The numeric operators convert their operands to numbers as if
   7396  * by calling the number function.
   7397  */
   7398 void
   7399 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7400     xmlXPathObjectPtr arg;
   7401     double val;
   7402 
   7403     arg = valuePop(ctxt);
   7404     if (arg == NULL)
   7405 	XP_ERROR(XPATH_INVALID_OPERAND);
   7406     val = xmlXPathCastToNumber(arg);
   7407     xmlXPathReleaseObject(ctxt->context, arg);
   7408     CAST_TO_NUMBER;
   7409     CHECK_TYPE(XPATH_NUMBER);
   7410     ctxt->value->floatval += val;
   7411 }
   7412 
   7413 /**
   7414  * xmlXPathSubValues:
   7415  * @ctxt:  the XPath Parser context
   7416  *
   7417  * Implement the subtraction operation on XPath objects:
   7418  * The numeric operators convert their operands to numbers as if
   7419  * by calling the number function.
   7420  */
   7421 void
   7422 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7423     xmlXPathObjectPtr arg;
   7424     double val;
   7425 
   7426     arg = valuePop(ctxt);
   7427     if (arg == NULL)
   7428 	XP_ERROR(XPATH_INVALID_OPERAND);
   7429     val = xmlXPathCastToNumber(arg);
   7430     xmlXPathReleaseObject(ctxt->context, arg);
   7431     CAST_TO_NUMBER;
   7432     CHECK_TYPE(XPATH_NUMBER);
   7433     ctxt->value->floatval -= val;
   7434 }
   7435 
   7436 /**
   7437  * xmlXPathMultValues:
   7438  * @ctxt:  the XPath Parser context
   7439  *
   7440  * Implement the multiply operation on XPath objects:
   7441  * The numeric operators convert their operands to numbers as if
   7442  * by calling the number function.
   7443  */
   7444 void
   7445 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7446     xmlXPathObjectPtr arg;
   7447     double val;
   7448 
   7449     arg = valuePop(ctxt);
   7450     if (arg == NULL)
   7451 	XP_ERROR(XPATH_INVALID_OPERAND);
   7452     val = xmlXPathCastToNumber(arg);
   7453     xmlXPathReleaseObject(ctxt->context, arg);
   7454     CAST_TO_NUMBER;
   7455     CHECK_TYPE(XPATH_NUMBER);
   7456     ctxt->value->floatval *= val;
   7457 }
   7458 
   7459 /**
   7460  * xmlXPathDivValues:
   7461  * @ctxt:  the XPath Parser context
   7462  *
   7463  * Implement the div operation on XPath objects @arg1 / @arg2:
   7464  * The numeric operators convert their operands to numbers as if
   7465  * by calling the number function.
   7466  */
   7467 void
   7468 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7469     xmlXPathObjectPtr arg;
   7470     double val;
   7471 
   7472     arg = valuePop(ctxt);
   7473     if (arg == NULL)
   7474 	XP_ERROR(XPATH_INVALID_OPERAND);
   7475     val = xmlXPathCastToNumber(arg);
   7476     xmlXPathReleaseObject(ctxt->context, arg);
   7477     CAST_TO_NUMBER;
   7478     CHECK_TYPE(XPATH_NUMBER);
   7479     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
   7480 	ctxt->value->floatval = xmlXPathNAN;
   7481     else if (val == 0 && xmlXPathGetSign(val) != 0) {
   7482 	if (ctxt->value->floatval == 0)
   7483 	    ctxt->value->floatval = xmlXPathNAN;
   7484 	else if (ctxt->value->floatval > 0)
   7485 	    ctxt->value->floatval = xmlXPathNINF;
   7486 	else if (ctxt->value->floatval < 0)
   7487 	    ctxt->value->floatval = xmlXPathPINF;
   7488     }
   7489     else if (val == 0) {
   7490 	if (ctxt->value->floatval == 0)
   7491 	    ctxt->value->floatval = xmlXPathNAN;
   7492 	else if (ctxt->value->floatval > 0)
   7493 	    ctxt->value->floatval = xmlXPathPINF;
   7494 	else if (ctxt->value->floatval < 0)
   7495 	    ctxt->value->floatval = xmlXPathNINF;
   7496     } else
   7497 	ctxt->value->floatval /= val;
   7498 }
   7499 
   7500 /**
   7501  * xmlXPathModValues:
   7502  * @ctxt:  the XPath Parser context
   7503  *
   7504  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7505  * The numeric operators convert their operands to numbers as if
   7506  * by calling the number function.
   7507  */
   7508 void
   7509 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7510     xmlXPathObjectPtr arg;
   7511     double arg1, arg2;
   7512 
   7513     arg = valuePop(ctxt);
   7514     if (arg == NULL)
   7515 	XP_ERROR(XPATH_INVALID_OPERAND);
   7516     arg2 = xmlXPathCastToNumber(arg);
   7517     xmlXPathReleaseObject(ctxt->context, arg);
   7518     CAST_TO_NUMBER;
   7519     CHECK_TYPE(XPATH_NUMBER);
   7520     arg1 = ctxt->value->floatval;
   7521     if (arg2 == 0)
   7522 	ctxt->value->floatval = xmlXPathNAN;
   7523     else {
   7524 	ctxt->value->floatval = fmod(arg1, arg2);
   7525     }
   7526 }
   7527 
   7528 /************************************************************************
   7529  *									*
   7530  *		The traversal functions					*
   7531  *									*
   7532  ************************************************************************/
   7533 
   7534 /*
   7535  * A traversal function enumerates nodes along an axis.
   7536  * Initially it must be called with NULL, and it indicates
   7537  * termination on the axis by returning NULL.
   7538  */
   7539 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7540                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7541 
   7542 /*
   7543  * xmlXPathTraversalFunctionExt:
   7544  * A traversal function enumerates nodes along an axis.
   7545  * Initially it must be called with NULL, and it indicates
   7546  * termination on the axis by returning NULL.
   7547  * The context node of the traversal is specified via @contextNode.
   7548  */
   7549 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7550                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7551 
   7552 /*
   7553  * xmlXPathNodeSetMergeFunction:
   7554  * Used for merging node sets in xmlXPathCollectAndTest().
   7555  */
   7556 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7557 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7558 
   7559 
   7560 /**
   7561  * xmlXPathNextSelf:
   7562  * @ctxt:  the XPath Parser context
   7563  * @cur:  the current node in the traversal
   7564  *
   7565  * Traversal function for the "self" direction
   7566  * The self axis contains just the context node itself
   7567  *
   7568  * Returns the next element following that axis
   7569  */
   7570 xmlNodePtr
   7571 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7572     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7573     if (cur == NULL)
   7574         return(ctxt->context->node);
   7575     return(NULL);
   7576 }
   7577 
   7578 /**
   7579  * xmlXPathNextChild:
   7580  * @ctxt:  the XPath Parser context
   7581  * @cur:  the current node in the traversal
   7582  *
   7583  * Traversal function for the "child" direction
   7584  * The child axis contains the children of the context node in document order.
   7585  *
   7586  * Returns the next element following that axis
   7587  */
   7588 xmlNodePtr
   7589 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7590     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7591     if (cur == NULL) {
   7592 	if (ctxt->context->node == NULL) return(NULL);
   7593 	switch (ctxt->context->node->type) {
   7594             case XML_ELEMENT_NODE:
   7595             case XML_TEXT_NODE:
   7596             case XML_CDATA_SECTION_NODE:
   7597             case XML_ENTITY_REF_NODE:
   7598             case XML_ENTITY_NODE:
   7599             case XML_PI_NODE:
   7600             case XML_COMMENT_NODE:
   7601             case XML_NOTATION_NODE:
   7602             case XML_DTD_NODE:
   7603 		return(ctxt->context->node->children);
   7604             case XML_DOCUMENT_NODE:
   7605             case XML_DOCUMENT_TYPE_NODE:
   7606             case XML_DOCUMENT_FRAG_NODE:
   7607             case XML_HTML_DOCUMENT_NODE:
   7608 #ifdef LIBXML_DOCB_ENABLED
   7609 	    case XML_DOCB_DOCUMENT_NODE:
   7610 #endif
   7611 		return(((xmlDocPtr) ctxt->context->node)->children);
   7612 	    case XML_ELEMENT_DECL:
   7613 	    case XML_ATTRIBUTE_DECL:
   7614 	    case XML_ENTITY_DECL:
   7615             case XML_ATTRIBUTE_NODE:
   7616 	    case XML_NAMESPACE_DECL:
   7617 	    case XML_XINCLUDE_START:
   7618 	    case XML_XINCLUDE_END:
   7619 		return(NULL);
   7620 	}
   7621 	return(NULL);
   7622     }
   7623     if ((cur->type == XML_DOCUMENT_NODE) ||
   7624         (cur->type == XML_HTML_DOCUMENT_NODE))
   7625 	return(NULL);
   7626     return(cur->next);
   7627 }
   7628 
   7629 /**
   7630  * xmlXPathNextChildElement:
   7631  * @ctxt:  the XPath Parser context
   7632  * @cur:  the current node in the traversal
   7633  *
   7634  * Traversal function for the "child" direction and nodes of type element.
   7635  * The child axis contains the children of the context node in document order.
   7636  *
   7637  * Returns the next element following that axis
   7638  */
   7639 static xmlNodePtr
   7640 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7641     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7642     if (cur == NULL) {
   7643 	cur = ctxt->context->node;
   7644 	if (cur == NULL) return(NULL);
   7645 	/*
   7646 	* Get the first element child.
   7647 	*/
   7648 	switch (cur->type) {
   7649             case XML_ELEMENT_NODE:
   7650 	    case XML_DOCUMENT_FRAG_NODE:
   7651 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7652             case XML_ENTITY_NODE:
   7653 		cur = cur->children;
   7654 		if (cur != NULL) {
   7655 		    if (cur->type == XML_ELEMENT_NODE)
   7656 			return(cur);
   7657 		    do {
   7658 			cur = cur->next;
   7659 		    } while ((cur != NULL) &&
   7660 			(cur->type != XML_ELEMENT_NODE));
   7661 		    return(cur);
   7662 		}
   7663 		return(NULL);
   7664             case XML_DOCUMENT_NODE:
   7665             case XML_HTML_DOCUMENT_NODE:
   7666 #ifdef LIBXML_DOCB_ENABLED
   7667 	    case XML_DOCB_DOCUMENT_NODE:
   7668 #endif
   7669 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7670 	    default:
   7671 		return(NULL);
   7672 	}
   7673 	return(NULL);
   7674     }
   7675     /*
   7676     * Get the next sibling element node.
   7677     */
   7678     switch (cur->type) {
   7679 	case XML_ELEMENT_NODE:
   7680 	case XML_TEXT_NODE:
   7681 	case XML_ENTITY_REF_NODE:
   7682 	case XML_ENTITY_NODE:
   7683 	case XML_CDATA_SECTION_NODE:
   7684 	case XML_PI_NODE:
   7685 	case XML_COMMENT_NODE:
   7686 	case XML_XINCLUDE_END:
   7687 	    break;
   7688 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7689 	default:
   7690 	    return(NULL);
   7691     }
   7692     if (cur->next != NULL) {
   7693 	if (cur->next->type == XML_ELEMENT_NODE)
   7694 	    return(cur->next);
   7695 	cur = cur->next;
   7696 	do {
   7697 	    cur = cur->next;
   7698 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7699 	return(cur);
   7700     }
   7701     return(NULL);
   7702 }
   7703 
   7704 /**
   7705  * xmlXPathNextDescendantOrSelfElemParent:
   7706  * @ctxt:  the XPath Parser context
   7707  * @cur:  the current node in the traversal
   7708  *
   7709  * Traversal function for the "descendant-or-self" axis.
   7710  * Additionally it returns only nodes which can be parents of
   7711  * element nodes.
   7712  *
   7713  *
   7714  * Returns the next element following that axis
   7715  */
   7716 static xmlNodePtr
   7717 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7718 				       xmlNodePtr contextNode)
   7719 {
   7720     if (cur == NULL) {
   7721 	if (contextNode == NULL)
   7722 	    return(NULL);
   7723 	switch (contextNode->type) {
   7724 	    case XML_ELEMENT_NODE:
   7725 	    case XML_XINCLUDE_START:
   7726 	    case XML_DOCUMENT_FRAG_NODE:
   7727 	    case XML_DOCUMENT_NODE:
   7728 #ifdef LIBXML_DOCB_ENABLED
   7729 	    case XML_DOCB_DOCUMENT_NODE:
   7730 #endif
   7731 	    case XML_HTML_DOCUMENT_NODE:
   7732 		return(contextNode);
   7733 	    default:
   7734 		return(NULL);
   7735 	}
   7736 	return(NULL);
   7737     } else {
   7738 	xmlNodePtr start = cur;
   7739 
   7740 	while (cur != NULL) {
   7741 	    switch (cur->type) {
   7742 		case XML_ELEMENT_NODE:
   7743 		/* TODO: OK to have XInclude here? */
   7744 		case XML_XINCLUDE_START:
   7745 		case XML_DOCUMENT_FRAG_NODE:
   7746 		    if (cur != start)
   7747 			return(cur);
   7748 		    if (cur->children != NULL) {
   7749 			cur = cur->children;
   7750 			continue;
   7751 		    }
   7752 		    break;
   7753 		/* Not sure if we need those here. */
   7754 		case XML_DOCUMENT_NODE:
   7755 #ifdef LIBXML_DOCB_ENABLED
   7756 		case XML_DOCB_DOCUMENT_NODE:
   7757 #endif
   7758 		case XML_HTML_DOCUMENT_NODE:
   7759 		    if (cur != start)
   7760 			return(cur);
   7761 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7762 		default:
   7763 		    break;
   7764 	    }
   7765 
   7766 next_sibling:
   7767 	    if ((cur == NULL) || (cur == contextNode))
   7768 		return(NULL);
   7769 	    if (cur->next != NULL) {
   7770 		cur = cur->next;
   7771 	    } else {
   7772 		cur = cur->parent;
   7773 		goto next_sibling;
   7774 	    }
   7775 	}
   7776     }
   7777     return(NULL);
   7778 }
   7779 
   7780 /**
   7781  * xmlXPathNextDescendant:
   7782  * @ctxt:  the XPath Parser context
   7783  * @cur:  the current node in the traversal
   7784  *
   7785  * Traversal function for the "descendant" direction
   7786  * the descendant axis contains the descendants of the context node in document
   7787  * order; a descendant is a child or a child of a child and so on.
   7788  *
   7789  * Returns the next element following that axis
   7790  */
   7791 xmlNodePtr
   7792 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7793     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7794     if (cur == NULL) {
   7795 	if (ctxt->context->node == NULL)
   7796 	    return(NULL);
   7797 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7798 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7799 	    return(NULL);
   7800 
   7801         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7802 	    return(ctxt->context->doc->children);
   7803         return(ctxt->context->node->children);
   7804     }
   7805 
   7806     if (cur->children != NULL) {
   7807 	/*
   7808 	 * Do not descend on entities declarations
   7809 	 */
   7810 	if (cur->children->type != XML_ENTITY_DECL) {
   7811 	    cur = cur->children;
   7812 	    /*
   7813 	     * Skip DTDs
   7814 	     */
   7815 	    if (cur->type != XML_DTD_NODE)
   7816 		return(cur);
   7817 	}
   7818     }
   7819 
   7820     if (cur == ctxt->context->node) return(NULL);
   7821 
   7822     while (cur->next != NULL) {
   7823 	cur = cur->next;
   7824 	if ((cur->type != XML_ENTITY_DECL) &&
   7825 	    (cur->type != XML_DTD_NODE))
   7826 	    return(cur);
   7827     }
   7828 
   7829     do {
   7830         cur = cur->parent;
   7831 	if (cur == NULL) break;
   7832 	if (cur == ctxt->context->node) return(NULL);
   7833 	if (cur->next != NULL) {
   7834 	    cur = cur->next;
   7835 	    return(cur);
   7836 	}
   7837     } while (cur != NULL);
   7838     return(cur);
   7839 }
   7840 
   7841 /**
   7842  * xmlXPathNextDescendantOrSelf:
   7843  * @ctxt:  the XPath Parser context
   7844  * @cur:  the current node in the traversal
   7845  *
   7846  * Traversal function for the "descendant-or-self" direction
   7847  * the descendant-or-self axis contains the context node and the descendants
   7848  * of the context node in document order; thus the context node is the first
   7849  * node on the axis, and the first child of the context node is the second node
   7850  * on the axis
   7851  *
   7852  * Returns the next element following that axis
   7853  */
   7854 xmlNodePtr
   7855 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7856     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7857     if (cur == NULL) {
   7858 	if (ctxt->context->node == NULL)
   7859 	    return(NULL);
   7860 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7861 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7862 	    return(NULL);
   7863         return(ctxt->context->node);
   7864     }
   7865 
   7866     return(xmlXPathNextDescendant(ctxt, cur));
   7867 }
   7868 
   7869 /**
   7870  * xmlXPathNextParent:
   7871  * @ctxt:  the XPath Parser context
   7872  * @cur:  the current node in the traversal
   7873  *
   7874  * Traversal function for the "parent" direction
   7875  * The parent axis contains the parent of the context node, if there is one.
   7876  *
   7877  * Returns the next element following that axis
   7878  */
   7879 xmlNodePtr
   7880 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7881     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7882     /*
   7883      * the parent of an attribute or namespace node is the element
   7884      * to which the attribute or namespace node is attached
   7885      * Namespace handling !!!
   7886      */
   7887     if (cur == NULL) {
   7888 	if (ctxt->context->node == NULL) return(NULL);
   7889 	switch (ctxt->context->node->type) {
   7890             case XML_ELEMENT_NODE:
   7891             case XML_TEXT_NODE:
   7892             case XML_CDATA_SECTION_NODE:
   7893             case XML_ENTITY_REF_NODE:
   7894             case XML_ENTITY_NODE:
   7895             case XML_PI_NODE:
   7896             case XML_COMMENT_NODE:
   7897             case XML_NOTATION_NODE:
   7898             case XML_DTD_NODE:
   7899 	    case XML_ELEMENT_DECL:
   7900 	    case XML_ATTRIBUTE_DECL:
   7901 	    case XML_XINCLUDE_START:
   7902 	    case XML_XINCLUDE_END:
   7903 	    case XML_ENTITY_DECL:
   7904 		if (ctxt->context->node->parent == NULL)
   7905 		    return((xmlNodePtr) ctxt->context->doc);
   7906 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7907 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7908 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7909 				 BAD_CAST "fake node libxslt"))))
   7910 		    return(NULL);
   7911 		return(ctxt->context->node->parent);
   7912             case XML_ATTRIBUTE_NODE: {
   7913 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7914 
   7915 		return(att->parent);
   7916 	    }
   7917             case XML_DOCUMENT_NODE:
   7918             case XML_DOCUMENT_TYPE_NODE:
   7919             case XML_DOCUMENT_FRAG_NODE:
   7920             case XML_HTML_DOCUMENT_NODE:
   7921 #ifdef LIBXML_DOCB_ENABLED
   7922 	    case XML_DOCB_DOCUMENT_NODE:
   7923 #endif
   7924                 return(NULL);
   7925 	    case XML_NAMESPACE_DECL: {
   7926 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7927 
   7928 		if ((ns->next != NULL) &&
   7929 		    (ns->next->type != XML_NAMESPACE_DECL))
   7930 		    return((xmlNodePtr) ns->next);
   7931                 return(NULL);
   7932 	    }
   7933 	}
   7934     }
   7935     return(NULL);
   7936 }
   7937 
   7938 /**
   7939  * xmlXPathNextAncestor:
   7940  * @ctxt:  the XPath Parser context
   7941  * @cur:  the current node in the traversal
   7942  *
   7943  * Traversal function for the "ancestor" direction
   7944  * the ancestor axis contains the ancestors of the context node; the ancestors
   7945  * of the context node consist of the parent of context node and the parent's
   7946  * parent and so on; the nodes are ordered in reverse document order; thus the
   7947  * parent is the first node on the axis, and the parent's parent is the second
   7948  * node on the axis
   7949  *
   7950  * Returns the next element following that axis
   7951  */
   7952 xmlNodePtr
   7953 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7954     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7955     /*
   7956      * the parent of an attribute or namespace node is the element
   7957      * to which the attribute or namespace node is attached
   7958      * !!!!!!!!!!!!!
   7959      */
   7960     if (cur == NULL) {
   7961 	if (ctxt->context->node == NULL) return(NULL);
   7962 	switch (ctxt->context->node->type) {
   7963             case XML_ELEMENT_NODE:
   7964             case XML_TEXT_NODE:
   7965             case XML_CDATA_SECTION_NODE:
   7966             case XML_ENTITY_REF_NODE:
   7967             case XML_ENTITY_NODE:
   7968             case XML_PI_NODE:
   7969             case XML_COMMENT_NODE:
   7970 	    case XML_DTD_NODE:
   7971 	    case XML_ELEMENT_DECL:
   7972 	    case XML_ATTRIBUTE_DECL:
   7973 	    case XML_ENTITY_DECL:
   7974             case XML_NOTATION_NODE:
   7975 	    case XML_XINCLUDE_START:
   7976 	    case XML_XINCLUDE_END:
   7977 		if (ctxt->context->node->parent == NULL)
   7978 		    return((xmlNodePtr) ctxt->context->doc);
   7979 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7980 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7981 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7982 				 BAD_CAST "fake node libxslt"))))
   7983 		    return(NULL);
   7984 		return(ctxt->context->node->parent);
   7985             case XML_ATTRIBUTE_NODE: {
   7986 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   7987 
   7988 		return(tmp->parent);
   7989 	    }
   7990             case XML_DOCUMENT_NODE:
   7991             case XML_DOCUMENT_TYPE_NODE:
   7992             case XML_DOCUMENT_FRAG_NODE:
   7993             case XML_HTML_DOCUMENT_NODE:
   7994 #ifdef LIBXML_DOCB_ENABLED
   7995 	    case XML_DOCB_DOCUMENT_NODE:
   7996 #endif
   7997                 return(NULL);
   7998 	    case XML_NAMESPACE_DECL: {
   7999 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8000 
   8001 		if ((ns->next != NULL) &&
   8002 		    (ns->next->type != XML_NAMESPACE_DECL))
   8003 		    return((xmlNodePtr) ns->next);
   8004 		/* Bad, how did that namespace end up here ? */
   8005                 return(NULL);
   8006 	    }
   8007 	}
   8008 	return(NULL);
   8009     }
   8010     if (cur == ctxt->context->doc->children)
   8011 	return((xmlNodePtr) ctxt->context->doc);
   8012     if (cur == (xmlNodePtr) ctxt->context->doc)
   8013 	return(NULL);
   8014     switch (cur->type) {
   8015 	case XML_ELEMENT_NODE:
   8016 	case XML_TEXT_NODE:
   8017 	case XML_CDATA_SECTION_NODE:
   8018 	case XML_ENTITY_REF_NODE:
   8019 	case XML_ENTITY_NODE:
   8020 	case XML_PI_NODE:
   8021 	case XML_COMMENT_NODE:
   8022 	case XML_NOTATION_NODE:
   8023 	case XML_DTD_NODE:
   8024         case XML_ELEMENT_DECL:
   8025         case XML_ATTRIBUTE_DECL:
   8026         case XML_ENTITY_DECL:
   8027 	case XML_XINCLUDE_START:
   8028 	case XML_XINCLUDE_END:
   8029 	    if (cur->parent == NULL)
   8030 		return(NULL);
   8031 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   8032 		((cur->parent->name[0] == ' ') ||
   8033 		 (xmlStrEqual(cur->parent->name,
   8034 			      BAD_CAST "fake node libxslt"))))
   8035 		return(NULL);
   8036 	    return(cur->parent);
   8037 	case XML_ATTRIBUTE_NODE: {
   8038 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   8039 
   8040 	    return(att->parent);
   8041 	}
   8042 	case XML_NAMESPACE_DECL: {
   8043 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8044 
   8045 	    if ((ns->next != NULL) &&
   8046 	        (ns->next->type != XML_NAMESPACE_DECL))
   8047 	        return((xmlNodePtr) ns->next);
   8048 	    /* Bad, how did that namespace end up here ? */
   8049             return(NULL);
   8050 	}
   8051 	case XML_DOCUMENT_NODE:
   8052 	case XML_DOCUMENT_TYPE_NODE:
   8053 	case XML_DOCUMENT_FRAG_NODE:
   8054 	case XML_HTML_DOCUMENT_NODE:
   8055 #ifdef LIBXML_DOCB_ENABLED
   8056 	case XML_DOCB_DOCUMENT_NODE:
   8057 #endif
   8058 	    return(NULL);
   8059     }
   8060     return(NULL);
   8061 }
   8062 
   8063 /**
   8064  * xmlXPathNextAncestorOrSelf:
   8065  * @ctxt:  the XPath Parser context
   8066  * @cur:  the current node in the traversal
   8067  *
   8068  * Traversal function for the "ancestor-or-self" direction
   8069  * he ancestor-or-self axis contains the context node and ancestors of
   8070  * the context node in reverse document order; thus the context node is
   8071  * the first node on the axis, and the context node's parent the second;
   8072  * parent here is defined the same as with the parent axis.
   8073  *
   8074  * Returns the next element following that axis
   8075  */
   8076 xmlNodePtr
   8077 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8078     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8079     if (cur == NULL)
   8080         return(ctxt->context->node);
   8081     return(xmlXPathNextAncestor(ctxt, cur));
   8082 }
   8083 
   8084 /**
   8085  * xmlXPathNextFollowingSibling:
   8086  * @ctxt:  the XPath Parser context
   8087  * @cur:  the current node in the traversal
   8088  *
   8089  * Traversal function for the "following-sibling" direction
   8090  * The following-sibling axis contains the following siblings of the context
   8091  * node in document order.
   8092  *
   8093  * Returns the next element following that axis
   8094  */
   8095 xmlNodePtr
   8096 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8097     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8098     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8099 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8100 	return(NULL);
   8101     if (cur == (xmlNodePtr) ctxt->context->doc)
   8102         return(NULL);
   8103     if (cur == NULL)
   8104         return(ctxt->context->node->next);
   8105     return(cur->next);
   8106 }
   8107 
   8108 /**
   8109  * xmlXPathNextPrecedingSibling:
   8110  * @ctxt:  the XPath Parser context
   8111  * @cur:  the current node in the traversal
   8112  *
   8113  * Traversal function for the "preceding-sibling" direction
   8114  * The preceding-sibling axis contains the preceding siblings of the context
   8115  * node in reverse document order; the first preceding sibling is first on the
   8116  * axis; the sibling preceding that node is the second on the axis and so on.
   8117  *
   8118  * Returns the next element following that axis
   8119  */
   8120 xmlNodePtr
   8121 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8122     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8123     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8124 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8125 	return(NULL);
   8126     if (cur == (xmlNodePtr) ctxt->context->doc)
   8127         return(NULL);
   8128     if (cur == NULL)
   8129         return(ctxt->context->node->prev);
   8130     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8131 	cur = cur->prev;
   8132 	if (cur == NULL)
   8133 	    return(ctxt->context->node->prev);
   8134     }
   8135     return(cur->prev);
   8136 }
   8137 
   8138 /**
   8139  * xmlXPathNextFollowing:
   8140  * @ctxt:  the XPath Parser context
   8141  * @cur:  the current node in the traversal
   8142  *
   8143  * Traversal function for the "following" direction
   8144  * The following axis contains all nodes in the same document as the context
   8145  * node that are after the context node in document order, excluding any
   8146  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8147  * are ordered in document order
   8148  *
   8149  * Returns the next element following that axis
   8150  */
   8151 xmlNodePtr
   8152 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8154     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8155         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8156         return(cur->children);
   8157 
   8158     if (cur == NULL) {
   8159         cur = ctxt->context->node;
   8160         if (cur->type == XML_NAMESPACE_DECL)
   8161             return(NULL);
   8162         if (cur->type == XML_ATTRIBUTE_NODE)
   8163             cur = cur->parent;
   8164     }
   8165     if (cur == NULL) return(NULL) ; /* ERROR */
   8166     if (cur->next != NULL) return(cur->next) ;
   8167     do {
   8168         cur = cur->parent;
   8169         if (cur == NULL) break;
   8170         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8171         if (cur->next != NULL) return(cur->next);
   8172     } while (cur != NULL);
   8173     return(cur);
   8174 }
   8175 
   8176 /*
   8177  * xmlXPathIsAncestor:
   8178  * @ancestor:  the ancestor node
   8179  * @node:  the current node
   8180  *
   8181  * Check that @ancestor is a @node's ancestor
   8182  *
   8183  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8184  */
   8185 static int
   8186 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8187     if ((ancestor == NULL) || (node == NULL)) return(0);
   8188     /* nodes need to be in the same document */
   8189     if (ancestor->doc != node->doc) return(0);
   8190     /* avoid searching if ancestor or node is the root node */
   8191     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8192     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8193     while (node->parent != NULL) {
   8194         if (node->parent == ancestor)
   8195             return(1);
   8196 	node = node->parent;
   8197     }
   8198     return(0);
   8199 }
   8200 
   8201 /**
   8202  * xmlXPathNextPreceding:
   8203  * @ctxt:  the XPath Parser context
   8204  * @cur:  the current node in the traversal
   8205  *
   8206  * Traversal function for the "preceding" direction
   8207  * the preceding axis contains all nodes in the same document as the context
   8208  * node that are before the context node in document order, excluding any
   8209  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8210  * ordered in reverse document order
   8211  *
   8212  * Returns the next element following that axis
   8213  */
   8214 xmlNodePtr
   8215 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8216 {
   8217     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8218     if (cur == NULL) {
   8219         cur = ctxt->context->node;
   8220         if (cur->type == XML_NAMESPACE_DECL)
   8221             return(NULL);
   8222         if (cur->type == XML_ATTRIBUTE_NODE)
   8223             return(cur->parent);
   8224     }
   8225     if (cur == NULL)
   8226 	return (NULL);
   8227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8228 	cur = cur->prev;
   8229     do {
   8230         if (cur->prev != NULL) {
   8231             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8232             return (cur);
   8233         }
   8234 
   8235         cur = cur->parent;
   8236         if (cur == NULL)
   8237             return (NULL);
   8238         if (cur == ctxt->context->doc->children)
   8239             return (NULL);
   8240     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8241     return (cur);
   8242 }
   8243 
   8244 /**
   8245  * xmlXPathNextPrecedingInternal:
   8246  * @ctxt:  the XPath Parser context
   8247  * @cur:  the current node in the traversal
   8248  *
   8249  * Traversal function for the "preceding" direction
   8250  * the preceding axis contains all nodes in the same document as the context
   8251  * node that are before the context node in document order, excluding any
   8252  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8253  * ordered in reverse document order
   8254  * This is a faster implementation but internal only since it requires a
   8255  * state kept in the parser context: ctxt->ancestor.
   8256  *
   8257  * Returns the next element following that axis
   8258  */
   8259 static xmlNodePtr
   8260 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8261                               xmlNodePtr cur)
   8262 {
   8263     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8264     if (cur == NULL) {
   8265         cur = ctxt->context->node;
   8266         if (cur == NULL)
   8267             return (NULL);
   8268         if (cur->type == XML_NAMESPACE_DECL)
   8269             return (NULL);
   8270         ctxt->ancestor = cur->parent;
   8271     }
   8272     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8273 	cur = cur->prev;
   8274     while (cur->prev == NULL) {
   8275         cur = cur->parent;
   8276         if (cur == NULL)
   8277             return (NULL);
   8278         if (cur == ctxt->context->doc->children)
   8279             return (NULL);
   8280         if (cur != ctxt->ancestor)
   8281             return (cur);
   8282         ctxt->ancestor = cur->parent;
   8283     }
   8284     cur = cur->prev;
   8285     while (cur->last != NULL)
   8286         cur = cur->last;
   8287     return (cur);
   8288 }
   8289 
   8290 /**
   8291  * xmlXPathNextNamespace:
   8292  * @ctxt:  the XPath Parser context
   8293  * @cur:  the current attribute in the traversal
   8294  *
   8295  * Traversal function for the "namespace" direction
   8296  * the namespace axis contains the namespace nodes of the context node;
   8297  * the order of nodes on this axis is implementation-defined; the axis will
   8298  * be empty unless the context node is an element
   8299  *
   8300  * We keep the XML namespace node at the end of the list.
   8301  *
   8302  * Returns the next element following that axis
   8303  */
   8304 xmlNodePtr
   8305 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8306     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8307     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8308     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
   8309         if (ctxt->context->tmpNsList != NULL)
   8310 	    xmlFree(ctxt->context->tmpNsList);
   8311 	ctxt->context->tmpNsList =
   8312 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8313 	ctxt->context->tmpNsNr = 0;
   8314 	if (ctxt->context->tmpNsList != NULL) {
   8315 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8316 		ctxt->context->tmpNsNr++;
   8317 	    }
   8318 	}
   8319 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8320     }
   8321     if (ctxt->context->tmpNsNr > 0) {
   8322 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8323     } else {
   8324 	if (ctxt->context->tmpNsList != NULL)
   8325 	    xmlFree(ctxt->context->tmpNsList);
   8326 	ctxt->context->tmpNsList = NULL;
   8327 	return(NULL);
   8328     }
   8329 }
   8330 
   8331 /**
   8332  * xmlXPathNextAttribute:
   8333  * @ctxt:  the XPath Parser context
   8334  * @cur:  the current attribute in the traversal
   8335  *
   8336  * Traversal function for the "attribute" direction
   8337  * TODO: support DTD inherited default attributes
   8338  *
   8339  * Returns the next element following that axis
   8340  */
   8341 xmlNodePtr
   8342 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8343     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8344     if (ctxt->context->node == NULL)
   8345 	return(NULL);
   8346     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8347 	return(NULL);
   8348     if (cur == NULL) {
   8349         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8350 	    return(NULL);
   8351         return((xmlNodePtr)ctxt->context->node->properties);
   8352     }
   8353     return((xmlNodePtr)cur->next);
   8354 }
   8355 
   8356 /************************************************************************
   8357  *									*
   8358  *		NodeTest Functions					*
   8359  *									*
   8360  ************************************************************************/
   8361 
   8362 #define IS_FUNCTION			200
   8363 
   8364 
   8365 /************************************************************************
   8366  *									*
   8367  *		Implicit tree core function library			*
   8368  *									*
   8369  ************************************************************************/
   8370 
   8371 /**
   8372  * xmlXPathRoot:
   8373  * @ctxt:  the XPath Parser context
   8374  *
   8375  * Initialize the context to the root of the document
   8376  */
   8377 void
   8378 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8379     if ((ctxt == NULL) || (ctxt->context == NULL))
   8380 	return;
   8381     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8382     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8383 	ctxt->context->node));
   8384 }
   8385 
   8386 /************************************************************************
   8387  *									*
   8388  *		The explicit core function library			*
   8389  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8390  *									*
   8391  ************************************************************************/
   8392 
   8393 
   8394 /**
   8395  * xmlXPathLastFunction:
   8396  * @ctxt:  the XPath Parser context
   8397  * @nargs:  the number of arguments
   8398  *
   8399  * Implement the last() XPath function
   8400  *    number last()
   8401  * The last function returns the number of nodes in the context node list.
   8402  */
   8403 void
   8404 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8405     CHECK_ARITY(0);
   8406     if (ctxt->context->contextSize >= 0) {
   8407 	valuePush(ctxt,
   8408 	    xmlXPathCacheNewFloat(ctxt->context,
   8409 		(double) ctxt->context->contextSize));
   8410 #ifdef DEBUG_EXPR
   8411 	xmlGenericError(xmlGenericErrorContext,
   8412 		"last() : %d\n", ctxt->context->contextSize);
   8413 #endif
   8414     } else {
   8415 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8416     }
   8417 }
   8418 
   8419 /**
   8420  * xmlXPathPositionFunction:
   8421  * @ctxt:  the XPath Parser context
   8422  * @nargs:  the number of arguments
   8423  *
   8424  * Implement the position() XPath function
   8425  *    number position()
   8426  * The position function returns the position of the context node in the
   8427  * context node list. The first position is 1, and so the last position
   8428  * will be equal to last().
   8429  */
   8430 void
   8431 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8432     CHECK_ARITY(0);
   8433     if (ctxt->context->proximityPosition >= 0) {
   8434 	valuePush(ctxt,
   8435 	      xmlXPathCacheNewFloat(ctxt->context,
   8436 		(double) ctxt->context->proximityPosition));
   8437 #ifdef DEBUG_EXPR
   8438 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8439 		ctxt->context->proximityPosition);
   8440 #endif
   8441     } else {
   8442 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8443     }
   8444 }
   8445 
   8446 /**
   8447  * xmlXPathCountFunction:
   8448  * @ctxt:  the XPath Parser context
   8449  * @nargs:  the number of arguments
   8450  *
   8451  * Implement the count() XPath function
   8452  *    number count(node-set)
   8453  */
   8454 void
   8455 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8456     xmlXPathObjectPtr cur;
   8457 
   8458     CHECK_ARITY(1);
   8459     if ((ctxt->value == NULL) ||
   8460 	((ctxt->value->type != XPATH_NODESET) &&
   8461 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8462 	XP_ERROR(XPATH_INVALID_TYPE);
   8463     cur = valuePop(ctxt);
   8464 
   8465     if ((cur == NULL) || (cur->nodesetval == NULL))
   8466 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8467     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8468 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8469 	    (double) cur->nodesetval->nodeNr));
   8470     } else {
   8471 	if ((cur->nodesetval->nodeNr != 1) ||
   8472 	    (cur->nodesetval->nodeTab == NULL)) {
   8473 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8474 	} else {
   8475 	    xmlNodePtr tmp;
   8476 	    int i = 0;
   8477 
   8478 	    tmp = cur->nodesetval->nodeTab[0];
   8479 	    if (tmp != NULL) {
   8480 		tmp = tmp->children;
   8481 		while (tmp != NULL) {
   8482 		    tmp = tmp->next;
   8483 		    i++;
   8484 		}
   8485 	    }
   8486 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8487 	}
   8488     }
   8489     xmlXPathReleaseObject(ctxt->context, cur);
   8490 }
   8491 
   8492 /**
   8493  * xmlXPathGetElementsByIds:
   8494  * @doc:  the document
   8495  * @ids:  a whitespace separated list of IDs
   8496  *
   8497  * Selects elements by their unique ID.
   8498  *
   8499  * Returns a node-set of selected elements.
   8500  */
   8501 static xmlNodeSetPtr
   8502 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8503     xmlNodeSetPtr ret;
   8504     const xmlChar *cur = ids;
   8505     xmlChar *ID;
   8506     xmlAttrPtr attr;
   8507     xmlNodePtr elem = NULL;
   8508 
   8509     if (ids == NULL) return(NULL);
   8510 
   8511     ret = xmlXPathNodeSetCreate(NULL);
   8512     if (ret == NULL)
   8513         return(ret);
   8514 
   8515     while (IS_BLANK_CH(*cur)) cur++;
   8516     while (*cur != 0) {
   8517 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8518 	    cur++;
   8519 
   8520         ID = xmlStrndup(ids, cur - ids);
   8521 	if (ID != NULL) {
   8522 	    /*
   8523 	     * We used to check the fact that the value passed
   8524 	     * was an NCName, but this generated much troubles for
   8525 	     * me and Aleksey Sanin, people blatantly violated that
   8526 	     * constaint, like Visa3D spec.
   8527 	     * if (xmlValidateNCName(ID, 1) == 0)
   8528 	     */
   8529 	    attr = xmlGetID(doc, ID);
   8530 	    if (attr != NULL) {
   8531 		if (attr->type == XML_ATTRIBUTE_NODE)
   8532 		    elem = attr->parent;
   8533 		else if (attr->type == XML_ELEMENT_NODE)
   8534 		    elem = (xmlNodePtr) attr;
   8535 		else
   8536 		    elem = NULL;
   8537 		if (elem != NULL)
   8538 		    xmlXPathNodeSetAdd(ret, elem);
   8539 	    }
   8540 	    xmlFree(ID);
   8541 	}
   8542 
   8543 	while (IS_BLANK_CH(*cur)) cur++;
   8544 	ids = cur;
   8545     }
   8546     return(ret);
   8547 }
   8548 
   8549 /**
   8550  * xmlXPathIdFunction:
   8551  * @ctxt:  the XPath Parser context
   8552  * @nargs:  the number of arguments
   8553  *
   8554  * Implement the id() XPath function
   8555  *    node-set id(object)
   8556  * The id function selects elements by their unique ID
   8557  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8558  * then the result is the union of the result of applying id to the
   8559  * string value of each of the nodes in the argument node-set. When the
   8560  * argument to id is of any other type, the argument is converted to a
   8561  * string as if by a call to the string function; the string is split
   8562  * into a whitespace-separated list of tokens (whitespace is any sequence
   8563  * of characters matching the production S); the result is a node-set
   8564  * containing the elements in the same document as the context node that
   8565  * have a unique ID equal to any of the tokens in the list.
   8566  */
   8567 void
   8568 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8569     xmlChar *tokens;
   8570     xmlNodeSetPtr ret;
   8571     xmlXPathObjectPtr obj;
   8572 
   8573     CHECK_ARITY(1);
   8574     obj = valuePop(ctxt);
   8575     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8576     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8577 	xmlNodeSetPtr ns;
   8578 	int i;
   8579 
   8580 	ret = xmlXPathNodeSetCreate(NULL);
   8581         /*
   8582          * FIXME -- in an out-of-memory condition this will behave badly.
   8583          * The solution is not clear -- we already popped an item from
   8584          * ctxt, so the object is in a corrupt state.
   8585          */
   8586 
   8587 	if (obj->nodesetval != NULL) {
   8588 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8589 		tokens =
   8590 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8591 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8592 		ret = xmlXPathNodeSetMerge(ret, ns);
   8593 		xmlXPathFreeNodeSet(ns);
   8594 		if (tokens != NULL)
   8595 		    xmlFree(tokens);
   8596 	    }
   8597 	}
   8598 	xmlXPathReleaseObject(ctxt->context, obj);
   8599 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8600 	return;
   8601     }
   8602     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8603     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8604     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8605     xmlXPathReleaseObject(ctxt->context, obj);
   8606     return;
   8607 }
   8608 
   8609 /**
   8610  * xmlXPathLocalNameFunction:
   8611  * @ctxt:  the XPath Parser context
   8612  * @nargs:  the number of arguments
   8613  *
   8614  * Implement the local-name() XPath function
   8615  *    string local-name(node-set?)
   8616  * The local-name function returns a string containing the local part
   8617  * of the name of the node in the argument node-set that is first in
   8618  * document order. If the node-set is empty or the first node has no
   8619  * name, an empty string is returned. If the argument is omitted it
   8620  * defaults to the context node.
   8621  */
   8622 void
   8623 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8624     xmlXPathObjectPtr cur;
   8625 
   8626     if (ctxt == NULL) return;
   8627 
   8628     if (nargs == 0) {
   8629 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8630 	    ctxt->context->node));
   8631 	nargs = 1;
   8632     }
   8633 
   8634     CHECK_ARITY(1);
   8635     if ((ctxt->value == NULL) ||
   8636 	((ctxt->value->type != XPATH_NODESET) &&
   8637 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8638 	XP_ERROR(XPATH_INVALID_TYPE);
   8639     cur = valuePop(ctxt);
   8640 
   8641     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8642 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8643     } else {
   8644 	int i = 0; /* Should be first in document order !!!!! */
   8645 	switch (cur->nodesetval->nodeTab[i]->type) {
   8646 	case XML_ELEMENT_NODE:
   8647 	case XML_ATTRIBUTE_NODE:
   8648 	case XML_PI_NODE:
   8649 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8650 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8651 	    else
   8652 		valuePush(ctxt,
   8653 		      xmlXPathCacheNewString(ctxt->context,
   8654 			cur->nodesetval->nodeTab[i]->name));
   8655 	    break;
   8656 	case XML_NAMESPACE_DECL:
   8657 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8658 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8659 	    break;
   8660 	default:
   8661 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8662 	}
   8663     }
   8664     xmlXPathReleaseObject(ctxt->context, cur);
   8665 }
   8666 
   8667 /**
   8668  * xmlXPathNamespaceURIFunction:
   8669  * @ctxt:  the XPath Parser context
   8670  * @nargs:  the number of arguments
   8671  *
   8672  * Implement the namespace-uri() XPath function
   8673  *    string namespace-uri(node-set?)
   8674  * The namespace-uri function returns a string containing the
   8675  * namespace URI of the expanded name of the node in the argument
   8676  * node-set that is first in document order. If the node-set is empty,
   8677  * the first node has no name, or the expanded name has no namespace
   8678  * URI, an empty string is returned. If the argument is omitted it
   8679  * defaults to the context node.
   8680  */
   8681 void
   8682 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8683     xmlXPathObjectPtr cur;
   8684 
   8685     if (ctxt == NULL) return;
   8686 
   8687     if (nargs == 0) {
   8688 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8689 	    ctxt->context->node));
   8690 	nargs = 1;
   8691     }
   8692     CHECK_ARITY(1);
   8693     if ((ctxt->value == NULL) ||
   8694 	((ctxt->value->type != XPATH_NODESET) &&
   8695 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8696 	XP_ERROR(XPATH_INVALID_TYPE);
   8697     cur = valuePop(ctxt);
   8698 
   8699     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8700 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8701     } else {
   8702 	int i = 0; /* Should be first in document order !!!!! */
   8703 	switch (cur->nodesetval->nodeTab[i]->type) {
   8704 	case XML_ELEMENT_NODE:
   8705 	case XML_ATTRIBUTE_NODE:
   8706 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8707 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8708 	    else
   8709 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8710 			  cur->nodesetval->nodeTab[i]->ns->href));
   8711 	    break;
   8712 	default:
   8713 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8714 	}
   8715     }
   8716     xmlXPathReleaseObject(ctxt->context, cur);
   8717 }
   8718 
   8719 /**
   8720  * xmlXPathNameFunction:
   8721  * @ctxt:  the XPath Parser context
   8722  * @nargs:  the number of arguments
   8723  *
   8724  * Implement the name() XPath function
   8725  *    string name(node-set?)
   8726  * The name function returns a string containing a QName representing
   8727  * the name of the node in the argument node-set that is first in document
   8728  * order. The QName must represent the name with respect to the namespace
   8729  * declarations in effect on the node whose name is being represented.
   8730  * Typically, this will be the form in which the name occurred in the XML
   8731  * source. This need not be the case if there are namespace declarations
   8732  * in effect on the node that associate multiple prefixes with the same
   8733  * namespace. However, an implementation may include information about
   8734  * the original prefix in its representation of nodes; in this case, an
   8735  * implementation can ensure that the returned string is always the same
   8736  * as the QName used in the XML source. If the argument it omitted it
   8737  * defaults to the context node.
   8738  * Libxml keep the original prefix so the "real qualified name" used is
   8739  * returned.
   8740  */
   8741 static void
   8742 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8743 {
   8744     xmlXPathObjectPtr cur;
   8745 
   8746     if (nargs == 0) {
   8747 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8748 	    ctxt->context->node));
   8749         nargs = 1;
   8750     }
   8751 
   8752     CHECK_ARITY(1);
   8753     if ((ctxt->value == NULL) ||
   8754         ((ctxt->value->type != XPATH_NODESET) &&
   8755          (ctxt->value->type != XPATH_XSLT_TREE)))
   8756         XP_ERROR(XPATH_INVALID_TYPE);
   8757     cur = valuePop(ctxt);
   8758 
   8759     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8760         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8761     } else {
   8762         int i = 0;              /* Should be first in document order !!!!! */
   8763 
   8764         switch (cur->nodesetval->nodeTab[i]->type) {
   8765             case XML_ELEMENT_NODE:
   8766             case XML_ATTRIBUTE_NODE:
   8767 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8768 		    valuePush(ctxt,
   8769 			xmlXPathCacheNewCString(ctxt->context, ""));
   8770 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8771                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8772 		    valuePush(ctxt,
   8773 		        xmlXPathCacheNewString(ctxt->context,
   8774 			    cur->nodesetval->nodeTab[i]->name));
   8775 		} else {
   8776 		    xmlChar *fullname;
   8777 
   8778 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8779 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8780 				     NULL, 0);
   8781 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8782 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8783 		    if (fullname == NULL) {
   8784 			XP_ERROR(XPATH_MEMORY_ERROR);
   8785 		    }
   8786 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8787 			ctxt->context, fullname));
   8788                 }
   8789                 break;
   8790             default:
   8791 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8792 		    cur->nodesetval->nodeTab[i]));
   8793                 xmlXPathLocalNameFunction(ctxt, 1);
   8794         }
   8795     }
   8796     xmlXPathReleaseObject(ctxt->context, cur);
   8797 }
   8798 
   8799 
   8800 /**
   8801  * xmlXPathStringFunction:
   8802  * @ctxt:  the XPath Parser context
   8803  * @nargs:  the number of arguments
   8804  *
   8805  * Implement the string() XPath function
   8806  *    string string(object?)
   8807  * The string function converts an object to a string as follows:
   8808  *    - A node-set is converted to a string by returning the value of
   8809  *      the node in the node-set that is first in document order.
   8810  *      If the node-set is empty, an empty string is returned.
   8811  *    - A number is converted to a string as follows
   8812  *      + NaN is converted to the string NaN
   8813  *      + positive zero is converted to the string 0
   8814  *      + negative zero is converted to the string 0
   8815  *      + positive infinity is converted to the string Infinity
   8816  *      + negative infinity is converted to the string -Infinity
   8817  *      + if the number is an integer, the number is represented in
   8818  *        decimal form as a Number with no decimal point and no leading
   8819  *        zeros, preceded by a minus sign (-) if the number is negative
   8820  *      + otherwise, the number is represented in decimal form as a
   8821  *        Number including a decimal point with at least one digit
   8822  *        before the decimal point and at least one digit after the
   8823  *        decimal point, preceded by a minus sign (-) if the number
   8824  *        is negative; there must be no leading zeros before the decimal
   8825  *        point apart possibly from the one required digit immediately
   8826  *        before the decimal point; beyond the one required digit
   8827  *        after the decimal point there must be as many, but only as
   8828  *        many, more digits as are needed to uniquely distinguish the
   8829  *        number from all other IEEE 754 numeric values.
   8830  *    - The boolean false value is converted to the string false.
   8831  *      The boolean true value is converted to the string true.
   8832  *
   8833  * If the argument is omitted, it defaults to a node-set with the
   8834  * context node as its only member.
   8835  */
   8836 void
   8837 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8838     xmlXPathObjectPtr cur;
   8839 
   8840     if (ctxt == NULL) return;
   8841     if (nargs == 0) {
   8842     valuePush(ctxt,
   8843 	xmlXPathCacheWrapString(ctxt->context,
   8844 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8845 	return;
   8846     }
   8847 
   8848     CHECK_ARITY(1);
   8849     cur = valuePop(ctxt);
   8850     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8851     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8852 }
   8853 
   8854 /**
   8855  * xmlXPathStringLengthFunction:
   8856  * @ctxt:  the XPath Parser context
   8857  * @nargs:  the number of arguments
   8858  *
   8859  * Implement the string-length() XPath function
   8860  *    number string-length(string?)
   8861  * The string-length returns the number of characters in the string
   8862  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8863  * the context node converted to a string, in other words the value
   8864  * of the context node.
   8865  */
   8866 void
   8867 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8868     xmlXPathObjectPtr cur;
   8869 
   8870     if (nargs == 0) {
   8871         if ((ctxt == NULL) || (ctxt->context == NULL))
   8872 	    return;
   8873 	if (ctxt->context->node == NULL) {
   8874 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8875 	} else {
   8876 	    xmlChar *content;
   8877 
   8878 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8879 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8880 		xmlUTF8Strlen(content)));
   8881 	    xmlFree(content);
   8882 	}
   8883 	return;
   8884     }
   8885     CHECK_ARITY(1);
   8886     CAST_TO_STRING;
   8887     CHECK_TYPE(XPATH_STRING);
   8888     cur = valuePop(ctxt);
   8889     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8890 	xmlUTF8Strlen(cur->stringval)));
   8891     xmlXPathReleaseObject(ctxt->context, cur);
   8892 }
   8893 
   8894 /**
   8895  * xmlXPathConcatFunction:
   8896  * @ctxt:  the XPath Parser context
   8897  * @nargs:  the number of arguments
   8898  *
   8899  * Implement the concat() XPath function
   8900  *    string concat(string, string, string*)
   8901  * The concat function returns the concatenation of its arguments.
   8902  */
   8903 void
   8904 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8905     xmlXPathObjectPtr cur, newobj;
   8906     xmlChar *tmp;
   8907 
   8908     if (ctxt == NULL) return;
   8909     if (nargs < 2) {
   8910 	CHECK_ARITY(2);
   8911     }
   8912 
   8913     CAST_TO_STRING;
   8914     cur = valuePop(ctxt);
   8915     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   8916 	xmlXPathReleaseObject(ctxt->context, cur);
   8917 	return;
   8918     }
   8919     nargs--;
   8920 
   8921     while (nargs > 0) {
   8922 	CAST_TO_STRING;
   8923 	newobj = valuePop(ctxt);
   8924 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   8925 	    xmlXPathReleaseObject(ctxt->context, newobj);
   8926 	    xmlXPathReleaseObject(ctxt->context, cur);
   8927 	    XP_ERROR(XPATH_INVALID_TYPE);
   8928 	}
   8929 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   8930 	newobj->stringval = cur->stringval;
   8931 	cur->stringval = tmp;
   8932 	xmlXPathReleaseObject(ctxt->context, newobj);
   8933 	nargs--;
   8934     }
   8935     valuePush(ctxt, cur);
   8936 }
   8937 
   8938 /**
   8939  * xmlXPathContainsFunction:
   8940  * @ctxt:  the XPath Parser context
   8941  * @nargs:  the number of arguments
   8942  *
   8943  * Implement the contains() XPath function
   8944  *    boolean contains(string, string)
   8945  * The contains function returns true if the first argument string
   8946  * contains the second argument string, and otherwise returns false.
   8947  */
   8948 void
   8949 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8950     xmlXPathObjectPtr hay, needle;
   8951 
   8952     CHECK_ARITY(2);
   8953     CAST_TO_STRING;
   8954     CHECK_TYPE(XPATH_STRING);
   8955     needle = valuePop(ctxt);
   8956     CAST_TO_STRING;
   8957     hay = valuePop(ctxt);
   8958 
   8959     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8960 	xmlXPathReleaseObject(ctxt->context, hay);
   8961 	xmlXPathReleaseObject(ctxt->context, needle);
   8962 	XP_ERROR(XPATH_INVALID_TYPE);
   8963     }
   8964     if (xmlStrstr(hay->stringval, needle->stringval))
   8965 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   8966     else
   8967 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   8968     xmlXPathReleaseObject(ctxt->context, hay);
   8969     xmlXPathReleaseObject(ctxt->context, needle);
   8970 }
   8971 
   8972 /**
   8973  * xmlXPathStartsWithFunction:
   8974  * @ctxt:  the XPath Parser context
   8975  * @nargs:  the number of arguments
   8976  *
   8977  * Implement the starts-with() XPath function
   8978  *    boolean starts-with(string, string)
   8979  * The starts-with function returns true if the first argument string
   8980  * starts with the second argument string, and otherwise returns false.
   8981  */
   8982 void
   8983 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8984     xmlXPathObjectPtr hay, needle;
   8985     int n;
   8986 
   8987     CHECK_ARITY(2);
   8988     CAST_TO_STRING;
   8989     CHECK_TYPE(XPATH_STRING);
   8990     needle = valuePop(ctxt);
   8991     CAST_TO_STRING;
   8992     hay = valuePop(ctxt);
   8993 
   8994     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8995 	xmlXPathReleaseObject(ctxt->context, hay);
   8996 	xmlXPathReleaseObject(ctxt->context, needle);
   8997 	XP_ERROR(XPATH_INVALID_TYPE);
   8998     }
   8999     n = xmlStrlen(needle->stringval);
   9000     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   9001         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9002     else
   9003         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9004     xmlXPathReleaseObject(ctxt->context, hay);
   9005     xmlXPathReleaseObject(ctxt->context, needle);
   9006 }
   9007 
   9008 /**
   9009  * xmlXPathSubstringFunction:
   9010  * @ctxt:  the XPath Parser context
   9011  * @nargs:  the number of arguments
   9012  *
   9013  * Implement the substring() XPath function
   9014  *    string substring(string, number, number?)
   9015  * The substring function returns the substring of the first argument
   9016  * starting at the position specified in the second argument with
   9017  * length specified in the third argument. For example,
   9018  * substring("12345",2,3) returns "234". If the third argument is not
   9019  * specified, it returns the substring starting at the position specified
   9020  * in the second argument and continuing to the end of the string. For
   9021  * example, substring("12345",2) returns "2345".  More precisely, each
   9022  * character in the string (see [3.6 Strings]) is considered to have a
   9023  * numeric position: the position of the first character is 1, the position
   9024  * of the second character is 2 and so on. The returned substring contains
   9025  * those characters for which the position of the character is greater than
   9026  * or equal to the second argument and, if the third argument is specified,
   9027  * less than the sum of the second and third arguments; the comparisons
   9028  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   9029  *  - substring("12345", 1.5, 2.6) returns "234"
   9030  *  - substring("12345", 0, 3) returns "12"
   9031  *  - substring("12345", 0 div 0, 3) returns ""
   9032  *  - substring("12345", 1, 0 div 0) returns ""
   9033  *  - substring("12345", -42, 1 div 0) returns "12345"
   9034  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   9035  */
   9036 void
   9037 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9038     xmlXPathObjectPtr str, start, len;
   9039     double le=0, in;
   9040     int i, l, m;
   9041     xmlChar *ret;
   9042 
   9043     if (nargs < 2) {
   9044 	CHECK_ARITY(2);
   9045     }
   9046     if (nargs > 3) {
   9047 	CHECK_ARITY(3);
   9048     }
   9049     /*
   9050      * take care of possible last (position) argument
   9051     */
   9052     if (nargs == 3) {
   9053 	CAST_TO_NUMBER;
   9054 	CHECK_TYPE(XPATH_NUMBER);
   9055 	len = valuePop(ctxt);
   9056 	le = len->floatval;
   9057 	xmlXPathReleaseObject(ctxt->context, len);
   9058     }
   9059 
   9060     CAST_TO_NUMBER;
   9061     CHECK_TYPE(XPATH_NUMBER);
   9062     start = valuePop(ctxt);
   9063     in = start->floatval;
   9064     xmlXPathReleaseObject(ctxt->context, start);
   9065     CAST_TO_STRING;
   9066     CHECK_TYPE(XPATH_STRING);
   9067     str = valuePop(ctxt);
   9068     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9069 
   9070     /*
   9071      * If last pos not present, calculate last position
   9072     */
   9073     if (nargs != 3) {
   9074 	le = (double)m;
   9075 	if (in < 1.0)
   9076 	    in = 1.0;
   9077     }
   9078 
   9079     /* Need to check for the special cases where either
   9080      * the index is NaN, the length is NaN, or both
   9081      * arguments are infinity (relying on Inf + -Inf = NaN)
   9082      */
   9083     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9084         /*
   9085          * To meet the requirements of the spec, the arguments
   9086 	 * must be converted to integer format before
   9087 	 * initial index calculations are done
   9088          *
   9089          * First we go to integer form, rounding up
   9090 	 * and checking for special cases
   9091          */
   9092         i = (int) in;
   9093         if (((double)i)+0.5 <= in) i++;
   9094 
   9095 	if (xmlXPathIsInf(le) == 1) {
   9096 	    l = m;
   9097 	    if (i < 1)
   9098 		i = 1;
   9099 	}
   9100 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9101 	    l = 0;
   9102 	else {
   9103 	    l = (int) le;
   9104 	    if (((double)l)+0.5 <= le) l++;
   9105 	}
   9106 
   9107 	/* Now we normalize inidices */
   9108         i -= 1;
   9109         l += i;
   9110         if (i < 0)
   9111             i = 0;
   9112         if (l > m)
   9113             l = m;
   9114 
   9115         /* number of chars to copy */
   9116         l -= i;
   9117 
   9118         ret = xmlUTF8Strsub(str->stringval, i, l);
   9119     }
   9120     else {
   9121         ret = NULL;
   9122     }
   9123     if (ret == NULL)
   9124 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9125     else {
   9126 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9127 	xmlFree(ret);
   9128     }
   9129     xmlXPathReleaseObject(ctxt->context, str);
   9130 }
   9131 
   9132 /**
   9133  * xmlXPathSubstringBeforeFunction:
   9134  * @ctxt:  the XPath Parser context
   9135  * @nargs:  the number of arguments
   9136  *
   9137  * Implement the substring-before() XPath function
   9138  *    string substring-before(string, string)
   9139  * The substring-before function returns the substring of the first
   9140  * argument string that precedes the first occurrence of the second
   9141  * argument string in the first argument string, or the empty string
   9142  * if the first argument string does not contain the second argument
   9143  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9144  */
   9145 void
   9146 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9147   xmlXPathObjectPtr str;
   9148   xmlXPathObjectPtr find;
   9149   xmlBufferPtr target;
   9150   const xmlChar *point;
   9151   int offset;
   9152 
   9153   CHECK_ARITY(2);
   9154   CAST_TO_STRING;
   9155   find = valuePop(ctxt);
   9156   CAST_TO_STRING;
   9157   str = valuePop(ctxt);
   9158 
   9159   target = xmlBufferCreate();
   9160   if (target) {
   9161     point = xmlStrstr(str->stringval, find->stringval);
   9162     if (point) {
   9163       offset = (int)(point - str->stringval);
   9164       xmlBufferAdd(target, str->stringval, offset);
   9165     }
   9166     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9167 	xmlBufferContent(target)));
   9168     xmlBufferFree(target);
   9169   }
   9170   xmlXPathReleaseObject(ctxt->context, str);
   9171   xmlXPathReleaseObject(ctxt->context, find);
   9172 }
   9173 
   9174 /**
   9175  * xmlXPathSubstringAfterFunction:
   9176  * @ctxt:  the XPath Parser context
   9177  * @nargs:  the number of arguments
   9178  *
   9179  * Implement the substring-after() XPath function
   9180  *    string substring-after(string, string)
   9181  * The substring-after function returns the substring of the first
   9182  * argument string that follows the first occurrence of the second
   9183  * argument string in the first argument string, or the empty stringi
   9184  * if the first argument string does not contain the second argument
   9185  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9186  * and substring-after("1999/04/01","19") returns 99/04/01.
   9187  */
   9188 void
   9189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9190   xmlXPathObjectPtr str;
   9191   xmlXPathObjectPtr find;
   9192   xmlBufferPtr target;
   9193   const xmlChar *point;
   9194   int offset;
   9195 
   9196   CHECK_ARITY(2);
   9197   CAST_TO_STRING;
   9198   find = valuePop(ctxt);
   9199   CAST_TO_STRING;
   9200   str = valuePop(ctxt);
   9201 
   9202   target = xmlBufferCreate();
   9203   if (target) {
   9204     point = xmlStrstr(str->stringval, find->stringval);
   9205     if (point) {
   9206       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9207       xmlBufferAdd(target, &str->stringval[offset],
   9208 		   xmlStrlen(str->stringval) - offset);
   9209     }
   9210     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9211 	xmlBufferContent(target)));
   9212     xmlBufferFree(target);
   9213   }
   9214   xmlXPathReleaseObject(ctxt->context, str);
   9215   xmlXPathReleaseObject(ctxt->context, find);
   9216 }
   9217 
   9218 /**
   9219  * xmlXPathNormalizeFunction:
   9220  * @ctxt:  the XPath Parser context
   9221  * @nargs:  the number of arguments
   9222  *
   9223  * Implement the normalize-space() XPath function
   9224  *    string normalize-space(string?)
   9225  * The normalize-space function returns the argument string with white
   9226  * space normalized by stripping leading and trailing whitespace
   9227  * and replacing sequences of whitespace characters by a single
   9228  * space. Whitespace characters are the same allowed by the S production
   9229  * in XML. If the argument is omitted, it defaults to the context
   9230  * node converted to a string, in other words the value of the context node.
   9231  */
   9232 void
   9233 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9234   xmlXPathObjectPtr obj = NULL;
   9235   xmlChar *source = NULL;
   9236   xmlBufferPtr target;
   9237   xmlChar blank;
   9238 
   9239   if (ctxt == NULL) return;
   9240   if (nargs == 0) {
   9241     /* Use current context node */
   9242       valuePush(ctxt,
   9243 	  xmlXPathCacheWrapString(ctxt->context,
   9244 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9245     nargs = 1;
   9246   }
   9247 
   9248   CHECK_ARITY(1);
   9249   CAST_TO_STRING;
   9250   CHECK_TYPE(XPATH_STRING);
   9251   obj = valuePop(ctxt);
   9252   source = obj->stringval;
   9253 
   9254   target = xmlBufferCreate();
   9255   if (target && source) {
   9256 
   9257     /* Skip leading whitespaces */
   9258     while (IS_BLANK_CH(*source))
   9259       source++;
   9260 
   9261     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9262     blank = 0;
   9263     while (*source) {
   9264       if (IS_BLANK_CH(*source)) {
   9265 	blank = 0x20;
   9266       } else {
   9267 	if (blank) {
   9268 	  xmlBufferAdd(target, &blank, 1);
   9269 	  blank = 0;
   9270 	}
   9271 	xmlBufferAdd(target, source, 1);
   9272       }
   9273       source++;
   9274     }
   9275     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9276 	xmlBufferContent(target)));
   9277     xmlBufferFree(target);
   9278   }
   9279   xmlXPathReleaseObject(ctxt->context, obj);
   9280 }
   9281 
   9282 /**
   9283  * xmlXPathTranslateFunction:
   9284  * @ctxt:  the XPath Parser context
   9285  * @nargs:  the number of arguments
   9286  *
   9287  * Implement the translate() XPath function
   9288  *    string translate(string, string, string)
   9289  * The translate function returns the first argument string with
   9290  * occurrences of characters in the second argument string replaced
   9291  * by the character at the corresponding position in the third argument
   9292  * string. For example, translate("bar","abc","ABC") returns the string
   9293  * BAr. If there is a character in the second argument string with no
   9294  * character at a corresponding position in the third argument string
   9295  * (because the second argument string is longer than the third argument
   9296  * string), then occurrences of that character in the first argument
   9297  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9298  * returns "AAA". If a character occurs more than once in second
   9299  * argument string, then the first occurrence determines the replacement
   9300  * character. If the third argument string is longer than the second
   9301  * argument string, then excess characters are ignored.
   9302  */
   9303 void
   9304 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9305     xmlXPathObjectPtr str;
   9306     xmlXPathObjectPtr from;
   9307     xmlXPathObjectPtr to;
   9308     xmlBufferPtr target;
   9309     int offset, max;
   9310     xmlChar ch;
   9311     const xmlChar *point;
   9312     xmlChar *cptr;
   9313 
   9314     CHECK_ARITY(3);
   9315 
   9316     CAST_TO_STRING;
   9317     to = valuePop(ctxt);
   9318     CAST_TO_STRING;
   9319     from = valuePop(ctxt);
   9320     CAST_TO_STRING;
   9321     str = valuePop(ctxt);
   9322 
   9323     target = xmlBufferCreate();
   9324     if (target) {
   9325 	max = xmlUTF8Strlen(to->stringval);
   9326 	for (cptr = str->stringval; (ch=*cptr); ) {
   9327 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9328 	    if (offset >= 0) {
   9329 		if (offset < max) {
   9330 		    point = xmlUTF8Strpos(to->stringval, offset);
   9331 		    if (point)
   9332 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
   9333 		}
   9334 	    } else
   9335 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9336 
   9337 	    /* Step to next character in input */
   9338 	    cptr++;
   9339 	    if ( ch & 0x80 ) {
   9340 		/* if not simple ascii, verify proper format */
   9341 		if ( (ch & 0xc0) != 0xc0 ) {
   9342 		    xmlGenericError(xmlGenericErrorContext,
   9343 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9344                     /* not asserting an XPath error is probably better */
   9345 		    break;
   9346 		}
   9347 		/* then skip over remaining bytes for this char */
   9348 		while ( (ch <<= 1) & 0x80 )
   9349 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9350 			xmlGenericError(xmlGenericErrorContext,
   9351 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9352                         /* not asserting an XPath error is probably better */
   9353 			break;
   9354 		    }
   9355 		if (ch & 0x80) /* must have had error encountered */
   9356 		    break;
   9357 	    }
   9358 	}
   9359     }
   9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9361 	xmlBufferContent(target)));
   9362     xmlBufferFree(target);
   9363     xmlXPathReleaseObject(ctxt->context, str);
   9364     xmlXPathReleaseObject(ctxt->context, from);
   9365     xmlXPathReleaseObject(ctxt->context, to);
   9366 }
   9367 
   9368 /**
   9369  * xmlXPathBooleanFunction:
   9370  * @ctxt:  the XPath Parser context
   9371  * @nargs:  the number of arguments
   9372  *
   9373  * Implement the boolean() XPath function
   9374  *    boolean boolean(object)
   9375  * The boolean function converts its argument to a boolean as follows:
   9376  *    - a number is true if and only if it is neither positive or
   9377  *      negative zero nor NaN
   9378  *    - a node-set is true if and only if it is non-empty
   9379  *    - a string is true if and only if its length is non-zero
   9380  */
   9381 void
   9382 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9383     xmlXPathObjectPtr cur;
   9384 
   9385     CHECK_ARITY(1);
   9386     cur = valuePop(ctxt);
   9387     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9388     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9389     valuePush(ctxt, cur);
   9390 }
   9391 
   9392 /**
   9393  * xmlXPathNotFunction:
   9394  * @ctxt:  the XPath Parser context
   9395  * @nargs:  the number of arguments
   9396  *
   9397  * Implement the not() XPath function
   9398  *    boolean not(boolean)
   9399  * The not function returns true if its argument is false,
   9400  * and false otherwise.
   9401  */
   9402 void
   9403 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9404     CHECK_ARITY(1);
   9405     CAST_TO_BOOLEAN;
   9406     CHECK_TYPE(XPATH_BOOLEAN);
   9407     ctxt->value->boolval = ! ctxt->value->boolval;
   9408 }
   9409 
   9410 /**
   9411  * xmlXPathTrueFunction:
   9412  * @ctxt:  the XPath Parser context
   9413  * @nargs:  the number of arguments
   9414  *
   9415  * Implement the true() XPath function
   9416  *    boolean true()
   9417  */
   9418 void
   9419 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9420     CHECK_ARITY(0);
   9421     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9422 }
   9423 
   9424 /**
   9425  * xmlXPathFalseFunction:
   9426  * @ctxt:  the XPath Parser context
   9427  * @nargs:  the number of arguments
   9428  *
   9429  * Implement the false() XPath function
   9430  *    boolean false()
   9431  */
   9432 void
   9433 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9434     CHECK_ARITY(0);
   9435     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9436 }
   9437 
   9438 /**
   9439  * xmlXPathLangFunction:
   9440  * @ctxt:  the XPath Parser context
   9441  * @nargs:  the number of arguments
   9442  *
   9443  * Implement the lang() XPath function
   9444  *    boolean lang(string)
   9445  * The lang function returns true or false depending on whether the
   9446  * language of the context node as specified by xml:lang attributes
   9447  * is the same as or is a sublanguage of the language specified by
   9448  * the argument string. The language of the context node is determined
   9449  * by the value of the xml:lang attribute on the context node, or, if
   9450  * the context node has no xml:lang attribute, by the value of the
   9451  * xml:lang attribute on the nearest ancestor of the context node that
   9452  * has an xml:lang attribute. If there is no such attribute, then lang
   9453  * returns false. If there is such an attribute, then lang returns
   9454  * true if the attribute value is equal to the argument ignoring case,
   9455  * or if there is some suffix starting with - such that the attribute
   9456  * value is equal to the argument ignoring that suffix of the attribute
   9457  * value and ignoring case.
   9458  */
   9459 void
   9460 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9461     xmlXPathObjectPtr val = NULL;
   9462     const xmlChar *theLang = NULL;
   9463     const xmlChar *lang;
   9464     int ret = 0;
   9465     int i;
   9466 
   9467     CHECK_ARITY(1);
   9468     CAST_TO_STRING;
   9469     CHECK_TYPE(XPATH_STRING);
   9470     val = valuePop(ctxt);
   9471     lang = val->stringval;
   9472     theLang = xmlNodeGetLang(ctxt->context->node);
   9473     if ((theLang != NULL) && (lang != NULL)) {
   9474         for (i = 0;lang[i] != 0;i++)
   9475 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9476 	        goto not_equal;
   9477 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9478 	    ret = 1;
   9479     }
   9480 not_equal:
   9481     if (theLang != NULL)
   9482 	xmlFree((void *)theLang);
   9483 
   9484     xmlXPathReleaseObject(ctxt->context, val);
   9485     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9486 }
   9487 
   9488 /**
   9489  * xmlXPathNumberFunction:
   9490  * @ctxt:  the XPath Parser context
   9491  * @nargs:  the number of arguments
   9492  *
   9493  * Implement the number() XPath function
   9494  *    number number(object?)
   9495  */
   9496 void
   9497 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9498     xmlXPathObjectPtr cur;
   9499     double res;
   9500 
   9501     if (ctxt == NULL) return;
   9502     if (nargs == 0) {
   9503 	if (ctxt->context->node == NULL) {
   9504 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9505 	} else {
   9506 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9507 
   9508 	    res = xmlXPathStringEvalNumber(content);
   9509 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9510 	    xmlFree(content);
   9511 	}
   9512 	return;
   9513     }
   9514 
   9515     CHECK_ARITY(1);
   9516     cur = valuePop(ctxt);
   9517     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9518 }
   9519 
   9520 /**
   9521  * xmlXPathSumFunction:
   9522  * @ctxt:  the XPath Parser context
   9523  * @nargs:  the number of arguments
   9524  *
   9525  * Implement the sum() XPath function
   9526  *    number sum(node-set)
   9527  * The sum function returns the sum of the values of the nodes in
   9528  * the argument node-set.
   9529  */
   9530 void
   9531 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9532     xmlXPathObjectPtr cur;
   9533     int i;
   9534     double res = 0.0;
   9535 
   9536     CHECK_ARITY(1);
   9537     if ((ctxt->value == NULL) ||
   9538 	((ctxt->value->type != XPATH_NODESET) &&
   9539 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9540 	XP_ERROR(XPATH_INVALID_TYPE);
   9541     cur = valuePop(ctxt);
   9542 
   9543     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9544 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9545 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9546 	}
   9547     }
   9548     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9549     xmlXPathReleaseObject(ctxt->context, cur);
   9550 }
   9551 
   9552 /*
   9553  * To assure working code on multiple platforms, we want to only depend
   9554  * upon the characteristic truncation of converting a floating point value
   9555  * to an integer.  Unfortunately, because of the different storage sizes
   9556  * of our internal floating point value (double) and integer (int), we
   9557  * can't directly convert (see bug 301162).  This macro is a messy
   9558  * 'workaround'
   9559  */
   9560 #define XTRUNC(f, v)            \
   9561     f = fmod((v), INT_MAX);     \
   9562     f = (v) - (f) + (double)((int)(f));
   9563 
   9564 /**
   9565  * xmlXPathFloorFunction:
   9566  * @ctxt:  the XPath Parser context
   9567  * @nargs:  the number of arguments
   9568  *
   9569  * Implement the floor() XPath function
   9570  *    number floor(number)
   9571  * The floor function returns the largest (closest to positive infinity)
   9572  * number that is not greater than the argument and that is an integer.
   9573  */
   9574 void
   9575 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9576     double f;
   9577 
   9578     CHECK_ARITY(1);
   9579     CAST_TO_NUMBER;
   9580     CHECK_TYPE(XPATH_NUMBER);
   9581 
   9582     XTRUNC(f, ctxt->value->floatval);
   9583     if (f != ctxt->value->floatval) {
   9584 	if (ctxt->value->floatval > 0)
   9585 	    ctxt->value->floatval = f;
   9586 	else
   9587 	    ctxt->value->floatval = f - 1;
   9588     }
   9589 }
   9590 
   9591 /**
   9592  * xmlXPathCeilingFunction:
   9593  * @ctxt:  the XPath Parser context
   9594  * @nargs:  the number of arguments
   9595  *
   9596  * Implement the ceiling() XPath function
   9597  *    number ceiling(number)
   9598  * The ceiling function returns the smallest (closest to negative infinity)
   9599  * number that is not less than the argument and that is an integer.
   9600  */
   9601 void
   9602 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9603     double f;
   9604 
   9605     CHECK_ARITY(1);
   9606     CAST_TO_NUMBER;
   9607     CHECK_TYPE(XPATH_NUMBER);
   9608 
   9609 #if 0
   9610     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9611 #else
   9612     XTRUNC(f, ctxt->value->floatval);
   9613     if (f != ctxt->value->floatval) {
   9614 	if (ctxt->value->floatval > 0)
   9615 	    ctxt->value->floatval = f + 1;
   9616 	else {
   9617 	    if (ctxt->value->floatval < 0 && f == 0)
   9618 	        ctxt->value->floatval = xmlXPathNZERO;
   9619 	    else
   9620 	        ctxt->value->floatval = f;
   9621 	}
   9622 
   9623     }
   9624 #endif
   9625 }
   9626 
   9627 /**
   9628  * xmlXPathRoundFunction:
   9629  * @ctxt:  the XPath Parser context
   9630  * @nargs:  the number of arguments
   9631  *
   9632  * Implement the round() XPath function
   9633  *    number round(number)
   9634  * The round function returns the number that is closest to the
   9635  * argument and that is an integer. If there are two such numbers,
   9636  * then the one that is even is returned.
   9637  */
   9638 void
   9639 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9640     double f;
   9641 
   9642     CHECK_ARITY(1);
   9643     CAST_TO_NUMBER;
   9644     CHECK_TYPE(XPATH_NUMBER);
   9645 
   9646     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
   9647 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
   9648 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
   9649 	(ctxt->value->floatval == 0.0))
   9650 	return;
   9651 
   9652     XTRUNC(f, ctxt->value->floatval);
   9653     if (ctxt->value->floatval < 0) {
   9654 	if (ctxt->value->floatval < f - 0.5)
   9655 	    ctxt->value->floatval = f - 1;
   9656 	else
   9657 	    ctxt->value->floatval = f;
   9658 	if (ctxt->value->floatval == 0)
   9659 	    ctxt->value->floatval = xmlXPathNZERO;
   9660     } else {
   9661 	if (ctxt->value->floatval < f + 0.5)
   9662 	    ctxt->value->floatval = f;
   9663 	else
   9664 	    ctxt->value->floatval = f + 1;
   9665     }
   9666 }
   9667 
   9668 /************************************************************************
   9669  *									*
   9670  *			The Parser					*
   9671  *									*
   9672  ************************************************************************/
   9673 
   9674 /*
   9675  * a few forward declarations since we use a recursive call based
   9676  * implementation.
   9677  */
   9678 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9679 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9680 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9681 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9682 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9683 	                                  int qualified);
   9684 
   9685 /**
   9686  * xmlXPathCurrentChar:
   9687  * @ctxt:  the XPath parser context
   9688  * @cur:  pointer to the beginning of the char
   9689  * @len:  pointer to the length of the char read
   9690  *
   9691  * The current char value, if using UTF-8 this may actually span multiple
   9692  * bytes in the input buffer.
   9693  *
   9694  * Returns the current char value and its length
   9695  */
   9696 
   9697 static int
   9698 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9699     unsigned char c;
   9700     unsigned int val;
   9701     const xmlChar *cur;
   9702 
   9703     if (ctxt == NULL)
   9704 	return(0);
   9705     cur = ctxt->cur;
   9706 
   9707     /*
   9708      * We are supposed to handle UTF8, check it's valid
   9709      * From rfc2044: encoding of the Unicode values on UTF-8:
   9710      *
   9711      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9712      * 0000 0000-0000 007F   0xxxxxxx
   9713      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9714      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9715      *
   9716      * Check for the 0x110000 limit too
   9717      */
   9718     c = *cur;
   9719     if (c & 0x80) {
   9720 	if ((cur[1] & 0xc0) != 0x80)
   9721 	    goto encoding_error;
   9722 	if ((c & 0xe0) == 0xe0) {
   9723 
   9724 	    if ((cur[2] & 0xc0) != 0x80)
   9725 		goto encoding_error;
   9726 	    if ((c & 0xf0) == 0xf0) {
   9727 		if (((c & 0xf8) != 0xf0) ||
   9728 		    ((cur[3] & 0xc0) != 0x80))
   9729 		    goto encoding_error;
   9730 		/* 4-byte code */
   9731 		*len = 4;
   9732 		val = (cur[0] & 0x7) << 18;
   9733 		val |= (cur[1] & 0x3f) << 12;
   9734 		val |= (cur[2] & 0x3f) << 6;
   9735 		val |= cur[3] & 0x3f;
   9736 	    } else {
   9737 	      /* 3-byte code */
   9738 		*len = 3;
   9739 		val = (cur[0] & 0xf) << 12;
   9740 		val |= (cur[1] & 0x3f) << 6;
   9741 		val |= cur[2] & 0x3f;
   9742 	    }
   9743 	} else {
   9744 	  /* 2-byte code */
   9745 	    *len = 2;
   9746 	    val = (cur[0] & 0x1f) << 6;
   9747 	    val |= cur[1] & 0x3f;
   9748 	}
   9749 	if (!IS_CHAR(val)) {
   9750 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9751 	}
   9752 	return(val);
   9753     } else {
   9754 	/* 1-byte code */
   9755 	*len = 1;
   9756 	return((int) *cur);
   9757     }
   9758 encoding_error:
   9759     /*
   9760      * If we detect an UTF8 error that probably means that the
   9761      * input encoding didn't get properly advertised in the
   9762      * declaration header. Report the error and switch the encoding
   9763      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9764      * encoding !)
   9765      */
   9766     *len = 0;
   9767     XP_ERROR0(XPATH_ENCODING_ERROR);
   9768 }
   9769 
   9770 /**
   9771  * xmlXPathParseNCName:
   9772  * @ctxt:  the XPath Parser context
   9773  *
   9774  * parse an XML namespace non qualified name.
   9775  *
   9776  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9777  *
   9778  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9779  *                       CombiningChar | Extender
   9780  *
   9781  * Returns the namespace name or NULL
   9782  */
   9783 
   9784 xmlChar *
   9785 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9786     const xmlChar *in;
   9787     xmlChar *ret;
   9788     int count = 0;
   9789 
   9790     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9791     /*
   9792      * Accelerator for simple ASCII names
   9793      */
   9794     in = ctxt->cur;
   9795     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9796 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9797 	(*in == '_')) {
   9798 	in++;
   9799 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9800 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9801 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9802 	       (*in == '_') || (*in == '.') ||
   9803 	       (*in == '-'))
   9804 	    in++;
   9805 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9806             (*in == '[') || (*in == ']') || (*in == ':') ||
   9807             (*in == '@') || (*in == '*')) {
   9808 	    count = in - ctxt->cur;
   9809 	    if (count == 0)
   9810 		return(NULL);
   9811 	    ret = xmlStrndup(ctxt->cur, count);
   9812 	    ctxt->cur = in;
   9813 	    return(ret);
   9814 	}
   9815     }
   9816     return(xmlXPathParseNameComplex(ctxt, 0));
   9817 }
   9818 
   9819 
   9820 /**
   9821  * xmlXPathParseQName:
   9822  * @ctxt:  the XPath Parser context
   9823  * @prefix:  a xmlChar **
   9824  *
   9825  * parse an XML qualified name
   9826  *
   9827  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9828  *
   9829  * [NS 6] Prefix ::= NCName
   9830  *
   9831  * [NS 7] LocalPart ::= NCName
   9832  *
   9833  * Returns the function returns the local part, and prefix is updated
   9834  *   to get the Prefix if any.
   9835  */
   9836 
   9837 static xmlChar *
   9838 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9839     xmlChar *ret = NULL;
   9840 
   9841     *prefix = NULL;
   9842     ret = xmlXPathParseNCName(ctxt);
   9843     if (ret && CUR == ':') {
   9844         *prefix = ret;
   9845 	NEXT;
   9846 	ret = xmlXPathParseNCName(ctxt);
   9847     }
   9848     return(ret);
   9849 }
   9850 
   9851 /**
   9852  * xmlXPathParseName:
   9853  * @ctxt:  the XPath Parser context
   9854  *
   9855  * parse an XML name
   9856  *
   9857  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9858  *                  CombiningChar | Extender
   9859  *
   9860  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9861  *
   9862  * Returns the namespace name or NULL
   9863  */
   9864 
   9865 xmlChar *
   9866 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9867     const xmlChar *in;
   9868     xmlChar *ret;
   9869     int count = 0;
   9870 
   9871     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9872     /*
   9873      * Accelerator for simple ASCII names
   9874      */
   9875     in = ctxt->cur;
   9876     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9877 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9878 	(*in == '_') || (*in == ':')) {
   9879 	in++;
   9880 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9881 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9882 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9883 	       (*in == '_') || (*in == '-') ||
   9884 	       (*in == ':') || (*in == '.'))
   9885 	    in++;
   9886 	if ((*in > 0) && (*in < 0x80)) {
   9887 	    count = in - ctxt->cur;
   9888 	    ret = xmlStrndup(ctxt->cur, count);
   9889 	    ctxt->cur = in;
   9890 	    return(ret);
   9891 	}
   9892     }
   9893     return(xmlXPathParseNameComplex(ctxt, 1));
   9894 }
   9895 
   9896 static xmlChar *
   9897 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9898     xmlChar buf[XML_MAX_NAMELEN + 5];
   9899     int len = 0, l;
   9900     int c;
   9901 
   9902     /*
   9903      * Handler for more complex cases
   9904      */
   9905     c = CUR_CHAR(l);
   9906     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9907         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9908         (c == '*') || /* accelerators */
   9909 	(!IS_LETTER(c) && (c != '_') &&
   9910          ((qualified) && (c != ':')))) {
   9911 	return(NULL);
   9912     }
   9913 
   9914     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9915 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   9916             (c == '.') || (c == '-') ||
   9917 	    (c == '_') || ((qualified) && (c == ':')) ||
   9918 	    (IS_COMBINING(c)) ||
   9919 	    (IS_EXTENDER(c)))) {
   9920 	COPY_BUF(l,buf,len,c);
   9921 	NEXTL(l);
   9922 	c = CUR_CHAR(l);
   9923 	if (len >= XML_MAX_NAMELEN) {
   9924 	    /*
   9925 	     * Okay someone managed to make a huge name, so he's ready to pay
   9926 	     * for the processing speed.
   9927 	     */
   9928 	    xmlChar *buffer;
   9929 	    int max = len * 2;
   9930 
   9931 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   9932 	    if (buffer == NULL) {
   9933 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9934 	    }
   9935 	    memcpy(buffer, buf, len);
   9936 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   9937 		   (c == '.') || (c == '-') ||
   9938 		   (c == '_') || ((qualified) && (c == ':')) ||
   9939 		   (IS_COMBINING(c)) ||
   9940 		   (IS_EXTENDER(c))) {
   9941 		if (len + 10 > max) {
   9942 		    max *= 2;
   9943 		    buffer = (xmlChar *) xmlRealloc(buffer,
   9944 			                            max * sizeof(xmlChar));
   9945 		    if (buffer == NULL) {
   9946 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9947 		    }
   9948 		}
   9949 		COPY_BUF(l,buffer,len,c);
   9950 		NEXTL(l);
   9951 		c = CUR_CHAR(l);
   9952 	    }
   9953 	    buffer[len] = 0;
   9954 	    return(buffer);
   9955 	}
   9956     }
   9957     if (len == 0)
   9958 	return(NULL);
   9959     return(xmlStrndup(buf, len));
   9960 }
   9961 
   9962 #define MAX_FRAC 20
   9963 
   9964 /*
   9965  * These are used as divisors for the fractional part of a number.
   9966  * Since the table includes 1.0 (representing '0' fractional digits),
   9967  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
   9968  */
   9969 static double my_pow10[MAX_FRAC+1] = {
   9970     1.0, 10.0, 100.0, 1000.0, 10000.0,
   9971     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
   9972     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
   9973     100000000000000.0,
   9974     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
   9975     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
   9976 };
   9977 
   9978 /**
   9979  * xmlXPathStringEvalNumber:
   9980  * @str:  A string to scan
   9981  *
   9982  *  [30a]  Float  ::= Number ('e' Digits?)?
   9983  *
   9984  *  [30]   Number ::=   Digits ('.' Digits?)?
   9985  *                    | '.' Digits
   9986  *  [31]   Digits ::=   [0-9]+
   9987  *
   9988  * Compile a Number in the string
   9989  * In complement of the Number expression, this function also handles
   9990  * negative values : '-' Number.
   9991  *
   9992  * Returns the double value.
   9993  */
   9994 double
   9995 xmlXPathStringEvalNumber(const xmlChar *str) {
   9996     const xmlChar *cur = str;
   9997     double ret;
   9998     int ok = 0;
   9999     int isneg = 0;
   10000     int exponent = 0;
   10001     int is_exponent_negative = 0;
   10002 #ifdef __GNUC__
   10003     unsigned long tmp = 0;
   10004     double temp;
   10005 #endif
   10006     if (cur == NULL) return(0);
   10007     while (IS_BLANK_CH(*cur)) cur++;
   10008     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   10009         return(xmlXPathNAN);
   10010     }
   10011     if (*cur == '-') {
   10012 	isneg = 1;
   10013 	cur++;
   10014     }
   10015 
   10016 #ifdef __GNUC__
   10017     /*
   10018      * tmp/temp is a workaround against a gcc compiler bug
   10019      * http://veillard.com/gcc.bug
   10020      */
   10021     ret = 0;
   10022     while ((*cur >= '0') && (*cur <= '9')) {
   10023 	ret = ret * 10;
   10024 	tmp = (*cur - '0');
   10025 	ok = 1;
   10026 	cur++;
   10027 	temp = (double) tmp;
   10028 	ret = ret + temp;
   10029     }
   10030 #else
   10031     ret = 0;
   10032     while ((*cur >= '0') && (*cur <= '9')) {
   10033 	ret = ret * 10 + (*cur - '0');
   10034 	ok = 1;
   10035 	cur++;
   10036     }
   10037 #endif
   10038 
   10039     if (*cur == '.') {
   10040 	int v, frac = 0;
   10041 	double fraction = 0;
   10042 
   10043         cur++;
   10044 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   10045 	    return(xmlXPathNAN);
   10046 	}
   10047 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
   10048 	    v = (*cur - '0');
   10049 	    fraction = fraction * 10 + v;
   10050 	    frac = frac + 1;
   10051 	    cur++;
   10052 	}
   10053 	fraction /= my_pow10[frac];
   10054 	ret = ret + fraction;
   10055 	while ((*cur >= '0') && (*cur <= '9'))
   10056 	    cur++;
   10057     }
   10058     if ((*cur == 'e') || (*cur == 'E')) {
   10059       cur++;
   10060       if (*cur == '-') {
   10061 	is_exponent_negative = 1;
   10062 	cur++;
   10063       } else if (*cur == '+') {
   10064         cur++;
   10065       }
   10066       while ((*cur >= '0') && (*cur <= '9')) {
   10067 	exponent = exponent * 10 + (*cur - '0');
   10068 	cur++;
   10069       }
   10070     }
   10071     while (IS_BLANK_CH(*cur)) cur++;
   10072     if (*cur != 0) return(xmlXPathNAN);
   10073     if (isneg) ret = -ret;
   10074     if (is_exponent_negative) exponent = -exponent;
   10075     ret *= pow(10.0, (double)exponent);
   10076     return(ret);
   10077 }
   10078 
   10079 /**
   10080  * xmlXPathCompNumber:
   10081  * @ctxt:  the XPath Parser context
   10082  *
   10083  *  [30]   Number ::=   Digits ('.' Digits?)?
   10084  *                    | '.' Digits
   10085  *  [31]   Digits ::=   [0-9]+
   10086  *
   10087  * Compile a Number, then push it on the stack
   10088  *
   10089  */
   10090 static void
   10091 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10092 {
   10093     double ret = 0.0;
   10094     int ok = 0;
   10095     int exponent = 0;
   10096     int is_exponent_negative = 0;
   10097 #ifdef __GNUC__
   10098     unsigned long tmp = 0;
   10099     double temp;
   10100 #endif
   10101 
   10102     CHECK_ERROR;
   10103     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10104         XP_ERROR(XPATH_NUMBER_ERROR);
   10105     }
   10106 #ifdef __GNUC__
   10107     /*
   10108      * tmp/temp is a workaround against a gcc compiler bug
   10109      * http://veillard.com/gcc.bug
   10110      */
   10111     ret = 0;
   10112     while ((CUR >= '0') && (CUR <= '9')) {
   10113 	ret = ret * 10;
   10114 	tmp = (CUR - '0');
   10115         ok = 1;
   10116         NEXT;
   10117 	temp = (double) tmp;
   10118 	ret = ret + temp;
   10119     }
   10120 #else
   10121     ret = 0;
   10122     while ((CUR >= '0') && (CUR <= '9')) {
   10123 	ret = ret * 10 + (CUR - '0');
   10124 	ok = 1;
   10125 	NEXT;
   10126     }
   10127 #endif
   10128     if (CUR == '.') {
   10129 	int v, frac = 0;
   10130 	double fraction = 0;
   10131 
   10132         NEXT;
   10133         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10134             XP_ERROR(XPATH_NUMBER_ERROR);
   10135         }
   10136         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
   10137 	    v = (CUR - '0');
   10138 	    fraction = fraction * 10 + v;
   10139 	    frac = frac + 1;
   10140             NEXT;
   10141         }
   10142         fraction /= my_pow10[frac];
   10143         ret = ret + fraction;
   10144         while ((CUR >= '0') && (CUR <= '9'))
   10145             NEXT;
   10146     }
   10147     if ((CUR == 'e') || (CUR == 'E')) {
   10148         NEXT;
   10149         if (CUR == '-') {
   10150             is_exponent_negative = 1;
   10151             NEXT;
   10152         } else if (CUR == '+') {
   10153 	    NEXT;
   10154 	}
   10155         while ((CUR >= '0') && (CUR <= '9')) {
   10156             exponent = exponent * 10 + (CUR - '0');
   10157             NEXT;
   10158         }
   10159         if (is_exponent_negative)
   10160             exponent = -exponent;
   10161         ret *= pow(10.0, (double) exponent);
   10162     }
   10163     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10164                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10165 }
   10166 
   10167 /**
   10168  * xmlXPathParseLiteral:
   10169  * @ctxt:  the XPath Parser context
   10170  *
   10171  * Parse a Literal
   10172  *
   10173  *  [29]   Literal ::=   '"' [^"]* '"'
   10174  *                    | "'" [^']* "'"
   10175  *
   10176  * Returns the value found or NULL in case of error
   10177  */
   10178 static xmlChar *
   10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10180     const xmlChar *q;
   10181     xmlChar *ret = NULL;
   10182 
   10183     if (CUR == '"') {
   10184         NEXT;
   10185 	q = CUR_PTR;
   10186 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10187 	    NEXT;
   10188 	if (!IS_CHAR_CH(CUR)) {
   10189 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10190 	} else {
   10191 	    ret = xmlStrndup(q, CUR_PTR - q);
   10192 	    NEXT;
   10193         }
   10194     } else if (CUR == '\'') {
   10195         NEXT;
   10196 	q = CUR_PTR;
   10197 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10198 	    NEXT;
   10199 	if (!IS_CHAR_CH(CUR)) {
   10200 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10201 	} else {
   10202 	    ret = xmlStrndup(q, CUR_PTR - q);
   10203 	    NEXT;
   10204         }
   10205     } else {
   10206 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10207     }
   10208     return(ret);
   10209 }
   10210 
   10211 /**
   10212  * xmlXPathCompLiteral:
   10213  * @ctxt:  the XPath Parser context
   10214  *
   10215  * Parse a Literal and push it on the stack.
   10216  *
   10217  *  [29]   Literal ::=   '"' [^"]* '"'
   10218  *                    | "'" [^']* "'"
   10219  *
   10220  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10221  */
   10222 static void
   10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10224     const xmlChar *q;
   10225     xmlChar *ret = NULL;
   10226 
   10227     if (CUR == '"') {
   10228         NEXT;
   10229 	q = CUR_PTR;
   10230 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10231 	    NEXT;
   10232 	if (!IS_CHAR_CH(CUR)) {
   10233 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10234 	} else {
   10235 	    ret = xmlStrndup(q, CUR_PTR - q);
   10236 	    NEXT;
   10237         }
   10238     } else if (CUR == '\'') {
   10239         NEXT;
   10240 	q = CUR_PTR;
   10241 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10242 	    NEXT;
   10243 	if (!IS_CHAR_CH(CUR)) {
   10244 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10245 	} else {
   10246 	    ret = xmlStrndup(q, CUR_PTR - q);
   10247 	    NEXT;
   10248         }
   10249     } else {
   10250 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10251     }
   10252     if (ret == NULL) return;
   10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10254 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10255     xmlFree(ret);
   10256 }
   10257 
   10258 /**
   10259  * xmlXPathCompVariableReference:
   10260  * @ctxt:  the XPath Parser context
   10261  *
   10262  * Parse a VariableReference, evaluate it and push it on the stack.
   10263  *
   10264  * The variable bindings consist of a mapping from variable names
   10265  * to variable values. The value of a variable is an object, which can be
   10266  * of any of the types that are possible for the value of an expression,
   10267  * and may also be of additional types not specified here.
   10268  *
   10269  * Early evaluation is possible since:
   10270  * The variable bindings [...] used to evaluate a subexpression are
   10271  * always the same as those used to evaluate the containing expression.
   10272  *
   10273  *  [36]   VariableReference ::=   '$' QName
   10274  */
   10275 static void
   10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10277     xmlChar *name;
   10278     xmlChar *prefix;
   10279 
   10280     SKIP_BLANKS;
   10281     if (CUR != '$') {
   10282 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10283     }
   10284     NEXT;
   10285     name = xmlXPathParseQName(ctxt, &prefix);
   10286     if (name == NULL) {
   10287 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10288     }
   10289     ctxt->comp->last = -1;
   10290     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10291 	           name, prefix);
   10292     SKIP_BLANKS;
   10293     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10294 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
   10295     }
   10296 }
   10297 
   10298 /**
   10299  * xmlXPathIsNodeType:
   10300  * @name:  a name string
   10301  *
   10302  * Is the name given a NodeType one.
   10303  *
   10304  *  [38]   NodeType ::=   'comment'
   10305  *                    | 'text'
   10306  *                    | 'processing-instruction'
   10307  *                    | 'node'
   10308  *
   10309  * Returns 1 if true 0 otherwise
   10310  */
   10311 int
   10312 xmlXPathIsNodeType(const xmlChar *name) {
   10313     if (name == NULL)
   10314 	return(0);
   10315 
   10316     if (xmlStrEqual(name, BAD_CAST "node"))
   10317 	return(1);
   10318     if (xmlStrEqual(name, BAD_CAST "text"))
   10319 	return(1);
   10320     if (xmlStrEqual(name, BAD_CAST "comment"))
   10321 	return(1);
   10322     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10323 	return(1);
   10324     return(0);
   10325 }
   10326 
   10327 /**
   10328  * xmlXPathCompFunctionCall:
   10329  * @ctxt:  the XPath Parser context
   10330  *
   10331  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10332  *  [17]   Argument ::=   Expr
   10333  *
   10334  * Compile a function call, the evaluation of all arguments are
   10335  * pushed on the stack
   10336  */
   10337 static void
   10338 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10339     xmlChar *name;
   10340     xmlChar *prefix;
   10341     int nbargs = 0;
   10342     int sort = 1;
   10343 
   10344     name = xmlXPathParseQName(ctxt, &prefix);
   10345     if (name == NULL) {
   10346 	xmlFree(prefix);
   10347 	XP_ERROR(XPATH_EXPR_ERROR);
   10348     }
   10349     SKIP_BLANKS;
   10350 #ifdef DEBUG_EXPR
   10351     if (prefix == NULL)
   10352 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10353 			name);
   10354     else
   10355 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10356 			prefix, name);
   10357 #endif
   10358 
   10359     if (CUR != '(') {
   10360 	XP_ERROR(XPATH_EXPR_ERROR);
   10361     }
   10362     NEXT;
   10363     SKIP_BLANKS;
   10364 
   10365     /*
   10366     * Optimization for count(): we don't need the node-set to be sorted.
   10367     */
   10368     if ((prefix == NULL) && (name[0] == 'c') &&
   10369 	xmlStrEqual(name, BAD_CAST "count"))
   10370     {
   10371 	sort = 0;
   10372     }
   10373     ctxt->comp->last = -1;
   10374     if (CUR != ')') {
   10375 	while (CUR != 0) {
   10376 	    int op1 = ctxt->comp->last;
   10377 	    ctxt->comp->last = -1;
   10378 	    xmlXPathCompileExpr(ctxt, sort);
   10379 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10380 		xmlFree(name);
   10381 		xmlFree(prefix);
   10382 		return;
   10383 	    }
   10384 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10385 	    nbargs++;
   10386 	    if (CUR == ')') break;
   10387 	    if (CUR != ',') {
   10388 		XP_ERROR(XPATH_EXPR_ERROR);
   10389 	    }
   10390 	    NEXT;
   10391 	    SKIP_BLANKS;
   10392 	}
   10393     }
   10394     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10395 	           name, prefix);
   10396     NEXT;
   10397     SKIP_BLANKS;
   10398 }
   10399 
   10400 /**
   10401  * xmlXPathCompPrimaryExpr:
   10402  * @ctxt:  the XPath Parser context
   10403  *
   10404  *  [15]   PrimaryExpr ::=   VariableReference
   10405  *                | '(' Expr ')'
   10406  *                | Literal
   10407  *                | Number
   10408  *                | FunctionCall
   10409  *
   10410  * Compile a primary expression.
   10411  */
   10412 static void
   10413 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10414     SKIP_BLANKS;
   10415     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10416     else if (CUR == '(') {
   10417 	NEXT;
   10418 	SKIP_BLANKS;
   10419 	xmlXPathCompileExpr(ctxt, 1);
   10420 	CHECK_ERROR;
   10421 	if (CUR != ')') {
   10422 	    XP_ERROR(XPATH_EXPR_ERROR);
   10423 	}
   10424 	NEXT;
   10425 	SKIP_BLANKS;
   10426     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10427 	xmlXPathCompNumber(ctxt);
   10428     } else if ((CUR == '\'') || (CUR == '"')) {
   10429 	xmlXPathCompLiteral(ctxt);
   10430     } else {
   10431 	xmlXPathCompFunctionCall(ctxt);
   10432     }
   10433     SKIP_BLANKS;
   10434 }
   10435 
   10436 /**
   10437  * xmlXPathCompFilterExpr:
   10438  * @ctxt:  the XPath Parser context
   10439  *
   10440  *  [20]   FilterExpr ::=   PrimaryExpr
   10441  *               | FilterExpr Predicate
   10442  *
   10443  * Compile a filter expression.
   10444  * Square brackets are used to filter expressions in the same way that
   10445  * they are used in location paths. It is an error if the expression to
   10446  * be filtered does not evaluate to a node-set. The context node list
   10447  * used for evaluating the expression in square brackets is the node-set
   10448  * to be filtered listed in document order.
   10449  */
   10450 
   10451 static void
   10452 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10453     xmlXPathCompPrimaryExpr(ctxt);
   10454     CHECK_ERROR;
   10455     SKIP_BLANKS;
   10456 
   10457     while (CUR == '[') {
   10458 	xmlXPathCompPredicate(ctxt, 1);
   10459 	SKIP_BLANKS;
   10460     }
   10461 
   10462 
   10463 }
   10464 
   10465 /**
   10466  * xmlXPathScanName:
   10467  * @ctxt:  the XPath Parser context
   10468  *
   10469  * Trickery: parse an XML name but without consuming the input flow
   10470  * Needed to avoid insanity in the parser state.
   10471  *
   10472  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10473  *                  CombiningChar | Extender
   10474  *
   10475  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10476  *
   10477  * [6] Names ::= Name (S Name)*
   10478  *
   10479  * Returns the Name parsed or NULL
   10480  */
   10481 
   10482 static xmlChar *
   10483 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10484     int len = 0, l;
   10485     int c;
   10486     const xmlChar *cur;
   10487     xmlChar *ret;
   10488 
   10489     cur = ctxt->cur;
   10490 
   10491     c = CUR_CHAR(l);
   10492     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10493 	(!IS_LETTER(c) && (c != '_') &&
   10494          (c != ':'))) {
   10495 	return(NULL);
   10496     }
   10497 
   10498     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10499 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10500             (c == '.') || (c == '-') ||
   10501 	    (c == '_') || (c == ':') ||
   10502 	    (IS_COMBINING(c)) ||
   10503 	    (IS_EXTENDER(c)))) {
   10504 	len += l;
   10505 	NEXTL(l);
   10506 	c = CUR_CHAR(l);
   10507     }
   10508     ret = xmlStrndup(cur, ctxt->cur - cur);
   10509     ctxt->cur = cur;
   10510     return(ret);
   10511 }
   10512 
   10513 /**
   10514  * xmlXPathCompPathExpr:
   10515  * @ctxt:  the XPath Parser context
   10516  *
   10517  *  [19]   PathExpr ::=   LocationPath
   10518  *               | FilterExpr
   10519  *               | FilterExpr '/' RelativeLocationPath
   10520  *               | FilterExpr '//' RelativeLocationPath
   10521  *
   10522  * Compile a path expression.
   10523  * The / operator and // operators combine an arbitrary expression
   10524  * and a relative location path. It is an error if the expression
   10525  * does not evaluate to a node-set.
   10526  * The / operator does composition in the same way as when / is
   10527  * used in a location path. As in location paths, // is short for
   10528  * /descendant-or-self::node()/.
   10529  */
   10530 
   10531 static void
   10532 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10533     int lc = 1;           /* Should we branch to LocationPath ?         */
   10534     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10535 
   10536     SKIP_BLANKS;
   10537     if ((CUR == '$') || (CUR == '(') ||
   10538 	(IS_ASCII_DIGIT(CUR)) ||
   10539         (CUR == '\'') || (CUR == '"') ||
   10540 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10541 	lc = 0;
   10542     } else if (CUR == '*') {
   10543 	/* relative or absolute location path */
   10544 	lc = 1;
   10545     } else if (CUR == '/') {
   10546 	/* relative or absolute location path */
   10547 	lc = 1;
   10548     } else if (CUR == '@') {
   10549 	/* relative abbreviated attribute location path */
   10550 	lc = 1;
   10551     } else if (CUR == '.') {
   10552 	/* relative abbreviated attribute location path */
   10553 	lc = 1;
   10554     } else {
   10555 	/*
   10556 	 * Problem is finding if we have a name here whether it's:
   10557 	 *   - a nodetype
   10558 	 *   - a function call in which case it's followed by '('
   10559 	 *   - an axis in which case it's followed by ':'
   10560 	 *   - a element name
   10561 	 * We do an a priori analysis here rather than having to
   10562 	 * maintain parsed token content through the recursive function
   10563 	 * calls. This looks uglier but makes the code easier to
   10564 	 * read/write/debug.
   10565 	 */
   10566 	SKIP_BLANKS;
   10567 	name = xmlXPathScanName(ctxt);
   10568 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10569 #ifdef DEBUG_STEP
   10570 	    xmlGenericError(xmlGenericErrorContext,
   10571 		    "PathExpr: Axis\n");
   10572 #endif
   10573 	    lc = 1;
   10574 	    xmlFree(name);
   10575 	} else if (name != NULL) {
   10576 	    int len =xmlStrlen(name);
   10577 
   10578 
   10579 	    while (NXT(len) != 0) {
   10580 		if (NXT(len) == '/') {
   10581 		    /* element name */
   10582 #ifdef DEBUG_STEP
   10583 		    xmlGenericError(xmlGenericErrorContext,
   10584 			    "PathExpr: AbbrRelLocation\n");
   10585 #endif
   10586 		    lc = 1;
   10587 		    break;
   10588 		} else if (IS_BLANK_CH(NXT(len))) {
   10589 		    /* ignore blanks */
   10590 		    ;
   10591 		} else if (NXT(len) == ':') {
   10592 #ifdef DEBUG_STEP
   10593 		    xmlGenericError(xmlGenericErrorContext,
   10594 			    "PathExpr: AbbrRelLocation\n");
   10595 #endif
   10596 		    lc = 1;
   10597 		    break;
   10598 		} else if ((NXT(len) == '(')) {
   10599 		    /* Note Type or Function */
   10600 		    if (xmlXPathIsNodeType(name)) {
   10601 #ifdef DEBUG_STEP
   10602 		        xmlGenericError(xmlGenericErrorContext,
   10603 				"PathExpr: Type search\n");
   10604 #endif
   10605 			lc = 1;
   10606 		    } else {
   10607 #ifdef DEBUG_STEP
   10608 		        xmlGenericError(xmlGenericErrorContext,
   10609 				"PathExpr: function call\n");
   10610 #endif
   10611 			lc = 0;
   10612 		    }
   10613                     break;
   10614 		} else if ((NXT(len) == '[')) {
   10615 		    /* element name */
   10616 #ifdef DEBUG_STEP
   10617 		    xmlGenericError(xmlGenericErrorContext,
   10618 			    "PathExpr: AbbrRelLocation\n");
   10619 #endif
   10620 		    lc = 1;
   10621 		    break;
   10622 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10623 			   (NXT(len) == '=')) {
   10624 		    lc = 1;
   10625 		    break;
   10626 		} else {
   10627 		    lc = 1;
   10628 		    break;
   10629 		}
   10630 		len++;
   10631 	    }
   10632 	    if (NXT(len) == 0) {
   10633 #ifdef DEBUG_STEP
   10634 		xmlGenericError(xmlGenericErrorContext,
   10635 			"PathExpr: AbbrRelLocation\n");
   10636 #endif
   10637 		/* element name */
   10638 		lc = 1;
   10639 	    }
   10640 	    xmlFree(name);
   10641 	} else {
   10642 	    /* make sure all cases are covered explicitly */
   10643 	    XP_ERROR(XPATH_EXPR_ERROR);
   10644 	}
   10645     }
   10646 
   10647     if (lc) {
   10648 	if (CUR == '/') {
   10649 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10650 	} else {
   10651 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10652 	}
   10653 	xmlXPathCompLocationPath(ctxt);
   10654     } else {
   10655 	xmlXPathCompFilterExpr(ctxt);
   10656 	CHECK_ERROR;
   10657 	if ((CUR == '/') && (NXT(1) == '/')) {
   10658 	    SKIP(2);
   10659 	    SKIP_BLANKS;
   10660 
   10661 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10662 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10663 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10664 
   10665 	    xmlXPathCompRelativeLocationPath(ctxt);
   10666 	} else if (CUR == '/') {
   10667 	    xmlXPathCompRelativeLocationPath(ctxt);
   10668 	}
   10669     }
   10670     SKIP_BLANKS;
   10671 }
   10672 
   10673 /**
   10674  * xmlXPathCompUnionExpr:
   10675  * @ctxt:  the XPath Parser context
   10676  *
   10677  *  [18]   UnionExpr ::=   PathExpr
   10678  *               | UnionExpr '|' PathExpr
   10679  *
   10680  * Compile an union expression.
   10681  */
   10682 
   10683 static void
   10684 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10685     xmlXPathCompPathExpr(ctxt);
   10686     CHECK_ERROR;
   10687     SKIP_BLANKS;
   10688     while (CUR == '|') {
   10689 	int op1 = ctxt->comp->last;
   10690 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10691 
   10692 	NEXT;
   10693 	SKIP_BLANKS;
   10694 	xmlXPathCompPathExpr(ctxt);
   10695 
   10696 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10697 
   10698 	SKIP_BLANKS;
   10699     }
   10700 }
   10701 
   10702 /**
   10703  * xmlXPathCompUnaryExpr:
   10704  * @ctxt:  the XPath Parser context
   10705  *
   10706  *  [27]   UnaryExpr ::=   UnionExpr
   10707  *                   | '-' UnaryExpr
   10708  *
   10709  * Compile an unary expression.
   10710  */
   10711 
   10712 static void
   10713 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10714     int minus = 0;
   10715     int found = 0;
   10716 
   10717     SKIP_BLANKS;
   10718     while (CUR == '-') {
   10719         minus = 1 - minus;
   10720 	found = 1;
   10721 	NEXT;
   10722 	SKIP_BLANKS;
   10723     }
   10724 
   10725     xmlXPathCompUnionExpr(ctxt);
   10726     CHECK_ERROR;
   10727     if (found) {
   10728 	if (minus)
   10729 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10730 	else
   10731 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10732     }
   10733 }
   10734 
   10735 /**
   10736  * xmlXPathCompMultiplicativeExpr:
   10737  * @ctxt:  the XPath Parser context
   10738  *
   10739  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10740  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10741  *                   | MultiplicativeExpr 'div' UnaryExpr
   10742  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10743  *  [34]   MultiplyOperator ::=   '*'
   10744  *
   10745  * Compile an Additive expression.
   10746  */
   10747 
   10748 static void
   10749 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10750     xmlXPathCompUnaryExpr(ctxt);
   10751     CHECK_ERROR;
   10752     SKIP_BLANKS;
   10753     while ((CUR == '*') ||
   10754            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10755            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10756 	int op = -1;
   10757 	int op1 = ctxt->comp->last;
   10758 
   10759         if (CUR == '*') {
   10760 	    op = 0;
   10761 	    NEXT;
   10762 	} else if (CUR == 'd') {
   10763 	    op = 1;
   10764 	    SKIP(3);
   10765 	} else if (CUR == 'm') {
   10766 	    op = 2;
   10767 	    SKIP(3);
   10768 	}
   10769 	SKIP_BLANKS;
   10770         xmlXPathCompUnaryExpr(ctxt);
   10771 	CHECK_ERROR;
   10772 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10773 	SKIP_BLANKS;
   10774     }
   10775 }
   10776 
   10777 /**
   10778  * xmlXPathCompAdditiveExpr:
   10779  * @ctxt:  the XPath Parser context
   10780  *
   10781  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10782  *                   | AdditiveExpr '+' MultiplicativeExpr
   10783  *                   | AdditiveExpr '-' MultiplicativeExpr
   10784  *
   10785  * Compile an Additive expression.
   10786  */
   10787 
   10788 static void
   10789 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10790 
   10791     xmlXPathCompMultiplicativeExpr(ctxt);
   10792     CHECK_ERROR;
   10793     SKIP_BLANKS;
   10794     while ((CUR == '+') || (CUR == '-')) {
   10795 	int plus;
   10796 	int op1 = ctxt->comp->last;
   10797 
   10798         if (CUR == '+') plus = 1;
   10799 	else plus = 0;
   10800 	NEXT;
   10801 	SKIP_BLANKS;
   10802         xmlXPathCompMultiplicativeExpr(ctxt);
   10803 	CHECK_ERROR;
   10804 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10805 	SKIP_BLANKS;
   10806     }
   10807 }
   10808 
   10809 /**
   10810  * xmlXPathCompRelationalExpr:
   10811  * @ctxt:  the XPath Parser context
   10812  *
   10813  *  [24]   RelationalExpr ::=   AdditiveExpr
   10814  *                 | RelationalExpr '<' AdditiveExpr
   10815  *                 | RelationalExpr '>' AdditiveExpr
   10816  *                 | RelationalExpr '<=' AdditiveExpr
   10817  *                 | RelationalExpr '>=' AdditiveExpr
   10818  *
   10819  *  A <= B > C is allowed ? Answer from James, yes with
   10820  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10821  *  which is basically what got implemented.
   10822  *
   10823  * Compile a Relational expression, then push the result
   10824  * on the stack
   10825  */
   10826 
   10827 static void
   10828 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10829     xmlXPathCompAdditiveExpr(ctxt);
   10830     CHECK_ERROR;
   10831     SKIP_BLANKS;
   10832     while ((CUR == '<') ||
   10833            (CUR == '>') ||
   10834            ((CUR == '<') && (NXT(1) == '=')) ||
   10835            ((CUR == '>') && (NXT(1) == '='))) {
   10836 	int inf, strict;
   10837 	int op1 = ctxt->comp->last;
   10838 
   10839         if (CUR == '<') inf = 1;
   10840 	else inf = 0;
   10841 	if (NXT(1) == '=') strict = 0;
   10842 	else strict = 1;
   10843 	NEXT;
   10844 	if (!strict) NEXT;
   10845 	SKIP_BLANKS;
   10846         xmlXPathCompAdditiveExpr(ctxt);
   10847 	CHECK_ERROR;
   10848 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10849 	SKIP_BLANKS;
   10850     }
   10851 }
   10852 
   10853 /**
   10854  * xmlXPathCompEqualityExpr:
   10855  * @ctxt:  the XPath Parser context
   10856  *
   10857  *  [23]   EqualityExpr ::=   RelationalExpr
   10858  *                 | EqualityExpr '=' RelationalExpr
   10859  *                 | EqualityExpr '!=' RelationalExpr
   10860  *
   10861  *  A != B != C is allowed ? Answer from James, yes with
   10862  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10863  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10864  *  which is basically what got implemented.
   10865  *
   10866  * Compile an Equality expression.
   10867  *
   10868  */
   10869 static void
   10870 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10871     xmlXPathCompRelationalExpr(ctxt);
   10872     CHECK_ERROR;
   10873     SKIP_BLANKS;
   10874     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10875 	int eq;
   10876 	int op1 = ctxt->comp->last;
   10877 
   10878         if (CUR == '=') eq = 1;
   10879 	else eq = 0;
   10880 	NEXT;
   10881 	if (!eq) NEXT;
   10882 	SKIP_BLANKS;
   10883         xmlXPathCompRelationalExpr(ctxt);
   10884 	CHECK_ERROR;
   10885 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10886 	SKIP_BLANKS;
   10887     }
   10888 }
   10889 
   10890 /**
   10891  * xmlXPathCompAndExpr:
   10892  * @ctxt:  the XPath Parser context
   10893  *
   10894  *  [22]   AndExpr ::=   EqualityExpr
   10895  *                 | AndExpr 'and' EqualityExpr
   10896  *
   10897  * Compile an AND expression.
   10898  *
   10899  */
   10900 static void
   10901 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10902     xmlXPathCompEqualityExpr(ctxt);
   10903     CHECK_ERROR;
   10904     SKIP_BLANKS;
   10905     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10906 	int op1 = ctxt->comp->last;
   10907         SKIP(3);
   10908 	SKIP_BLANKS;
   10909         xmlXPathCompEqualityExpr(ctxt);
   10910 	CHECK_ERROR;
   10911 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   10912 	SKIP_BLANKS;
   10913     }
   10914 }
   10915 
   10916 /**
   10917  * xmlXPathCompileExpr:
   10918  * @ctxt:  the XPath Parser context
   10919  *
   10920  *  [14]   Expr ::=   OrExpr
   10921  *  [21]   OrExpr ::=   AndExpr
   10922  *                 | OrExpr 'or' AndExpr
   10923  *
   10924  * Parse and compile an expression
   10925  */
   10926 static void
   10927 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   10928     xmlXPathCompAndExpr(ctxt);
   10929     CHECK_ERROR;
   10930     SKIP_BLANKS;
   10931     while ((CUR == 'o') && (NXT(1) == 'r')) {
   10932 	int op1 = ctxt->comp->last;
   10933         SKIP(2);
   10934 	SKIP_BLANKS;
   10935         xmlXPathCompAndExpr(ctxt);
   10936 	CHECK_ERROR;
   10937 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   10938 	SKIP_BLANKS;
   10939     }
   10940     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   10941 	/* more ops could be optimized too */
   10942 	/*
   10943 	* This is the main place to eliminate sorting for
   10944 	* operations which don't require a sorted node-set.
   10945 	* E.g. count().
   10946 	*/
   10947 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   10948     }
   10949 }
   10950 
   10951 /**
   10952  * xmlXPathCompPredicate:
   10953  * @ctxt:  the XPath Parser context
   10954  * @filter:  act as a filter
   10955  *
   10956  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   10957  *  [9]   PredicateExpr ::=   Expr
   10958  *
   10959  * Compile a predicate expression
   10960  */
   10961 static void
   10962 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   10963     int op1 = ctxt->comp->last;
   10964 
   10965     SKIP_BLANKS;
   10966     if (CUR != '[') {
   10967 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10968     }
   10969     NEXT;
   10970     SKIP_BLANKS;
   10971 
   10972     ctxt->comp->last = -1;
   10973     /*
   10974     * This call to xmlXPathCompileExpr() will deactivate sorting
   10975     * of the predicate result.
   10976     * TODO: Sorting is still activated for filters, since I'm not
   10977     *  sure if needed. Normally sorting should not be needed, since
   10978     *  a filter can only diminish the number of items in a sequence,
   10979     *  but won't change its order; so if the initial sequence is sorted,
   10980     *  subsequent sorting is not needed.
   10981     */
   10982     if (! filter)
   10983 	xmlXPathCompileExpr(ctxt, 0);
   10984     else
   10985 	xmlXPathCompileExpr(ctxt, 1);
   10986     CHECK_ERROR;
   10987 
   10988     if (CUR != ']') {
   10989 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10990     }
   10991 
   10992     if (filter)
   10993 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   10994     else
   10995 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   10996 
   10997     NEXT;
   10998     SKIP_BLANKS;
   10999 }
   11000 
   11001 /**
   11002  * xmlXPathCompNodeTest:
   11003  * @ctxt:  the XPath Parser context
   11004  * @test:  pointer to a xmlXPathTestVal
   11005  * @type:  pointer to a xmlXPathTypeVal
   11006  * @prefix:  placeholder for a possible name prefix
   11007  *
   11008  * [7] NodeTest ::=   NameTest
   11009  *		    | NodeType '(' ')'
   11010  *		    | 'processing-instruction' '(' Literal ')'
   11011  *
   11012  * [37] NameTest ::=  '*'
   11013  *		    | NCName ':' '*'
   11014  *		    | QName
   11015  * [38] NodeType ::= 'comment'
   11016  *		   | 'text'
   11017  *		   | 'processing-instruction'
   11018  *		   | 'node'
   11019  *
   11020  * Returns the name found and updates @test, @type and @prefix appropriately
   11021  */
   11022 static xmlChar *
   11023 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11024 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11025 		     xmlChar *name) {
   11026     int blanks;
   11027 
   11028     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11029 	STRANGE;
   11030 	return(NULL);
   11031     }
   11032     *type = (xmlXPathTypeVal) 0;
   11033     *test = (xmlXPathTestVal) 0;
   11034     *prefix = NULL;
   11035     SKIP_BLANKS;
   11036 
   11037     if ((name == NULL) && (CUR == '*')) {
   11038 	/*
   11039 	 * All elements
   11040 	 */
   11041 	NEXT;
   11042 	*test = NODE_TEST_ALL;
   11043 	return(NULL);
   11044     }
   11045 
   11046     if (name == NULL)
   11047 	name = xmlXPathParseNCName(ctxt);
   11048     if (name == NULL) {
   11049 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11050     }
   11051 
   11052     blanks = IS_BLANK_CH(CUR);
   11053     SKIP_BLANKS;
   11054     if (CUR == '(') {
   11055 	NEXT;
   11056 	/*
   11057 	 * NodeType or PI search
   11058 	 */
   11059 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11060 	    *type = NODE_TYPE_COMMENT;
   11061 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11062 	    *type = NODE_TYPE_NODE;
   11063 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11064 	    *type = NODE_TYPE_PI;
   11065 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11066 	    *type = NODE_TYPE_TEXT;
   11067 	else {
   11068 	    if (name != NULL)
   11069 		xmlFree(name);
   11070 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11071 	}
   11072 
   11073 	*test = NODE_TEST_TYPE;
   11074 
   11075 	SKIP_BLANKS;
   11076 	if (*type == NODE_TYPE_PI) {
   11077 	    /*
   11078 	     * Specific case: search a PI by name.
   11079 	     */
   11080 	    if (name != NULL)
   11081 		xmlFree(name);
   11082 	    name = NULL;
   11083 	    if (CUR != ')') {
   11084 		name = xmlXPathParseLiteral(ctxt);
   11085 		CHECK_ERROR NULL;
   11086 		*test = NODE_TEST_PI;
   11087 		SKIP_BLANKS;
   11088 	    }
   11089 	}
   11090 	if (CUR != ')') {
   11091 	    if (name != NULL)
   11092 		xmlFree(name);
   11093 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11094 	}
   11095 	NEXT;
   11096 	return(name);
   11097     }
   11098     *test = NODE_TEST_NAME;
   11099     if ((!blanks) && (CUR == ':')) {
   11100 	NEXT;
   11101 
   11102 	/*
   11103 	 * Since currently the parser context don't have a
   11104 	 * namespace list associated:
   11105 	 * The namespace name for this prefix can be computed
   11106 	 * only at evaluation time. The compilation is done
   11107 	 * outside of any context.
   11108 	 */
   11109 #if 0
   11110 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11111 	if (name != NULL)
   11112 	    xmlFree(name);
   11113 	if (*prefix == NULL) {
   11114 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11115 	}
   11116 #else
   11117 	*prefix = name;
   11118 #endif
   11119 
   11120 	if (CUR == '*') {
   11121 	    /*
   11122 	     * All elements
   11123 	     */
   11124 	    NEXT;
   11125 	    *test = NODE_TEST_ALL;
   11126 	    return(NULL);
   11127 	}
   11128 
   11129 	name = xmlXPathParseNCName(ctxt);
   11130 	if (name == NULL) {
   11131 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11132 	}
   11133     }
   11134     return(name);
   11135 }
   11136 
   11137 /**
   11138  * xmlXPathIsAxisName:
   11139  * @name:  a preparsed name token
   11140  *
   11141  * [6] AxisName ::=   'ancestor'
   11142  *                  | 'ancestor-or-self'
   11143  *                  | 'attribute'
   11144  *                  | 'child'
   11145  *                  | 'descendant'
   11146  *                  | 'descendant-or-self'
   11147  *                  | 'following'
   11148  *                  | 'following-sibling'
   11149  *                  | 'namespace'
   11150  *                  | 'parent'
   11151  *                  | 'preceding'
   11152  *                  | 'preceding-sibling'
   11153  *                  | 'self'
   11154  *
   11155  * Returns the axis or 0
   11156  */
   11157 static xmlXPathAxisVal
   11158 xmlXPathIsAxisName(const xmlChar *name) {
   11159     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11160     switch (name[0]) {
   11161 	case 'a':
   11162 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11163 		ret = AXIS_ANCESTOR;
   11164 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11165 		ret = AXIS_ANCESTOR_OR_SELF;
   11166 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11167 		ret = AXIS_ATTRIBUTE;
   11168 	    break;
   11169 	case 'c':
   11170 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11171 		ret = AXIS_CHILD;
   11172 	    break;
   11173 	case 'd':
   11174 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11175 		ret = AXIS_DESCENDANT;
   11176 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11177 		ret = AXIS_DESCENDANT_OR_SELF;
   11178 	    break;
   11179 	case 'f':
   11180 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11181 		ret = AXIS_FOLLOWING;
   11182 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11183 		ret = AXIS_FOLLOWING_SIBLING;
   11184 	    break;
   11185 	case 'n':
   11186 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11187 		ret = AXIS_NAMESPACE;
   11188 	    break;
   11189 	case 'p':
   11190 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11191 		ret = AXIS_PARENT;
   11192 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11193 		ret = AXIS_PRECEDING;
   11194 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11195 		ret = AXIS_PRECEDING_SIBLING;
   11196 	    break;
   11197 	case 's':
   11198 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11199 		ret = AXIS_SELF;
   11200 	    break;
   11201     }
   11202     return(ret);
   11203 }
   11204 
   11205 /**
   11206  * xmlXPathCompStep:
   11207  * @ctxt:  the XPath Parser context
   11208  *
   11209  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11210  *                  | AbbreviatedStep
   11211  *
   11212  * [12] AbbreviatedStep ::=   '.' | '..'
   11213  *
   11214  * [5] AxisSpecifier ::= AxisName '::'
   11215  *                  | AbbreviatedAxisSpecifier
   11216  *
   11217  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11218  *
   11219  * Modified for XPtr range support as:
   11220  *
   11221  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11222  *                     | AbbreviatedStep
   11223  *                     | 'range-to' '(' Expr ')' Predicate*
   11224  *
   11225  * Compile one step in a Location Path
   11226  * A location step of . is short for self::node(). This is
   11227  * particularly useful in conjunction with //. For example, the
   11228  * location path .//para is short for
   11229  * self::node()/descendant-or-self::node()/child::para
   11230  * and so will select all para descendant elements of the context
   11231  * node.
   11232  * Similarly, a location step of .. is short for parent::node().
   11233  * For example, ../title is short for parent::node()/child::title
   11234  * and so will select the title children of the parent of the context
   11235  * node.
   11236  */
   11237 static void
   11238 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11239 #ifdef LIBXML_XPTR_ENABLED
   11240     int rangeto = 0;
   11241     int op2 = -1;
   11242 #endif
   11243 
   11244     SKIP_BLANKS;
   11245     if ((CUR == '.') && (NXT(1) == '.')) {
   11246 	SKIP(2);
   11247 	SKIP_BLANKS;
   11248 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11249 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11250     } else if (CUR == '.') {
   11251 	NEXT;
   11252 	SKIP_BLANKS;
   11253     } else {
   11254 	xmlChar *name = NULL;
   11255 	const xmlChar *prefix = NULL;
   11256 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11257 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11258 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11259 	int op1;
   11260 
   11261 	/*
   11262 	 * The modification needed for XPointer change to the production
   11263 	 */
   11264 #ifdef LIBXML_XPTR_ENABLED
   11265 	if (ctxt->xptr) {
   11266 	    name = xmlXPathParseNCName(ctxt);
   11267 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11268                 op2 = ctxt->comp->last;
   11269 		xmlFree(name);
   11270 		SKIP_BLANKS;
   11271 		if (CUR != '(') {
   11272 		    XP_ERROR(XPATH_EXPR_ERROR);
   11273 		}
   11274 		NEXT;
   11275 		SKIP_BLANKS;
   11276 
   11277 		xmlXPathCompileExpr(ctxt, 1);
   11278 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11279 		CHECK_ERROR;
   11280 
   11281 		SKIP_BLANKS;
   11282 		if (CUR != ')') {
   11283 		    XP_ERROR(XPATH_EXPR_ERROR);
   11284 		}
   11285 		NEXT;
   11286 		rangeto = 1;
   11287 		goto eval_predicates;
   11288 	    }
   11289 	}
   11290 #endif
   11291 	if (CUR == '*') {
   11292 	    axis = AXIS_CHILD;
   11293 	} else {
   11294 	    if (name == NULL)
   11295 		name = xmlXPathParseNCName(ctxt);
   11296 	    if (name != NULL) {
   11297 		axis = xmlXPathIsAxisName(name);
   11298 		if (axis != 0) {
   11299 		    SKIP_BLANKS;
   11300 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11301 			SKIP(2);
   11302 			xmlFree(name);
   11303 			name = NULL;
   11304 		    } else {
   11305 			/* an element name can conflict with an axis one :-\ */
   11306 			axis = AXIS_CHILD;
   11307 		    }
   11308 		} else {
   11309 		    axis = AXIS_CHILD;
   11310 		}
   11311 	    } else if (CUR == '@') {
   11312 		NEXT;
   11313 		axis = AXIS_ATTRIBUTE;
   11314 	    } else {
   11315 		axis = AXIS_CHILD;
   11316 	    }
   11317 	}
   11318 
   11319         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11320             xmlFree(name);
   11321             return;
   11322         }
   11323 
   11324 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11325 	if (test == 0)
   11326 	    return;
   11327 
   11328         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11329 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11330 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11331 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11332 	    }
   11333 	}
   11334 #ifdef DEBUG_STEP
   11335 	xmlGenericError(xmlGenericErrorContext,
   11336 		"Basis : computing new set\n");
   11337 #endif
   11338 
   11339 #ifdef DEBUG_STEP
   11340 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11341 	if (ctxt->value == NULL)
   11342 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11343 	else if (ctxt->value->nodesetval == NULL)
   11344 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11345 	else
   11346 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11347 #endif
   11348 
   11349 #ifdef LIBXML_XPTR_ENABLED
   11350 eval_predicates:
   11351 #endif
   11352 	op1 = ctxt->comp->last;
   11353 	ctxt->comp->last = -1;
   11354 
   11355 	SKIP_BLANKS;
   11356 	while (CUR == '[') {
   11357 	    xmlXPathCompPredicate(ctxt, 0);
   11358 	}
   11359 
   11360 #ifdef LIBXML_XPTR_ENABLED
   11361 	if (rangeto) {
   11362 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11363 	} else
   11364 #endif
   11365 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11366 			   test, type, (void *)prefix, (void *)name);
   11367 
   11368     }
   11369 #ifdef DEBUG_STEP
   11370     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11371     if (ctxt->value == NULL)
   11372 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11373     else if (ctxt->value->nodesetval == NULL)
   11374 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11375     else
   11376 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11377 		ctxt->value->nodesetval);
   11378 #endif
   11379 }
   11380 
   11381 /**
   11382  * xmlXPathCompRelativeLocationPath:
   11383  * @ctxt:  the XPath Parser context
   11384  *
   11385  *  [3]   RelativeLocationPath ::=   Step
   11386  *                     | RelativeLocationPath '/' Step
   11387  *                     | AbbreviatedRelativeLocationPath
   11388  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11389  *
   11390  * Compile a relative location path.
   11391  */
   11392 static void
   11393 xmlXPathCompRelativeLocationPath
   11394 (xmlXPathParserContextPtr ctxt) {
   11395     SKIP_BLANKS;
   11396     if ((CUR == '/') && (NXT(1) == '/')) {
   11397 	SKIP(2);
   11398 	SKIP_BLANKS;
   11399 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11400 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11401     } else if (CUR == '/') {
   11402 	    NEXT;
   11403 	SKIP_BLANKS;
   11404     }
   11405     xmlXPathCompStep(ctxt);
   11406     CHECK_ERROR;
   11407     SKIP_BLANKS;
   11408     while (CUR == '/') {
   11409 	if ((CUR == '/') && (NXT(1) == '/')) {
   11410 	    SKIP(2);
   11411 	    SKIP_BLANKS;
   11412 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11413 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11414 	    xmlXPathCompStep(ctxt);
   11415 	} else if (CUR == '/') {
   11416 	    NEXT;
   11417 	    SKIP_BLANKS;
   11418 	    xmlXPathCompStep(ctxt);
   11419 	}
   11420 	SKIP_BLANKS;
   11421     }
   11422 }
   11423 
   11424 /**
   11425  * xmlXPathCompLocationPath:
   11426  * @ctxt:  the XPath Parser context
   11427  *
   11428  *  [1]   LocationPath ::=   RelativeLocationPath
   11429  *                     | AbsoluteLocationPath
   11430  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11431  *                     | AbbreviatedAbsoluteLocationPath
   11432  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11433  *                           '//' RelativeLocationPath
   11434  *
   11435  * Compile a location path
   11436  *
   11437  * // is short for /descendant-or-self::node()/. For example,
   11438  * //para is short for /descendant-or-self::node()/child::para and
   11439  * so will select any para element in the document (even a para element
   11440  * that is a document element will be selected by //para since the
   11441  * document element node is a child of the root node); div//para is
   11442  * short for div/descendant-or-self::node()/child::para and so will
   11443  * select all para descendants of div children.
   11444  */
   11445 static void
   11446 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11447     SKIP_BLANKS;
   11448     if (CUR != '/') {
   11449         xmlXPathCompRelativeLocationPath(ctxt);
   11450     } else {
   11451 	while (CUR == '/') {
   11452 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11453 		SKIP(2);
   11454 		SKIP_BLANKS;
   11455 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11456 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11457 		xmlXPathCompRelativeLocationPath(ctxt);
   11458 	    } else if (CUR == '/') {
   11459 		NEXT;
   11460 		SKIP_BLANKS;
   11461 		if ((CUR != 0 ) &&
   11462 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11463 		     (CUR == '@') || (CUR == '*')))
   11464 		    xmlXPathCompRelativeLocationPath(ctxt);
   11465 	    }
   11466 	    CHECK_ERROR;
   11467 	}
   11468     }
   11469 }
   11470 
   11471 /************************************************************************
   11472  *									*
   11473  *		XPath precompiled expression evaluation			*
   11474  *									*
   11475  ************************************************************************/
   11476 
   11477 static int
   11478 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11479 
   11480 #ifdef DEBUG_STEP
   11481 static void
   11482 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11483 			  int nbNodes)
   11484 {
   11485     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11486     switch (op->value) {
   11487         case AXIS_ANCESTOR:
   11488             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11489             break;
   11490         case AXIS_ANCESTOR_OR_SELF:
   11491             xmlGenericError(xmlGenericErrorContext,
   11492                             "axis 'ancestors-or-self' ");
   11493             break;
   11494         case AXIS_ATTRIBUTE:
   11495             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11496             break;
   11497         case AXIS_CHILD:
   11498             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11499             break;
   11500         case AXIS_DESCENDANT:
   11501             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11502             break;
   11503         case AXIS_DESCENDANT_OR_SELF:
   11504             xmlGenericError(xmlGenericErrorContext,
   11505                             "axis 'descendant-or-self' ");
   11506             break;
   11507         case AXIS_FOLLOWING:
   11508             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11509             break;
   11510         case AXIS_FOLLOWING_SIBLING:
   11511             xmlGenericError(xmlGenericErrorContext,
   11512                             "axis 'following-siblings' ");
   11513             break;
   11514         case AXIS_NAMESPACE:
   11515             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11516             break;
   11517         case AXIS_PARENT:
   11518             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11519             break;
   11520         case AXIS_PRECEDING:
   11521             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11522             break;
   11523         case AXIS_PRECEDING_SIBLING:
   11524             xmlGenericError(xmlGenericErrorContext,
   11525                             "axis 'preceding-sibling' ");
   11526             break;
   11527         case AXIS_SELF:
   11528             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11529             break;
   11530     }
   11531     xmlGenericError(xmlGenericErrorContext,
   11532 	" context contains %d nodes\n", nbNodes);
   11533     switch (op->value2) {
   11534         case NODE_TEST_NONE:
   11535             xmlGenericError(xmlGenericErrorContext,
   11536                             "           searching for none !!!\n");
   11537             break;
   11538         case NODE_TEST_TYPE:
   11539             xmlGenericError(xmlGenericErrorContext,
   11540                             "           searching for type %d\n", op->value3);
   11541             break;
   11542         case NODE_TEST_PI:
   11543             xmlGenericError(xmlGenericErrorContext,
   11544                             "           searching for PI !!!\n");
   11545             break;
   11546         case NODE_TEST_ALL:
   11547             xmlGenericError(xmlGenericErrorContext,
   11548                             "           searching for *\n");
   11549             break;
   11550         case NODE_TEST_NS:
   11551             xmlGenericError(xmlGenericErrorContext,
   11552                             "           searching for namespace %s\n",
   11553                             op->value5);
   11554             break;
   11555         case NODE_TEST_NAME:
   11556             xmlGenericError(xmlGenericErrorContext,
   11557                             "           searching for name %s\n", op->value5);
   11558             if (op->value4)
   11559                 xmlGenericError(xmlGenericErrorContext,
   11560                                 "           with namespace %s\n", op->value4);
   11561             break;
   11562     }
   11563     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11564 }
   11565 #endif /* DEBUG_STEP */
   11566 
   11567 static int
   11568 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11569 			    xmlXPathStepOpPtr op,
   11570 			    xmlNodeSetPtr set,
   11571 			    int contextSize,
   11572 			    int hasNsNodes)
   11573 {
   11574     if (op->ch1 != -1) {
   11575 	xmlXPathCompExprPtr comp = ctxt->comp;
   11576 	/*
   11577 	* Process inner predicates first.
   11578 	*/
   11579 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11580 	    /*
   11581 	    * TODO: raise an internal error.
   11582 	    */
   11583 	}
   11584 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11585 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11586 	CHECK_ERROR0;
   11587 	if (contextSize <= 0)
   11588 	    return(0);
   11589     }
   11590     if (op->ch2 != -1) {
   11591 	xmlXPathContextPtr xpctxt = ctxt->context;
   11592 	xmlNodePtr contextNode, oldContextNode;
   11593 	xmlDocPtr oldContextDoc;
   11594 	int i, res, contextPos = 0, newContextSize;
   11595 	xmlXPathStepOpPtr exprOp;
   11596 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11597 
   11598 #ifdef LIBXML_XPTR_ENABLED
   11599 	/*
   11600 	* URGENT TODO: Check the following:
   11601 	*  We don't expect location sets if evaluating prediates, right?
   11602 	*  Only filters should expect location sets, right?
   11603 	*/
   11604 #endif
   11605 	/*
   11606 	* SPEC XPath 1.0:
   11607 	*  "For each node in the node-set to be filtered, the
   11608 	*  PredicateExpr is evaluated with that node as the
   11609 	*  context node, with the number of nodes in the
   11610 	*  node-set as the context size, and with the proximity
   11611 	*  position of the node in the node-set with respect to
   11612 	*  the axis as the context position;"
   11613 	* @oldset is the node-set" to be filtered.
   11614 	*
   11615 	* SPEC XPath 1.0:
   11616 	*  "only predicates change the context position and
   11617 	*  context size (see [2.4 Predicates])."
   11618 	* Example:
   11619 	*   node-set  context pos
   11620 	*    nA         1
   11621 	*    nB         2
   11622 	*    nC         3
   11623 	*   After applying predicate [position() > 1] :
   11624 	*   node-set  context pos
   11625 	*    nB         1
   11626 	*    nC         2
   11627 	*/
   11628 	oldContextNode = xpctxt->node;
   11629 	oldContextDoc = xpctxt->doc;
   11630 	/*
   11631 	* Get the expression of this predicate.
   11632 	*/
   11633 	exprOp = &ctxt->comp->steps[op->ch2];
   11634 	newContextSize = 0;
   11635 	for (i = 0; i < set->nodeNr; i++) {
   11636 	    if (set->nodeTab[i] == NULL)
   11637 		continue;
   11638 
   11639 	    contextNode = set->nodeTab[i];
   11640 	    xpctxt->node = contextNode;
   11641 	    xpctxt->contextSize = contextSize;
   11642 	    xpctxt->proximityPosition = ++contextPos;
   11643 
   11644 	    /*
   11645 	    * Also set the xpath document in case things like
   11646 	    * key() are evaluated in the predicate.
   11647 	    */
   11648 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11649 		(contextNode->doc != NULL))
   11650 		xpctxt->doc = contextNode->doc;
   11651 	    /*
   11652 	    * Evaluate the predicate expression with 1 context node
   11653 	    * at a time; this node is packaged into a node set; this
   11654 	    * node set is handed over to the evaluation mechanism.
   11655 	    */
   11656 	    if (contextObj == NULL)
   11657 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11658 	    else
   11659 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11660 		    contextNode);
   11661 
   11662 	    valuePush(ctxt, contextObj);
   11663 
   11664 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11665 
   11666 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11667 		xmlXPathNodeSetClear(set, hasNsNodes);
   11668 		newContextSize = 0;
   11669 		goto evaluation_exit;
   11670 	    }
   11671 
   11672 	    if (res != 0) {
   11673 		newContextSize++;
   11674 	    } else {
   11675 		/*
   11676 		* Remove the entry from the initial node set.
   11677 		*/
   11678 		set->nodeTab[i] = NULL;
   11679 		if (contextNode->type == XML_NAMESPACE_DECL)
   11680 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11681 	    }
   11682 	    if (ctxt->value == contextObj) {
   11683 		/*
   11684 		* Don't free the temporary XPath object holding the
   11685 		* context node, in order to avoid massive recreation
   11686 		* inside this loop.
   11687 		*/
   11688 		valuePop(ctxt);
   11689 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11690 	    } else {
   11691 		/*
   11692 		* TODO: The object was lost in the evaluation machinery.
   11693 		*  Can this happen? Maybe in internal-error cases.
   11694 		*/
   11695 		contextObj = NULL;
   11696 	    }
   11697 	}
   11698 
   11699 	if (contextObj != NULL) {
   11700 	    if (ctxt->value == contextObj)
   11701 		valuePop(ctxt);
   11702 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11703 	}
   11704 evaluation_exit:
   11705 	if (exprRes != NULL)
   11706 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11707 	/*
   11708 	* Reset/invalidate the context.
   11709 	*/
   11710 	xpctxt->node = oldContextNode;
   11711 	xpctxt->doc = oldContextDoc;
   11712 	xpctxt->contextSize = -1;
   11713 	xpctxt->proximityPosition = -1;
   11714 	return(newContextSize);
   11715     }
   11716     return(contextSize);
   11717 }
   11718 
   11719 static int
   11720 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11721 				      xmlXPathStepOpPtr op,
   11722 				      xmlNodeSetPtr set,
   11723 				      int contextSize,
   11724 				      int minPos,
   11725 				      int maxPos,
   11726 				      int hasNsNodes)
   11727 {
   11728     if (op->ch1 != -1) {
   11729 	xmlXPathCompExprPtr comp = ctxt->comp;
   11730 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11731 	    /*
   11732 	    * TODO: raise an internal error.
   11733 	    */
   11734 	}
   11735 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11736 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11737 	CHECK_ERROR0;
   11738 	if (contextSize <= 0)
   11739 	    return(0);
   11740     }
   11741     /*
   11742     * Check if the node set contains a sufficient number of nodes for
   11743     * the requested range.
   11744     */
   11745     if (contextSize < minPos) {
   11746 	xmlXPathNodeSetClear(set, hasNsNodes);
   11747 	return(0);
   11748     }
   11749     if (op->ch2 == -1) {
   11750 	/*
   11751 	* TODO: Can this ever happen?
   11752 	*/
   11753 	return (contextSize);
   11754     } else {
   11755 	xmlDocPtr oldContextDoc;
   11756 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11757 	xmlXPathStepOpPtr exprOp;
   11758 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11759 	xmlNodePtr oldContextNode, contextNode = NULL;
   11760 	xmlXPathContextPtr xpctxt = ctxt->context;
   11761         int frame;
   11762 
   11763 #ifdef LIBXML_XPTR_ENABLED
   11764 	    /*
   11765 	    * URGENT TODO: Check the following:
   11766 	    *  We don't expect location sets if evaluating prediates, right?
   11767 	    *  Only filters should expect location sets, right?
   11768 	*/
   11769 #endif /* LIBXML_XPTR_ENABLED */
   11770 
   11771 	/*
   11772 	* Save old context.
   11773 	*/
   11774 	oldContextNode = xpctxt->node;
   11775 	oldContextDoc = xpctxt->doc;
   11776 	/*
   11777 	* Get the expression of this predicate.
   11778 	*/
   11779 	exprOp = &ctxt->comp->steps[op->ch2];
   11780 	for (i = 0; i < set->nodeNr; i++) {
   11781             xmlXPathObjectPtr tmp;
   11782 
   11783 	    if (set->nodeTab[i] == NULL)
   11784 		continue;
   11785 
   11786 	    contextNode = set->nodeTab[i];
   11787 	    xpctxt->node = contextNode;
   11788 	    xpctxt->contextSize = contextSize;
   11789 	    xpctxt->proximityPosition = ++contextPos;
   11790 
   11791 	    /*
   11792 	    * Initialize the new set.
   11793 	    * Also set the xpath document in case things like
   11794 	    * key() evaluation are attempted on the predicate
   11795 	    */
   11796 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11797 		(contextNode->doc != NULL))
   11798 		xpctxt->doc = contextNode->doc;
   11799 	    /*
   11800 	    * Evaluate the predicate expression with 1 context node
   11801 	    * at a time; this node is packaged into a node set; this
   11802 	    * node set is handed over to the evaluation mechanism.
   11803 	    */
   11804 	    if (contextObj == NULL)
   11805 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11806 	    else
   11807 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11808 		    contextNode);
   11809 
   11810             frame = xmlXPathSetFrame(ctxt);
   11811 	    valuePush(ctxt, contextObj);
   11812 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11813             tmp = valuePop(ctxt);
   11814             xmlXPathPopFrame(ctxt, frame);
   11815 
   11816 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11817                 while (tmp != contextObj) {
   11818                     /*
   11819                      * Free up the result
   11820                      * then pop off contextObj, which will be freed later
   11821                      */
   11822                     xmlXPathReleaseObject(xpctxt, tmp);
   11823                     tmp = valuePop(ctxt);
   11824                 }
   11825 		goto evaluation_error;
   11826 	    }
   11827             /* push the result back onto the stack */
   11828             valuePush(ctxt, tmp);
   11829 
   11830 	    if (res)
   11831 		pos++;
   11832 
   11833 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11834 		/*
   11835 		* Fits in the requested range.
   11836 		*/
   11837 		newContextSize++;
   11838 		if (minPos == maxPos) {
   11839 		    /*
   11840 		    * Only 1 node was requested.
   11841 		    */
   11842 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11843 			/*
   11844 			* As always: take care of those nasty
   11845 			* namespace nodes.
   11846 			*/
   11847 			set->nodeTab[i] = NULL;
   11848 		    }
   11849 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11850 		    set->nodeNr = 1;
   11851 		    set->nodeTab[0] = contextNode;
   11852 		    goto evaluation_exit;
   11853 		}
   11854 		if (pos == maxPos) {
   11855 		    /*
   11856 		    * We are done.
   11857 		    */
   11858 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11859 		    goto evaluation_exit;
   11860 		}
   11861 	    } else {
   11862 		/*
   11863 		* Remove the entry from the initial node set.
   11864 		*/
   11865 		set->nodeTab[i] = NULL;
   11866 		if (contextNode->type == XML_NAMESPACE_DECL)
   11867 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11868 	    }
   11869 	    if (exprRes != NULL) {
   11870 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11871 		exprRes = NULL;
   11872 	    }
   11873 	    if (ctxt->value == contextObj) {
   11874 		/*
   11875 		* Don't free the temporary XPath object holding the
   11876 		* context node, in order to avoid massive recreation
   11877 		* inside this loop.
   11878 		*/
   11879 		valuePop(ctxt);
   11880 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11881 	    } else {
   11882 		/*
   11883 		* The object was lost in the evaluation machinery.
   11884 		* Can this happen? Maybe in case of internal-errors.
   11885 		*/
   11886 		contextObj = NULL;
   11887 	    }
   11888 	}
   11889 	goto evaluation_exit;
   11890 
   11891 evaluation_error:
   11892 	xmlXPathNodeSetClear(set, hasNsNodes);
   11893 	newContextSize = 0;
   11894 
   11895 evaluation_exit:
   11896 	if (contextObj != NULL) {
   11897 	    if (ctxt->value == contextObj)
   11898 		valuePop(ctxt);
   11899 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11900 	}
   11901 	if (exprRes != NULL)
   11902 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11903 	/*
   11904 	* Reset/invalidate the context.
   11905 	*/
   11906 	xpctxt->node = oldContextNode;
   11907 	xpctxt->doc = oldContextDoc;
   11908 	xpctxt->contextSize = -1;
   11909 	xpctxt->proximityPosition = -1;
   11910 	return(newContextSize);
   11911     }
   11912     return(contextSize);
   11913 }
   11914 
   11915 static int
   11916 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11917 			    xmlXPathStepOpPtr op,
   11918 			    int *maxPos)
   11919 {
   11920 
   11921     xmlXPathStepOpPtr exprOp;
   11922 
   11923     /*
   11924     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   11925     */
   11926 
   11927     /*
   11928     * If not -1, then ch1 will point to:
   11929     * 1) For predicates (XPATH_OP_PREDICATE):
   11930     *    - an inner predicate operator
   11931     * 2) For filters (XPATH_OP_FILTER):
   11932     *    - an inner filter operater OR
   11933     *    - an expression selecting the node set.
   11934     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   11935     */
   11936     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   11937 	return(0);
   11938 
   11939     if (op->ch2 != -1) {
   11940 	exprOp = &ctxt->comp->steps[op->ch2];
   11941     } else
   11942 	return(0);
   11943 
   11944     if ((exprOp != NULL) &&
   11945 	(exprOp->op == XPATH_OP_VALUE) &&
   11946 	(exprOp->value4 != NULL) &&
   11947 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   11948     {
   11949 	/*
   11950 	* We have a "[n]" predicate here.
   11951 	* TODO: Unfortunately this simplistic test here is not
   11952 	* able to detect a position() predicate in compound
   11953 	* expressions like "[@attr = 'a" and position() = 1],
   11954 	* and even not the usage of position() in
   11955 	* "[position() = 1]"; thus - obviously - a position-range,
   11956 	* like it "[position() < 5]", is also not detected.
   11957 	* Maybe we could rewrite the AST to ease the optimization.
   11958 	*/
   11959 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   11960 
   11961 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   11962 	    (float) *maxPos)
   11963 	{
   11964 	    return(1);
   11965 	}
   11966     }
   11967     return(0);
   11968 }
   11969 
   11970 static int
   11971 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   11972                            xmlXPathStepOpPtr op,
   11973 			   xmlNodePtr * first, xmlNodePtr * last,
   11974 			   int toBool)
   11975 {
   11976 
   11977 #define XP_TEST_HIT \
   11978     if (hasAxisRange != 0) { \
   11979 	if (++pos == maxPos) { \
   11980 	    addNode(seq, cur); \
   11981 	goto axis_range_end; } \
   11982     } else { \
   11983 	addNode(seq, cur); \
   11984 	if (breakOnFirstHit) goto first_hit; }
   11985 
   11986 #define XP_TEST_HIT_NS \
   11987     if (hasAxisRange != 0) { \
   11988 	if (++pos == maxPos) { \
   11989 	    hasNsNodes = 1; \
   11990 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
   11991 	goto axis_range_end; } \
   11992     } else { \
   11993 	hasNsNodes = 1; \
   11994 	xmlXPathNodeSetAddNs(seq, \
   11995 	xpctxt->node, (xmlNsPtr) cur); \
   11996 	if (breakOnFirstHit) goto first_hit; }
   11997 
   11998     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   11999     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12000     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12001     const xmlChar *prefix = op->value4;
   12002     const xmlChar *name = op->value5;
   12003     const xmlChar *URI = NULL;
   12004 
   12005 #ifdef DEBUG_STEP
   12006     int nbMatches = 0, prevMatches = 0;
   12007 #endif
   12008     int total = 0, hasNsNodes = 0;
   12009     /* The popped object holding the context nodes */
   12010     xmlXPathObjectPtr obj;
   12011     /* The set of context nodes for the node tests */
   12012     xmlNodeSetPtr contextSeq;
   12013     int contextIdx;
   12014     xmlNodePtr contextNode;
   12015     /* The context node for a compound traversal */
   12016     xmlNodePtr outerContextNode;
   12017     /* The final resulting node set wrt to all context nodes */
   12018     xmlNodeSetPtr outSeq;
   12019     /*
   12020     * The temporary resulting node set wrt 1 context node.
   12021     * Used to feed predicate evaluation.
   12022     */
   12023     xmlNodeSetPtr seq;
   12024     xmlNodePtr cur;
   12025     /* First predicate operator */
   12026     xmlXPathStepOpPtr predOp;
   12027     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12028     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12029     int breakOnFirstHit;
   12030 
   12031     xmlXPathTraversalFunction next = NULL;
   12032     /* compound axis traversal */
   12033     xmlXPathTraversalFunctionExt outerNext = NULL;
   12034     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12035     xmlXPathNodeSetMergeFunction mergeAndClear;
   12036     xmlNodePtr oldContextNode;
   12037     xmlXPathContextPtr xpctxt = ctxt->context;
   12038 
   12039 
   12040     CHECK_TYPE0(XPATH_NODESET);
   12041     obj = valuePop(ctxt);
   12042     /*
   12043     * Setup namespaces.
   12044     */
   12045     if (prefix != NULL) {
   12046         URI = xmlXPathNsLookup(xpctxt, prefix);
   12047         if (URI == NULL) {
   12048 	    xmlXPathReleaseObject(xpctxt, obj);
   12049             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12050 	}
   12051     }
   12052     /*
   12053     * Setup axis.
   12054     *
   12055     * MAYBE FUTURE TODO: merging optimizations:
   12056     * - If the nodes to be traversed wrt to the initial nodes and
   12057     *   the current axis cannot overlap, then we could avoid searching
   12058     *   for duplicates during the merge.
   12059     *   But the question is how/when to evaluate if they cannot overlap.
   12060     *   Example: if we know that for two initial nodes, the one is
   12061     *   not in the ancestor-or-self axis of the other, then we could safely
   12062     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12063     *   the descendant-or-self axis.
   12064     */
   12065     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12066     switch (axis) {
   12067         case AXIS_ANCESTOR:
   12068             first = NULL;
   12069             next = xmlXPathNextAncestor;
   12070             break;
   12071         case AXIS_ANCESTOR_OR_SELF:
   12072             first = NULL;
   12073             next = xmlXPathNextAncestorOrSelf;
   12074             break;
   12075         case AXIS_ATTRIBUTE:
   12076             first = NULL;
   12077 	    last = NULL;
   12078             next = xmlXPathNextAttribute;
   12079 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12080             break;
   12081         case AXIS_CHILD:
   12082 	    last = NULL;
   12083 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
   12084 		/*
   12085 		* This iterator will give us only nodes which can
   12086 		* hold element nodes.
   12087 		*/
   12088 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
   12089 	    }
   12090 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12091 		(type == NODE_TYPE_NODE))
   12092 	    {
   12093 		/*
   12094 		* Optimization if an element node type is 'element'.
   12095 		*/
   12096 		next = xmlXPathNextChildElement;
   12097 	    } else
   12098 		next = xmlXPathNextChild;
   12099 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12100             break;
   12101         case AXIS_DESCENDANT:
   12102 	    last = NULL;
   12103             next = xmlXPathNextDescendant;
   12104             break;
   12105         case AXIS_DESCENDANT_OR_SELF:
   12106 	    last = NULL;
   12107             next = xmlXPathNextDescendantOrSelf;
   12108             break;
   12109         case AXIS_FOLLOWING:
   12110 	    last = NULL;
   12111             next = xmlXPathNextFollowing;
   12112             break;
   12113         case AXIS_FOLLOWING_SIBLING:
   12114 	    last = NULL;
   12115             next = xmlXPathNextFollowingSibling;
   12116             break;
   12117         case AXIS_NAMESPACE:
   12118             first = NULL;
   12119 	    last = NULL;
   12120             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12121 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12122             break;
   12123         case AXIS_PARENT:
   12124             first = NULL;
   12125             next = xmlXPathNextParent;
   12126             break;
   12127         case AXIS_PRECEDING:
   12128             first = NULL;
   12129             next = xmlXPathNextPrecedingInternal;
   12130             break;
   12131         case AXIS_PRECEDING_SIBLING:
   12132             first = NULL;
   12133             next = xmlXPathNextPrecedingSibling;
   12134             break;
   12135         case AXIS_SELF:
   12136             first = NULL;
   12137 	    last = NULL;
   12138             next = xmlXPathNextSelf;
   12139 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12140             break;
   12141     }
   12142 
   12143 #ifdef DEBUG_STEP
   12144     xmlXPathDebugDumpStepAxis(op,
   12145 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12146 #endif
   12147 
   12148     if (next == NULL) {
   12149 	xmlXPathReleaseObject(xpctxt, obj);
   12150         return(0);
   12151     }
   12152     contextSeq = obj->nodesetval;
   12153     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12154 	xmlXPathReleaseObject(xpctxt, obj);
   12155         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12156         return(0);
   12157     }
   12158     /*
   12159     * Predicate optimization ---------------------------------------------
   12160     * If this step has a last predicate, which contains a position(),
   12161     * then we'll optimize (although not exactly "position()", but only
   12162     * the  short-hand form, i.e., "[n]".
   12163     *
   12164     * Example - expression "/foo[parent::bar][1]":
   12165     *
   12166     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12167     *   ROOT                               -- op->ch1
   12168     *   PREDICATE                          -- op->ch2 (predOp)
   12169     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12170     *       SORT
   12171     *         COLLECT  'parent' 'name' 'node' bar
   12172     *           NODE
   12173     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12174     *
   12175     */
   12176     maxPos = 0;
   12177     predOp = NULL;
   12178     hasPredicateRange = 0;
   12179     hasAxisRange = 0;
   12180     if (op->ch2 != -1) {
   12181 	/*
   12182 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12183 	*/
   12184 	predOp = &ctxt->comp->steps[op->ch2];
   12185 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12186 	    if (predOp->ch1 != -1) {
   12187 		/*
   12188 		* Use the next inner predicate operator.
   12189 		*/
   12190 		predOp = &ctxt->comp->steps[predOp->ch1];
   12191 		hasPredicateRange = 1;
   12192 	    } else {
   12193 		/*
   12194 		* There's no other predicate than the [n] predicate.
   12195 		*/
   12196 		predOp = NULL;
   12197 		hasAxisRange = 1;
   12198 	    }
   12199 	}
   12200     }
   12201     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12202     /*
   12203     * Axis traversal -----------------------------------------------------
   12204     */
   12205     /*
   12206      * 2.3 Node Tests
   12207      *  - For the attribute axis, the principal node type is attribute.
   12208      *  - For the namespace axis, the principal node type is namespace.
   12209      *  - For other axes, the principal node type is element.
   12210      *
   12211      * A node test * is true for any node of the
   12212      * principal node type. For example, child::* will
   12213      * select all element children of the context node
   12214      */
   12215     oldContextNode = xpctxt->node;
   12216     addNode = xmlXPathNodeSetAddUnique;
   12217     outSeq = NULL;
   12218     seq = NULL;
   12219     outerContextNode = NULL;
   12220     contextNode = NULL;
   12221     contextIdx = 0;
   12222 
   12223 
   12224     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
   12225 	if (outerNext != NULL) {
   12226 	    /*
   12227 	    * This is a compound traversal.
   12228 	    */
   12229 	    if (contextNode == NULL) {
   12230 		/*
   12231 		* Set the context for the outer traversal.
   12232 		*/
   12233 		outerContextNode = contextSeq->nodeTab[contextIdx++];
   12234 		contextNode = outerNext(NULL, outerContextNode);
   12235 	    } else
   12236 		contextNode = outerNext(contextNode, outerContextNode);
   12237 	    if (contextNode == NULL)
   12238 		continue;
   12239 	    /*
   12240 	    * Set the context for the main traversal.
   12241 	    */
   12242 	    xpctxt->node = contextNode;
   12243 	} else
   12244 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12245 
   12246 	if (seq == NULL) {
   12247 	    seq = xmlXPathNodeSetCreate(NULL);
   12248 	    if (seq == NULL) {
   12249 		total = 0;
   12250 		goto error;
   12251 	    }
   12252 	}
   12253 	/*
   12254 	* Traverse the axis and test the nodes.
   12255 	*/
   12256 	pos = 0;
   12257 	cur = NULL;
   12258 	hasNsNodes = 0;
   12259         do {
   12260             cur = next(ctxt, cur);
   12261             if (cur == NULL)
   12262                 break;
   12263 
   12264 	    /*
   12265 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12266 	    */
   12267             if ((first != NULL) && (*first != NULL)) {
   12268 		if (*first == cur)
   12269 		    break;
   12270 		if (((total % 256) == 0) &&
   12271 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12272 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12273 #else
   12274 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12275 #endif
   12276 		{
   12277 		    break;
   12278 		}
   12279 	    }
   12280 	    if ((last != NULL) && (*last != NULL)) {
   12281 		if (*last == cur)
   12282 		    break;
   12283 		if (((total % 256) == 0) &&
   12284 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12285 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12286 #else
   12287 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12288 #endif
   12289 		{
   12290 		    break;
   12291 		}
   12292 	    }
   12293 
   12294             total++;
   12295 
   12296 #ifdef DEBUG_STEP
   12297             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12298 #endif
   12299 
   12300 	    switch (test) {
   12301                 case NODE_TEST_NONE:
   12302 		    total = 0;
   12303                     STRANGE
   12304 		    goto error;
   12305                 case NODE_TEST_TYPE:
   12306 		    /*
   12307 		    * TODO: Don't we need to use
   12308 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12309 		    *  Surprisingly, some c14n tests fail, if we do this.
   12310 		    */
   12311 		    if (type == NODE_TYPE_NODE) {
   12312 			switch (cur->type) {
   12313 			    case XML_DOCUMENT_NODE:
   12314 			    case XML_HTML_DOCUMENT_NODE:
   12315 #ifdef LIBXML_DOCB_ENABLED
   12316 			    case XML_DOCB_DOCUMENT_NODE:
   12317 #endif
   12318 			    case XML_ELEMENT_NODE:
   12319 			    case XML_ATTRIBUTE_NODE:
   12320 			    case XML_PI_NODE:
   12321 			    case XML_COMMENT_NODE:
   12322 			    case XML_CDATA_SECTION_NODE:
   12323 			    case XML_TEXT_NODE:
   12324 			    case XML_NAMESPACE_DECL:
   12325 				XP_TEST_HIT
   12326 				break;
   12327 			    default:
   12328 				break;
   12329 			}
   12330 		    } else if (cur->type == type) {
   12331 			if (type == XML_NAMESPACE_DECL)
   12332 			    XP_TEST_HIT_NS
   12333 			else
   12334 			    XP_TEST_HIT
   12335 		    } else if ((type == NODE_TYPE_TEXT) &&
   12336 			 (cur->type == XML_CDATA_SECTION_NODE))
   12337 		    {
   12338 			XP_TEST_HIT
   12339 		    }
   12340 		    break;
   12341                 case NODE_TEST_PI:
   12342                     if ((cur->type == XML_PI_NODE) &&
   12343                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12344 		    {
   12345 			XP_TEST_HIT
   12346                     }
   12347                     break;
   12348                 case NODE_TEST_ALL:
   12349                     if (axis == AXIS_ATTRIBUTE) {
   12350                         if (cur->type == XML_ATTRIBUTE_NODE)
   12351 			{
   12352 			    XP_TEST_HIT
   12353                         }
   12354                     } else if (axis == AXIS_NAMESPACE) {
   12355                         if (cur->type == XML_NAMESPACE_DECL)
   12356 			{
   12357 			    XP_TEST_HIT_NS
   12358                         }
   12359                     } else {
   12360                         if (cur->type == XML_ELEMENT_NODE) {
   12361                             if (prefix == NULL)
   12362 			    {
   12363 				XP_TEST_HIT
   12364 
   12365                             } else if ((cur->ns != NULL) &&
   12366 				(xmlStrEqual(URI, cur->ns->href)))
   12367 			    {
   12368 				XP_TEST_HIT
   12369                             }
   12370                         }
   12371                     }
   12372                     break;
   12373                 case NODE_TEST_NS:{
   12374                         TODO;
   12375                         break;
   12376                     }
   12377                 case NODE_TEST_NAME:
   12378                     if (axis == AXIS_ATTRIBUTE) {
   12379                         if (cur->type != XML_ATTRIBUTE_NODE)
   12380 			    break;
   12381 		    } else if (axis == AXIS_NAMESPACE) {
   12382                         if (cur->type != XML_NAMESPACE_DECL)
   12383 			    break;
   12384 		    } else {
   12385 		        if (cur->type != XML_ELEMENT_NODE)
   12386 			    break;
   12387 		    }
   12388                     switch (cur->type) {
   12389                         case XML_ELEMENT_NODE:
   12390                             if (xmlStrEqual(name, cur->name)) {
   12391                                 if (prefix == NULL) {
   12392                                     if (cur->ns == NULL)
   12393 				    {
   12394 					XP_TEST_HIT
   12395                                     }
   12396                                 } else {
   12397                                     if ((cur->ns != NULL) &&
   12398                                         (xmlStrEqual(URI, cur->ns->href)))
   12399 				    {
   12400 					XP_TEST_HIT
   12401                                     }
   12402                                 }
   12403                             }
   12404                             break;
   12405                         case XML_ATTRIBUTE_NODE:{
   12406                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12407 
   12408                                 if (xmlStrEqual(name, attr->name)) {
   12409                                     if (prefix == NULL) {
   12410                                         if ((attr->ns == NULL) ||
   12411                                             (attr->ns->prefix == NULL))
   12412 					{
   12413 					    XP_TEST_HIT
   12414                                         }
   12415                                     } else {
   12416                                         if ((attr->ns != NULL) &&
   12417                                             (xmlStrEqual(URI,
   12418 					      attr->ns->href)))
   12419 					{
   12420 					    XP_TEST_HIT
   12421                                         }
   12422                                     }
   12423                                 }
   12424                                 break;
   12425                             }
   12426                         case XML_NAMESPACE_DECL:
   12427                             if (cur->type == XML_NAMESPACE_DECL) {
   12428                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12429 
   12430                                 if ((ns->prefix != NULL) && (name != NULL)
   12431                                     && (xmlStrEqual(ns->prefix, name)))
   12432 				{
   12433 				    XP_TEST_HIT_NS
   12434                                 }
   12435                             }
   12436                             break;
   12437                         default:
   12438                             break;
   12439                     }
   12440                     break;
   12441 	    } /* switch(test) */
   12442         } while (cur != NULL);
   12443 
   12444 	goto apply_predicates;
   12445 
   12446 axis_range_end: /* ----------------------------------------------------- */
   12447 	/*
   12448 	* We have a "/foo[n]", and position() = n was reached.
   12449 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12450 	* a duplicate-aware merge is still needed.
   12451 	* Merge with the result.
   12452 	*/
   12453 	if (outSeq == NULL) {
   12454 	    outSeq = seq;
   12455 	    seq = NULL;
   12456 	} else
   12457 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12458 	/*
   12459 	* Break if only a true/false result was requested.
   12460 	*/
   12461 	if (toBool)
   12462 	    break;
   12463 	continue;
   12464 
   12465 first_hit: /* ---------------------------------------------------------- */
   12466 	/*
   12467 	* Break if only a true/false result was requested and
   12468 	* no predicates existed and a node test succeeded.
   12469 	*/
   12470 	if (outSeq == NULL) {
   12471 	    outSeq = seq;
   12472 	    seq = NULL;
   12473 	} else
   12474 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12475 	break;
   12476 
   12477 #ifdef DEBUG_STEP
   12478 	if (seq != NULL)
   12479 	    nbMatches += seq->nodeNr;
   12480 #endif
   12481 
   12482 apply_predicates: /* --------------------------------------------------- */
   12483         /*
   12484 	* Apply predicates.
   12485 	*/
   12486         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12487 	    /*
   12488 	    * E.g. when we have a "/foo[some expression][n]".
   12489 	    */
   12490 	    /*
   12491 	    * QUESTION TODO: The old predicate evaluation took into
   12492 	    *  account location-sets.
   12493 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12494 	    *  Do we expect such a set here?
   12495 	    *  All what I learned now from the evaluation semantics
   12496 	    *  does not indicate that a location-set will be processed
   12497 	    *  here, so this looks OK.
   12498 	    */
   12499 	    /*
   12500 	    * Iterate over all predicates, starting with the outermost
   12501 	    * predicate.
   12502 	    * TODO: Problem: we cannot execute the inner predicates first
   12503 	    *  since we cannot go back *up* the operator tree!
   12504 	    *  Options we have:
   12505 	    *  1) Use of recursive functions (like is it currently done
   12506 	    *     via xmlXPathCompOpEval())
   12507 	    *  2) Add a predicate evaluation information stack to the
   12508 	    *     context struct
   12509 	    *  3) Change the way the operators are linked; we need a
   12510 	    *     "parent" field on xmlXPathStepOp
   12511 	    *
   12512 	    * For the moment, I'll try to solve this with a recursive
   12513 	    * function: xmlXPathCompOpEvalPredicate().
   12514 	    */
   12515 	    size = seq->nodeNr;
   12516 	    if (hasPredicateRange != 0)
   12517 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12518 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12519 	    else
   12520 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12521 		    predOp, seq, size, hasNsNodes);
   12522 
   12523 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12524 		total = 0;
   12525 		goto error;
   12526 	    }
   12527 	    /*
   12528 	    * Add the filtered set of nodes to the result node set.
   12529 	    */
   12530 	    if (newSize == 0) {
   12531 		/*
   12532 		* The predicates filtered all nodes out.
   12533 		*/
   12534 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12535 	    } else if (seq->nodeNr > 0) {
   12536 		/*
   12537 		* Add to result set.
   12538 		*/
   12539 		if (outSeq == NULL) {
   12540 		    if (size != newSize) {
   12541 			/*
   12542 			* We need to merge and clear here, since
   12543 			* the sequence will contained NULLed entries.
   12544 			*/
   12545 			outSeq = mergeAndClear(NULL, seq, 1);
   12546 		    } else {
   12547 			outSeq = seq;
   12548 			seq = NULL;
   12549 		    }
   12550 		} else
   12551 		    outSeq = mergeAndClear(outSeq, seq,
   12552 			(size != newSize) ? 1: 0);
   12553 		/*
   12554 		* Break if only a true/false result was requested.
   12555 		*/
   12556 		if (toBool)
   12557 		    break;
   12558 	    }
   12559         } else if (seq->nodeNr > 0) {
   12560 	    /*
   12561 	    * Add to result set.
   12562 	    */
   12563 	    if (outSeq == NULL) {
   12564 		outSeq = seq;
   12565 		seq = NULL;
   12566 	    } else {
   12567 		outSeq = mergeAndClear(outSeq, seq, 0);
   12568 	    }
   12569 	}
   12570     }
   12571 
   12572 error:
   12573     if ((obj->boolval) && (obj->user != NULL)) {
   12574 	/*
   12575 	* QUESTION TODO: What does this do and why?
   12576 	* TODO: Do we have to do this also for the "error"
   12577 	* cleanup further down?
   12578 	*/
   12579 	ctxt->value->boolval = 1;
   12580 	ctxt->value->user = obj->user;
   12581 	obj->user = NULL;
   12582 	obj->boolval = 0;
   12583     }
   12584     xmlXPathReleaseObject(xpctxt, obj);
   12585 
   12586     /*
   12587     * Ensure we return at least an emtpy set.
   12588     */
   12589     if (outSeq == NULL) {
   12590 	if ((seq != NULL) && (seq->nodeNr == 0))
   12591 	    outSeq = seq;
   12592 	else
   12593 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12594         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12595     }
   12596     if ((seq != NULL) && (seq != outSeq)) {
   12597 	 xmlXPathFreeNodeSet(seq);
   12598     }
   12599     /*
   12600     * Hand over the result. Better to push the set also in
   12601     * case of errors.
   12602     */
   12603     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12604     /*
   12605     * Reset the context node.
   12606     */
   12607     xpctxt->node = oldContextNode;
   12608 
   12609 #ifdef DEBUG_STEP
   12610     xmlGenericError(xmlGenericErrorContext,
   12611 	"\nExamined %d nodes, found %d nodes at that step\n",
   12612 	total, nbMatches);
   12613 #endif
   12614 
   12615     return(total);
   12616 }
   12617 
   12618 static int
   12619 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12620 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12621 
   12622 /**
   12623  * xmlXPathCompOpEvalFirst:
   12624  * @ctxt:  the XPath parser context with the compiled expression
   12625  * @op:  an XPath compiled operation
   12626  * @first:  the first elem found so far
   12627  *
   12628  * Evaluate the Precompiled XPath operation searching only the first
   12629  * element in document order
   12630  *
   12631  * Returns the number of examined objects.
   12632  */
   12633 static int
   12634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12635                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12636 {
   12637     int total = 0, cur;
   12638     xmlXPathCompExprPtr comp;
   12639     xmlXPathObjectPtr arg1, arg2;
   12640 
   12641     CHECK_ERROR0;
   12642     comp = ctxt->comp;
   12643     switch (op->op) {
   12644         case XPATH_OP_END:
   12645             return (0);
   12646         case XPATH_OP_UNION:
   12647             total =
   12648                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12649                                         first);
   12650 	    CHECK_ERROR0;
   12651             if ((ctxt->value != NULL)
   12652                 && (ctxt->value->type == XPATH_NODESET)
   12653                 && (ctxt->value->nodesetval != NULL)
   12654                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12655                 /*
   12656                  * limit tree traversing to first node in the result
   12657                  */
   12658 		/*
   12659 		* OPTIMIZE TODO: This implicitely sorts
   12660 		*  the result, even if not needed. E.g. if the argument
   12661 		*  of the count() function, no sorting is needed.
   12662 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12663 		*  aready sorted?
   12664 		*/
   12665 		if (ctxt->value->nodesetval->nodeNr > 1)
   12666 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12667                 *first = ctxt->value->nodesetval->nodeTab[0];
   12668             }
   12669             cur =
   12670                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12671                                         first);
   12672 	    CHECK_ERROR0;
   12673             CHECK_TYPE0(XPATH_NODESET);
   12674             arg2 = valuePop(ctxt);
   12675 
   12676             CHECK_TYPE0(XPATH_NODESET);
   12677             arg1 = valuePop(ctxt);
   12678 
   12679             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12680                                                     arg2->nodesetval);
   12681             valuePush(ctxt, arg1);
   12682 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12683             /* optimizer */
   12684 	    if (total > cur)
   12685 		xmlXPathCompSwap(op);
   12686             return (total + cur);
   12687         case XPATH_OP_ROOT:
   12688             xmlXPathRoot(ctxt);
   12689             return (0);
   12690         case XPATH_OP_NODE:
   12691             if (op->ch1 != -1)
   12692                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12693 	    CHECK_ERROR0;
   12694             if (op->ch2 != -1)
   12695                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12696 	    CHECK_ERROR0;
   12697 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12698 		ctxt->context->node));
   12699             return (total);
   12700         case XPATH_OP_RESET:
   12701             if (op->ch1 != -1)
   12702                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12703 	    CHECK_ERROR0;
   12704             if (op->ch2 != -1)
   12705                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12706 	    CHECK_ERROR0;
   12707             ctxt->context->node = NULL;
   12708             return (total);
   12709         case XPATH_OP_COLLECT:{
   12710                 if (op->ch1 == -1)
   12711                     return (total);
   12712 
   12713                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12714 		CHECK_ERROR0;
   12715 
   12716                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12717                 return (total);
   12718             }
   12719         case XPATH_OP_VALUE:
   12720             valuePush(ctxt,
   12721                       xmlXPathCacheObjectCopy(ctxt->context,
   12722 			(xmlXPathObjectPtr) op->value4));
   12723             return (0);
   12724         case XPATH_OP_SORT:
   12725             if (op->ch1 != -1)
   12726                 total +=
   12727                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12728                                             first);
   12729 	    CHECK_ERROR0;
   12730             if ((ctxt->value != NULL)
   12731                 && (ctxt->value->type == XPATH_NODESET)
   12732                 && (ctxt->value->nodesetval != NULL)
   12733 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12734                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12735             return (total);
   12736 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12737 	case XPATH_OP_FILTER:
   12738                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12739             return (total);
   12740 #endif
   12741         default:
   12742             return (xmlXPathCompOpEval(ctxt, op));
   12743     }
   12744 }
   12745 
   12746 /**
   12747  * xmlXPathCompOpEvalLast:
   12748  * @ctxt:  the XPath parser context with the compiled expression
   12749  * @op:  an XPath compiled operation
   12750  * @last:  the last elem found so far
   12751  *
   12752  * Evaluate the Precompiled XPath operation searching only the last
   12753  * element in document order
   12754  *
   12755  * Returns the number of nodes traversed
   12756  */
   12757 static int
   12758 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12759                        xmlNodePtr * last)
   12760 {
   12761     int total = 0, cur;
   12762     xmlXPathCompExprPtr comp;
   12763     xmlXPathObjectPtr arg1, arg2;
   12764     xmlNodePtr bak;
   12765     xmlDocPtr bakd;
   12766     int pp;
   12767     int cs;
   12768 
   12769     CHECK_ERROR0;
   12770     comp = ctxt->comp;
   12771     switch (op->op) {
   12772         case XPATH_OP_END:
   12773             return (0);
   12774         case XPATH_OP_UNION:
   12775 	    bakd = ctxt->context->doc;
   12776 	    bak = ctxt->context->node;
   12777 	    pp = ctxt->context->proximityPosition;
   12778 	    cs = ctxt->context->contextSize;
   12779             total =
   12780                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12781 	    CHECK_ERROR0;
   12782             if ((ctxt->value != NULL)
   12783                 && (ctxt->value->type == XPATH_NODESET)
   12784                 && (ctxt->value->nodesetval != NULL)
   12785                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12786                 /*
   12787                  * limit tree traversing to first node in the result
   12788                  */
   12789 		if (ctxt->value->nodesetval->nodeNr > 1)
   12790 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12791                 *last =
   12792                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12793                                                      nodesetval->nodeNr -
   12794                                                      1];
   12795             }
   12796 	    ctxt->context->doc = bakd;
   12797 	    ctxt->context->node = bak;
   12798 	    ctxt->context->proximityPosition = pp;
   12799 	    ctxt->context->contextSize = cs;
   12800             cur =
   12801                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12802 	    CHECK_ERROR0;
   12803             if ((ctxt->value != NULL)
   12804                 && (ctxt->value->type == XPATH_NODESET)
   12805                 && (ctxt->value->nodesetval != NULL)
   12806                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12807             }
   12808             CHECK_TYPE0(XPATH_NODESET);
   12809             arg2 = valuePop(ctxt);
   12810 
   12811             CHECK_TYPE0(XPATH_NODESET);
   12812             arg1 = valuePop(ctxt);
   12813 
   12814             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12815                                                     arg2->nodesetval);
   12816             valuePush(ctxt, arg1);
   12817 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12818             /* optimizer */
   12819 	    if (total > cur)
   12820 		xmlXPathCompSwap(op);
   12821             return (total + cur);
   12822         case XPATH_OP_ROOT:
   12823             xmlXPathRoot(ctxt);
   12824             return (0);
   12825         case XPATH_OP_NODE:
   12826             if (op->ch1 != -1)
   12827                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12828 	    CHECK_ERROR0;
   12829             if (op->ch2 != -1)
   12830                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12831 	    CHECK_ERROR0;
   12832 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12833 		ctxt->context->node));
   12834             return (total);
   12835         case XPATH_OP_RESET:
   12836             if (op->ch1 != -1)
   12837                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12838 	    CHECK_ERROR0;
   12839             if (op->ch2 != -1)
   12840                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12841 	    CHECK_ERROR0;
   12842             ctxt->context->node = NULL;
   12843             return (total);
   12844         case XPATH_OP_COLLECT:{
   12845                 if (op->ch1 == -1)
   12846                     return (0);
   12847 
   12848                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12849 		CHECK_ERROR0;
   12850 
   12851                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12852                 return (total);
   12853             }
   12854         case XPATH_OP_VALUE:
   12855             valuePush(ctxt,
   12856                       xmlXPathCacheObjectCopy(ctxt->context,
   12857 			(xmlXPathObjectPtr) op->value4));
   12858             return (0);
   12859         case XPATH_OP_SORT:
   12860             if (op->ch1 != -1)
   12861                 total +=
   12862                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12863                                            last);
   12864 	    CHECK_ERROR0;
   12865             if ((ctxt->value != NULL)
   12866                 && (ctxt->value->type == XPATH_NODESET)
   12867                 && (ctxt->value->nodesetval != NULL)
   12868 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12869                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12870             return (total);
   12871         default:
   12872             return (xmlXPathCompOpEval(ctxt, op));
   12873     }
   12874 }
   12875 
   12876 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12877 static int
   12878 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12879 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12880 {
   12881     int total = 0;
   12882     xmlXPathCompExprPtr comp;
   12883     xmlXPathObjectPtr res;
   12884     xmlXPathObjectPtr obj;
   12885     xmlNodeSetPtr oldset;
   12886     xmlNodePtr oldnode;
   12887     xmlDocPtr oldDoc;
   12888     int i;
   12889 
   12890     CHECK_ERROR0;
   12891     comp = ctxt->comp;
   12892     /*
   12893     * Optimization for ()[last()] selection i.e. the last elem
   12894     */
   12895     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12896 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12897 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12898 	int f = comp->steps[op->ch2].ch1;
   12899 
   12900 	if ((f != -1) &&
   12901 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12902 	    (comp->steps[f].value5 == NULL) &&
   12903 	    (comp->steps[f].value == 0) &&
   12904 	    (comp->steps[f].value4 != NULL) &&
   12905 	    (xmlStrEqual
   12906 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12907 	    xmlNodePtr last = NULL;
   12908 
   12909 	    total +=
   12910 		xmlXPathCompOpEvalLast(ctxt,
   12911 		    &comp->steps[op->ch1],
   12912 		    &last);
   12913 	    CHECK_ERROR0;
   12914 	    /*
   12915 	    * The nodeset should be in document order,
   12916 	    * Keep only the last value
   12917 	    */
   12918 	    if ((ctxt->value != NULL) &&
   12919 		(ctxt->value->type == XPATH_NODESET) &&
   12920 		(ctxt->value->nodesetval != NULL) &&
   12921 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12922 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12923 		ctxt->value->nodesetval->nodeTab[0] =
   12924 		    ctxt->value->nodesetval->nodeTab[ctxt->
   12925 		    value->
   12926 		    nodesetval->
   12927 		    nodeNr -
   12928 		    1];
   12929 		ctxt->value->nodesetval->nodeNr = 1;
   12930 		*first = *(ctxt->value->nodesetval->nodeTab);
   12931 	    }
   12932 	    return (total);
   12933 	}
   12934     }
   12935 
   12936     if (op->ch1 != -1)
   12937 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12938     CHECK_ERROR0;
   12939     if (op->ch2 == -1)
   12940 	return (total);
   12941     if (ctxt->value == NULL)
   12942 	return (total);
   12943 
   12944 #ifdef LIBXML_XPTR_ENABLED
   12945     oldnode = ctxt->context->node;
   12946     /*
   12947     * Hum are we filtering the result of an XPointer expression
   12948     */
   12949     if (ctxt->value->type == XPATH_LOCATIONSET) {
   12950 	xmlXPathObjectPtr tmp = NULL;
   12951 	xmlLocationSetPtr newlocset = NULL;
   12952 	xmlLocationSetPtr oldlocset;
   12953 
   12954 	/*
   12955 	* Extract the old locset, and then evaluate the result of the
   12956 	* expression for all the element in the locset. use it to grow
   12957 	* up a new locset.
   12958 	*/
   12959 	CHECK_TYPE0(XPATH_LOCATIONSET);
   12960 	obj = valuePop(ctxt);
   12961 	oldlocset = obj->user;
   12962 	ctxt->context->node = NULL;
   12963 
   12964 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   12965 	    ctxt->context->contextSize = 0;
   12966 	    ctxt->context->proximityPosition = 0;
   12967 	    if (op->ch2 != -1)
   12968 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12969 	    res = valuePop(ctxt);
   12970 	    if (res != NULL) {
   12971 		xmlXPathReleaseObject(ctxt->context, res);
   12972 	    }
   12973 	    valuePush(ctxt, obj);
   12974 	    CHECK_ERROR0;
   12975 	    return (total);
   12976 	}
   12977 	newlocset = xmlXPtrLocationSetCreate(NULL);
   12978 
   12979 	for (i = 0; i < oldlocset->locNr; i++) {
   12980 	    /*
   12981 	    * Run the evaluation with a node list made of a
   12982 	    * single item in the nodelocset.
   12983 	    */
   12984 	    ctxt->context->node = oldlocset->locTab[i]->user;
   12985 	    ctxt->context->contextSize = oldlocset->locNr;
   12986 	    ctxt->context->proximityPosition = i + 1;
   12987 	    if (tmp == NULL) {
   12988 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   12989 		    ctxt->context->node);
   12990 	    } else {
   12991 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   12992 		    ctxt->context->node);
   12993 	    }
   12994 	    valuePush(ctxt, tmp);
   12995 	    if (op->ch2 != -1)
   12996 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12997 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12998 		xmlXPathFreeObject(obj);
   12999 		return(0);
   13000 	    }
   13001 	    /*
   13002 	    * The result of the evaluation need to be tested to
   13003 	    * decided whether the filter succeeded or not
   13004 	    */
   13005 	    res = valuePop(ctxt);
   13006 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13007 		xmlXPtrLocationSetAdd(newlocset,
   13008 		    xmlXPathCacheObjectCopy(ctxt->context,
   13009 			oldlocset->locTab[i]));
   13010 	    }
   13011 	    /*
   13012 	    * Cleanup
   13013 	    */
   13014 	    if (res != NULL) {
   13015 		xmlXPathReleaseObject(ctxt->context, res);
   13016 	    }
   13017 	    if (ctxt->value == tmp) {
   13018 		valuePop(ctxt);
   13019 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13020 		/*
   13021 		* REVISIT TODO: Don't create a temporary nodeset
   13022 		* for everly iteration.
   13023 		*/
   13024 		/* OLD: xmlXPathFreeObject(res); */
   13025 	    } else
   13026 		tmp = NULL;
   13027 	    ctxt->context->node = NULL;
   13028 	    /*
   13029 	    * Only put the first node in the result, then leave.
   13030 	    */
   13031 	    if (newlocset->locNr > 0) {
   13032 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13033 		break;
   13034 	    }
   13035 	}
   13036 	if (tmp != NULL) {
   13037 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13038 	}
   13039 	/*
   13040 	* The result is used as the new evaluation locset.
   13041 	*/
   13042 	xmlXPathReleaseObject(ctxt->context, obj);
   13043 	ctxt->context->node = NULL;
   13044 	ctxt->context->contextSize = -1;
   13045 	ctxt->context->proximityPosition = -1;
   13046 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13047 	ctxt->context->node = oldnode;
   13048 	return (total);
   13049     }
   13050 #endif /* LIBXML_XPTR_ENABLED */
   13051 
   13052     /*
   13053     * Extract the old set, and then evaluate the result of the
   13054     * expression for all the element in the set. use it to grow
   13055     * up a new set.
   13056     */
   13057     CHECK_TYPE0(XPATH_NODESET);
   13058     obj = valuePop(ctxt);
   13059     oldset = obj->nodesetval;
   13060 
   13061     oldnode = ctxt->context->node;
   13062     oldDoc = ctxt->context->doc;
   13063     ctxt->context->node = NULL;
   13064 
   13065     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13066 	ctxt->context->contextSize = 0;
   13067 	ctxt->context->proximityPosition = 0;
   13068 	/* QUESTION TODO: Why was this code commented out?
   13069 	    if (op->ch2 != -1)
   13070 		total +=
   13071 		    xmlXPathCompOpEval(ctxt,
   13072 			&comp->steps[op->ch2]);
   13073 	    CHECK_ERROR0;
   13074 	    res = valuePop(ctxt);
   13075 	    if (res != NULL)
   13076 		xmlXPathFreeObject(res);
   13077 	*/
   13078 	valuePush(ctxt, obj);
   13079 	ctxt->context->node = oldnode;
   13080 	CHECK_ERROR0;
   13081     } else {
   13082 	xmlNodeSetPtr newset;
   13083 	xmlXPathObjectPtr tmp = NULL;
   13084 	/*
   13085 	* Initialize the new set.
   13086 	* Also set the xpath document in case things like
   13087 	* key() evaluation are attempted on the predicate
   13088 	*/
   13089 	newset = xmlXPathNodeSetCreate(NULL);
   13090         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13091 
   13092 	for (i = 0; i < oldset->nodeNr; i++) {
   13093 	    /*
   13094 	    * Run the evaluation with a node list made of
   13095 	    * a single item in the nodeset.
   13096 	    */
   13097 	    ctxt->context->node = oldset->nodeTab[i];
   13098 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13099 		(oldset->nodeTab[i]->doc != NULL))
   13100 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13101 	    if (tmp == NULL) {
   13102 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13103 		    ctxt->context->node);
   13104 	    } else {
   13105 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13106 		    ctxt->context->node);
   13107 	    }
   13108 	    valuePush(ctxt, tmp);
   13109 	    ctxt->context->contextSize = oldset->nodeNr;
   13110 	    ctxt->context->proximityPosition = i + 1;
   13111 	    if (op->ch2 != -1)
   13112 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13113 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13114 		xmlXPathFreeNodeSet(newset);
   13115 		xmlXPathFreeObject(obj);
   13116 		return(0);
   13117 	    }
   13118 	    /*
   13119 	    * The result of the evaluation needs to be tested to
   13120 	    * decide whether the filter succeeded or not
   13121 	    */
   13122 	    res = valuePop(ctxt);
   13123 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13124 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13125 	    }
   13126 	    /*
   13127 	    * Cleanup
   13128 	    */
   13129 	    if (res != NULL) {
   13130 		xmlXPathReleaseObject(ctxt->context, res);
   13131 	    }
   13132 	    if (ctxt->value == tmp) {
   13133 		valuePop(ctxt);
   13134 		/*
   13135 		* Don't free the temporary nodeset
   13136 		* in order to avoid massive recreation inside this
   13137 		* loop.
   13138 		*/
   13139 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13140 	    } else
   13141 		tmp = NULL;
   13142 	    ctxt->context->node = NULL;
   13143 	    /*
   13144 	    * Only put the first node in the result, then leave.
   13145 	    */
   13146 	    if (newset->nodeNr > 0) {
   13147 		*first = *(newset->nodeTab);
   13148 		break;
   13149 	    }
   13150 	}
   13151 	if (tmp != NULL) {
   13152 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13153 	}
   13154 	/*
   13155 	* The result is used as the new evaluation set.
   13156 	*/
   13157 	xmlXPathReleaseObject(ctxt->context, obj);
   13158 	ctxt->context->node = NULL;
   13159 	ctxt->context->contextSize = -1;
   13160 	ctxt->context->proximityPosition = -1;
   13161 	/* may want to move this past the '}' later */
   13162 	ctxt->context->doc = oldDoc;
   13163 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13164     }
   13165     ctxt->context->node = oldnode;
   13166     return(total);
   13167 }
   13168 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13169 
   13170 /**
   13171  * xmlXPathCompOpEval:
   13172  * @ctxt:  the XPath parser context with the compiled expression
   13173  * @op:  an XPath compiled operation
   13174  *
   13175  * Evaluate the Precompiled XPath operation
   13176  * Returns the number of nodes traversed
   13177  */
   13178 static int
   13179 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13180 {
   13181     int total = 0;
   13182     int equal, ret;
   13183     xmlXPathCompExprPtr comp;
   13184     xmlXPathObjectPtr arg1, arg2;
   13185     xmlNodePtr bak;
   13186     xmlDocPtr bakd;
   13187     int pp;
   13188     int cs;
   13189 
   13190     CHECK_ERROR0;
   13191     comp = ctxt->comp;
   13192     switch (op->op) {
   13193         case XPATH_OP_END:
   13194             return (0);
   13195         case XPATH_OP_AND:
   13196 	    bakd = ctxt->context->doc;
   13197 	    bak = ctxt->context->node;
   13198 	    pp = ctxt->context->proximityPosition;
   13199 	    cs = ctxt->context->contextSize;
   13200             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13201 	    CHECK_ERROR0;
   13202             xmlXPathBooleanFunction(ctxt, 1);
   13203             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13204                 return (total);
   13205             arg2 = valuePop(ctxt);
   13206 	    ctxt->context->doc = bakd;
   13207 	    ctxt->context->node = bak;
   13208 	    ctxt->context->proximityPosition = pp;
   13209 	    ctxt->context->contextSize = cs;
   13210             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13211 	    if (ctxt->error) {
   13212 		xmlXPathFreeObject(arg2);
   13213 		return(0);
   13214 	    }
   13215             xmlXPathBooleanFunction(ctxt, 1);
   13216             arg1 = valuePop(ctxt);
   13217             arg1->boolval &= arg2->boolval;
   13218             valuePush(ctxt, arg1);
   13219 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13220             return (total);
   13221         case XPATH_OP_OR:
   13222 	    bakd = ctxt->context->doc;
   13223 	    bak = ctxt->context->node;
   13224 	    pp = ctxt->context->proximityPosition;
   13225 	    cs = ctxt->context->contextSize;
   13226             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13227 	    CHECK_ERROR0;
   13228             xmlXPathBooleanFunction(ctxt, 1);
   13229             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13230                 return (total);
   13231             arg2 = valuePop(ctxt);
   13232 	    ctxt->context->doc = bakd;
   13233 	    ctxt->context->node = bak;
   13234 	    ctxt->context->proximityPosition = pp;
   13235 	    ctxt->context->contextSize = cs;
   13236             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13237 	    if (ctxt->error) {
   13238 		xmlXPathFreeObject(arg2);
   13239 		return(0);
   13240 	    }
   13241             xmlXPathBooleanFunction(ctxt, 1);
   13242             arg1 = valuePop(ctxt);
   13243             arg1->boolval |= arg2->boolval;
   13244             valuePush(ctxt, arg1);
   13245 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13246             return (total);
   13247         case XPATH_OP_EQUAL:
   13248 	    bakd = ctxt->context->doc;
   13249 	    bak = ctxt->context->node;
   13250 	    pp = ctxt->context->proximityPosition;
   13251 	    cs = ctxt->context->contextSize;
   13252             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13253 	    CHECK_ERROR0;
   13254 	    ctxt->context->doc = bakd;
   13255 	    ctxt->context->node = bak;
   13256 	    ctxt->context->proximityPosition = pp;
   13257 	    ctxt->context->contextSize = cs;
   13258             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13259 	    CHECK_ERROR0;
   13260 	    if (op->value)
   13261 		equal = xmlXPathEqualValues(ctxt);
   13262 	    else
   13263 		equal = xmlXPathNotEqualValues(ctxt);
   13264 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13265             return (total);
   13266         case XPATH_OP_CMP:
   13267 	    bakd = ctxt->context->doc;
   13268 	    bak = ctxt->context->node;
   13269 	    pp = ctxt->context->proximityPosition;
   13270 	    cs = ctxt->context->contextSize;
   13271             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13272 	    CHECK_ERROR0;
   13273 	    ctxt->context->doc = bakd;
   13274 	    ctxt->context->node = bak;
   13275 	    ctxt->context->proximityPosition = pp;
   13276 	    ctxt->context->contextSize = cs;
   13277             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13278 	    CHECK_ERROR0;
   13279             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13280 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13281             return (total);
   13282         case XPATH_OP_PLUS:
   13283 	    bakd = ctxt->context->doc;
   13284 	    bak = ctxt->context->node;
   13285 	    pp = ctxt->context->proximityPosition;
   13286 	    cs = ctxt->context->contextSize;
   13287             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13288 	    CHECK_ERROR0;
   13289             if (op->ch2 != -1) {
   13290 		ctxt->context->doc = bakd;
   13291 		ctxt->context->node = bak;
   13292 		ctxt->context->proximityPosition = pp;
   13293 		ctxt->context->contextSize = cs;
   13294                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13295 	    }
   13296 	    CHECK_ERROR0;
   13297             if (op->value == 0)
   13298                 xmlXPathSubValues(ctxt);
   13299             else if (op->value == 1)
   13300                 xmlXPathAddValues(ctxt);
   13301             else if (op->value == 2)
   13302                 xmlXPathValueFlipSign(ctxt);
   13303             else if (op->value == 3) {
   13304                 CAST_TO_NUMBER;
   13305                 CHECK_TYPE0(XPATH_NUMBER);
   13306             }
   13307             return (total);
   13308         case XPATH_OP_MULT:
   13309 	    bakd = ctxt->context->doc;
   13310 	    bak = ctxt->context->node;
   13311 	    pp = ctxt->context->proximityPosition;
   13312 	    cs = ctxt->context->contextSize;
   13313             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13314 	    CHECK_ERROR0;
   13315 	    ctxt->context->doc = bakd;
   13316 	    ctxt->context->node = bak;
   13317 	    ctxt->context->proximityPosition = pp;
   13318 	    ctxt->context->contextSize = cs;
   13319             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13320 	    CHECK_ERROR0;
   13321             if (op->value == 0)
   13322                 xmlXPathMultValues(ctxt);
   13323             else if (op->value == 1)
   13324                 xmlXPathDivValues(ctxt);
   13325             else if (op->value == 2)
   13326                 xmlXPathModValues(ctxt);
   13327             return (total);
   13328         case XPATH_OP_UNION:
   13329 	    bakd = ctxt->context->doc;
   13330 	    bak = ctxt->context->node;
   13331 	    pp = ctxt->context->proximityPosition;
   13332 	    cs = ctxt->context->contextSize;
   13333             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13334 	    CHECK_ERROR0;
   13335 	    ctxt->context->doc = bakd;
   13336 	    ctxt->context->node = bak;
   13337 	    ctxt->context->proximityPosition = pp;
   13338 	    ctxt->context->contextSize = cs;
   13339             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13340 	    CHECK_ERROR0;
   13341             CHECK_TYPE0(XPATH_NODESET);
   13342             arg2 = valuePop(ctxt);
   13343 
   13344             CHECK_TYPE0(XPATH_NODESET);
   13345             arg1 = valuePop(ctxt);
   13346 
   13347 	    if ((arg1->nodesetval == NULL) ||
   13348 		((arg2->nodesetval != NULL) &&
   13349 		 (arg2->nodesetval->nodeNr != 0)))
   13350 	    {
   13351 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13352 							arg2->nodesetval);
   13353 	    }
   13354 
   13355             valuePush(ctxt, arg1);
   13356 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13357             return (total);
   13358         case XPATH_OP_ROOT:
   13359             xmlXPathRoot(ctxt);
   13360             return (total);
   13361         case XPATH_OP_NODE:
   13362             if (op->ch1 != -1)
   13363                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13364 	    CHECK_ERROR0;
   13365             if (op->ch2 != -1)
   13366                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13367 	    CHECK_ERROR0;
   13368 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13369 		ctxt->context->node));
   13370             return (total);
   13371         case XPATH_OP_RESET:
   13372             if (op->ch1 != -1)
   13373                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13374 	    CHECK_ERROR0;
   13375             if (op->ch2 != -1)
   13376                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13377 	    CHECK_ERROR0;
   13378             ctxt->context->node = NULL;
   13379             return (total);
   13380         case XPATH_OP_COLLECT:{
   13381                 if (op->ch1 == -1)
   13382                     return (total);
   13383 
   13384                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13385 		CHECK_ERROR0;
   13386 
   13387                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13388                 return (total);
   13389             }
   13390         case XPATH_OP_VALUE:
   13391             valuePush(ctxt,
   13392                       xmlXPathCacheObjectCopy(ctxt->context,
   13393 			(xmlXPathObjectPtr) op->value4));
   13394             return (total);
   13395         case XPATH_OP_VARIABLE:{
   13396 		xmlXPathObjectPtr val;
   13397 
   13398                 if (op->ch1 != -1)
   13399                     total +=
   13400                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13401                 if (op->value5 == NULL) {
   13402 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13403 		    if (val == NULL) {
   13404 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13405 			return(0);
   13406 		    }
   13407                     valuePush(ctxt, val);
   13408 		} else {
   13409                     const xmlChar *URI;
   13410 
   13411                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13412                     if (URI == NULL) {
   13413                         xmlGenericError(xmlGenericErrorContext,
   13414             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13415                                     (char *) op->value4, (char *)op->value5);
   13416                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13417                         return (total);
   13418                     }
   13419 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13420                                                        op->value4, URI);
   13421 		    if (val == NULL) {
   13422 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13423 			return(0);
   13424 		    }
   13425                     valuePush(ctxt, val);
   13426                 }
   13427                 return (total);
   13428             }
   13429         case XPATH_OP_FUNCTION:{
   13430                 xmlXPathFunction func;
   13431                 const xmlChar *oldFunc, *oldFuncURI;
   13432 		int i;
   13433                 int frame;
   13434 
   13435                 frame = xmlXPathSetFrame(ctxt);
   13436                 if (op->ch1 != -1)
   13437                     total +=
   13438                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13439 		if (ctxt->valueNr < op->value) {
   13440 		    xmlGenericError(xmlGenericErrorContext,
   13441 			    "xmlXPathCompOpEval: parameter error\n");
   13442 		    ctxt->error = XPATH_INVALID_OPERAND;
   13443                     xmlXPathPopFrame(ctxt, frame);
   13444 		    return (total);
   13445 		}
   13446 		for (i = 0; i < op->value; i++) {
   13447 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13448 			xmlGenericError(xmlGenericErrorContext,
   13449 				"xmlXPathCompOpEval: parameter error\n");
   13450 			ctxt->error = XPATH_INVALID_OPERAND;
   13451                         xmlXPathPopFrame(ctxt, frame);
   13452 			return (total);
   13453 		    }
   13454                 }
   13455                 if (op->cache != NULL)
   13456                     XML_CAST_FPTR(func) = op->cache;
   13457                 else {
   13458                     const xmlChar *URI = NULL;
   13459 
   13460                     if (op->value5 == NULL)
   13461                         func =
   13462                             xmlXPathFunctionLookup(ctxt->context,
   13463                                                    op->value4);
   13464                     else {
   13465                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13466                         if (URI == NULL) {
   13467                             xmlGenericError(xmlGenericErrorContext,
   13468             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13469                                     (char *)op->value4, (char *)op->value5);
   13470                             xmlXPathPopFrame(ctxt, frame);
   13471                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13472                             return (total);
   13473                         }
   13474                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13475                                                         op->value4, URI);
   13476                     }
   13477                     if (func == NULL) {
   13478                         xmlGenericError(xmlGenericErrorContext,
   13479                                 "xmlXPathCompOpEval: function %s not found\n",
   13480                                         (char *)op->value4);
   13481                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13482                     }
   13483                     op->cache = XML_CAST_FPTR(func);
   13484                     op->cacheURI = (void *) URI;
   13485                 }
   13486                 oldFunc = ctxt->context->function;
   13487                 oldFuncURI = ctxt->context->functionURI;
   13488                 ctxt->context->function = op->value4;
   13489                 ctxt->context->functionURI = op->cacheURI;
   13490                 func(ctxt, op->value);
   13491                 ctxt->context->function = oldFunc;
   13492                 ctxt->context->functionURI = oldFuncURI;
   13493                 xmlXPathPopFrame(ctxt, frame);
   13494                 return (total);
   13495             }
   13496         case XPATH_OP_ARG:
   13497 	    bakd = ctxt->context->doc;
   13498 	    bak = ctxt->context->node;
   13499 	    pp = ctxt->context->proximityPosition;
   13500 	    cs = ctxt->context->contextSize;
   13501             if (op->ch1 != -1)
   13502                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13503 	    ctxt->context->contextSize = cs;
   13504 	    ctxt->context->proximityPosition = pp;
   13505 	    ctxt->context->node = bak;
   13506 	    ctxt->context->doc = bakd;
   13507 	    CHECK_ERROR0;
   13508             if (op->ch2 != -1) {
   13509                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13510 	        ctxt->context->doc = bakd;
   13511 	        ctxt->context->node = bak;
   13512 	        CHECK_ERROR0;
   13513 	    }
   13514             return (total);
   13515         case XPATH_OP_PREDICATE:
   13516         case XPATH_OP_FILTER:{
   13517                 xmlXPathObjectPtr res;
   13518                 xmlXPathObjectPtr obj, tmp;
   13519                 xmlNodeSetPtr newset = NULL;
   13520                 xmlNodeSetPtr oldset;
   13521                 xmlNodePtr oldnode;
   13522 		xmlDocPtr oldDoc;
   13523                 int i;
   13524 
   13525                 /*
   13526                  * Optimization for ()[1] selection i.e. the first elem
   13527                  */
   13528                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13529 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13530 		    /*
   13531 		    * FILTER TODO: Can we assume that the inner processing
   13532 		    *  will result in an ordered list if we have an
   13533 		    *  XPATH_OP_FILTER?
   13534 		    *  What about an additional field or flag on
   13535 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13536 		    *  to assume anything, so it would be more robust and
   13537 		    *  easier to optimize.
   13538 		    */
   13539                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13540 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13541 #else
   13542 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13543 #endif
   13544                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13545                     xmlXPathObjectPtr val;
   13546 
   13547                     val = comp->steps[op->ch2].value4;
   13548                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13549                         (val->floatval == 1.0)) {
   13550                         xmlNodePtr first = NULL;
   13551 
   13552                         total +=
   13553                             xmlXPathCompOpEvalFirst(ctxt,
   13554                                                     &comp->steps[op->ch1],
   13555                                                     &first);
   13556 			CHECK_ERROR0;
   13557                         /*
   13558                          * The nodeset should be in document order,
   13559                          * Keep only the first value
   13560                          */
   13561                         if ((ctxt->value != NULL) &&
   13562                             (ctxt->value->type == XPATH_NODESET) &&
   13563                             (ctxt->value->nodesetval != NULL) &&
   13564                             (ctxt->value->nodesetval->nodeNr > 1))
   13565                             ctxt->value->nodesetval->nodeNr = 1;
   13566                         return (total);
   13567                     }
   13568                 }
   13569                 /*
   13570                  * Optimization for ()[last()] selection i.e. the last elem
   13571                  */
   13572                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13573                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13574                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13575                     int f = comp->steps[op->ch2].ch1;
   13576 
   13577                     if ((f != -1) &&
   13578                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13579                         (comp->steps[f].value5 == NULL) &&
   13580                         (comp->steps[f].value == 0) &&
   13581                         (comp->steps[f].value4 != NULL) &&
   13582                         (xmlStrEqual
   13583                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13584                         xmlNodePtr last = NULL;
   13585 
   13586                         total +=
   13587                             xmlXPathCompOpEvalLast(ctxt,
   13588                                                    &comp->steps[op->ch1],
   13589                                                    &last);
   13590 			CHECK_ERROR0;
   13591                         /*
   13592                          * The nodeset should be in document order,
   13593                          * Keep only the last value
   13594                          */
   13595                         if ((ctxt->value != NULL) &&
   13596                             (ctxt->value->type == XPATH_NODESET) &&
   13597                             (ctxt->value->nodesetval != NULL) &&
   13598                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13599                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13600                             ctxt->value->nodesetval->nodeTab[0] =
   13601                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13602                                                                  value->
   13603                                                                  nodesetval->
   13604                                                                  nodeNr -
   13605                                                                  1];
   13606                             ctxt->value->nodesetval->nodeNr = 1;
   13607                         }
   13608                         return (total);
   13609                     }
   13610                 }
   13611 		/*
   13612 		* Process inner predicates first.
   13613 		* Example "index[parent::book][1]":
   13614 		* ...
   13615 		*   PREDICATE   <-- we are here "[1]"
   13616 		*     PREDICATE <-- process "[parent::book]" first
   13617 		*       SORT
   13618 		*         COLLECT  'parent' 'name' 'node' book
   13619 		*           NODE
   13620 		*     ELEM Object is a number : 1
   13621 		*/
   13622                 if (op->ch1 != -1)
   13623                     total +=
   13624                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13625 		CHECK_ERROR0;
   13626                 if (op->ch2 == -1)
   13627                     return (total);
   13628                 if (ctxt->value == NULL)
   13629                     return (total);
   13630 
   13631                 oldnode = ctxt->context->node;
   13632 
   13633 #ifdef LIBXML_XPTR_ENABLED
   13634                 /*
   13635                  * Hum are we filtering the result of an XPointer expression
   13636                  */
   13637                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13638                     xmlLocationSetPtr newlocset = NULL;
   13639                     xmlLocationSetPtr oldlocset;
   13640 
   13641                     /*
   13642                      * Extract the old locset, and then evaluate the result of the
   13643                      * expression for all the element in the locset. use it to grow
   13644                      * up a new locset.
   13645                      */
   13646                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13647                     obj = valuePop(ctxt);
   13648                     oldlocset = obj->user;
   13649                     ctxt->context->node = NULL;
   13650 
   13651                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13652                         ctxt->context->contextSize = 0;
   13653                         ctxt->context->proximityPosition = 0;
   13654                         if (op->ch2 != -1)
   13655                             total +=
   13656                                 xmlXPathCompOpEval(ctxt,
   13657                                                    &comp->steps[op->ch2]);
   13658                         res = valuePop(ctxt);
   13659                         if (res != NULL) {
   13660 			    xmlXPathReleaseObject(ctxt->context, res);
   13661 			}
   13662                         valuePush(ctxt, obj);
   13663                         CHECK_ERROR0;
   13664                         return (total);
   13665                     }
   13666                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13667 
   13668                     for (i = 0; i < oldlocset->locNr; i++) {
   13669                         /*
   13670                          * Run the evaluation with a node list made of a
   13671                          * single item in the nodelocset.
   13672                          */
   13673                         ctxt->context->node = oldlocset->locTab[i]->user;
   13674                         ctxt->context->contextSize = oldlocset->locNr;
   13675                         ctxt->context->proximityPosition = i + 1;
   13676 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13677 			    ctxt->context->node);
   13678                         valuePush(ctxt, tmp);
   13679 
   13680                         if (op->ch2 != -1)
   13681                             total +=
   13682                                 xmlXPathCompOpEval(ctxt,
   13683                                                    &comp->steps[op->ch2]);
   13684 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13685 			    xmlXPathFreeObject(obj);
   13686 			    return(0);
   13687 			}
   13688 
   13689                         /*
   13690                          * The result of the evaluation need to be tested to
   13691                          * decided whether the filter succeeded or not
   13692                          */
   13693                         res = valuePop(ctxt);
   13694                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13695                             xmlXPtrLocationSetAdd(newlocset,
   13696                                                   xmlXPathObjectCopy
   13697                                                   (oldlocset->locTab[i]));
   13698                         }
   13699 
   13700                         /*
   13701                          * Cleanup
   13702                          */
   13703                         if (res != NULL) {
   13704 			    xmlXPathReleaseObject(ctxt->context, res);
   13705 			}
   13706                         if (ctxt->value == tmp) {
   13707                             res = valuePop(ctxt);
   13708 			    xmlXPathReleaseObject(ctxt->context, res);
   13709                         }
   13710 
   13711                         ctxt->context->node = NULL;
   13712                     }
   13713 
   13714                     /*
   13715                      * The result is used as the new evaluation locset.
   13716                      */
   13717 		    xmlXPathReleaseObject(ctxt->context, obj);
   13718                     ctxt->context->node = NULL;
   13719                     ctxt->context->contextSize = -1;
   13720                     ctxt->context->proximityPosition = -1;
   13721                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13722                     ctxt->context->node = oldnode;
   13723                     return (total);
   13724                 }
   13725 #endif /* LIBXML_XPTR_ENABLED */
   13726 
   13727                 /*
   13728                  * Extract the old set, and then evaluate the result of the
   13729                  * expression for all the element in the set. use it to grow
   13730                  * up a new set.
   13731                  */
   13732                 CHECK_TYPE0(XPATH_NODESET);
   13733                 obj = valuePop(ctxt);
   13734                 oldset = obj->nodesetval;
   13735 
   13736                 oldnode = ctxt->context->node;
   13737 		oldDoc = ctxt->context->doc;
   13738                 ctxt->context->node = NULL;
   13739 
   13740                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13741                     ctxt->context->contextSize = 0;
   13742                     ctxt->context->proximityPosition = 0;
   13743 /*
   13744                     if (op->ch2 != -1)
   13745                         total +=
   13746                             xmlXPathCompOpEval(ctxt,
   13747                                                &comp->steps[op->ch2]);
   13748 		    CHECK_ERROR0;
   13749                     res = valuePop(ctxt);
   13750                     if (res != NULL)
   13751                         xmlXPathFreeObject(res);
   13752 */
   13753                     valuePush(ctxt, obj);
   13754                     ctxt->context->node = oldnode;
   13755                     CHECK_ERROR0;
   13756                 } else {
   13757 		    tmp = NULL;
   13758                     /*
   13759                      * Initialize the new set.
   13760 		     * Also set the xpath document in case things like
   13761 		     * key() evaluation are attempted on the predicate
   13762                      */
   13763                     newset = xmlXPathNodeSetCreate(NULL);
   13764 		    /*
   13765 		    * SPEC XPath 1.0:
   13766 		    *  "For each node in the node-set to be filtered, the
   13767 		    *  PredicateExpr is evaluated with that node as the
   13768 		    *  context node, with the number of nodes in the
   13769 		    *  node-set as the context size, and with the proximity
   13770 		    *  position of the node in the node-set with respect to
   13771 		    *  the axis as the context position;"
   13772 		    * @oldset is the node-set" to be filtered.
   13773 		    *
   13774 		    * SPEC XPath 1.0:
   13775 		    *  "only predicates change the context position and
   13776 		    *  context size (see [2.4 Predicates])."
   13777 		    * Example:
   13778 		    *   node-set  context pos
   13779 		    *    nA         1
   13780 		    *    nB         2
   13781 		    *    nC         3
   13782 		    *   After applying predicate [position() > 1] :
   13783 		    *   node-set  context pos
   13784 		    *    nB         1
   13785 		    *    nC         2
   13786 		    *
   13787 		    * removed the first node in the node-set, then
   13788 		    * the context position of the
   13789 		    */
   13790                     for (i = 0; i < oldset->nodeNr; i++) {
   13791                         /*
   13792                          * Run the evaluation with a node list made of
   13793                          * a single item in the nodeset.
   13794                          */
   13795                         ctxt->context->node = oldset->nodeTab[i];
   13796 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13797 			    (oldset->nodeTab[i]->doc != NULL))
   13798 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13799 			if (tmp == NULL) {
   13800 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13801 				ctxt->context->node);
   13802 			} else {
   13803 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13804 				ctxt->context->node);
   13805 			}
   13806                         valuePush(ctxt, tmp);
   13807                         ctxt->context->contextSize = oldset->nodeNr;
   13808                         ctxt->context->proximityPosition = i + 1;
   13809 			/*
   13810 			* Evaluate the predicate against the context node.
   13811 			* Can/should we optimize position() predicates
   13812 			* here (e.g. "[1]")?
   13813 			*/
   13814                         if (op->ch2 != -1)
   13815                             total +=
   13816                                 xmlXPathCompOpEval(ctxt,
   13817                                                    &comp->steps[op->ch2]);
   13818 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13819 			    xmlXPathFreeNodeSet(newset);
   13820 			    xmlXPathFreeObject(obj);
   13821 			    return(0);
   13822 			}
   13823 
   13824                         /*
   13825                          * The result of the evaluation needs to be tested to
   13826                          * decide whether the filter succeeded or not
   13827                          */
   13828 			/*
   13829 			* OPTIMIZE TODO: Can we use
   13830 			* xmlXPathNodeSetAdd*Unique()* instead?
   13831 			*/
   13832                         res = valuePop(ctxt);
   13833                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13834                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13835                         }
   13836 
   13837                         /*
   13838                          * Cleanup
   13839                          */
   13840                         if (res != NULL) {
   13841 			    xmlXPathReleaseObject(ctxt->context, res);
   13842 			}
   13843                         if (ctxt->value == tmp) {
   13844                             valuePop(ctxt);
   13845 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13846 			    /*
   13847 			    * Don't free the temporary nodeset
   13848 			    * in order to avoid massive recreation inside this
   13849 			    * loop.
   13850 			    */
   13851                         } else
   13852 			    tmp = NULL;
   13853                         ctxt->context->node = NULL;
   13854                     }
   13855 		    if (tmp != NULL)
   13856 			xmlXPathReleaseObject(ctxt->context, tmp);
   13857                     /*
   13858                      * The result is used as the new evaluation set.
   13859                      */
   13860 		    xmlXPathReleaseObject(ctxt->context, obj);
   13861                     ctxt->context->node = NULL;
   13862                     ctxt->context->contextSize = -1;
   13863                     ctxt->context->proximityPosition = -1;
   13864 		    /* may want to move this past the '}' later */
   13865 		    ctxt->context->doc = oldDoc;
   13866 		    valuePush(ctxt,
   13867 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13868                 }
   13869                 ctxt->context->node = oldnode;
   13870                 return (total);
   13871             }
   13872         case XPATH_OP_SORT:
   13873             if (op->ch1 != -1)
   13874                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13875 	    CHECK_ERROR0;
   13876             if ((ctxt->value != NULL) &&
   13877                 (ctxt->value->type == XPATH_NODESET) &&
   13878                 (ctxt->value->nodesetval != NULL) &&
   13879 		(ctxt->value->nodesetval->nodeNr > 1))
   13880 	    {
   13881                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13882 	    }
   13883             return (total);
   13884 #ifdef LIBXML_XPTR_ENABLED
   13885         case XPATH_OP_RANGETO:{
   13886                 xmlXPathObjectPtr range;
   13887                 xmlXPathObjectPtr res, obj;
   13888                 xmlXPathObjectPtr tmp;
   13889                 xmlLocationSetPtr newlocset = NULL;
   13890 		    xmlLocationSetPtr oldlocset;
   13891                 xmlNodeSetPtr oldset;
   13892                 int i, j;
   13893 
   13894                 if (op->ch1 != -1)
   13895                     total +=
   13896                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13897                 if (op->ch2 == -1)
   13898                     return (total);
   13899 
   13900                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13901                     /*
   13902                      * Extract the old locset, and then evaluate the result of the
   13903                      * expression for all the element in the locset. use it to grow
   13904                      * up a new locset.
   13905                      */
   13906                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13907                     obj = valuePop(ctxt);
   13908                     oldlocset = obj->user;
   13909 
   13910                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13911 		        ctxt->context->node = NULL;
   13912                         ctxt->context->contextSize = 0;
   13913                         ctxt->context->proximityPosition = 0;
   13914                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   13915                         res = valuePop(ctxt);
   13916                         if (res != NULL) {
   13917 			    xmlXPathReleaseObject(ctxt->context, res);
   13918 			}
   13919                         valuePush(ctxt, obj);
   13920                         CHECK_ERROR0;
   13921                         return (total);
   13922                     }
   13923                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13924 
   13925                     for (i = 0; i < oldlocset->locNr; i++) {
   13926                         /*
   13927                          * Run the evaluation with a node list made of a
   13928                          * single item in the nodelocset.
   13929                          */
   13930                         ctxt->context->node = oldlocset->locTab[i]->user;
   13931                         ctxt->context->contextSize = oldlocset->locNr;
   13932                         ctxt->context->proximityPosition = i + 1;
   13933 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13934 			    ctxt->context->node);
   13935                         valuePush(ctxt, tmp);
   13936 
   13937                         if (op->ch2 != -1)
   13938                             total +=
   13939                                 xmlXPathCompOpEval(ctxt,
   13940                                                    &comp->steps[op->ch2]);
   13941 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13942 			    xmlXPathFreeObject(obj);
   13943 			    return(0);
   13944 			}
   13945 
   13946                         res = valuePop(ctxt);
   13947 			if (res->type == XPATH_LOCATIONSET) {
   13948 			    xmlLocationSetPtr rloc =
   13949 			        (xmlLocationSetPtr)res->user;
   13950 			    for (j=0; j<rloc->locNr; j++) {
   13951 			        range = xmlXPtrNewRange(
   13952 				  oldlocset->locTab[i]->user,
   13953 				  oldlocset->locTab[i]->index,
   13954 				  rloc->locTab[j]->user2,
   13955 				  rloc->locTab[j]->index2);
   13956 				if (range != NULL) {
   13957 				    xmlXPtrLocationSetAdd(newlocset, range);
   13958 				}
   13959 			    }
   13960 			} else {
   13961 			    range = xmlXPtrNewRangeNodeObject(
   13962 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   13963                             if (range != NULL) {
   13964                                 xmlXPtrLocationSetAdd(newlocset,range);
   13965 			    }
   13966                         }
   13967 
   13968                         /*
   13969                          * Cleanup
   13970                          */
   13971                         if (res != NULL) {
   13972 			    xmlXPathReleaseObject(ctxt->context, res);
   13973 			}
   13974                         if (ctxt->value == tmp) {
   13975                             res = valuePop(ctxt);
   13976 			    xmlXPathReleaseObject(ctxt->context, res);
   13977                         }
   13978 
   13979                         ctxt->context->node = NULL;
   13980                     }
   13981 		} else {	/* Not a location set */
   13982                     CHECK_TYPE0(XPATH_NODESET);
   13983                     obj = valuePop(ctxt);
   13984                     oldset = obj->nodesetval;
   13985                     ctxt->context->node = NULL;
   13986 
   13987                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13988 
   13989                     if (oldset != NULL) {
   13990                         for (i = 0; i < oldset->nodeNr; i++) {
   13991                             /*
   13992                              * Run the evaluation with a node list made of a single item
   13993                              * in the nodeset.
   13994                              */
   13995                             ctxt->context->node = oldset->nodeTab[i];
   13996 			    /*
   13997 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   13998 			    */
   13999 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14000 				ctxt->context->node);
   14001                             valuePush(ctxt, tmp);
   14002 
   14003                             if (op->ch2 != -1)
   14004                                 total +=
   14005                                     xmlXPathCompOpEval(ctxt,
   14006                                                    &comp->steps[op->ch2]);
   14007 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   14008 				xmlXPathFreeObject(obj);
   14009 				return(0);
   14010 			    }
   14011 
   14012                             res = valuePop(ctxt);
   14013                             range =
   14014                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   14015                                                       res);
   14016                             if (range != NULL) {
   14017                                 xmlXPtrLocationSetAdd(newlocset, range);
   14018                             }
   14019 
   14020                             /*
   14021                              * Cleanup
   14022                              */
   14023                             if (res != NULL) {
   14024 				xmlXPathReleaseObject(ctxt->context, res);
   14025 			    }
   14026                             if (ctxt->value == tmp) {
   14027                                 res = valuePop(ctxt);
   14028 				xmlXPathReleaseObject(ctxt->context, res);
   14029                             }
   14030 
   14031                             ctxt->context->node = NULL;
   14032                         }
   14033                     }
   14034                 }
   14035 
   14036                 /*
   14037                  * The result is used as the new evaluation set.
   14038                  */
   14039 		xmlXPathReleaseObject(ctxt->context, obj);
   14040                 ctxt->context->node = NULL;
   14041                 ctxt->context->contextSize = -1;
   14042                 ctxt->context->proximityPosition = -1;
   14043                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   14044                 return (total);
   14045             }
   14046 #endif /* LIBXML_XPTR_ENABLED */
   14047     }
   14048     xmlGenericError(xmlGenericErrorContext,
   14049                     "XPath: unknown precompiled operation %d\n", op->op);
   14050     ctxt->error = XPATH_INVALID_OPERAND;
   14051     return (total);
   14052 }
   14053 
   14054 /**
   14055  * xmlXPathCompOpEvalToBoolean:
   14056  * @ctxt:  the XPath parser context
   14057  *
   14058  * Evaluates if the expression evaluates to true.
   14059  *
   14060  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   14061  */
   14062 static int
   14063 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   14064 			    xmlXPathStepOpPtr op,
   14065 			    int isPredicate)
   14066 {
   14067     xmlXPathObjectPtr resObj = NULL;
   14068 
   14069 start:
   14070     /* comp = ctxt->comp; */
   14071     switch (op->op) {
   14072         case XPATH_OP_END:
   14073             return (0);
   14074 	case XPATH_OP_VALUE:
   14075 	    resObj = (xmlXPathObjectPtr) op->value4;
   14076 	    if (isPredicate)
   14077 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14078 	    return(xmlXPathCastToBoolean(resObj));
   14079 	case XPATH_OP_SORT:
   14080 	    /*
   14081 	    * We don't need sorting for boolean results. Skip this one.
   14082 	    */
   14083             if (op->ch1 != -1) {
   14084 		op = &ctxt->comp->steps[op->ch1];
   14085 		goto start;
   14086 	    }
   14087 	    return(0);
   14088 	case XPATH_OP_COLLECT:
   14089 	    if (op->ch1 == -1)
   14090 		return(0);
   14091 
   14092             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14093 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14094 		return(-1);
   14095 
   14096             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14097 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14098 		return(-1);
   14099 
   14100 	    resObj = valuePop(ctxt);
   14101 	    if (resObj == NULL)
   14102 		return(-1);
   14103 	    break;
   14104 	default:
   14105 	    /*
   14106 	    * Fallback to call xmlXPathCompOpEval().
   14107 	    */
   14108 	    xmlXPathCompOpEval(ctxt, op);
   14109 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14110 		return(-1);
   14111 
   14112 	    resObj = valuePop(ctxt);
   14113 	    if (resObj == NULL)
   14114 		return(-1);
   14115 	    break;
   14116     }
   14117 
   14118     if (resObj) {
   14119 	int res;
   14120 
   14121 	if (resObj->type == XPATH_BOOLEAN) {
   14122 	    res = resObj->boolval;
   14123 	} else if (isPredicate) {
   14124 	    /*
   14125 	    * For predicates a result of type "number" is handled
   14126 	    * differently:
   14127 	    * SPEC XPath 1.0:
   14128 	    * "If the result is a number, the result will be converted
   14129 	    *  to true if the number is equal to the context position
   14130 	    *  and will be converted to false otherwise;"
   14131 	    */
   14132 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14133 	} else {
   14134 	    res = xmlXPathCastToBoolean(resObj);
   14135 	}
   14136 	xmlXPathReleaseObject(ctxt->context, resObj);
   14137 	return(res);
   14138     }
   14139 
   14140     return(0);
   14141 }
   14142 
   14143 #ifdef XPATH_STREAMING
   14144 /**
   14145  * xmlXPathRunStreamEval:
   14146  * @ctxt:  the XPath parser context with the compiled expression
   14147  *
   14148  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14149  */
   14150 static int
   14151 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14152 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14153 {
   14154     int max_depth, min_depth;
   14155     int from_root;
   14156     int ret, depth;
   14157     int eval_all_nodes;
   14158     xmlNodePtr cur = NULL, limit = NULL;
   14159     xmlStreamCtxtPtr patstream = NULL;
   14160 
   14161     int nb_nodes = 0;
   14162 
   14163     if ((ctxt == NULL) || (comp == NULL))
   14164         return(-1);
   14165     max_depth = xmlPatternMaxDepth(comp);
   14166     if (max_depth == -1)
   14167         return(-1);
   14168     if (max_depth == -2)
   14169         max_depth = 10000;
   14170     min_depth = xmlPatternMinDepth(comp);
   14171     if (min_depth == -1)
   14172         return(-1);
   14173     from_root = xmlPatternFromRoot(comp);
   14174     if (from_root < 0)
   14175         return(-1);
   14176 #if 0
   14177     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14178 #endif
   14179 
   14180     if (! toBool) {
   14181 	if (resultSeq == NULL)
   14182 	    return(-1);
   14183 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14184 	if (*resultSeq == NULL)
   14185 	    return(-1);
   14186     }
   14187 
   14188     /*
   14189      * handle the special cases of "/" amd "." being matched
   14190      */
   14191     if (min_depth == 0) {
   14192 	if (from_root) {
   14193 	    /* Select "/" */
   14194 	    if (toBool)
   14195 		return(1);
   14196 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14197 		(xmlNodePtr) ctxt->doc);
   14198 	} else {
   14199 	    /* Select "self::node()" */
   14200 	    if (toBool)
   14201 		return(1);
   14202 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14203 	}
   14204     }
   14205     if (max_depth == 0) {
   14206 	return(0);
   14207     }
   14208 
   14209     if (from_root) {
   14210         cur = (xmlNodePtr)ctxt->doc;
   14211     } else if (ctxt->node != NULL) {
   14212         switch (ctxt->node->type) {
   14213             case XML_ELEMENT_NODE:
   14214             case XML_DOCUMENT_NODE:
   14215             case XML_DOCUMENT_FRAG_NODE:
   14216             case XML_HTML_DOCUMENT_NODE:
   14217 #ifdef LIBXML_DOCB_ENABLED
   14218             case XML_DOCB_DOCUMENT_NODE:
   14219 #endif
   14220 	        cur = ctxt->node;
   14221 		break;
   14222             case XML_ATTRIBUTE_NODE:
   14223             case XML_TEXT_NODE:
   14224             case XML_CDATA_SECTION_NODE:
   14225             case XML_ENTITY_REF_NODE:
   14226             case XML_ENTITY_NODE:
   14227             case XML_PI_NODE:
   14228             case XML_COMMENT_NODE:
   14229             case XML_NOTATION_NODE:
   14230             case XML_DTD_NODE:
   14231             case XML_DOCUMENT_TYPE_NODE:
   14232             case XML_ELEMENT_DECL:
   14233             case XML_ATTRIBUTE_DECL:
   14234             case XML_ENTITY_DECL:
   14235             case XML_NAMESPACE_DECL:
   14236             case XML_XINCLUDE_START:
   14237             case XML_XINCLUDE_END:
   14238 		break;
   14239 	}
   14240 	limit = cur;
   14241     }
   14242     if (cur == NULL) {
   14243         return(0);
   14244     }
   14245 
   14246     patstream = xmlPatternGetStreamCtxt(comp);
   14247     if (patstream == NULL) {
   14248 	/*
   14249 	* QUESTION TODO: Is this an error?
   14250 	*/
   14251 	return(0);
   14252     }
   14253 
   14254     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14255 
   14256     if (from_root) {
   14257 	ret = xmlStreamPush(patstream, NULL, NULL);
   14258 	if (ret < 0) {
   14259 	} else if (ret == 1) {
   14260 	    if (toBool)
   14261 		goto return_1;
   14262 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14263 	}
   14264     }
   14265     depth = 0;
   14266     goto scan_children;
   14267 next_node:
   14268     do {
   14269         nb_nodes++;
   14270 
   14271 	switch (cur->type) {
   14272 	    case XML_ELEMENT_NODE:
   14273 	    case XML_TEXT_NODE:
   14274 	    case XML_CDATA_SECTION_NODE:
   14275 	    case XML_COMMENT_NODE:
   14276 	    case XML_PI_NODE:
   14277 		if (cur->type == XML_ELEMENT_NODE) {
   14278 		    ret = xmlStreamPush(patstream, cur->name,
   14279 				(cur->ns ? cur->ns->href : NULL));
   14280 		} else if (eval_all_nodes)
   14281 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14282 		else
   14283 		    break;
   14284 
   14285 		if (ret < 0) {
   14286 		    /* NOP. */
   14287 		} else if (ret == 1) {
   14288 		    if (toBool)
   14289 			goto return_1;
   14290 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14291 		}
   14292 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14293 		    ret = xmlStreamPop(patstream);
   14294 		    while (cur->next != NULL) {
   14295 			cur = cur->next;
   14296 			if ((cur->type != XML_ENTITY_DECL) &&
   14297 			    (cur->type != XML_DTD_NODE))
   14298 			    goto next_node;
   14299 		    }
   14300 		}
   14301 	    default:
   14302 		break;
   14303 	}
   14304 
   14305 scan_children:
   14306 	if ((cur->children != NULL) && (depth < max_depth)) {
   14307 	    /*
   14308 	     * Do not descend on entities declarations
   14309 	     */
   14310 	    if (cur->children->type != XML_ENTITY_DECL) {
   14311 		cur = cur->children;
   14312 		depth++;
   14313 		/*
   14314 		 * Skip DTDs
   14315 		 */
   14316 		if (cur->type != XML_DTD_NODE)
   14317 		    continue;
   14318 	    }
   14319 	}
   14320 
   14321 	if (cur == limit)
   14322 	    break;
   14323 
   14324 	while (cur->next != NULL) {
   14325 	    cur = cur->next;
   14326 	    if ((cur->type != XML_ENTITY_DECL) &&
   14327 		(cur->type != XML_DTD_NODE))
   14328 		goto next_node;
   14329 	}
   14330 
   14331 	do {
   14332 	    cur = cur->parent;
   14333 	    depth--;
   14334 	    if ((cur == NULL) || (cur == limit))
   14335 	        goto done;
   14336 	    if (cur->type == XML_ELEMENT_NODE) {
   14337 		ret = xmlStreamPop(patstream);
   14338 	    } else if ((eval_all_nodes) &&
   14339 		((cur->type == XML_TEXT_NODE) ||
   14340 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14341 		 (cur->type == XML_COMMENT_NODE) ||
   14342 		 (cur->type == XML_PI_NODE)))
   14343 	    {
   14344 		ret = xmlStreamPop(patstream);
   14345 	    }
   14346 	    if (cur->next != NULL) {
   14347 		cur = cur->next;
   14348 		break;
   14349 	    }
   14350 	} while (cur != NULL);
   14351 
   14352     } while ((cur != NULL) && (depth >= 0));
   14353 
   14354 done:
   14355 
   14356 #if 0
   14357     printf("stream eval: checked %d nodes selected %d\n",
   14358            nb_nodes, retObj->nodesetval->nodeNr);
   14359 #endif
   14360 
   14361     if (patstream)
   14362 	xmlFreeStreamCtxt(patstream);
   14363     return(0);
   14364 
   14365 return_1:
   14366     if (patstream)
   14367 	xmlFreeStreamCtxt(patstream);
   14368     return(1);
   14369 }
   14370 #endif /* XPATH_STREAMING */
   14371 
   14372 /**
   14373  * xmlXPathRunEval:
   14374  * @ctxt:  the XPath parser context with the compiled expression
   14375  * @toBool:  evaluate to a boolean result
   14376  *
   14377  * Evaluate the Precompiled XPath expression in the given context.
   14378  */
   14379 static int
   14380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14381 {
   14382     xmlXPathCompExprPtr comp;
   14383 
   14384     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14385 	return(-1);
   14386 
   14387     if (ctxt->valueTab == NULL) {
   14388 	/* Allocate the value stack */
   14389 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14390 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14391 	if (ctxt->valueTab == NULL) {
   14392 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14393 	    xmlFree(ctxt);
   14394 	}
   14395 	ctxt->valueNr = 0;
   14396 	ctxt->valueMax = 10;
   14397 	ctxt->value = NULL;
   14398         ctxt->valueFrame = 0;
   14399     }
   14400 #ifdef XPATH_STREAMING
   14401     if (ctxt->comp->stream) {
   14402 	int res;
   14403 
   14404 	if (toBool) {
   14405 	    /*
   14406 	    * Evaluation to boolean result.
   14407 	    */
   14408 	    res = xmlXPathRunStreamEval(ctxt->context,
   14409 		ctxt->comp->stream, NULL, 1);
   14410 	    if (res != -1)
   14411 		return(res);
   14412 	} else {
   14413 	    xmlXPathObjectPtr resObj = NULL;
   14414 
   14415 	    /*
   14416 	    * Evaluation to a sequence.
   14417 	    */
   14418 	    res = xmlXPathRunStreamEval(ctxt->context,
   14419 		ctxt->comp->stream, &resObj, 0);
   14420 
   14421 	    if ((res != -1) && (resObj != NULL)) {
   14422 		valuePush(ctxt, resObj);
   14423 		return(0);
   14424 	    }
   14425 	    if (resObj != NULL)
   14426 		xmlXPathReleaseObject(ctxt->context, resObj);
   14427 	}
   14428 	/*
   14429 	* QUESTION TODO: This falls back to normal XPath evaluation
   14430 	* if res == -1. Is this intended?
   14431 	*/
   14432     }
   14433 #endif
   14434     comp = ctxt->comp;
   14435     if (comp->last < 0) {
   14436 	xmlGenericError(xmlGenericErrorContext,
   14437 	    "xmlXPathRunEval: last is less than zero\n");
   14438 	return(-1);
   14439     }
   14440     if (toBool)
   14441 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14442 	    &comp->steps[comp->last], 0));
   14443     else
   14444 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14445 
   14446     return(0);
   14447 }
   14448 
   14449 /************************************************************************
   14450  *									*
   14451  *			Public interfaces				*
   14452  *									*
   14453  ************************************************************************/
   14454 
   14455 /**
   14456  * xmlXPathEvalPredicate:
   14457  * @ctxt:  the XPath context
   14458  * @res:  the Predicate Expression evaluation result
   14459  *
   14460  * Evaluate a predicate result for the current node.
   14461  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14462  * the result to a boolean. If the result is a number, the result will
   14463  * be converted to true if the number is equal to the position of the
   14464  * context node in the context node list (as returned by the position
   14465  * function) and will be converted to false otherwise; if the result
   14466  * is not a number, then the result will be converted as if by a call
   14467  * to the boolean function.
   14468  *
   14469  * Returns 1 if predicate is true, 0 otherwise
   14470  */
   14471 int
   14472 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14473     if ((ctxt == NULL) || (res == NULL)) return(0);
   14474     switch (res->type) {
   14475         case XPATH_BOOLEAN:
   14476 	    return(res->boolval);
   14477         case XPATH_NUMBER:
   14478 	    return(res->floatval == ctxt->proximityPosition);
   14479         case XPATH_NODESET:
   14480         case XPATH_XSLT_TREE:
   14481 	    if (res->nodesetval == NULL)
   14482 		return(0);
   14483 	    return(res->nodesetval->nodeNr != 0);
   14484         case XPATH_STRING:
   14485 	    return((res->stringval != NULL) &&
   14486 	           (xmlStrlen(res->stringval) != 0));
   14487         default:
   14488 	    STRANGE
   14489     }
   14490     return(0);
   14491 }
   14492 
   14493 /**
   14494  * xmlXPathEvaluatePredicateResult:
   14495  * @ctxt:  the XPath Parser context
   14496  * @res:  the Predicate Expression evaluation result
   14497  *
   14498  * Evaluate a predicate result for the current node.
   14499  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14500  * the result to a boolean. If the result is a number, the result will
   14501  * be converted to true if the number is equal to the position of the
   14502  * context node in the context node list (as returned by the position
   14503  * function) and will be converted to false otherwise; if the result
   14504  * is not a number, then the result will be converted as if by a call
   14505  * to the boolean function.
   14506  *
   14507  * Returns 1 if predicate is true, 0 otherwise
   14508  */
   14509 int
   14510 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14511                                 xmlXPathObjectPtr res) {
   14512     if ((ctxt == NULL) || (res == NULL)) return(0);
   14513     switch (res->type) {
   14514         case XPATH_BOOLEAN:
   14515 	    return(res->boolval);
   14516         case XPATH_NUMBER:
   14517 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14518 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14519 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14520 #else
   14521 	    return(res->floatval == ctxt->context->proximityPosition);
   14522 #endif
   14523         case XPATH_NODESET:
   14524         case XPATH_XSLT_TREE:
   14525 	    if (res->nodesetval == NULL)
   14526 		return(0);
   14527 	    return(res->nodesetval->nodeNr != 0);
   14528         case XPATH_STRING:
   14529 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14530 #ifdef LIBXML_XPTR_ENABLED
   14531 	case XPATH_LOCATIONSET:{
   14532 	    xmlLocationSetPtr ptr = res->user;
   14533 	    if (ptr == NULL)
   14534 	        return(0);
   14535 	    return (ptr->locNr != 0);
   14536 	    }
   14537 #endif
   14538         default:
   14539 	    STRANGE
   14540     }
   14541     return(0);
   14542 }
   14543 
   14544 #ifdef XPATH_STREAMING
   14545 /**
   14546  * xmlXPathTryStreamCompile:
   14547  * @ctxt: an XPath context
   14548  * @str:  the XPath expression
   14549  *
   14550  * Try to compile the XPath expression as a streamable subset.
   14551  *
   14552  * Returns the compiled expression or NULL if failed to compile.
   14553  */
   14554 static xmlXPathCompExprPtr
   14555 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14556     /*
   14557      * Optimization: use streaming patterns when the XPath expression can
   14558      * be compiled to a stream lookup
   14559      */
   14560     xmlPatternPtr stream;
   14561     xmlXPathCompExprPtr comp;
   14562     xmlDictPtr dict = NULL;
   14563     const xmlChar **namespaces = NULL;
   14564     xmlNsPtr ns;
   14565     int i, j;
   14566 
   14567     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14568         (!xmlStrchr(str, '@'))) {
   14569 	const xmlChar *tmp;
   14570 
   14571 	/*
   14572 	 * We don't try to handle expressions using the verbose axis
   14573 	 * specifiers ("::"), just the simplied form at this point.
   14574 	 * Additionally, if there is no list of namespaces available and
   14575 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14576 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14577 	 *  to have a list of namespaces at compilation time in order to
   14578 	 *  compile prefixed name tests.
   14579 	 */
   14580 	tmp = xmlStrchr(str, ':');
   14581 	if ((tmp != NULL) &&
   14582 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14583 	    return(NULL);
   14584 
   14585 	if (ctxt != NULL) {
   14586 	    dict = ctxt->dict;
   14587 	    if (ctxt->nsNr > 0) {
   14588 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14589 		if (namespaces == NULL) {
   14590 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14591 		    return(NULL);
   14592 		}
   14593 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14594 		    ns = ctxt->namespaces[j];
   14595 		    namespaces[i++] = ns->href;
   14596 		    namespaces[i++] = ns->prefix;
   14597 		}
   14598 		namespaces[i++] = NULL;
   14599 		namespaces[i] = NULL;
   14600 	    }
   14601 	}
   14602 
   14603 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14604 			&namespaces[0]);
   14605 	if (namespaces != NULL) {
   14606 	    xmlFree((xmlChar **)namespaces);
   14607 	}
   14608 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14609 	    comp = xmlXPathNewCompExpr();
   14610 	    if (comp == NULL) {
   14611 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14612 		return(NULL);
   14613 	    }
   14614 	    comp->stream = stream;
   14615 	    comp->dict = dict;
   14616 	    if (comp->dict)
   14617 		xmlDictReference(comp->dict);
   14618 	    return(comp);
   14619 	}
   14620 	xmlFreePattern(stream);
   14621     }
   14622     return(NULL);
   14623 }
   14624 #endif /* XPATH_STREAMING */
   14625 
   14626 static int
   14627 xmlXPathCanRewriteDosExpression(xmlChar *expr)
   14628 {
   14629     if (expr == NULL)
   14630 	return(0);
   14631     do {
   14632         if ((*expr == '/') && (*(++expr) == '/'))
   14633 	    return(1);
   14634     } while (*expr++);
   14635     return(0);
   14636 }
   14637 static void
   14638 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14639 {
   14640     /*
   14641     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14642     * internal representation.
   14643     */
   14644     if (op->ch1 != -1) {
   14645 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14646 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
   14647 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
   14648 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
   14649 	{
   14650 	    /*
   14651 	    * This is a "child::foo"
   14652 	    */
   14653 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14654 
   14655 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14656 		(prevop->ch1 != -1) &&
   14657 		((xmlXPathAxisVal) prevop->value ==
   14658 		    AXIS_DESCENDANT_OR_SELF) &&
   14659 		(prevop->ch2 == -1) &&
   14660 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14661 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
   14662 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
   14663 	    {
   14664 		/*
   14665 		* This is a "/descendant-or-self::node()" without predicates.
   14666 		* Eliminate it.
   14667 		*/
   14668 		op->ch1 = prevop->ch1;
   14669 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
   14670 	    }
   14671 	}
   14672 	if (op->ch1 != -1)
   14673 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
   14674     }
   14675     if (op->ch2 != -1)
   14676 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
   14677 }
   14678 
   14679 /**
   14680  * xmlXPathCtxtCompile:
   14681  * @ctxt: an XPath context
   14682  * @str:  the XPath expression
   14683  *
   14684  * Compile an XPath expression
   14685  *
   14686  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14687  *         the caller has to free the object.
   14688  */
   14689 xmlXPathCompExprPtr
   14690 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14691     xmlXPathParserContextPtr pctxt;
   14692     xmlXPathCompExprPtr comp;
   14693 
   14694 #ifdef XPATH_STREAMING
   14695     comp = xmlXPathTryStreamCompile(ctxt, str);
   14696     if (comp != NULL)
   14697         return(comp);
   14698 #endif
   14699 
   14700     xmlXPathInit();
   14701 
   14702     pctxt = xmlXPathNewParserContext(str, ctxt);
   14703     if (pctxt == NULL)
   14704         return NULL;
   14705     xmlXPathCompileExpr(pctxt, 1);
   14706 
   14707     if( pctxt->error != XPATH_EXPRESSION_OK )
   14708     {
   14709         xmlXPathFreeParserContext(pctxt);
   14710         return(NULL);
   14711     }
   14712 
   14713     if (*pctxt->cur != 0) {
   14714 	/*
   14715 	 * aleksey: in some cases this line prints *second* error message
   14716 	 * (see bug #78858) and probably this should be fixed.
   14717 	 * However, we are not sure that all error messages are printed
   14718 	 * out in other places. It's not critical so we leave it as-is for now
   14719 	 */
   14720 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14721 	comp = NULL;
   14722     } else {
   14723 	comp = pctxt->comp;
   14724 	pctxt->comp = NULL;
   14725     }
   14726     xmlXPathFreeParserContext(pctxt);
   14727 
   14728     if (comp != NULL) {
   14729 	comp->expr = xmlStrdup(str);
   14730 #ifdef DEBUG_EVAL_COUNTS
   14731 	comp->string = xmlStrdup(str);
   14732 	comp->nb = 0;
   14733 #endif
   14734 	if ((comp->expr != NULL) &&
   14735 	    (comp->nbStep > 2) &&
   14736 	    (comp->last >= 0) &&
   14737 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
   14738 	{
   14739 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
   14740 	}
   14741     }
   14742     return(comp);
   14743 }
   14744 
   14745 /**
   14746  * xmlXPathCompile:
   14747  * @str:  the XPath expression
   14748  *
   14749  * Compile an XPath expression
   14750  *
   14751  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14752  *         the caller has to free the object.
   14753  */
   14754 xmlXPathCompExprPtr
   14755 xmlXPathCompile(const xmlChar *str) {
   14756     return(xmlXPathCtxtCompile(NULL, str));
   14757 }
   14758 
   14759 /**
   14760  * xmlXPathCompiledEvalInternal:
   14761  * @comp:  the compiled XPath expression
   14762  * @ctxt:  the XPath context
   14763  * @resObj: the resulting XPath object or NULL
   14764  * @toBool: 1 if only a boolean result is requested
   14765  *
   14766  * Evaluate the Precompiled XPath expression in the given context.
   14767  * The caller has to free @resObj.
   14768  *
   14769  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14770  *         the caller has to free the object.
   14771  */
   14772 static int
   14773 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14774 			     xmlXPathContextPtr ctxt,
   14775 			     xmlXPathObjectPtr *resObj,
   14776 			     int toBool)
   14777 {
   14778     xmlXPathParserContextPtr pctxt;
   14779 #ifndef LIBXML_THREAD_ENABLED
   14780     static int reentance = 0;
   14781 #endif
   14782     int res;
   14783 
   14784     CHECK_CTXT_NEG(ctxt)
   14785 
   14786     if (comp == NULL)
   14787 	return(-1);
   14788     xmlXPathInit();
   14789 
   14790 #ifndef LIBXML_THREAD_ENABLED
   14791     reentance++;
   14792     if (reentance > 1)
   14793 	xmlXPathDisableOptimizer = 1;
   14794 #endif
   14795 
   14796 #ifdef DEBUG_EVAL_COUNTS
   14797     comp->nb++;
   14798     if ((comp->string != NULL) && (comp->nb > 100)) {
   14799 	fprintf(stderr, "100 x %s\n", comp->string);
   14800 	comp->nb = 0;
   14801     }
   14802 #endif
   14803     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14804     res = xmlXPathRunEval(pctxt, toBool);
   14805 
   14806     if (resObj) {
   14807 	if (pctxt->value == NULL) {
   14808 	    xmlGenericError(xmlGenericErrorContext,
   14809 		"xmlXPathCompiledEval: evaluation failed\n");
   14810 	    *resObj = NULL;
   14811 	} else {
   14812 	    *resObj = valuePop(pctxt);
   14813 	}
   14814     }
   14815 
   14816     /*
   14817     * Pop all remaining objects from the stack.
   14818     */
   14819     if (pctxt->valueNr > 0) {
   14820 	xmlXPathObjectPtr tmp;
   14821 	int stack = 0;
   14822 
   14823 	do {
   14824 	    tmp = valuePop(pctxt);
   14825 	    if (tmp != NULL) {
   14826 		stack++;
   14827 		xmlXPathReleaseObject(ctxt, tmp);
   14828 	    }
   14829 	} while (tmp != NULL);
   14830 	if ((stack != 0) &&
   14831 	    ((toBool) || ((resObj) && (*resObj))))
   14832 	{
   14833 	    xmlGenericError(xmlGenericErrorContext,
   14834 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14835 		stack);
   14836 	}
   14837     }
   14838 
   14839     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14840 	xmlXPathFreeObject(*resObj);
   14841 	*resObj = NULL;
   14842     }
   14843     pctxt->comp = NULL;
   14844     xmlXPathFreeParserContext(pctxt);
   14845 #ifndef LIBXML_THREAD_ENABLED
   14846     reentance--;
   14847 #endif
   14848 
   14849     return(res);
   14850 }
   14851 
   14852 /**
   14853  * xmlXPathCompiledEval:
   14854  * @comp:  the compiled XPath expression
   14855  * @ctx:  the XPath context
   14856  *
   14857  * Evaluate the Precompiled XPath expression in the given context.
   14858  *
   14859  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14860  *         the caller has to free the object.
   14861  */
   14862 xmlXPathObjectPtr
   14863 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14864 {
   14865     xmlXPathObjectPtr res = NULL;
   14866 
   14867     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14868     return(res);
   14869 }
   14870 
   14871 /**
   14872  * xmlXPathCompiledEvalToBoolean:
   14873  * @comp:  the compiled XPath expression
   14874  * @ctxt:  the XPath context
   14875  *
   14876  * Applies the XPath boolean() function on the result of the given
   14877  * compiled expression.
   14878  *
   14879  * Returns 1 if the expression evaluated to true, 0 if to false and
   14880  *         -1 in API and internal errors.
   14881  */
   14882 int
   14883 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14884 			      xmlXPathContextPtr ctxt)
   14885 {
   14886     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14887 }
   14888 
   14889 /**
   14890  * xmlXPathEvalExpr:
   14891  * @ctxt:  the XPath Parser context
   14892  *
   14893  * Parse and evaluate an XPath expression in the given context,
   14894  * then push the result on the context stack
   14895  */
   14896 void
   14897 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14898 #ifdef XPATH_STREAMING
   14899     xmlXPathCompExprPtr comp;
   14900 #endif
   14901 
   14902     if (ctxt == NULL) return;
   14903 
   14904 #ifdef XPATH_STREAMING
   14905     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14906     if (comp != NULL) {
   14907         if (ctxt->comp != NULL)
   14908 	    xmlXPathFreeCompExpr(ctxt->comp);
   14909         ctxt->comp = comp;
   14910 	if (ctxt->cur != NULL)
   14911 	    while (*ctxt->cur != 0) ctxt->cur++;
   14912     } else
   14913 #endif
   14914     {
   14915 	xmlXPathCompileExpr(ctxt, 1);
   14916 	/*
   14917 	* In this scenario the expression string will sit in ctxt->base.
   14918 	*/
   14919 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   14920 	    (ctxt->comp != NULL) &&
   14921 	    (ctxt->base != NULL) &&
   14922 	    (ctxt->comp->nbStep > 2) &&
   14923 	    (ctxt->comp->last >= 0) &&
   14924 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
   14925 	{
   14926 	    xmlXPathRewriteDOSExpression(ctxt->comp,
   14927 		&ctxt->comp->steps[ctxt->comp->last]);
   14928 	}
   14929     }
   14930     CHECK_ERROR;
   14931     xmlXPathRunEval(ctxt, 0);
   14932 }
   14933 
   14934 /**
   14935  * xmlXPathEval:
   14936  * @str:  the XPath expression
   14937  * @ctx:  the XPath context
   14938  *
   14939  * Evaluate the XPath Location Path in the given context.
   14940  *
   14941  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14942  *         the caller has to free the object.
   14943  */
   14944 xmlXPathObjectPtr
   14945 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   14946     xmlXPathParserContextPtr ctxt;
   14947     xmlXPathObjectPtr res, tmp, init = NULL;
   14948     int stack = 0;
   14949 
   14950     CHECK_CTXT(ctx)
   14951 
   14952     xmlXPathInit();
   14953 
   14954     ctxt = xmlXPathNewParserContext(str, ctx);
   14955     if (ctxt == NULL)
   14956         return NULL;
   14957     xmlXPathEvalExpr(ctxt);
   14958 
   14959     if (ctxt->value == NULL) {
   14960 	xmlGenericError(xmlGenericErrorContext,
   14961 		"xmlXPathEval: evaluation failed\n");
   14962 	res = NULL;
   14963     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   14964 #ifdef XPATH_STREAMING
   14965             && (ctxt->comp->stream == NULL)
   14966 #endif
   14967 	      ) {
   14968 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14969 	res = NULL;
   14970     } else {
   14971 	res = valuePop(ctxt);
   14972     }
   14973 
   14974     do {
   14975         tmp = valuePop(ctxt);
   14976 	if (tmp != NULL) {
   14977 	    if (tmp != init)
   14978 		stack++;
   14979 	    xmlXPathReleaseObject(ctx, tmp);
   14980         }
   14981     } while (tmp != NULL);
   14982     if ((stack != 0) && (res != NULL)) {
   14983 	xmlGenericError(xmlGenericErrorContext,
   14984 		"xmlXPathEval: %d object left on the stack\n",
   14985 	        stack);
   14986     }
   14987     if (ctxt->error != XPATH_EXPRESSION_OK) {
   14988 	xmlXPathFreeObject(res);
   14989 	res = NULL;
   14990     }
   14991 
   14992     xmlXPathFreeParserContext(ctxt);
   14993     return(res);
   14994 }
   14995 
   14996 /**
   14997  * xmlXPathEvalExpression:
   14998  * @str:  the XPath expression
   14999  * @ctxt:  the XPath context
   15000  *
   15001  * Evaluate the XPath expression in the given context.
   15002  *
   15003  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15004  *         the caller has to free the object.
   15005  */
   15006 xmlXPathObjectPtr
   15007 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   15008     xmlXPathParserContextPtr pctxt;
   15009     xmlXPathObjectPtr res, tmp;
   15010     int stack = 0;
   15011 
   15012     CHECK_CTXT(ctxt)
   15013 
   15014     xmlXPathInit();
   15015 
   15016     pctxt = xmlXPathNewParserContext(str, ctxt);
   15017     if (pctxt == NULL)
   15018         return NULL;
   15019     xmlXPathEvalExpr(pctxt);
   15020 
   15021     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   15022 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15023 	res = NULL;
   15024     } else {
   15025 	res = valuePop(pctxt);
   15026     }
   15027     do {
   15028         tmp = valuePop(pctxt);
   15029 	if (tmp != NULL) {
   15030 	    xmlXPathReleaseObject(ctxt, tmp);
   15031 	    stack++;
   15032 	}
   15033     } while (tmp != NULL);
   15034     if ((stack != 0) && (res != NULL)) {
   15035 	xmlGenericError(xmlGenericErrorContext,
   15036 		"xmlXPathEvalExpression: %d object left on the stack\n",
   15037 	        stack);
   15038     }
   15039     xmlXPathFreeParserContext(pctxt);
   15040     return(res);
   15041 }
   15042 
   15043 /************************************************************************
   15044  *									*
   15045  *	Extra functions not pertaining to the XPath spec		*
   15046  *									*
   15047  ************************************************************************/
   15048 /**
   15049  * xmlXPathEscapeUriFunction:
   15050  * @ctxt:  the XPath Parser context
   15051  * @nargs:  the number of arguments
   15052  *
   15053  * Implement the escape-uri() XPath function
   15054  *    string escape-uri(string $str, bool $escape-reserved)
   15055  *
   15056  * This function applies the URI escaping rules defined in section 2 of [RFC
   15057  * 2396] to the string supplied as $uri-part, which typically represents all
   15058  * or part of a URI. The effect of the function is to replace any special
   15059  * character in the string by an escape sequence of the form %xx%yy...,
   15060  * where xxyy... is the hexadecimal representation of the octets used to
   15061  * represent the character in UTF-8.
   15062  *
   15063  * The set of characters that are escaped depends on the setting of the
   15064  * boolean argument $escape-reserved.
   15065  *
   15066  * If $escape-reserved is true, all characters are escaped other than lower
   15067  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   15068  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   15069  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   15070  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15071  * A-F).
   15072  *
   15073  * If $escape-reserved is false, the behavior differs in that characters
   15074  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15075  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15076  *
   15077  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15078  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15079  * compared using string comparison functions, this function must always use
   15080  * the upper-case letters A-F.
   15081  *
   15082  * Generally, $escape-reserved should be set to true when escaping a string
   15083  * that is to form a single part of a URI, and to false when escaping an
   15084  * entire URI or URI reference.
   15085  *
   15086  * In the case of non-ascii characters, the string is encoded according to
   15087  * utf-8 and then converted according to RFC 2396.
   15088  *
   15089  * Examples
   15090  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15091  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15092  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15093  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15094  *
   15095  */
   15096 static void
   15097 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15098     xmlXPathObjectPtr str;
   15099     int escape_reserved;
   15100     xmlBufferPtr target;
   15101     xmlChar *cptr;
   15102     xmlChar escape[4];
   15103 
   15104     CHECK_ARITY(2);
   15105 
   15106     escape_reserved = xmlXPathPopBoolean(ctxt);
   15107 
   15108     CAST_TO_STRING;
   15109     str = valuePop(ctxt);
   15110 
   15111     target = xmlBufferCreate();
   15112 
   15113     escape[0] = '%';
   15114     escape[3] = 0;
   15115 
   15116     if (target) {
   15117 	for (cptr = str->stringval; *cptr; cptr++) {
   15118 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15119 		(*cptr >= 'a' && *cptr <= 'z') ||
   15120 		(*cptr >= '0' && *cptr <= '9') ||
   15121 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15122 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15123 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15124 		(*cptr == '%' &&
   15125 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15126 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15127 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15128 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15129 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15130 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15131 		(!escape_reserved &&
   15132 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15133 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15134 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15135 		  *cptr == ','))) {
   15136 		xmlBufferAdd(target, cptr, 1);
   15137 	    } else {
   15138 		if ((*cptr >> 4) < 10)
   15139 		    escape[1] = '0' + (*cptr >> 4);
   15140 		else
   15141 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15142 		if ((*cptr & 0xF) < 10)
   15143 		    escape[2] = '0' + (*cptr & 0xF);
   15144 		else
   15145 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15146 
   15147 		xmlBufferAdd(target, &escape[0], 3);
   15148 	    }
   15149 	}
   15150     }
   15151     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15152 	xmlBufferContent(target)));
   15153     xmlBufferFree(target);
   15154     xmlXPathReleaseObject(ctxt->context, str);
   15155 }
   15156 
   15157 /**
   15158  * xmlXPathRegisterAllFunctions:
   15159  * @ctxt:  the XPath context
   15160  *
   15161  * Registers all default XPath functions in this context
   15162  */
   15163 void
   15164 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15165 {
   15166     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15167                          xmlXPathBooleanFunction);
   15168     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15169                          xmlXPathCeilingFunction);
   15170     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15171                          xmlXPathCountFunction);
   15172     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15173                          xmlXPathConcatFunction);
   15174     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15175                          xmlXPathContainsFunction);
   15176     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15177                          xmlXPathIdFunction);
   15178     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15179                          xmlXPathFalseFunction);
   15180     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15181                          xmlXPathFloorFunction);
   15182     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15183                          xmlXPathLastFunction);
   15184     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15185                          xmlXPathLangFunction);
   15186     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15187                          xmlXPathLocalNameFunction);
   15188     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15189                          xmlXPathNotFunction);
   15190     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15191                          xmlXPathNameFunction);
   15192     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15193                          xmlXPathNamespaceURIFunction);
   15194     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15195                          xmlXPathNormalizeFunction);
   15196     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15197                          xmlXPathNumberFunction);
   15198     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15199                          xmlXPathPositionFunction);
   15200     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15201                          xmlXPathRoundFunction);
   15202     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15203                          xmlXPathStringFunction);
   15204     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15205                          xmlXPathStringLengthFunction);
   15206     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15207                          xmlXPathStartsWithFunction);
   15208     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15209                          xmlXPathSubstringFunction);
   15210     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15211                          xmlXPathSubstringBeforeFunction);
   15212     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15213                          xmlXPathSubstringAfterFunction);
   15214     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15215                          xmlXPathSumFunction);
   15216     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15217                          xmlXPathTrueFunction);
   15218     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15219                          xmlXPathTranslateFunction);
   15220 
   15221     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15222 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15223                          xmlXPathEscapeUriFunction);
   15224 }
   15225 
   15226 #endif /* LIBXML_XPATH_ENABLED */
   15227 #define bottom_xpath
   15228 #include "elfgcchack.h"
   15229