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     "?? Unknown error ??\n"	/* Must be last in the list! */
    256 };
    257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    258 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    259 /**
    260  * xmlXPathErrMemory:
    261  * @ctxt:  an XPath context
    262  * @extra:  extra informations
    263  *
    264  * Handle a redefinition of attribute error
    265  */
    266 static void
    267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    268 {
    269     if (ctxt != NULL) {
    270         if (extra) {
    271             xmlChar buf[200];
    272 
    273             xmlStrPrintf(buf, 200,
    274                          BAD_CAST "Memory allocation failed : %s\n",
    275                          extra);
    276             ctxt->lastError.message = (char *) xmlStrdup(buf);
    277         } else {
    278             ctxt->lastError.message = (char *)
    279 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    280         }
    281         ctxt->lastError.domain = XML_FROM_XPATH;
    282         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    283 	if (ctxt->error != NULL)
    284 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    285     } else {
    286         if (extra)
    287             __xmlRaiseError(NULL, NULL, NULL,
    288                             NULL, NULL, XML_FROM_XPATH,
    289                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    290                             extra, NULL, NULL, 0, 0,
    291                             "Memory allocation failed : %s\n", extra);
    292         else
    293             __xmlRaiseError(NULL, NULL, NULL,
    294                             NULL, NULL, XML_FROM_XPATH,
    295                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    296                             NULL, NULL, NULL, 0, 0,
    297                             "Memory allocation failed\n");
    298     }
    299 }
    300 
    301 /**
    302  * xmlXPathPErrMemory:
    303  * @ctxt:  an XPath parser context
    304  * @extra:  extra informations
    305  *
    306  * Handle a redefinition of attribute error
    307  */
    308 static void
    309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    310 {
    311     if (ctxt == NULL)
    312 	xmlXPathErrMemory(NULL, extra);
    313     else {
    314 	ctxt->error = XPATH_MEMORY_ERROR;
    315 	xmlXPathErrMemory(ctxt->context, extra);
    316     }
    317 }
    318 
    319 /**
    320  * xmlXPathErr:
    321  * @ctxt:  a XPath parser context
    322  * @error:  the error code
    323  *
    324  * Handle an XPath error
    325  */
    326 void
    327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    328 {
    329     if ((error < 0) || (error > MAXERRNO))
    330 	error = MAXERRNO;
    331     if (ctxt == NULL) {
    332 	__xmlRaiseError(NULL, NULL, NULL,
    333 			NULL, NULL, XML_FROM_XPATH,
    334 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    335 			XML_ERR_ERROR, NULL, 0,
    336 			NULL, NULL, NULL, 0, 0,
    337 			"%s", xmlXPathErrorMessages[error]);
    338 	return;
    339     }
    340     ctxt->error = error;
    341     if (ctxt->context == NULL) {
    342 	__xmlRaiseError(NULL, NULL, NULL,
    343 			NULL, NULL, XML_FROM_XPATH,
    344 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    345 			XML_ERR_ERROR, NULL, 0,
    346 			(const char *) ctxt->base, NULL, NULL,
    347 			ctxt->cur - ctxt->base, 0,
    348 			"%s", xmlXPathErrorMessages[error]);
    349 	return;
    350     }
    351 
    352     /* cleanup current last error */
    353     xmlResetError(&ctxt->context->lastError);
    354 
    355     ctxt->context->lastError.domain = XML_FROM_XPATH;
    356     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    357                            XPATH_EXPRESSION_OK;
    358     ctxt->context->lastError.level = XML_ERR_ERROR;
    359     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    360     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    361     ctxt->context->lastError.node = ctxt->context->debugNode;
    362     if (ctxt->context->error != NULL) {
    363 	ctxt->context->error(ctxt->context->userData,
    364 	                     &ctxt->context->lastError);
    365     } else {
    366 	__xmlRaiseError(NULL, NULL, NULL,
    367 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    368 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    369 			XML_ERR_ERROR, NULL, 0,
    370 			(const char *) ctxt->base, NULL, NULL,
    371 			ctxt->cur - ctxt->base, 0,
    372 			"%s", xmlXPathErrorMessages[error]);
    373     }
    374 
    375 }
    376 
    377 /**
    378  * xmlXPatherror:
    379  * @ctxt:  the XPath Parser context
    380  * @file:  the file name
    381  * @line:  the line number
    382  * @no:  the error number
    383  *
    384  * Formats an error message.
    385  */
    386 void
    387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    388               int line ATTRIBUTE_UNUSED, int no) {
    389     xmlXPathErr(ctxt, no);
    390 }
    391 
    392 /************************************************************************
    393  *									*
    394  *			Utilities					*
    395  *									*
    396  ************************************************************************/
    397 
    398 /**
    399  * xsltPointerList:
    400  *
    401  * Pointer-list for various purposes.
    402  */
    403 typedef struct _xmlPointerList xmlPointerList;
    404 typedef xmlPointerList *xmlPointerListPtr;
    405 struct _xmlPointerList {
    406     void **items;
    407     int number;
    408     int size;
    409 };
    410 /*
    411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    412 * and here, we should make the functions public.
    413 */
    414 static int
    415 xmlPointerListAddSize(xmlPointerListPtr list,
    416 		       void *item,
    417 		       int initialSize)
    418 {
    419     if (list->items == NULL) {
    420 	if (initialSize <= 0)
    421 	    initialSize = 1;
    422 	list->items = (void **) xmlMalloc(
    423 	    initialSize * sizeof(void *));
    424 	if (list->items == NULL) {
    425 	    xmlXPathErrMemory(NULL,
    426 		"xmlPointerListCreate: allocating item\n");
    427 	    return(-1);
    428 	}
    429 	list->number = 0;
    430 	list->size = initialSize;
    431     } else if (list->size <= list->number) {
    432 	list->size *= 2;
    433 	list->items = (void **) xmlRealloc(list->items,
    434 	    list->size * sizeof(void *));
    435 	if (list->items == NULL) {
    436 	    xmlXPathErrMemory(NULL,
    437 		"xmlPointerListCreate: re-allocating item\n");
    438 	    list->size = 0;
    439 	    return(-1);
    440 	}
    441     }
    442     list->items[list->number++] = item;
    443     return(0);
    444 }
    445 
    446 /**
    447  * xsltPointerListCreate:
    448  *
    449  * Creates an xsltPointerList structure.
    450  *
    451  * Returns a xsltPointerList structure or NULL in case of an error.
    452  */
    453 static xmlPointerListPtr
    454 xmlPointerListCreate(int initialSize)
    455 {
    456     xmlPointerListPtr ret;
    457 
    458     ret = xmlMalloc(sizeof(xmlPointerList));
    459     if (ret == NULL) {
    460 	xmlXPathErrMemory(NULL,
    461 	    "xmlPointerListCreate: allocating item\n");
    462 	return (NULL);
    463     }
    464     memset(ret, 0, sizeof(xmlPointerList));
    465     if (initialSize > 0) {
    466 	xmlPointerListAddSize(ret, NULL, initialSize);
    467 	ret->number = 0;
    468     }
    469     return (ret);
    470 }
    471 
    472 /**
    473  * xsltPointerListFree:
    474  *
    475  * Frees the xsltPointerList structure. This does not free
    476  * the content of the list.
    477  */
    478 static void
    479 xmlPointerListFree(xmlPointerListPtr list)
    480 {
    481     if (list == NULL)
    482 	return;
    483     if (list->items != NULL)
    484 	xmlFree(list->items);
    485     xmlFree(list);
    486 }
    487 
    488 /************************************************************************
    489  *									*
    490  *			Parser Types					*
    491  *									*
    492  ************************************************************************/
    493 
    494 /*
    495  * Types are private:
    496  */
    497 
    498 typedef enum {
    499     XPATH_OP_END=0,
    500     XPATH_OP_AND,
    501     XPATH_OP_OR,
    502     XPATH_OP_EQUAL,
    503     XPATH_OP_CMP,
    504     XPATH_OP_PLUS,
    505     XPATH_OP_MULT,
    506     XPATH_OP_UNION,
    507     XPATH_OP_ROOT,
    508     XPATH_OP_NODE,
    509     XPATH_OP_RESET, /* 10 */
    510     XPATH_OP_COLLECT,
    511     XPATH_OP_VALUE, /* 12 */
    512     XPATH_OP_VARIABLE,
    513     XPATH_OP_FUNCTION,
    514     XPATH_OP_ARG,
    515     XPATH_OP_PREDICATE,
    516     XPATH_OP_FILTER, /* 17 */
    517     XPATH_OP_SORT /* 18 */
    518 #ifdef LIBXML_XPTR_ENABLED
    519     ,XPATH_OP_RANGETO
    520 #endif
    521 } xmlXPathOp;
    522 
    523 typedef enum {
    524     AXIS_ANCESTOR = 1,
    525     AXIS_ANCESTOR_OR_SELF,
    526     AXIS_ATTRIBUTE,
    527     AXIS_CHILD,
    528     AXIS_DESCENDANT,
    529     AXIS_DESCENDANT_OR_SELF,
    530     AXIS_FOLLOWING,
    531     AXIS_FOLLOWING_SIBLING,
    532     AXIS_NAMESPACE,
    533     AXIS_PARENT,
    534     AXIS_PRECEDING,
    535     AXIS_PRECEDING_SIBLING,
    536     AXIS_SELF
    537 } xmlXPathAxisVal;
    538 
    539 typedef enum {
    540     NODE_TEST_NONE = 0,
    541     NODE_TEST_TYPE = 1,
    542     NODE_TEST_PI = 2,
    543     NODE_TEST_ALL = 3,
    544     NODE_TEST_NS = 4,
    545     NODE_TEST_NAME = 5
    546 } xmlXPathTestVal;
    547 
    548 typedef enum {
    549     NODE_TYPE_NODE = 0,
    550     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    551     NODE_TYPE_TEXT = XML_TEXT_NODE,
    552     NODE_TYPE_PI = XML_PI_NODE
    553 } xmlXPathTypeVal;
    554 
    555 #define XP_REWRITE_DOS_CHILD_ELEM 1
    556 
    557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    559 struct _xmlXPathStepOp {
    560     xmlXPathOp op;		/* The identifier of the operation */
    561     int ch1;			/* First child */
    562     int ch2;			/* Second child */
    563     int value;
    564     int value2;
    565     int value3;
    566     void *value4;
    567     void *value5;
    568     void *cache;
    569     void *cacheURI;
    570     int rewriteType;
    571 };
    572 
    573 struct _xmlXPathCompExpr {
    574     int nbStep;			/* Number of steps in this expression */
    575     int maxStep;		/* Maximum number of steps allocated */
    576     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    577     int last;			/* index of last step in expression */
    578     xmlChar *expr;		/* the expression being computed */
    579     xmlDictPtr dict;		/* the dictionnary to use if any */
    580 #ifdef DEBUG_EVAL_COUNTS
    581     int nb;
    582     xmlChar *string;
    583 #endif
    584 #ifdef XPATH_STREAMING
    585     xmlPatternPtr stream;
    586 #endif
    587 };
    588 
    589 /************************************************************************
    590  *									*
    591  *			Forward declarations				*
    592  *									*
    593  ************************************************************************/
    594 static void
    595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    596 static void
    597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    598 static int
    599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    600                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    601 static int
    602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    603 			    xmlXPathStepOpPtr op,
    604 			    int isPredicate);
    605 
    606 /************************************************************************
    607  *									*
    608  *			Parser Type functions				*
    609  *									*
    610  ************************************************************************/
    611 
    612 /**
    613  * xmlXPathNewCompExpr:
    614  *
    615  * Create a new Xpath component
    616  *
    617  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    618  */
    619 static xmlXPathCompExprPtr
    620 xmlXPathNewCompExpr(void) {
    621     xmlXPathCompExprPtr cur;
    622 
    623     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    624     if (cur == NULL) {
    625         xmlXPathErrMemory(NULL, "allocating component\n");
    626 	return(NULL);
    627     }
    628     memset(cur, 0, sizeof(xmlXPathCompExpr));
    629     cur->maxStep = 10;
    630     cur->nbStep = 0;
    631     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    632 	                                   sizeof(xmlXPathStepOp));
    633     if (cur->steps == NULL) {
    634         xmlXPathErrMemory(NULL, "allocating steps\n");
    635 	xmlFree(cur);
    636 	return(NULL);
    637     }
    638     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    639     cur->last = -1;
    640 #ifdef DEBUG_EVAL_COUNTS
    641     cur->nb = 0;
    642 #endif
    643     return(cur);
    644 }
    645 
    646 /**
    647  * xmlXPathFreeCompExpr:
    648  * @comp:  an XPATH comp
    649  *
    650  * Free up the memory allocated by @comp
    651  */
    652 void
    653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
    654 {
    655     xmlXPathStepOpPtr op;
    656     int i;
    657 
    658     if (comp == NULL)
    659         return;
    660     if (comp->dict == NULL) {
    661 	for (i = 0; i < comp->nbStep; i++) {
    662 	    op = &comp->steps[i];
    663 	    if (op->value4 != NULL) {
    664 		if (op->op == XPATH_OP_VALUE)
    665 		    xmlXPathFreeObject(op->value4);
    666 		else
    667 		    xmlFree(op->value4);
    668 	    }
    669 	    if (op->value5 != NULL)
    670 		xmlFree(op->value5);
    671 	}
    672     } else {
    673 	for (i = 0; i < comp->nbStep; i++) {
    674 	    op = &comp->steps[i];
    675 	    if (op->value4 != NULL) {
    676 		if (op->op == XPATH_OP_VALUE)
    677 		    xmlXPathFreeObject(op->value4);
    678 	    }
    679 	}
    680         xmlDictFree(comp->dict);
    681     }
    682     if (comp->steps != NULL) {
    683         xmlFree(comp->steps);
    684     }
    685 #ifdef DEBUG_EVAL_COUNTS
    686     if (comp->string != NULL) {
    687         xmlFree(comp->string);
    688     }
    689 #endif
    690 #ifdef XPATH_STREAMING
    691     if (comp->stream != NULL) {
    692         xmlFreePatternList(comp->stream);
    693     }
    694 #endif
    695     if (comp->expr != NULL) {
    696         xmlFree(comp->expr);
    697     }
    698 
    699     xmlFree(comp);
    700 }
    701 
    702 /**
    703  * xmlXPathCompExprAdd:
    704  * @comp:  the compiled expression
    705  * @ch1: first child index
    706  * @ch2: second child index
    707  * @op:  an op
    708  * @value:  the first int value
    709  * @value2:  the second int value
    710  * @value3:  the third int value
    711  * @value4:  the first string value
    712  * @value5:  the second string value
    713  *
    714  * Add a step to an XPath Compiled Expression
    715  *
    716  * Returns -1 in case of failure, the index otherwise
    717  */
    718 static int
    719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
    720    xmlXPathOp op, int value,
    721    int value2, int value3, void *value4, void *value5) {
    722     if (comp->nbStep >= comp->maxStep) {
    723 	xmlXPathStepOp *real;
    724 
    725 	comp->maxStep *= 2;
    726 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
    727 		                      comp->maxStep * sizeof(xmlXPathStepOp));
    728 	if (real == NULL) {
    729 	    comp->maxStep /= 2;
    730 	    xmlXPathErrMemory(NULL, "adding step\n");
    731 	    return(-1);
    732 	}
    733 	comp->steps = real;
    734     }
    735     comp->last = comp->nbStep;
    736     comp->steps[comp->nbStep].rewriteType = 0;
    737     comp->steps[comp->nbStep].ch1 = ch1;
    738     comp->steps[comp->nbStep].ch2 = ch2;
    739     comp->steps[comp->nbStep].op = op;
    740     comp->steps[comp->nbStep].value = value;
    741     comp->steps[comp->nbStep].value2 = value2;
    742     comp->steps[comp->nbStep].value3 = value3;
    743     if ((comp->dict != NULL) &&
    744         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
    745 	 (op == XPATH_OP_COLLECT))) {
    746         if (value4 != NULL) {
    747 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
    748 	        (void *)xmlDictLookup(comp->dict, value4, -1);
    749 	    xmlFree(value4);
    750 	} else
    751 	    comp->steps[comp->nbStep].value4 = NULL;
    752         if (value5 != NULL) {
    753 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
    754 	        (void *)xmlDictLookup(comp->dict, value5, -1);
    755 	    xmlFree(value5);
    756 	} else
    757 	    comp->steps[comp->nbStep].value5 = NULL;
    758     } else {
    759 	comp->steps[comp->nbStep].value4 = value4;
    760 	comp->steps[comp->nbStep].value5 = value5;
    761     }
    762     comp->steps[comp->nbStep].cache = NULL;
    763     return(comp->nbStep++);
    764 }
    765 
    766 /**
    767  * xmlXPathCompSwap:
    768  * @comp:  the compiled expression
    769  * @op: operation index
    770  *
    771  * Swaps 2 operations in the compiled expression
    772  */
    773 static void
    774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
    775     int tmp;
    776 
    777 #ifndef LIBXML_THREAD_ENABLED
    778     /*
    779      * Since this manipulates possibly shared variables, this is
    780      * disabled if one detects that the library is used in a multithreaded
    781      * application
    782      */
    783     if (xmlXPathDisableOptimizer)
    784 	return;
    785 #endif
    786 
    787     tmp = op->ch1;
    788     op->ch1 = op->ch2;
    789     op->ch2 = tmp;
    790 }
    791 
    792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
    793     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
    794 	                (op), (val), (val2), (val3), (val4), (val5))
    795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
    796     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
    797 	                (op), (val), (val2), (val3), (val4), (val5))
    798 
    799 #define PUSH_LEAVE_EXPR(op, val, val2)					\
    800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
    801 
    802 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
    803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
    804 
    805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
    806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
    807 			(val), (val2), 0 ,NULL ,NULL)
    808 
    809 /************************************************************************
    810  *									*
    811  *		XPath object cache structures				*
    812  *									*
    813  ************************************************************************/
    814 
    815 /* #define XP_DEFAULT_CACHE_ON */
    816 
    817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
    818 
    819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
    820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
    821 struct _xmlXPathContextCache {
    822     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
    823     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
    824     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
    825     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
    826     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
    827     int maxNodeset;
    828     int maxString;
    829     int maxBoolean;
    830     int maxNumber;
    831     int maxMisc;
    832 #ifdef XP_DEBUG_OBJ_USAGE
    833     int dbgCachedAll;
    834     int dbgCachedNodeset;
    835     int dbgCachedString;
    836     int dbgCachedBool;
    837     int dbgCachedNumber;
    838     int dbgCachedPoint;
    839     int dbgCachedRange;
    840     int dbgCachedLocset;
    841     int dbgCachedUsers;
    842     int dbgCachedXSLTTree;
    843     int dbgCachedUndefined;
    844 
    845 
    846     int dbgReusedAll;
    847     int dbgReusedNodeset;
    848     int dbgReusedString;
    849     int dbgReusedBool;
    850     int dbgReusedNumber;
    851     int dbgReusedPoint;
    852     int dbgReusedRange;
    853     int dbgReusedLocset;
    854     int dbgReusedUsers;
    855     int dbgReusedXSLTTree;
    856     int dbgReusedUndefined;
    857 
    858 #endif
    859 };
    860 
    861 /************************************************************************
    862  *									*
    863  *		Debugging related functions				*
    864  *									*
    865  ************************************************************************/
    866 
    867 #define STRANGE							\
    868     xmlGenericError(xmlGenericErrorContext,				\
    869 	    "Internal error at %s:%d\n",				\
    870             __FILE__, __LINE__);
    871 
    872 #ifdef LIBXML_DEBUG_ENABLED
    873 static void
    874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
    875     int i;
    876     char shift[100];
    877 
    878     for (i = 0;((i < depth) && (i < 25));i++)
    879         shift[2 * i] = shift[2 * i + 1] = ' ';
    880     shift[2 * i] = shift[2 * i + 1] = 0;
    881     if (cur == NULL) {
    882 	fprintf(output, "%s", shift);
    883 	fprintf(output, "Node is NULL !\n");
    884 	return;
    885 
    886     }
    887 
    888     if ((cur->type == XML_DOCUMENT_NODE) ||
    889 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
    890 	fprintf(output, "%s", shift);
    891 	fprintf(output, " /\n");
    892     } else if (cur->type == XML_ATTRIBUTE_NODE)
    893 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
    894     else
    895 	xmlDebugDumpOneNode(output, cur, depth);
    896 }
    897 static void
    898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
    899     xmlNodePtr tmp;
    900     int i;
    901     char shift[100];
    902 
    903     for (i = 0;((i < depth) && (i < 25));i++)
    904         shift[2 * i] = shift[2 * i + 1] = ' ';
    905     shift[2 * i] = shift[2 * i + 1] = 0;
    906     if (cur == NULL) {
    907 	fprintf(output, "%s", shift);
    908 	fprintf(output, "Node is NULL !\n");
    909 	return;
    910 
    911     }
    912 
    913     while (cur != NULL) {
    914 	tmp = cur;
    915 	cur = cur->next;
    916 	xmlDebugDumpOneNode(output, tmp, depth);
    917     }
    918 }
    919 
    920 static void
    921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
    922     int i;
    923     char shift[100];
    924 
    925     for (i = 0;((i < depth) && (i < 25));i++)
    926         shift[2 * i] = shift[2 * i + 1] = ' ';
    927     shift[2 * i] = shift[2 * i + 1] = 0;
    928 
    929     if (cur == NULL) {
    930 	fprintf(output, "%s", shift);
    931 	fprintf(output, "NodeSet is NULL !\n");
    932 	return;
    933 
    934     }
    935 
    936     if (cur != NULL) {
    937 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
    938 	for (i = 0;i < cur->nodeNr;i++) {
    939 	    fprintf(output, "%s", shift);
    940 	    fprintf(output, "%d", i + 1);
    941 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
    942 	}
    943     }
    944 }
    945 
    946 static void
    947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
    948     int i;
    949     char shift[100];
    950 
    951     for (i = 0;((i < depth) && (i < 25));i++)
    952         shift[2 * i] = shift[2 * i + 1] = ' ';
    953     shift[2 * i] = shift[2 * i + 1] = 0;
    954 
    955     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
    956 	fprintf(output, "%s", shift);
    957 	fprintf(output, "Value Tree is NULL !\n");
    958 	return;
    959 
    960     }
    961 
    962     fprintf(output, "%s", shift);
    963     fprintf(output, "%d", i + 1);
    964     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
    965 }
    966 #if defined(LIBXML_XPTR_ENABLED)
    967 static void
    968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
    969     int i;
    970     char shift[100];
    971 
    972     for (i = 0;((i < depth) && (i < 25));i++)
    973         shift[2 * i] = shift[2 * i + 1] = ' ';
    974     shift[2 * i] = shift[2 * i + 1] = 0;
    975 
    976     if (cur == NULL) {
    977 	fprintf(output, "%s", shift);
    978 	fprintf(output, "LocationSet is NULL !\n");
    979 	return;
    980 
    981     }
    982 
    983     for (i = 0;i < cur->locNr;i++) {
    984 	fprintf(output, "%s", shift);
    985         fprintf(output, "%d : ", i + 1);
    986 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
    987     }
    988 }
    989 #endif /* LIBXML_XPTR_ENABLED */
    990 
    991 /**
    992  * xmlXPathDebugDumpObject:
    993  * @output:  the FILE * to dump the output
    994  * @cur:  the object to inspect
    995  * @depth:  indentation level
    996  *
    997  * Dump the content of the object for debugging purposes
    998  */
    999 void
   1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1001     int i;
   1002     char shift[100];
   1003 
   1004     if (output == NULL) return;
   1005 
   1006     for (i = 0;((i < depth) && (i < 25));i++)
   1007         shift[2 * i] = shift[2 * i + 1] = ' ';
   1008     shift[2 * i] = shift[2 * i + 1] = 0;
   1009 
   1010 
   1011     fprintf(output, "%s", shift);
   1012 
   1013     if (cur == NULL) {
   1014         fprintf(output, "Object is empty (NULL)\n");
   1015 	return;
   1016     }
   1017     switch(cur->type) {
   1018         case XPATH_UNDEFINED:
   1019 	    fprintf(output, "Object is uninitialized\n");
   1020 	    break;
   1021         case XPATH_NODESET:
   1022 	    fprintf(output, "Object is a Node Set :\n");
   1023 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1024 	    break;
   1025 	case XPATH_XSLT_TREE:
   1026 	    fprintf(output, "Object is an XSLT value tree :\n");
   1027 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1028 	    break;
   1029         case XPATH_BOOLEAN:
   1030 	    fprintf(output, "Object is a Boolean : ");
   1031 	    if (cur->boolval) fprintf(output, "true\n");
   1032 	    else fprintf(output, "false\n");
   1033 	    break;
   1034         case XPATH_NUMBER:
   1035 	    switch (xmlXPathIsInf(cur->floatval)) {
   1036 	    case 1:
   1037 		fprintf(output, "Object is a number : Infinity\n");
   1038 		break;
   1039 	    case -1:
   1040 		fprintf(output, "Object is a number : -Infinity\n");
   1041 		break;
   1042 	    default:
   1043 		if (xmlXPathIsNaN(cur->floatval)) {
   1044 		    fprintf(output, "Object is a number : NaN\n");
   1045 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1046 		    fprintf(output, "Object is a number : 0\n");
   1047 		} else {
   1048 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1049 		}
   1050 	    }
   1051 	    break;
   1052         case XPATH_STRING:
   1053 	    fprintf(output, "Object is a string : ");
   1054 	    xmlDebugDumpString(output, cur->stringval);
   1055 	    fprintf(output, "\n");
   1056 	    break;
   1057 	case XPATH_POINT:
   1058 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1059 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1060 	    fprintf(output, "\n");
   1061 	    break;
   1062 	case XPATH_RANGE:
   1063 	    if ((cur->user2 == NULL) ||
   1064 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1065 		fprintf(output, "Object is a collapsed range :\n");
   1066 		fprintf(output, "%s", shift);
   1067 		if (cur->index >= 0)
   1068 		    fprintf(output, "index %d in ", cur->index);
   1069 		fprintf(output, "node\n");
   1070 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1071 			              depth + 1);
   1072 	    } else  {
   1073 		fprintf(output, "Object is a range :\n");
   1074 		fprintf(output, "%s", shift);
   1075 		fprintf(output, "From ");
   1076 		if (cur->index >= 0)
   1077 		    fprintf(output, "index %d in ", cur->index);
   1078 		fprintf(output, "node\n");
   1079 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1080 			              depth + 1);
   1081 		fprintf(output, "%s", shift);
   1082 		fprintf(output, "To ");
   1083 		if (cur->index2 >= 0)
   1084 		    fprintf(output, "index %d in ", cur->index2);
   1085 		fprintf(output, "node\n");
   1086 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1087 			              depth + 1);
   1088 		fprintf(output, "\n");
   1089 	    }
   1090 	    break;
   1091 	case XPATH_LOCATIONSET:
   1092 #if defined(LIBXML_XPTR_ENABLED)
   1093 	    fprintf(output, "Object is a Location Set:\n");
   1094 	    xmlXPathDebugDumpLocationSet(output,
   1095 		    (xmlLocationSetPtr) cur->user, depth);
   1096 #endif
   1097 	    break;
   1098 	case XPATH_USERS:
   1099 	    fprintf(output, "Object is user defined\n");
   1100 	    break;
   1101     }
   1102 }
   1103 
   1104 static void
   1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1106 	                     xmlXPathStepOpPtr op, int depth) {
   1107     int i;
   1108     char shift[100];
   1109 
   1110     for (i = 0;((i < depth) && (i < 25));i++)
   1111         shift[2 * i] = shift[2 * i + 1] = ' ';
   1112     shift[2 * i] = shift[2 * i + 1] = 0;
   1113 
   1114     fprintf(output, "%s", shift);
   1115     if (op == NULL) {
   1116 	fprintf(output, "Step is NULL\n");
   1117 	return;
   1118     }
   1119     switch (op->op) {
   1120         case XPATH_OP_END:
   1121 	    fprintf(output, "END"); break;
   1122         case XPATH_OP_AND:
   1123 	    fprintf(output, "AND"); break;
   1124         case XPATH_OP_OR:
   1125 	    fprintf(output, "OR"); break;
   1126         case XPATH_OP_EQUAL:
   1127 	     if (op->value)
   1128 		 fprintf(output, "EQUAL =");
   1129 	     else
   1130 		 fprintf(output, "EQUAL !=");
   1131 	     break;
   1132         case XPATH_OP_CMP:
   1133 	     if (op->value)
   1134 		 fprintf(output, "CMP <");
   1135 	     else
   1136 		 fprintf(output, "CMP >");
   1137 	     if (!op->value2)
   1138 		 fprintf(output, "=");
   1139 	     break;
   1140         case XPATH_OP_PLUS:
   1141 	     if (op->value == 0)
   1142 		 fprintf(output, "PLUS -");
   1143 	     else if (op->value == 1)
   1144 		 fprintf(output, "PLUS +");
   1145 	     else if (op->value == 2)
   1146 		 fprintf(output, "PLUS unary -");
   1147 	     else if (op->value == 3)
   1148 		 fprintf(output, "PLUS unary - -");
   1149 	     break;
   1150         case XPATH_OP_MULT:
   1151 	     if (op->value == 0)
   1152 		 fprintf(output, "MULT *");
   1153 	     else if (op->value == 1)
   1154 		 fprintf(output, "MULT div");
   1155 	     else
   1156 		 fprintf(output, "MULT mod");
   1157 	     break;
   1158         case XPATH_OP_UNION:
   1159 	     fprintf(output, "UNION"); break;
   1160         case XPATH_OP_ROOT:
   1161 	     fprintf(output, "ROOT"); break;
   1162         case XPATH_OP_NODE:
   1163 	     fprintf(output, "NODE"); break;
   1164         case XPATH_OP_RESET:
   1165 	     fprintf(output, "RESET"); break;
   1166         case XPATH_OP_SORT:
   1167 	     fprintf(output, "SORT"); break;
   1168         case XPATH_OP_COLLECT: {
   1169 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1170 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1171 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1172 	    const xmlChar *prefix = op->value4;
   1173 	    const xmlChar *name = op->value5;
   1174 
   1175 	    fprintf(output, "COLLECT ");
   1176 	    switch (axis) {
   1177 		case AXIS_ANCESTOR:
   1178 		    fprintf(output, " 'ancestors' "); break;
   1179 		case AXIS_ANCESTOR_OR_SELF:
   1180 		    fprintf(output, " 'ancestors-or-self' "); break;
   1181 		case AXIS_ATTRIBUTE:
   1182 		    fprintf(output, " 'attributes' "); break;
   1183 		case AXIS_CHILD:
   1184 		    fprintf(output, " 'child' "); break;
   1185 		case AXIS_DESCENDANT:
   1186 		    fprintf(output, " 'descendant' "); break;
   1187 		case AXIS_DESCENDANT_OR_SELF:
   1188 		    fprintf(output, " 'descendant-or-self' "); break;
   1189 		case AXIS_FOLLOWING:
   1190 		    fprintf(output, " 'following' "); break;
   1191 		case AXIS_FOLLOWING_SIBLING:
   1192 		    fprintf(output, " 'following-siblings' "); break;
   1193 		case AXIS_NAMESPACE:
   1194 		    fprintf(output, " 'namespace' "); break;
   1195 		case AXIS_PARENT:
   1196 		    fprintf(output, " 'parent' "); break;
   1197 		case AXIS_PRECEDING:
   1198 		    fprintf(output, " 'preceding' "); break;
   1199 		case AXIS_PRECEDING_SIBLING:
   1200 		    fprintf(output, " 'preceding-sibling' "); break;
   1201 		case AXIS_SELF:
   1202 		    fprintf(output, " 'self' "); break;
   1203 	    }
   1204 	    switch (test) {
   1205                 case NODE_TEST_NONE:
   1206 		    fprintf(output, "'none' "); break;
   1207                 case NODE_TEST_TYPE:
   1208 		    fprintf(output, "'type' "); break;
   1209                 case NODE_TEST_PI:
   1210 		    fprintf(output, "'PI' "); break;
   1211                 case NODE_TEST_ALL:
   1212 		    fprintf(output, "'all' "); break;
   1213                 case NODE_TEST_NS:
   1214 		    fprintf(output, "'namespace' "); break;
   1215                 case NODE_TEST_NAME:
   1216 		    fprintf(output, "'name' "); break;
   1217 	    }
   1218 	    switch (type) {
   1219                 case NODE_TYPE_NODE:
   1220 		    fprintf(output, "'node' "); break;
   1221                 case NODE_TYPE_COMMENT:
   1222 		    fprintf(output, "'comment' "); break;
   1223                 case NODE_TYPE_TEXT:
   1224 		    fprintf(output, "'text' "); break;
   1225                 case NODE_TYPE_PI:
   1226 		    fprintf(output, "'PI' "); break;
   1227 	    }
   1228 	    if (prefix != NULL)
   1229 		fprintf(output, "%s:", prefix);
   1230 	    if (name != NULL)
   1231 		fprintf(output, "%s", (const char *) name);
   1232 	    break;
   1233 
   1234         }
   1235 	case XPATH_OP_VALUE: {
   1236 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1237 
   1238 	    fprintf(output, "ELEM ");
   1239 	    xmlXPathDebugDumpObject(output, object, 0);
   1240 	    goto finish;
   1241 	}
   1242 	case XPATH_OP_VARIABLE: {
   1243 	    const xmlChar *prefix = op->value5;
   1244 	    const xmlChar *name = op->value4;
   1245 
   1246 	    if (prefix != NULL)
   1247 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1248 	    else
   1249 		fprintf(output, "VARIABLE %s", name);
   1250 	    break;
   1251 	}
   1252 	case XPATH_OP_FUNCTION: {
   1253 	    int nbargs = op->value;
   1254 	    const xmlChar *prefix = op->value5;
   1255 	    const xmlChar *name = op->value4;
   1256 
   1257 	    if (prefix != NULL)
   1258 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1259 			prefix, name, nbargs);
   1260 	    else
   1261 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1262 	    break;
   1263 	}
   1264         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1265         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1266         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1267 #ifdef LIBXML_XPTR_ENABLED
   1268         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1269 #endif
   1270 	default:
   1271         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1272     }
   1273     fprintf(output, "\n");
   1274 finish:
   1275     if (op->ch1 >= 0)
   1276 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1277     if (op->ch2 >= 0)
   1278 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1279 }
   1280 
   1281 /**
   1282  * xmlXPathDebugDumpCompExpr:
   1283  * @output:  the FILE * for the output
   1284  * @comp:  the precompiled XPath expression
   1285  * @depth:  the indentation level.
   1286  *
   1287  * Dumps the tree of the compiled XPath expression.
   1288  */
   1289 void
   1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1291 	                  int depth) {
   1292     int i;
   1293     char shift[100];
   1294 
   1295     if ((output == NULL) || (comp == NULL)) return;
   1296 
   1297     for (i = 0;((i < depth) && (i < 25));i++)
   1298         shift[2 * i] = shift[2 * i + 1] = ' ';
   1299     shift[2 * i] = shift[2 * i + 1] = 0;
   1300 
   1301     fprintf(output, "%s", shift);
   1302 
   1303     fprintf(output, "Compiled Expression : %d elements\n",
   1304 	    comp->nbStep);
   1305     i = comp->last;
   1306     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1307 }
   1308 
   1309 #ifdef XP_DEBUG_OBJ_USAGE
   1310 
   1311 /*
   1312 * XPath object usage related debugging variables.
   1313 */
   1314 static int xmlXPathDebugObjCounterUndefined = 0;
   1315 static int xmlXPathDebugObjCounterNodeset = 0;
   1316 static int xmlXPathDebugObjCounterBool = 0;
   1317 static int xmlXPathDebugObjCounterNumber = 0;
   1318 static int xmlXPathDebugObjCounterString = 0;
   1319 static int xmlXPathDebugObjCounterPoint = 0;
   1320 static int xmlXPathDebugObjCounterRange = 0;
   1321 static int xmlXPathDebugObjCounterLocset = 0;
   1322 static int xmlXPathDebugObjCounterUsers = 0;
   1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1324 static int xmlXPathDebugObjCounterAll = 0;
   1325 
   1326 static int xmlXPathDebugObjTotalUndefined = 0;
   1327 static int xmlXPathDebugObjTotalNodeset = 0;
   1328 static int xmlXPathDebugObjTotalBool = 0;
   1329 static int xmlXPathDebugObjTotalNumber = 0;
   1330 static int xmlXPathDebugObjTotalString = 0;
   1331 static int xmlXPathDebugObjTotalPoint = 0;
   1332 static int xmlXPathDebugObjTotalRange = 0;
   1333 static int xmlXPathDebugObjTotalLocset = 0;
   1334 static int xmlXPathDebugObjTotalUsers = 0;
   1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1336 static int xmlXPathDebugObjTotalAll = 0;
   1337 
   1338 static int xmlXPathDebugObjMaxUndefined = 0;
   1339 static int xmlXPathDebugObjMaxNodeset = 0;
   1340 static int xmlXPathDebugObjMaxBool = 0;
   1341 static int xmlXPathDebugObjMaxNumber = 0;
   1342 static int xmlXPathDebugObjMaxString = 0;
   1343 static int xmlXPathDebugObjMaxPoint = 0;
   1344 static int xmlXPathDebugObjMaxRange = 0;
   1345 static int xmlXPathDebugObjMaxLocset = 0;
   1346 static int xmlXPathDebugObjMaxUsers = 0;
   1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1348 static int xmlXPathDebugObjMaxAll = 0;
   1349 
   1350 /* REVISIT TODO: Make this static when committing */
   1351 static void
   1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1353 {
   1354     if (ctxt != NULL) {
   1355 	if (ctxt->cache != NULL) {
   1356 	    xmlXPathContextCachePtr cache =
   1357 		(xmlXPathContextCachePtr) ctxt->cache;
   1358 
   1359 	    cache->dbgCachedAll = 0;
   1360 	    cache->dbgCachedNodeset = 0;
   1361 	    cache->dbgCachedString = 0;
   1362 	    cache->dbgCachedBool = 0;
   1363 	    cache->dbgCachedNumber = 0;
   1364 	    cache->dbgCachedPoint = 0;
   1365 	    cache->dbgCachedRange = 0;
   1366 	    cache->dbgCachedLocset = 0;
   1367 	    cache->dbgCachedUsers = 0;
   1368 	    cache->dbgCachedXSLTTree = 0;
   1369 	    cache->dbgCachedUndefined = 0;
   1370 
   1371 	    cache->dbgReusedAll = 0;
   1372 	    cache->dbgReusedNodeset = 0;
   1373 	    cache->dbgReusedString = 0;
   1374 	    cache->dbgReusedBool = 0;
   1375 	    cache->dbgReusedNumber = 0;
   1376 	    cache->dbgReusedPoint = 0;
   1377 	    cache->dbgReusedRange = 0;
   1378 	    cache->dbgReusedLocset = 0;
   1379 	    cache->dbgReusedUsers = 0;
   1380 	    cache->dbgReusedXSLTTree = 0;
   1381 	    cache->dbgReusedUndefined = 0;
   1382 	}
   1383     }
   1384 
   1385     xmlXPathDebugObjCounterUndefined = 0;
   1386     xmlXPathDebugObjCounterNodeset = 0;
   1387     xmlXPathDebugObjCounterBool = 0;
   1388     xmlXPathDebugObjCounterNumber = 0;
   1389     xmlXPathDebugObjCounterString = 0;
   1390     xmlXPathDebugObjCounterPoint = 0;
   1391     xmlXPathDebugObjCounterRange = 0;
   1392     xmlXPathDebugObjCounterLocset = 0;
   1393     xmlXPathDebugObjCounterUsers = 0;
   1394     xmlXPathDebugObjCounterXSLTTree = 0;
   1395     xmlXPathDebugObjCounterAll = 0;
   1396 
   1397     xmlXPathDebugObjTotalUndefined = 0;
   1398     xmlXPathDebugObjTotalNodeset = 0;
   1399     xmlXPathDebugObjTotalBool = 0;
   1400     xmlXPathDebugObjTotalNumber = 0;
   1401     xmlXPathDebugObjTotalString = 0;
   1402     xmlXPathDebugObjTotalPoint = 0;
   1403     xmlXPathDebugObjTotalRange = 0;
   1404     xmlXPathDebugObjTotalLocset = 0;
   1405     xmlXPathDebugObjTotalUsers = 0;
   1406     xmlXPathDebugObjTotalXSLTTree = 0;
   1407     xmlXPathDebugObjTotalAll = 0;
   1408 
   1409     xmlXPathDebugObjMaxUndefined = 0;
   1410     xmlXPathDebugObjMaxNodeset = 0;
   1411     xmlXPathDebugObjMaxBool = 0;
   1412     xmlXPathDebugObjMaxNumber = 0;
   1413     xmlXPathDebugObjMaxString = 0;
   1414     xmlXPathDebugObjMaxPoint = 0;
   1415     xmlXPathDebugObjMaxRange = 0;
   1416     xmlXPathDebugObjMaxLocset = 0;
   1417     xmlXPathDebugObjMaxUsers = 0;
   1418     xmlXPathDebugObjMaxXSLTTree = 0;
   1419     xmlXPathDebugObjMaxAll = 0;
   1420 
   1421 }
   1422 
   1423 static void
   1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1425 			      xmlXPathObjectType objType)
   1426 {
   1427     int isCached = 0;
   1428 
   1429     if (ctxt != NULL) {
   1430 	if (ctxt->cache != NULL) {
   1431 	    xmlXPathContextCachePtr cache =
   1432 		(xmlXPathContextCachePtr) ctxt->cache;
   1433 
   1434 	    isCached = 1;
   1435 
   1436 	    cache->dbgReusedAll++;
   1437 	    switch (objType) {
   1438 		case XPATH_UNDEFINED:
   1439 		    cache->dbgReusedUndefined++;
   1440 		    break;
   1441 		case XPATH_NODESET:
   1442 		    cache->dbgReusedNodeset++;
   1443 		    break;
   1444 		case XPATH_BOOLEAN:
   1445 		    cache->dbgReusedBool++;
   1446 		    break;
   1447 		case XPATH_NUMBER:
   1448 		    cache->dbgReusedNumber++;
   1449 		    break;
   1450 		case XPATH_STRING:
   1451 		    cache->dbgReusedString++;
   1452 		    break;
   1453 		case XPATH_POINT:
   1454 		    cache->dbgReusedPoint++;
   1455 		    break;
   1456 		case XPATH_RANGE:
   1457 		    cache->dbgReusedRange++;
   1458 		    break;
   1459 		case XPATH_LOCATIONSET:
   1460 		    cache->dbgReusedLocset++;
   1461 		    break;
   1462 		case XPATH_USERS:
   1463 		    cache->dbgReusedUsers++;
   1464 		    break;
   1465 		case XPATH_XSLT_TREE:
   1466 		    cache->dbgReusedXSLTTree++;
   1467 		    break;
   1468 		default:
   1469 		    break;
   1470 	    }
   1471 	}
   1472     }
   1473 
   1474     switch (objType) {
   1475 	case XPATH_UNDEFINED:
   1476 	    if (! isCached)
   1477 		xmlXPathDebugObjTotalUndefined++;
   1478 	    xmlXPathDebugObjCounterUndefined++;
   1479 	    if (xmlXPathDebugObjCounterUndefined >
   1480 		xmlXPathDebugObjMaxUndefined)
   1481 		xmlXPathDebugObjMaxUndefined =
   1482 		    xmlXPathDebugObjCounterUndefined;
   1483 	    break;
   1484 	case XPATH_NODESET:
   1485 	    if (! isCached)
   1486 		xmlXPathDebugObjTotalNodeset++;
   1487 	    xmlXPathDebugObjCounterNodeset++;
   1488 	    if (xmlXPathDebugObjCounterNodeset >
   1489 		xmlXPathDebugObjMaxNodeset)
   1490 		xmlXPathDebugObjMaxNodeset =
   1491 		    xmlXPathDebugObjCounterNodeset;
   1492 	    break;
   1493 	case XPATH_BOOLEAN:
   1494 	    if (! isCached)
   1495 		xmlXPathDebugObjTotalBool++;
   1496 	    xmlXPathDebugObjCounterBool++;
   1497 	    if (xmlXPathDebugObjCounterBool >
   1498 		xmlXPathDebugObjMaxBool)
   1499 		xmlXPathDebugObjMaxBool =
   1500 		    xmlXPathDebugObjCounterBool;
   1501 	    break;
   1502 	case XPATH_NUMBER:
   1503 	    if (! isCached)
   1504 		xmlXPathDebugObjTotalNumber++;
   1505 	    xmlXPathDebugObjCounterNumber++;
   1506 	    if (xmlXPathDebugObjCounterNumber >
   1507 		xmlXPathDebugObjMaxNumber)
   1508 		xmlXPathDebugObjMaxNumber =
   1509 		    xmlXPathDebugObjCounterNumber;
   1510 	    break;
   1511 	case XPATH_STRING:
   1512 	    if (! isCached)
   1513 		xmlXPathDebugObjTotalString++;
   1514 	    xmlXPathDebugObjCounterString++;
   1515 	    if (xmlXPathDebugObjCounterString >
   1516 		xmlXPathDebugObjMaxString)
   1517 		xmlXPathDebugObjMaxString =
   1518 		    xmlXPathDebugObjCounterString;
   1519 	    break;
   1520 	case XPATH_POINT:
   1521 	    if (! isCached)
   1522 		xmlXPathDebugObjTotalPoint++;
   1523 	    xmlXPathDebugObjCounterPoint++;
   1524 	    if (xmlXPathDebugObjCounterPoint >
   1525 		xmlXPathDebugObjMaxPoint)
   1526 		xmlXPathDebugObjMaxPoint =
   1527 		    xmlXPathDebugObjCounterPoint;
   1528 	    break;
   1529 	case XPATH_RANGE:
   1530 	    if (! isCached)
   1531 		xmlXPathDebugObjTotalRange++;
   1532 	    xmlXPathDebugObjCounterRange++;
   1533 	    if (xmlXPathDebugObjCounterRange >
   1534 		xmlXPathDebugObjMaxRange)
   1535 		xmlXPathDebugObjMaxRange =
   1536 		    xmlXPathDebugObjCounterRange;
   1537 	    break;
   1538 	case XPATH_LOCATIONSET:
   1539 	    if (! isCached)
   1540 		xmlXPathDebugObjTotalLocset++;
   1541 	    xmlXPathDebugObjCounterLocset++;
   1542 	    if (xmlXPathDebugObjCounterLocset >
   1543 		xmlXPathDebugObjMaxLocset)
   1544 		xmlXPathDebugObjMaxLocset =
   1545 		    xmlXPathDebugObjCounterLocset;
   1546 	    break;
   1547 	case XPATH_USERS:
   1548 	    if (! isCached)
   1549 		xmlXPathDebugObjTotalUsers++;
   1550 	    xmlXPathDebugObjCounterUsers++;
   1551 	    if (xmlXPathDebugObjCounterUsers >
   1552 		xmlXPathDebugObjMaxUsers)
   1553 		xmlXPathDebugObjMaxUsers =
   1554 		    xmlXPathDebugObjCounterUsers;
   1555 	    break;
   1556 	case XPATH_XSLT_TREE:
   1557 	    if (! isCached)
   1558 		xmlXPathDebugObjTotalXSLTTree++;
   1559 	    xmlXPathDebugObjCounterXSLTTree++;
   1560 	    if (xmlXPathDebugObjCounterXSLTTree >
   1561 		xmlXPathDebugObjMaxXSLTTree)
   1562 		xmlXPathDebugObjMaxXSLTTree =
   1563 		    xmlXPathDebugObjCounterXSLTTree;
   1564 	    break;
   1565 	default:
   1566 	    break;
   1567     }
   1568     if (! isCached)
   1569 	xmlXPathDebugObjTotalAll++;
   1570     xmlXPathDebugObjCounterAll++;
   1571     if (xmlXPathDebugObjCounterAll >
   1572 	xmlXPathDebugObjMaxAll)
   1573 	xmlXPathDebugObjMaxAll =
   1574 	    xmlXPathDebugObjCounterAll;
   1575 }
   1576 
   1577 static void
   1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1579 			      xmlXPathObjectType objType)
   1580 {
   1581     int isCached = 0;
   1582 
   1583     if (ctxt != NULL) {
   1584 	if (ctxt->cache != NULL) {
   1585 	    xmlXPathContextCachePtr cache =
   1586 		(xmlXPathContextCachePtr) ctxt->cache;
   1587 
   1588 	    isCached = 1;
   1589 
   1590 	    cache->dbgCachedAll++;
   1591 	    switch (objType) {
   1592 		case XPATH_UNDEFINED:
   1593 		    cache->dbgCachedUndefined++;
   1594 		    break;
   1595 		case XPATH_NODESET:
   1596 		    cache->dbgCachedNodeset++;
   1597 		    break;
   1598 		case XPATH_BOOLEAN:
   1599 		    cache->dbgCachedBool++;
   1600 		    break;
   1601 		case XPATH_NUMBER:
   1602 		    cache->dbgCachedNumber++;
   1603 		    break;
   1604 		case XPATH_STRING:
   1605 		    cache->dbgCachedString++;
   1606 		    break;
   1607 		case XPATH_POINT:
   1608 		    cache->dbgCachedPoint++;
   1609 		    break;
   1610 		case XPATH_RANGE:
   1611 		    cache->dbgCachedRange++;
   1612 		    break;
   1613 		case XPATH_LOCATIONSET:
   1614 		    cache->dbgCachedLocset++;
   1615 		    break;
   1616 		case XPATH_USERS:
   1617 		    cache->dbgCachedUsers++;
   1618 		    break;
   1619 		case XPATH_XSLT_TREE:
   1620 		    cache->dbgCachedXSLTTree++;
   1621 		    break;
   1622 		default:
   1623 		    break;
   1624 	    }
   1625 
   1626 	}
   1627     }
   1628     switch (objType) {
   1629 	case XPATH_UNDEFINED:
   1630 	    xmlXPathDebugObjCounterUndefined--;
   1631 	    break;
   1632 	case XPATH_NODESET:
   1633 	    xmlXPathDebugObjCounterNodeset--;
   1634 	    break;
   1635 	case XPATH_BOOLEAN:
   1636 	    xmlXPathDebugObjCounterBool--;
   1637 	    break;
   1638 	case XPATH_NUMBER:
   1639 	    xmlXPathDebugObjCounterNumber--;
   1640 	    break;
   1641 	case XPATH_STRING:
   1642 	    xmlXPathDebugObjCounterString--;
   1643 	    break;
   1644 	case XPATH_POINT:
   1645 	    xmlXPathDebugObjCounterPoint--;
   1646 	    break;
   1647 	case XPATH_RANGE:
   1648 	    xmlXPathDebugObjCounterRange--;
   1649 	    break;
   1650 	case XPATH_LOCATIONSET:
   1651 	    xmlXPathDebugObjCounterLocset--;
   1652 	    break;
   1653 	case XPATH_USERS:
   1654 	    xmlXPathDebugObjCounterUsers--;
   1655 	    break;
   1656 	case XPATH_XSLT_TREE:
   1657 	    xmlXPathDebugObjCounterXSLTTree--;
   1658 	    break;
   1659 	default:
   1660 	    break;
   1661     }
   1662     xmlXPathDebugObjCounterAll--;
   1663 }
   1664 
   1665 /* REVISIT TODO: Make this static when committing */
   1666 static void
   1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   1668 {
   1669     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   1670 	reqXSLTTree, reqUndefined;
   1671     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   1672 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   1673     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   1674 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   1675     int leftObjs = xmlXPathDebugObjCounterAll;
   1676 
   1677     reqAll = xmlXPathDebugObjTotalAll;
   1678     reqNodeset = xmlXPathDebugObjTotalNodeset;
   1679     reqString = xmlXPathDebugObjTotalString;
   1680     reqBool = xmlXPathDebugObjTotalBool;
   1681     reqNumber = xmlXPathDebugObjTotalNumber;
   1682     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   1683     reqUndefined = xmlXPathDebugObjTotalUndefined;
   1684 
   1685     printf("# XPath object usage:\n");
   1686 
   1687     if (ctxt != NULL) {
   1688 	if (ctxt->cache != NULL) {
   1689 	    xmlXPathContextCachePtr cache =
   1690 		(xmlXPathContextCachePtr) ctxt->cache;
   1691 
   1692 	    reAll = cache->dbgReusedAll;
   1693 	    reqAll += reAll;
   1694 	    reNodeset = cache->dbgReusedNodeset;
   1695 	    reqNodeset += reNodeset;
   1696 	    reString = cache->dbgReusedString;
   1697 	    reqString += reString;
   1698 	    reBool = cache->dbgReusedBool;
   1699 	    reqBool += reBool;
   1700 	    reNumber = cache->dbgReusedNumber;
   1701 	    reqNumber += reNumber;
   1702 	    reXSLTTree = cache->dbgReusedXSLTTree;
   1703 	    reqXSLTTree += reXSLTTree;
   1704 	    reUndefined = cache->dbgReusedUndefined;
   1705 	    reqUndefined += reUndefined;
   1706 
   1707 	    caAll = cache->dbgCachedAll;
   1708 	    caBool = cache->dbgCachedBool;
   1709 	    caNodeset = cache->dbgCachedNodeset;
   1710 	    caString = cache->dbgCachedString;
   1711 	    caNumber = cache->dbgCachedNumber;
   1712 	    caXSLTTree = cache->dbgCachedXSLTTree;
   1713 	    caUndefined = cache->dbgCachedUndefined;
   1714 
   1715 	    if (cache->nodesetObjs)
   1716 		leftObjs -= cache->nodesetObjs->number;
   1717 	    if (cache->stringObjs)
   1718 		leftObjs -= cache->stringObjs->number;
   1719 	    if (cache->booleanObjs)
   1720 		leftObjs -= cache->booleanObjs->number;
   1721 	    if (cache->numberObjs)
   1722 		leftObjs -= cache->numberObjs->number;
   1723 	    if (cache->miscObjs)
   1724 		leftObjs -= cache->miscObjs->number;
   1725 	}
   1726     }
   1727 
   1728     printf("# all\n");
   1729     printf("#   total  : %d\n", reqAll);
   1730     printf("#   left  : %d\n", leftObjs);
   1731     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   1732     printf("#   reused : %d\n", reAll);
   1733     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   1734 
   1735     printf("# node-sets\n");
   1736     printf("#   total  : %d\n", reqNodeset);
   1737     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   1738     printf("#   reused : %d\n", reNodeset);
   1739     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   1740 
   1741     printf("# strings\n");
   1742     printf("#   total  : %d\n", reqString);
   1743     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   1744     printf("#   reused : %d\n", reString);
   1745     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   1746 
   1747     printf("# booleans\n");
   1748     printf("#   total  : %d\n", reqBool);
   1749     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   1750     printf("#   reused : %d\n", reBool);
   1751     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   1752 
   1753     printf("# numbers\n");
   1754     printf("#   total  : %d\n", reqNumber);
   1755     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   1756     printf("#   reused : %d\n", reNumber);
   1757     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   1758 
   1759     printf("# XSLT result tree fragments\n");
   1760     printf("#   total  : %d\n", reqXSLTTree);
   1761     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   1762     printf("#   reused : %d\n", reXSLTTree);
   1763     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   1764 
   1765     printf("# undefined\n");
   1766     printf("#   total  : %d\n", reqUndefined);
   1767     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   1768     printf("#   reused : %d\n", reUndefined);
   1769     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   1770 
   1771 }
   1772 
   1773 #endif /* XP_DEBUG_OBJ_USAGE */
   1774 
   1775 #endif /* LIBXML_DEBUG_ENABLED */
   1776 
   1777 /************************************************************************
   1778  *									*
   1779  *			XPath object caching				*
   1780  *									*
   1781  ************************************************************************/
   1782 
   1783 /**
   1784  * xmlXPathNewCache:
   1785  *
   1786  * Create a new object cache
   1787  *
   1788  * Returns the xmlXPathCache just allocated.
   1789  */
   1790 static xmlXPathContextCachePtr
   1791 xmlXPathNewCache(void)
   1792 {
   1793     xmlXPathContextCachePtr ret;
   1794 
   1795     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   1796     if (ret == NULL) {
   1797         xmlXPathErrMemory(NULL, "creating object cache\n");
   1798 	return(NULL);
   1799     }
   1800     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   1801     ret->maxNodeset = 100;
   1802     ret->maxString = 100;
   1803     ret->maxBoolean = 100;
   1804     ret->maxNumber = 100;
   1805     ret->maxMisc = 100;
   1806     return(ret);
   1807 }
   1808 
   1809 static void
   1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   1811 {
   1812     int i;
   1813     xmlXPathObjectPtr obj;
   1814 
   1815     if (list == NULL)
   1816 	return;
   1817 
   1818     for (i = 0; i < list->number; i++) {
   1819 	obj = list->items[i];
   1820 	/*
   1821 	* Note that it is already assured that we don't need to
   1822 	* look out for namespace nodes in the node-set.
   1823 	*/
   1824 	if (obj->nodesetval != NULL) {
   1825 	    if (obj->nodesetval->nodeTab != NULL)
   1826 		xmlFree(obj->nodesetval->nodeTab);
   1827 	    xmlFree(obj->nodesetval);
   1828 	}
   1829 	xmlFree(obj);
   1830 #ifdef XP_DEBUG_OBJ_USAGE
   1831 	xmlXPathDebugObjCounterAll--;
   1832 #endif
   1833     }
   1834     xmlPointerListFree(list);
   1835 }
   1836 
   1837 static void
   1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   1839 {
   1840     if (cache == NULL)
   1841 	return;
   1842     if (cache->nodesetObjs)
   1843 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   1844     if (cache->stringObjs)
   1845 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   1846     if (cache->booleanObjs)
   1847 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   1848     if (cache->numberObjs)
   1849 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   1850     if (cache->miscObjs)
   1851 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   1852     xmlFree(cache);
   1853 }
   1854 
   1855 /**
   1856  * xmlXPathContextSetCache:
   1857  *
   1858  * @ctxt:  the XPath context
   1859  * @active: enables/disables (creates/frees) the cache
   1860  * @value: a value with semantics dependant on @options
   1861  * @options: options (currently only the value 0 is used)
   1862  *
   1863  * Creates/frees an object cache on the XPath context.
   1864  * If activates XPath objects (xmlXPathObject) will be cached internally
   1865  * to be reused.
   1866  * @options:
   1867  *   0: This will set the XPath object caching:
   1868  *      @value:
   1869  *        This will set the maximum number of XPath objects
   1870  *        to be cached per slot
   1871  *        There are 5 slots for: node-set, string, number, boolean, and
   1872  *        misc objects. Use <0 for the default number (100).
   1873  *   Other values for @options have currently no effect.
   1874  *
   1875  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   1876  */
   1877 int
   1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   1879 			int active,
   1880 			int value,
   1881 			int options)
   1882 {
   1883     if (ctxt == NULL)
   1884 	return(-1);
   1885     if (active) {
   1886 	xmlXPathContextCachePtr cache;
   1887 
   1888 	if (ctxt->cache == NULL) {
   1889 	    ctxt->cache = xmlXPathNewCache();
   1890 	    if (ctxt->cache == NULL)
   1891 		return(-1);
   1892 	}
   1893 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   1894 	if (options == 0) {
   1895 	    if (value < 0)
   1896 		value = 100;
   1897 	    cache->maxNodeset = value;
   1898 	    cache->maxString = value;
   1899 	    cache->maxNumber = value;
   1900 	    cache->maxBoolean = value;
   1901 	    cache->maxMisc = value;
   1902 	}
   1903     } else if (ctxt->cache != NULL) {
   1904 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   1905 	ctxt->cache = NULL;
   1906     }
   1907     return(0);
   1908 }
   1909 
   1910 /**
   1911  * xmlXPathCacheWrapNodeSet:
   1912  * @ctxt: the XPath context
   1913  * @val:  the NodePtr value
   1914  *
   1915  * This is the cached version of xmlXPathWrapNodeSet().
   1916  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   1917  *
   1918  * Returns the created or reused object.
   1919  */
   1920 static xmlXPathObjectPtr
   1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   1922 {
   1923     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1924 	xmlXPathContextCachePtr cache =
   1925 	    (xmlXPathContextCachePtr) ctxt->cache;
   1926 
   1927 	if ((cache->miscObjs != NULL) &&
   1928 	    (cache->miscObjs->number != 0))
   1929 	{
   1930 	    xmlXPathObjectPtr ret;
   1931 
   1932 	    ret = (xmlXPathObjectPtr)
   1933 		cache->miscObjs->items[--cache->miscObjs->number];
   1934 	    ret->type = XPATH_NODESET;
   1935 	    ret->nodesetval = val;
   1936 #ifdef XP_DEBUG_OBJ_USAGE
   1937 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   1938 #endif
   1939 	    return(ret);
   1940 	}
   1941     }
   1942 
   1943     return(xmlXPathWrapNodeSet(val));
   1944 
   1945 }
   1946 
   1947 /**
   1948  * xmlXPathCacheWrapString:
   1949  * @ctxt: the XPath context
   1950  * @val:  the xmlChar * value
   1951  *
   1952  * This is the cached version of xmlXPathWrapString().
   1953  * Wraps the @val string into an XPath object.
   1954  *
   1955  * Returns the created or reused object.
   1956  */
   1957 static xmlXPathObjectPtr
   1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   1959 {
   1960     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1961 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   1962 
   1963 	if ((cache->stringObjs != NULL) &&
   1964 	    (cache->stringObjs->number != 0))
   1965 	{
   1966 
   1967 	    xmlXPathObjectPtr ret;
   1968 
   1969 	    ret = (xmlXPathObjectPtr)
   1970 		cache->stringObjs->items[--cache->stringObjs->number];
   1971 	    ret->type = XPATH_STRING;
   1972 	    ret->stringval = val;
   1973 #ifdef XP_DEBUG_OBJ_USAGE
   1974 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1975 #endif
   1976 	    return(ret);
   1977 	} else if ((cache->miscObjs != NULL) &&
   1978 	    (cache->miscObjs->number != 0))
   1979 	{
   1980 	    xmlXPathObjectPtr ret;
   1981 	    /*
   1982 	    * Fallback to misc-cache.
   1983 	    */
   1984 	    ret = (xmlXPathObjectPtr)
   1985 		cache->miscObjs->items[--cache->miscObjs->number];
   1986 
   1987 	    ret->type = XPATH_STRING;
   1988 	    ret->stringval = val;
   1989 #ifdef XP_DEBUG_OBJ_USAGE
   1990 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1991 #endif
   1992 	    return(ret);
   1993 	}
   1994     }
   1995     return(xmlXPathWrapString(val));
   1996 }
   1997 
   1998 /**
   1999  * xmlXPathCacheNewNodeSet:
   2000  * @ctxt: the XPath context
   2001  * @val:  the NodePtr value
   2002  *
   2003  * This is the cached version of xmlXPathNewNodeSet().
   2004  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2005  * it with the single Node @val
   2006  *
   2007  * Returns the created or reused object.
   2008  */
   2009 static xmlXPathObjectPtr
   2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2011 {
   2012     if ((ctxt != NULL) && (ctxt->cache)) {
   2013 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2014 
   2015 	if ((cache->nodesetObjs != NULL) &&
   2016 	    (cache->nodesetObjs->number != 0))
   2017 	{
   2018 	    xmlXPathObjectPtr ret;
   2019 	    /*
   2020 	    * Use the nodset-cache.
   2021 	    */
   2022 	    ret = (xmlXPathObjectPtr)
   2023 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2024 	    ret->type = XPATH_NODESET;
   2025 	    ret->boolval = 0;
   2026 	    if (val) {
   2027 		if ((ret->nodesetval->nodeMax == 0) ||
   2028 		    (val->type == XML_NAMESPACE_DECL))
   2029 		{
   2030 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2031 		} else {
   2032 		    ret->nodesetval->nodeTab[0] = val;
   2033 		    ret->nodesetval->nodeNr = 1;
   2034 		}
   2035 	    }
   2036 #ifdef XP_DEBUG_OBJ_USAGE
   2037 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2038 #endif
   2039 	    return(ret);
   2040 	} else if ((cache->miscObjs != NULL) &&
   2041 	    (cache->miscObjs->number != 0))
   2042 	{
   2043 	    xmlXPathObjectPtr ret;
   2044 	    /*
   2045 	    * Fallback to misc-cache.
   2046 	    */
   2047 
   2048 	    ret = (xmlXPathObjectPtr)
   2049 		cache->miscObjs->items[--cache->miscObjs->number];
   2050 
   2051 	    ret->type = XPATH_NODESET;
   2052 	    ret->boolval = 0;
   2053 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2054 #ifdef XP_DEBUG_OBJ_USAGE
   2055 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2056 #endif
   2057 	    return(ret);
   2058 	}
   2059     }
   2060     return(xmlXPathNewNodeSet(val));
   2061 }
   2062 
   2063 /**
   2064  * xmlXPathCacheNewCString:
   2065  * @ctxt: the XPath context
   2066  * @val:  the char * value
   2067  *
   2068  * This is the cached version of xmlXPathNewCString().
   2069  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2070  *
   2071  * Returns the created or reused object.
   2072  */
   2073 static xmlXPathObjectPtr
   2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2075 {
   2076     if ((ctxt != NULL) && (ctxt->cache)) {
   2077 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2078 
   2079 	if ((cache->stringObjs != NULL) &&
   2080 	    (cache->stringObjs->number != 0))
   2081 	{
   2082 	    xmlXPathObjectPtr ret;
   2083 
   2084 	    ret = (xmlXPathObjectPtr)
   2085 		cache->stringObjs->items[--cache->stringObjs->number];
   2086 
   2087 	    ret->type = XPATH_STRING;
   2088 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2089 #ifdef XP_DEBUG_OBJ_USAGE
   2090 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2091 #endif
   2092 	    return(ret);
   2093 	} else if ((cache->miscObjs != NULL) &&
   2094 	    (cache->miscObjs->number != 0))
   2095 	{
   2096 	    xmlXPathObjectPtr ret;
   2097 
   2098 	    ret = (xmlXPathObjectPtr)
   2099 		cache->miscObjs->items[--cache->miscObjs->number];
   2100 
   2101 	    ret->type = XPATH_STRING;
   2102 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2103 #ifdef XP_DEBUG_OBJ_USAGE
   2104 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2105 #endif
   2106 	    return(ret);
   2107 	}
   2108     }
   2109     return(xmlXPathNewCString(val));
   2110 }
   2111 
   2112 /**
   2113  * xmlXPathCacheNewString:
   2114  * @ctxt: the XPath context
   2115  * @val:  the xmlChar * value
   2116  *
   2117  * This is the cached version of xmlXPathNewString().
   2118  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2119  *
   2120  * Returns the created or reused object.
   2121  */
   2122 static xmlXPathObjectPtr
   2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2124 {
   2125     if ((ctxt != NULL) && (ctxt->cache)) {
   2126 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2127 
   2128 	if ((cache->stringObjs != NULL) &&
   2129 	    (cache->stringObjs->number != 0))
   2130 	{
   2131 	    xmlXPathObjectPtr ret;
   2132 
   2133 	    ret = (xmlXPathObjectPtr)
   2134 		cache->stringObjs->items[--cache->stringObjs->number];
   2135 	    ret->type = XPATH_STRING;
   2136 	    if (val != NULL)
   2137 		ret->stringval = xmlStrdup(val);
   2138 	    else
   2139 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2140 #ifdef XP_DEBUG_OBJ_USAGE
   2141 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2142 #endif
   2143 	    return(ret);
   2144 	} else if ((cache->miscObjs != NULL) &&
   2145 	    (cache->miscObjs->number != 0))
   2146 	{
   2147 	    xmlXPathObjectPtr ret;
   2148 
   2149 	    ret = (xmlXPathObjectPtr)
   2150 		cache->miscObjs->items[--cache->miscObjs->number];
   2151 
   2152 	    ret->type = XPATH_STRING;
   2153 	    if (val != NULL)
   2154 		ret->stringval = xmlStrdup(val);
   2155 	    else
   2156 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2157 #ifdef XP_DEBUG_OBJ_USAGE
   2158 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2159 #endif
   2160 	    return(ret);
   2161 	}
   2162     }
   2163     return(xmlXPathNewString(val));
   2164 }
   2165 
   2166 /**
   2167  * xmlXPathCacheNewBoolean:
   2168  * @ctxt: the XPath context
   2169  * @val:  the boolean value
   2170  *
   2171  * This is the cached version of xmlXPathNewBoolean().
   2172  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2173  *
   2174  * Returns the created or reused object.
   2175  */
   2176 static xmlXPathObjectPtr
   2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2178 {
   2179     if ((ctxt != NULL) && (ctxt->cache)) {
   2180 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2181 
   2182 	if ((cache->booleanObjs != NULL) &&
   2183 	    (cache->booleanObjs->number != 0))
   2184 	{
   2185 	    xmlXPathObjectPtr ret;
   2186 
   2187 	    ret = (xmlXPathObjectPtr)
   2188 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2189 	    ret->type = XPATH_BOOLEAN;
   2190 	    ret->boolval = (val != 0);
   2191 #ifdef XP_DEBUG_OBJ_USAGE
   2192 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2193 #endif
   2194 	    return(ret);
   2195 	} else if ((cache->miscObjs != NULL) &&
   2196 	    (cache->miscObjs->number != 0))
   2197 	{
   2198 	    xmlXPathObjectPtr ret;
   2199 
   2200 	    ret = (xmlXPathObjectPtr)
   2201 		cache->miscObjs->items[--cache->miscObjs->number];
   2202 
   2203 	    ret->type = XPATH_BOOLEAN;
   2204 	    ret->boolval = (val != 0);
   2205 #ifdef XP_DEBUG_OBJ_USAGE
   2206 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2207 #endif
   2208 	    return(ret);
   2209 	}
   2210     }
   2211     return(xmlXPathNewBoolean(val));
   2212 }
   2213 
   2214 /**
   2215  * xmlXPathCacheNewFloat:
   2216  * @ctxt: the XPath context
   2217  * @val:  the double value
   2218  *
   2219  * This is the cached version of xmlXPathNewFloat().
   2220  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2221  *
   2222  * Returns the created or reused object.
   2223  */
   2224 static xmlXPathObjectPtr
   2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2226 {
   2227      if ((ctxt != NULL) && (ctxt->cache)) {
   2228 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2229 
   2230 	if ((cache->numberObjs != NULL) &&
   2231 	    (cache->numberObjs->number != 0))
   2232 	{
   2233 	    xmlXPathObjectPtr ret;
   2234 
   2235 	    ret = (xmlXPathObjectPtr)
   2236 		cache->numberObjs->items[--cache->numberObjs->number];
   2237 	    ret->type = XPATH_NUMBER;
   2238 	    ret->floatval = val;
   2239 #ifdef XP_DEBUG_OBJ_USAGE
   2240 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2241 #endif
   2242 	    return(ret);
   2243 	} else if ((cache->miscObjs != NULL) &&
   2244 	    (cache->miscObjs->number != 0))
   2245 	{
   2246 	    xmlXPathObjectPtr ret;
   2247 
   2248 	    ret = (xmlXPathObjectPtr)
   2249 		cache->miscObjs->items[--cache->miscObjs->number];
   2250 
   2251 	    ret->type = XPATH_NUMBER;
   2252 	    ret->floatval = val;
   2253 #ifdef XP_DEBUG_OBJ_USAGE
   2254 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2255 #endif
   2256 	    return(ret);
   2257 	}
   2258     }
   2259     return(xmlXPathNewFloat(val));
   2260 }
   2261 
   2262 /**
   2263  * xmlXPathCacheConvertString:
   2264  * @ctxt: the XPath context
   2265  * @val:  an XPath object
   2266  *
   2267  * This is the cached version of xmlXPathConvertString().
   2268  * Converts an existing object to its string() equivalent
   2269  *
   2270  * Returns a created or reused object, the old one is freed (cached)
   2271  *         (or the operation is done directly on @val)
   2272  */
   2273 
   2274 static xmlXPathObjectPtr
   2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2276     xmlChar *res = NULL;
   2277 
   2278     if (val == NULL)
   2279 	return(xmlXPathCacheNewCString(ctxt, ""));
   2280 
   2281     switch (val->type) {
   2282     case XPATH_UNDEFINED:
   2283 #ifdef DEBUG_EXPR
   2284 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2285 #endif
   2286 	break;
   2287     case XPATH_NODESET:
   2288     case XPATH_XSLT_TREE:
   2289 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2290 	break;
   2291     case XPATH_STRING:
   2292 	return(val);
   2293     case XPATH_BOOLEAN:
   2294 	res = xmlXPathCastBooleanToString(val->boolval);
   2295 	break;
   2296     case XPATH_NUMBER:
   2297 	res = xmlXPathCastNumberToString(val->floatval);
   2298 	break;
   2299     case XPATH_USERS:
   2300     case XPATH_POINT:
   2301     case XPATH_RANGE:
   2302     case XPATH_LOCATIONSET:
   2303 	TODO;
   2304 	break;
   2305     }
   2306     xmlXPathReleaseObject(ctxt, val);
   2307     if (res == NULL)
   2308 	return(xmlXPathCacheNewCString(ctxt, ""));
   2309     return(xmlXPathCacheWrapString(ctxt, res));
   2310 }
   2311 
   2312 /**
   2313  * xmlXPathCacheObjectCopy:
   2314  * @ctxt: the XPath context
   2315  * @val:  the original object
   2316  *
   2317  * This is the cached version of xmlXPathObjectCopy().
   2318  * Acquire a copy of a given object
   2319  *
   2320  * Returns a created or reused created object.
   2321  */
   2322 static xmlXPathObjectPtr
   2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2324 {
   2325     if (val == NULL)
   2326 	return(NULL);
   2327 
   2328     if (XP_HAS_CACHE(ctxt)) {
   2329 	switch (val->type) {
   2330 	    case XPATH_NODESET:
   2331 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2332 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2333 	    case XPATH_STRING:
   2334 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2335 	    case XPATH_BOOLEAN:
   2336 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2337 	    case XPATH_NUMBER:
   2338 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2339 	    default:
   2340 		break;
   2341 	}
   2342     }
   2343     return(xmlXPathObjectCopy(val));
   2344 }
   2345 
   2346 /**
   2347  * xmlXPathCacheConvertBoolean:
   2348  * @ctxt: the XPath context
   2349  * @val:  an XPath object
   2350  *
   2351  * This is the cached version of xmlXPathConvertBoolean().
   2352  * Converts an existing object to its boolean() equivalent
   2353  *
   2354  * Returns a created or reused object, the old one is freed (or the operation
   2355  *         is done directly on @val)
   2356  */
   2357 static xmlXPathObjectPtr
   2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2359     xmlXPathObjectPtr ret;
   2360 
   2361     if (val == NULL)
   2362 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2363     if (val->type == XPATH_BOOLEAN)
   2364 	return(val);
   2365     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2366     xmlXPathReleaseObject(ctxt, val);
   2367     return(ret);
   2368 }
   2369 
   2370 /**
   2371  * xmlXPathCacheConvertNumber:
   2372  * @ctxt: the XPath context
   2373  * @val:  an XPath object
   2374  *
   2375  * This is the cached version of xmlXPathConvertNumber().
   2376  * Converts an existing object to its number() equivalent
   2377  *
   2378  * Returns a created or reused object, the old one is freed (or the operation
   2379  *         is done directly on @val)
   2380  */
   2381 static xmlXPathObjectPtr
   2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2383     xmlXPathObjectPtr ret;
   2384 
   2385     if (val == NULL)
   2386 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2387     if (val->type == XPATH_NUMBER)
   2388 	return(val);
   2389     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2390     xmlXPathReleaseObject(ctxt, val);
   2391     return(ret);
   2392 }
   2393 
   2394 /************************************************************************
   2395  *									*
   2396  *		Parser stacks related functions and macros		*
   2397  *									*
   2398  ************************************************************************/
   2399 
   2400 /**
   2401  * valuePop:
   2402  * @ctxt: an XPath evaluation context
   2403  *
   2404  * Pops the top XPath object from the value stack
   2405  *
   2406  * Returns the XPath object just removed
   2407  */
   2408 xmlXPathObjectPtr
   2409 valuePop(xmlXPathParserContextPtr ctxt)
   2410 {
   2411     xmlXPathObjectPtr ret;
   2412 
   2413     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2414         return (NULL);
   2415     ctxt->valueNr--;
   2416     if (ctxt->valueNr > 0)
   2417         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2418     else
   2419         ctxt->value = NULL;
   2420     ret = ctxt->valueTab[ctxt->valueNr];
   2421     ctxt->valueTab[ctxt->valueNr] = NULL;
   2422     return (ret);
   2423 }
   2424 /**
   2425  * valuePush:
   2426  * @ctxt:  an XPath evaluation context
   2427  * @value:  the XPath object
   2428  *
   2429  * Pushes a new XPath object on top of the value stack
   2430  *
   2431  * returns the number of items on the value stack
   2432  */
   2433 int
   2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2435 {
   2436     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2437     if (ctxt->valueNr >= ctxt->valueMax) {
   2438         xmlXPathObjectPtr *tmp;
   2439 
   2440         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2441                                              2 * ctxt->valueMax *
   2442                                              sizeof(ctxt->valueTab[0]));
   2443         if (tmp == NULL) {
   2444             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
   2445             return (0);
   2446         }
   2447         ctxt->valueMax *= 2;
   2448 	ctxt->valueTab = tmp;
   2449     }
   2450     ctxt->valueTab[ctxt->valueNr] = value;
   2451     ctxt->value = value;
   2452     return (ctxt->valueNr++);
   2453 }
   2454 
   2455 /**
   2456  * xmlXPathPopBoolean:
   2457  * @ctxt:  an XPath parser context
   2458  *
   2459  * Pops a boolean from the stack, handling conversion if needed.
   2460  * Check error with #xmlXPathCheckError.
   2461  *
   2462  * Returns the boolean
   2463  */
   2464 int
   2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2466     xmlXPathObjectPtr obj;
   2467     int ret;
   2468 
   2469     obj = valuePop(ctxt);
   2470     if (obj == NULL) {
   2471 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2472 	return(0);
   2473     }
   2474     if (obj->type != XPATH_BOOLEAN)
   2475 	ret = xmlXPathCastToBoolean(obj);
   2476     else
   2477         ret = obj->boolval;
   2478     xmlXPathReleaseObject(ctxt->context, obj);
   2479     return(ret);
   2480 }
   2481 
   2482 /**
   2483  * xmlXPathPopNumber:
   2484  * @ctxt:  an XPath parser context
   2485  *
   2486  * Pops a number from the stack, handling conversion if needed.
   2487  * Check error with #xmlXPathCheckError.
   2488  *
   2489  * Returns the number
   2490  */
   2491 double
   2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2493     xmlXPathObjectPtr obj;
   2494     double ret;
   2495 
   2496     obj = valuePop(ctxt);
   2497     if (obj == NULL) {
   2498 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2499 	return(0);
   2500     }
   2501     if (obj->type != XPATH_NUMBER)
   2502 	ret = xmlXPathCastToNumber(obj);
   2503     else
   2504         ret = obj->floatval;
   2505     xmlXPathReleaseObject(ctxt->context, obj);
   2506     return(ret);
   2507 }
   2508 
   2509 /**
   2510  * xmlXPathPopString:
   2511  * @ctxt:  an XPath parser context
   2512  *
   2513  * Pops a string from the stack, handling conversion if needed.
   2514  * Check error with #xmlXPathCheckError.
   2515  *
   2516  * Returns the string
   2517  */
   2518 xmlChar *
   2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2520     xmlXPathObjectPtr obj;
   2521     xmlChar * ret;
   2522 
   2523     obj = valuePop(ctxt);
   2524     if (obj == NULL) {
   2525 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2526 	return(NULL);
   2527     }
   2528     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2529     /* TODO: needs refactoring somewhere else */
   2530     if (obj->stringval == ret)
   2531 	obj->stringval = NULL;
   2532     xmlXPathReleaseObject(ctxt->context, obj);
   2533     return(ret);
   2534 }
   2535 
   2536 /**
   2537  * xmlXPathPopNodeSet:
   2538  * @ctxt:  an XPath parser context
   2539  *
   2540  * Pops a node-set from the stack, handling conversion if needed.
   2541  * Check error with #xmlXPathCheckError.
   2542  *
   2543  * Returns the node-set
   2544  */
   2545 xmlNodeSetPtr
   2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2547     xmlXPathObjectPtr obj;
   2548     xmlNodeSetPtr ret;
   2549 
   2550     if (ctxt == NULL) return(NULL);
   2551     if (ctxt->value == NULL) {
   2552 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2553 	return(NULL);
   2554     }
   2555     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2556 	xmlXPathSetTypeError(ctxt);
   2557 	return(NULL);
   2558     }
   2559     obj = valuePop(ctxt);
   2560     ret = obj->nodesetval;
   2561 #if 0
   2562     /* to fix memory leak of not clearing obj->user */
   2563     if (obj->boolval && obj->user != NULL)
   2564         xmlFreeNodeList((xmlNodePtr) obj->user);
   2565 #endif
   2566     obj->nodesetval = NULL;
   2567     xmlXPathReleaseObject(ctxt->context, obj);
   2568     return(ret);
   2569 }
   2570 
   2571 /**
   2572  * xmlXPathPopExternal:
   2573  * @ctxt:  an XPath parser context
   2574  *
   2575  * Pops an external object from the stack, handling conversion if needed.
   2576  * Check error with #xmlXPathCheckError.
   2577  *
   2578  * Returns the object
   2579  */
   2580 void *
   2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   2582     xmlXPathObjectPtr obj;
   2583     void * ret;
   2584 
   2585     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   2586 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2587 	return(NULL);
   2588     }
   2589     if (ctxt->value->type != XPATH_USERS) {
   2590 	xmlXPathSetTypeError(ctxt);
   2591 	return(NULL);
   2592     }
   2593     obj = valuePop(ctxt);
   2594     ret = obj->user;
   2595     obj->user = NULL;
   2596     xmlXPathReleaseObject(ctxt->context, obj);
   2597     return(ret);
   2598 }
   2599 
   2600 /*
   2601  * Macros for accessing the content. Those should be used only by the parser,
   2602  * and not exported.
   2603  *
   2604  * Dirty macros, i.e. one need to make assumption on the context to use them
   2605  *
   2606  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   2607  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   2608  *           in ISO-Latin or UTF-8.
   2609  *           This should be used internally by the parser
   2610  *           only to compare to ASCII values otherwise it would break when
   2611  *           running with UTF-8 encoding.
   2612  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   2613  *           to compare on ASCII based substring.
   2614  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   2615  *           strings within the parser.
   2616  *   CURRENT Returns the current char value, with the full decoding of
   2617  *           UTF-8 if we are using this mode. It returns an int.
   2618  *   NEXT    Skip to the next character, this does the proper decoding
   2619  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   2620  *           It returns the pointer to the current xmlChar.
   2621  */
   2622 
   2623 #define CUR (*ctxt->cur)
   2624 #define SKIP(val) ctxt->cur += (val)
   2625 #define NXT(val) ctxt->cur[(val)]
   2626 #define CUR_PTR ctxt->cur
   2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   2628 
   2629 #define COPY_BUF(l,b,i,v)                                              \
   2630     if (l == 1) b[i++] = (xmlChar) v;                                  \
   2631     else i += xmlCopyChar(l,&b[i],v)
   2632 
   2633 #define NEXTL(l)  ctxt->cur += l
   2634 
   2635 #define SKIP_BLANKS							\
   2636     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   2637 
   2638 #define CURRENT (*ctxt->cur)
   2639 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   2640 
   2641 
   2642 #ifndef DBL_DIG
   2643 #define DBL_DIG 16
   2644 #endif
   2645 #ifndef DBL_EPSILON
   2646 #define DBL_EPSILON 1E-9
   2647 #endif
   2648 
   2649 #define UPPER_DOUBLE 1E9
   2650 #define LOWER_DOUBLE 1E-5
   2651 #define	LOWER_DOUBLE_EXP 5
   2652 
   2653 #define INTEGER_DIGITS DBL_DIG
   2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   2655 #define EXPONENT_DIGITS (3 + 2)
   2656 
   2657 /**
   2658  * xmlXPathFormatNumber:
   2659  * @number:     number to format
   2660  * @buffer:     output buffer
   2661  * @buffersize: size of output buffer
   2662  *
   2663  * Convert the number into a string representation.
   2664  */
   2665 static void
   2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   2667 {
   2668     switch (xmlXPathIsInf(number)) {
   2669     case 1:
   2670 	if (buffersize > (int)sizeof("Infinity"))
   2671 	    snprintf(buffer, buffersize, "Infinity");
   2672 	break;
   2673     case -1:
   2674 	if (buffersize > (int)sizeof("-Infinity"))
   2675 	    snprintf(buffer, buffersize, "-Infinity");
   2676 	break;
   2677     default:
   2678 	if (xmlXPathIsNaN(number)) {
   2679 	    if (buffersize > (int)sizeof("NaN"))
   2680 		snprintf(buffer, buffersize, "NaN");
   2681 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   2682 	    snprintf(buffer, buffersize, "0");
   2683 	} else if (number == ((int) number)) {
   2684 	    char work[30];
   2685 	    char *ptr, *cur;
   2686 	    int value = (int) number;
   2687 
   2688             ptr = &buffer[0];
   2689 	    if (value == 0) {
   2690 		*ptr++ = '0';
   2691 	    } else {
   2692 		snprintf(work, 29, "%d", value);
   2693 		cur = &work[0];
   2694 		while ((*cur) && (ptr - buffer < buffersize)) {
   2695 		    *ptr++ = *cur++;
   2696 		}
   2697 	    }
   2698 	    if (ptr - buffer < buffersize) {
   2699 		*ptr = 0;
   2700 	    } else if (buffersize > 0) {
   2701 		ptr--;
   2702 		*ptr = 0;
   2703 	    }
   2704 	} else {
   2705 	    /*
   2706 	      For the dimension of work,
   2707 	          DBL_DIG is number of significant digits
   2708 		  EXPONENT is only needed for "scientific notation"
   2709 	          3 is sign, decimal point, and terminating zero
   2710 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   2711 	      Note that this dimension is slightly (a few characters)
   2712 	      larger than actually necessary.
   2713 	    */
   2714 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   2715 	    int integer_place, fraction_place;
   2716 	    char *ptr;
   2717 	    char *after_fraction;
   2718 	    double absolute_value;
   2719 	    int size;
   2720 
   2721 	    absolute_value = fabs(number);
   2722 
   2723 	    /*
   2724 	     * First choose format - scientific or regular floating point.
   2725 	     * In either case, result is in work, and after_fraction points
   2726 	     * just past the fractional part.
   2727 	    */
   2728 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   2729 		  (absolute_value < LOWER_DOUBLE)) &&
   2730 		 (absolute_value != 0.0) ) {
   2731 		/* Use scientific notation */
   2732 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   2733 		fraction_place = DBL_DIG - 1;
   2734 		size = snprintf(work, sizeof(work),"%*.*e",
   2735 			 integer_place, fraction_place, number);
   2736 		while ((size > 0) && (work[size] != 'e')) size--;
   2737 
   2738 	    }
   2739 	    else {
   2740 		/* Use regular notation */
   2741 		if (absolute_value > 0.0) {
   2742 		    integer_place = (int)log10(absolute_value);
   2743 		    if (integer_place > 0)
   2744 		        fraction_place = DBL_DIG - integer_place - 1;
   2745 		    else
   2746 		        fraction_place = DBL_DIG - integer_place;
   2747 		} else {
   2748 		    fraction_place = 1;
   2749 		}
   2750 		size = snprintf(work, sizeof(work), "%0.*f",
   2751 				fraction_place, number);
   2752 	    }
   2753 
   2754 	    /* Remove fractional trailing zeroes */
   2755 	    after_fraction = work + size;
   2756 	    ptr = after_fraction;
   2757 	    while (*(--ptr) == '0')
   2758 		;
   2759 	    if (*ptr != '.')
   2760 	        ptr++;
   2761 	    while ((*ptr++ = *after_fraction++) != 0);
   2762 
   2763 	    /* Finally copy result back to caller */
   2764 	    size = strlen(work) + 1;
   2765 	    if (size > buffersize) {
   2766 		work[buffersize - 1] = 0;
   2767 		size = buffersize;
   2768 	    }
   2769 	    memmove(buffer, work, size);
   2770 	}
   2771 	break;
   2772     }
   2773 }
   2774 
   2775 
   2776 /************************************************************************
   2777  *									*
   2778  *			Routines to handle NodeSets			*
   2779  *									*
   2780  ************************************************************************/
   2781 
   2782 /**
   2783  * xmlXPathOrderDocElems:
   2784  * @doc:  an input document
   2785  *
   2786  * Call this routine to speed up XPath computation on static documents.
   2787  * This stamps all the element nodes with the document order
   2788  * Like for line information, the order is kept in the element->content
   2789  * field, the value stored is actually - the node number (starting at -1)
   2790  * to be able to differentiate from line numbers.
   2791  *
   2792  * Returns the number of elements found in the document or -1 in case
   2793  *    of error.
   2794  */
   2795 long
   2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
   2797     long count = 0;
   2798     xmlNodePtr cur;
   2799 
   2800     if (doc == NULL)
   2801 	return(-1);
   2802     cur = doc->children;
   2803     while (cur != NULL) {
   2804 	if (cur->type == XML_ELEMENT_NODE) {
   2805 	    cur->content = (void *) (-(++count));
   2806 	    if (cur->children != NULL) {
   2807 		cur = cur->children;
   2808 		continue;
   2809 	    }
   2810 	}
   2811 	if (cur->next != NULL) {
   2812 	    cur = cur->next;
   2813 	    continue;
   2814 	}
   2815 	do {
   2816 	    cur = cur->parent;
   2817 	    if (cur == NULL)
   2818 		break;
   2819 	    if (cur == (xmlNodePtr) doc) {
   2820 		cur = NULL;
   2821 		break;
   2822 	    }
   2823 	    if (cur->next != NULL) {
   2824 		cur = cur->next;
   2825 		break;
   2826 	    }
   2827 	} while (cur != NULL);
   2828     }
   2829     return(count);
   2830 }
   2831 
   2832 /**
   2833  * xmlXPathCmpNodes:
   2834  * @node1:  the first node
   2835  * @node2:  the second node
   2836  *
   2837  * Compare two nodes w.r.t document order
   2838  *
   2839  * Returns -2 in case of error 1 if first point < second point, 0 if
   2840  *         it's the same node, -1 otherwise
   2841  */
   2842 int
   2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   2844     int depth1, depth2;
   2845     int attr1 = 0, attr2 = 0;
   2846     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   2847     xmlNodePtr cur, root;
   2848 
   2849     if ((node1 == NULL) || (node2 == NULL))
   2850 	return(-2);
   2851     /*
   2852      * a couple of optimizations which will avoid computations in most cases
   2853      */
   2854     if (node1 == node2)		/* trivial case */
   2855 	return(0);
   2856     if (node1->type == XML_ATTRIBUTE_NODE) {
   2857 	attr1 = 1;
   2858 	attrNode1 = node1;
   2859 	node1 = node1->parent;
   2860     }
   2861     if (node2->type == XML_ATTRIBUTE_NODE) {
   2862 	attr2 = 1;
   2863 	attrNode2 = node2;
   2864 	node2 = node2->parent;
   2865     }
   2866     if (node1 == node2) {
   2867 	if (attr1 == attr2) {
   2868 	    /* not required, but we keep attributes in order */
   2869 	    if (attr1 != 0) {
   2870 	        cur = attrNode2->prev;
   2871 		while (cur != NULL) {
   2872 		    if (cur == attrNode1)
   2873 		        return (1);
   2874 		    cur = cur->prev;
   2875 		}
   2876 		return (-1);
   2877 	    }
   2878 	    return(0);
   2879 	}
   2880 	if (attr2 == 1)
   2881 	    return(1);
   2882 	return(-1);
   2883     }
   2884     if ((node1->type == XML_NAMESPACE_DECL) ||
   2885         (node2->type == XML_NAMESPACE_DECL))
   2886 	return(1);
   2887     if (node1 == node2->prev)
   2888 	return(1);
   2889     if (node1 == node2->next)
   2890 	return(-1);
   2891 
   2892     /*
   2893      * Speedup using document order if availble.
   2894      */
   2895     if ((node1->type == XML_ELEMENT_NODE) &&
   2896 	(node2->type == XML_ELEMENT_NODE) &&
   2897 	(0 > (long) node1->content) &&
   2898 	(0 > (long) node2->content) &&
   2899 	(node1->doc == node2->doc)) {
   2900 	long l1, l2;
   2901 
   2902 	l1 = -((long) node1->content);
   2903 	l2 = -((long) node2->content);
   2904 	if (l1 < l2)
   2905 	    return(1);
   2906 	if (l1 > l2)
   2907 	    return(-1);
   2908     }
   2909 
   2910     /*
   2911      * compute depth to root
   2912      */
   2913     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   2914 	if (cur == node1)
   2915 	    return(1);
   2916 	depth2++;
   2917     }
   2918     root = cur;
   2919     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   2920 	if (cur == node2)
   2921 	    return(-1);
   2922 	depth1++;
   2923     }
   2924     /*
   2925      * Distinct document (or distinct entities :-( ) case.
   2926      */
   2927     if (root != cur) {
   2928 	return(-2);
   2929     }
   2930     /*
   2931      * get the nearest common ancestor.
   2932      */
   2933     while (depth1 > depth2) {
   2934 	depth1--;
   2935 	node1 = node1->parent;
   2936     }
   2937     while (depth2 > depth1) {
   2938 	depth2--;
   2939 	node2 = node2->parent;
   2940     }
   2941     while (node1->parent != node2->parent) {
   2942 	node1 = node1->parent;
   2943 	node2 = node2->parent;
   2944 	/* should not happen but just in case ... */
   2945 	if ((node1 == NULL) || (node2 == NULL))
   2946 	    return(-2);
   2947     }
   2948     /*
   2949      * Find who's first.
   2950      */
   2951     if (node1 == node2->prev)
   2952 	return(1);
   2953     if (node1 == node2->next)
   2954 	return(-1);
   2955     /*
   2956      * Speedup using document order if availble.
   2957      */
   2958     if ((node1->type == XML_ELEMENT_NODE) &&
   2959 	(node2->type == XML_ELEMENT_NODE) &&
   2960 	(0 > (long) node1->content) &&
   2961 	(0 > (long) node2->content) &&
   2962 	(node1->doc == node2->doc)) {
   2963 	long l1, l2;
   2964 
   2965 	l1 = -((long) node1->content);
   2966 	l2 = -((long) node2->content);
   2967 	if (l1 < l2)
   2968 	    return(1);
   2969 	if (l1 > l2)
   2970 	    return(-1);
   2971     }
   2972 
   2973     for (cur = node1->next;cur != NULL;cur = cur->next)
   2974 	if (cur == node2)
   2975 	    return(1);
   2976     return(-1); /* assume there is no sibling list corruption */
   2977 }
   2978 
   2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   2980 /**
   2981  * xmlXPathCmpNodesExt:
   2982  * @node1:  the first node
   2983  * @node2:  the second node
   2984  *
   2985  * Compare two nodes w.r.t document order.
   2986  * This one is optimized for handling of non-element nodes.
   2987  *
   2988  * Returns -2 in case of error 1 if first point < second point, 0 if
   2989  *         it's the same node, -1 otherwise
   2990  */
   2991 static int
   2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
   2993     int depth1, depth2;
   2994     int misc = 0, precedence1 = 0, precedence2 = 0;
   2995     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
   2996     xmlNodePtr cur, root;
   2997     long l1, l2;
   2998 
   2999     if ((node1 == NULL) || (node2 == NULL))
   3000 	return(-2);
   3001 
   3002     if (node1 == node2)
   3003 	return(0);
   3004 
   3005     /*
   3006      * a couple of optimizations which will avoid computations in most cases
   3007      */
   3008     switch (node1->type) {
   3009 	case XML_ELEMENT_NODE:
   3010 	    if (node2->type == XML_ELEMENT_NODE) {
   3011 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
   3012 		    (0 > (long) node2->content) &&
   3013 		    (node1->doc == node2->doc))
   3014 		{
   3015 		    l1 = -((long) node1->content);
   3016 		    l2 = -((long) node2->content);
   3017 		    if (l1 < l2)
   3018 			return(1);
   3019 		    if (l1 > l2)
   3020 			return(-1);
   3021 		} else
   3022 		    goto turtle_comparison;
   3023 	    }
   3024 	    break;
   3025 	case XML_ATTRIBUTE_NODE:
   3026 	    precedence1 = 1; /* element is owner */
   3027 	    miscNode1 = node1;
   3028 	    node1 = node1->parent;
   3029 	    misc = 1;
   3030 	    break;
   3031 	case XML_TEXT_NODE:
   3032 	case XML_CDATA_SECTION_NODE:
   3033 	case XML_COMMENT_NODE:
   3034 	case XML_PI_NODE: {
   3035 	    miscNode1 = node1;
   3036 	    /*
   3037 	    * Find nearest element node.
   3038 	    */
   3039 	    if (node1->prev != NULL) {
   3040 		do {
   3041 		    node1 = node1->prev;
   3042 		    if (node1->type == XML_ELEMENT_NODE) {
   3043 			precedence1 = 3; /* element in prev-sibl axis */
   3044 			break;
   3045 		    }
   3046 		    if (node1->prev == NULL) {
   3047 			precedence1 = 2; /* element is parent */
   3048 			/*
   3049 			* URGENT TODO: Are there any cases, where the
   3050 			* parent of such a node is not an element node?
   3051 			*/
   3052 			node1 = node1->parent;
   3053 			break;
   3054 		    }
   3055 		} while (1);
   3056 	    } else {
   3057 		precedence1 = 2; /* element is parent */
   3058 		node1 = node1->parent;
   3059 	    }
   3060 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
   3061 		(0 <= (long) node1->content)) {
   3062 		/*
   3063 		* Fallback for whatever case.
   3064 		*/
   3065 		node1 = miscNode1;
   3066 		precedence1 = 0;
   3067 	    } else
   3068 		misc = 1;
   3069 	}
   3070 	    break;
   3071 	case XML_NAMESPACE_DECL:
   3072 	    /*
   3073 	    * TODO: why do we return 1 for namespace nodes?
   3074 	    */
   3075 	    return(1);
   3076 	default:
   3077 	    break;
   3078     }
   3079     switch (node2->type) {
   3080 	case XML_ELEMENT_NODE:
   3081 	    break;
   3082 	case XML_ATTRIBUTE_NODE:
   3083 	    precedence2 = 1; /* element is owner */
   3084 	    miscNode2 = node2;
   3085 	    node2 = node2->parent;
   3086 	    misc = 1;
   3087 	    break;
   3088 	case XML_TEXT_NODE:
   3089 	case XML_CDATA_SECTION_NODE:
   3090 	case XML_COMMENT_NODE:
   3091 	case XML_PI_NODE: {
   3092 	    miscNode2 = node2;
   3093 	    if (node2->prev != NULL) {
   3094 		do {
   3095 		    node2 = node2->prev;
   3096 		    if (node2->type == XML_ELEMENT_NODE) {
   3097 			precedence2 = 3; /* element in prev-sibl axis */
   3098 			break;
   3099 		    }
   3100 		    if (node2->prev == NULL) {
   3101 			precedence2 = 2; /* element is parent */
   3102 			node2 = node2->parent;
   3103 			break;
   3104 		    }
   3105 		} while (1);
   3106 	    } else {
   3107 		precedence2 = 2; /* element is parent */
   3108 		node2 = node2->parent;
   3109 	    }
   3110 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
   3111 		(0 <= (long) node1->content))
   3112 	    {
   3113 		node2 = miscNode2;
   3114 		precedence2 = 0;
   3115 	    } else
   3116 		misc = 1;
   3117 	}
   3118 	    break;
   3119 	case XML_NAMESPACE_DECL:
   3120 	    return(1);
   3121 	default:
   3122 	    break;
   3123     }
   3124     if (misc) {
   3125 	if (node1 == node2) {
   3126 	    if (precedence1 == precedence2) {
   3127 		/*
   3128 		* The ugly case; but normally there aren't many
   3129 		* adjacent non-element nodes around.
   3130 		*/
   3131 		cur = miscNode2->prev;
   3132 		while (cur != NULL) {
   3133 		    if (cur == miscNode1)
   3134 			return(1);
   3135 		    if (cur->type == XML_ELEMENT_NODE)
   3136 			return(-1);
   3137 		    cur = cur->prev;
   3138 		}
   3139 		return (-1);
   3140 	    } else {
   3141 		/*
   3142 		* Evaluate based on higher precedence wrt to the element.
   3143 		* TODO: This assumes attributes are sorted before content.
   3144 		*   Is this 100% correct?
   3145 		*/
   3146 		if (precedence1 < precedence2)
   3147 		    return(1);
   3148 		else
   3149 		    return(-1);
   3150 	    }
   3151 	}
   3152 	/*
   3153 	* Special case: One of the helper-elements is contained by the other.
   3154 	* <foo>
   3155 	*   <node2>
   3156 	*     <node1>Text-1(precedence1 == 2)</node1>
   3157 	*   </node2>
   3158 	*   Text-6(precedence2 == 3)
   3159 	* </foo>
   3160 	*/
   3161 	if ((precedence2 == 3) && (precedence1 > 1)) {
   3162 	    cur = node1->parent;
   3163 	    while (cur) {
   3164 		if (cur == node2)
   3165 		    return(1);
   3166 		cur = cur->parent;
   3167 	    }
   3168 	}
   3169 	if ((precedence1 == 3) && (precedence2 > 1)) {
   3170 	    cur = node2->parent;
   3171 	    while (cur) {
   3172 		if (cur == node1)
   3173 		    return(-1);
   3174 		cur = cur->parent;
   3175 	    }
   3176 	}
   3177     }
   3178 
   3179     /*
   3180      * Speedup using document order if availble.
   3181      */
   3182     if ((node1->type == XML_ELEMENT_NODE) &&
   3183 	(node2->type == XML_ELEMENT_NODE) &&
   3184 	(0 > (long) node1->content) &&
   3185 	(0 > (long) node2->content) &&
   3186 	(node1->doc == node2->doc)) {
   3187 
   3188 	l1 = -((long) node1->content);
   3189 	l2 = -((long) node2->content);
   3190 	if (l1 < l2)
   3191 	    return(1);
   3192 	if (l1 > l2)
   3193 	    return(-1);
   3194     }
   3195 
   3196 turtle_comparison:
   3197 
   3198     if (node1 == node2->prev)
   3199 	return(1);
   3200     if (node1 == node2->next)
   3201 	return(-1);
   3202     /*
   3203      * compute depth to root
   3204      */
   3205     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3206 	if (cur == node1)
   3207 	    return(1);
   3208 	depth2++;
   3209     }
   3210     root = cur;
   3211     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3212 	if (cur == node2)
   3213 	    return(-1);
   3214 	depth1++;
   3215     }
   3216     /*
   3217      * Distinct document (or distinct entities :-( ) case.
   3218      */
   3219     if (root != cur) {
   3220 	return(-2);
   3221     }
   3222     /*
   3223      * get the nearest common ancestor.
   3224      */
   3225     while (depth1 > depth2) {
   3226 	depth1--;
   3227 	node1 = node1->parent;
   3228     }
   3229     while (depth2 > depth1) {
   3230 	depth2--;
   3231 	node2 = node2->parent;
   3232     }
   3233     while (node1->parent != node2->parent) {
   3234 	node1 = node1->parent;
   3235 	node2 = node2->parent;
   3236 	/* should not happen but just in case ... */
   3237 	if ((node1 == NULL) || (node2 == NULL))
   3238 	    return(-2);
   3239     }
   3240     /*
   3241      * Find who's first.
   3242      */
   3243     if (node1 == node2->prev)
   3244 	return(1);
   3245     if (node1 == node2->next)
   3246 	return(-1);
   3247     /*
   3248      * Speedup using document order if availble.
   3249      */
   3250     if ((node1->type == XML_ELEMENT_NODE) &&
   3251 	(node2->type == XML_ELEMENT_NODE) &&
   3252 	(0 > (long) node1->content) &&
   3253 	(0 > (long) node2->content) &&
   3254 	(node1->doc == node2->doc)) {
   3255 
   3256 	l1 = -((long) node1->content);
   3257 	l2 = -((long) node2->content);
   3258 	if (l1 < l2)
   3259 	    return(1);
   3260 	if (l1 > l2)
   3261 	    return(-1);
   3262     }
   3263 
   3264     for (cur = node1->next;cur != NULL;cur = cur->next)
   3265 	if (cur == node2)
   3266 	    return(1);
   3267     return(-1); /* assume there is no sibling list corruption */
   3268 }
   3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
   3270 
   3271 /**
   3272  * xmlXPathNodeSetSort:
   3273  * @set:  the node set
   3274  *
   3275  * Sort the node set in document order
   3276  */
   3277 void
   3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3279     int i, j, incr, len;
   3280     xmlNodePtr tmp;
   3281 
   3282     if (set == NULL)
   3283 	return;
   3284 
   3285     /* Use Shell's sort to sort the node-set */
   3286     len = set->nodeNr;
   3287     for (incr = len / 2; incr > 0; incr /= 2) {
   3288 	for (i = incr; i < len; i++) {
   3289 	    j = i - incr;
   3290 	    while (j >= 0) {
   3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3292 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3293 			set->nodeTab[j + incr]) == -1)
   3294 #else
   3295 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3296 			set->nodeTab[j + incr]) == -1)
   3297 #endif
   3298 		{
   3299 		    tmp = set->nodeTab[j];
   3300 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3301 		    set->nodeTab[j + incr] = tmp;
   3302 		    j -= incr;
   3303 		} else
   3304 		    break;
   3305 	    }
   3306 	}
   3307     }
   3308 }
   3309 
   3310 #define XML_NODESET_DEFAULT	10
   3311 /**
   3312  * xmlXPathNodeSetDupNs:
   3313  * @node:  the parent node of the namespace XPath node
   3314  * @ns:  the libxml namespace declaration node.
   3315  *
   3316  * Namespace node in libxml don't match the XPath semantic. In a node set
   3317  * the namespace nodes are duplicated and the next pointer is set to the
   3318  * parent node in the XPath semantic.
   3319  *
   3320  * Returns the newly created object.
   3321  */
   3322 static xmlNodePtr
   3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3324     xmlNsPtr cur;
   3325 
   3326     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3327 	return(NULL);
   3328     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3329 	return((xmlNodePtr) ns);
   3330 
   3331     /*
   3332      * Allocate a new Namespace and fill the fields.
   3333      */
   3334     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3335     if (cur == NULL) {
   3336         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3337 	return(NULL);
   3338     }
   3339     memset(cur, 0, sizeof(xmlNs));
   3340     cur->type = XML_NAMESPACE_DECL;
   3341     if (ns->href != NULL)
   3342 	cur->href = xmlStrdup(ns->href);
   3343     if (ns->prefix != NULL)
   3344 	cur->prefix = xmlStrdup(ns->prefix);
   3345     cur->next = (xmlNsPtr) node;
   3346     return((xmlNodePtr) cur);
   3347 }
   3348 
   3349 /**
   3350  * xmlXPathNodeSetFreeNs:
   3351  * @ns:  the XPath namespace node found in a nodeset.
   3352  *
   3353  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3354  * the namespace nodes are duplicated and the next pointer is set to the
   3355  * parent node in the XPath semantic. Check if such a node needs to be freed
   3356  */
   3357 void
   3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3359     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3360 	return;
   3361 
   3362     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3363 	if (ns->href != NULL)
   3364 	    xmlFree((xmlChar *)ns->href);
   3365 	if (ns->prefix != NULL)
   3366 	    xmlFree((xmlChar *)ns->prefix);
   3367 	xmlFree(ns);
   3368     }
   3369 }
   3370 
   3371 /**
   3372  * xmlXPathNodeSetCreate:
   3373  * @val:  an initial xmlNodePtr, or NULL
   3374  *
   3375  * Create a new xmlNodeSetPtr of type double and of value @val
   3376  *
   3377  * Returns the newly created object.
   3378  */
   3379 xmlNodeSetPtr
   3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3381     xmlNodeSetPtr ret;
   3382 
   3383     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3384     if (ret == NULL) {
   3385         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3386 	return(NULL);
   3387     }
   3388     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3389     if (val != NULL) {
   3390         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3391 					     sizeof(xmlNodePtr));
   3392 	if (ret->nodeTab == NULL) {
   3393 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3394 	    xmlFree(ret);
   3395 	    return(NULL);
   3396 	}
   3397 	memset(ret->nodeTab, 0 ,
   3398 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3399         ret->nodeMax = XML_NODESET_DEFAULT;
   3400 	if (val->type == XML_NAMESPACE_DECL) {
   3401 	    xmlNsPtr ns = (xmlNsPtr) val;
   3402 
   3403 	    ret->nodeTab[ret->nodeNr++] =
   3404 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3405 	} else
   3406 	    ret->nodeTab[ret->nodeNr++] = val;
   3407     }
   3408     return(ret);
   3409 }
   3410 
   3411 /**
   3412  * xmlXPathNodeSetCreateSize:
   3413  * @size:  the initial size of the set
   3414  *
   3415  * Create a new xmlNodeSetPtr of type double and of value @val
   3416  *
   3417  * Returns the newly created object.
   3418  */
   3419 static xmlNodeSetPtr
   3420 xmlXPathNodeSetCreateSize(int size) {
   3421     xmlNodeSetPtr ret;
   3422 
   3423     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3424     if (ret == NULL) {
   3425         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3426 	return(NULL);
   3427     }
   3428     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3429     if (size < XML_NODESET_DEFAULT)
   3430 	size = XML_NODESET_DEFAULT;
   3431     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3432     if (ret->nodeTab == NULL) {
   3433 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3434 	xmlFree(ret);
   3435 	return(NULL);
   3436     }
   3437     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3438     ret->nodeMax = size;
   3439     return(ret);
   3440 }
   3441 
   3442 /**
   3443  * xmlXPathNodeSetContains:
   3444  * @cur:  the node-set
   3445  * @val:  the node
   3446  *
   3447  * checks whether @cur contains @val
   3448  *
   3449  * Returns true (1) if @cur contains @val, false (0) otherwise
   3450  */
   3451 int
   3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3453     int i;
   3454 
   3455     if ((cur == NULL) || (val == NULL)) return(0);
   3456     if (val->type == XML_NAMESPACE_DECL) {
   3457 	for (i = 0; i < cur->nodeNr; i++) {
   3458 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3459 		xmlNsPtr ns1, ns2;
   3460 
   3461 		ns1 = (xmlNsPtr) val;
   3462 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3463 		if (ns1 == ns2)
   3464 		    return(1);
   3465 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3466 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3467 		    return(1);
   3468 	    }
   3469 	}
   3470     } else {
   3471 	for (i = 0; i < cur->nodeNr; i++) {
   3472 	    if (cur->nodeTab[i] == val)
   3473 		return(1);
   3474 	}
   3475     }
   3476     return(0);
   3477 }
   3478 
   3479 /**
   3480  * xmlXPathNodeSetAddNs:
   3481  * @cur:  the initial node set
   3482  * @node:  the hosting node
   3483  * @ns:  a the namespace node
   3484  *
   3485  * add a new namespace node to an existing NodeSet
   3486  */
   3487 void
   3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3489     int i;
   3490 
   3491 
   3492     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3493         (ns->type != XML_NAMESPACE_DECL) ||
   3494 	(node->type != XML_ELEMENT_NODE))
   3495 	return;
   3496 
   3497     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3498     /*
   3499      * prevent duplicates
   3500      */
   3501     for (i = 0;i < cur->nodeNr;i++) {
   3502         if ((cur->nodeTab[i] != NULL) &&
   3503 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3504 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3505 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3506 	    return;
   3507     }
   3508 
   3509     /*
   3510      * grow the nodeTab if needed
   3511      */
   3512     if (cur->nodeMax == 0) {
   3513         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3514 					     sizeof(xmlNodePtr));
   3515 	if (cur->nodeTab == NULL) {
   3516 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3517 	    return;
   3518 	}
   3519 	memset(cur->nodeTab, 0 ,
   3520 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3521         cur->nodeMax = XML_NODESET_DEFAULT;
   3522     } else if (cur->nodeNr == cur->nodeMax) {
   3523         xmlNodePtr *temp;
   3524 
   3525         cur->nodeMax *= 2;
   3526 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3527 				      sizeof(xmlNodePtr));
   3528 	if (temp == NULL) {
   3529 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3530 	    return;
   3531 	}
   3532 	cur->nodeTab = temp;
   3533     }
   3534     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3535 }
   3536 
   3537 /**
   3538  * xmlXPathNodeSetAdd:
   3539  * @cur:  the initial node set
   3540  * @val:  a new xmlNodePtr
   3541  *
   3542  * add a new xmlNodePtr to an existing NodeSet
   3543  */
   3544 void
   3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3546     int i;
   3547 
   3548     if ((cur == NULL) || (val == NULL)) return;
   3549 
   3550 #if 0
   3551     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3552 	return;	/* an XSLT fake node */
   3553 #endif
   3554 
   3555     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3556     /*
   3557      * prevent duplcates
   3558      */
   3559     for (i = 0;i < cur->nodeNr;i++)
   3560         if (cur->nodeTab[i] == val) return;
   3561 
   3562     /*
   3563      * grow the nodeTab if needed
   3564      */
   3565     if (cur->nodeMax == 0) {
   3566         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3567 					     sizeof(xmlNodePtr));
   3568 	if (cur->nodeTab == NULL) {
   3569 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3570 	    return;
   3571 	}
   3572 	memset(cur->nodeTab, 0 ,
   3573 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3574         cur->nodeMax = XML_NODESET_DEFAULT;
   3575     } else if (cur->nodeNr == cur->nodeMax) {
   3576         xmlNodePtr *temp;
   3577 
   3578         cur->nodeMax *= 2;
   3579 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3580 				      sizeof(xmlNodePtr));
   3581 	if (temp == NULL) {
   3582 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3583 	    return;
   3584 	}
   3585 	cur->nodeTab = temp;
   3586     }
   3587     if (val->type == XML_NAMESPACE_DECL) {
   3588 	xmlNsPtr ns = (xmlNsPtr) val;
   3589 
   3590 	cur->nodeTab[cur->nodeNr++] =
   3591 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3592     } else
   3593 	cur->nodeTab[cur->nodeNr++] = val;
   3594 }
   3595 
   3596 /**
   3597  * xmlXPathNodeSetAddUnique:
   3598  * @cur:  the initial node set
   3599  * @val:  a new xmlNodePtr
   3600  *
   3601  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3602  * when we are sure the node is not already in the set.
   3603  */
   3604 void
   3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3606     if ((cur == NULL) || (val == NULL)) return;
   3607 
   3608 #if 0
   3609     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3610 	return;	/* an XSLT fake node */
   3611 #endif
   3612 
   3613     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3614     /*
   3615      * grow the nodeTab if needed
   3616      */
   3617     if (cur->nodeMax == 0) {
   3618         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3619 					     sizeof(xmlNodePtr));
   3620 	if (cur->nodeTab == NULL) {
   3621 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3622 	    return;
   3623 	}
   3624 	memset(cur->nodeTab, 0 ,
   3625 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3626         cur->nodeMax = XML_NODESET_DEFAULT;
   3627     } else if (cur->nodeNr == cur->nodeMax) {
   3628         xmlNodePtr *temp;
   3629 
   3630         cur->nodeMax *= 2;
   3631 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
   3632 				      sizeof(xmlNodePtr));
   3633 	if (temp == NULL) {
   3634 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3635 	    return;
   3636 	}
   3637 	cur->nodeTab = temp;
   3638     }
   3639     if (val->type == XML_NAMESPACE_DECL) {
   3640 	xmlNsPtr ns = (xmlNsPtr) val;
   3641 
   3642 	cur->nodeTab[cur->nodeNr++] =
   3643 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3644     } else
   3645 	cur->nodeTab[cur->nodeNr++] = val;
   3646 }
   3647 
   3648 /**
   3649  * xmlXPathNodeSetMerge:
   3650  * @val1:  the first NodeSet or NULL
   3651  * @val2:  the second NodeSet
   3652  *
   3653  * Merges two nodesets, all nodes from @val2 are added to @val1
   3654  * if @val1 is NULL, a new set is created and copied from @val2
   3655  *
   3656  * Returns @val1 once extended or NULL in case of error.
   3657  */
   3658 xmlNodeSetPtr
   3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3660     int i, j, initNr, skip;
   3661     xmlNodePtr n1, n2;
   3662 
   3663     if (val2 == NULL) return(val1);
   3664     if (val1 == NULL) {
   3665 	val1 = xmlXPathNodeSetCreate(NULL);
   3666     if (val1 == NULL)
   3667         return (NULL);
   3668 #if 0
   3669 	/*
   3670 	* TODO: The optimization won't work in every case, since
   3671 	*  those nasty namespace nodes need to be added with
   3672 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3673 	*  memcpy is not possible.
   3674 	*  If there was a flag on the nodesetval, indicating that
   3675 	*  some temporary nodes are in, that would be helpfull.
   3676 	*/
   3677 	/*
   3678 	* Optimization: Create an equally sized node-set
   3679 	* and memcpy the content.
   3680 	*/
   3681 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3682 	if (val1 == NULL)
   3683 	    return(NULL);
   3684 	if (val2->nodeNr != 0) {
   3685 	    if (val2->nodeNr == 1)
   3686 		*(val1->nodeTab) = *(val2->nodeTab);
   3687 	    else {
   3688 		memcpy(val1->nodeTab, val2->nodeTab,
   3689 		    val2->nodeNr * sizeof(xmlNodePtr));
   3690 	    }
   3691 	    val1->nodeNr = val2->nodeNr;
   3692 	}
   3693 	return(val1);
   3694 #endif
   3695     }
   3696 
   3697     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3698     initNr = val1->nodeNr;
   3699 
   3700     for (i = 0;i < val2->nodeNr;i++) {
   3701 	n2 = val2->nodeTab[i];
   3702 	/*
   3703 	 * check against duplicates
   3704 	 */
   3705 	skip = 0;
   3706 	for (j = 0; j < initNr; j++) {
   3707 	    n1 = val1->nodeTab[j];
   3708 	    if (n1 == n2) {
   3709 		skip = 1;
   3710 		break;
   3711 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3712 		       (n2->type == XML_NAMESPACE_DECL)) {
   3713 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3714 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3715 			((xmlNsPtr) n2)->prefix)))
   3716 		{
   3717 		    skip = 1;
   3718 		    break;
   3719 		}
   3720 	    }
   3721 	}
   3722 	if (skip)
   3723 	    continue;
   3724 
   3725 	/*
   3726 	 * grow the nodeTab if needed
   3727 	 */
   3728 	if (val1->nodeMax == 0) {
   3729 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3730 						    sizeof(xmlNodePtr));
   3731 	    if (val1->nodeTab == NULL) {
   3732 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3733 		return(NULL);
   3734 	    }
   3735 	    memset(val1->nodeTab, 0 ,
   3736 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3737 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3738 	} else if (val1->nodeNr == val1->nodeMax) {
   3739 	    xmlNodePtr *temp;
   3740 
   3741 	    val1->nodeMax *= 2;
   3742 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3743 					     sizeof(xmlNodePtr));
   3744 	    if (temp == NULL) {
   3745 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3746 		return(NULL);
   3747 	    }
   3748 	    val1->nodeTab = temp;
   3749 	}
   3750 	if (n2->type == XML_NAMESPACE_DECL) {
   3751 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3752 
   3753 	    val1->nodeTab[val1->nodeNr++] =
   3754 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3755 	} else
   3756 	    val1->nodeTab[val1->nodeNr++] = n2;
   3757     }
   3758 
   3759     return(val1);
   3760 }
   3761 
   3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3763 /**
   3764  * xmlXPathNodeSetMergeUnique:
   3765  * @val1:  the first NodeSet or NULL
   3766  * @val2:  the second NodeSet
   3767  *
   3768  * Merges two nodesets, all nodes from @val2 are added to @val1
   3769  * if @val1 is NULL, a new set is created and copied from @val2
   3770  *
   3771  * Returns @val1 once extended or NULL in case of error.
   3772  */
   3773 static xmlNodeSetPtr
   3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3775     int i;
   3776 
   3777     if (val2 == NULL) return(val1);
   3778     if (val1 == NULL) {
   3779 	val1 = xmlXPathNodeSetCreate(NULL);
   3780     }
   3781     if (val1 == NULL)
   3782         return (NULL);
   3783 
   3784     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3785 
   3786     for (i = 0;i < val2->nodeNr;i++) {
   3787 	/*
   3788 	 * grow the nodeTab if needed
   3789 	 */
   3790 	if (val1->nodeMax == 0) {
   3791 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3792 						    sizeof(xmlNodePtr));
   3793 	    if (val1->nodeTab == NULL) {
   3794 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3795 		return(NULL);
   3796 	    }
   3797 	    memset(val1->nodeTab, 0 ,
   3798 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3799 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3800 	} else if (val1->nodeNr == val1->nodeMax) {
   3801 	    xmlNodePtr *temp;
   3802 
   3803 	    val1->nodeMax *= 2;
   3804 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3805 					     sizeof(xmlNodePtr));
   3806 	    if (temp == NULL) {
   3807 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3808 		return(NULL);
   3809 	    }
   3810 	    val1->nodeTab = temp;
   3811 	}
   3812 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3813 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
   3814 
   3815 	    val1->nodeTab[val1->nodeNr++] =
   3816 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3817 	} else
   3818 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
   3819     }
   3820 
   3821     return(val1);
   3822 }
   3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3824 
   3825 /**
   3826  * xmlXPathNodeSetMergeAndClear:
   3827  * @set1:  the first NodeSet or NULL
   3828  * @set2:  the second NodeSet
   3829  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3830  *
   3831  * Merges two nodesets, all nodes from @set2 are added to @set1
   3832  * if @set1 is NULL, a new set is created and copied from @set2.
   3833  * Checks for duplicate nodes. Clears set2.
   3834  *
   3835  * Returns @set1 once extended or NULL in case of error.
   3836  */
   3837 static xmlNodeSetPtr
   3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3839 			     int hasNullEntries)
   3840 {
   3841     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3842 	/*
   3843 	* Note that doing a memcpy of the list, namespace nodes are
   3844 	* just assigned to set1, since set2 is cleared anyway.
   3845 	*/
   3846 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3847 	if (set1 == NULL)
   3848 	    return(NULL);
   3849 	if (set2->nodeNr != 0) {
   3850 	    memcpy(set1->nodeTab, set2->nodeTab,
   3851 		set2->nodeNr * sizeof(xmlNodePtr));
   3852 	    set1->nodeNr = set2->nodeNr;
   3853 	}
   3854     } else {
   3855 	int i, j, initNbSet1;
   3856 	xmlNodePtr n1, n2;
   3857 
   3858 	if (set1 == NULL)
   3859             set1 = xmlXPathNodeSetCreate(NULL);
   3860         if (set1 == NULL)
   3861             return (NULL);
   3862 
   3863 	initNbSet1 = set1->nodeNr;
   3864 	for (i = 0;i < set2->nodeNr;i++) {
   3865 	    n2 = set2->nodeTab[i];
   3866 	    /*
   3867 	    * Skip NULLed entries.
   3868 	    */
   3869 	    if (n2 == NULL)
   3870 		continue;
   3871 	    /*
   3872 	    * Skip duplicates.
   3873 	    */
   3874 	    for (j = 0; j < initNbSet1; j++) {
   3875 		n1 = set1->nodeTab[j];
   3876 		if (n1 == n2) {
   3877 		    goto skip_node;
   3878 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3879 		    (n2->type == XML_NAMESPACE_DECL))
   3880 		{
   3881 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3882 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3883 			((xmlNsPtr) n2)->prefix)))
   3884 		    {
   3885 			/*
   3886 			* Free the namespace node.
   3887 			*/
   3888 			set2->nodeTab[i] = NULL;
   3889 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3890 			goto skip_node;
   3891 		    }
   3892 		}
   3893 	    }
   3894 	    /*
   3895 	    * grow the nodeTab if needed
   3896 	    */
   3897 	    if (set1->nodeMax == 0) {
   3898 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3899 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3900 		if (set1->nodeTab == NULL) {
   3901 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3902 		    return(NULL);
   3903 		}
   3904 		memset(set1->nodeTab, 0,
   3905 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3906 		set1->nodeMax = XML_NODESET_DEFAULT;
   3907 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3908 		xmlNodePtr *temp;
   3909 
   3910 		set1->nodeMax *= 2;
   3911 		temp = (xmlNodePtr *) xmlRealloc(
   3912 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
   3913 		if (temp == NULL) {
   3914 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3915 		    return(NULL);
   3916 		}
   3917 		set1->nodeTab = temp;
   3918 	    }
   3919 	    if (n2->type == XML_NAMESPACE_DECL) {
   3920 		xmlNsPtr ns = (xmlNsPtr) n2;
   3921 
   3922 		set1->nodeTab[set1->nodeNr++] =
   3923 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3924 	    } else
   3925 		set1->nodeTab[set1->nodeNr++] = n2;
   3926 skip_node:
   3927 	    {}
   3928 	}
   3929     }
   3930     set2->nodeNr = 0;
   3931     return(set1);
   3932 }
   3933 
   3934 /**
   3935  * xmlXPathNodeSetMergeAndClearNoDupls:
   3936  * @set1:  the first NodeSet or NULL
   3937  * @set2:  the second NodeSet
   3938  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3939  *
   3940  * Merges two nodesets, all nodes from @set2 are added to @set1
   3941  * if @set1 is NULL, a new set is created and copied from @set2.
   3942  * Doesn't chack for duplicate nodes. Clears set2.
   3943  *
   3944  * Returns @set1 once extended or NULL in case of error.
   3945  */
   3946 static xmlNodeSetPtr
   3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3948 				    int hasNullEntries)
   3949 {
   3950     if (set2 == NULL)
   3951 	return(set1);
   3952     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3953 	/*
   3954 	* Note that doing a memcpy of the list, namespace nodes are
   3955 	* just assigned to set1, since set2 is cleared anyway.
   3956 	*/
   3957 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3958 	if (set1 == NULL)
   3959 	    return(NULL);
   3960 	if (set2->nodeNr != 0) {
   3961 	    memcpy(set1->nodeTab, set2->nodeTab,
   3962 		set2->nodeNr * sizeof(xmlNodePtr));
   3963 	    set1->nodeNr = set2->nodeNr;
   3964 	}
   3965     } else {
   3966 	int i;
   3967 	xmlNodePtr n2;
   3968 
   3969 	if (set1 == NULL)
   3970 	    set1 = xmlXPathNodeSetCreate(NULL);
   3971         if (set1 == NULL)
   3972             return (NULL);
   3973 
   3974 	for (i = 0;i < set2->nodeNr;i++) {
   3975 	    n2 = set2->nodeTab[i];
   3976 	    /*
   3977 	    * Skip NULLed entries.
   3978 	    */
   3979 	    if (n2 == NULL)
   3980 		continue;
   3981 	    if (set1->nodeMax == 0) {
   3982 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3983 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3984 		if (set1->nodeTab == NULL) {
   3985 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3986 		    return(NULL);
   3987 		}
   3988 		memset(set1->nodeTab, 0,
   3989 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3990 		set1->nodeMax = XML_NODESET_DEFAULT;
   3991 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3992 		xmlNodePtr *temp;
   3993 
   3994 		set1->nodeMax *= 2;
   3995 		temp = (xmlNodePtr *) xmlRealloc(
   3996 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
   3997 		if (temp == NULL) {
   3998 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3999 		    return(NULL);
   4000 		}
   4001 		set1->nodeTab = temp;
   4002 	    }
   4003 	    set1->nodeTab[set1->nodeNr++] = n2;
   4004 	}
   4005     }
   4006     set2->nodeNr = 0;
   4007     return(set1);
   4008 }
   4009 
   4010 /**
   4011  * xmlXPathNodeSetDel:
   4012  * @cur:  the initial node set
   4013  * @val:  an xmlNodePtr
   4014  *
   4015  * Removes an xmlNodePtr from an existing NodeSet
   4016  */
   4017 void
   4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4019     int i;
   4020 
   4021     if (cur == NULL) return;
   4022     if (val == NULL) return;
   4023 
   4024     /*
   4025      * find node in nodeTab
   4026      */
   4027     for (i = 0;i < cur->nodeNr;i++)
   4028         if (cur->nodeTab[i] == val) break;
   4029 
   4030     if (i >= cur->nodeNr) {	/* not found */
   4031 #ifdef DEBUG
   4032         xmlGenericError(xmlGenericErrorContext,
   4033 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4034 		val->name);
   4035 #endif
   4036         return;
   4037     }
   4038     if ((cur->nodeTab[i] != NULL) &&
   4039 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4040 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4041     cur->nodeNr--;
   4042     for (;i < cur->nodeNr;i++)
   4043         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4044     cur->nodeTab[cur->nodeNr] = NULL;
   4045 }
   4046 
   4047 /**
   4048  * xmlXPathNodeSetRemove:
   4049  * @cur:  the initial node set
   4050  * @val:  the index to remove
   4051  *
   4052  * Removes an entry from an existing NodeSet list.
   4053  */
   4054 void
   4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4056     if (cur == NULL) return;
   4057     if (val >= cur->nodeNr) return;
   4058     if ((cur->nodeTab[val] != NULL) &&
   4059 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4060 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4061     cur->nodeNr--;
   4062     for (;val < cur->nodeNr;val++)
   4063         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4064     cur->nodeTab[cur->nodeNr] = NULL;
   4065 }
   4066 
   4067 /**
   4068  * xmlXPathFreeNodeSet:
   4069  * @obj:  the xmlNodeSetPtr to free
   4070  *
   4071  * Free the NodeSet compound (not the actual nodes !).
   4072  */
   4073 void
   4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4075     if (obj == NULL) return;
   4076     if (obj->nodeTab != NULL) {
   4077 	int i;
   4078 
   4079 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4080 	for (i = 0;i < obj->nodeNr;i++)
   4081 	    if ((obj->nodeTab[i] != NULL) &&
   4082 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4083 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4084 	xmlFree(obj->nodeTab);
   4085     }
   4086     xmlFree(obj);
   4087 }
   4088 
   4089 /**
   4090  * xmlXPathNodeSetClear:
   4091  * @set:  the node set to clear
   4092  *
   4093  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4094  * are feed), but does *not* free the list itself. Sets the length of the
   4095  * list to 0.
   4096  */
   4097 static void
   4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4099 {
   4100     if ((set == NULL) || (set->nodeNr <= 0))
   4101 	return;
   4102     else if (hasNsNodes) {
   4103 	int i;
   4104 	xmlNodePtr node;
   4105 
   4106 	for (i = 0; i < set->nodeNr; i++) {
   4107 	    node = set->nodeTab[i];
   4108 	    if ((node != NULL) &&
   4109 		(node->type == XML_NAMESPACE_DECL))
   4110 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4111 	}
   4112     }
   4113     set->nodeNr = 0;
   4114 }
   4115 
   4116 /**
   4117  * xmlXPathNodeSetClearFromPos:
   4118  * @set: the node set to be cleared
   4119  * @pos: the start position to clear from
   4120  *
   4121  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4122  * are feed) starting with the entry at @pos, but does *not* free the list
   4123  * itself. Sets the length of the list to @pos.
   4124  */
   4125 static void
   4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4127 {
   4128     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4129 	return;
   4130     else if ((hasNsNodes)) {
   4131 	int i;
   4132 	xmlNodePtr node;
   4133 
   4134 	for (i = pos; i < set->nodeNr; i++) {
   4135 	    node = set->nodeTab[i];
   4136 	    if ((node != NULL) &&
   4137 		(node->type == XML_NAMESPACE_DECL))
   4138 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4139 	}
   4140     }
   4141     set->nodeNr = pos;
   4142 }
   4143 
   4144 /**
   4145  * xmlXPathFreeValueTree:
   4146  * @obj:  the xmlNodeSetPtr to free
   4147  *
   4148  * Free the NodeSet compound and the actual tree, this is different
   4149  * from xmlXPathFreeNodeSet()
   4150  */
   4151 static void
   4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4153     int i;
   4154 
   4155     if (obj == NULL) return;
   4156 
   4157     if (obj->nodeTab != NULL) {
   4158 	for (i = 0;i < obj->nodeNr;i++) {
   4159 	    if (obj->nodeTab[i] != NULL) {
   4160 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4161 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4162 		} else {
   4163 		    xmlFreeNodeList(obj->nodeTab[i]);
   4164 		}
   4165 	    }
   4166 	}
   4167 	xmlFree(obj->nodeTab);
   4168     }
   4169     xmlFree(obj);
   4170 }
   4171 
   4172 #if defined(DEBUG) || defined(DEBUG_STEP)
   4173 /**
   4174  * xmlGenericErrorContextNodeSet:
   4175  * @output:  a FILE * for the output
   4176  * @obj:  the xmlNodeSetPtr to display
   4177  *
   4178  * Quick display of a NodeSet
   4179  */
   4180 void
   4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4182     int i;
   4183 
   4184     if (output == NULL) output = xmlGenericErrorContext;
   4185     if (obj == NULL)  {
   4186         fprintf(output, "NodeSet == NULL !\n");
   4187 	return;
   4188     }
   4189     if (obj->nodeNr == 0) {
   4190         fprintf(output, "NodeSet is empty\n");
   4191 	return;
   4192     }
   4193     if (obj->nodeTab == NULL) {
   4194 	fprintf(output, " nodeTab == NULL !\n");
   4195 	return;
   4196     }
   4197     for (i = 0; i < obj->nodeNr; i++) {
   4198         if (obj->nodeTab[i] == NULL) {
   4199 	    fprintf(output, " NULL !\n");
   4200 	    return;
   4201         }
   4202 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4203 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4204 	    fprintf(output, " /");
   4205 	else if (obj->nodeTab[i]->name == NULL)
   4206 	    fprintf(output, " noname!");
   4207 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4208     }
   4209     fprintf(output, "\n");
   4210 }
   4211 #endif
   4212 
   4213 /**
   4214  * xmlXPathNewNodeSet:
   4215  * @val:  the NodePtr value
   4216  *
   4217  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4218  * it with the single Node @val
   4219  *
   4220  * Returns the newly created object.
   4221  */
   4222 xmlXPathObjectPtr
   4223 xmlXPathNewNodeSet(xmlNodePtr val) {
   4224     xmlXPathObjectPtr ret;
   4225 
   4226     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4227     if (ret == NULL) {
   4228         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4229 	return(NULL);
   4230     }
   4231     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4232     ret->type = XPATH_NODESET;
   4233     ret->boolval = 0;
   4234     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4235     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4236 #ifdef XP_DEBUG_OBJ_USAGE
   4237     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4238 #endif
   4239     return(ret);
   4240 }
   4241 
   4242 /**
   4243  * xmlXPathNewValueTree:
   4244  * @val:  the NodePtr value
   4245  *
   4246  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4247  * it with the tree root @val
   4248  *
   4249  * Returns the newly created object.
   4250  */
   4251 xmlXPathObjectPtr
   4252 xmlXPathNewValueTree(xmlNodePtr val) {
   4253     xmlXPathObjectPtr ret;
   4254 
   4255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4256     if (ret == NULL) {
   4257         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4258 	return(NULL);
   4259     }
   4260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4261     ret->type = XPATH_XSLT_TREE;
   4262     ret->boolval = 1;
   4263     ret->user = (void *) val;
   4264     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4265 #ifdef XP_DEBUG_OBJ_USAGE
   4266     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4267 #endif
   4268     return(ret);
   4269 }
   4270 
   4271 /**
   4272  * xmlXPathNewNodeSetList:
   4273  * @val:  an existing NodeSet
   4274  *
   4275  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4276  * it with the Nodeset @val
   4277  *
   4278  * Returns the newly created object.
   4279  */
   4280 xmlXPathObjectPtr
   4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4282 {
   4283     xmlXPathObjectPtr ret;
   4284     int i;
   4285 
   4286     if (val == NULL)
   4287         ret = NULL;
   4288     else if (val->nodeTab == NULL)
   4289         ret = xmlXPathNewNodeSet(NULL);
   4290     else {
   4291         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4292         if (ret)
   4293             for (i = 1; i < val->nodeNr; ++i)
   4294                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
   4295     }
   4296 
   4297     return (ret);
   4298 }
   4299 
   4300 /**
   4301  * xmlXPathWrapNodeSet:
   4302  * @val:  the NodePtr value
   4303  *
   4304  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4305  *
   4306  * Returns the newly created object.
   4307  */
   4308 xmlXPathObjectPtr
   4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4310     xmlXPathObjectPtr ret;
   4311 
   4312     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4313     if (ret == NULL) {
   4314         xmlXPathErrMemory(NULL, "creating node set object\n");
   4315 	return(NULL);
   4316     }
   4317     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4318     ret->type = XPATH_NODESET;
   4319     ret->nodesetval = val;
   4320 #ifdef XP_DEBUG_OBJ_USAGE
   4321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4322 #endif
   4323     return(ret);
   4324 }
   4325 
   4326 /**
   4327  * xmlXPathFreeNodeSetList:
   4328  * @obj:  an existing NodeSetList object
   4329  *
   4330  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4331  * the list contrary to xmlXPathFreeObject().
   4332  */
   4333 void
   4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4335     if (obj == NULL) return;
   4336 #ifdef XP_DEBUG_OBJ_USAGE
   4337     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4338 #endif
   4339     xmlFree(obj);
   4340 }
   4341 
   4342 /**
   4343  * xmlXPathDifference:
   4344  * @nodes1:  a node-set
   4345  * @nodes2:  a node-set
   4346  *
   4347  * Implements the EXSLT - Sets difference() function:
   4348  *    node-set set:difference (node-set, node-set)
   4349  *
   4350  * Returns the difference between the two node sets, or nodes1 if
   4351  *         nodes2 is empty
   4352  */
   4353 xmlNodeSetPtr
   4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4355     xmlNodeSetPtr ret;
   4356     int i, l1;
   4357     xmlNodePtr cur;
   4358 
   4359     if (xmlXPathNodeSetIsEmpty(nodes2))
   4360 	return(nodes1);
   4361 
   4362     ret = xmlXPathNodeSetCreate(NULL);
   4363     if (xmlXPathNodeSetIsEmpty(nodes1))
   4364 	return(ret);
   4365 
   4366     l1 = xmlXPathNodeSetGetLength(nodes1);
   4367 
   4368     for (i = 0; i < l1; i++) {
   4369 	cur = xmlXPathNodeSetItem(nodes1, i);
   4370 	if (!xmlXPathNodeSetContains(nodes2, cur))
   4371 	    xmlXPathNodeSetAddUnique(ret, cur);
   4372     }
   4373     return(ret);
   4374 }
   4375 
   4376 /**
   4377  * xmlXPathIntersection:
   4378  * @nodes1:  a node-set
   4379  * @nodes2:  a node-set
   4380  *
   4381  * Implements the EXSLT - Sets intersection() function:
   4382  *    node-set set:intersection (node-set, node-set)
   4383  *
   4384  * Returns a node set comprising the nodes that are within both the
   4385  *         node sets passed as arguments
   4386  */
   4387 xmlNodeSetPtr
   4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4389     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4390     int i, l1;
   4391     xmlNodePtr cur;
   4392 
   4393     if (ret == NULL)
   4394         return(ret);
   4395     if (xmlXPathNodeSetIsEmpty(nodes1))
   4396 	return(ret);
   4397     if (xmlXPathNodeSetIsEmpty(nodes2))
   4398 	return(ret);
   4399 
   4400     l1 = xmlXPathNodeSetGetLength(nodes1);
   4401 
   4402     for (i = 0; i < l1; i++) {
   4403 	cur = xmlXPathNodeSetItem(nodes1, i);
   4404 	if (xmlXPathNodeSetContains(nodes2, cur))
   4405 	    xmlXPathNodeSetAddUnique(ret, cur);
   4406     }
   4407     return(ret);
   4408 }
   4409 
   4410 /**
   4411  * xmlXPathDistinctSorted:
   4412  * @nodes:  a node-set, sorted by document order
   4413  *
   4414  * Implements the EXSLT - Sets distinct() function:
   4415  *    node-set set:distinct (node-set)
   4416  *
   4417  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4418  *         it is empty
   4419  */
   4420 xmlNodeSetPtr
   4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4422     xmlNodeSetPtr ret;
   4423     xmlHashTablePtr hash;
   4424     int i, l;
   4425     xmlChar * strval;
   4426     xmlNodePtr cur;
   4427 
   4428     if (xmlXPathNodeSetIsEmpty(nodes))
   4429 	return(nodes);
   4430 
   4431     ret = xmlXPathNodeSetCreate(NULL);
   4432     if (ret == NULL)
   4433         return(ret);
   4434     l = xmlXPathNodeSetGetLength(nodes);
   4435     hash = xmlHashCreate (l);
   4436     for (i = 0; i < l; i++) {
   4437 	cur = xmlXPathNodeSetItem(nodes, i);
   4438 	strval = xmlXPathCastNodeToString(cur);
   4439 	if (xmlHashLookup(hash, strval) == NULL) {
   4440 	    xmlHashAddEntry(hash, strval, strval);
   4441 	    xmlXPathNodeSetAddUnique(ret, cur);
   4442 	} else {
   4443 	    xmlFree(strval);
   4444 	}
   4445     }
   4446     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4447     return(ret);
   4448 }
   4449 
   4450 /**
   4451  * xmlXPathDistinct:
   4452  * @nodes:  a node-set
   4453  *
   4454  * Implements the EXSLT - Sets distinct() function:
   4455  *    node-set set:distinct (node-set)
   4456  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4457  * is called with the sorted node-set
   4458  *
   4459  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4460  *         it is empty
   4461  */
   4462 xmlNodeSetPtr
   4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4464     if (xmlXPathNodeSetIsEmpty(nodes))
   4465 	return(nodes);
   4466 
   4467     xmlXPathNodeSetSort(nodes);
   4468     return(xmlXPathDistinctSorted(nodes));
   4469 }
   4470 
   4471 /**
   4472  * xmlXPathHasSameNodes:
   4473  * @nodes1:  a node-set
   4474  * @nodes2:  a node-set
   4475  *
   4476  * Implements the EXSLT - Sets has-same-nodes function:
   4477  *    boolean set:has-same-node(node-set, node-set)
   4478  *
   4479  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4480  *         otherwise
   4481  */
   4482 int
   4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4484     int i, l;
   4485     xmlNodePtr cur;
   4486 
   4487     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4488 	xmlXPathNodeSetIsEmpty(nodes2))
   4489 	return(0);
   4490 
   4491     l = xmlXPathNodeSetGetLength(nodes1);
   4492     for (i = 0; i < l; i++) {
   4493 	cur = xmlXPathNodeSetItem(nodes1, i);
   4494 	if (xmlXPathNodeSetContains(nodes2, cur))
   4495 	    return(1);
   4496     }
   4497     return(0);
   4498 }
   4499 
   4500 /**
   4501  * xmlXPathNodeLeadingSorted:
   4502  * @nodes: a node-set, sorted by document order
   4503  * @node: a node
   4504  *
   4505  * Implements the EXSLT - Sets leading() function:
   4506  *    node-set set:leading (node-set, node-set)
   4507  *
   4508  * Returns the nodes in @nodes that precede @node in document order,
   4509  *         @nodes if @node is NULL or an empty node-set if @nodes
   4510  *         doesn't contain @node
   4511  */
   4512 xmlNodeSetPtr
   4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4514     int i, l;
   4515     xmlNodePtr cur;
   4516     xmlNodeSetPtr ret;
   4517 
   4518     if (node == NULL)
   4519 	return(nodes);
   4520 
   4521     ret = xmlXPathNodeSetCreate(NULL);
   4522     if (ret == NULL)
   4523         return(ret);
   4524     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4525 	(!xmlXPathNodeSetContains(nodes, node)))
   4526 	return(ret);
   4527 
   4528     l = xmlXPathNodeSetGetLength(nodes);
   4529     for (i = 0; i < l; i++) {
   4530 	cur = xmlXPathNodeSetItem(nodes, i);
   4531 	if (cur == node)
   4532 	    break;
   4533 	xmlXPathNodeSetAddUnique(ret, cur);
   4534     }
   4535     return(ret);
   4536 }
   4537 
   4538 /**
   4539  * xmlXPathNodeLeading:
   4540  * @nodes:  a node-set
   4541  * @node:  a node
   4542  *
   4543  * Implements the EXSLT - Sets leading() function:
   4544  *    node-set set:leading (node-set, node-set)
   4545  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4546  * is called.
   4547  *
   4548  * Returns the nodes in @nodes that precede @node in document order,
   4549  *         @nodes if @node is NULL or an empty node-set if @nodes
   4550  *         doesn't contain @node
   4551  */
   4552 xmlNodeSetPtr
   4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4554     xmlXPathNodeSetSort(nodes);
   4555     return(xmlXPathNodeLeadingSorted(nodes, node));
   4556 }
   4557 
   4558 /**
   4559  * xmlXPathLeadingSorted:
   4560  * @nodes1:  a node-set, sorted by document order
   4561  * @nodes2:  a node-set, sorted by document order
   4562  *
   4563  * Implements the EXSLT - Sets leading() function:
   4564  *    node-set set:leading (node-set, node-set)
   4565  *
   4566  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4567  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4568  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4569  */
   4570 xmlNodeSetPtr
   4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4572     if (xmlXPathNodeSetIsEmpty(nodes2))
   4573 	return(nodes1);
   4574     return(xmlXPathNodeLeadingSorted(nodes1,
   4575 				     xmlXPathNodeSetItem(nodes2, 1)));
   4576 }
   4577 
   4578 /**
   4579  * xmlXPathLeading:
   4580  * @nodes1:  a node-set
   4581  * @nodes2:  a node-set
   4582  *
   4583  * Implements the EXSLT - Sets leading() function:
   4584  *    node-set set:leading (node-set, node-set)
   4585  * @nodes1 and @nodes2 are sorted by document order, then
   4586  * #exslSetsLeadingSorted is called.
   4587  *
   4588  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4589  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4590  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4591  */
   4592 xmlNodeSetPtr
   4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4594     if (xmlXPathNodeSetIsEmpty(nodes2))
   4595 	return(nodes1);
   4596     if (xmlXPathNodeSetIsEmpty(nodes1))
   4597 	return(xmlXPathNodeSetCreate(NULL));
   4598     xmlXPathNodeSetSort(nodes1);
   4599     xmlXPathNodeSetSort(nodes2);
   4600     return(xmlXPathNodeLeadingSorted(nodes1,
   4601 				     xmlXPathNodeSetItem(nodes2, 1)));
   4602 }
   4603 
   4604 /**
   4605  * xmlXPathNodeTrailingSorted:
   4606  * @nodes: a node-set, sorted by document order
   4607  * @node: a node
   4608  *
   4609  * Implements the EXSLT - Sets trailing() function:
   4610  *    node-set set:trailing (node-set, node-set)
   4611  *
   4612  * Returns the nodes in @nodes that follow @node in document order,
   4613  *         @nodes if @node is NULL or an empty node-set if @nodes
   4614  *         doesn't contain @node
   4615  */
   4616 xmlNodeSetPtr
   4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4618     int i, l;
   4619     xmlNodePtr cur;
   4620     xmlNodeSetPtr ret;
   4621 
   4622     if (node == NULL)
   4623 	return(nodes);
   4624 
   4625     ret = xmlXPathNodeSetCreate(NULL);
   4626     if (ret == NULL)
   4627         return(ret);
   4628     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4629 	(!xmlXPathNodeSetContains(nodes, node)))
   4630 	return(ret);
   4631 
   4632     l = xmlXPathNodeSetGetLength(nodes);
   4633     for (i = l - 1; i >= 0; i--) {
   4634 	cur = xmlXPathNodeSetItem(nodes, i);
   4635 	if (cur == node)
   4636 	    break;
   4637 	xmlXPathNodeSetAddUnique(ret, cur);
   4638     }
   4639     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4640     return(ret);
   4641 }
   4642 
   4643 /**
   4644  * xmlXPathNodeTrailing:
   4645  * @nodes:  a node-set
   4646  * @node:  a node
   4647  *
   4648  * Implements the EXSLT - Sets trailing() function:
   4649  *    node-set set:trailing (node-set, node-set)
   4650  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4651  * is called.
   4652  *
   4653  * Returns the nodes in @nodes that follow @node in document order,
   4654  *         @nodes if @node is NULL or an empty node-set if @nodes
   4655  *         doesn't contain @node
   4656  */
   4657 xmlNodeSetPtr
   4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4659     xmlXPathNodeSetSort(nodes);
   4660     return(xmlXPathNodeTrailingSorted(nodes, node));
   4661 }
   4662 
   4663 /**
   4664  * xmlXPathTrailingSorted:
   4665  * @nodes1:  a node-set, sorted by document order
   4666  * @nodes2:  a node-set, sorted by document order
   4667  *
   4668  * Implements the EXSLT - Sets trailing() function:
   4669  *    node-set set:trailing (node-set, node-set)
   4670  *
   4671  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4672  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4673  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4674  */
   4675 xmlNodeSetPtr
   4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4677     if (xmlXPathNodeSetIsEmpty(nodes2))
   4678 	return(nodes1);
   4679     return(xmlXPathNodeTrailingSorted(nodes1,
   4680 				      xmlXPathNodeSetItem(nodes2, 0)));
   4681 }
   4682 
   4683 /**
   4684  * xmlXPathTrailing:
   4685  * @nodes1:  a node-set
   4686  * @nodes2:  a node-set
   4687  *
   4688  * Implements the EXSLT - Sets trailing() function:
   4689  *    node-set set:trailing (node-set, node-set)
   4690  * @nodes1 and @nodes2 are sorted by document order, then
   4691  * #xmlXPathTrailingSorted is called.
   4692  *
   4693  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4694  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4695  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4696  */
   4697 xmlNodeSetPtr
   4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4699     if (xmlXPathNodeSetIsEmpty(nodes2))
   4700 	return(nodes1);
   4701     if (xmlXPathNodeSetIsEmpty(nodes1))
   4702 	return(xmlXPathNodeSetCreate(NULL));
   4703     xmlXPathNodeSetSort(nodes1);
   4704     xmlXPathNodeSetSort(nodes2);
   4705     return(xmlXPathNodeTrailingSorted(nodes1,
   4706 				      xmlXPathNodeSetItem(nodes2, 0)));
   4707 }
   4708 
   4709 /************************************************************************
   4710  *									*
   4711  *		Routines to handle extra functions			*
   4712  *									*
   4713  ************************************************************************/
   4714 
   4715 /**
   4716  * xmlXPathRegisterFunc:
   4717  * @ctxt:  the XPath context
   4718  * @name:  the function name
   4719  * @f:  the function implementation or NULL
   4720  *
   4721  * Register a new function. If @f is NULL it unregisters the function
   4722  *
   4723  * Returns 0 in case of success, -1 in case of error
   4724  */
   4725 int
   4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4727 		     xmlXPathFunction f) {
   4728     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4729 }
   4730 
   4731 /**
   4732  * xmlXPathRegisterFuncNS:
   4733  * @ctxt:  the XPath context
   4734  * @name:  the function name
   4735  * @ns_uri:  the function namespace URI
   4736  * @f:  the function implementation or NULL
   4737  *
   4738  * Register a new function. If @f is NULL it unregisters the function
   4739  *
   4740  * Returns 0 in case of success, -1 in case of error
   4741  */
   4742 int
   4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4744 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4745     if (ctxt == NULL)
   4746 	return(-1);
   4747     if (name == NULL)
   4748 	return(-1);
   4749 
   4750     if (ctxt->funcHash == NULL)
   4751 	ctxt->funcHash = xmlHashCreate(0);
   4752     if (ctxt->funcHash == NULL)
   4753 	return(-1);
   4754     if (f == NULL)
   4755         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4756     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
   4757 }
   4758 
   4759 /**
   4760  * xmlXPathRegisterFuncLookup:
   4761  * @ctxt:  the XPath context
   4762  * @f:  the lookup function
   4763  * @funcCtxt:  the lookup data
   4764  *
   4765  * Registers an external mechanism to do function lookup.
   4766  */
   4767 void
   4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4769 			    xmlXPathFuncLookupFunc f,
   4770 			    void *funcCtxt) {
   4771     if (ctxt == NULL)
   4772 	return;
   4773     ctxt->funcLookupFunc = f;
   4774     ctxt->funcLookupData = funcCtxt;
   4775 }
   4776 
   4777 /**
   4778  * xmlXPathFunctionLookup:
   4779  * @ctxt:  the XPath context
   4780  * @name:  the function name
   4781  *
   4782  * Search in the Function array of the context for the given
   4783  * function.
   4784  *
   4785  * Returns the xmlXPathFunction or NULL if not found
   4786  */
   4787 xmlXPathFunction
   4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4789     if (ctxt == NULL)
   4790 	return (NULL);
   4791 
   4792     if (ctxt->funcLookupFunc != NULL) {
   4793 	xmlXPathFunction ret;
   4794 	xmlXPathFuncLookupFunc f;
   4795 
   4796 	f = ctxt->funcLookupFunc;
   4797 	ret = f(ctxt->funcLookupData, name, NULL);
   4798 	if (ret != NULL)
   4799 	    return(ret);
   4800     }
   4801     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4802 }
   4803 
   4804 /**
   4805  * xmlXPathFunctionLookupNS:
   4806  * @ctxt:  the XPath context
   4807  * @name:  the function name
   4808  * @ns_uri:  the function namespace URI
   4809  *
   4810  * Search in the Function array of the context for the given
   4811  * function.
   4812  *
   4813  * Returns the xmlXPathFunction or NULL if not found
   4814  */
   4815 xmlXPathFunction
   4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4817 			 const xmlChar *ns_uri) {
   4818     xmlXPathFunction ret;
   4819 
   4820     if (ctxt == NULL)
   4821 	return(NULL);
   4822     if (name == NULL)
   4823 	return(NULL);
   4824 
   4825     if (ctxt->funcLookupFunc != NULL) {
   4826 	xmlXPathFuncLookupFunc f;
   4827 
   4828 	f = ctxt->funcLookupFunc;
   4829 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4830 	if (ret != NULL)
   4831 	    return(ret);
   4832     }
   4833 
   4834     if (ctxt->funcHash == NULL)
   4835 	return(NULL);
   4836 
   4837     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4838     return(ret);
   4839 }
   4840 
   4841 /**
   4842  * xmlXPathRegisteredFuncsCleanup:
   4843  * @ctxt:  the XPath context
   4844  *
   4845  * Cleanup the XPath context data associated to registered functions
   4846  */
   4847 void
   4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4849     if (ctxt == NULL)
   4850 	return;
   4851 
   4852     xmlHashFree(ctxt->funcHash, NULL);
   4853     ctxt->funcHash = NULL;
   4854 }
   4855 
   4856 /************************************************************************
   4857  *									*
   4858  *			Routines to handle Variables			*
   4859  *									*
   4860  ************************************************************************/
   4861 
   4862 /**
   4863  * xmlXPathRegisterVariable:
   4864  * @ctxt:  the XPath context
   4865  * @name:  the variable name
   4866  * @value:  the variable value or NULL
   4867  *
   4868  * Register a new variable value. If @value is NULL it unregisters
   4869  * the variable
   4870  *
   4871  * Returns 0 in case of success, -1 in case of error
   4872  */
   4873 int
   4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   4875 			 xmlXPathObjectPtr value) {
   4876     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   4877 }
   4878 
   4879 /**
   4880  * xmlXPathRegisterVariableNS:
   4881  * @ctxt:  the XPath context
   4882  * @name:  the variable name
   4883  * @ns_uri:  the variable namespace URI
   4884  * @value:  the variable value or NULL
   4885  *
   4886  * Register a new variable value. If @value is NULL it unregisters
   4887  * the variable
   4888  *
   4889  * Returns 0 in case of success, -1 in case of error
   4890  */
   4891 int
   4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4893 			   const xmlChar *ns_uri,
   4894 			   xmlXPathObjectPtr value) {
   4895     if (ctxt == NULL)
   4896 	return(-1);
   4897     if (name == NULL)
   4898 	return(-1);
   4899 
   4900     if (ctxt->varHash == NULL)
   4901 	ctxt->varHash = xmlHashCreate(0);
   4902     if (ctxt->varHash == NULL)
   4903 	return(-1);
   4904     if (value == NULL)
   4905         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   4906 	                           (xmlHashDeallocator)xmlXPathFreeObject));
   4907     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   4908 			       (void *) value,
   4909 			       (xmlHashDeallocator)xmlXPathFreeObject));
   4910 }
   4911 
   4912 /**
   4913  * xmlXPathRegisterVariableLookup:
   4914  * @ctxt:  the XPath context
   4915  * @f:  the lookup function
   4916  * @data:  the lookup data
   4917  *
   4918  * register an external mechanism to do variable lookup
   4919  */
   4920 void
   4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   4922 	 xmlXPathVariableLookupFunc f, void *data) {
   4923     if (ctxt == NULL)
   4924 	return;
   4925     ctxt->varLookupFunc = f;
   4926     ctxt->varLookupData = data;
   4927 }
   4928 
   4929 /**
   4930  * xmlXPathVariableLookup:
   4931  * @ctxt:  the XPath context
   4932  * @name:  the variable name
   4933  *
   4934  * Search in the Variable array of the context for the given
   4935  * variable value.
   4936  *
   4937  * Returns a copy of the value or NULL if not found
   4938  */
   4939 xmlXPathObjectPtr
   4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4941     if (ctxt == NULL)
   4942 	return(NULL);
   4943 
   4944     if (ctxt->varLookupFunc != NULL) {
   4945 	xmlXPathObjectPtr ret;
   4946 
   4947 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   4948 	        (ctxt->varLookupData, name, NULL);
   4949 	return(ret);
   4950     }
   4951     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   4952 }
   4953 
   4954 /**
   4955  * xmlXPathVariableLookupNS:
   4956  * @ctxt:  the XPath context
   4957  * @name:  the variable name
   4958  * @ns_uri:  the variable namespace URI
   4959  *
   4960  * Search in the Variable array of the context for the given
   4961  * variable value.
   4962  *
   4963  * Returns the a copy of the value or NULL if not found
   4964  */
   4965 xmlXPathObjectPtr
   4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4967 			 const xmlChar *ns_uri) {
   4968     if (ctxt == NULL)
   4969 	return(NULL);
   4970 
   4971     if (ctxt->varLookupFunc != NULL) {
   4972 	xmlXPathObjectPtr ret;
   4973 
   4974 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   4975 	        (ctxt->varLookupData, name, ns_uri);
   4976 	if (ret != NULL) return(ret);
   4977     }
   4978 
   4979     if (ctxt->varHash == NULL)
   4980 	return(NULL);
   4981     if (name == NULL)
   4982 	return(NULL);
   4983 
   4984     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   4985 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   4986 }
   4987 
   4988 /**
   4989  * xmlXPathRegisteredVariablesCleanup:
   4990  * @ctxt:  the XPath context
   4991  *
   4992  * Cleanup the XPath context data associated to registered variables
   4993  */
   4994 void
   4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   4996     if (ctxt == NULL)
   4997 	return;
   4998 
   4999     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
   5000     ctxt->varHash = NULL;
   5001 }
   5002 
   5003 /**
   5004  * xmlXPathRegisterNs:
   5005  * @ctxt:  the XPath context
   5006  * @prefix:  the namespace prefix
   5007  * @ns_uri:  the namespace name
   5008  *
   5009  * Register a new namespace. If @ns_uri is NULL it unregisters
   5010  * the namespace
   5011  *
   5012  * Returns 0 in case of success, -1 in case of error
   5013  */
   5014 int
   5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5016 			   const xmlChar *ns_uri) {
   5017     if (ctxt == NULL)
   5018 	return(-1);
   5019     if (prefix == NULL)
   5020 	return(-1);
   5021 
   5022     if (ctxt->nsHash == NULL)
   5023 	ctxt->nsHash = xmlHashCreate(10);
   5024     if (ctxt->nsHash == NULL)
   5025 	return(-1);
   5026     if (ns_uri == NULL)
   5027         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5028 	                          (xmlHashDeallocator)xmlFree));
   5029     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5030 			      (xmlHashDeallocator)xmlFree));
   5031 }
   5032 
   5033 /**
   5034  * xmlXPathNsLookup:
   5035  * @ctxt:  the XPath context
   5036  * @prefix:  the namespace prefix value
   5037  *
   5038  * Search in the namespace declaration array of the context for the given
   5039  * namespace name associated to the given prefix
   5040  *
   5041  * Returns the value or NULL if not found
   5042  */
   5043 const xmlChar *
   5044 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5045     if (ctxt == NULL)
   5046 	return(NULL);
   5047     if (prefix == NULL)
   5048 	return(NULL);
   5049 
   5050 #ifdef XML_XML_NAMESPACE
   5051     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5052 	return(XML_XML_NAMESPACE);
   5053 #endif
   5054 
   5055     if (ctxt->namespaces != NULL) {
   5056 	int i;
   5057 
   5058 	for (i = 0;i < ctxt->nsNr;i++) {
   5059 	    if ((ctxt->namespaces[i] != NULL) &&
   5060 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5061 		return(ctxt->namespaces[i]->href);
   5062 	}
   5063     }
   5064 
   5065     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5066 }
   5067 
   5068 /**
   5069  * xmlXPathRegisteredNsCleanup:
   5070  * @ctxt:  the XPath context
   5071  *
   5072  * Cleanup the XPath context data associated to registered variables
   5073  */
   5074 void
   5075 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5076     if (ctxt == NULL)
   5077 	return;
   5078 
   5079     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
   5080     ctxt->nsHash = NULL;
   5081 }
   5082 
   5083 /************************************************************************
   5084  *									*
   5085  *			Routines to handle Values			*
   5086  *									*
   5087  ************************************************************************/
   5088 
   5089 /* Allocations are terrible, one needs to optimize all this !!! */
   5090 
   5091 /**
   5092  * xmlXPathNewFloat:
   5093  * @val:  the double value
   5094  *
   5095  * Create a new xmlXPathObjectPtr of type double and of value @val
   5096  *
   5097  * Returns the newly created object.
   5098  */
   5099 xmlXPathObjectPtr
   5100 xmlXPathNewFloat(double val) {
   5101     xmlXPathObjectPtr ret;
   5102 
   5103     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5104     if (ret == NULL) {
   5105         xmlXPathErrMemory(NULL, "creating float object\n");
   5106 	return(NULL);
   5107     }
   5108     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5109     ret->type = XPATH_NUMBER;
   5110     ret->floatval = val;
   5111 #ifdef XP_DEBUG_OBJ_USAGE
   5112     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5113 #endif
   5114     return(ret);
   5115 }
   5116 
   5117 /**
   5118  * xmlXPathNewBoolean:
   5119  * @val:  the boolean value
   5120  *
   5121  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5122  *
   5123  * Returns the newly created object.
   5124  */
   5125 xmlXPathObjectPtr
   5126 xmlXPathNewBoolean(int val) {
   5127     xmlXPathObjectPtr ret;
   5128 
   5129     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5130     if (ret == NULL) {
   5131         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5132 	return(NULL);
   5133     }
   5134     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5135     ret->type = XPATH_BOOLEAN;
   5136     ret->boolval = (val != 0);
   5137 #ifdef XP_DEBUG_OBJ_USAGE
   5138     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5139 #endif
   5140     return(ret);
   5141 }
   5142 
   5143 /**
   5144  * xmlXPathNewString:
   5145  * @val:  the xmlChar * value
   5146  *
   5147  * Create a new xmlXPathObjectPtr of type string and of value @val
   5148  *
   5149  * Returns the newly created object.
   5150  */
   5151 xmlXPathObjectPtr
   5152 xmlXPathNewString(const xmlChar *val) {
   5153     xmlXPathObjectPtr ret;
   5154 
   5155     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5156     if (ret == NULL) {
   5157         xmlXPathErrMemory(NULL, "creating string object\n");
   5158 	return(NULL);
   5159     }
   5160     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5161     ret->type = XPATH_STRING;
   5162     if (val != NULL)
   5163 	ret->stringval = xmlStrdup(val);
   5164     else
   5165 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5166 #ifdef XP_DEBUG_OBJ_USAGE
   5167     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5168 #endif
   5169     return(ret);
   5170 }
   5171 
   5172 /**
   5173  * xmlXPathWrapString:
   5174  * @val:  the xmlChar * value
   5175  *
   5176  * Wraps the @val string into an XPath object.
   5177  *
   5178  * Returns the newly created object.
   5179  */
   5180 xmlXPathObjectPtr
   5181 xmlXPathWrapString (xmlChar *val) {
   5182     xmlXPathObjectPtr ret;
   5183 
   5184     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5185     if (ret == NULL) {
   5186         xmlXPathErrMemory(NULL, "creating string object\n");
   5187 	return(NULL);
   5188     }
   5189     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5190     ret->type = XPATH_STRING;
   5191     ret->stringval = val;
   5192 #ifdef XP_DEBUG_OBJ_USAGE
   5193     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5194 #endif
   5195     return(ret);
   5196 }
   5197 
   5198 /**
   5199  * xmlXPathNewCString:
   5200  * @val:  the char * value
   5201  *
   5202  * Create a new xmlXPathObjectPtr of type string and of value @val
   5203  *
   5204  * Returns the newly created object.
   5205  */
   5206 xmlXPathObjectPtr
   5207 xmlXPathNewCString(const char *val) {
   5208     xmlXPathObjectPtr ret;
   5209 
   5210     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5211     if (ret == NULL) {
   5212         xmlXPathErrMemory(NULL, "creating string object\n");
   5213 	return(NULL);
   5214     }
   5215     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5216     ret->type = XPATH_STRING;
   5217     ret->stringval = xmlStrdup(BAD_CAST val);
   5218 #ifdef XP_DEBUG_OBJ_USAGE
   5219     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5220 #endif
   5221     return(ret);
   5222 }
   5223 
   5224 /**
   5225  * xmlXPathWrapCString:
   5226  * @val:  the char * value
   5227  *
   5228  * Wraps a string into an XPath object.
   5229  *
   5230  * Returns the newly created object.
   5231  */
   5232 xmlXPathObjectPtr
   5233 xmlXPathWrapCString (char * val) {
   5234     return(xmlXPathWrapString((xmlChar *)(val)));
   5235 }
   5236 
   5237 /**
   5238  * xmlXPathWrapExternal:
   5239  * @val:  the user data
   5240  *
   5241  * Wraps the @val data into an XPath object.
   5242  *
   5243  * Returns the newly created object.
   5244  */
   5245 xmlXPathObjectPtr
   5246 xmlXPathWrapExternal (void *val) {
   5247     xmlXPathObjectPtr ret;
   5248 
   5249     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5250     if (ret == NULL) {
   5251         xmlXPathErrMemory(NULL, "creating user object\n");
   5252 	return(NULL);
   5253     }
   5254     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5255     ret->type = XPATH_USERS;
   5256     ret->user = val;
   5257 #ifdef XP_DEBUG_OBJ_USAGE
   5258     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5259 #endif
   5260     return(ret);
   5261 }
   5262 
   5263 /**
   5264  * xmlXPathObjectCopy:
   5265  * @val:  the original object
   5266  *
   5267  * allocate a new copy of a given object
   5268  *
   5269  * Returns the newly created object.
   5270  */
   5271 xmlXPathObjectPtr
   5272 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5273     xmlXPathObjectPtr ret;
   5274 
   5275     if (val == NULL)
   5276 	return(NULL);
   5277 
   5278     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5279     if (ret == NULL) {
   5280         xmlXPathErrMemory(NULL, "copying object\n");
   5281 	return(NULL);
   5282     }
   5283     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5284 #ifdef XP_DEBUG_OBJ_USAGE
   5285     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5286 #endif
   5287     switch (val->type) {
   5288 	case XPATH_BOOLEAN:
   5289 	case XPATH_NUMBER:
   5290 	case XPATH_POINT:
   5291 	case XPATH_RANGE:
   5292 	    break;
   5293 	case XPATH_STRING:
   5294 	    ret->stringval = xmlStrdup(val->stringval);
   5295 	    break;
   5296 	case XPATH_XSLT_TREE:
   5297 #if 0
   5298 /*
   5299   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5300   this previous handling is no longer correct, and can cause some serious
   5301   problems (ref. bug 145547)
   5302 */
   5303 	    if ((val->nodesetval != NULL) &&
   5304 		(val->nodesetval->nodeTab != NULL)) {
   5305 		xmlNodePtr cur, tmp;
   5306 		xmlDocPtr top;
   5307 
   5308 		ret->boolval = 1;
   5309 		top =  xmlNewDoc(NULL);
   5310 		top->name = (char *)
   5311 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5312 		ret->user = top;
   5313 		if (top != NULL) {
   5314 		    top->doc = top;
   5315 		    cur = val->nodesetval->nodeTab[0]->children;
   5316 		    while (cur != NULL) {
   5317 			tmp = xmlDocCopyNode(cur, top, 1);
   5318 			xmlAddChild((xmlNodePtr) top, tmp);
   5319 			cur = cur->next;
   5320 		    }
   5321 		}
   5322 
   5323 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5324 	    } else
   5325 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5326 	    /* Deallocate the copied tree value */
   5327 	    break;
   5328 #endif
   5329 	case XPATH_NODESET:
   5330 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5331 	    /* Do not deallocate the copied tree value */
   5332 	    ret->boolval = 0;
   5333 	    break;
   5334 	case XPATH_LOCATIONSET:
   5335 #ifdef LIBXML_XPTR_ENABLED
   5336 	{
   5337 	    xmlLocationSetPtr loc = val->user;
   5338 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5339 	    break;
   5340 	}
   5341 #endif
   5342         case XPATH_USERS:
   5343 	    ret->user = val->user;
   5344 	    break;
   5345         case XPATH_UNDEFINED:
   5346 	    xmlGenericError(xmlGenericErrorContext,
   5347 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5348 		    val->type);
   5349 	    break;
   5350     }
   5351     return(ret);
   5352 }
   5353 
   5354 /**
   5355  * xmlXPathFreeObject:
   5356  * @obj:  the object to free
   5357  *
   5358  * Free up an xmlXPathObjectPtr object.
   5359  */
   5360 void
   5361 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5362     if (obj == NULL) return;
   5363     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5364 	if (obj->boolval) {
   5365 #if 0
   5366 	    if (obj->user != NULL) {
   5367                 xmlXPathFreeNodeSet(obj->nodesetval);
   5368 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5369 	    } else
   5370 #endif
   5371 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5372 	    if (obj->nodesetval != NULL)
   5373 		xmlXPathFreeValueTree(obj->nodesetval);
   5374 	} else {
   5375 	    if (obj->nodesetval != NULL)
   5376 		xmlXPathFreeNodeSet(obj->nodesetval);
   5377 	}
   5378 #ifdef LIBXML_XPTR_ENABLED
   5379     } else if (obj->type == XPATH_LOCATIONSET) {
   5380 	if (obj->user != NULL)
   5381 	    xmlXPtrFreeLocationSet(obj->user);
   5382 #endif
   5383     } else if (obj->type == XPATH_STRING) {
   5384 	if (obj->stringval != NULL)
   5385 	    xmlFree(obj->stringval);
   5386     }
   5387 #ifdef XP_DEBUG_OBJ_USAGE
   5388     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5389 #endif
   5390     xmlFree(obj);
   5391 }
   5392 
   5393 /**
   5394  * xmlXPathReleaseObject:
   5395  * @obj:  the xmlXPathObjectPtr to free or to cache
   5396  *
   5397  * Depending on the state of the cache this frees the given
   5398  * XPath object or stores it in the cache.
   5399  */
   5400 static void
   5401 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5402 {
   5403 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5404 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5405     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5406 
   5407 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5408 
   5409     if (obj == NULL)
   5410 	return;
   5411     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5412 	 xmlXPathFreeObject(obj);
   5413     } else {
   5414 	xmlXPathContextCachePtr cache =
   5415 	    (xmlXPathContextCachePtr) ctxt->cache;
   5416 
   5417 	switch (obj->type) {
   5418 	    case XPATH_NODESET:
   5419 	    case XPATH_XSLT_TREE:
   5420 		if (obj->nodesetval != NULL) {
   5421 		    if (obj->boolval) {
   5422 			/*
   5423 			* It looks like the @boolval is used for
   5424 			* evaluation if this an XSLT Result Tree Fragment.
   5425 			* TODO: Check if this assumption is correct.
   5426 			*/
   5427 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5428 			xmlXPathFreeValueTree(obj->nodesetval);
   5429 			obj->nodesetval = NULL;
   5430 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5431 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5432 					cache->maxNodeset)))
   5433 		    {
   5434 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5435 			goto obj_cached;
   5436 		    } else {
   5437 			xmlXPathFreeNodeSet(obj->nodesetval);
   5438 			obj->nodesetval = NULL;
   5439 		    }
   5440 		}
   5441 		break;
   5442 	    case XPATH_STRING:
   5443 		if (obj->stringval != NULL)
   5444 		    xmlFree(obj->stringval);
   5445 
   5446 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5447 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5448 		    goto obj_cached;
   5449 		}
   5450 		break;
   5451 	    case XPATH_BOOLEAN:
   5452 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5453 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5454 		    goto obj_cached;
   5455 		}
   5456 		break;
   5457 	    case XPATH_NUMBER:
   5458 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5459 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5460 		    goto obj_cached;
   5461 		}
   5462 		break;
   5463 #ifdef LIBXML_XPTR_ENABLED
   5464 	    case XPATH_LOCATIONSET:
   5465 		if (obj->user != NULL) {
   5466 		    xmlXPtrFreeLocationSet(obj->user);
   5467 		}
   5468 		goto free_obj;
   5469 #endif
   5470 	    default:
   5471 		goto free_obj;
   5472 	}
   5473 
   5474 	/*
   5475 	* Fallback to adding to the misc-objects slot.
   5476 	*/
   5477 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5478 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5479 	} else
   5480 	    goto free_obj;
   5481 
   5482 obj_cached:
   5483 
   5484 #ifdef XP_DEBUG_OBJ_USAGE
   5485 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5486 #endif
   5487 
   5488 	if (obj->nodesetval != NULL) {
   5489 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5490 
   5491 	    /*
   5492 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5493 	    *  the list and free the ns-nodes.
   5494 	    * URGENT TODO: Check if it's actually slowing things down.
   5495 	    *  Maybe we shouldn't try to preserve the list.
   5496 	    */
   5497 	    if (tmpset->nodeNr > 1) {
   5498 		int i;
   5499 		xmlNodePtr node;
   5500 
   5501 		for (i = 0; i < tmpset->nodeNr; i++) {
   5502 		    node = tmpset->nodeTab[i];
   5503 		    if ((node != NULL) &&
   5504 			(node->type == XML_NAMESPACE_DECL))
   5505 		    {
   5506 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5507 		    }
   5508 		}
   5509 	    } else if (tmpset->nodeNr == 1) {
   5510 		if ((tmpset->nodeTab[0] != NULL) &&
   5511 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5512 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5513 	    }
   5514 	    tmpset->nodeNr = 0;
   5515 	    memset(obj, 0, sizeof(xmlXPathObject));
   5516 	    obj->nodesetval = tmpset;
   5517 	} else
   5518 	    memset(obj, 0, sizeof(xmlXPathObject));
   5519 
   5520 	return;
   5521 
   5522 free_obj:
   5523 	/*
   5524 	* Cache is full; free the object.
   5525 	*/
   5526 	if (obj->nodesetval != NULL)
   5527 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5528 #ifdef XP_DEBUG_OBJ_USAGE
   5529 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5530 #endif
   5531 	xmlFree(obj);
   5532     }
   5533     return;
   5534 }
   5535 
   5536 
   5537 /************************************************************************
   5538  *									*
   5539  *			Type Casting Routines				*
   5540  *									*
   5541  ************************************************************************/
   5542 
   5543 /**
   5544  * xmlXPathCastBooleanToString:
   5545  * @val:  a boolean
   5546  *
   5547  * Converts a boolean to its string value.
   5548  *
   5549  * Returns a newly allocated string.
   5550  */
   5551 xmlChar *
   5552 xmlXPathCastBooleanToString (int val) {
   5553     xmlChar *ret;
   5554     if (val)
   5555 	ret = xmlStrdup((const xmlChar *) "true");
   5556     else
   5557 	ret = xmlStrdup((const xmlChar *) "false");
   5558     return(ret);
   5559 }
   5560 
   5561 /**
   5562  * xmlXPathCastNumberToString:
   5563  * @val:  a number
   5564  *
   5565  * Converts a number to its string value.
   5566  *
   5567  * Returns a newly allocated string.
   5568  */
   5569 xmlChar *
   5570 xmlXPathCastNumberToString (double val) {
   5571     xmlChar *ret;
   5572     switch (xmlXPathIsInf(val)) {
   5573     case 1:
   5574 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5575 	break;
   5576     case -1:
   5577 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5578 	break;
   5579     default:
   5580 	if (xmlXPathIsNaN(val)) {
   5581 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5582 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
   5583 	    ret = xmlStrdup((const xmlChar *) "0");
   5584 	} else {
   5585 	    /* could be improved */
   5586 	    char buf[100];
   5587 	    xmlXPathFormatNumber(val, buf, 99);
   5588 	    buf[99] = 0;
   5589 	    ret = xmlStrdup((const xmlChar *) buf);
   5590 	}
   5591     }
   5592     return(ret);
   5593 }
   5594 
   5595 /**
   5596  * xmlXPathCastNodeToString:
   5597  * @node:  a node
   5598  *
   5599  * Converts a node to its string value.
   5600  *
   5601  * Returns a newly allocated string.
   5602  */
   5603 xmlChar *
   5604 xmlXPathCastNodeToString (xmlNodePtr node) {
   5605 xmlChar *ret;
   5606     if ((ret = xmlNodeGetContent(node)) == NULL)
   5607 	ret = xmlStrdup((const xmlChar *) "");
   5608     return(ret);
   5609 }
   5610 
   5611 /**
   5612  * xmlXPathCastNodeSetToString:
   5613  * @ns:  a node-set
   5614  *
   5615  * Converts a node-set to its string value.
   5616  *
   5617  * Returns a newly allocated string.
   5618  */
   5619 xmlChar *
   5620 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5621     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5622 	return(xmlStrdup((const xmlChar *) ""));
   5623 
   5624     if (ns->nodeNr > 1)
   5625 	xmlXPathNodeSetSort(ns);
   5626     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5627 }
   5628 
   5629 /**
   5630  * xmlXPathCastToString:
   5631  * @val:  an XPath object
   5632  *
   5633  * Converts an existing object to its string() equivalent
   5634  *
   5635  * Returns the allocated string value of the object, NULL in case of error.
   5636  *         It's up to the caller to free the string memory with xmlFree().
   5637  */
   5638 xmlChar *
   5639 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5640     xmlChar *ret = NULL;
   5641 
   5642     if (val == NULL)
   5643 	return(xmlStrdup((const xmlChar *) ""));
   5644     switch (val->type) {
   5645 	case XPATH_UNDEFINED:
   5646 #ifdef DEBUG_EXPR
   5647 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5648 #endif
   5649 	    ret = xmlStrdup((const xmlChar *) "");
   5650 	    break;
   5651         case XPATH_NODESET:
   5652         case XPATH_XSLT_TREE:
   5653 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5654 	    break;
   5655 	case XPATH_STRING:
   5656 	    return(xmlStrdup(val->stringval));
   5657         case XPATH_BOOLEAN:
   5658 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5659 	    break;
   5660 	case XPATH_NUMBER: {
   5661 	    ret = xmlXPathCastNumberToString(val->floatval);
   5662 	    break;
   5663 	}
   5664 	case XPATH_USERS:
   5665 	case XPATH_POINT:
   5666 	case XPATH_RANGE:
   5667 	case XPATH_LOCATIONSET:
   5668 	    TODO
   5669 	    ret = xmlStrdup((const xmlChar *) "");
   5670 	    break;
   5671     }
   5672     return(ret);
   5673 }
   5674 
   5675 /**
   5676  * xmlXPathConvertString:
   5677  * @val:  an XPath object
   5678  *
   5679  * Converts an existing object to its string() equivalent
   5680  *
   5681  * Returns the new object, the old one is freed (or the operation
   5682  *         is done directly on @val)
   5683  */
   5684 xmlXPathObjectPtr
   5685 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5686     xmlChar *res = NULL;
   5687 
   5688     if (val == NULL)
   5689 	return(xmlXPathNewCString(""));
   5690 
   5691     switch (val->type) {
   5692     case XPATH_UNDEFINED:
   5693 #ifdef DEBUG_EXPR
   5694 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5695 #endif
   5696 	break;
   5697     case XPATH_NODESET:
   5698     case XPATH_XSLT_TREE:
   5699 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5700 	break;
   5701     case XPATH_STRING:
   5702 	return(val);
   5703     case XPATH_BOOLEAN:
   5704 	res = xmlXPathCastBooleanToString(val->boolval);
   5705 	break;
   5706     case XPATH_NUMBER:
   5707 	res = xmlXPathCastNumberToString(val->floatval);
   5708 	break;
   5709     case XPATH_USERS:
   5710     case XPATH_POINT:
   5711     case XPATH_RANGE:
   5712     case XPATH_LOCATIONSET:
   5713 	TODO;
   5714 	break;
   5715     }
   5716     xmlXPathFreeObject(val);
   5717     if (res == NULL)
   5718 	return(xmlXPathNewCString(""));
   5719     return(xmlXPathWrapString(res));
   5720 }
   5721 
   5722 /**
   5723  * xmlXPathCastBooleanToNumber:
   5724  * @val:  a boolean
   5725  *
   5726  * Converts a boolean to its number value
   5727  *
   5728  * Returns the number value
   5729  */
   5730 double
   5731 xmlXPathCastBooleanToNumber(int val) {
   5732     if (val)
   5733 	return(1.0);
   5734     return(0.0);
   5735 }
   5736 
   5737 /**
   5738  * xmlXPathCastStringToNumber:
   5739  * @val:  a string
   5740  *
   5741  * Converts a string to its number value
   5742  *
   5743  * Returns the number value
   5744  */
   5745 double
   5746 xmlXPathCastStringToNumber(const xmlChar * val) {
   5747     return(xmlXPathStringEvalNumber(val));
   5748 }
   5749 
   5750 /**
   5751  * xmlXPathCastNodeToNumber:
   5752  * @node:  a node
   5753  *
   5754  * Converts a node to its number value
   5755  *
   5756  * Returns the number value
   5757  */
   5758 double
   5759 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5760     xmlChar *strval;
   5761     double ret;
   5762 
   5763     if (node == NULL)
   5764 	return(xmlXPathNAN);
   5765     strval = xmlXPathCastNodeToString(node);
   5766     if (strval == NULL)
   5767 	return(xmlXPathNAN);
   5768     ret = xmlXPathCastStringToNumber(strval);
   5769     xmlFree(strval);
   5770 
   5771     return(ret);
   5772 }
   5773 
   5774 /**
   5775  * xmlXPathCastNodeSetToNumber:
   5776  * @ns:  a node-set
   5777  *
   5778  * Converts a node-set to its number value
   5779  *
   5780  * Returns the number value
   5781  */
   5782 double
   5783 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5784     xmlChar *str;
   5785     double ret;
   5786 
   5787     if (ns == NULL)
   5788 	return(xmlXPathNAN);
   5789     str = xmlXPathCastNodeSetToString(ns);
   5790     ret = xmlXPathCastStringToNumber(str);
   5791     xmlFree(str);
   5792     return(ret);
   5793 }
   5794 
   5795 /**
   5796  * xmlXPathCastToNumber:
   5797  * @val:  an XPath object
   5798  *
   5799  * Converts an XPath object to its number value
   5800  *
   5801  * Returns the number value
   5802  */
   5803 double
   5804 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5805     double ret = 0.0;
   5806 
   5807     if (val == NULL)
   5808 	return(xmlXPathNAN);
   5809     switch (val->type) {
   5810     case XPATH_UNDEFINED:
   5811 #ifdef DEGUB_EXPR
   5812 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5813 #endif
   5814 	ret = xmlXPathNAN;
   5815 	break;
   5816     case XPATH_NODESET:
   5817     case XPATH_XSLT_TREE:
   5818 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5819 	break;
   5820     case XPATH_STRING:
   5821 	ret = xmlXPathCastStringToNumber(val->stringval);
   5822 	break;
   5823     case XPATH_NUMBER:
   5824 	ret = val->floatval;
   5825 	break;
   5826     case XPATH_BOOLEAN:
   5827 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5828 	break;
   5829     case XPATH_USERS:
   5830     case XPATH_POINT:
   5831     case XPATH_RANGE:
   5832     case XPATH_LOCATIONSET:
   5833 	TODO;
   5834 	ret = xmlXPathNAN;
   5835 	break;
   5836     }
   5837     return(ret);
   5838 }
   5839 
   5840 /**
   5841  * xmlXPathConvertNumber:
   5842  * @val:  an XPath object
   5843  *
   5844  * Converts an existing object to its number() equivalent
   5845  *
   5846  * Returns the new object, the old one is freed (or the operation
   5847  *         is done directly on @val)
   5848  */
   5849 xmlXPathObjectPtr
   5850 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5851     xmlXPathObjectPtr ret;
   5852 
   5853     if (val == NULL)
   5854 	return(xmlXPathNewFloat(0.0));
   5855     if (val->type == XPATH_NUMBER)
   5856 	return(val);
   5857     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5858     xmlXPathFreeObject(val);
   5859     return(ret);
   5860 }
   5861 
   5862 /**
   5863  * xmlXPathCastNumberToBoolean:
   5864  * @val:  a number
   5865  *
   5866  * Converts a number to its boolean value
   5867  *
   5868  * Returns the boolean value
   5869  */
   5870 int
   5871 xmlXPathCastNumberToBoolean (double val) {
   5872      if (xmlXPathIsNaN(val) || (val == 0.0))
   5873 	 return(0);
   5874      return(1);
   5875 }
   5876 
   5877 /**
   5878  * xmlXPathCastStringToBoolean:
   5879  * @val:  a string
   5880  *
   5881  * Converts a string to its boolean value
   5882  *
   5883  * Returns the boolean value
   5884  */
   5885 int
   5886 xmlXPathCastStringToBoolean (const xmlChar *val) {
   5887     if ((val == NULL) || (xmlStrlen(val) == 0))
   5888 	return(0);
   5889     return(1);
   5890 }
   5891 
   5892 /**
   5893  * xmlXPathCastNodeSetToBoolean:
   5894  * @ns:  a node-set
   5895  *
   5896  * Converts a node-set to its boolean value
   5897  *
   5898  * Returns the boolean value
   5899  */
   5900 int
   5901 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   5902     if ((ns == NULL) || (ns->nodeNr == 0))
   5903 	return(0);
   5904     return(1);
   5905 }
   5906 
   5907 /**
   5908  * xmlXPathCastToBoolean:
   5909  * @val:  an XPath object
   5910  *
   5911  * Converts an XPath object to its boolean value
   5912  *
   5913  * Returns the boolean value
   5914  */
   5915 int
   5916 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   5917     int ret = 0;
   5918 
   5919     if (val == NULL)
   5920 	return(0);
   5921     switch (val->type) {
   5922     case XPATH_UNDEFINED:
   5923 #ifdef DEBUG_EXPR
   5924 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   5925 #endif
   5926 	ret = 0;
   5927 	break;
   5928     case XPATH_NODESET:
   5929     case XPATH_XSLT_TREE:
   5930 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   5931 	break;
   5932     case XPATH_STRING:
   5933 	ret = xmlXPathCastStringToBoolean(val->stringval);
   5934 	break;
   5935     case XPATH_NUMBER:
   5936 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   5937 	break;
   5938     case XPATH_BOOLEAN:
   5939 	ret = val->boolval;
   5940 	break;
   5941     case XPATH_USERS:
   5942     case XPATH_POINT:
   5943     case XPATH_RANGE:
   5944     case XPATH_LOCATIONSET:
   5945 	TODO;
   5946 	ret = 0;
   5947 	break;
   5948     }
   5949     return(ret);
   5950 }
   5951 
   5952 
   5953 /**
   5954  * xmlXPathConvertBoolean:
   5955  * @val:  an XPath object
   5956  *
   5957  * Converts an existing object to its boolean() equivalent
   5958  *
   5959  * Returns the new object, the old one is freed (or the operation
   5960  *         is done directly on @val)
   5961  */
   5962 xmlXPathObjectPtr
   5963 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   5964     xmlXPathObjectPtr ret;
   5965 
   5966     if (val == NULL)
   5967 	return(xmlXPathNewBoolean(0));
   5968     if (val->type == XPATH_BOOLEAN)
   5969 	return(val);
   5970     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   5971     xmlXPathFreeObject(val);
   5972     return(ret);
   5973 }
   5974 
   5975 /************************************************************************
   5976  *									*
   5977  *		Routines to handle XPath contexts			*
   5978  *									*
   5979  ************************************************************************/
   5980 
   5981 /**
   5982  * xmlXPathNewContext:
   5983  * @doc:  the XML document
   5984  *
   5985  * Create a new xmlXPathContext
   5986  *
   5987  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   5988  */
   5989 xmlXPathContextPtr
   5990 xmlXPathNewContext(xmlDocPtr doc) {
   5991     xmlXPathContextPtr ret;
   5992 
   5993     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   5994     if (ret == NULL) {
   5995         xmlXPathErrMemory(NULL, "creating context\n");
   5996 	return(NULL);
   5997     }
   5998     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   5999     ret->doc = doc;
   6000     ret->node = NULL;
   6001 
   6002     ret->varHash = NULL;
   6003 
   6004     ret->nb_types = 0;
   6005     ret->max_types = 0;
   6006     ret->types = NULL;
   6007 
   6008     ret->funcHash = xmlHashCreate(0);
   6009 
   6010     ret->nb_axis = 0;
   6011     ret->max_axis = 0;
   6012     ret->axis = NULL;
   6013 
   6014     ret->nsHash = NULL;
   6015     ret->user = NULL;
   6016 
   6017     ret->contextSize = -1;
   6018     ret->proximityPosition = -1;
   6019 
   6020 #ifdef XP_DEFAULT_CACHE_ON
   6021     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6022 	xmlXPathFreeContext(ret);
   6023 	return(NULL);
   6024     }
   6025 #endif
   6026 
   6027     xmlXPathRegisterAllFunctions(ret);
   6028 
   6029     return(ret);
   6030 }
   6031 
   6032 /**
   6033  * xmlXPathFreeContext:
   6034  * @ctxt:  the context to free
   6035  *
   6036  * Free up an xmlXPathContext
   6037  */
   6038 void
   6039 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6040     if (ctxt == NULL) return;
   6041 
   6042     if (ctxt->cache != NULL)
   6043 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6044     xmlXPathRegisteredNsCleanup(ctxt);
   6045     xmlXPathRegisteredFuncsCleanup(ctxt);
   6046     xmlXPathRegisteredVariablesCleanup(ctxt);
   6047     xmlResetError(&ctxt->lastError);
   6048     xmlFree(ctxt);
   6049 }
   6050 
   6051 /************************************************************************
   6052  *									*
   6053  *		Routines to handle XPath parser contexts		*
   6054  *									*
   6055  ************************************************************************/
   6056 
   6057 #define CHECK_CTXT(ctxt)						\
   6058     if (ctxt == NULL) {						\
   6059 	__xmlRaiseError(NULL, NULL, NULL,				\
   6060 		NULL, NULL, XML_FROM_XPATH,				\
   6061 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6062 		__FILE__, __LINE__,					\
   6063 		NULL, NULL, NULL, 0, 0,					\
   6064 		"NULL context pointer\n");				\
   6065 	return(NULL);							\
   6066     }									\
   6067 
   6068 #define CHECK_CTXT_NEG(ctxt)						\
   6069     if (ctxt == NULL) {						\
   6070 	__xmlRaiseError(NULL, NULL, NULL,				\
   6071 		NULL, NULL, XML_FROM_XPATH,				\
   6072 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6073 		__FILE__, __LINE__,					\
   6074 		NULL, NULL, NULL, 0, 0,					\
   6075 		"NULL context pointer\n");				\
   6076 	return(-1);							\
   6077     }									\
   6078 
   6079 
   6080 #define CHECK_CONTEXT(ctxt)						\
   6081     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6082         (ctxt->doc->children == NULL)) {				\
   6083 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6084 	return(NULL);							\
   6085     }
   6086 
   6087 
   6088 /**
   6089  * xmlXPathNewParserContext:
   6090  * @str:  the XPath expression
   6091  * @ctxt:  the XPath context
   6092  *
   6093  * Create a new xmlXPathParserContext
   6094  *
   6095  * Returns the xmlXPathParserContext just allocated.
   6096  */
   6097 xmlXPathParserContextPtr
   6098 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6099     xmlXPathParserContextPtr ret;
   6100 
   6101     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6102     if (ret == NULL) {
   6103         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6104 	return(NULL);
   6105     }
   6106     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6107     ret->cur = ret->base = str;
   6108     ret->context = ctxt;
   6109 
   6110     ret->comp = xmlXPathNewCompExpr();
   6111     if (ret->comp == NULL) {
   6112 	xmlFree(ret->valueTab);
   6113 	xmlFree(ret);
   6114 	return(NULL);
   6115     }
   6116     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6117         ret->comp->dict = ctxt->dict;
   6118 	xmlDictReference(ret->comp->dict);
   6119     }
   6120 
   6121     return(ret);
   6122 }
   6123 
   6124 /**
   6125  * xmlXPathCompParserContext:
   6126  * @comp:  the XPath compiled expression
   6127  * @ctxt:  the XPath context
   6128  *
   6129  * Create a new xmlXPathParserContext when processing a compiled expression
   6130  *
   6131  * Returns the xmlXPathParserContext just allocated.
   6132  */
   6133 static xmlXPathParserContextPtr
   6134 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6135     xmlXPathParserContextPtr ret;
   6136 
   6137     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6138     if (ret == NULL) {
   6139         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6140 	return(NULL);
   6141     }
   6142     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6143 
   6144     /* Allocate the value stack */
   6145     ret->valueTab = (xmlXPathObjectPtr *)
   6146                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6147     if (ret->valueTab == NULL) {
   6148 	xmlFree(ret);
   6149 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6150 	return(NULL);
   6151     }
   6152     ret->valueNr = 0;
   6153     ret->valueMax = 10;
   6154     ret->value = NULL;
   6155 
   6156     ret->context = ctxt;
   6157     ret->comp = comp;
   6158 
   6159     return(ret);
   6160 }
   6161 
   6162 /**
   6163  * xmlXPathFreeParserContext:
   6164  * @ctxt:  the context to free
   6165  *
   6166  * Free up an xmlXPathParserContext
   6167  */
   6168 void
   6169 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6170     if (ctxt->valueTab != NULL) {
   6171         xmlFree(ctxt->valueTab);
   6172     }
   6173     if (ctxt->comp != NULL) {
   6174 #ifdef XPATH_STREAMING
   6175 	if (ctxt->comp->stream != NULL) {
   6176 	    xmlFreePatternList(ctxt->comp->stream);
   6177 	    ctxt->comp->stream = NULL;
   6178 	}
   6179 #endif
   6180 	xmlXPathFreeCompExpr(ctxt->comp);
   6181     }
   6182     xmlFree(ctxt);
   6183 }
   6184 
   6185 /************************************************************************
   6186  *									*
   6187  *		The implicit core function library			*
   6188  *									*
   6189  ************************************************************************/
   6190 
   6191 /**
   6192  * xmlXPathNodeValHash:
   6193  * @node:  a node pointer
   6194  *
   6195  * Function computing the beginning of the string value of the node,
   6196  * used to speed up comparisons
   6197  *
   6198  * Returns an int usable as a hash
   6199  */
   6200 static unsigned int
   6201 xmlXPathNodeValHash(xmlNodePtr node) {
   6202     int len = 2;
   6203     const xmlChar * string = NULL;
   6204     xmlNodePtr tmp = NULL;
   6205     unsigned int ret = 0;
   6206 
   6207     if (node == NULL)
   6208 	return(0);
   6209 
   6210     if (node->type == XML_DOCUMENT_NODE) {
   6211 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6212 	if (tmp == NULL)
   6213 	    node = node->children;
   6214 	else
   6215 	    node = tmp;
   6216 
   6217 	if (node == NULL)
   6218 	    return(0);
   6219     }
   6220 
   6221     switch (node->type) {
   6222 	case XML_COMMENT_NODE:
   6223 	case XML_PI_NODE:
   6224 	case XML_CDATA_SECTION_NODE:
   6225 	case XML_TEXT_NODE:
   6226 	    string = node->content;
   6227 	    if (string == NULL)
   6228 		return(0);
   6229 	    if (string[0] == 0)
   6230 		return(0);
   6231 	    return(((unsigned int) string[0]) +
   6232 		   (((unsigned int) string[1]) << 8));
   6233 	case XML_NAMESPACE_DECL:
   6234 	    string = ((xmlNsPtr)node)->href;
   6235 	    if (string == NULL)
   6236 		return(0);
   6237 	    if (string[0] == 0)
   6238 		return(0);
   6239 	    return(((unsigned int) string[0]) +
   6240 		   (((unsigned int) string[1]) << 8));
   6241 	case XML_ATTRIBUTE_NODE:
   6242 	    tmp = ((xmlAttrPtr) node)->children;
   6243 	    break;
   6244 	case XML_ELEMENT_NODE:
   6245 	    tmp = node->children;
   6246 	    break;
   6247 	default:
   6248 	    return(0);
   6249     }
   6250     while (tmp != NULL) {
   6251 	switch (tmp->type) {
   6252 	    case XML_COMMENT_NODE:
   6253 	    case XML_PI_NODE:
   6254 	    case XML_CDATA_SECTION_NODE:
   6255 	    case XML_TEXT_NODE:
   6256 		string = tmp->content;
   6257 		break;
   6258 	    case XML_NAMESPACE_DECL:
   6259 		string = ((xmlNsPtr)tmp)->href;
   6260 		break;
   6261 	    default:
   6262 		break;
   6263 	}
   6264 	if ((string != NULL) && (string[0] != 0)) {
   6265 	    if (len == 1) {
   6266 		return(ret + (((unsigned int) string[0]) << 8));
   6267 	    }
   6268 	    if (string[1] == 0) {
   6269 		len = 1;
   6270 		ret = (unsigned int) string[0];
   6271 	    } else {
   6272 		return(((unsigned int) string[0]) +
   6273 		       (((unsigned int) string[1]) << 8));
   6274 	    }
   6275 	}
   6276 	/*
   6277 	 * Skip to next node
   6278 	 */
   6279 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6280 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6281 		tmp = tmp->children;
   6282 		continue;
   6283 	    }
   6284 	}
   6285 	if (tmp == node)
   6286 	    break;
   6287 
   6288 	if (tmp->next != NULL) {
   6289 	    tmp = tmp->next;
   6290 	    continue;
   6291 	}
   6292 
   6293 	do {
   6294 	    tmp = tmp->parent;
   6295 	    if (tmp == NULL)
   6296 		break;
   6297 	    if (tmp == node) {
   6298 		tmp = NULL;
   6299 		break;
   6300 	    }
   6301 	    if (tmp->next != NULL) {
   6302 		tmp = tmp->next;
   6303 		break;
   6304 	    }
   6305 	} while (tmp != NULL);
   6306     }
   6307     return(ret);
   6308 }
   6309 
   6310 /**
   6311  * xmlXPathStringHash:
   6312  * @string:  a string
   6313  *
   6314  * Function computing the beginning of the string value of the node,
   6315  * used to speed up comparisons
   6316  *
   6317  * Returns an int usable as a hash
   6318  */
   6319 static unsigned int
   6320 xmlXPathStringHash(const xmlChar * string) {
   6321     if (string == NULL)
   6322 	return((unsigned int) 0);
   6323     if (string[0] == 0)
   6324 	return(0);
   6325     return(((unsigned int) string[0]) +
   6326 	   (((unsigned int) string[1]) << 8));
   6327 }
   6328 
   6329 /**
   6330  * xmlXPathCompareNodeSetFloat:
   6331  * @ctxt:  the XPath Parser context
   6332  * @inf:  less than (1) or greater than (0)
   6333  * @strict:  is the comparison strict
   6334  * @arg:  the node set
   6335  * @f:  the value
   6336  *
   6337  * Implement the compare operation between a nodeset and a number
   6338  *     @ns < @val    (1, 1, ...
   6339  *     @ns <= @val   (1, 0, ...
   6340  *     @ns > @val    (0, 1, ...
   6341  *     @ns >= @val   (0, 0, ...
   6342  *
   6343  * If one object to be compared is a node-set and the other is a number,
   6344  * then the comparison will be true if and only if there is a node in the
   6345  * node-set such that the result of performing the comparison on the number
   6346  * to be compared and on the result of converting the string-value of that
   6347  * node to a number using the number function is true.
   6348  *
   6349  * Returns 0 or 1 depending on the results of the test.
   6350  */
   6351 static int
   6352 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6353 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6354     int i, ret = 0;
   6355     xmlNodeSetPtr ns;
   6356     xmlChar *str2;
   6357 
   6358     if ((f == NULL) || (arg == NULL) ||
   6359 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6360 	xmlXPathReleaseObject(ctxt->context, arg);
   6361 	xmlXPathReleaseObject(ctxt->context, f);
   6362         return(0);
   6363     }
   6364     ns = arg->nodesetval;
   6365     if (ns != NULL) {
   6366 	for (i = 0;i < ns->nodeNr;i++) {
   6367 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6368 	     if (str2 != NULL) {
   6369 		 valuePush(ctxt,
   6370 			   xmlXPathCacheNewString(ctxt->context, str2));
   6371 		 xmlFree(str2);
   6372 		 xmlXPathNumberFunction(ctxt, 1);
   6373 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6374 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6375 		 if (ret)
   6376 		     break;
   6377 	     }
   6378 	}
   6379     }
   6380     xmlXPathReleaseObject(ctxt->context, arg);
   6381     xmlXPathReleaseObject(ctxt->context, f);
   6382     return(ret);
   6383 }
   6384 
   6385 /**
   6386  * xmlXPathCompareNodeSetString:
   6387  * @ctxt:  the XPath Parser context
   6388  * @inf:  less than (1) or greater than (0)
   6389  * @strict:  is the comparison strict
   6390  * @arg:  the node set
   6391  * @s:  the value
   6392  *
   6393  * Implement the compare operation between a nodeset and a string
   6394  *     @ns < @val    (1, 1, ...
   6395  *     @ns <= @val   (1, 0, ...
   6396  *     @ns > @val    (0, 1, ...
   6397  *     @ns >= @val   (0, 0, ...
   6398  *
   6399  * If one object to be compared is a node-set and the other is a string,
   6400  * then the comparison will be true if and only if there is a node in
   6401  * the node-set such that the result of performing the comparison on the
   6402  * string-value of the node and the other string is true.
   6403  *
   6404  * Returns 0 or 1 depending on the results of the test.
   6405  */
   6406 static int
   6407 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6408 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6409     int i, ret = 0;
   6410     xmlNodeSetPtr ns;
   6411     xmlChar *str2;
   6412 
   6413     if ((s == NULL) || (arg == NULL) ||
   6414 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6415 	xmlXPathReleaseObject(ctxt->context, arg);
   6416 	xmlXPathReleaseObject(ctxt->context, s);
   6417         return(0);
   6418     }
   6419     ns = arg->nodesetval;
   6420     if (ns != NULL) {
   6421 	for (i = 0;i < ns->nodeNr;i++) {
   6422 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6423 	     if (str2 != NULL) {
   6424 		 valuePush(ctxt,
   6425 			   xmlXPathCacheNewString(ctxt->context, str2));
   6426 		 xmlFree(str2);
   6427 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6428 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6429 		 if (ret)
   6430 		     break;
   6431 	     }
   6432 	}
   6433     }
   6434     xmlXPathReleaseObject(ctxt->context, arg);
   6435     xmlXPathReleaseObject(ctxt->context, s);
   6436     return(ret);
   6437 }
   6438 
   6439 /**
   6440  * xmlXPathCompareNodeSets:
   6441  * @inf:  less than (1) or greater than (0)
   6442  * @strict:  is the comparison strict
   6443  * @arg1:  the first node set object
   6444  * @arg2:  the second node set object
   6445  *
   6446  * Implement the compare operation on nodesets:
   6447  *
   6448  * If both objects to be compared are node-sets, then the comparison
   6449  * will be true if and only if there is a node in the first node-set
   6450  * and a node in the second node-set such that the result of performing
   6451  * the comparison on the string-values of the two nodes is true.
   6452  * ....
   6453  * When neither object to be compared is a node-set and the operator
   6454  * is <=, <, >= or >, then the objects are compared by converting both
   6455  * objects to numbers and comparing the numbers according to IEEE 754.
   6456  * ....
   6457  * The number function converts its argument to a number as follows:
   6458  *  - a string that consists of optional whitespace followed by an
   6459  *    optional minus sign followed by a Number followed by whitespace
   6460  *    is converted to the IEEE 754 number that is nearest (according
   6461  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6462  *    represented by the string; any other string is converted to NaN
   6463  *
   6464  * Conclusion all nodes need to be converted first to their string value
   6465  * and then the comparison must be done when possible
   6466  */
   6467 static int
   6468 xmlXPathCompareNodeSets(int inf, int strict,
   6469 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6470     int i, j, init = 0;
   6471     double val1;
   6472     double *values2;
   6473     int ret = 0;
   6474     xmlNodeSetPtr ns1;
   6475     xmlNodeSetPtr ns2;
   6476 
   6477     if ((arg1 == NULL) ||
   6478 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6479 	xmlXPathFreeObject(arg2);
   6480         return(0);
   6481     }
   6482     if ((arg2 == NULL) ||
   6483 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6484 	xmlXPathFreeObject(arg1);
   6485 	xmlXPathFreeObject(arg2);
   6486         return(0);
   6487     }
   6488 
   6489     ns1 = arg1->nodesetval;
   6490     ns2 = arg2->nodesetval;
   6491 
   6492     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6493 	xmlXPathFreeObject(arg1);
   6494 	xmlXPathFreeObject(arg2);
   6495 	return(0);
   6496     }
   6497     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6498 	xmlXPathFreeObject(arg1);
   6499 	xmlXPathFreeObject(arg2);
   6500 	return(0);
   6501     }
   6502 
   6503     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6504     if (values2 == NULL) {
   6505         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6506 	xmlXPathFreeObject(arg1);
   6507 	xmlXPathFreeObject(arg2);
   6508 	return(0);
   6509     }
   6510     for (i = 0;i < ns1->nodeNr;i++) {
   6511 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6512 	if (xmlXPathIsNaN(val1))
   6513 	    continue;
   6514 	for (j = 0;j < ns2->nodeNr;j++) {
   6515 	    if (init == 0) {
   6516 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6517 	    }
   6518 	    if (xmlXPathIsNaN(values2[j]))
   6519 		continue;
   6520 	    if (inf && strict)
   6521 		ret = (val1 < values2[j]);
   6522 	    else if (inf && !strict)
   6523 		ret = (val1 <= values2[j]);
   6524 	    else if (!inf && strict)
   6525 		ret = (val1 > values2[j]);
   6526 	    else if (!inf && !strict)
   6527 		ret = (val1 >= values2[j]);
   6528 	    if (ret)
   6529 		break;
   6530 	}
   6531 	if (ret)
   6532 	    break;
   6533 	init = 1;
   6534     }
   6535     xmlFree(values2);
   6536     xmlXPathFreeObject(arg1);
   6537     xmlXPathFreeObject(arg2);
   6538     return(ret);
   6539 }
   6540 
   6541 /**
   6542  * xmlXPathCompareNodeSetValue:
   6543  * @ctxt:  the XPath Parser context
   6544  * @inf:  less than (1) or greater than (0)
   6545  * @strict:  is the comparison strict
   6546  * @arg:  the node set
   6547  * @val:  the value
   6548  *
   6549  * Implement the compare operation between a nodeset and a value
   6550  *     @ns < @val    (1, 1, ...
   6551  *     @ns <= @val   (1, 0, ...
   6552  *     @ns > @val    (0, 1, ...
   6553  *     @ns >= @val   (0, 0, ...
   6554  *
   6555  * If one object to be compared is a node-set and the other is a boolean,
   6556  * then the comparison will be true if and only if the result of performing
   6557  * the comparison on the boolean and on the result of converting
   6558  * the node-set to a boolean using the boolean function is true.
   6559  *
   6560  * Returns 0 or 1 depending on the results of the test.
   6561  */
   6562 static int
   6563 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6564 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6565     if ((val == NULL) || (arg == NULL) ||
   6566 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6567         return(0);
   6568 
   6569     switch(val->type) {
   6570         case XPATH_NUMBER:
   6571 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6572         case XPATH_NODESET:
   6573         case XPATH_XSLT_TREE:
   6574 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6575         case XPATH_STRING:
   6576 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6577         case XPATH_BOOLEAN:
   6578 	    valuePush(ctxt, arg);
   6579 	    xmlXPathBooleanFunction(ctxt, 1);
   6580 	    valuePush(ctxt, val);
   6581 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6582 	default:
   6583 	    TODO
   6584     }
   6585     return(0);
   6586 }
   6587 
   6588 /**
   6589  * xmlXPathEqualNodeSetString:
   6590  * @arg:  the nodeset object argument
   6591  * @str:  the string to compare to.
   6592  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6593  *
   6594  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6595  * If one object to be compared is a node-set and the other is a string,
   6596  * then the comparison will be true if and only if there is a node in
   6597  * the node-set such that the result of performing the comparison on the
   6598  * string-value of the node and the other string is true.
   6599  *
   6600  * Returns 0 or 1 depending on the results of the test.
   6601  */
   6602 static int
   6603 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6604 {
   6605     int i;
   6606     xmlNodeSetPtr ns;
   6607     xmlChar *str2;
   6608     unsigned int hash;
   6609 
   6610     if ((str == NULL) || (arg == NULL) ||
   6611         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6612         return (0);
   6613     ns = arg->nodesetval;
   6614     /*
   6615      * A NULL nodeset compared with a string is always false
   6616      * (since there is no node equal, and no node not equal)
   6617      */
   6618     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6619         return (0);
   6620     hash = xmlXPathStringHash(str);
   6621     for (i = 0; i < ns->nodeNr; i++) {
   6622         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6623             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6624             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6625                 xmlFree(str2);
   6626 		if (neq)
   6627 		    continue;
   6628                 return (1);
   6629 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6630 		if (neq)
   6631 		    continue;
   6632                 return (1);
   6633             } else if (neq) {
   6634 		if (str2 != NULL)
   6635 		    xmlFree(str2);
   6636 		return (1);
   6637 	    }
   6638             if (str2 != NULL)
   6639                 xmlFree(str2);
   6640         } else if (neq)
   6641 	    return (1);
   6642     }
   6643     return (0);
   6644 }
   6645 
   6646 /**
   6647  * xmlXPathEqualNodeSetFloat:
   6648  * @arg:  the nodeset object argument
   6649  * @f:  the float to compare to
   6650  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6651  *
   6652  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6653  * If one object to be compared is a node-set and the other is a number,
   6654  * then the comparison will be true if and only if there is a node in
   6655  * the node-set such that the result of performing the comparison on the
   6656  * number to be compared and on the result of converting the string-value
   6657  * of that node to a number using the number function is true.
   6658  *
   6659  * Returns 0 or 1 depending on the results of the test.
   6660  */
   6661 static int
   6662 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6663     xmlXPathObjectPtr arg, double f, int neq) {
   6664   int i, ret=0;
   6665   xmlNodeSetPtr ns;
   6666   xmlChar *str2;
   6667   xmlXPathObjectPtr val;
   6668   double v;
   6669 
   6670     if ((arg == NULL) ||
   6671 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6672         return(0);
   6673 
   6674     ns = arg->nodesetval;
   6675     if (ns != NULL) {
   6676 	for (i=0;i<ns->nodeNr;i++) {
   6677 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6678 	    if (str2 != NULL) {
   6679 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6680 		xmlFree(str2);
   6681 		xmlXPathNumberFunction(ctxt, 1);
   6682 		val = valuePop(ctxt);
   6683 		v = val->floatval;
   6684 		xmlXPathReleaseObject(ctxt->context, val);
   6685 		if (!xmlXPathIsNaN(v)) {
   6686 		    if ((!neq) && (v==f)) {
   6687 			ret = 1;
   6688 			break;
   6689 		    } else if ((neq) && (v!=f)) {
   6690 			ret = 1;
   6691 			break;
   6692 		    }
   6693 		} else {	/* NaN is unequal to any value */
   6694 		    if (neq)
   6695 			ret = 1;
   6696 		}
   6697 	    }
   6698 	}
   6699     }
   6700 
   6701     return(ret);
   6702 }
   6703 
   6704 
   6705 /**
   6706  * xmlXPathEqualNodeSets:
   6707  * @arg1:  first nodeset object argument
   6708  * @arg2:  second nodeset object argument
   6709  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6710  *
   6711  * Implement the equal / not equal operation on XPath nodesets:
   6712  * @arg1 == @arg2  or  @arg1 != @arg2
   6713  * If both objects to be compared are node-sets, then the comparison
   6714  * will be true if and only if there is a node in the first node-set and
   6715  * a node in the second node-set such that the result of performing the
   6716  * comparison on the string-values of the two nodes is true.
   6717  *
   6718  * (needless to say, this is a costly operation)
   6719  *
   6720  * Returns 0 or 1 depending on the results of the test.
   6721  */
   6722 static int
   6723 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6724     int i, j;
   6725     unsigned int *hashs1;
   6726     unsigned int *hashs2;
   6727     xmlChar **values1;
   6728     xmlChar **values2;
   6729     int ret = 0;
   6730     xmlNodeSetPtr ns1;
   6731     xmlNodeSetPtr ns2;
   6732 
   6733     if ((arg1 == NULL) ||
   6734 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6735         return(0);
   6736     if ((arg2 == NULL) ||
   6737 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6738         return(0);
   6739 
   6740     ns1 = arg1->nodesetval;
   6741     ns2 = arg2->nodesetval;
   6742 
   6743     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6744 	return(0);
   6745     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6746 	return(0);
   6747 
   6748     /*
   6749      * for equal, check if there is a node pertaining to both sets
   6750      */
   6751     if (neq == 0)
   6752 	for (i = 0;i < ns1->nodeNr;i++)
   6753 	    for (j = 0;j < ns2->nodeNr;j++)
   6754 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6755 		    return(1);
   6756 
   6757     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6758     if (values1 == NULL) {
   6759         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6760 	return(0);
   6761     }
   6762     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6763     if (hashs1 == NULL) {
   6764         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6765 	xmlFree(values1);
   6766 	return(0);
   6767     }
   6768     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6769     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6770     if (values2 == NULL) {
   6771         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6772 	xmlFree(hashs1);
   6773 	xmlFree(values1);
   6774 	return(0);
   6775     }
   6776     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6777     if (hashs2 == NULL) {
   6778         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6779 	xmlFree(hashs1);
   6780 	xmlFree(values1);
   6781 	xmlFree(values2);
   6782 	return(0);
   6783     }
   6784     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6785     for (i = 0;i < ns1->nodeNr;i++) {
   6786 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6787 	for (j = 0;j < ns2->nodeNr;j++) {
   6788 	    if (i == 0)
   6789 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6790 	    if (hashs1[i] != hashs2[j]) {
   6791 		if (neq) {
   6792 		    ret = 1;
   6793 		    break;
   6794 		}
   6795 	    }
   6796 	    else {
   6797 		if (values1[i] == NULL)
   6798 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6799 		if (values2[j] == NULL)
   6800 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6801 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6802 		if (ret)
   6803 		    break;
   6804 	    }
   6805 	}
   6806 	if (ret)
   6807 	    break;
   6808     }
   6809     for (i = 0;i < ns1->nodeNr;i++)
   6810 	if (values1[i] != NULL)
   6811 	    xmlFree(values1[i]);
   6812     for (j = 0;j < ns2->nodeNr;j++)
   6813 	if (values2[j] != NULL)
   6814 	    xmlFree(values2[j]);
   6815     xmlFree(values1);
   6816     xmlFree(values2);
   6817     xmlFree(hashs1);
   6818     xmlFree(hashs2);
   6819     return(ret);
   6820 }
   6821 
   6822 static int
   6823 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6824   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6825     int ret = 0;
   6826     /*
   6827      *At this point we are assured neither arg1 nor arg2
   6828      *is a nodeset, so we can just pick the appropriate routine.
   6829      */
   6830     switch (arg1->type) {
   6831         case XPATH_UNDEFINED:
   6832 #ifdef DEBUG_EXPR
   6833 	    xmlGenericError(xmlGenericErrorContext,
   6834 		    "Equal: undefined\n");
   6835 #endif
   6836 	    break;
   6837         case XPATH_BOOLEAN:
   6838 	    switch (arg2->type) {
   6839 	        case XPATH_UNDEFINED:
   6840 #ifdef DEBUG_EXPR
   6841 		    xmlGenericError(xmlGenericErrorContext,
   6842 			    "Equal: undefined\n");
   6843 #endif
   6844 		    break;
   6845 		case XPATH_BOOLEAN:
   6846 #ifdef DEBUG_EXPR
   6847 		    xmlGenericError(xmlGenericErrorContext,
   6848 			    "Equal: %d boolean %d \n",
   6849 			    arg1->boolval, arg2->boolval);
   6850 #endif
   6851 		    ret = (arg1->boolval == arg2->boolval);
   6852 		    break;
   6853 		case XPATH_NUMBER:
   6854 		    ret = (arg1->boolval ==
   6855 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   6856 		    break;
   6857 		case XPATH_STRING:
   6858 		    if ((arg2->stringval == NULL) ||
   6859 			(arg2->stringval[0] == 0)) ret = 0;
   6860 		    else
   6861 			ret = 1;
   6862 		    ret = (arg1->boolval == ret);
   6863 		    break;
   6864 		case XPATH_USERS:
   6865 		case XPATH_POINT:
   6866 		case XPATH_RANGE:
   6867 		case XPATH_LOCATIONSET:
   6868 		    TODO
   6869 		    break;
   6870 		case XPATH_NODESET:
   6871 		case XPATH_XSLT_TREE:
   6872 		    break;
   6873 	    }
   6874 	    break;
   6875         case XPATH_NUMBER:
   6876 	    switch (arg2->type) {
   6877 	        case XPATH_UNDEFINED:
   6878 #ifdef DEBUG_EXPR
   6879 		    xmlGenericError(xmlGenericErrorContext,
   6880 			    "Equal: undefined\n");
   6881 #endif
   6882 		    break;
   6883 		case XPATH_BOOLEAN:
   6884 		    ret = (arg2->boolval==
   6885 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   6886 		    break;
   6887 		case XPATH_STRING:
   6888 		    valuePush(ctxt, arg2);
   6889 		    xmlXPathNumberFunction(ctxt, 1);
   6890 		    arg2 = valuePop(ctxt);
   6891 		    /* no break on purpose */
   6892 		case XPATH_NUMBER:
   6893 		    /* Hand check NaN and Infinity equalities */
   6894 		    if (xmlXPathIsNaN(arg1->floatval) ||
   6895 			    xmlXPathIsNaN(arg2->floatval)) {
   6896 		        ret = 0;
   6897 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   6898 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   6899 			    ret = 1;
   6900 			else
   6901 			    ret = 0;
   6902 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   6903 			if (xmlXPathIsInf(arg2->floatval) == -1)
   6904 			    ret = 1;
   6905 			else
   6906 			    ret = 0;
   6907 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   6908 			if (xmlXPathIsInf(arg1->floatval) == 1)
   6909 			    ret = 1;
   6910 			else
   6911 			    ret = 0;
   6912 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   6913 			if (xmlXPathIsInf(arg1->floatval) == -1)
   6914 			    ret = 1;
   6915 			else
   6916 			    ret = 0;
   6917 		    } else {
   6918 		        ret = (arg1->floatval == arg2->floatval);
   6919 		    }
   6920 		    break;
   6921 		case XPATH_USERS:
   6922 		case XPATH_POINT:
   6923 		case XPATH_RANGE:
   6924 		case XPATH_LOCATIONSET:
   6925 		    TODO
   6926 		    break;
   6927 		case XPATH_NODESET:
   6928 		case XPATH_XSLT_TREE:
   6929 		    break;
   6930 	    }
   6931 	    break;
   6932         case XPATH_STRING:
   6933 	    switch (arg2->type) {
   6934 	        case XPATH_UNDEFINED:
   6935 #ifdef DEBUG_EXPR
   6936 		    xmlGenericError(xmlGenericErrorContext,
   6937 			    "Equal: undefined\n");
   6938 #endif
   6939 		    break;
   6940 		case XPATH_BOOLEAN:
   6941 		    if ((arg1->stringval == NULL) ||
   6942 			(arg1->stringval[0] == 0)) ret = 0;
   6943 		    else
   6944 			ret = 1;
   6945 		    ret = (arg2->boolval == ret);
   6946 		    break;
   6947 		case XPATH_STRING:
   6948 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   6949 		    break;
   6950 		case XPATH_NUMBER:
   6951 		    valuePush(ctxt, arg1);
   6952 		    xmlXPathNumberFunction(ctxt, 1);
   6953 		    arg1 = valuePop(ctxt);
   6954 		    /* Hand check NaN and Infinity equalities */
   6955 		    if (xmlXPathIsNaN(arg1->floatval) ||
   6956 			    xmlXPathIsNaN(arg2->floatval)) {
   6957 		        ret = 0;
   6958 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   6959 			if (xmlXPathIsInf(arg2->floatval) == 1)
   6960 			    ret = 1;
   6961 			else
   6962 			    ret = 0;
   6963 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   6964 			if (xmlXPathIsInf(arg2->floatval) == -1)
   6965 			    ret = 1;
   6966 			else
   6967 			    ret = 0;
   6968 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   6969 			if (xmlXPathIsInf(arg1->floatval) == 1)
   6970 			    ret = 1;
   6971 			else
   6972 			    ret = 0;
   6973 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   6974 			if (xmlXPathIsInf(arg1->floatval) == -1)
   6975 			    ret = 1;
   6976 			else
   6977 			    ret = 0;
   6978 		    } else {
   6979 		        ret = (arg1->floatval == arg2->floatval);
   6980 		    }
   6981 		    break;
   6982 		case XPATH_USERS:
   6983 		case XPATH_POINT:
   6984 		case XPATH_RANGE:
   6985 		case XPATH_LOCATIONSET:
   6986 		    TODO
   6987 		    break;
   6988 		case XPATH_NODESET:
   6989 		case XPATH_XSLT_TREE:
   6990 		    break;
   6991 	    }
   6992 	    break;
   6993         case XPATH_USERS:
   6994 	case XPATH_POINT:
   6995 	case XPATH_RANGE:
   6996 	case XPATH_LOCATIONSET:
   6997 	    TODO
   6998 	    break;
   6999 	case XPATH_NODESET:
   7000 	case XPATH_XSLT_TREE:
   7001 	    break;
   7002     }
   7003     xmlXPathReleaseObject(ctxt->context, arg1);
   7004     xmlXPathReleaseObject(ctxt->context, arg2);
   7005     return(ret);
   7006 }
   7007 
   7008 /**
   7009  * xmlXPathEqualValues:
   7010  * @ctxt:  the XPath Parser context
   7011  *
   7012  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7013  *
   7014  * Returns 0 or 1 depending on the results of the test.
   7015  */
   7016 int
   7017 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7018     xmlXPathObjectPtr arg1, arg2, argtmp;
   7019     int ret = 0;
   7020 
   7021     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7022     arg2 = valuePop(ctxt);
   7023     arg1 = valuePop(ctxt);
   7024     if ((arg1 == NULL) || (arg2 == NULL)) {
   7025 	if (arg1 != NULL)
   7026 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7027 	else
   7028 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7029 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7030     }
   7031 
   7032     if (arg1 == arg2) {
   7033 #ifdef DEBUG_EXPR
   7034         xmlGenericError(xmlGenericErrorContext,
   7035 		"Equal: by pointer\n");
   7036 #endif
   7037 	xmlXPathFreeObject(arg1);
   7038         return(1);
   7039     }
   7040 
   7041     /*
   7042      *If either argument is a nodeset, it's a 'special case'
   7043      */
   7044     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7045       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7046 	/*
   7047 	 *Hack it to assure arg1 is the nodeset
   7048 	 */
   7049 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7050 		argtmp = arg2;
   7051 		arg2 = arg1;
   7052 		arg1 = argtmp;
   7053 	}
   7054 	switch (arg2->type) {
   7055 	    case XPATH_UNDEFINED:
   7056 #ifdef DEBUG_EXPR
   7057 		xmlGenericError(xmlGenericErrorContext,
   7058 			"Equal: undefined\n");
   7059 #endif
   7060 		break;
   7061 	    case XPATH_NODESET:
   7062 	    case XPATH_XSLT_TREE:
   7063 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7064 		break;
   7065 	    case XPATH_BOOLEAN:
   7066 		if ((arg1->nodesetval == NULL) ||
   7067 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7068 		else
   7069 		    ret = 1;
   7070 		ret = (ret == arg2->boolval);
   7071 		break;
   7072 	    case XPATH_NUMBER:
   7073 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7074 		break;
   7075 	    case XPATH_STRING:
   7076 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7077 		break;
   7078 	    case XPATH_USERS:
   7079 	    case XPATH_POINT:
   7080 	    case XPATH_RANGE:
   7081 	    case XPATH_LOCATIONSET:
   7082 		TODO
   7083 		break;
   7084 	}
   7085 	xmlXPathReleaseObject(ctxt->context, arg1);
   7086 	xmlXPathReleaseObject(ctxt->context, arg2);
   7087 	return(ret);
   7088     }
   7089 
   7090     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7091 }
   7092 
   7093 /**
   7094  * xmlXPathNotEqualValues:
   7095  * @ctxt:  the XPath Parser context
   7096  *
   7097  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7098  *
   7099  * Returns 0 or 1 depending on the results of the test.
   7100  */
   7101 int
   7102 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7103     xmlXPathObjectPtr arg1, arg2, argtmp;
   7104     int ret = 0;
   7105 
   7106     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7107     arg2 = valuePop(ctxt);
   7108     arg1 = valuePop(ctxt);
   7109     if ((arg1 == NULL) || (arg2 == NULL)) {
   7110 	if (arg1 != NULL)
   7111 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7112 	else
   7113 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7114 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7115     }
   7116 
   7117     if (arg1 == arg2) {
   7118 #ifdef DEBUG_EXPR
   7119         xmlGenericError(xmlGenericErrorContext,
   7120 		"NotEqual: by pointer\n");
   7121 #endif
   7122 	xmlXPathReleaseObject(ctxt->context, arg1);
   7123         return(0);
   7124     }
   7125 
   7126     /*
   7127      *If either argument is a nodeset, it's a 'special case'
   7128      */
   7129     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7130       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7131 	/*
   7132 	 *Hack it to assure arg1 is the nodeset
   7133 	 */
   7134 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7135 		argtmp = arg2;
   7136 		arg2 = arg1;
   7137 		arg1 = argtmp;
   7138 	}
   7139 	switch (arg2->type) {
   7140 	    case XPATH_UNDEFINED:
   7141 #ifdef DEBUG_EXPR
   7142 		xmlGenericError(xmlGenericErrorContext,
   7143 			"NotEqual: undefined\n");
   7144 #endif
   7145 		break;
   7146 	    case XPATH_NODESET:
   7147 	    case XPATH_XSLT_TREE:
   7148 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7149 		break;
   7150 	    case XPATH_BOOLEAN:
   7151 		if ((arg1->nodesetval == NULL) ||
   7152 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7153 		else
   7154 		    ret = 1;
   7155 		ret = (ret != arg2->boolval);
   7156 		break;
   7157 	    case XPATH_NUMBER:
   7158 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7159 		break;
   7160 	    case XPATH_STRING:
   7161 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7162 		break;
   7163 	    case XPATH_USERS:
   7164 	    case XPATH_POINT:
   7165 	    case XPATH_RANGE:
   7166 	    case XPATH_LOCATIONSET:
   7167 		TODO
   7168 		break;
   7169 	}
   7170 	xmlXPathReleaseObject(ctxt->context, arg1);
   7171 	xmlXPathReleaseObject(ctxt->context, arg2);
   7172 	return(ret);
   7173     }
   7174 
   7175     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7176 }
   7177 
   7178 /**
   7179  * xmlXPathCompareValues:
   7180  * @ctxt:  the XPath Parser context
   7181  * @inf:  less than (1) or greater than (0)
   7182  * @strict:  is the comparison strict
   7183  *
   7184  * Implement the compare operation on XPath objects:
   7185  *     @arg1 < @arg2    (1, 1, ...
   7186  *     @arg1 <= @arg2   (1, 0, ...
   7187  *     @arg1 > @arg2    (0, 1, ...
   7188  *     @arg1 >= @arg2   (0, 0, ...
   7189  *
   7190  * When neither object to be compared is a node-set and the operator is
   7191  * <=, <, >=, >, then the objects are compared by converted both objects
   7192  * to numbers and comparing the numbers according to IEEE 754. The <
   7193  * comparison will be true if and only if the first number is less than the
   7194  * second number. The <= comparison will be true if and only if the first
   7195  * number is less than or equal to the second number. The > comparison
   7196  * will be true if and only if the first number is greater than the second
   7197  * number. The >= comparison will be true if and only if the first number
   7198  * is greater than or equal to the second number.
   7199  *
   7200  * Returns 1 if the comparison succeeded, 0 if it failed
   7201  */
   7202 int
   7203 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7204     int ret = 0, arg1i = 0, arg2i = 0;
   7205     xmlXPathObjectPtr arg1, arg2;
   7206 
   7207     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7208     arg2 = valuePop(ctxt);
   7209     arg1 = valuePop(ctxt);
   7210     if ((arg1 == NULL) || (arg2 == NULL)) {
   7211 	if (arg1 != NULL)
   7212 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7213 	else
   7214 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7215 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7216     }
   7217 
   7218     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7219       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7220 	/*
   7221 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7222 	 * are not freed from within this routine; they will be freed from the
   7223 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7224 	 */
   7225 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7226 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7227 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7228 	} else {
   7229 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7230 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7231 			                          arg1, arg2);
   7232 	    } else {
   7233 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7234 			                          arg2, arg1);
   7235 	    }
   7236 	}
   7237 	return(ret);
   7238     }
   7239 
   7240     if (arg1->type != XPATH_NUMBER) {
   7241 	valuePush(ctxt, arg1);
   7242 	xmlXPathNumberFunction(ctxt, 1);
   7243 	arg1 = valuePop(ctxt);
   7244     }
   7245     if (arg1->type != XPATH_NUMBER) {
   7246 	xmlXPathFreeObject(arg1);
   7247 	xmlXPathFreeObject(arg2);
   7248 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7249     }
   7250     if (arg2->type != XPATH_NUMBER) {
   7251 	valuePush(ctxt, arg2);
   7252 	xmlXPathNumberFunction(ctxt, 1);
   7253 	arg2 = valuePop(ctxt);
   7254     }
   7255     if (arg2->type != XPATH_NUMBER) {
   7256 	xmlXPathReleaseObject(ctxt->context, arg1);
   7257 	xmlXPathReleaseObject(ctxt->context, arg2);
   7258 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7259     }
   7260     /*
   7261      * Add tests for infinity and nan
   7262      * => feedback on 3.4 for Inf and NaN
   7263      */
   7264     /* Hand check NaN and Infinity comparisons */
   7265     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7266 	ret=0;
   7267     } else {
   7268 	arg1i=xmlXPathIsInf(arg1->floatval);
   7269 	arg2i=xmlXPathIsInf(arg2->floatval);
   7270 	if (inf && strict) {
   7271 	    if ((arg1i == -1 && arg2i != -1) ||
   7272 		(arg2i == 1 && arg1i != 1)) {
   7273 		ret = 1;
   7274 	    } else if (arg1i == 0 && arg2i == 0) {
   7275 		ret = (arg1->floatval < arg2->floatval);
   7276 	    } else {
   7277 		ret = 0;
   7278 	    }
   7279 	}
   7280 	else if (inf && !strict) {
   7281 	    if (arg1i == -1 || arg2i == 1) {
   7282 		ret = 1;
   7283 	    } else if (arg1i == 0 && arg2i == 0) {
   7284 		ret = (arg1->floatval <= arg2->floatval);
   7285 	    } else {
   7286 		ret = 0;
   7287 	    }
   7288 	}
   7289 	else if (!inf && strict) {
   7290 	    if ((arg1i == 1 && arg2i != 1) ||
   7291 		(arg2i == -1 && arg1i != -1)) {
   7292 		ret = 1;
   7293 	    } else if (arg1i == 0 && arg2i == 0) {
   7294 		ret = (arg1->floatval > arg2->floatval);
   7295 	    } else {
   7296 		ret = 0;
   7297 	    }
   7298 	}
   7299 	else if (!inf && !strict) {
   7300 	    if (arg1i == 1 || arg2i == -1) {
   7301 		ret = 1;
   7302 	    } else if (arg1i == 0 && arg2i == 0) {
   7303 		ret = (arg1->floatval >= arg2->floatval);
   7304 	    } else {
   7305 		ret = 0;
   7306 	    }
   7307 	}
   7308     }
   7309     xmlXPathReleaseObject(ctxt->context, arg1);
   7310     xmlXPathReleaseObject(ctxt->context, arg2);
   7311     return(ret);
   7312 }
   7313 
   7314 /**
   7315  * xmlXPathValueFlipSign:
   7316  * @ctxt:  the XPath Parser context
   7317  *
   7318  * Implement the unary - operation on an XPath object
   7319  * The numeric operators convert their operands to numbers as if
   7320  * by calling the number function.
   7321  */
   7322 void
   7323 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7324     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7325     CAST_TO_NUMBER;
   7326     CHECK_TYPE(XPATH_NUMBER);
   7327     if (xmlXPathIsNaN(ctxt->value->floatval))
   7328         ctxt->value->floatval=xmlXPathNAN;
   7329     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
   7330         ctxt->value->floatval=xmlXPathNINF;
   7331     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
   7332         ctxt->value->floatval=xmlXPathPINF;
   7333     else if (ctxt->value->floatval == 0) {
   7334         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
   7335 	    ctxt->value->floatval = xmlXPathNZERO;
   7336 	else
   7337 	    ctxt->value->floatval = 0;
   7338     }
   7339     else
   7340         ctxt->value->floatval = - ctxt->value->floatval;
   7341 }
   7342 
   7343 /**
   7344  * xmlXPathAddValues:
   7345  * @ctxt:  the XPath Parser context
   7346  *
   7347  * Implement the add operation on XPath objects:
   7348  * The numeric operators convert their operands to numbers as if
   7349  * by calling the number function.
   7350  */
   7351 void
   7352 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7353     xmlXPathObjectPtr arg;
   7354     double val;
   7355 
   7356     arg = valuePop(ctxt);
   7357     if (arg == NULL)
   7358 	XP_ERROR(XPATH_INVALID_OPERAND);
   7359     val = xmlXPathCastToNumber(arg);
   7360     xmlXPathReleaseObject(ctxt->context, arg);
   7361     CAST_TO_NUMBER;
   7362     CHECK_TYPE(XPATH_NUMBER);
   7363     ctxt->value->floatval += val;
   7364 }
   7365 
   7366 /**
   7367  * xmlXPathSubValues:
   7368  * @ctxt:  the XPath Parser context
   7369  *
   7370  * Implement the subtraction operation on XPath objects:
   7371  * The numeric operators convert their operands to numbers as if
   7372  * by calling the number function.
   7373  */
   7374 void
   7375 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7376     xmlXPathObjectPtr arg;
   7377     double val;
   7378 
   7379     arg = valuePop(ctxt);
   7380     if (arg == NULL)
   7381 	XP_ERROR(XPATH_INVALID_OPERAND);
   7382     val = xmlXPathCastToNumber(arg);
   7383     xmlXPathReleaseObject(ctxt->context, arg);
   7384     CAST_TO_NUMBER;
   7385     CHECK_TYPE(XPATH_NUMBER);
   7386     ctxt->value->floatval -= val;
   7387 }
   7388 
   7389 /**
   7390  * xmlXPathMultValues:
   7391  * @ctxt:  the XPath Parser context
   7392  *
   7393  * Implement the multiply operation on XPath objects:
   7394  * The numeric operators convert their operands to numbers as if
   7395  * by calling the number function.
   7396  */
   7397 void
   7398 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7399     xmlXPathObjectPtr arg;
   7400     double val;
   7401 
   7402     arg = valuePop(ctxt);
   7403     if (arg == NULL)
   7404 	XP_ERROR(XPATH_INVALID_OPERAND);
   7405     val = xmlXPathCastToNumber(arg);
   7406     xmlXPathReleaseObject(ctxt->context, arg);
   7407     CAST_TO_NUMBER;
   7408     CHECK_TYPE(XPATH_NUMBER);
   7409     ctxt->value->floatval *= val;
   7410 }
   7411 
   7412 /**
   7413  * xmlXPathDivValues:
   7414  * @ctxt:  the XPath Parser context
   7415  *
   7416  * Implement the div operation on XPath objects @arg1 / @arg2:
   7417  * The numeric operators convert their operands to numbers as if
   7418  * by calling the number function.
   7419  */
   7420 void
   7421 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7422     xmlXPathObjectPtr arg;
   7423     double val;
   7424 
   7425     arg = valuePop(ctxt);
   7426     if (arg == NULL)
   7427 	XP_ERROR(XPATH_INVALID_OPERAND);
   7428     val = xmlXPathCastToNumber(arg);
   7429     xmlXPathReleaseObject(ctxt->context, arg);
   7430     CAST_TO_NUMBER;
   7431     CHECK_TYPE(XPATH_NUMBER);
   7432     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
   7433 	ctxt->value->floatval = xmlXPathNAN;
   7434     else if (val == 0 && xmlXPathGetSign(val) != 0) {
   7435 	if (ctxt->value->floatval == 0)
   7436 	    ctxt->value->floatval = xmlXPathNAN;
   7437 	else if (ctxt->value->floatval > 0)
   7438 	    ctxt->value->floatval = xmlXPathNINF;
   7439 	else if (ctxt->value->floatval < 0)
   7440 	    ctxt->value->floatval = xmlXPathPINF;
   7441     }
   7442     else if (val == 0) {
   7443 	if (ctxt->value->floatval == 0)
   7444 	    ctxt->value->floatval = xmlXPathNAN;
   7445 	else if (ctxt->value->floatval > 0)
   7446 	    ctxt->value->floatval = xmlXPathPINF;
   7447 	else if (ctxt->value->floatval < 0)
   7448 	    ctxt->value->floatval = xmlXPathNINF;
   7449     } else
   7450 	ctxt->value->floatval /= val;
   7451 }
   7452 
   7453 /**
   7454  * xmlXPathModValues:
   7455  * @ctxt:  the XPath Parser context
   7456  *
   7457  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7458  * The numeric operators convert their operands to numbers as if
   7459  * by calling the number function.
   7460  */
   7461 void
   7462 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7463     xmlXPathObjectPtr arg;
   7464     double arg1, arg2;
   7465 
   7466     arg = valuePop(ctxt);
   7467     if (arg == NULL)
   7468 	XP_ERROR(XPATH_INVALID_OPERAND);
   7469     arg2 = xmlXPathCastToNumber(arg);
   7470     xmlXPathReleaseObject(ctxt->context, arg);
   7471     CAST_TO_NUMBER;
   7472     CHECK_TYPE(XPATH_NUMBER);
   7473     arg1 = ctxt->value->floatval;
   7474     if (arg2 == 0)
   7475 	ctxt->value->floatval = xmlXPathNAN;
   7476     else {
   7477 	ctxt->value->floatval = fmod(arg1, arg2);
   7478     }
   7479 }
   7480 
   7481 /************************************************************************
   7482  *									*
   7483  *		The traversal functions					*
   7484  *									*
   7485  ************************************************************************/
   7486 
   7487 /*
   7488  * A traversal function enumerates nodes along an axis.
   7489  * Initially it must be called with NULL, and it indicates
   7490  * termination on the axis by returning NULL.
   7491  */
   7492 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7493                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7494 
   7495 /*
   7496  * xmlXPathTraversalFunctionExt:
   7497  * A traversal function enumerates nodes along an axis.
   7498  * Initially it must be called with NULL, and it indicates
   7499  * termination on the axis by returning NULL.
   7500  * The context node of the traversal is specified via @contextNode.
   7501  */
   7502 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7503                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7504 
   7505 /*
   7506  * xmlXPathNodeSetMergeFunction:
   7507  * Used for merging node sets in xmlXPathCollectAndTest().
   7508  */
   7509 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7510 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7511 
   7512 
   7513 /**
   7514  * xmlXPathNextSelf:
   7515  * @ctxt:  the XPath Parser context
   7516  * @cur:  the current node in the traversal
   7517  *
   7518  * Traversal function for the "self" direction
   7519  * The self axis contains just the context node itself
   7520  *
   7521  * Returns the next element following that axis
   7522  */
   7523 xmlNodePtr
   7524 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7525     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7526     if (cur == NULL)
   7527         return(ctxt->context->node);
   7528     return(NULL);
   7529 }
   7530 
   7531 /**
   7532  * xmlXPathNextChild:
   7533  * @ctxt:  the XPath Parser context
   7534  * @cur:  the current node in the traversal
   7535  *
   7536  * Traversal function for the "child" direction
   7537  * The child axis contains the children of the context node in document order.
   7538  *
   7539  * Returns the next element following that axis
   7540  */
   7541 xmlNodePtr
   7542 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7543     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7544     if (cur == NULL) {
   7545 	if (ctxt->context->node == NULL) return(NULL);
   7546 	switch (ctxt->context->node->type) {
   7547             case XML_ELEMENT_NODE:
   7548             case XML_TEXT_NODE:
   7549             case XML_CDATA_SECTION_NODE:
   7550             case XML_ENTITY_REF_NODE:
   7551             case XML_ENTITY_NODE:
   7552             case XML_PI_NODE:
   7553             case XML_COMMENT_NODE:
   7554             case XML_NOTATION_NODE:
   7555             case XML_DTD_NODE:
   7556 		return(ctxt->context->node->children);
   7557             case XML_DOCUMENT_NODE:
   7558             case XML_DOCUMENT_TYPE_NODE:
   7559             case XML_DOCUMENT_FRAG_NODE:
   7560             case XML_HTML_DOCUMENT_NODE:
   7561 #ifdef LIBXML_DOCB_ENABLED
   7562 	    case XML_DOCB_DOCUMENT_NODE:
   7563 #endif
   7564 		return(((xmlDocPtr) ctxt->context->node)->children);
   7565 	    case XML_ELEMENT_DECL:
   7566 	    case XML_ATTRIBUTE_DECL:
   7567 	    case XML_ENTITY_DECL:
   7568             case XML_ATTRIBUTE_NODE:
   7569 	    case XML_NAMESPACE_DECL:
   7570 	    case XML_XINCLUDE_START:
   7571 	    case XML_XINCLUDE_END:
   7572 		return(NULL);
   7573 	}
   7574 	return(NULL);
   7575     }
   7576     if ((cur->type == XML_DOCUMENT_NODE) ||
   7577         (cur->type == XML_HTML_DOCUMENT_NODE))
   7578 	return(NULL);
   7579     return(cur->next);
   7580 }
   7581 
   7582 /**
   7583  * xmlXPathNextChildElement:
   7584  * @ctxt:  the XPath Parser context
   7585  * @cur:  the current node in the traversal
   7586  *
   7587  * Traversal function for the "child" direction and nodes of type element.
   7588  * The child axis contains the children of the context node in document order.
   7589  *
   7590  * Returns the next element following that axis
   7591  */
   7592 static xmlNodePtr
   7593 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7594     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7595     if (cur == NULL) {
   7596 	cur = ctxt->context->node;
   7597 	if (cur == NULL) return(NULL);
   7598 	/*
   7599 	* Get the first element child.
   7600 	*/
   7601 	switch (cur->type) {
   7602             case XML_ELEMENT_NODE:
   7603 	    case XML_DOCUMENT_FRAG_NODE:
   7604 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7605             case XML_ENTITY_NODE:
   7606 		cur = cur->children;
   7607 		if (cur != NULL) {
   7608 		    if (cur->type == XML_ELEMENT_NODE)
   7609 			return(cur);
   7610 		    do {
   7611 			cur = cur->next;
   7612 		    } while ((cur != NULL) &&
   7613 			(cur->type != XML_ELEMENT_NODE));
   7614 		    return(cur);
   7615 		}
   7616 		return(NULL);
   7617             case XML_DOCUMENT_NODE:
   7618             case XML_HTML_DOCUMENT_NODE:
   7619 #ifdef LIBXML_DOCB_ENABLED
   7620 	    case XML_DOCB_DOCUMENT_NODE:
   7621 #endif
   7622 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7623 	    default:
   7624 		return(NULL);
   7625 	}
   7626 	return(NULL);
   7627     }
   7628     /*
   7629     * Get the next sibling element node.
   7630     */
   7631     switch (cur->type) {
   7632 	case XML_ELEMENT_NODE:
   7633 	case XML_TEXT_NODE:
   7634 	case XML_ENTITY_REF_NODE:
   7635 	case XML_ENTITY_NODE:
   7636 	case XML_CDATA_SECTION_NODE:
   7637 	case XML_PI_NODE:
   7638 	case XML_COMMENT_NODE:
   7639 	case XML_XINCLUDE_END:
   7640 	    break;
   7641 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7642 	default:
   7643 	    return(NULL);
   7644     }
   7645     if (cur->next != NULL) {
   7646 	if (cur->next->type == XML_ELEMENT_NODE)
   7647 	    return(cur->next);
   7648 	cur = cur->next;
   7649 	do {
   7650 	    cur = cur->next;
   7651 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7652 	return(cur);
   7653     }
   7654     return(NULL);
   7655 }
   7656 
   7657 /**
   7658  * xmlXPathNextDescendantOrSelfElemParent:
   7659  * @ctxt:  the XPath Parser context
   7660  * @cur:  the current node in the traversal
   7661  *
   7662  * Traversal function for the "descendant-or-self" axis.
   7663  * Additionally it returns only nodes which can be parents of
   7664  * element nodes.
   7665  *
   7666  *
   7667  * Returns the next element following that axis
   7668  */
   7669 static xmlNodePtr
   7670 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7671 				       xmlNodePtr contextNode)
   7672 {
   7673     if (cur == NULL) {
   7674 	if (contextNode == NULL)
   7675 	    return(NULL);
   7676 	switch (contextNode->type) {
   7677 	    case XML_ELEMENT_NODE:
   7678 	    case XML_XINCLUDE_START:
   7679 	    case XML_DOCUMENT_FRAG_NODE:
   7680 	    case XML_DOCUMENT_NODE:
   7681 #ifdef LIBXML_DOCB_ENABLED
   7682 	    case XML_DOCB_DOCUMENT_NODE:
   7683 #endif
   7684 	    case XML_HTML_DOCUMENT_NODE:
   7685 		return(contextNode);
   7686 	    default:
   7687 		return(NULL);
   7688 	}
   7689 	return(NULL);
   7690     } else {
   7691 	xmlNodePtr start = cur;
   7692 
   7693 	while (cur != NULL) {
   7694 	    switch (cur->type) {
   7695 		case XML_ELEMENT_NODE:
   7696 		/* TODO: OK to have XInclude here? */
   7697 		case XML_XINCLUDE_START:
   7698 		case XML_DOCUMENT_FRAG_NODE:
   7699 		    if (cur != start)
   7700 			return(cur);
   7701 		    if (cur->children != NULL) {
   7702 			cur = cur->children;
   7703 			continue;
   7704 		    }
   7705 		    break;
   7706 		/* Not sure if we need those here. */
   7707 		case XML_DOCUMENT_NODE:
   7708 #ifdef LIBXML_DOCB_ENABLED
   7709 		case XML_DOCB_DOCUMENT_NODE:
   7710 #endif
   7711 		case XML_HTML_DOCUMENT_NODE:
   7712 		    if (cur != start)
   7713 			return(cur);
   7714 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7715 		default:
   7716 		    break;
   7717 	    }
   7718 
   7719 next_sibling:
   7720 	    if ((cur == NULL) || (cur == contextNode))
   7721 		return(NULL);
   7722 	    if (cur->next != NULL) {
   7723 		cur = cur->next;
   7724 	    } else {
   7725 		cur = cur->parent;
   7726 		goto next_sibling;
   7727 	    }
   7728 	}
   7729     }
   7730     return(NULL);
   7731 }
   7732 
   7733 /**
   7734  * xmlXPathNextDescendant:
   7735  * @ctxt:  the XPath Parser context
   7736  * @cur:  the current node in the traversal
   7737  *
   7738  * Traversal function for the "descendant" direction
   7739  * the descendant axis contains the descendants of the context node in document
   7740  * order; a descendant is a child or a child of a child and so on.
   7741  *
   7742  * Returns the next element following that axis
   7743  */
   7744 xmlNodePtr
   7745 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7746     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7747     if (cur == NULL) {
   7748 	if (ctxt->context->node == NULL)
   7749 	    return(NULL);
   7750 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7751 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7752 	    return(NULL);
   7753 
   7754         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7755 	    return(ctxt->context->doc->children);
   7756         return(ctxt->context->node->children);
   7757     }
   7758 
   7759     if (cur->children != NULL) {
   7760 	/*
   7761 	 * Do not descend on entities declarations
   7762 	 */
   7763 	if (cur->children->type != XML_ENTITY_DECL) {
   7764 	    cur = cur->children;
   7765 	    /*
   7766 	     * Skip DTDs
   7767 	     */
   7768 	    if (cur->type != XML_DTD_NODE)
   7769 		return(cur);
   7770 	}
   7771     }
   7772 
   7773     if (cur == ctxt->context->node) return(NULL);
   7774 
   7775     while (cur->next != NULL) {
   7776 	cur = cur->next;
   7777 	if ((cur->type != XML_ENTITY_DECL) &&
   7778 	    (cur->type != XML_DTD_NODE))
   7779 	    return(cur);
   7780     }
   7781 
   7782     do {
   7783         cur = cur->parent;
   7784 	if (cur == NULL) break;
   7785 	if (cur == ctxt->context->node) return(NULL);
   7786 	if (cur->next != NULL) {
   7787 	    cur = cur->next;
   7788 	    return(cur);
   7789 	}
   7790     } while (cur != NULL);
   7791     return(cur);
   7792 }
   7793 
   7794 /**
   7795  * xmlXPathNextDescendantOrSelf:
   7796  * @ctxt:  the XPath Parser context
   7797  * @cur:  the current node in the traversal
   7798  *
   7799  * Traversal function for the "descendant-or-self" direction
   7800  * the descendant-or-self axis contains the context node and the descendants
   7801  * of the context node in document order; thus the context node is the first
   7802  * node on the axis, and the first child of the context node is the second node
   7803  * on the axis
   7804  *
   7805  * Returns the next element following that axis
   7806  */
   7807 xmlNodePtr
   7808 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7809     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7810     if (cur == NULL) {
   7811 	if (ctxt->context->node == NULL)
   7812 	    return(NULL);
   7813 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7814 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7815 	    return(NULL);
   7816         return(ctxt->context->node);
   7817     }
   7818 
   7819     return(xmlXPathNextDescendant(ctxt, cur));
   7820 }
   7821 
   7822 /**
   7823  * xmlXPathNextParent:
   7824  * @ctxt:  the XPath Parser context
   7825  * @cur:  the current node in the traversal
   7826  *
   7827  * Traversal function for the "parent" direction
   7828  * The parent axis contains the parent of the context node, if there is one.
   7829  *
   7830  * Returns the next element following that axis
   7831  */
   7832 xmlNodePtr
   7833 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7834     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7835     /*
   7836      * the parent of an attribute or namespace node is the element
   7837      * to which the attribute or namespace node is attached
   7838      * Namespace handling !!!
   7839      */
   7840     if (cur == NULL) {
   7841 	if (ctxt->context->node == NULL) return(NULL);
   7842 	switch (ctxt->context->node->type) {
   7843             case XML_ELEMENT_NODE:
   7844             case XML_TEXT_NODE:
   7845             case XML_CDATA_SECTION_NODE:
   7846             case XML_ENTITY_REF_NODE:
   7847             case XML_ENTITY_NODE:
   7848             case XML_PI_NODE:
   7849             case XML_COMMENT_NODE:
   7850             case XML_NOTATION_NODE:
   7851             case XML_DTD_NODE:
   7852 	    case XML_ELEMENT_DECL:
   7853 	    case XML_ATTRIBUTE_DECL:
   7854 	    case XML_XINCLUDE_START:
   7855 	    case XML_XINCLUDE_END:
   7856 	    case XML_ENTITY_DECL:
   7857 		if (ctxt->context->node->parent == NULL)
   7858 		    return((xmlNodePtr) ctxt->context->doc);
   7859 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7860 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7861 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7862 				 BAD_CAST "fake node libxslt"))))
   7863 		    return(NULL);
   7864 		return(ctxt->context->node->parent);
   7865             case XML_ATTRIBUTE_NODE: {
   7866 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7867 
   7868 		return(att->parent);
   7869 	    }
   7870             case XML_DOCUMENT_NODE:
   7871             case XML_DOCUMENT_TYPE_NODE:
   7872             case XML_DOCUMENT_FRAG_NODE:
   7873             case XML_HTML_DOCUMENT_NODE:
   7874 #ifdef LIBXML_DOCB_ENABLED
   7875 	    case XML_DOCB_DOCUMENT_NODE:
   7876 #endif
   7877                 return(NULL);
   7878 	    case XML_NAMESPACE_DECL: {
   7879 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7880 
   7881 		if ((ns->next != NULL) &&
   7882 		    (ns->next->type != XML_NAMESPACE_DECL))
   7883 		    return((xmlNodePtr) ns->next);
   7884                 return(NULL);
   7885 	    }
   7886 	}
   7887     }
   7888     return(NULL);
   7889 }
   7890 
   7891 /**
   7892  * xmlXPathNextAncestor:
   7893  * @ctxt:  the XPath Parser context
   7894  * @cur:  the current node in the traversal
   7895  *
   7896  * Traversal function for the "ancestor" direction
   7897  * the ancestor axis contains the ancestors of the context node; the ancestors
   7898  * of the context node consist of the parent of context node and the parent's
   7899  * parent and so on; the nodes are ordered in reverse document order; thus the
   7900  * parent is the first node on the axis, and the parent's parent is the second
   7901  * node on the axis
   7902  *
   7903  * Returns the next element following that axis
   7904  */
   7905 xmlNodePtr
   7906 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7907     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7908     /*
   7909      * the parent of an attribute or namespace node is the element
   7910      * to which the attribute or namespace node is attached
   7911      * !!!!!!!!!!!!!
   7912      */
   7913     if (cur == NULL) {
   7914 	if (ctxt->context->node == NULL) return(NULL);
   7915 	switch (ctxt->context->node->type) {
   7916             case XML_ELEMENT_NODE:
   7917             case XML_TEXT_NODE:
   7918             case XML_CDATA_SECTION_NODE:
   7919             case XML_ENTITY_REF_NODE:
   7920             case XML_ENTITY_NODE:
   7921             case XML_PI_NODE:
   7922             case XML_COMMENT_NODE:
   7923 	    case XML_DTD_NODE:
   7924 	    case XML_ELEMENT_DECL:
   7925 	    case XML_ATTRIBUTE_DECL:
   7926 	    case XML_ENTITY_DECL:
   7927             case XML_NOTATION_NODE:
   7928 	    case XML_XINCLUDE_START:
   7929 	    case XML_XINCLUDE_END:
   7930 		if (ctxt->context->node->parent == NULL)
   7931 		    return((xmlNodePtr) ctxt->context->doc);
   7932 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7933 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7934 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7935 				 BAD_CAST "fake node libxslt"))))
   7936 		    return(NULL);
   7937 		return(ctxt->context->node->parent);
   7938             case XML_ATTRIBUTE_NODE: {
   7939 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   7940 
   7941 		return(tmp->parent);
   7942 	    }
   7943             case XML_DOCUMENT_NODE:
   7944             case XML_DOCUMENT_TYPE_NODE:
   7945             case XML_DOCUMENT_FRAG_NODE:
   7946             case XML_HTML_DOCUMENT_NODE:
   7947 #ifdef LIBXML_DOCB_ENABLED
   7948 	    case XML_DOCB_DOCUMENT_NODE:
   7949 #endif
   7950                 return(NULL);
   7951 	    case XML_NAMESPACE_DECL: {
   7952 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7953 
   7954 		if ((ns->next != NULL) &&
   7955 		    (ns->next->type != XML_NAMESPACE_DECL))
   7956 		    return((xmlNodePtr) ns->next);
   7957 		/* Bad, how did that namespace end up here ? */
   7958                 return(NULL);
   7959 	    }
   7960 	}
   7961 	return(NULL);
   7962     }
   7963     if (cur == ctxt->context->doc->children)
   7964 	return((xmlNodePtr) ctxt->context->doc);
   7965     if (cur == (xmlNodePtr) ctxt->context->doc)
   7966 	return(NULL);
   7967     switch (cur->type) {
   7968 	case XML_ELEMENT_NODE:
   7969 	case XML_TEXT_NODE:
   7970 	case XML_CDATA_SECTION_NODE:
   7971 	case XML_ENTITY_REF_NODE:
   7972 	case XML_ENTITY_NODE:
   7973 	case XML_PI_NODE:
   7974 	case XML_COMMENT_NODE:
   7975 	case XML_NOTATION_NODE:
   7976 	case XML_DTD_NODE:
   7977         case XML_ELEMENT_DECL:
   7978         case XML_ATTRIBUTE_DECL:
   7979         case XML_ENTITY_DECL:
   7980 	case XML_XINCLUDE_START:
   7981 	case XML_XINCLUDE_END:
   7982 	    if (cur->parent == NULL)
   7983 		return(NULL);
   7984 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   7985 		((cur->parent->name[0] == ' ') ||
   7986 		 (xmlStrEqual(cur->parent->name,
   7987 			      BAD_CAST "fake node libxslt"))))
   7988 		return(NULL);
   7989 	    return(cur->parent);
   7990 	case XML_ATTRIBUTE_NODE: {
   7991 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7992 
   7993 	    return(att->parent);
   7994 	}
   7995 	case XML_NAMESPACE_DECL: {
   7996 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   7997 
   7998 	    if ((ns->next != NULL) &&
   7999 	        (ns->next->type != XML_NAMESPACE_DECL))
   8000 	        return((xmlNodePtr) ns->next);
   8001 	    /* Bad, how did that namespace end up here ? */
   8002             return(NULL);
   8003 	}
   8004 	case XML_DOCUMENT_NODE:
   8005 	case XML_DOCUMENT_TYPE_NODE:
   8006 	case XML_DOCUMENT_FRAG_NODE:
   8007 	case XML_HTML_DOCUMENT_NODE:
   8008 #ifdef LIBXML_DOCB_ENABLED
   8009 	case XML_DOCB_DOCUMENT_NODE:
   8010 #endif
   8011 	    return(NULL);
   8012     }
   8013     return(NULL);
   8014 }
   8015 
   8016 /**
   8017  * xmlXPathNextAncestorOrSelf:
   8018  * @ctxt:  the XPath Parser context
   8019  * @cur:  the current node in the traversal
   8020  *
   8021  * Traversal function for the "ancestor-or-self" direction
   8022  * he ancestor-or-self axis contains the context node and ancestors of
   8023  * the context node in reverse document order; thus the context node is
   8024  * the first node on the axis, and the context node's parent the second;
   8025  * parent here is defined the same as with the parent axis.
   8026  *
   8027  * Returns the next element following that axis
   8028  */
   8029 xmlNodePtr
   8030 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8031     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8032     if (cur == NULL)
   8033         return(ctxt->context->node);
   8034     return(xmlXPathNextAncestor(ctxt, cur));
   8035 }
   8036 
   8037 /**
   8038  * xmlXPathNextFollowingSibling:
   8039  * @ctxt:  the XPath Parser context
   8040  * @cur:  the current node in the traversal
   8041  *
   8042  * Traversal function for the "following-sibling" direction
   8043  * The following-sibling axis contains the following siblings of the context
   8044  * node in document order.
   8045  *
   8046  * Returns the next element following that axis
   8047  */
   8048 xmlNodePtr
   8049 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8050     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8051     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8052 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8053 	return(NULL);
   8054     if (cur == (xmlNodePtr) ctxt->context->doc)
   8055         return(NULL);
   8056     if (cur == NULL)
   8057         return(ctxt->context->node->next);
   8058     return(cur->next);
   8059 }
   8060 
   8061 /**
   8062  * xmlXPathNextPrecedingSibling:
   8063  * @ctxt:  the XPath Parser context
   8064  * @cur:  the current node in the traversal
   8065  *
   8066  * Traversal function for the "preceding-sibling" direction
   8067  * The preceding-sibling axis contains the preceding siblings of the context
   8068  * node in reverse document order; the first preceding sibling is first on the
   8069  * axis; the sibling preceding that node is the second on the axis and so on.
   8070  *
   8071  * Returns the next element following that axis
   8072  */
   8073 xmlNodePtr
   8074 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8075     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8076     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8077 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8078 	return(NULL);
   8079     if (cur == (xmlNodePtr) ctxt->context->doc)
   8080         return(NULL);
   8081     if (cur == NULL)
   8082         return(ctxt->context->node->prev);
   8083     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8084 	cur = cur->prev;
   8085 	if (cur == NULL)
   8086 	    return(ctxt->context->node->prev);
   8087     }
   8088     return(cur->prev);
   8089 }
   8090 
   8091 /**
   8092  * xmlXPathNextFollowing:
   8093  * @ctxt:  the XPath Parser context
   8094  * @cur:  the current node in the traversal
   8095  *
   8096  * Traversal function for the "following" direction
   8097  * The following axis contains all nodes in the same document as the context
   8098  * node that are after the context node in document order, excluding any
   8099  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8100  * are ordered in document order
   8101  *
   8102  * Returns the next element following that axis
   8103  */
   8104 xmlNodePtr
   8105 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8106     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8107     if (cur != NULL && cur->children != NULL)
   8108         return cur->children ;
   8109     if (cur == NULL) cur = ctxt->context->node;
   8110     if (cur == NULL) return(NULL) ; /* ERROR */
   8111     if (cur->next != NULL) return(cur->next) ;
   8112     do {
   8113         cur = cur->parent;
   8114         if (cur == NULL) break;
   8115         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8116         if (cur->next != NULL) return(cur->next);
   8117     } while (cur != NULL);
   8118     return(cur);
   8119 }
   8120 
   8121 /*
   8122  * xmlXPathIsAncestor:
   8123  * @ancestor:  the ancestor node
   8124  * @node:  the current node
   8125  *
   8126  * Check that @ancestor is a @node's ancestor
   8127  *
   8128  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8129  */
   8130 static int
   8131 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8132     if ((ancestor == NULL) || (node == NULL)) return(0);
   8133     /* nodes need to be in the same document */
   8134     if (ancestor->doc != node->doc) return(0);
   8135     /* avoid searching if ancestor or node is the root node */
   8136     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8137     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8138     while (node->parent != NULL) {
   8139         if (node->parent == ancestor)
   8140             return(1);
   8141 	node = node->parent;
   8142     }
   8143     return(0);
   8144 }
   8145 
   8146 /**
   8147  * xmlXPathNextPreceding:
   8148  * @ctxt:  the XPath Parser context
   8149  * @cur:  the current node in the traversal
   8150  *
   8151  * Traversal function for the "preceding" direction
   8152  * the preceding axis contains all nodes in the same document as the context
   8153  * node that are before the context node in document order, excluding any
   8154  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8155  * ordered in reverse document order
   8156  *
   8157  * Returns the next element following that axis
   8158  */
   8159 xmlNodePtr
   8160 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8161 {
   8162     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8163     if (cur == NULL)
   8164         cur = ctxt->context->node;
   8165     if (cur == NULL)
   8166 	return (NULL);
   8167     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8168 	cur = cur->prev;
   8169     do {
   8170         if (cur->prev != NULL) {
   8171             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8172             return (cur);
   8173         }
   8174 
   8175         cur = cur->parent;
   8176         if (cur == NULL)
   8177             return (NULL);
   8178         if (cur == ctxt->context->doc->children)
   8179             return (NULL);
   8180     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8181     return (cur);
   8182 }
   8183 
   8184 /**
   8185  * xmlXPathNextPrecedingInternal:
   8186  * @ctxt:  the XPath Parser context
   8187  * @cur:  the current node in the traversal
   8188  *
   8189  * Traversal function for the "preceding" direction
   8190  * the preceding axis contains all nodes in the same document as the context
   8191  * node that are before the context node in document order, excluding any
   8192  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8193  * ordered in reverse document order
   8194  * This is a faster implementation but internal only since it requires a
   8195  * state kept in the parser context: ctxt->ancestor.
   8196  *
   8197  * Returns the next element following that axis
   8198  */
   8199 static xmlNodePtr
   8200 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8201                               xmlNodePtr cur)
   8202 {
   8203     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8204     if (cur == NULL) {
   8205         cur = ctxt->context->node;
   8206         if (cur == NULL)
   8207             return (NULL);
   8208 	if (cur->type == XML_NAMESPACE_DECL)
   8209 	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
   8210         ctxt->ancestor = cur->parent;
   8211     }
   8212     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8213 	cur = cur->prev;
   8214     while (cur->prev == NULL) {
   8215         cur = cur->parent;
   8216         if (cur == NULL)
   8217             return (NULL);
   8218         if (cur == ctxt->context->doc->children)
   8219             return (NULL);
   8220         if (cur != ctxt->ancestor)
   8221             return (cur);
   8222         ctxt->ancestor = cur->parent;
   8223     }
   8224     cur = cur->prev;
   8225     while (cur->last != NULL)
   8226         cur = cur->last;
   8227     return (cur);
   8228 }
   8229 
   8230 /**
   8231  * xmlXPathNextNamespace:
   8232  * @ctxt:  the XPath Parser context
   8233  * @cur:  the current attribute in the traversal
   8234  *
   8235  * Traversal function for the "namespace" direction
   8236  * the namespace axis contains the namespace nodes of the context node;
   8237  * the order of nodes on this axis is implementation-defined; the axis will
   8238  * be empty unless the context node is an element
   8239  *
   8240  * We keep the XML namespace node at the end of the list.
   8241  *
   8242  * Returns the next element following that axis
   8243  */
   8244 xmlNodePtr
   8245 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8246     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8247     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8248     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
   8249         if (ctxt->context->tmpNsList != NULL)
   8250 	    xmlFree(ctxt->context->tmpNsList);
   8251 	ctxt->context->tmpNsList =
   8252 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8253 	ctxt->context->tmpNsNr = 0;
   8254 	if (ctxt->context->tmpNsList != NULL) {
   8255 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8256 		ctxt->context->tmpNsNr++;
   8257 	    }
   8258 	}
   8259 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8260     }
   8261     if (ctxt->context->tmpNsNr > 0) {
   8262 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8263     } else {
   8264 	if (ctxt->context->tmpNsList != NULL)
   8265 	    xmlFree(ctxt->context->tmpNsList);
   8266 	ctxt->context->tmpNsList = NULL;
   8267 	return(NULL);
   8268     }
   8269 }
   8270 
   8271 /**
   8272  * xmlXPathNextAttribute:
   8273  * @ctxt:  the XPath Parser context
   8274  * @cur:  the current attribute in the traversal
   8275  *
   8276  * Traversal function for the "attribute" direction
   8277  * TODO: support DTD inherited default attributes
   8278  *
   8279  * Returns the next element following that axis
   8280  */
   8281 xmlNodePtr
   8282 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8283     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8284     if (ctxt->context->node == NULL)
   8285 	return(NULL);
   8286     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8287 	return(NULL);
   8288     if (cur == NULL) {
   8289         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8290 	    return(NULL);
   8291         return((xmlNodePtr)ctxt->context->node->properties);
   8292     }
   8293     return((xmlNodePtr)cur->next);
   8294 }
   8295 
   8296 /************************************************************************
   8297  *									*
   8298  *		NodeTest Functions					*
   8299  *									*
   8300  ************************************************************************/
   8301 
   8302 #define IS_FUNCTION			200
   8303 
   8304 
   8305 /************************************************************************
   8306  *									*
   8307  *		Implicit tree core function library			*
   8308  *									*
   8309  ************************************************************************/
   8310 
   8311 /**
   8312  * xmlXPathRoot:
   8313  * @ctxt:  the XPath Parser context
   8314  *
   8315  * Initialize the context to the root of the document
   8316  */
   8317 void
   8318 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8319     if ((ctxt == NULL) || (ctxt->context == NULL))
   8320 	return;
   8321     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8322     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8323 	ctxt->context->node));
   8324 }
   8325 
   8326 /************************************************************************
   8327  *									*
   8328  *		The explicit core function library			*
   8329  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8330  *									*
   8331  ************************************************************************/
   8332 
   8333 
   8334 /**
   8335  * xmlXPathLastFunction:
   8336  * @ctxt:  the XPath Parser context
   8337  * @nargs:  the number of arguments
   8338  *
   8339  * Implement the last() XPath function
   8340  *    number last()
   8341  * The last function returns the number of nodes in the context node list.
   8342  */
   8343 void
   8344 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8345     CHECK_ARITY(0);
   8346     if (ctxt->context->contextSize >= 0) {
   8347 	valuePush(ctxt,
   8348 	    xmlXPathCacheNewFloat(ctxt->context,
   8349 		(double) ctxt->context->contextSize));
   8350 #ifdef DEBUG_EXPR
   8351 	xmlGenericError(xmlGenericErrorContext,
   8352 		"last() : %d\n", ctxt->context->contextSize);
   8353 #endif
   8354     } else {
   8355 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8356     }
   8357 }
   8358 
   8359 /**
   8360  * xmlXPathPositionFunction:
   8361  * @ctxt:  the XPath Parser context
   8362  * @nargs:  the number of arguments
   8363  *
   8364  * Implement the position() XPath function
   8365  *    number position()
   8366  * The position function returns the position of the context node in the
   8367  * context node list. The first position is 1, and so the last position
   8368  * will be equal to last().
   8369  */
   8370 void
   8371 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8372     CHECK_ARITY(0);
   8373     if (ctxt->context->proximityPosition >= 0) {
   8374 	valuePush(ctxt,
   8375 	      xmlXPathCacheNewFloat(ctxt->context,
   8376 		(double) ctxt->context->proximityPosition));
   8377 #ifdef DEBUG_EXPR
   8378 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8379 		ctxt->context->proximityPosition);
   8380 #endif
   8381     } else {
   8382 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8383     }
   8384 }
   8385 
   8386 /**
   8387  * xmlXPathCountFunction:
   8388  * @ctxt:  the XPath Parser context
   8389  * @nargs:  the number of arguments
   8390  *
   8391  * Implement the count() XPath function
   8392  *    number count(node-set)
   8393  */
   8394 void
   8395 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8396     xmlXPathObjectPtr cur;
   8397 
   8398     CHECK_ARITY(1);
   8399     if ((ctxt->value == NULL) ||
   8400 	((ctxt->value->type != XPATH_NODESET) &&
   8401 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8402 	XP_ERROR(XPATH_INVALID_TYPE);
   8403     cur = valuePop(ctxt);
   8404 
   8405     if ((cur == NULL) || (cur->nodesetval == NULL))
   8406 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8407     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8408 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8409 	    (double) cur->nodesetval->nodeNr));
   8410     } else {
   8411 	if ((cur->nodesetval->nodeNr != 1) ||
   8412 	    (cur->nodesetval->nodeTab == NULL)) {
   8413 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8414 	} else {
   8415 	    xmlNodePtr tmp;
   8416 	    int i = 0;
   8417 
   8418 	    tmp = cur->nodesetval->nodeTab[0];
   8419 	    if (tmp != NULL) {
   8420 		tmp = tmp->children;
   8421 		while (tmp != NULL) {
   8422 		    tmp = tmp->next;
   8423 		    i++;
   8424 		}
   8425 	    }
   8426 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8427 	}
   8428     }
   8429     xmlXPathReleaseObject(ctxt->context, cur);
   8430 }
   8431 
   8432 /**
   8433  * xmlXPathGetElementsByIds:
   8434  * @doc:  the document
   8435  * @ids:  a whitespace separated list of IDs
   8436  *
   8437  * Selects elements by their unique ID.
   8438  *
   8439  * Returns a node-set of selected elements.
   8440  */
   8441 static xmlNodeSetPtr
   8442 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8443     xmlNodeSetPtr ret;
   8444     const xmlChar *cur = ids;
   8445     xmlChar *ID;
   8446     xmlAttrPtr attr;
   8447     xmlNodePtr elem = NULL;
   8448 
   8449     if (ids == NULL) return(NULL);
   8450 
   8451     ret = xmlXPathNodeSetCreate(NULL);
   8452     if (ret == NULL)
   8453         return(ret);
   8454 
   8455     while (IS_BLANK_CH(*cur)) cur++;
   8456     while (*cur != 0) {
   8457 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8458 	    cur++;
   8459 
   8460         ID = xmlStrndup(ids, cur - ids);
   8461 	if (ID != NULL) {
   8462 	    /*
   8463 	     * We used to check the fact that the value passed
   8464 	     * was an NCName, but this generated much troubles for
   8465 	     * me and Aleksey Sanin, people blatantly violated that
   8466 	     * constaint, like Visa3D spec.
   8467 	     * if (xmlValidateNCName(ID, 1) == 0)
   8468 	     */
   8469 	    attr = xmlGetID(doc, ID);
   8470 	    if (attr != NULL) {
   8471 		if (attr->type == XML_ATTRIBUTE_NODE)
   8472 		    elem = attr->parent;
   8473 		else if (attr->type == XML_ELEMENT_NODE)
   8474 		    elem = (xmlNodePtr) attr;
   8475 		else
   8476 		    elem = NULL;
   8477 		if (elem != NULL)
   8478 		    xmlXPathNodeSetAdd(ret, elem);
   8479 	    }
   8480 	    xmlFree(ID);
   8481 	}
   8482 
   8483 	while (IS_BLANK_CH(*cur)) cur++;
   8484 	ids = cur;
   8485     }
   8486     return(ret);
   8487 }
   8488 
   8489 /**
   8490  * xmlXPathIdFunction:
   8491  * @ctxt:  the XPath Parser context
   8492  * @nargs:  the number of arguments
   8493  *
   8494  * Implement the id() XPath function
   8495  *    node-set id(object)
   8496  * The id function selects elements by their unique ID
   8497  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8498  * then the result is the union of the result of applying id to the
   8499  * string value of each of the nodes in the argument node-set. When the
   8500  * argument to id is of any other type, the argument is converted to a
   8501  * string as if by a call to the string function; the string is split
   8502  * into a whitespace-separated list of tokens (whitespace is any sequence
   8503  * of characters matching the production S); the result is a node-set
   8504  * containing the elements in the same document as the context node that
   8505  * have a unique ID equal to any of the tokens in the list.
   8506  */
   8507 void
   8508 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8509     xmlChar *tokens;
   8510     xmlNodeSetPtr ret;
   8511     xmlXPathObjectPtr obj;
   8512 
   8513     CHECK_ARITY(1);
   8514     obj = valuePop(ctxt);
   8515     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8516     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8517 	xmlNodeSetPtr ns;
   8518 	int i;
   8519 
   8520 	ret = xmlXPathNodeSetCreate(NULL);
   8521         /*
   8522          * FIXME -- in an out-of-memory condition this will behave badly.
   8523          * The solution is not clear -- we already popped an item from
   8524          * ctxt, so the object is in a corrupt state.
   8525          */
   8526 
   8527 	if (obj->nodesetval != NULL) {
   8528 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8529 		tokens =
   8530 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8531 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8532 		ret = xmlXPathNodeSetMerge(ret, ns);
   8533 		xmlXPathFreeNodeSet(ns);
   8534 		if (tokens != NULL)
   8535 		    xmlFree(tokens);
   8536 	    }
   8537 	}
   8538 	xmlXPathReleaseObject(ctxt->context, obj);
   8539 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8540 	return;
   8541     }
   8542     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8543     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8544     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8545     xmlXPathReleaseObject(ctxt->context, obj);
   8546     return;
   8547 }
   8548 
   8549 /**
   8550  * xmlXPathLocalNameFunction:
   8551  * @ctxt:  the XPath Parser context
   8552  * @nargs:  the number of arguments
   8553  *
   8554  * Implement the local-name() XPath function
   8555  *    string local-name(node-set?)
   8556  * The local-name function returns a string containing the local part
   8557  * of the name of the node in the argument node-set that is first in
   8558  * document order. If the node-set is empty or the first node has no
   8559  * name, an empty string is returned. If the argument is omitted it
   8560  * defaults to the context node.
   8561  */
   8562 void
   8563 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8564     xmlXPathObjectPtr cur;
   8565 
   8566     if (ctxt == NULL) return;
   8567 
   8568     if (nargs == 0) {
   8569 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8570 	    ctxt->context->node));
   8571 	nargs = 1;
   8572     }
   8573 
   8574     CHECK_ARITY(1);
   8575     if ((ctxt->value == NULL) ||
   8576 	((ctxt->value->type != XPATH_NODESET) &&
   8577 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8578 	XP_ERROR(XPATH_INVALID_TYPE);
   8579     cur = valuePop(ctxt);
   8580 
   8581     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8582 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8583     } else {
   8584 	int i = 0; /* Should be first in document order !!!!! */
   8585 	switch (cur->nodesetval->nodeTab[i]->type) {
   8586 	case XML_ELEMENT_NODE:
   8587 	case XML_ATTRIBUTE_NODE:
   8588 	case XML_PI_NODE:
   8589 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8590 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8591 	    else
   8592 		valuePush(ctxt,
   8593 		      xmlXPathCacheNewString(ctxt->context,
   8594 			cur->nodesetval->nodeTab[i]->name));
   8595 	    break;
   8596 	case XML_NAMESPACE_DECL:
   8597 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8598 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8599 	    break;
   8600 	default:
   8601 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8602 	}
   8603     }
   8604     xmlXPathReleaseObject(ctxt->context, cur);
   8605 }
   8606 
   8607 /**
   8608  * xmlXPathNamespaceURIFunction:
   8609  * @ctxt:  the XPath Parser context
   8610  * @nargs:  the number of arguments
   8611  *
   8612  * Implement the namespace-uri() XPath function
   8613  *    string namespace-uri(node-set?)
   8614  * The namespace-uri function returns a string containing the
   8615  * namespace URI of the expanded name of the node in the argument
   8616  * node-set that is first in document order. If the node-set is empty,
   8617  * the first node has no name, or the expanded name has no namespace
   8618  * URI, an empty string is returned. If the argument is omitted it
   8619  * defaults to the context node.
   8620  */
   8621 void
   8622 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8623     xmlXPathObjectPtr cur;
   8624 
   8625     if (ctxt == NULL) return;
   8626 
   8627     if (nargs == 0) {
   8628 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8629 	    ctxt->context->node));
   8630 	nargs = 1;
   8631     }
   8632     CHECK_ARITY(1);
   8633     if ((ctxt->value == NULL) ||
   8634 	((ctxt->value->type != XPATH_NODESET) &&
   8635 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8636 	XP_ERROR(XPATH_INVALID_TYPE);
   8637     cur = valuePop(ctxt);
   8638 
   8639     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8640 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8641     } else {
   8642 	int i = 0; /* Should be first in document order !!!!! */
   8643 	switch (cur->nodesetval->nodeTab[i]->type) {
   8644 	case XML_ELEMENT_NODE:
   8645 	case XML_ATTRIBUTE_NODE:
   8646 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8647 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8648 	    else
   8649 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8650 			  cur->nodesetval->nodeTab[i]->ns->href));
   8651 	    break;
   8652 	default:
   8653 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8654 	}
   8655     }
   8656     xmlXPathReleaseObject(ctxt->context, cur);
   8657 }
   8658 
   8659 /**
   8660  * xmlXPathNameFunction:
   8661  * @ctxt:  the XPath Parser context
   8662  * @nargs:  the number of arguments
   8663  *
   8664  * Implement the name() XPath function
   8665  *    string name(node-set?)
   8666  * The name function returns a string containing a QName representing
   8667  * the name of the node in the argument node-set that is first in document
   8668  * order. The QName must represent the name with respect to the namespace
   8669  * declarations in effect on the node whose name is being represented.
   8670  * Typically, this will be the form in which the name occurred in the XML
   8671  * source. This need not be the case if there are namespace declarations
   8672  * in effect on the node that associate multiple prefixes with the same
   8673  * namespace. However, an implementation may include information about
   8674  * the original prefix in its representation of nodes; in this case, an
   8675  * implementation can ensure that the returned string is always the same
   8676  * as the QName used in the XML source. If the argument it omitted it
   8677  * defaults to the context node.
   8678  * Libxml keep the original prefix so the "real qualified name" used is
   8679  * returned.
   8680  */
   8681 static void
   8682 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8683 {
   8684     xmlXPathObjectPtr cur;
   8685 
   8686     if (nargs == 0) {
   8687 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8688 	    ctxt->context->node));
   8689         nargs = 1;
   8690     }
   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 
   8704         switch (cur->nodesetval->nodeTab[i]->type) {
   8705             case XML_ELEMENT_NODE:
   8706             case XML_ATTRIBUTE_NODE:
   8707 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8708 		    valuePush(ctxt,
   8709 			xmlXPathCacheNewCString(ctxt->context, ""));
   8710 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8711                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8712 		    valuePush(ctxt,
   8713 		        xmlXPathCacheNewString(ctxt->context,
   8714 			    cur->nodesetval->nodeTab[i]->name));
   8715 		} else {
   8716 		    xmlChar *fullname;
   8717 
   8718 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8719 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8720 				     NULL, 0);
   8721 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8722 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8723 		    if (fullname == NULL) {
   8724 			XP_ERROR(XPATH_MEMORY_ERROR);
   8725 		    }
   8726 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8727 			ctxt->context, fullname));
   8728                 }
   8729                 break;
   8730             default:
   8731 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8732 		    cur->nodesetval->nodeTab[i]));
   8733                 xmlXPathLocalNameFunction(ctxt, 1);
   8734         }
   8735     }
   8736     xmlXPathReleaseObject(ctxt->context, cur);
   8737 }
   8738 
   8739 
   8740 /**
   8741  * xmlXPathStringFunction:
   8742  * @ctxt:  the XPath Parser context
   8743  * @nargs:  the number of arguments
   8744  *
   8745  * Implement the string() XPath function
   8746  *    string string(object?)
   8747  * The string function converts an object to a string as follows:
   8748  *    - A node-set is converted to a string by returning the value of
   8749  *      the node in the node-set that is first in document order.
   8750  *      If the node-set is empty, an empty string is returned.
   8751  *    - A number is converted to a string as follows
   8752  *      + NaN is converted to the string NaN
   8753  *      + positive zero is converted to the string 0
   8754  *      + negative zero is converted to the string 0
   8755  *      + positive infinity is converted to the string Infinity
   8756  *      + negative infinity is converted to the string -Infinity
   8757  *      + if the number is an integer, the number is represented in
   8758  *        decimal form as a Number with no decimal point and no leading
   8759  *        zeros, preceded by a minus sign (-) if the number is negative
   8760  *      + otherwise, the number is represented in decimal form as a
   8761  *        Number including a decimal point with at least one digit
   8762  *        before the decimal point and at least one digit after the
   8763  *        decimal point, preceded by a minus sign (-) if the number
   8764  *        is negative; there must be no leading zeros before the decimal
   8765  *        point apart possibly from the one required digit immediately
   8766  *        before the decimal point; beyond the one required digit
   8767  *        after the decimal point there must be as many, but only as
   8768  *        many, more digits as are needed to uniquely distinguish the
   8769  *        number from all other IEEE 754 numeric values.
   8770  *    - The boolean false value is converted to the string false.
   8771  *      The boolean true value is converted to the string true.
   8772  *
   8773  * If the argument is omitted, it defaults to a node-set with the
   8774  * context node as its only member.
   8775  */
   8776 void
   8777 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8778     xmlXPathObjectPtr cur;
   8779 
   8780     if (ctxt == NULL) return;
   8781     if (nargs == 0) {
   8782     valuePush(ctxt,
   8783 	xmlXPathCacheWrapString(ctxt->context,
   8784 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8785 	return;
   8786     }
   8787 
   8788     CHECK_ARITY(1);
   8789     cur = valuePop(ctxt);
   8790     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8791     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8792 }
   8793 
   8794 /**
   8795  * xmlXPathStringLengthFunction:
   8796  * @ctxt:  the XPath Parser context
   8797  * @nargs:  the number of arguments
   8798  *
   8799  * Implement the string-length() XPath function
   8800  *    number string-length(string?)
   8801  * The string-length returns the number of characters in the string
   8802  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8803  * the context node converted to a string, in other words the value
   8804  * of the context node.
   8805  */
   8806 void
   8807 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8808     xmlXPathObjectPtr cur;
   8809 
   8810     if (nargs == 0) {
   8811         if ((ctxt == NULL) || (ctxt->context == NULL))
   8812 	    return;
   8813 	if (ctxt->context->node == NULL) {
   8814 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8815 	} else {
   8816 	    xmlChar *content;
   8817 
   8818 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8819 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8820 		xmlUTF8Strlen(content)));
   8821 	    xmlFree(content);
   8822 	}
   8823 	return;
   8824     }
   8825     CHECK_ARITY(1);
   8826     CAST_TO_STRING;
   8827     CHECK_TYPE(XPATH_STRING);
   8828     cur = valuePop(ctxt);
   8829     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8830 	xmlUTF8Strlen(cur->stringval)));
   8831     xmlXPathReleaseObject(ctxt->context, cur);
   8832 }
   8833 
   8834 /**
   8835  * xmlXPathConcatFunction:
   8836  * @ctxt:  the XPath Parser context
   8837  * @nargs:  the number of arguments
   8838  *
   8839  * Implement the concat() XPath function
   8840  *    string concat(string, string, string*)
   8841  * The concat function returns the concatenation of its arguments.
   8842  */
   8843 void
   8844 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8845     xmlXPathObjectPtr cur, newobj;
   8846     xmlChar *tmp;
   8847 
   8848     if (ctxt == NULL) return;
   8849     if (nargs < 2) {
   8850 	CHECK_ARITY(2);
   8851     }
   8852 
   8853     CAST_TO_STRING;
   8854     cur = valuePop(ctxt);
   8855     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   8856 	xmlXPathReleaseObject(ctxt->context, cur);
   8857 	return;
   8858     }
   8859     nargs--;
   8860 
   8861     while (nargs > 0) {
   8862 	CAST_TO_STRING;
   8863 	newobj = valuePop(ctxt);
   8864 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   8865 	    xmlXPathReleaseObject(ctxt->context, newobj);
   8866 	    xmlXPathReleaseObject(ctxt->context, cur);
   8867 	    XP_ERROR(XPATH_INVALID_TYPE);
   8868 	}
   8869 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   8870 	newobj->stringval = cur->stringval;
   8871 	cur->stringval = tmp;
   8872 	xmlXPathReleaseObject(ctxt->context, newobj);
   8873 	nargs--;
   8874     }
   8875     valuePush(ctxt, cur);
   8876 }
   8877 
   8878 /**
   8879  * xmlXPathContainsFunction:
   8880  * @ctxt:  the XPath Parser context
   8881  * @nargs:  the number of arguments
   8882  *
   8883  * Implement the contains() XPath function
   8884  *    boolean contains(string, string)
   8885  * The contains function returns true if the first argument string
   8886  * contains the second argument string, and otherwise returns false.
   8887  */
   8888 void
   8889 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8890     xmlXPathObjectPtr hay, needle;
   8891 
   8892     CHECK_ARITY(2);
   8893     CAST_TO_STRING;
   8894     CHECK_TYPE(XPATH_STRING);
   8895     needle = valuePop(ctxt);
   8896     CAST_TO_STRING;
   8897     hay = valuePop(ctxt);
   8898 
   8899     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8900 	xmlXPathReleaseObject(ctxt->context, hay);
   8901 	xmlXPathReleaseObject(ctxt->context, needle);
   8902 	XP_ERROR(XPATH_INVALID_TYPE);
   8903     }
   8904     if (xmlStrstr(hay->stringval, needle->stringval))
   8905 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   8906     else
   8907 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   8908     xmlXPathReleaseObject(ctxt->context, hay);
   8909     xmlXPathReleaseObject(ctxt->context, needle);
   8910 }
   8911 
   8912 /**
   8913  * xmlXPathStartsWithFunction:
   8914  * @ctxt:  the XPath Parser context
   8915  * @nargs:  the number of arguments
   8916  *
   8917  * Implement the starts-with() XPath function
   8918  *    boolean starts-with(string, string)
   8919  * The starts-with function returns true if the first argument string
   8920  * starts with the second argument string, and otherwise returns false.
   8921  */
   8922 void
   8923 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8924     xmlXPathObjectPtr hay, needle;
   8925     int n;
   8926 
   8927     CHECK_ARITY(2);
   8928     CAST_TO_STRING;
   8929     CHECK_TYPE(XPATH_STRING);
   8930     needle = valuePop(ctxt);
   8931     CAST_TO_STRING;
   8932     hay = valuePop(ctxt);
   8933 
   8934     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   8935 	xmlXPathReleaseObject(ctxt->context, hay);
   8936 	xmlXPathReleaseObject(ctxt->context, needle);
   8937 	XP_ERROR(XPATH_INVALID_TYPE);
   8938     }
   8939     n = xmlStrlen(needle->stringval);
   8940     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   8941         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   8942     else
   8943         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   8944     xmlXPathReleaseObject(ctxt->context, hay);
   8945     xmlXPathReleaseObject(ctxt->context, needle);
   8946 }
   8947 
   8948 /**
   8949  * xmlXPathSubstringFunction:
   8950  * @ctxt:  the XPath Parser context
   8951  * @nargs:  the number of arguments
   8952  *
   8953  * Implement the substring() XPath function
   8954  *    string substring(string, number, number?)
   8955  * The substring function returns the substring of the first argument
   8956  * starting at the position specified in the second argument with
   8957  * length specified in the third argument. For example,
   8958  * substring("12345",2,3) returns "234". If the third argument is not
   8959  * specified, it returns the substring starting at the position specified
   8960  * in the second argument and continuing to the end of the string. For
   8961  * example, substring("12345",2) returns "2345".  More precisely, each
   8962  * character in the string (see [3.6 Strings]) is considered to have a
   8963  * numeric position: the position of the first character is 1, the position
   8964  * of the second character is 2 and so on. The returned substring contains
   8965  * those characters for which the position of the character is greater than
   8966  * or equal to the second argument and, if the third argument is specified,
   8967  * less than the sum of the second and third arguments; the comparisons
   8968  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   8969  *  - substring("12345", 1.5, 2.6) returns "234"
   8970  *  - substring("12345", 0, 3) returns "12"
   8971  *  - substring("12345", 0 div 0, 3) returns ""
   8972  *  - substring("12345", 1, 0 div 0) returns ""
   8973  *  - substring("12345", -42, 1 div 0) returns "12345"
   8974  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   8975  */
   8976 void
   8977 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8978     xmlXPathObjectPtr str, start, len;
   8979     double le=0, in;
   8980     int i, l, m;
   8981     xmlChar *ret;
   8982 
   8983     if (nargs < 2) {
   8984 	CHECK_ARITY(2);
   8985     }
   8986     if (nargs > 3) {
   8987 	CHECK_ARITY(3);
   8988     }
   8989     /*
   8990      * take care of possible last (position) argument
   8991     */
   8992     if (nargs == 3) {
   8993 	CAST_TO_NUMBER;
   8994 	CHECK_TYPE(XPATH_NUMBER);
   8995 	len = valuePop(ctxt);
   8996 	le = len->floatval;
   8997 	xmlXPathReleaseObject(ctxt->context, len);
   8998     }
   8999 
   9000     CAST_TO_NUMBER;
   9001     CHECK_TYPE(XPATH_NUMBER);
   9002     start = valuePop(ctxt);
   9003     in = start->floatval;
   9004     xmlXPathReleaseObject(ctxt->context, start);
   9005     CAST_TO_STRING;
   9006     CHECK_TYPE(XPATH_STRING);
   9007     str = valuePop(ctxt);
   9008     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9009 
   9010     /*
   9011      * If last pos not present, calculate last position
   9012     */
   9013     if (nargs != 3) {
   9014 	le = (double)m;
   9015 	if (in < 1.0)
   9016 	    in = 1.0;
   9017     }
   9018 
   9019     /* Need to check for the special cases where either
   9020      * the index is NaN, the length is NaN, or both
   9021      * arguments are infinity (relying on Inf + -Inf = NaN)
   9022      */
   9023     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
   9024         /*
   9025          * To meet the requirements of the spec, the arguments
   9026 	 * must be converted to integer format before
   9027 	 * initial index calculations are done
   9028          *
   9029          * First we go to integer form, rounding up
   9030 	 * and checking for special cases
   9031          */
   9032         i = (int) in;
   9033         if (((double)i)+0.5 <= in) i++;
   9034 
   9035 	if (xmlXPathIsInf(le) == 1) {
   9036 	    l = m;
   9037 	    if (i < 1)
   9038 		i = 1;
   9039 	}
   9040 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9041 	    l = 0;
   9042 	else {
   9043 	    l = (int) le;
   9044 	    if (((double)l)+0.5 <= le) l++;
   9045 	}
   9046 
   9047 	/* Now we normalize inidices */
   9048         i -= 1;
   9049         l += i;
   9050         if (i < 0)
   9051             i = 0;
   9052         if (l > m)
   9053             l = m;
   9054 
   9055         /* number of chars to copy */
   9056         l -= i;
   9057 
   9058         ret = xmlUTF8Strsub(str->stringval, i, l);
   9059     }
   9060     else {
   9061         ret = NULL;
   9062     }
   9063     if (ret == NULL)
   9064 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9065     else {
   9066 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9067 	xmlFree(ret);
   9068     }
   9069     xmlXPathReleaseObject(ctxt->context, str);
   9070 }
   9071 
   9072 /**
   9073  * xmlXPathSubstringBeforeFunction:
   9074  * @ctxt:  the XPath Parser context
   9075  * @nargs:  the number of arguments
   9076  *
   9077  * Implement the substring-before() XPath function
   9078  *    string substring-before(string, string)
   9079  * The substring-before function returns the substring of the first
   9080  * argument string that precedes the first occurrence of the second
   9081  * argument string in the first argument string, or the empty string
   9082  * if the first argument string does not contain the second argument
   9083  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9084  */
   9085 void
   9086 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9087   xmlXPathObjectPtr str;
   9088   xmlXPathObjectPtr find;
   9089   xmlBufferPtr target;
   9090   const xmlChar *point;
   9091   int offset;
   9092 
   9093   CHECK_ARITY(2);
   9094   CAST_TO_STRING;
   9095   find = valuePop(ctxt);
   9096   CAST_TO_STRING;
   9097   str = valuePop(ctxt);
   9098 
   9099   target = xmlBufferCreate();
   9100   if (target) {
   9101     point = xmlStrstr(str->stringval, find->stringval);
   9102     if (point) {
   9103       offset = (int)(point - str->stringval);
   9104       xmlBufferAdd(target, str->stringval, offset);
   9105     }
   9106     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9107 	xmlBufferContent(target)));
   9108     xmlBufferFree(target);
   9109   }
   9110   xmlXPathReleaseObject(ctxt->context, str);
   9111   xmlXPathReleaseObject(ctxt->context, find);
   9112 }
   9113 
   9114 /**
   9115  * xmlXPathSubstringAfterFunction:
   9116  * @ctxt:  the XPath Parser context
   9117  * @nargs:  the number of arguments
   9118  *
   9119  * Implement the substring-after() XPath function
   9120  *    string substring-after(string, string)
   9121  * The substring-after function returns the substring of the first
   9122  * argument string that follows the first occurrence of the second
   9123  * argument string in the first argument string, or the empty stringi
   9124  * if the first argument string does not contain the second argument
   9125  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9126  * and substring-after("1999/04/01","19") returns 99/04/01.
   9127  */
   9128 void
   9129 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9130   xmlXPathObjectPtr str;
   9131   xmlXPathObjectPtr find;
   9132   xmlBufferPtr target;
   9133   const xmlChar *point;
   9134   int offset;
   9135 
   9136   CHECK_ARITY(2);
   9137   CAST_TO_STRING;
   9138   find = valuePop(ctxt);
   9139   CAST_TO_STRING;
   9140   str = valuePop(ctxt);
   9141 
   9142   target = xmlBufferCreate();
   9143   if (target) {
   9144     point = xmlStrstr(str->stringval, find->stringval);
   9145     if (point) {
   9146       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9147       xmlBufferAdd(target, &str->stringval[offset],
   9148 		   xmlStrlen(str->stringval) - offset);
   9149     }
   9150     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9151 	xmlBufferContent(target)));
   9152     xmlBufferFree(target);
   9153   }
   9154   xmlXPathReleaseObject(ctxt->context, str);
   9155   xmlXPathReleaseObject(ctxt->context, find);
   9156 }
   9157 
   9158 /**
   9159  * xmlXPathNormalizeFunction:
   9160  * @ctxt:  the XPath Parser context
   9161  * @nargs:  the number of arguments
   9162  *
   9163  * Implement the normalize-space() XPath function
   9164  *    string normalize-space(string?)
   9165  * The normalize-space function returns the argument string with white
   9166  * space normalized by stripping leading and trailing whitespace
   9167  * and replacing sequences of whitespace characters by a single
   9168  * space. Whitespace characters are the same allowed by the S production
   9169  * in XML. If the argument is omitted, it defaults to the context
   9170  * node converted to a string, in other words the value of the context node.
   9171  */
   9172 void
   9173 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9174   xmlXPathObjectPtr obj = NULL;
   9175   xmlChar *source = NULL;
   9176   xmlBufferPtr target;
   9177   xmlChar blank;
   9178 
   9179   if (ctxt == NULL) return;
   9180   if (nargs == 0) {
   9181     /* Use current context node */
   9182       valuePush(ctxt,
   9183 	  xmlXPathCacheWrapString(ctxt->context,
   9184 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9185     nargs = 1;
   9186   }
   9187 
   9188   CHECK_ARITY(1);
   9189   CAST_TO_STRING;
   9190   CHECK_TYPE(XPATH_STRING);
   9191   obj = valuePop(ctxt);
   9192   source = obj->stringval;
   9193 
   9194   target = xmlBufferCreate();
   9195   if (target && source) {
   9196 
   9197     /* Skip leading whitespaces */
   9198     while (IS_BLANK_CH(*source))
   9199       source++;
   9200 
   9201     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9202     blank = 0;
   9203     while (*source) {
   9204       if (IS_BLANK_CH(*source)) {
   9205 	blank = 0x20;
   9206       } else {
   9207 	if (blank) {
   9208 	  xmlBufferAdd(target, &blank, 1);
   9209 	  blank = 0;
   9210 	}
   9211 	xmlBufferAdd(target, source, 1);
   9212       }
   9213       source++;
   9214     }
   9215     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9216 	xmlBufferContent(target)));
   9217     xmlBufferFree(target);
   9218   }
   9219   xmlXPathReleaseObject(ctxt->context, obj);
   9220 }
   9221 
   9222 /**
   9223  * xmlXPathTranslateFunction:
   9224  * @ctxt:  the XPath Parser context
   9225  * @nargs:  the number of arguments
   9226  *
   9227  * Implement the translate() XPath function
   9228  *    string translate(string, string, string)
   9229  * The translate function returns the first argument string with
   9230  * occurrences of characters in the second argument string replaced
   9231  * by the character at the corresponding position in the third argument
   9232  * string. For example, translate("bar","abc","ABC") returns the string
   9233  * BAr. If there is a character in the second argument string with no
   9234  * character at a corresponding position in the third argument string
   9235  * (because the second argument string is longer than the third argument
   9236  * string), then occurrences of that character in the first argument
   9237  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9238  * returns "AAA". If a character occurs more than once in second
   9239  * argument string, then the first occurrence determines the replacement
   9240  * character. If the third argument string is longer than the second
   9241  * argument string, then excess characters are ignored.
   9242  */
   9243 void
   9244 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9245     xmlXPathObjectPtr str;
   9246     xmlXPathObjectPtr from;
   9247     xmlXPathObjectPtr to;
   9248     xmlBufferPtr target;
   9249     int offset, max;
   9250     xmlChar ch;
   9251     const xmlChar *point;
   9252     xmlChar *cptr;
   9253 
   9254     CHECK_ARITY(3);
   9255 
   9256     CAST_TO_STRING;
   9257     to = valuePop(ctxt);
   9258     CAST_TO_STRING;
   9259     from = valuePop(ctxt);
   9260     CAST_TO_STRING;
   9261     str = valuePop(ctxt);
   9262 
   9263     target = xmlBufferCreate();
   9264     if (target) {
   9265 	max = xmlUTF8Strlen(to->stringval);
   9266 	for (cptr = str->stringval; (ch=*cptr); ) {
   9267 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9268 	    if (offset >= 0) {
   9269 		if (offset < max) {
   9270 		    point = xmlUTF8Strpos(to->stringval, offset);
   9271 		    if (point)
   9272 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
   9273 		}
   9274 	    } else
   9275 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9276 
   9277 	    /* Step to next character in input */
   9278 	    cptr++;
   9279 	    if ( ch & 0x80 ) {
   9280 		/* if not simple ascii, verify proper format */
   9281 		if ( (ch & 0xc0) != 0xc0 ) {
   9282 		    xmlGenericError(xmlGenericErrorContext,
   9283 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9284 		    break;
   9285 		}
   9286 		/* then skip over remaining bytes for this char */
   9287 		while ( (ch <<= 1) & 0x80 )
   9288 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9289 			xmlGenericError(xmlGenericErrorContext,
   9290 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9291 			break;
   9292 		    }
   9293 		if (ch & 0x80) /* must have had error encountered */
   9294 		    break;
   9295 	    }
   9296 	}
   9297     }
   9298     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9299 	xmlBufferContent(target)));
   9300     xmlBufferFree(target);
   9301     xmlXPathReleaseObject(ctxt->context, str);
   9302     xmlXPathReleaseObject(ctxt->context, from);
   9303     xmlXPathReleaseObject(ctxt->context, to);
   9304 }
   9305 
   9306 /**
   9307  * xmlXPathBooleanFunction:
   9308  * @ctxt:  the XPath Parser context
   9309  * @nargs:  the number of arguments
   9310  *
   9311  * Implement the boolean() XPath function
   9312  *    boolean boolean(object)
   9313  * The boolean function converts its argument to a boolean as follows:
   9314  *    - a number is true if and only if it is neither positive or
   9315  *      negative zero nor NaN
   9316  *    - a node-set is true if and only if it is non-empty
   9317  *    - a string is true if and only if its length is non-zero
   9318  */
   9319 void
   9320 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9321     xmlXPathObjectPtr cur;
   9322 
   9323     CHECK_ARITY(1);
   9324     cur = valuePop(ctxt);
   9325     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9326     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9327     valuePush(ctxt, cur);
   9328 }
   9329 
   9330 /**
   9331  * xmlXPathNotFunction:
   9332  * @ctxt:  the XPath Parser context
   9333  * @nargs:  the number of arguments
   9334  *
   9335  * Implement the not() XPath function
   9336  *    boolean not(boolean)
   9337  * The not function returns true if its argument is false,
   9338  * and false otherwise.
   9339  */
   9340 void
   9341 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9342     CHECK_ARITY(1);
   9343     CAST_TO_BOOLEAN;
   9344     CHECK_TYPE(XPATH_BOOLEAN);
   9345     ctxt->value->boolval = ! ctxt->value->boolval;
   9346 }
   9347 
   9348 /**
   9349  * xmlXPathTrueFunction:
   9350  * @ctxt:  the XPath Parser context
   9351  * @nargs:  the number of arguments
   9352  *
   9353  * Implement the true() XPath function
   9354  *    boolean true()
   9355  */
   9356 void
   9357 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9358     CHECK_ARITY(0);
   9359     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9360 }
   9361 
   9362 /**
   9363  * xmlXPathFalseFunction:
   9364  * @ctxt:  the XPath Parser context
   9365  * @nargs:  the number of arguments
   9366  *
   9367  * Implement the false() XPath function
   9368  *    boolean false()
   9369  */
   9370 void
   9371 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9372     CHECK_ARITY(0);
   9373     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9374 }
   9375 
   9376 /**
   9377  * xmlXPathLangFunction:
   9378  * @ctxt:  the XPath Parser context
   9379  * @nargs:  the number of arguments
   9380  *
   9381  * Implement the lang() XPath function
   9382  *    boolean lang(string)
   9383  * The lang function returns true or false depending on whether the
   9384  * language of the context node as specified by xml:lang attributes
   9385  * is the same as or is a sublanguage of the language specified by
   9386  * the argument string. The language of the context node is determined
   9387  * by the value of the xml:lang attribute on the context node, or, if
   9388  * the context node has no xml:lang attribute, by the value of the
   9389  * xml:lang attribute on the nearest ancestor of the context node that
   9390  * has an xml:lang attribute. If there is no such attribute, then lang
   9391  * returns false. If there is such an attribute, then lang returns
   9392  * true if the attribute value is equal to the argument ignoring case,
   9393  * or if there is some suffix starting with - such that the attribute
   9394  * value is equal to the argument ignoring that suffix of the attribute
   9395  * value and ignoring case.
   9396  */
   9397 void
   9398 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9399     xmlXPathObjectPtr val = NULL;
   9400     const xmlChar *theLang = NULL;
   9401     const xmlChar *lang;
   9402     int ret = 0;
   9403     int i;
   9404 
   9405     CHECK_ARITY(1);
   9406     CAST_TO_STRING;
   9407     CHECK_TYPE(XPATH_STRING);
   9408     val = valuePop(ctxt);
   9409     lang = val->stringval;
   9410     theLang = xmlNodeGetLang(ctxt->context->node);
   9411     if ((theLang != NULL) && (lang != NULL)) {
   9412         for (i = 0;lang[i] != 0;i++)
   9413 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9414 	        goto not_equal;
   9415 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9416 	    ret = 1;
   9417     }
   9418 not_equal:
   9419     if (theLang != NULL)
   9420 	xmlFree((void *)theLang);
   9421 
   9422     xmlXPathReleaseObject(ctxt->context, val);
   9423     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9424 }
   9425 
   9426 /**
   9427  * xmlXPathNumberFunction:
   9428  * @ctxt:  the XPath Parser context
   9429  * @nargs:  the number of arguments
   9430  *
   9431  * Implement the number() XPath function
   9432  *    number number(object?)
   9433  */
   9434 void
   9435 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9436     xmlXPathObjectPtr cur;
   9437     double res;
   9438 
   9439     if (ctxt == NULL) return;
   9440     if (nargs == 0) {
   9441 	if (ctxt->context->node == NULL) {
   9442 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9443 	} else {
   9444 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9445 
   9446 	    res = xmlXPathStringEvalNumber(content);
   9447 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9448 	    xmlFree(content);
   9449 	}
   9450 	return;
   9451     }
   9452 
   9453     CHECK_ARITY(1);
   9454     cur = valuePop(ctxt);
   9455     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9456 }
   9457 
   9458 /**
   9459  * xmlXPathSumFunction:
   9460  * @ctxt:  the XPath Parser context
   9461  * @nargs:  the number of arguments
   9462  *
   9463  * Implement the sum() XPath function
   9464  *    number sum(node-set)
   9465  * The sum function returns the sum of the values of the nodes in
   9466  * the argument node-set.
   9467  */
   9468 void
   9469 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9470     xmlXPathObjectPtr cur;
   9471     int i;
   9472     double res = 0.0;
   9473 
   9474     CHECK_ARITY(1);
   9475     if ((ctxt->value == NULL) ||
   9476 	((ctxt->value->type != XPATH_NODESET) &&
   9477 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9478 	XP_ERROR(XPATH_INVALID_TYPE);
   9479     cur = valuePop(ctxt);
   9480 
   9481     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9482 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9483 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9484 	}
   9485     }
   9486     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9487     xmlXPathReleaseObject(ctxt->context, cur);
   9488 }
   9489 
   9490 /*
   9491  * To assure working code on multiple platforms, we want to only depend
   9492  * upon the characteristic truncation of converting a floating point value
   9493  * to an integer.  Unfortunately, because of the different storage sizes
   9494  * of our internal floating point value (double) and integer (int), we
   9495  * can't directly convert (see bug 301162).  This macro is a messy
   9496  * 'workaround'
   9497  */
   9498 #define XTRUNC(f, v)            \
   9499     f = fmod((v), INT_MAX);     \
   9500     f = (v) - (f) + (double)((int)(f));
   9501 
   9502 /**
   9503  * xmlXPathFloorFunction:
   9504  * @ctxt:  the XPath Parser context
   9505  * @nargs:  the number of arguments
   9506  *
   9507  * Implement the floor() XPath function
   9508  *    number floor(number)
   9509  * The floor function returns the largest (closest to positive infinity)
   9510  * number that is not greater than the argument and that is an integer.
   9511  */
   9512 void
   9513 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9514     double f;
   9515 
   9516     CHECK_ARITY(1);
   9517     CAST_TO_NUMBER;
   9518     CHECK_TYPE(XPATH_NUMBER);
   9519 
   9520     XTRUNC(f, ctxt->value->floatval);
   9521     if (f != ctxt->value->floatval) {
   9522 	if (ctxt->value->floatval > 0)
   9523 	    ctxt->value->floatval = f;
   9524 	else
   9525 	    ctxt->value->floatval = f - 1;
   9526     }
   9527 }
   9528 
   9529 /**
   9530  * xmlXPathCeilingFunction:
   9531  * @ctxt:  the XPath Parser context
   9532  * @nargs:  the number of arguments
   9533  *
   9534  * Implement the ceiling() XPath function
   9535  *    number ceiling(number)
   9536  * The ceiling function returns the smallest (closest to negative infinity)
   9537  * number that is not less than the argument and that is an integer.
   9538  */
   9539 void
   9540 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9541     double f;
   9542 
   9543     CHECK_ARITY(1);
   9544     CAST_TO_NUMBER;
   9545     CHECK_TYPE(XPATH_NUMBER);
   9546 
   9547 #if 0
   9548     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9549 #else
   9550     XTRUNC(f, ctxt->value->floatval);
   9551     if (f != ctxt->value->floatval) {
   9552 	if (ctxt->value->floatval > 0)
   9553 	    ctxt->value->floatval = f + 1;
   9554 	else {
   9555 	    if (ctxt->value->floatval < 0 && f == 0)
   9556 	        ctxt->value->floatval = xmlXPathNZERO;
   9557 	    else
   9558 	        ctxt->value->floatval = f;
   9559 	}
   9560 
   9561     }
   9562 #endif
   9563 }
   9564 
   9565 /**
   9566  * xmlXPathRoundFunction:
   9567  * @ctxt:  the XPath Parser context
   9568  * @nargs:  the number of arguments
   9569  *
   9570  * Implement the round() XPath function
   9571  *    number round(number)
   9572  * The round function returns the number that is closest to the
   9573  * argument and that is an integer. If there are two such numbers,
   9574  * then the one that is even is returned.
   9575  */
   9576 void
   9577 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9578     double f;
   9579 
   9580     CHECK_ARITY(1);
   9581     CAST_TO_NUMBER;
   9582     CHECK_TYPE(XPATH_NUMBER);
   9583 
   9584     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
   9585 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
   9586 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
   9587 	(ctxt->value->floatval == 0.0))
   9588 	return;
   9589 
   9590     XTRUNC(f, ctxt->value->floatval);
   9591     if (ctxt->value->floatval < 0) {
   9592 	if (ctxt->value->floatval < f - 0.5)
   9593 	    ctxt->value->floatval = f - 1;
   9594 	else
   9595 	    ctxt->value->floatval = f;
   9596 	if (ctxt->value->floatval == 0)
   9597 	    ctxt->value->floatval = xmlXPathNZERO;
   9598     } else {
   9599 	if (ctxt->value->floatval < f + 0.5)
   9600 	    ctxt->value->floatval = f;
   9601 	else
   9602 	    ctxt->value->floatval = f + 1;
   9603     }
   9604 }
   9605 
   9606 /************************************************************************
   9607  *									*
   9608  *			The Parser					*
   9609  *									*
   9610  ************************************************************************/
   9611 
   9612 /*
   9613  * a few forward declarations since we use a recursive call based
   9614  * implementation.
   9615  */
   9616 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9617 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9618 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9619 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9620 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9621 	                                  int qualified);
   9622 
   9623 /**
   9624  * xmlXPathCurrentChar:
   9625  * @ctxt:  the XPath parser context
   9626  * @cur:  pointer to the beginning of the char
   9627  * @len:  pointer to the length of the char read
   9628  *
   9629  * The current char value, if using UTF-8 this may actually span multiple
   9630  * bytes in the input buffer.
   9631  *
   9632  * Returns the current char value and its length
   9633  */
   9634 
   9635 static int
   9636 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9637     unsigned char c;
   9638     unsigned int val;
   9639     const xmlChar *cur;
   9640 
   9641     if (ctxt == NULL)
   9642 	return(0);
   9643     cur = ctxt->cur;
   9644 
   9645     /*
   9646      * We are supposed to handle UTF8, check it's valid
   9647      * From rfc2044: encoding of the Unicode values on UTF-8:
   9648      *
   9649      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9650      * 0000 0000-0000 007F   0xxxxxxx
   9651      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9652      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9653      *
   9654      * Check for the 0x110000 limit too
   9655      */
   9656     c = *cur;
   9657     if (c & 0x80) {
   9658 	if ((cur[1] & 0xc0) != 0x80)
   9659 	    goto encoding_error;
   9660 	if ((c & 0xe0) == 0xe0) {
   9661 
   9662 	    if ((cur[2] & 0xc0) != 0x80)
   9663 		goto encoding_error;
   9664 	    if ((c & 0xf0) == 0xf0) {
   9665 		if (((c & 0xf8) != 0xf0) ||
   9666 		    ((cur[3] & 0xc0) != 0x80))
   9667 		    goto encoding_error;
   9668 		/* 4-byte code */
   9669 		*len = 4;
   9670 		val = (cur[0] & 0x7) << 18;
   9671 		val |= (cur[1] & 0x3f) << 12;
   9672 		val |= (cur[2] & 0x3f) << 6;
   9673 		val |= cur[3] & 0x3f;
   9674 	    } else {
   9675 	      /* 3-byte code */
   9676 		*len = 3;
   9677 		val = (cur[0] & 0xf) << 12;
   9678 		val |= (cur[1] & 0x3f) << 6;
   9679 		val |= cur[2] & 0x3f;
   9680 	    }
   9681 	} else {
   9682 	  /* 2-byte code */
   9683 	    *len = 2;
   9684 	    val = (cur[0] & 0x1f) << 6;
   9685 	    val |= cur[1] & 0x3f;
   9686 	}
   9687 	if (!IS_CHAR(val)) {
   9688 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9689 	}
   9690 	return(val);
   9691     } else {
   9692 	/* 1-byte code */
   9693 	*len = 1;
   9694 	return((int) *cur);
   9695     }
   9696 encoding_error:
   9697     /*
   9698      * If we detect an UTF8 error that probably means that the
   9699      * input encoding didn't get properly advertised in the
   9700      * declaration header. Report the error and switch the encoding
   9701      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9702      * encoding !)
   9703      */
   9704     *len = 0;
   9705     XP_ERROR0(XPATH_ENCODING_ERROR);
   9706 }
   9707 
   9708 /**
   9709  * xmlXPathParseNCName:
   9710  * @ctxt:  the XPath Parser context
   9711  *
   9712  * parse an XML namespace non qualified name.
   9713  *
   9714  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9715  *
   9716  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9717  *                       CombiningChar | Extender
   9718  *
   9719  * Returns the namespace name or NULL
   9720  */
   9721 
   9722 xmlChar *
   9723 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9724     const xmlChar *in;
   9725     xmlChar *ret;
   9726     int count = 0;
   9727 
   9728     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9729     /*
   9730      * Accelerator for simple ASCII names
   9731      */
   9732     in = ctxt->cur;
   9733     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9734 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9735 	(*in == '_')) {
   9736 	in++;
   9737 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9738 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9739 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9740 	       (*in == '_') || (*in == '.') ||
   9741 	       (*in == '-'))
   9742 	    in++;
   9743 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9744             (*in == '[') || (*in == ']') || (*in == ':') ||
   9745             (*in == '@') || (*in == '*')) {
   9746 	    count = in - ctxt->cur;
   9747 	    if (count == 0)
   9748 		return(NULL);
   9749 	    ret = xmlStrndup(ctxt->cur, count);
   9750 	    ctxt->cur = in;
   9751 	    return(ret);
   9752 	}
   9753     }
   9754     return(xmlXPathParseNameComplex(ctxt, 0));
   9755 }
   9756 
   9757 
   9758 /**
   9759  * xmlXPathParseQName:
   9760  * @ctxt:  the XPath Parser context
   9761  * @prefix:  a xmlChar **
   9762  *
   9763  * parse an XML qualified name
   9764  *
   9765  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9766  *
   9767  * [NS 6] Prefix ::= NCName
   9768  *
   9769  * [NS 7] LocalPart ::= NCName
   9770  *
   9771  * Returns the function returns the local part, and prefix is updated
   9772  *   to get the Prefix if any.
   9773  */
   9774 
   9775 static xmlChar *
   9776 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9777     xmlChar *ret = NULL;
   9778 
   9779     *prefix = NULL;
   9780     ret = xmlXPathParseNCName(ctxt);
   9781     if (ret && CUR == ':') {
   9782         *prefix = ret;
   9783 	NEXT;
   9784 	ret = xmlXPathParseNCName(ctxt);
   9785     }
   9786     return(ret);
   9787 }
   9788 
   9789 /**
   9790  * xmlXPathParseName:
   9791  * @ctxt:  the XPath Parser context
   9792  *
   9793  * parse an XML name
   9794  *
   9795  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9796  *                  CombiningChar | Extender
   9797  *
   9798  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9799  *
   9800  * Returns the namespace name or NULL
   9801  */
   9802 
   9803 xmlChar *
   9804 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9805     const xmlChar *in;
   9806     xmlChar *ret;
   9807     int count = 0;
   9808 
   9809     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9810     /*
   9811      * Accelerator for simple ASCII names
   9812      */
   9813     in = ctxt->cur;
   9814     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9815 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9816 	(*in == '_') || (*in == ':')) {
   9817 	in++;
   9818 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9819 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9820 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9821 	       (*in == '_') || (*in == '-') ||
   9822 	       (*in == ':') || (*in == '.'))
   9823 	    in++;
   9824 	if ((*in > 0) && (*in < 0x80)) {
   9825 	    count = in - ctxt->cur;
   9826 	    ret = xmlStrndup(ctxt->cur, count);
   9827 	    ctxt->cur = in;
   9828 	    return(ret);
   9829 	}
   9830     }
   9831     return(xmlXPathParseNameComplex(ctxt, 1));
   9832 }
   9833 
   9834 static xmlChar *
   9835 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9836     xmlChar buf[XML_MAX_NAMELEN + 5];
   9837     int len = 0, l;
   9838     int c;
   9839 
   9840     /*
   9841      * Handler for more complex cases
   9842      */
   9843     c = CUR_CHAR(l);
   9844     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9845         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9846         (c == '*') || /* accelerators */
   9847 	(!IS_LETTER(c) && (c != '_') &&
   9848          ((qualified) && (c != ':')))) {
   9849 	return(NULL);
   9850     }
   9851 
   9852     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9853 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   9854             (c == '.') || (c == '-') ||
   9855 	    (c == '_') || ((qualified) && (c == ':')) ||
   9856 	    (IS_COMBINING(c)) ||
   9857 	    (IS_EXTENDER(c)))) {
   9858 	COPY_BUF(l,buf,len,c);
   9859 	NEXTL(l);
   9860 	c = CUR_CHAR(l);
   9861 	if (len >= XML_MAX_NAMELEN) {
   9862 	    /*
   9863 	     * Okay someone managed to make a huge name, so he's ready to pay
   9864 	     * for the processing speed.
   9865 	     */
   9866 	    xmlChar *buffer;
   9867 	    int max = len * 2;
   9868 
   9869 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   9870 	    if (buffer == NULL) {
   9871 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9872 	    }
   9873 	    memcpy(buffer, buf, len);
   9874 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   9875 		   (c == '.') || (c == '-') ||
   9876 		   (c == '_') || ((qualified) && (c == ':')) ||
   9877 		   (IS_COMBINING(c)) ||
   9878 		   (IS_EXTENDER(c))) {
   9879 		if (len + 10 > max) {
   9880 		    max *= 2;
   9881 		    buffer = (xmlChar *) xmlRealloc(buffer,
   9882 			                            max * sizeof(xmlChar));
   9883 		    if (buffer == NULL) {
   9884 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9885 		    }
   9886 		}
   9887 		COPY_BUF(l,buffer,len,c);
   9888 		NEXTL(l);
   9889 		c = CUR_CHAR(l);
   9890 	    }
   9891 	    buffer[len] = 0;
   9892 	    return(buffer);
   9893 	}
   9894     }
   9895     if (len == 0)
   9896 	return(NULL);
   9897     return(xmlStrndup(buf, len));
   9898 }
   9899 
   9900 #define MAX_FRAC 20
   9901 
   9902 /*
   9903  * These are used as divisors for the fractional part of a number.
   9904  * Since the table includes 1.0 (representing '0' fractional digits),
   9905  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
   9906  */
   9907 static double my_pow10[MAX_FRAC+1] = {
   9908     1.0, 10.0, 100.0, 1000.0, 10000.0,
   9909     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
   9910     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
   9911     100000000000000.0,
   9912     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
   9913     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
   9914 };
   9915 
   9916 /**
   9917  * xmlXPathStringEvalNumber:
   9918  * @str:  A string to scan
   9919  *
   9920  *  [30a]  Float  ::= Number ('e' Digits?)?
   9921  *
   9922  *  [30]   Number ::=   Digits ('.' Digits?)?
   9923  *                    | '.' Digits
   9924  *  [31]   Digits ::=   [0-9]+
   9925  *
   9926  * Compile a Number in the string
   9927  * In complement of the Number expression, this function also handles
   9928  * negative values : '-' Number.
   9929  *
   9930  * Returns the double value.
   9931  */
   9932 double
   9933 xmlXPathStringEvalNumber(const xmlChar *str) {
   9934     const xmlChar *cur = str;
   9935     double ret;
   9936     int ok = 0;
   9937     int isneg = 0;
   9938     int exponent = 0;
   9939     int is_exponent_negative = 0;
   9940 #ifdef __GNUC__
   9941     unsigned long tmp = 0;
   9942     double temp;
   9943 #endif
   9944     if (cur == NULL) return(0);
   9945     while (IS_BLANK_CH(*cur)) cur++;
   9946     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   9947         return(xmlXPathNAN);
   9948     }
   9949     if (*cur == '-') {
   9950 	isneg = 1;
   9951 	cur++;
   9952     }
   9953 
   9954 #ifdef __GNUC__
   9955     /*
   9956      * tmp/temp is a workaround against a gcc compiler bug
   9957      * http://veillard.com/gcc.bug
   9958      */
   9959     ret = 0;
   9960     while ((*cur >= '0') && (*cur <= '9')) {
   9961 	ret = ret * 10;
   9962 	tmp = (*cur - '0');
   9963 	ok = 1;
   9964 	cur++;
   9965 	temp = (double) tmp;
   9966 	ret = ret + temp;
   9967     }
   9968 #else
   9969     ret = 0;
   9970     while ((*cur >= '0') && (*cur <= '9')) {
   9971 	ret = ret * 10 + (*cur - '0');
   9972 	ok = 1;
   9973 	cur++;
   9974     }
   9975 #endif
   9976 
   9977     if (*cur == '.') {
   9978 	int v, frac = 0;
   9979 	double fraction = 0;
   9980 
   9981         cur++;
   9982 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   9983 	    return(xmlXPathNAN);
   9984 	}
   9985 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
   9986 	    v = (*cur - '0');
   9987 	    fraction = fraction * 10 + v;
   9988 	    frac = frac + 1;
   9989 	    cur++;
   9990 	}
   9991 	fraction /= my_pow10[frac];
   9992 	ret = ret + fraction;
   9993 	while ((*cur >= '0') && (*cur <= '9'))
   9994 	    cur++;
   9995     }
   9996     if ((*cur == 'e') || (*cur == 'E')) {
   9997       cur++;
   9998       if (*cur == '-') {
   9999 	is_exponent_negative = 1;
   10000 	cur++;
   10001       } else if (*cur == '+') {
   10002         cur++;
   10003       }
   10004       while ((*cur >= '0') && (*cur <= '9')) {
   10005 	exponent = exponent * 10 + (*cur - '0');
   10006 	cur++;
   10007       }
   10008     }
   10009     while (IS_BLANK_CH(*cur)) cur++;
   10010     if (*cur != 0) return(xmlXPathNAN);
   10011     if (isneg) ret = -ret;
   10012     if (is_exponent_negative) exponent = -exponent;
   10013     ret *= pow(10.0, (double)exponent);
   10014     return(ret);
   10015 }
   10016 
   10017 /**
   10018  * xmlXPathCompNumber:
   10019  * @ctxt:  the XPath Parser context
   10020  *
   10021  *  [30]   Number ::=   Digits ('.' Digits?)?
   10022  *                    | '.' Digits
   10023  *  [31]   Digits ::=   [0-9]+
   10024  *
   10025  * Compile a Number, then push it on the stack
   10026  *
   10027  */
   10028 static void
   10029 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10030 {
   10031     double ret = 0.0;
   10032     double mult = 1;
   10033     int ok = 0;
   10034     int exponent = 0;
   10035     int is_exponent_negative = 0;
   10036 #ifdef __GNUC__
   10037     unsigned long tmp = 0;
   10038     double temp;
   10039 #endif
   10040 
   10041     CHECK_ERROR;
   10042     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10043         XP_ERROR(XPATH_NUMBER_ERROR);
   10044     }
   10045 #ifdef __GNUC__
   10046     /*
   10047      * tmp/temp is a workaround against a gcc compiler bug
   10048      * http://veillard.com/gcc.bug
   10049      */
   10050     ret = 0;
   10051     while ((CUR >= '0') && (CUR <= '9')) {
   10052 	ret = ret * 10;
   10053 	tmp = (CUR - '0');
   10054         ok = 1;
   10055         NEXT;
   10056 	temp = (double) tmp;
   10057 	ret = ret + temp;
   10058     }
   10059 #else
   10060     ret = 0;
   10061     while ((CUR >= '0') && (CUR <= '9')) {
   10062 	ret = ret * 10 + (CUR - '0');
   10063 	ok = 1;
   10064 	NEXT;
   10065     }
   10066 #endif
   10067     if (CUR == '.') {
   10068         NEXT;
   10069         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10070             XP_ERROR(XPATH_NUMBER_ERROR);
   10071         }
   10072         while ((CUR >= '0') && (CUR <= '9')) {
   10073             mult /= 10;
   10074             ret = ret + (CUR - '0') * mult;
   10075             NEXT;
   10076         }
   10077     }
   10078     if ((CUR == 'e') || (CUR == 'E')) {
   10079         NEXT;
   10080         if (CUR == '-') {
   10081             is_exponent_negative = 1;
   10082             NEXT;
   10083         } else if (CUR == '+') {
   10084 	    NEXT;
   10085 	}
   10086         while ((CUR >= '0') && (CUR <= '9')) {
   10087             exponent = exponent * 10 + (CUR - '0');
   10088             NEXT;
   10089         }
   10090         if (is_exponent_negative)
   10091             exponent = -exponent;
   10092         ret *= pow(10.0, (double) exponent);
   10093     }
   10094     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10095                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10096 }
   10097 
   10098 /**
   10099  * xmlXPathParseLiteral:
   10100  * @ctxt:  the XPath Parser context
   10101  *
   10102  * Parse a Literal
   10103  *
   10104  *  [29]   Literal ::=   '"' [^"]* '"'
   10105  *                    | "'" [^']* "'"
   10106  *
   10107  * Returns the value found or NULL in case of error
   10108  */
   10109 static xmlChar *
   10110 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10111     const xmlChar *q;
   10112     xmlChar *ret = NULL;
   10113 
   10114     if (CUR == '"') {
   10115         NEXT;
   10116 	q = CUR_PTR;
   10117 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10118 	    NEXT;
   10119 	if (!IS_CHAR_CH(CUR)) {
   10120 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10121 	} else {
   10122 	    ret = xmlStrndup(q, CUR_PTR - q);
   10123 	    NEXT;
   10124         }
   10125     } else if (CUR == '\'') {
   10126         NEXT;
   10127 	q = CUR_PTR;
   10128 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10129 	    NEXT;
   10130 	if (!IS_CHAR_CH(CUR)) {
   10131 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10132 	} else {
   10133 	    ret = xmlStrndup(q, CUR_PTR - q);
   10134 	    NEXT;
   10135         }
   10136     } else {
   10137 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10138     }
   10139     return(ret);
   10140 }
   10141 
   10142 /**
   10143  * xmlXPathCompLiteral:
   10144  * @ctxt:  the XPath Parser context
   10145  *
   10146  * Parse a Literal and push it on the stack.
   10147  *
   10148  *  [29]   Literal ::=   '"' [^"]* '"'
   10149  *                    | "'" [^']* "'"
   10150  *
   10151  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10152  */
   10153 static void
   10154 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10155     const xmlChar *q;
   10156     xmlChar *ret = NULL;
   10157 
   10158     if (CUR == '"') {
   10159         NEXT;
   10160 	q = CUR_PTR;
   10161 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10162 	    NEXT;
   10163 	if (!IS_CHAR_CH(CUR)) {
   10164 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10165 	} else {
   10166 	    ret = xmlStrndup(q, CUR_PTR - q);
   10167 	    NEXT;
   10168         }
   10169     } else if (CUR == '\'') {
   10170         NEXT;
   10171 	q = CUR_PTR;
   10172 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10173 	    NEXT;
   10174 	if (!IS_CHAR_CH(CUR)) {
   10175 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10176 	} else {
   10177 	    ret = xmlStrndup(q, CUR_PTR - q);
   10178 	    NEXT;
   10179         }
   10180     } else {
   10181 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10182     }
   10183     if (ret == NULL) return;
   10184     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10185 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10186     xmlFree(ret);
   10187 }
   10188 
   10189 /**
   10190  * xmlXPathCompVariableReference:
   10191  * @ctxt:  the XPath Parser context
   10192  *
   10193  * Parse a VariableReference, evaluate it and push it on the stack.
   10194  *
   10195  * The variable bindings consist of a mapping from variable names
   10196  * to variable values. The value of a variable is an object, which can be
   10197  * of any of the types that are possible for the value of an expression,
   10198  * and may also be of additional types not specified here.
   10199  *
   10200  * Early evaluation is possible since:
   10201  * The variable bindings [...] used to evaluate a subexpression are
   10202  * always the same as those used to evaluate the containing expression.
   10203  *
   10204  *  [36]   VariableReference ::=   '$' QName
   10205  */
   10206 static void
   10207 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10208     xmlChar *name;
   10209     xmlChar *prefix;
   10210 
   10211     SKIP_BLANKS;
   10212     if (CUR != '$') {
   10213 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10214     }
   10215     NEXT;
   10216     name = xmlXPathParseQName(ctxt, &prefix);
   10217     if (name == NULL) {
   10218 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10219     }
   10220     ctxt->comp->last = -1;
   10221     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10222 	           name, prefix);
   10223     SKIP_BLANKS;
   10224     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10225 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
   10226     }
   10227 }
   10228 
   10229 /**
   10230  * xmlXPathIsNodeType:
   10231  * @name:  a name string
   10232  *
   10233  * Is the name given a NodeType one.
   10234  *
   10235  *  [38]   NodeType ::=   'comment'
   10236  *                    | 'text'
   10237  *                    | 'processing-instruction'
   10238  *                    | 'node'
   10239  *
   10240  * Returns 1 if true 0 otherwise
   10241  */
   10242 int
   10243 xmlXPathIsNodeType(const xmlChar *name) {
   10244     if (name == NULL)
   10245 	return(0);
   10246 
   10247     if (xmlStrEqual(name, BAD_CAST "node"))
   10248 	return(1);
   10249     if (xmlStrEqual(name, BAD_CAST "text"))
   10250 	return(1);
   10251     if (xmlStrEqual(name, BAD_CAST "comment"))
   10252 	return(1);
   10253     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10254 	return(1);
   10255     return(0);
   10256 }
   10257 
   10258 /**
   10259  * xmlXPathCompFunctionCall:
   10260  * @ctxt:  the XPath Parser context
   10261  *
   10262  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10263  *  [17]   Argument ::=   Expr
   10264  *
   10265  * Compile a function call, the evaluation of all arguments are
   10266  * pushed on the stack
   10267  */
   10268 static void
   10269 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10270     xmlChar *name;
   10271     xmlChar *prefix;
   10272     int nbargs = 0;
   10273     int sort = 1;
   10274 
   10275     name = xmlXPathParseQName(ctxt, &prefix);
   10276     if (name == NULL) {
   10277 	xmlFree(prefix);
   10278 	XP_ERROR(XPATH_EXPR_ERROR);
   10279     }
   10280     SKIP_BLANKS;
   10281 #ifdef DEBUG_EXPR
   10282     if (prefix == NULL)
   10283 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10284 			name);
   10285     else
   10286 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10287 			prefix, name);
   10288 #endif
   10289 
   10290     if (CUR != '(') {
   10291 	XP_ERROR(XPATH_EXPR_ERROR);
   10292     }
   10293     NEXT;
   10294     SKIP_BLANKS;
   10295 
   10296     /*
   10297     * Optimization for count(): we don't need the node-set to be sorted.
   10298     */
   10299     if ((prefix == NULL) && (name[0] == 'c') &&
   10300 	xmlStrEqual(name, BAD_CAST "count"))
   10301     {
   10302 	sort = 0;
   10303     }
   10304     ctxt->comp->last = -1;
   10305     if (CUR != ')') {
   10306 	while (CUR != 0) {
   10307 	    int op1 = ctxt->comp->last;
   10308 	    ctxt->comp->last = -1;
   10309 	    xmlXPathCompileExpr(ctxt, sort);
   10310 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10311 		xmlFree(name);
   10312 		xmlFree(prefix);
   10313 		return;
   10314 	    }
   10315 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10316 	    nbargs++;
   10317 	    if (CUR == ')') break;
   10318 	    if (CUR != ',') {
   10319 		XP_ERROR(XPATH_EXPR_ERROR);
   10320 	    }
   10321 	    NEXT;
   10322 	    SKIP_BLANKS;
   10323 	}
   10324     }
   10325     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10326 	           name, prefix);
   10327     NEXT;
   10328     SKIP_BLANKS;
   10329 }
   10330 
   10331 /**
   10332  * xmlXPathCompPrimaryExpr:
   10333  * @ctxt:  the XPath Parser context
   10334  *
   10335  *  [15]   PrimaryExpr ::=   VariableReference
   10336  *                | '(' Expr ')'
   10337  *                | Literal
   10338  *                | Number
   10339  *                | FunctionCall
   10340  *
   10341  * Compile a primary expression.
   10342  */
   10343 static void
   10344 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10345     SKIP_BLANKS;
   10346     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10347     else if (CUR == '(') {
   10348 	NEXT;
   10349 	SKIP_BLANKS;
   10350 	xmlXPathCompileExpr(ctxt, 1);
   10351 	CHECK_ERROR;
   10352 	if (CUR != ')') {
   10353 	    XP_ERROR(XPATH_EXPR_ERROR);
   10354 	}
   10355 	NEXT;
   10356 	SKIP_BLANKS;
   10357     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10358 	xmlXPathCompNumber(ctxt);
   10359     } else if ((CUR == '\'') || (CUR == '"')) {
   10360 	xmlXPathCompLiteral(ctxt);
   10361     } else {
   10362 	xmlXPathCompFunctionCall(ctxt);
   10363     }
   10364     SKIP_BLANKS;
   10365 }
   10366 
   10367 /**
   10368  * xmlXPathCompFilterExpr:
   10369  * @ctxt:  the XPath Parser context
   10370  *
   10371  *  [20]   FilterExpr ::=   PrimaryExpr
   10372  *               | FilterExpr Predicate
   10373  *
   10374  * Compile a filter expression.
   10375  * Square brackets are used to filter expressions in the same way that
   10376  * they are used in location paths. It is an error if the expression to
   10377  * be filtered does not evaluate to a node-set. The context node list
   10378  * used for evaluating the expression in square brackets is the node-set
   10379  * to be filtered listed in document order.
   10380  */
   10381 
   10382 static void
   10383 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10384     xmlXPathCompPrimaryExpr(ctxt);
   10385     CHECK_ERROR;
   10386     SKIP_BLANKS;
   10387 
   10388     while (CUR == '[') {
   10389 	xmlXPathCompPredicate(ctxt, 1);
   10390 	SKIP_BLANKS;
   10391     }
   10392 
   10393 
   10394 }
   10395 
   10396 /**
   10397  * xmlXPathScanName:
   10398  * @ctxt:  the XPath Parser context
   10399  *
   10400  * Trickery: parse an XML name but without consuming the input flow
   10401  * Needed to avoid insanity in the parser state.
   10402  *
   10403  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10404  *                  CombiningChar | Extender
   10405  *
   10406  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10407  *
   10408  * [6] Names ::= Name (S Name)*
   10409  *
   10410  * Returns the Name parsed or NULL
   10411  */
   10412 
   10413 static xmlChar *
   10414 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10415     int len = 0, l;
   10416     int c;
   10417     const xmlChar *cur;
   10418     xmlChar *ret;
   10419 
   10420     cur = ctxt->cur;
   10421 
   10422     c = CUR_CHAR(l);
   10423     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10424 	(!IS_LETTER(c) && (c != '_') &&
   10425          (c != ':'))) {
   10426 	return(NULL);
   10427     }
   10428 
   10429     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10430 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10431             (c == '.') || (c == '-') ||
   10432 	    (c == '_') || (c == ':') ||
   10433 	    (IS_COMBINING(c)) ||
   10434 	    (IS_EXTENDER(c)))) {
   10435 	len += l;
   10436 	NEXTL(l);
   10437 	c = CUR_CHAR(l);
   10438     }
   10439     ret = xmlStrndup(cur, ctxt->cur - cur);
   10440     ctxt->cur = cur;
   10441     return(ret);
   10442 }
   10443 
   10444 /**
   10445  * xmlXPathCompPathExpr:
   10446  * @ctxt:  the XPath Parser context
   10447  *
   10448  *  [19]   PathExpr ::=   LocationPath
   10449  *               | FilterExpr
   10450  *               | FilterExpr '/' RelativeLocationPath
   10451  *               | FilterExpr '//' RelativeLocationPath
   10452  *
   10453  * Compile a path expression.
   10454  * The / operator and // operators combine an arbitrary expression
   10455  * and a relative location path. It is an error if the expression
   10456  * does not evaluate to a node-set.
   10457  * The / operator does composition in the same way as when / is
   10458  * used in a location path. As in location paths, // is short for
   10459  * /descendant-or-self::node()/.
   10460  */
   10461 
   10462 static void
   10463 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10464     int lc = 1;           /* Should we branch to LocationPath ?         */
   10465     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10466 
   10467     SKIP_BLANKS;
   10468     if ((CUR == '$') || (CUR == '(') ||
   10469 	(IS_ASCII_DIGIT(CUR)) ||
   10470         (CUR == '\'') || (CUR == '"') ||
   10471 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10472 	lc = 0;
   10473     } else if (CUR == '*') {
   10474 	/* relative or absolute location path */
   10475 	lc = 1;
   10476     } else if (CUR == '/') {
   10477 	/* relative or absolute location path */
   10478 	lc = 1;
   10479     } else if (CUR == '@') {
   10480 	/* relative abbreviated attribute location path */
   10481 	lc = 1;
   10482     } else if (CUR == '.') {
   10483 	/* relative abbreviated attribute location path */
   10484 	lc = 1;
   10485     } else {
   10486 	/*
   10487 	 * Problem is finding if we have a name here whether it's:
   10488 	 *   - a nodetype
   10489 	 *   - a function call in which case it's followed by '('
   10490 	 *   - an axis in which case it's followed by ':'
   10491 	 *   - a element name
   10492 	 * We do an a priori analysis here rather than having to
   10493 	 * maintain parsed token content through the recursive function
   10494 	 * calls. This looks uglier but makes the code easier to
   10495 	 * read/write/debug.
   10496 	 */
   10497 	SKIP_BLANKS;
   10498 	name = xmlXPathScanName(ctxt);
   10499 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10500 #ifdef DEBUG_STEP
   10501 	    xmlGenericError(xmlGenericErrorContext,
   10502 		    "PathExpr: Axis\n");
   10503 #endif
   10504 	    lc = 1;
   10505 	    xmlFree(name);
   10506 	} else if (name != NULL) {
   10507 	    int len =xmlStrlen(name);
   10508 
   10509 
   10510 	    while (NXT(len) != 0) {
   10511 		if (NXT(len) == '/') {
   10512 		    /* element name */
   10513 #ifdef DEBUG_STEP
   10514 		    xmlGenericError(xmlGenericErrorContext,
   10515 			    "PathExpr: AbbrRelLocation\n");
   10516 #endif
   10517 		    lc = 1;
   10518 		    break;
   10519 		} else if (IS_BLANK_CH(NXT(len))) {
   10520 		    /* ignore blanks */
   10521 		    ;
   10522 		} else if (NXT(len) == ':') {
   10523 #ifdef DEBUG_STEP
   10524 		    xmlGenericError(xmlGenericErrorContext,
   10525 			    "PathExpr: AbbrRelLocation\n");
   10526 #endif
   10527 		    lc = 1;
   10528 		    break;
   10529 		} else if ((NXT(len) == '(')) {
   10530 		    /* Note Type or Function */
   10531 		    if (xmlXPathIsNodeType(name)) {
   10532 #ifdef DEBUG_STEP
   10533 		        xmlGenericError(xmlGenericErrorContext,
   10534 				"PathExpr: Type search\n");
   10535 #endif
   10536 			lc = 1;
   10537 		    } else {
   10538 #ifdef DEBUG_STEP
   10539 		        xmlGenericError(xmlGenericErrorContext,
   10540 				"PathExpr: function call\n");
   10541 #endif
   10542 			lc = 0;
   10543 		    }
   10544                     break;
   10545 		} else if ((NXT(len) == '[')) {
   10546 		    /* element name */
   10547 #ifdef DEBUG_STEP
   10548 		    xmlGenericError(xmlGenericErrorContext,
   10549 			    "PathExpr: AbbrRelLocation\n");
   10550 #endif
   10551 		    lc = 1;
   10552 		    break;
   10553 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10554 			   (NXT(len) == '=')) {
   10555 		    lc = 1;
   10556 		    break;
   10557 		} else {
   10558 		    lc = 1;
   10559 		    break;
   10560 		}
   10561 		len++;
   10562 	    }
   10563 	    if (NXT(len) == 0) {
   10564 #ifdef DEBUG_STEP
   10565 		xmlGenericError(xmlGenericErrorContext,
   10566 			"PathExpr: AbbrRelLocation\n");
   10567 #endif
   10568 		/* element name */
   10569 		lc = 1;
   10570 	    }
   10571 	    xmlFree(name);
   10572 	} else {
   10573 	    /* make sure all cases are covered explicitly */
   10574 	    XP_ERROR(XPATH_EXPR_ERROR);
   10575 	}
   10576     }
   10577 
   10578     if (lc) {
   10579 	if (CUR == '/') {
   10580 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10581 	} else {
   10582 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10583 	}
   10584 	xmlXPathCompLocationPath(ctxt);
   10585     } else {
   10586 	xmlXPathCompFilterExpr(ctxt);
   10587 	CHECK_ERROR;
   10588 	if ((CUR == '/') && (NXT(1) == '/')) {
   10589 	    SKIP(2);
   10590 	    SKIP_BLANKS;
   10591 
   10592 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10593 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10594 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10595 
   10596 	    xmlXPathCompRelativeLocationPath(ctxt);
   10597 	} else if (CUR == '/') {
   10598 	    xmlXPathCompRelativeLocationPath(ctxt);
   10599 	}
   10600     }
   10601     SKIP_BLANKS;
   10602 }
   10603 
   10604 /**
   10605  * xmlXPathCompUnionExpr:
   10606  * @ctxt:  the XPath Parser context
   10607  *
   10608  *  [18]   UnionExpr ::=   PathExpr
   10609  *               | UnionExpr '|' PathExpr
   10610  *
   10611  * Compile an union expression.
   10612  */
   10613 
   10614 static void
   10615 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10616     xmlXPathCompPathExpr(ctxt);
   10617     CHECK_ERROR;
   10618     SKIP_BLANKS;
   10619     while (CUR == '|') {
   10620 	int op1 = ctxt->comp->last;
   10621 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10622 
   10623 	NEXT;
   10624 	SKIP_BLANKS;
   10625 	xmlXPathCompPathExpr(ctxt);
   10626 
   10627 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10628 
   10629 	SKIP_BLANKS;
   10630     }
   10631 }
   10632 
   10633 /**
   10634  * xmlXPathCompUnaryExpr:
   10635  * @ctxt:  the XPath Parser context
   10636  *
   10637  *  [27]   UnaryExpr ::=   UnionExpr
   10638  *                   | '-' UnaryExpr
   10639  *
   10640  * Compile an unary expression.
   10641  */
   10642 
   10643 static void
   10644 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10645     int minus = 0;
   10646     int found = 0;
   10647 
   10648     SKIP_BLANKS;
   10649     while (CUR == '-') {
   10650         minus = 1 - minus;
   10651 	found = 1;
   10652 	NEXT;
   10653 	SKIP_BLANKS;
   10654     }
   10655 
   10656     xmlXPathCompUnionExpr(ctxt);
   10657     CHECK_ERROR;
   10658     if (found) {
   10659 	if (minus)
   10660 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10661 	else
   10662 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10663     }
   10664 }
   10665 
   10666 /**
   10667  * xmlXPathCompMultiplicativeExpr:
   10668  * @ctxt:  the XPath Parser context
   10669  *
   10670  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10671  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10672  *                   | MultiplicativeExpr 'div' UnaryExpr
   10673  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10674  *  [34]   MultiplyOperator ::=   '*'
   10675  *
   10676  * Compile an Additive expression.
   10677  */
   10678 
   10679 static void
   10680 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10681     xmlXPathCompUnaryExpr(ctxt);
   10682     CHECK_ERROR;
   10683     SKIP_BLANKS;
   10684     while ((CUR == '*') ||
   10685            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10686            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10687 	int op = -1;
   10688 	int op1 = ctxt->comp->last;
   10689 
   10690         if (CUR == '*') {
   10691 	    op = 0;
   10692 	    NEXT;
   10693 	} else if (CUR == 'd') {
   10694 	    op = 1;
   10695 	    SKIP(3);
   10696 	} else if (CUR == 'm') {
   10697 	    op = 2;
   10698 	    SKIP(3);
   10699 	}
   10700 	SKIP_BLANKS;
   10701         xmlXPathCompUnaryExpr(ctxt);
   10702 	CHECK_ERROR;
   10703 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10704 	SKIP_BLANKS;
   10705     }
   10706 }
   10707 
   10708 /**
   10709  * xmlXPathCompAdditiveExpr:
   10710  * @ctxt:  the XPath Parser context
   10711  *
   10712  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10713  *                   | AdditiveExpr '+' MultiplicativeExpr
   10714  *                   | AdditiveExpr '-' MultiplicativeExpr
   10715  *
   10716  * Compile an Additive expression.
   10717  */
   10718 
   10719 static void
   10720 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10721 
   10722     xmlXPathCompMultiplicativeExpr(ctxt);
   10723     CHECK_ERROR;
   10724     SKIP_BLANKS;
   10725     while ((CUR == '+') || (CUR == '-')) {
   10726 	int plus;
   10727 	int op1 = ctxt->comp->last;
   10728 
   10729         if (CUR == '+') plus = 1;
   10730 	else plus = 0;
   10731 	NEXT;
   10732 	SKIP_BLANKS;
   10733         xmlXPathCompMultiplicativeExpr(ctxt);
   10734 	CHECK_ERROR;
   10735 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10736 	SKIP_BLANKS;
   10737     }
   10738 }
   10739 
   10740 /**
   10741  * xmlXPathCompRelationalExpr:
   10742  * @ctxt:  the XPath Parser context
   10743  *
   10744  *  [24]   RelationalExpr ::=   AdditiveExpr
   10745  *                 | RelationalExpr '<' AdditiveExpr
   10746  *                 | RelationalExpr '>' AdditiveExpr
   10747  *                 | RelationalExpr '<=' AdditiveExpr
   10748  *                 | RelationalExpr '>=' AdditiveExpr
   10749  *
   10750  *  A <= B > C is allowed ? Answer from James, yes with
   10751  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10752  *  which is basically what got implemented.
   10753  *
   10754  * Compile a Relational expression, then push the result
   10755  * on the stack
   10756  */
   10757 
   10758 static void
   10759 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10760     xmlXPathCompAdditiveExpr(ctxt);
   10761     CHECK_ERROR;
   10762     SKIP_BLANKS;
   10763     while ((CUR == '<') ||
   10764            (CUR == '>') ||
   10765            ((CUR == '<') && (NXT(1) == '=')) ||
   10766            ((CUR == '>') && (NXT(1) == '='))) {
   10767 	int inf, strict;
   10768 	int op1 = ctxt->comp->last;
   10769 
   10770         if (CUR == '<') inf = 1;
   10771 	else inf = 0;
   10772 	if (NXT(1) == '=') strict = 0;
   10773 	else strict = 1;
   10774 	NEXT;
   10775 	if (!strict) NEXT;
   10776 	SKIP_BLANKS;
   10777         xmlXPathCompAdditiveExpr(ctxt);
   10778 	CHECK_ERROR;
   10779 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10780 	SKIP_BLANKS;
   10781     }
   10782 }
   10783 
   10784 /**
   10785  * xmlXPathCompEqualityExpr:
   10786  * @ctxt:  the XPath Parser context
   10787  *
   10788  *  [23]   EqualityExpr ::=   RelationalExpr
   10789  *                 | EqualityExpr '=' RelationalExpr
   10790  *                 | EqualityExpr '!=' RelationalExpr
   10791  *
   10792  *  A != B != C is allowed ? Answer from James, yes with
   10793  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10794  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10795  *  which is basically what got implemented.
   10796  *
   10797  * Compile an Equality expression.
   10798  *
   10799  */
   10800 static void
   10801 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10802     xmlXPathCompRelationalExpr(ctxt);
   10803     CHECK_ERROR;
   10804     SKIP_BLANKS;
   10805     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10806 	int eq;
   10807 	int op1 = ctxt->comp->last;
   10808 
   10809         if (CUR == '=') eq = 1;
   10810 	else eq = 0;
   10811 	NEXT;
   10812 	if (!eq) NEXT;
   10813 	SKIP_BLANKS;
   10814         xmlXPathCompRelationalExpr(ctxt);
   10815 	CHECK_ERROR;
   10816 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10817 	SKIP_BLANKS;
   10818     }
   10819 }
   10820 
   10821 /**
   10822  * xmlXPathCompAndExpr:
   10823  * @ctxt:  the XPath Parser context
   10824  *
   10825  *  [22]   AndExpr ::=   EqualityExpr
   10826  *                 | AndExpr 'and' EqualityExpr
   10827  *
   10828  * Compile an AND expression.
   10829  *
   10830  */
   10831 static void
   10832 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10833     xmlXPathCompEqualityExpr(ctxt);
   10834     CHECK_ERROR;
   10835     SKIP_BLANKS;
   10836     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10837 	int op1 = ctxt->comp->last;
   10838         SKIP(3);
   10839 	SKIP_BLANKS;
   10840         xmlXPathCompEqualityExpr(ctxt);
   10841 	CHECK_ERROR;
   10842 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   10843 	SKIP_BLANKS;
   10844     }
   10845 }
   10846 
   10847 /**
   10848  * xmlXPathCompileExpr:
   10849  * @ctxt:  the XPath Parser context
   10850  *
   10851  *  [14]   Expr ::=   OrExpr
   10852  *  [21]   OrExpr ::=   AndExpr
   10853  *                 | OrExpr 'or' AndExpr
   10854  *
   10855  * Parse and compile an expression
   10856  */
   10857 static void
   10858 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   10859     xmlXPathCompAndExpr(ctxt);
   10860     CHECK_ERROR;
   10861     SKIP_BLANKS;
   10862     while ((CUR == 'o') && (NXT(1) == 'r')) {
   10863 	int op1 = ctxt->comp->last;
   10864         SKIP(2);
   10865 	SKIP_BLANKS;
   10866         xmlXPathCompAndExpr(ctxt);
   10867 	CHECK_ERROR;
   10868 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   10869 	op1 = ctxt->comp->nbStep;
   10870 	SKIP_BLANKS;
   10871     }
   10872     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   10873 	/* more ops could be optimized too */
   10874 	/*
   10875 	* This is the main place to eliminate sorting for
   10876 	* operations which don't require a sorted node-set.
   10877 	* E.g. count().
   10878 	*/
   10879 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   10880     }
   10881 }
   10882 
   10883 /**
   10884  * xmlXPathCompPredicate:
   10885  * @ctxt:  the XPath Parser context
   10886  * @filter:  act as a filter
   10887  *
   10888  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   10889  *  [9]   PredicateExpr ::=   Expr
   10890  *
   10891  * Compile a predicate expression
   10892  */
   10893 static void
   10894 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   10895     int op1 = ctxt->comp->last;
   10896 
   10897     SKIP_BLANKS;
   10898     if (CUR != '[') {
   10899 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10900     }
   10901     NEXT;
   10902     SKIP_BLANKS;
   10903 
   10904     ctxt->comp->last = -1;
   10905     /*
   10906     * This call to xmlXPathCompileExpr() will deactivate sorting
   10907     * of the predicate result.
   10908     * TODO: Sorting is still activated for filters, since I'm not
   10909     *  sure if needed. Normally sorting should not be needed, since
   10910     *  a filter can only diminish the number of items in a sequence,
   10911     *  but won't change its order; so if the initial sequence is sorted,
   10912     *  subsequent sorting is not needed.
   10913     */
   10914     if (! filter)
   10915 	xmlXPathCompileExpr(ctxt, 0);
   10916     else
   10917 	xmlXPathCompileExpr(ctxt, 1);
   10918     CHECK_ERROR;
   10919 
   10920     if (CUR != ']') {
   10921 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   10922     }
   10923 
   10924     if (filter)
   10925 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   10926     else
   10927 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   10928 
   10929     NEXT;
   10930     SKIP_BLANKS;
   10931 }
   10932 
   10933 /**
   10934  * xmlXPathCompNodeTest:
   10935  * @ctxt:  the XPath Parser context
   10936  * @test:  pointer to a xmlXPathTestVal
   10937  * @type:  pointer to a xmlXPathTypeVal
   10938  * @prefix:  placeholder for a possible name prefix
   10939  *
   10940  * [7] NodeTest ::=   NameTest
   10941  *		    | NodeType '(' ')'
   10942  *		    | 'processing-instruction' '(' Literal ')'
   10943  *
   10944  * [37] NameTest ::=  '*'
   10945  *		    | NCName ':' '*'
   10946  *		    | QName
   10947  * [38] NodeType ::= 'comment'
   10948  *		   | 'text'
   10949  *		   | 'processing-instruction'
   10950  *		   | 'node'
   10951  *
   10952  * Returns the name found and updates @test, @type and @prefix appropriately
   10953  */
   10954 static xmlChar *
   10955 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   10956 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   10957 		     xmlChar *name) {
   10958     int blanks;
   10959 
   10960     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   10961 	STRANGE;
   10962 	return(NULL);
   10963     }
   10964     *type = (xmlXPathTypeVal) 0;
   10965     *test = (xmlXPathTestVal) 0;
   10966     *prefix = NULL;
   10967     SKIP_BLANKS;
   10968 
   10969     if ((name == NULL) && (CUR == '*')) {
   10970 	/*
   10971 	 * All elements
   10972 	 */
   10973 	NEXT;
   10974 	*test = NODE_TEST_ALL;
   10975 	return(NULL);
   10976     }
   10977 
   10978     if (name == NULL)
   10979 	name = xmlXPathParseNCName(ctxt);
   10980     if (name == NULL) {
   10981 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   10982     }
   10983 
   10984     blanks = IS_BLANK_CH(CUR);
   10985     SKIP_BLANKS;
   10986     if (CUR == '(') {
   10987 	NEXT;
   10988 	/*
   10989 	 * NodeType or PI search
   10990 	 */
   10991 	if (xmlStrEqual(name, BAD_CAST "comment"))
   10992 	    *type = NODE_TYPE_COMMENT;
   10993 	else if (xmlStrEqual(name, BAD_CAST "node"))
   10994 	    *type = NODE_TYPE_NODE;
   10995 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10996 	    *type = NODE_TYPE_PI;
   10997 	else if (xmlStrEqual(name, BAD_CAST "text"))
   10998 	    *type = NODE_TYPE_TEXT;
   10999 	else {
   11000 	    if (name != NULL)
   11001 		xmlFree(name);
   11002 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11003 	}
   11004 
   11005 	*test = NODE_TEST_TYPE;
   11006 
   11007 	SKIP_BLANKS;
   11008 	if (*type == NODE_TYPE_PI) {
   11009 	    /*
   11010 	     * Specific case: search a PI by name.
   11011 	     */
   11012 	    if (name != NULL)
   11013 		xmlFree(name);
   11014 	    name = NULL;
   11015 	    if (CUR != ')') {
   11016 		name = xmlXPathParseLiteral(ctxt);
   11017 		CHECK_ERROR NULL;
   11018 		*test = NODE_TEST_PI;
   11019 		SKIP_BLANKS;
   11020 	    }
   11021 	}
   11022 	if (CUR != ')') {
   11023 	    if (name != NULL)
   11024 		xmlFree(name);
   11025 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11026 	}
   11027 	NEXT;
   11028 	return(name);
   11029     }
   11030     *test = NODE_TEST_NAME;
   11031     if ((!blanks) && (CUR == ':')) {
   11032 	NEXT;
   11033 
   11034 	/*
   11035 	 * Since currently the parser context don't have a
   11036 	 * namespace list associated:
   11037 	 * The namespace name for this prefix can be computed
   11038 	 * only at evaluation time. The compilation is done
   11039 	 * outside of any context.
   11040 	 */
   11041 #if 0
   11042 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11043 	if (name != NULL)
   11044 	    xmlFree(name);
   11045 	if (*prefix == NULL) {
   11046 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11047 	}
   11048 #else
   11049 	*prefix = name;
   11050 #endif
   11051 
   11052 	if (CUR == '*') {
   11053 	    /*
   11054 	     * All elements
   11055 	     */
   11056 	    NEXT;
   11057 	    *test = NODE_TEST_ALL;
   11058 	    return(NULL);
   11059 	}
   11060 
   11061 	name = xmlXPathParseNCName(ctxt);
   11062 	if (name == NULL) {
   11063 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11064 	}
   11065     }
   11066     return(name);
   11067 }
   11068 
   11069 /**
   11070  * xmlXPathIsAxisName:
   11071  * @name:  a preparsed name token
   11072  *
   11073  * [6] AxisName ::=   'ancestor'
   11074  *                  | 'ancestor-or-self'
   11075  *                  | 'attribute'
   11076  *                  | 'child'
   11077  *                  | 'descendant'
   11078  *                  | 'descendant-or-self'
   11079  *                  | 'following'
   11080  *                  | 'following-sibling'
   11081  *                  | 'namespace'
   11082  *                  | 'parent'
   11083  *                  | 'preceding'
   11084  *                  | 'preceding-sibling'
   11085  *                  | 'self'
   11086  *
   11087  * Returns the axis or 0
   11088  */
   11089 static xmlXPathAxisVal
   11090 xmlXPathIsAxisName(const xmlChar *name) {
   11091     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11092     switch (name[0]) {
   11093 	case 'a':
   11094 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11095 		ret = AXIS_ANCESTOR;
   11096 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11097 		ret = AXIS_ANCESTOR_OR_SELF;
   11098 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11099 		ret = AXIS_ATTRIBUTE;
   11100 	    break;
   11101 	case 'c':
   11102 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11103 		ret = AXIS_CHILD;
   11104 	    break;
   11105 	case 'd':
   11106 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11107 		ret = AXIS_DESCENDANT;
   11108 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11109 		ret = AXIS_DESCENDANT_OR_SELF;
   11110 	    break;
   11111 	case 'f':
   11112 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11113 		ret = AXIS_FOLLOWING;
   11114 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11115 		ret = AXIS_FOLLOWING_SIBLING;
   11116 	    break;
   11117 	case 'n':
   11118 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11119 		ret = AXIS_NAMESPACE;
   11120 	    break;
   11121 	case 'p':
   11122 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11123 		ret = AXIS_PARENT;
   11124 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11125 		ret = AXIS_PRECEDING;
   11126 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11127 		ret = AXIS_PRECEDING_SIBLING;
   11128 	    break;
   11129 	case 's':
   11130 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11131 		ret = AXIS_SELF;
   11132 	    break;
   11133     }
   11134     return(ret);
   11135 }
   11136 
   11137 /**
   11138  * xmlXPathCompStep:
   11139  * @ctxt:  the XPath Parser context
   11140  *
   11141  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11142  *                  | AbbreviatedStep
   11143  *
   11144  * [12] AbbreviatedStep ::=   '.' | '..'
   11145  *
   11146  * [5] AxisSpecifier ::= AxisName '::'
   11147  *                  | AbbreviatedAxisSpecifier
   11148  *
   11149  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11150  *
   11151  * Modified for XPtr range support as:
   11152  *
   11153  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11154  *                     | AbbreviatedStep
   11155  *                     | 'range-to' '(' Expr ')' Predicate*
   11156  *
   11157  * Compile one step in a Location Path
   11158  * A location step of . is short for self::node(). This is
   11159  * particularly useful in conjunction with //. For example, the
   11160  * location path .//para is short for
   11161  * self::node()/descendant-or-self::node()/child::para
   11162  * and so will select all para descendant elements of the context
   11163  * node.
   11164  * Similarly, a location step of .. is short for parent::node().
   11165  * For example, ../title is short for parent::node()/child::title
   11166  * and so will select the title children of the parent of the context
   11167  * node.
   11168  */
   11169 static void
   11170 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11171 #ifdef LIBXML_XPTR_ENABLED
   11172     int rangeto = 0;
   11173     int op2 = -1;
   11174 #endif
   11175 
   11176     SKIP_BLANKS;
   11177     if ((CUR == '.') && (NXT(1) == '.')) {
   11178 	SKIP(2);
   11179 	SKIP_BLANKS;
   11180 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11181 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11182     } else if (CUR == '.') {
   11183 	NEXT;
   11184 	SKIP_BLANKS;
   11185     } else {
   11186 	xmlChar *name = NULL;
   11187 	const xmlChar *prefix = NULL;
   11188 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11189 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11190 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11191 	int op1;
   11192 
   11193 	/*
   11194 	 * The modification needed for XPointer change to the production
   11195 	 */
   11196 #ifdef LIBXML_XPTR_ENABLED
   11197 	if (ctxt->xptr) {
   11198 	    name = xmlXPathParseNCName(ctxt);
   11199 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11200                 op2 = ctxt->comp->last;
   11201 		xmlFree(name);
   11202 		SKIP_BLANKS;
   11203 		if (CUR != '(') {
   11204 		    XP_ERROR(XPATH_EXPR_ERROR);
   11205 		}
   11206 		NEXT;
   11207 		SKIP_BLANKS;
   11208 
   11209 		xmlXPathCompileExpr(ctxt, 1);
   11210 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11211 		CHECK_ERROR;
   11212 
   11213 		SKIP_BLANKS;
   11214 		if (CUR != ')') {
   11215 		    XP_ERROR(XPATH_EXPR_ERROR);
   11216 		}
   11217 		NEXT;
   11218 		rangeto = 1;
   11219 		goto eval_predicates;
   11220 	    }
   11221 	}
   11222 #endif
   11223 	if (CUR == '*') {
   11224 	    axis = AXIS_CHILD;
   11225 	} else {
   11226 	    if (name == NULL)
   11227 		name = xmlXPathParseNCName(ctxt);
   11228 	    if (name != NULL) {
   11229 		axis = xmlXPathIsAxisName(name);
   11230 		if (axis != 0) {
   11231 		    SKIP_BLANKS;
   11232 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11233 			SKIP(2);
   11234 			xmlFree(name);
   11235 			name = NULL;
   11236 		    } else {
   11237 			/* an element name can conflict with an axis one :-\ */
   11238 			axis = AXIS_CHILD;
   11239 		    }
   11240 		} else {
   11241 		    axis = AXIS_CHILD;
   11242 		}
   11243 	    } else if (CUR == '@') {
   11244 		NEXT;
   11245 		axis = AXIS_ATTRIBUTE;
   11246 	    } else {
   11247 		axis = AXIS_CHILD;
   11248 	    }
   11249 	}
   11250 
   11251 	CHECK_ERROR;
   11252 
   11253 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11254 	if (test == 0)
   11255 	    return;
   11256 
   11257         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11258 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11259 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11260 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11261 	    }
   11262 	}
   11263 #ifdef DEBUG_STEP
   11264 	xmlGenericError(xmlGenericErrorContext,
   11265 		"Basis : computing new set\n");
   11266 #endif
   11267 
   11268 #ifdef DEBUG_STEP
   11269 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11270 	if (ctxt->value == NULL)
   11271 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11272 	else if (ctxt->value->nodesetval == NULL)
   11273 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11274 	else
   11275 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11276 #endif
   11277 
   11278 #ifdef LIBXML_XPTR_ENABLED
   11279 eval_predicates:
   11280 #endif
   11281 	op1 = ctxt->comp->last;
   11282 	ctxt->comp->last = -1;
   11283 
   11284 	SKIP_BLANKS;
   11285 	while (CUR == '[') {
   11286 	    xmlXPathCompPredicate(ctxt, 0);
   11287 	}
   11288 
   11289 #ifdef LIBXML_XPTR_ENABLED
   11290 	if (rangeto) {
   11291 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11292 	} else
   11293 #endif
   11294 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11295 			   test, type, (void *)prefix, (void *)name);
   11296 
   11297     }
   11298 #ifdef DEBUG_STEP
   11299     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11300     if (ctxt->value == NULL)
   11301 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11302     else if (ctxt->value->nodesetval == NULL)
   11303 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11304     else
   11305 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11306 		ctxt->value->nodesetval);
   11307 #endif
   11308 }
   11309 
   11310 /**
   11311  * xmlXPathCompRelativeLocationPath:
   11312  * @ctxt:  the XPath Parser context
   11313  *
   11314  *  [3]   RelativeLocationPath ::=   Step
   11315  *                     | RelativeLocationPath '/' Step
   11316  *                     | AbbreviatedRelativeLocationPath
   11317  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11318  *
   11319  * Compile a relative location path.
   11320  */
   11321 static void
   11322 xmlXPathCompRelativeLocationPath
   11323 (xmlXPathParserContextPtr ctxt) {
   11324     SKIP_BLANKS;
   11325     if ((CUR == '/') && (NXT(1) == '/')) {
   11326 	SKIP(2);
   11327 	SKIP_BLANKS;
   11328 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11329 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11330     } else if (CUR == '/') {
   11331 	    NEXT;
   11332 	SKIP_BLANKS;
   11333     }
   11334     xmlXPathCompStep(ctxt);
   11335     SKIP_BLANKS;
   11336     while (CUR == '/') {
   11337 	if ((CUR == '/') && (NXT(1) == '/')) {
   11338 	    SKIP(2);
   11339 	    SKIP_BLANKS;
   11340 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11341 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11342 	    xmlXPathCompStep(ctxt);
   11343 	} else if (CUR == '/') {
   11344 	    NEXT;
   11345 	    SKIP_BLANKS;
   11346 	    xmlXPathCompStep(ctxt);
   11347 	}
   11348 	SKIP_BLANKS;
   11349     }
   11350 }
   11351 
   11352 /**
   11353  * xmlXPathCompLocationPath:
   11354  * @ctxt:  the XPath Parser context
   11355  *
   11356  *  [1]   LocationPath ::=   RelativeLocationPath
   11357  *                     | AbsoluteLocationPath
   11358  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11359  *                     | AbbreviatedAbsoluteLocationPath
   11360  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11361  *                           '//' RelativeLocationPath
   11362  *
   11363  * Compile a location path
   11364  *
   11365  * // is short for /descendant-or-self::node()/. For example,
   11366  * //para is short for /descendant-or-self::node()/child::para and
   11367  * so will select any para element in the document (even a para element
   11368  * that is a document element will be selected by //para since the
   11369  * document element node is a child of the root node); div//para is
   11370  * short for div/descendant-or-self::node()/child::para and so will
   11371  * select all para descendants of div children.
   11372  */
   11373 static void
   11374 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11375     SKIP_BLANKS;
   11376     if (CUR != '/') {
   11377         xmlXPathCompRelativeLocationPath(ctxt);
   11378     } else {
   11379 	while (CUR == '/') {
   11380 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11381 		SKIP(2);
   11382 		SKIP_BLANKS;
   11383 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11384 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11385 		xmlXPathCompRelativeLocationPath(ctxt);
   11386 	    } else if (CUR == '/') {
   11387 		NEXT;
   11388 		SKIP_BLANKS;
   11389 		if ((CUR != 0 ) &&
   11390 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11391 		     (CUR == '@') || (CUR == '*')))
   11392 		    xmlXPathCompRelativeLocationPath(ctxt);
   11393 	    }
   11394 	}
   11395     }
   11396 }
   11397 
   11398 /************************************************************************
   11399  *									*
   11400  *		XPath precompiled expression evaluation			*
   11401  *									*
   11402  ************************************************************************/
   11403 
   11404 static int
   11405 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11406 
   11407 #ifdef DEBUG_STEP
   11408 static void
   11409 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11410 			  int nbNodes)
   11411 {
   11412     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11413     switch (op->value) {
   11414         case AXIS_ANCESTOR:
   11415             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11416             break;
   11417         case AXIS_ANCESTOR_OR_SELF:
   11418             xmlGenericError(xmlGenericErrorContext,
   11419                             "axis 'ancestors-or-self' ");
   11420             break;
   11421         case AXIS_ATTRIBUTE:
   11422             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11423             break;
   11424         case AXIS_CHILD:
   11425             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11426             break;
   11427         case AXIS_DESCENDANT:
   11428             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11429             break;
   11430         case AXIS_DESCENDANT_OR_SELF:
   11431             xmlGenericError(xmlGenericErrorContext,
   11432                             "axis 'descendant-or-self' ");
   11433             break;
   11434         case AXIS_FOLLOWING:
   11435             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11436             break;
   11437         case AXIS_FOLLOWING_SIBLING:
   11438             xmlGenericError(xmlGenericErrorContext,
   11439                             "axis 'following-siblings' ");
   11440             break;
   11441         case AXIS_NAMESPACE:
   11442             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11443             break;
   11444         case AXIS_PARENT:
   11445             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11446             break;
   11447         case AXIS_PRECEDING:
   11448             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11449             break;
   11450         case AXIS_PRECEDING_SIBLING:
   11451             xmlGenericError(xmlGenericErrorContext,
   11452                             "axis 'preceding-sibling' ");
   11453             break;
   11454         case AXIS_SELF:
   11455             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11456             break;
   11457     }
   11458     xmlGenericError(xmlGenericErrorContext,
   11459 	" context contains %d nodes\n", nbNodes);
   11460     switch (op->value2) {
   11461         case NODE_TEST_NONE:
   11462             xmlGenericError(xmlGenericErrorContext,
   11463                             "           searching for none !!!\n");
   11464             break;
   11465         case NODE_TEST_TYPE:
   11466             xmlGenericError(xmlGenericErrorContext,
   11467                             "           searching for type %d\n", op->value3);
   11468             break;
   11469         case NODE_TEST_PI:
   11470             xmlGenericError(xmlGenericErrorContext,
   11471                             "           searching for PI !!!\n");
   11472             break;
   11473         case NODE_TEST_ALL:
   11474             xmlGenericError(xmlGenericErrorContext,
   11475                             "           searching for *\n");
   11476             break;
   11477         case NODE_TEST_NS:
   11478             xmlGenericError(xmlGenericErrorContext,
   11479                             "           searching for namespace %s\n",
   11480                             op->value5);
   11481             break;
   11482         case NODE_TEST_NAME:
   11483             xmlGenericError(xmlGenericErrorContext,
   11484                             "           searching for name %s\n", op->value5);
   11485             if (op->value4)
   11486                 xmlGenericError(xmlGenericErrorContext,
   11487                                 "           with namespace %s\n", op->value4);
   11488             break;
   11489     }
   11490     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11491 }
   11492 #endif /* DEBUG_STEP */
   11493 
   11494 static int
   11495 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11496 			    xmlXPathStepOpPtr op,
   11497 			    xmlNodeSetPtr set,
   11498 			    int contextSize,
   11499 			    int hasNsNodes)
   11500 {
   11501     if (op->ch1 != -1) {
   11502 	xmlXPathCompExprPtr comp = ctxt->comp;
   11503 	/*
   11504 	* Process inner predicates first.
   11505 	*/
   11506 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11507 	    /*
   11508 	    * TODO: raise an internal error.
   11509 	    */
   11510 	}
   11511 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11512 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11513 	CHECK_ERROR0;
   11514 	if (contextSize <= 0)
   11515 	    return(0);
   11516     }
   11517     if (op->ch2 != -1) {
   11518 	xmlXPathContextPtr xpctxt = ctxt->context;
   11519 	xmlNodePtr contextNode, oldContextNode;
   11520 	xmlDocPtr oldContextDoc;
   11521 	int i, res, contextPos = 0, newContextSize;
   11522 	xmlXPathStepOpPtr exprOp;
   11523 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11524 
   11525 #ifdef LIBXML_XPTR_ENABLED
   11526 	/*
   11527 	* URGENT TODO: Check the following:
   11528 	*  We don't expect location sets if evaluating prediates, right?
   11529 	*  Only filters should expect location sets, right?
   11530 	*/
   11531 #endif
   11532 	/*
   11533 	* SPEC XPath 1.0:
   11534 	*  "For each node in the node-set to be filtered, the
   11535 	*  PredicateExpr is evaluated with that node as the
   11536 	*  context node, with the number of nodes in the
   11537 	*  node-set as the context size, and with the proximity
   11538 	*  position of the node in the node-set with respect to
   11539 	*  the axis as the context position;"
   11540 	* @oldset is the node-set" to be filtered.
   11541 	*
   11542 	* SPEC XPath 1.0:
   11543 	*  "only predicates change the context position and
   11544 	*  context size (see [2.4 Predicates])."
   11545 	* Example:
   11546 	*   node-set  context pos
   11547 	*    nA         1
   11548 	*    nB         2
   11549 	*    nC         3
   11550 	*   After applying predicate [position() > 1] :
   11551 	*   node-set  context pos
   11552 	*    nB         1
   11553 	*    nC         2
   11554 	*/
   11555 	oldContextNode = xpctxt->node;
   11556 	oldContextDoc = xpctxt->doc;
   11557 	/*
   11558 	* Get the expression of this predicate.
   11559 	*/
   11560 	exprOp = &ctxt->comp->steps[op->ch2];
   11561 	newContextSize = 0;
   11562 	for (i = 0; i < set->nodeNr; i++) {
   11563 	    if (set->nodeTab[i] == NULL)
   11564 		continue;
   11565 
   11566 	    contextNode = set->nodeTab[i];
   11567 	    xpctxt->node = contextNode;
   11568 	    xpctxt->contextSize = contextSize;
   11569 	    xpctxt->proximityPosition = ++contextPos;
   11570 
   11571 	    /*
   11572 	    * Also set the xpath document in case things like
   11573 	    * key() are evaluated in the predicate.
   11574 	    */
   11575 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11576 		(contextNode->doc != NULL))
   11577 		xpctxt->doc = contextNode->doc;
   11578 	    /*
   11579 	    * Evaluate the predicate expression with 1 context node
   11580 	    * at a time; this node is packaged into a node set; this
   11581 	    * node set is handed over to the evaluation mechanism.
   11582 	    */
   11583 	    if (contextObj == NULL)
   11584 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11585 	    else
   11586 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11587 		    contextNode);
   11588 
   11589 	    valuePush(ctxt, contextObj);
   11590 
   11591 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11592 
   11593 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11594 		xmlXPathNodeSetClear(set, hasNsNodes);
   11595 		newContextSize = 0;
   11596 		goto evaluation_exit;
   11597 	    }
   11598 
   11599 	    if (res != 0) {
   11600 		newContextSize++;
   11601 	    } else {
   11602 		/*
   11603 		* Remove the entry from the initial node set.
   11604 		*/
   11605 		set->nodeTab[i] = NULL;
   11606 		if (contextNode->type == XML_NAMESPACE_DECL)
   11607 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11608 	    }
   11609 	    if (ctxt->value == contextObj) {
   11610 		/*
   11611 		* Don't free the temporary XPath object holding the
   11612 		* context node, in order to avoid massive recreation
   11613 		* inside this loop.
   11614 		*/
   11615 		valuePop(ctxt);
   11616 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11617 	    } else {
   11618 		/*
   11619 		* TODO: The object was lost in the evaluation machinery.
   11620 		*  Can this happen? Maybe in internal-error cases.
   11621 		*/
   11622 		contextObj = NULL;
   11623 	    }
   11624 	}
   11625 
   11626 	if (contextObj != NULL) {
   11627 	    if (ctxt->value == contextObj)
   11628 		valuePop(ctxt);
   11629 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11630 	}
   11631 evaluation_exit:
   11632 	if (exprRes != NULL)
   11633 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11634 	/*
   11635 	* Reset/invalidate the context.
   11636 	*/
   11637 	xpctxt->node = oldContextNode;
   11638 	xpctxt->doc = oldContextDoc;
   11639 	xpctxt->contextSize = -1;
   11640 	xpctxt->proximityPosition = -1;
   11641 	return(newContextSize);
   11642     }
   11643     return(contextSize);
   11644 }
   11645 
   11646 static int
   11647 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11648 				      xmlXPathStepOpPtr op,
   11649 				      xmlNodeSetPtr set,
   11650 				      int contextSize,
   11651 				      int minPos,
   11652 				      int maxPos,
   11653 				      int hasNsNodes)
   11654 {
   11655     if (op->ch1 != -1) {
   11656 	xmlXPathCompExprPtr comp = ctxt->comp;
   11657 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11658 	    /*
   11659 	    * TODO: raise an internal error.
   11660 	    */
   11661 	}
   11662 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11663 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11664 	CHECK_ERROR0;
   11665 	if (contextSize <= 0)
   11666 	    return(0);
   11667     }
   11668     /*
   11669     * Check if the node set contains a sufficient number of nodes for
   11670     * the requested range.
   11671     */
   11672     if (contextSize < minPos) {
   11673 	xmlXPathNodeSetClear(set, hasNsNodes);
   11674 	return(0);
   11675     }
   11676     if (op->ch2 == -1) {
   11677 	/*
   11678 	* TODO: Can this ever happen?
   11679 	*/
   11680 	return (contextSize);
   11681     } else {
   11682 	xmlDocPtr oldContextDoc;
   11683 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11684 	xmlXPathStepOpPtr exprOp;
   11685 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11686 	xmlNodePtr oldContextNode, contextNode = NULL;
   11687 	xmlXPathContextPtr xpctxt = ctxt->context;
   11688 
   11689 #ifdef LIBXML_XPTR_ENABLED
   11690 	    /*
   11691 	    * URGENT TODO: Check the following:
   11692 	    *  We don't expect location sets if evaluating prediates, right?
   11693 	    *  Only filters should expect location sets, right?
   11694 	*/
   11695 #endif /* LIBXML_XPTR_ENABLED */
   11696 
   11697 	/*
   11698 	* Save old context.
   11699 	*/
   11700 	oldContextNode = xpctxt->node;
   11701 	oldContextDoc = xpctxt->doc;
   11702 	/*
   11703 	* Get the expression of this predicate.
   11704 	*/
   11705 	exprOp = &ctxt->comp->steps[op->ch2];
   11706 	for (i = 0; i < set->nodeNr; i++) {
   11707 	    if (set->nodeTab[i] == NULL)
   11708 		continue;
   11709 
   11710 	    contextNode = set->nodeTab[i];
   11711 	    xpctxt->node = contextNode;
   11712 	    xpctxt->contextSize = contextSize;
   11713 	    xpctxt->proximityPosition = ++contextPos;
   11714 
   11715 	    /*
   11716 	    * Initialize the new set.
   11717 	    * Also set the xpath document in case things like
   11718 	    * key() evaluation are attempted on the predicate
   11719 	    */
   11720 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11721 		(contextNode->doc != NULL))
   11722 		xpctxt->doc = contextNode->doc;
   11723 	    /*
   11724 	    * Evaluate the predicate expression with 1 context node
   11725 	    * at a time; this node is packaged into a node set; this
   11726 	    * node set is handed over to the evaluation mechanism.
   11727 	    */
   11728 	    if (contextObj == NULL)
   11729 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11730 	    else
   11731 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11732 		    contextNode);
   11733 
   11734 	    valuePush(ctxt, contextObj);
   11735 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11736 
   11737 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11738 	        xmlXPathObjectPtr tmp;
   11739 		/* pop the result */
   11740 		tmp = valuePop(ctxt);
   11741 		xmlXPathReleaseObject(xpctxt, tmp);
   11742 		/* then pop off contextObj, which will be freed later */
   11743 		valuePop(ctxt);
   11744 		goto evaluation_error;
   11745 	    }
   11746 
   11747 	    if (res)
   11748 		pos++;
   11749 
   11750 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11751 		/*
   11752 		* Fits in the requested range.
   11753 		*/
   11754 		newContextSize++;
   11755 		if (minPos == maxPos) {
   11756 		    /*
   11757 		    * Only 1 node was requested.
   11758 		    */
   11759 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11760 			/*
   11761 			* As always: take care of those nasty
   11762 			* namespace nodes.
   11763 			*/
   11764 			set->nodeTab[i] = NULL;
   11765 		    }
   11766 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11767 		    set->nodeNr = 1;
   11768 		    set->nodeTab[0] = contextNode;
   11769 		    goto evaluation_exit;
   11770 		}
   11771 		if (pos == maxPos) {
   11772 		    /*
   11773 		    * We are done.
   11774 		    */
   11775 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11776 		    goto evaluation_exit;
   11777 		}
   11778 	    } else {
   11779 		/*
   11780 		* Remove the entry from the initial node set.
   11781 		*/
   11782 		set->nodeTab[i] = NULL;
   11783 		if (contextNode->type == XML_NAMESPACE_DECL)
   11784 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11785 	    }
   11786 	    if (exprRes != NULL) {
   11787 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11788 		exprRes = NULL;
   11789 	    }
   11790 	    if (ctxt->value == contextObj) {
   11791 		/*
   11792 		* Don't free the temporary XPath object holding the
   11793 		* context node, in order to avoid massive recreation
   11794 		* inside this loop.
   11795 		*/
   11796 		valuePop(ctxt);
   11797 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11798 	    } else {
   11799 		/*
   11800 		* The object was lost in the evaluation machinery.
   11801 		* Can this happen? Maybe in case of internal-errors.
   11802 		*/
   11803 		contextObj = NULL;
   11804 	    }
   11805 	}
   11806 	goto evaluation_exit;
   11807 
   11808 evaluation_error:
   11809 	xmlXPathNodeSetClear(set, hasNsNodes);
   11810 	newContextSize = 0;
   11811 
   11812 evaluation_exit:
   11813 	if (contextObj != NULL) {
   11814 	    if (ctxt->value == contextObj)
   11815 		valuePop(ctxt);
   11816 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11817 	}
   11818 	if (exprRes != NULL)
   11819 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11820 	/*
   11821 	* Reset/invalidate the context.
   11822 	*/
   11823 	xpctxt->node = oldContextNode;
   11824 	xpctxt->doc = oldContextDoc;
   11825 	xpctxt->contextSize = -1;
   11826 	xpctxt->proximityPosition = -1;
   11827 	return(newContextSize);
   11828     }
   11829     return(contextSize);
   11830 }
   11831 
   11832 static int
   11833 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11834 			    xmlXPathStepOpPtr op,
   11835 			    int *maxPos)
   11836 {
   11837 
   11838     xmlXPathStepOpPtr exprOp;
   11839 
   11840     /*
   11841     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   11842     */
   11843 
   11844     /*
   11845     * If not -1, then ch1 will point to:
   11846     * 1) For predicates (XPATH_OP_PREDICATE):
   11847     *    - an inner predicate operator
   11848     * 2) For filters (XPATH_OP_FILTER):
   11849     *    - an inner filter operater OR
   11850     *    - an expression selecting the node set.
   11851     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   11852     */
   11853     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   11854 	return(0);
   11855 
   11856     if (op->ch2 != -1) {
   11857 	exprOp = &ctxt->comp->steps[op->ch2];
   11858     } else
   11859 	return(0);
   11860 
   11861     if ((exprOp != NULL) &&
   11862 	(exprOp->op == XPATH_OP_VALUE) &&
   11863 	(exprOp->value4 != NULL) &&
   11864 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   11865     {
   11866 	/*
   11867 	* We have a "[n]" predicate here.
   11868 	* TODO: Unfortunately this simplistic test here is not
   11869 	* able to detect a position() predicate in compound
   11870 	* expressions like "[@attr = 'a" and position() = 1],
   11871 	* and even not the usage of position() in
   11872 	* "[position() = 1]"; thus - obviously - a position-range,
   11873 	* like it "[position() < 5]", is also not detected.
   11874 	* Maybe we could rewrite the AST to ease the optimization.
   11875 	*/
   11876 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   11877 
   11878 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   11879 	    (float) *maxPos)
   11880 	{
   11881 	    return(1);
   11882 	}
   11883     }
   11884     return(0);
   11885 }
   11886 
   11887 static int
   11888 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   11889                            xmlXPathStepOpPtr op,
   11890 			   xmlNodePtr * first, xmlNodePtr * last,
   11891 			   int toBool)
   11892 {
   11893 
   11894 #define XP_TEST_HIT \
   11895     if (hasAxisRange != 0) { \
   11896 	if (++pos == maxPos) { \
   11897 	    addNode(seq, cur); \
   11898 	goto axis_range_end; } \
   11899     } else { \
   11900 	addNode(seq, cur); \
   11901 	if (breakOnFirstHit) goto first_hit; }
   11902 
   11903 #define XP_TEST_HIT_NS \
   11904     if (hasAxisRange != 0) { \
   11905 	if (++pos == maxPos) { \
   11906 	    hasNsNodes = 1; \
   11907 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
   11908 	goto axis_range_end; } \
   11909     } else { \
   11910 	hasNsNodes = 1; \
   11911 	xmlXPathNodeSetAddNs(seq, \
   11912 	xpctxt->node, (xmlNsPtr) cur); \
   11913 	if (breakOnFirstHit) goto first_hit; }
   11914 
   11915     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   11916     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   11917     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   11918     const xmlChar *prefix = op->value4;
   11919     const xmlChar *name = op->value5;
   11920     const xmlChar *URI = NULL;
   11921 
   11922 #ifdef DEBUG_STEP
   11923     int nbMatches = 0, prevMatches = 0;
   11924 #endif
   11925     int total = 0, hasNsNodes = 0;
   11926     /* The popped object holding the context nodes */
   11927     xmlXPathObjectPtr obj;
   11928     /* The set of context nodes for the node tests */
   11929     xmlNodeSetPtr contextSeq;
   11930     int contextIdx;
   11931     xmlNodePtr contextNode;
   11932     /* The context node for a compound traversal */
   11933     xmlNodePtr outerContextNode;
   11934     /* The final resulting node set wrt to all context nodes */
   11935     xmlNodeSetPtr outSeq;
   11936     /*
   11937     * The temporary resulting node set wrt 1 context node.
   11938     * Used to feed predicate evaluation.
   11939     */
   11940     xmlNodeSetPtr seq;
   11941     xmlNodePtr cur;
   11942     /* First predicate operator */
   11943     xmlXPathStepOpPtr predOp;
   11944     int maxPos; /* The requested position() (when a "[n]" predicate) */
   11945     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   11946     int breakOnFirstHit;
   11947 
   11948     xmlXPathTraversalFunction next = NULL;
   11949     /* compound axis traversal */
   11950     xmlXPathTraversalFunctionExt outerNext = NULL;
   11951     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   11952     xmlXPathNodeSetMergeFunction mergeAndClear;
   11953     xmlNodePtr oldContextNode;
   11954     xmlXPathContextPtr xpctxt = ctxt->context;
   11955 
   11956 
   11957     CHECK_TYPE0(XPATH_NODESET);
   11958     obj = valuePop(ctxt);
   11959     /*
   11960     * Setup namespaces.
   11961     */
   11962     if (prefix != NULL) {
   11963         URI = xmlXPathNsLookup(xpctxt, prefix);
   11964         if (URI == NULL) {
   11965 	    xmlXPathReleaseObject(xpctxt, obj);
   11966             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11967 	}
   11968     }
   11969     /*
   11970     * Setup axis.
   11971     *
   11972     * MAYBE FUTURE TODO: merging optimizations:
   11973     * - If the nodes to be traversed wrt to the initial nodes and
   11974     *   the current axis cannot overlap, then we could avoid searching
   11975     *   for duplicates during the merge.
   11976     *   But the question is how/when to evaluate if they cannot overlap.
   11977     *   Example: if we know that for two initial nodes, the one is
   11978     *   not in the ancestor-or-self axis of the other, then we could safely
   11979     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   11980     *   the descendant-or-self axis.
   11981     */
   11982     addNode = xmlXPathNodeSetAdd;
   11983     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   11984     switch (axis) {
   11985         case AXIS_ANCESTOR:
   11986             first = NULL;
   11987             next = xmlXPathNextAncestor;
   11988             break;
   11989         case AXIS_ANCESTOR_OR_SELF:
   11990             first = NULL;
   11991             next = xmlXPathNextAncestorOrSelf;
   11992             break;
   11993         case AXIS_ATTRIBUTE:
   11994             first = NULL;
   11995 	    last = NULL;
   11996             next = xmlXPathNextAttribute;
   11997 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   11998             break;
   11999         case AXIS_CHILD:
   12000 	    last = NULL;
   12001 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
   12002 		/*
   12003 		* This iterator will give us only nodes which can
   12004 		* hold element nodes.
   12005 		*/
   12006 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
   12007 	    }
   12008 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12009 		(type == NODE_TYPE_NODE))
   12010 	    {
   12011 		/*
   12012 		* Optimization if an element node type is 'element'.
   12013 		*/
   12014 		next = xmlXPathNextChildElement;
   12015 	    } else
   12016 		next = xmlXPathNextChild;
   12017 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12018             break;
   12019         case AXIS_DESCENDANT:
   12020 	    last = NULL;
   12021             next = xmlXPathNextDescendant;
   12022             break;
   12023         case AXIS_DESCENDANT_OR_SELF:
   12024 	    last = NULL;
   12025             next = xmlXPathNextDescendantOrSelf;
   12026             break;
   12027         case AXIS_FOLLOWING:
   12028 	    last = NULL;
   12029             next = xmlXPathNextFollowing;
   12030             break;
   12031         case AXIS_FOLLOWING_SIBLING:
   12032 	    last = NULL;
   12033             next = xmlXPathNextFollowingSibling;
   12034             break;
   12035         case AXIS_NAMESPACE:
   12036             first = NULL;
   12037 	    last = NULL;
   12038             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12039 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12040             break;
   12041         case AXIS_PARENT:
   12042             first = NULL;
   12043             next = xmlXPathNextParent;
   12044             break;
   12045         case AXIS_PRECEDING:
   12046             first = NULL;
   12047             next = xmlXPathNextPrecedingInternal;
   12048             break;
   12049         case AXIS_PRECEDING_SIBLING:
   12050             first = NULL;
   12051             next = xmlXPathNextPrecedingSibling;
   12052             break;
   12053         case AXIS_SELF:
   12054             first = NULL;
   12055 	    last = NULL;
   12056             next = xmlXPathNextSelf;
   12057 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12058             break;
   12059     }
   12060 
   12061 #ifdef DEBUG_STEP
   12062     xmlXPathDebugDumpStepAxis(op,
   12063 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12064 #endif
   12065 
   12066     if (next == NULL) {
   12067 	xmlXPathReleaseObject(xpctxt, obj);
   12068         return(0);
   12069     }
   12070     contextSeq = obj->nodesetval;
   12071     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12072 	xmlXPathReleaseObject(xpctxt, obj);
   12073         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12074         return(0);
   12075     }
   12076     /*
   12077     * Predicate optimization ---------------------------------------------
   12078     * If this step has a last predicate, which contains a position(),
   12079     * then we'll optimize (although not exactly "position()", but only
   12080     * the  short-hand form, i.e., "[n]".
   12081     *
   12082     * Example - expression "/foo[parent::bar][1]":
   12083     *
   12084     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12085     *   ROOT                               -- op->ch1
   12086     *   PREDICATE                          -- op->ch2 (predOp)
   12087     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12088     *       SORT
   12089     *         COLLECT  'parent' 'name' 'node' bar
   12090     *           NODE
   12091     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12092     *
   12093     */
   12094     maxPos = 0;
   12095     predOp = NULL;
   12096     hasPredicateRange = 0;
   12097     hasAxisRange = 0;
   12098     if (op->ch2 != -1) {
   12099 	/*
   12100 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12101 	*/
   12102 	predOp = &ctxt->comp->steps[op->ch2];
   12103 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12104 	    if (predOp->ch1 != -1) {
   12105 		/*
   12106 		* Use the next inner predicate operator.
   12107 		*/
   12108 		predOp = &ctxt->comp->steps[predOp->ch1];
   12109 		hasPredicateRange = 1;
   12110 	    } else {
   12111 		/*
   12112 		* There's no other predicate than the [n] predicate.
   12113 		*/
   12114 		predOp = NULL;
   12115 		hasAxisRange = 1;
   12116 	    }
   12117 	}
   12118     }
   12119     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12120     /*
   12121     * Axis traversal -----------------------------------------------------
   12122     */
   12123     /*
   12124      * 2.3 Node Tests
   12125      *  - For the attribute axis, the principal node type is attribute.
   12126      *  - For the namespace axis, the principal node type is namespace.
   12127      *  - For other axes, the principal node type is element.
   12128      *
   12129      * A node test * is true for any node of the
   12130      * principal node type. For example, child::* will
   12131      * select all element children of the context node
   12132      */
   12133     oldContextNode = xpctxt->node;
   12134     addNode = xmlXPathNodeSetAddUnique;
   12135     outSeq = NULL;
   12136     seq = NULL;
   12137     outerContextNode = NULL;
   12138     contextNode = NULL;
   12139     contextIdx = 0;
   12140 
   12141 
   12142     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
   12143 	if (outerNext != NULL) {
   12144 	    /*
   12145 	    * This is a compound traversal.
   12146 	    */
   12147 	    if (contextNode == NULL) {
   12148 		/*
   12149 		* Set the context for the outer traversal.
   12150 		*/
   12151 		outerContextNode = contextSeq->nodeTab[contextIdx++];
   12152 		contextNode = outerNext(NULL, outerContextNode);
   12153 	    } else
   12154 		contextNode = outerNext(contextNode, outerContextNode);
   12155 	    if (contextNode == NULL)
   12156 		continue;
   12157 	    /*
   12158 	    * Set the context for the main traversal.
   12159 	    */
   12160 	    xpctxt->node = contextNode;
   12161 	} else
   12162 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12163 
   12164 	if (seq == NULL) {
   12165 	    seq = xmlXPathNodeSetCreate(NULL);
   12166 	    if (seq == NULL) {
   12167 		total = 0;
   12168 		goto error;
   12169 	    }
   12170 	}
   12171 	/*
   12172 	* Traverse the axis and test the nodes.
   12173 	*/
   12174 	pos = 0;
   12175 	cur = NULL;
   12176 	hasNsNodes = 0;
   12177         do {
   12178             cur = next(ctxt, cur);
   12179             if (cur == NULL)
   12180                 break;
   12181 
   12182 	    /*
   12183 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12184 	    */
   12185             if ((first != NULL) && (*first != NULL)) {
   12186 		if (*first == cur)
   12187 		    break;
   12188 		if (((total % 256) == 0) &&
   12189 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12190 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12191 #else
   12192 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12193 #endif
   12194 		{
   12195 		    break;
   12196 		}
   12197 	    }
   12198 	    if ((last != NULL) && (*last != NULL)) {
   12199 		if (*last == cur)
   12200 		    break;
   12201 		if (((total % 256) == 0) &&
   12202 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12203 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12204 #else
   12205 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12206 #endif
   12207 		{
   12208 		    break;
   12209 		}
   12210 	    }
   12211 
   12212             total++;
   12213 
   12214 #ifdef DEBUG_STEP
   12215             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12216 #endif
   12217 
   12218 	    switch (test) {
   12219                 case NODE_TEST_NONE:
   12220 		    total = 0;
   12221                     STRANGE
   12222 		    goto error;
   12223                 case NODE_TEST_TYPE:
   12224 		    /*
   12225 		    * TODO: Don't we need to use
   12226 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12227 		    *  Surprisingly, some c14n tests fail, if we do this.
   12228 		    */
   12229 		    if (type == NODE_TYPE_NODE) {
   12230 			switch (cur->type) {
   12231 			    case XML_DOCUMENT_NODE:
   12232 			    case XML_HTML_DOCUMENT_NODE:
   12233 #ifdef LIBXML_DOCB_ENABLED
   12234 			    case XML_DOCB_DOCUMENT_NODE:
   12235 #endif
   12236 			    case XML_ELEMENT_NODE:
   12237 			    case XML_ATTRIBUTE_NODE:
   12238 			    case XML_PI_NODE:
   12239 			    case XML_COMMENT_NODE:
   12240 			    case XML_CDATA_SECTION_NODE:
   12241 			    case XML_TEXT_NODE:
   12242 			    case XML_NAMESPACE_DECL:
   12243 				XP_TEST_HIT
   12244 				break;
   12245 			    default:
   12246 				break;
   12247 			}
   12248 		    } else if (cur->type == type) {
   12249 			if (type == XML_NAMESPACE_DECL)
   12250 			    XP_TEST_HIT_NS
   12251 			else
   12252 			    XP_TEST_HIT
   12253 		    } else if ((type == NODE_TYPE_TEXT) &&
   12254 			 (cur->type == XML_CDATA_SECTION_NODE))
   12255 		    {
   12256 			XP_TEST_HIT
   12257 		    }
   12258 		    break;
   12259                 case NODE_TEST_PI:
   12260                     if ((cur->type == XML_PI_NODE) &&
   12261                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12262 		    {
   12263 			XP_TEST_HIT
   12264                     }
   12265                     break;
   12266                 case NODE_TEST_ALL:
   12267                     if (axis == AXIS_ATTRIBUTE) {
   12268                         if (cur->type == XML_ATTRIBUTE_NODE)
   12269 			{
   12270 			    XP_TEST_HIT
   12271                         }
   12272                     } else if (axis == AXIS_NAMESPACE) {
   12273                         if (cur->type == XML_NAMESPACE_DECL)
   12274 			{
   12275 			    XP_TEST_HIT_NS
   12276                         }
   12277                     } else {
   12278                         if (cur->type == XML_ELEMENT_NODE) {
   12279                             if (prefix == NULL)
   12280 			    {
   12281 				XP_TEST_HIT
   12282 
   12283                             } else if ((cur->ns != NULL) &&
   12284 				(xmlStrEqual(URI, cur->ns->href)))
   12285 			    {
   12286 				XP_TEST_HIT
   12287                             }
   12288                         }
   12289                     }
   12290                     break;
   12291                 case NODE_TEST_NS:{
   12292                         TODO;
   12293                         break;
   12294                     }
   12295                 case NODE_TEST_NAME:
   12296                     if (axis == AXIS_ATTRIBUTE) {
   12297                         if (cur->type != XML_ATTRIBUTE_NODE)
   12298 			    break;
   12299 		    } else if (axis == AXIS_NAMESPACE) {
   12300                         if (cur->type != XML_NAMESPACE_DECL)
   12301 			    break;
   12302 		    } else {
   12303 		        if (cur->type != XML_ELEMENT_NODE)
   12304 			    break;
   12305 		    }
   12306                     switch (cur->type) {
   12307                         case XML_ELEMENT_NODE:
   12308                             if (xmlStrEqual(name, cur->name)) {
   12309                                 if (prefix == NULL) {
   12310                                     if (cur->ns == NULL)
   12311 				    {
   12312 					XP_TEST_HIT
   12313                                     }
   12314                                 } else {
   12315                                     if ((cur->ns != NULL) &&
   12316                                         (xmlStrEqual(URI, cur->ns->href)))
   12317 				    {
   12318 					XP_TEST_HIT
   12319                                     }
   12320                                 }
   12321                             }
   12322                             break;
   12323                         case XML_ATTRIBUTE_NODE:{
   12324                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12325 
   12326                                 if (xmlStrEqual(name, attr->name)) {
   12327                                     if (prefix == NULL) {
   12328                                         if ((attr->ns == NULL) ||
   12329                                             (attr->ns->prefix == NULL))
   12330 					{
   12331 					    XP_TEST_HIT
   12332                                         }
   12333                                     } else {
   12334                                         if ((attr->ns != NULL) &&
   12335                                             (xmlStrEqual(URI,
   12336 					      attr->ns->href)))
   12337 					{
   12338 					    XP_TEST_HIT
   12339                                         }
   12340                                     }
   12341                                 }
   12342                                 break;
   12343                             }
   12344                         case XML_NAMESPACE_DECL:
   12345                             if (cur->type == XML_NAMESPACE_DECL) {
   12346                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12347 
   12348                                 if ((ns->prefix != NULL) && (name != NULL)
   12349                                     && (xmlStrEqual(ns->prefix, name)))
   12350 				{
   12351 				    XP_TEST_HIT_NS
   12352                                 }
   12353                             }
   12354                             break;
   12355                         default:
   12356                             break;
   12357                     }
   12358                     break;
   12359 	    } /* switch(test) */
   12360         } while (cur != NULL);
   12361 
   12362 	goto apply_predicates;
   12363 
   12364 axis_range_end: /* ----------------------------------------------------- */
   12365 	/*
   12366 	* We have a "/foo[n]", and position() = n was reached.
   12367 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12368 	* a duplicate-aware merge is still needed.
   12369 	* Merge with the result.
   12370 	*/
   12371 	if (outSeq == NULL) {
   12372 	    outSeq = seq;
   12373 	    seq = NULL;
   12374 	} else
   12375 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12376 	/*
   12377 	* Break if only a true/false result was requested.
   12378 	*/
   12379 	if (toBool)
   12380 	    break;
   12381 	continue;
   12382 
   12383 first_hit: /* ---------------------------------------------------------- */
   12384 	/*
   12385 	* Break if only a true/false result was requested and
   12386 	* no predicates existed and a node test succeeded.
   12387 	*/
   12388 	if (outSeq == NULL) {
   12389 	    outSeq = seq;
   12390 	    seq = NULL;
   12391 	} else
   12392 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12393 	break;
   12394 
   12395 #ifdef DEBUG_STEP
   12396 	if (seq != NULL)
   12397 	    nbMatches += seq->nodeNr;
   12398 #endif
   12399 
   12400 apply_predicates: /* --------------------------------------------------- */
   12401         /*
   12402 	* Apply predicates.
   12403 	*/
   12404         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12405 	    /*
   12406 	    * E.g. when we have a "/foo[some expression][n]".
   12407 	    */
   12408 	    /*
   12409 	    * QUESTION TODO: The old predicate evaluation took into
   12410 	    *  account location-sets.
   12411 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12412 	    *  Do we expect such a set here?
   12413 	    *  All what I learned now from the evaluation semantics
   12414 	    *  does not indicate that a location-set will be processed
   12415 	    *  here, so this looks OK.
   12416 	    */
   12417 	    /*
   12418 	    * Iterate over all predicates, starting with the outermost
   12419 	    * predicate.
   12420 	    * TODO: Problem: we cannot execute the inner predicates first
   12421 	    *  since we cannot go back *up* the operator tree!
   12422 	    *  Options we have:
   12423 	    *  1) Use of recursive functions (like is it currently done
   12424 	    *     via xmlXPathCompOpEval())
   12425 	    *  2) Add a predicate evaluation information stack to the
   12426 	    *     context struct
   12427 	    *  3) Change the way the operators are linked; we need a
   12428 	    *     "parent" field on xmlXPathStepOp
   12429 	    *
   12430 	    * For the moment, I'll try to solve this with a recursive
   12431 	    * function: xmlXPathCompOpEvalPredicate().
   12432 	    */
   12433 	    size = seq->nodeNr;
   12434 	    if (hasPredicateRange != 0)
   12435 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12436 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12437 	    else
   12438 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12439 		    predOp, seq, size, hasNsNodes);
   12440 
   12441 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12442 		total = 0;
   12443 		goto error;
   12444 	    }
   12445 	    /*
   12446 	    * Add the filtered set of nodes to the result node set.
   12447 	    */
   12448 	    if (newSize == 0) {
   12449 		/*
   12450 		* The predicates filtered all nodes out.
   12451 		*/
   12452 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12453 	    } else if (seq->nodeNr > 0) {
   12454 		/*
   12455 		* Add to result set.
   12456 		*/
   12457 		if (outSeq == NULL) {
   12458 		    if (size != newSize) {
   12459 			/*
   12460 			* We need to merge and clear here, since
   12461 			* the sequence will contained NULLed entries.
   12462 			*/
   12463 			outSeq = mergeAndClear(NULL, seq, 1);
   12464 		    } else {
   12465 			outSeq = seq;
   12466 			seq = NULL;
   12467 		    }
   12468 		} else
   12469 		    outSeq = mergeAndClear(outSeq, seq,
   12470 			(size != newSize) ? 1: 0);
   12471 		/*
   12472 		* Break if only a true/false result was requested.
   12473 		*/
   12474 		if (toBool)
   12475 		    break;
   12476 	    }
   12477         } else if (seq->nodeNr > 0) {
   12478 	    /*
   12479 	    * Add to result set.
   12480 	    */
   12481 	    if (outSeq == NULL) {
   12482 		outSeq = seq;
   12483 		seq = NULL;
   12484 	    } else {
   12485 		outSeq = mergeAndClear(outSeq, seq, 0);
   12486 	    }
   12487 	}
   12488     }
   12489 
   12490 error:
   12491     if ((obj->boolval) && (obj->user != NULL)) {
   12492 	/*
   12493 	* QUESTION TODO: What does this do and why?
   12494 	* TODO: Do we have to do this also for the "error"
   12495 	* cleanup further down?
   12496 	*/
   12497 	ctxt->value->boolval = 1;
   12498 	ctxt->value->user = obj->user;
   12499 	obj->user = NULL;
   12500 	obj->boolval = 0;
   12501     }
   12502     xmlXPathReleaseObject(xpctxt, obj);
   12503 
   12504     /*
   12505     * Ensure we return at least an emtpy set.
   12506     */
   12507     if (outSeq == NULL) {
   12508 	if ((seq != NULL) && (seq->nodeNr == 0))
   12509 	    outSeq = seq;
   12510 	else
   12511 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12512         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12513     }
   12514     if ((seq != NULL) && (seq != outSeq)) {
   12515 	 xmlXPathFreeNodeSet(seq);
   12516     }
   12517     /*
   12518     * Hand over the result. Better to push the set also in
   12519     * case of errors.
   12520     */
   12521     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12522     /*
   12523     * Reset the context node.
   12524     */
   12525     xpctxt->node = oldContextNode;
   12526 
   12527 #ifdef DEBUG_STEP
   12528     xmlGenericError(xmlGenericErrorContext,
   12529 	"\nExamined %d nodes, found %d nodes at that step\n",
   12530 	total, nbMatches);
   12531 #endif
   12532 
   12533     return(total);
   12534 }
   12535 
   12536 static int
   12537 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12538 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12539 
   12540 /**
   12541  * xmlXPathCompOpEvalFirst:
   12542  * @ctxt:  the XPath parser context with the compiled expression
   12543  * @op:  an XPath compiled operation
   12544  * @first:  the first elem found so far
   12545  *
   12546  * Evaluate the Precompiled XPath operation searching only the first
   12547  * element in document order
   12548  *
   12549  * Returns the number of examined objects.
   12550  */
   12551 static int
   12552 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12553                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12554 {
   12555     int total = 0, cur;
   12556     xmlXPathCompExprPtr comp;
   12557     xmlXPathObjectPtr arg1, arg2;
   12558 
   12559     CHECK_ERROR0;
   12560     comp = ctxt->comp;
   12561     switch (op->op) {
   12562         case XPATH_OP_END:
   12563             return (0);
   12564         case XPATH_OP_UNION:
   12565             total =
   12566                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12567                                         first);
   12568 	    CHECK_ERROR0;
   12569             if ((ctxt->value != NULL)
   12570                 && (ctxt->value->type == XPATH_NODESET)
   12571                 && (ctxt->value->nodesetval != NULL)
   12572                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12573                 /*
   12574                  * limit tree traversing to first node in the result
   12575                  */
   12576 		/*
   12577 		* OPTIMIZE TODO: This implicitely sorts
   12578 		*  the result, even if not needed. E.g. if the argument
   12579 		*  of the count() function, no sorting is needed.
   12580 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12581 		*  aready sorted?
   12582 		*/
   12583 		if (ctxt->value->nodesetval->nodeNr > 1)
   12584 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12585                 *first = ctxt->value->nodesetval->nodeTab[0];
   12586             }
   12587             cur =
   12588                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12589                                         first);
   12590 	    CHECK_ERROR0;
   12591             CHECK_TYPE0(XPATH_NODESET);
   12592             arg2 = valuePop(ctxt);
   12593 
   12594             CHECK_TYPE0(XPATH_NODESET);
   12595             arg1 = valuePop(ctxt);
   12596 
   12597             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12598                                                     arg2->nodesetval);
   12599             valuePush(ctxt, arg1);
   12600 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12601             /* optimizer */
   12602 	    if (total > cur)
   12603 		xmlXPathCompSwap(op);
   12604             return (total + cur);
   12605         case XPATH_OP_ROOT:
   12606             xmlXPathRoot(ctxt);
   12607             return (0);
   12608         case XPATH_OP_NODE:
   12609             if (op->ch1 != -1)
   12610                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12611 	    CHECK_ERROR0;
   12612             if (op->ch2 != -1)
   12613                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12614 	    CHECK_ERROR0;
   12615 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12616 		ctxt->context->node));
   12617             return (total);
   12618         case XPATH_OP_RESET:
   12619             if (op->ch1 != -1)
   12620                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12621 	    CHECK_ERROR0;
   12622             if (op->ch2 != -1)
   12623                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12624 	    CHECK_ERROR0;
   12625             ctxt->context->node = NULL;
   12626             return (total);
   12627         case XPATH_OP_COLLECT:{
   12628                 if (op->ch1 == -1)
   12629                     return (total);
   12630 
   12631                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12632 		CHECK_ERROR0;
   12633 
   12634                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12635                 return (total);
   12636             }
   12637         case XPATH_OP_VALUE:
   12638             valuePush(ctxt,
   12639                       xmlXPathCacheObjectCopy(ctxt->context,
   12640 			(xmlXPathObjectPtr) op->value4));
   12641             return (0);
   12642         case XPATH_OP_SORT:
   12643             if (op->ch1 != -1)
   12644                 total +=
   12645                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12646                                             first);
   12647 	    CHECK_ERROR0;
   12648             if ((ctxt->value != NULL)
   12649                 && (ctxt->value->type == XPATH_NODESET)
   12650                 && (ctxt->value->nodesetval != NULL)
   12651 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12652                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12653             return (total);
   12654 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12655 	case XPATH_OP_FILTER:
   12656                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12657             return (total);
   12658 #endif
   12659         default:
   12660             return (xmlXPathCompOpEval(ctxt, op));
   12661     }
   12662 }
   12663 
   12664 /**
   12665  * xmlXPathCompOpEvalLast:
   12666  * @ctxt:  the XPath parser context with the compiled expression
   12667  * @op:  an XPath compiled operation
   12668  * @last:  the last elem found so far
   12669  *
   12670  * Evaluate the Precompiled XPath operation searching only the last
   12671  * element in document order
   12672  *
   12673  * Returns the number of nodes traversed
   12674  */
   12675 static int
   12676 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12677                        xmlNodePtr * last)
   12678 {
   12679     int total = 0, cur;
   12680     xmlXPathCompExprPtr comp;
   12681     xmlXPathObjectPtr arg1, arg2;
   12682     xmlNodePtr bak;
   12683     xmlDocPtr bakd;
   12684     int pp;
   12685     int cs;
   12686 
   12687     CHECK_ERROR0;
   12688     comp = ctxt->comp;
   12689     switch (op->op) {
   12690         case XPATH_OP_END:
   12691             return (0);
   12692         case XPATH_OP_UNION:
   12693 	    bakd = ctxt->context->doc;
   12694 	    bak = ctxt->context->node;
   12695 	    pp = ctxt->context->proximityPosition;
   12696 	    cs = ctxt->context->contextSize;
   12697             total =
   12698                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12699 	    CHECK_ERROR0;
   12700             if ((ctxt->value != NULL)
   12701                 && (ctxt->value->type == XPATH_NODESET)
   12702                 && (ctxt->value->nodesetval != NULL)
   12703                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12704                 /*
   12705                  * limit tree traversing to first node in the result
   12706                  */
   12707 		if (ctxt->value->nodesetval->nodeNr > 1)
   12708 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12709                 *last =
   12710                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12711                                                      nodesetval->nodeNr -
   12712                                                      1];
   12713             }
   12714 	    ctxt->context->doc = bakd;
   12715 	    ctxt->context->node = bak;
   12716 	    ctxt->context->proximityPosition = pp;
   12717 	    ctxt->context->contextSize = cs;
   12718             cur =
   12719                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12720 	    CHECK_ERROR0;
   12721             if ((ctxt->value != NULL)
   12722                 && (ctxt->value->type == XPATH_NODESET)
   12723                 && (ctxt->value->nodesetval != NULL)
   12724                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12725             }
   12726             CHECK_TYPE0(XPATH_NODESET);
   12727             arg2 = valuePop(ctxt);
   12728 
   12729             CHECK_TYPE0(XPATH_NODESET);
   12730             arg1 = valuePop(ctxt);
   12731 
   12732             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12733                                                     arg2->nodesetval);
   12734             valuePush(ctxt, arg1);
   12735 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12736             /* optimizer */
   12737 	    if (total > cur)
   12738 		xmlXPathCompSwap(op);
   12739             return (total + cur);
   12740         case XPATH_OP_ROOT:
   12741             xmlXPathRoot(ctxt);
   12742             return (0);
   12743         case XPATH_OP_NODE:
   12744             if (op->ch1 != -1)
   12745                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12746 	    CHECK_ERROR0;
   12747             if (op->ch2 != -1)
   12748                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12749 	    CHECK_ERROR0;
   12750 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12751 		ctxt->context->node));
   12752             return (total);
   12753         case XPATH_OP_RESET:
   12754             if (op->ch1 != -1)
   12755                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12756 	    CHECK_ERROR0;
   12757             if (op->ch2 != -1)
   12758                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12759 	    CHECK_ERROR0;
   12760             ctxt->context->node = NULL;
   12761             return (total);
   12762         case XPATH_OP_COLLECT:{
   12763                 if (op->ch1 == -1)
   12764                     return (0);
   12765 
   12766                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12767 		CHECK_ERROR0;
   12768 
   12769                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12770                 return (total);
   12771             }
   12772         case XPATH_OP_VALUE:
   12773             valuePush(ctxt,
   12774                       xmlXPathCacheObjectCopy(ctxt->context,
   12775 			(xmlXPathObjectPtr) op->value4));
   12776             return (0);
   12777         case XPATH_OP_SORT:
   12778             if (op->ch1 != -1)
   12779                 total +=
   12780                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12781                                            last);
   12782 	    CHECK_ERROR0;
   12783             if ((ctxt->value != NULL)
   12784                 && (ctxt->value->type == XPATH_NODESET)
   12785                 && (ctxt->value->nodesetval != NULL)
   12786 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12787                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12788             return (total);
   12789         default:
   12790             return (xmlXPathCompOpEval(ctxt, op));
   12791     }
   12792 }
   12793 
   12794 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12795 static int
   12796 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12797 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12798 {
   12799     int total = 0;
   12800     xmlXPathCompExprPtr comp;
   12801     xmlXPathObjectPtr res;
   12802     xmlXPathObjectPtr obj;
   12803     xmlNodeSetPtr oldset;
   12804     xmlNodePtr oldnode;
   12805     xmlDocPtr oldDoc;
   12806     int i;
   12807 
   12808     CHECK_ERROR0;
   12809     comp = ctxt->comp;
   12810     /*
   12811     * Optimization for ()[last()] selection i.e. the last elem
   12812     */
   12813     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12814 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12815 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12816 	int f = comp->steps[op->ch2].ch1;
   12817 
   12818 	if ((f != -1) &&
   12819 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12820 	    (comp->steps[f].value5 == NULL) &&
   12821 	    (comp->steps[f].value == 0) &&
   12822 	    (comp->steps[f].value4 != NULL) &&
   12823 	    (xmlStrEqual
   12824 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12825 	    xmlNodePtr last = NULL;
   12826 
   12827 	    total +=
   12828 		xmlXPathCompOpEvalLast(ctxt,
   12829 		    &comp->steps[op->ch1],
   12830 		    &last);
   12831 	    CHECK_ERROR0;
   12832 	    /*
   12833 	    * The nodeset should be in document order,
   12834 	    * Keep only the last value
   12835 	    */
   12836 	    if ((ctxt->value != NULL) &&
   12837 		(ctxt->value->type == XPATH_NODESET) &&
   12838 		(ctxt->value->nodesetval != NULL) &&
   12839 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12840 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12841 		ctxt->value->nodesetval->nodeTab[0] =
   12842 		    ctxt->value->nodesetval->nodeTab[ctxt->
   12843 		    value->
   12844 		    nodesetval->
   12845 		    nodeNr -
   12846 		    1];
   12847 		ctxt->value->nodesetval->nodeNr = 1;
   12848 		*first = *(ctxt->value->nodesetval->nodeTab);
   12849 	    }
   12850 	    return (total);
   12851 	}
   12852     }
   12853 
   12854     if (op->ch1 != -1)
   12855 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12856     CHECK_ERROR0;
   12857     if (op->ch2 == -1)
   12858 	return (total);
   12859     if (ctxt->value == NULL)
   12860 	return (total);
   12861 
   12862 #ifdef LIBXML_XPTR_ENABLED
   12863     oldnode = ctxt->context->node;
   12864     /*
   12865     * Hum are we filtering the result of an XPointer expression
   12866     */
   12867     if (ctxt->value->type == XPATH_LOCATIONSET) {
   12868 	xmlXPathObjectPtr tmp = NULL;
   12869 	xmlLocationSetPtr newlocset = NULL;
   12870 	xmlLocationSetPtr oldlocset;
   12871 
   12872 	/*
   12873 	* Extract the old locset, and then evaluate the result of the
   12874 	* expression for all the element in the locset. use it to grow
   12875 	* up a new locset.
   12876 	*/
   12877 	CHECK_TYPE0(XPATH_LOCATIONSET);
   12878 	obj = valuePop(ctxt);
   12879 	oldlocset = obj->user;
   12880 	ctxt->context->node = NULL;
   12881 
   12882 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   12883 	    ctxt->context->contextSize = 0;
   12884 	    ctxt->context->proximityPosition = 0;
   12885 	    if (op->ch2 != -1)
   12886 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12887 	    res = valuePop(ctxt);
   12888 	    if (res != NULL) {
   12889 		xmlXPathReleaseObject(ctxt->context, res);
   12890 	    }
   12891 	    valuePush(ctxt, obj);
   12892 	    CHECK_ERROR0;
   12893 	    return (total);
   12894 	}
   12895 	newlocset = xmlXPtrLocationSetCreate(NULL);
   12896 
   12897 	for (i = 0; i < oldlocset->locNr; i++) {
   12898 	    /*
   12899 	    * Run the evaluation with a node list made of a
   12900 	    * single item in the nodelocset.
   12901 	    */
   12902 	    ctxt->context->node = oldlocset->locTab[i]->user;
   12903 	    ctxt->context->contextSize = oldlocset->locNr;
   12904 	    ctxt->context->proximityPosition = i + 1;
   12905 	    if (tmp == NULL) {
   12906 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   12907 		    ctxt->context->node);
   12908 	    } else {
   12909 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   12910 		    ctxt->context->node);
   12911 	    }
   12912 	    valuePush(ctxt, tmp);
   12913 	    if (op->ch2 != -1)
   12914 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12915 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12916 		xmlXPathFreeObject(obj);
   12917 		return(0);
   12918 	    }
   12919 	    /*
   12920 	    * The result of the evaluation need to be tested to
   12921 	    * decided whether the filter succeeded or not
   12922 	    */
   12923 	    res = valuePop(ctxt);
   12924 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   12925 		xmlXPtrLocationSetAdd(newlocset,
   12926 		    xmlXPathCacheObjectCopy(ctxt->context,
   12927 			oldlocset->locTab[i]));
   12928 	    }
   12929 	    /*
   12930 	    * Cleanup
   12931 	    */
   12932 	    if (res != NULL) {
   12933 		xmlXPathReleaseObject(ctxt->context, res);
   12934 	    }
   12935 	    if (ctxt->value == tmp) {
   12936 		valuePop(ctxt);
   12937 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   12938 		/*
   12939 		* REVISIT TODO: Don't create a temporary nodeset
   12940 		* for everly iteration.
   12941 		*/
   12942 		/* OLD: xmlXPathFreeObject(res); */
   12943 	    } else
   12944 		tmp = NULL;
   12945 	    ctxt->context->node = NULL;
   12946 	    /*
   12947 	    * Only put the first node in the result, then leave.
   12948 	    */
   12949 	    if (newlocset->locNr > 0) {
   12950 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   12951 		break;
   12952 	    }
   12953 	}
   12954 	if (tmp != NULL) {
   12955 	    xmlXPathReleaseObject(ctxt->context, tmp);
   12956 	}
   12957 	/*
   12958 	* The result is used as the new evaluation locset.
   12959 	*/
   12960 	xmlXPathReleaseObject(ctxt->context, obj);
   12961 	ctxt->context->node = NULL;
   12962 	ctxt->context->contextSize = -1;
   12963 	ctxt->context->proximityPosition = -1;
   12964 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   12965 	ctxt->context->node = oldnode;
   12966 	return (total);
   12967     }
   12968 #endif /* LIBXML_XPTR_ENABLED */
   12969 
   12970     /*
   12971     * Extract the old set, and then evaluate the result of the
   12972     * expression for all the element in the set. use it to grow
   12973     * up a new set.
   12974     */
   12975     CHECK_TYPE0(XPATH_NODESET);
   12976     obj = valuePop(ctxt);
   12977     oldset = obj->nodesetval;
   12978 
   12979     oldnode = ctxt->context->node;
   12980     oldDoc = ctxt->context->doc;
   12981     ctxt->context->node = NULL;
   12982 
   12983     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   12984 	ctxt->context->contextSize = 0;
   12985 	ctxt->context->proximityPosition = 0;
   12986 	/* QUESTION TODO: Why was this code commented out?
   12987 	    if (op->ch2 != -1)
   12988 		total +=
   12989 		    xmlXPathCompOpEval(ctxt,
   12990 			&comp->steps[op->ch2]);
   12991 	    CHECK_ERROR0;
   12992 	    res = valuePop(ctxt);
   12993 	    if (res != NULL)
   12994 		xmlXPathFreeObject(res);
   12995 	*/
   12996 	valuePush(ctxt, obj);
   12997 	ctxt->context->node = oldnode;
   12998 	CHECK_ERROR0;
   12999     } else {
   13000 	xmlNodeSetPtr newset;
   13001 	xmlXPathObjectPtr tmp = NULL;
   13002 	/*
   13003 	* Initialize the new set.
   13004 	* Also set the xpath document in case things like
   13005 	* key() evaluation are attempted on the predicate
   13006 	*/
   13007 	newset = xmlXPathNodeSetCreate(NULL);
   13008         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13009 
   13010 	for (i = 0; i < oldset->nodeNr; i++) {
   13011 	    /*
   13012 	    * Run the evaluation with a node list made of
   13013 	    * a single item in the nodeset.
   13014 	    */
   13015 	    ctxt->context->node = oldset->nodeTab[i];
   13016 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13017 		(oldset->nodeTab[i]->doc != NULL))
   13018 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13019 	    if (tmp == NULL) {
   13020 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13021 		    ctxt->context->node);
   13022 	    } else {
   13023 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13024 		    ctxt->context->node);
   13025 	    }
   13026 	    valuePush(ctxt, tmp);
   13027 	    ctxt->context->contextSize = oldset->nodeNr;
   13028 	    ctxt->context->proximityPosition = i + 1;
   13029 	    if (op->ch2 != -1)
   13030 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13031 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13032 		xmlXPathFreeNodeSet(newset);
   13033 		xmlXPathFreeObject(obj);
   13034 		return(0);
   13035 	    }
   13036 	    /*
   13037 	    * The result of the evaluation needs to be tested to
   13038 	    * decide whether the filter succeeded or not
   13039 	    */
   13040 	    res = valuePop(ctxt);
   13041 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13042 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13043 	    }
   13044 	    /*
   13045 	    * Cleanup
   13046 	    */
   13047 	    if (res != NULL) {
   13048 		xmlXPathReleaseObject(ctxt->context, res);
   13049 	    }
   13050 	    if (ctxt->value == tmp) {
   13051 		valuePop(ctxt);
   13052 		/*
   13053 		* Don't free the temporary nodeset
   13054 		* in order to avoid massive recreation inside this
   13055 		* loop.
   13056 		*/
   13057 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13058 	    } else
   13059 		tmp = NULL;
   13060 	    ctxt->context->node = NULL;
   13061 	    /*
   13062 	    * Only put the first node in the result, then leave.
   13063 	    */
   13064 	    if (newset->nodeNr > 0) {
   13065 		*first = *(newset->nodeTab);
   13066 		break;
   13067 	    }
   13068 	}
   13069 	if (tmp != NULL) {
   13070 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13071 	}
   13072 	/*
   13073 	* The result is used as the new evaluation set.
   13074 	*/
   13075 	xmlXPathReleaseObject(ctxt->context, obj);
   13076 	ctxt->context->node = NULL;
   13077 	ctxt->context->contextSize = -1;
   13078 	ctxt->context->proximityPosition = -1;
   13079 	/* may want to move this past the '}' later */
   13080 	ctxt->context->doc = oldDoc;
   13081 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13082     }
   13083     ctxt->context->node = oldnode;
   13084     return(total);
   13085 }
   13086 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13087 
   13088 /**
   13089  * xmlXPathCompOpEval:
   13090  * @ctxt:  the XPath parser context with the compiled expression
   13091  * @op:  an XPath compiled operation
   13092  *
   13093  * Evaluate the Precompiled XPath operation
   13094  * Returns the number of nodes traversed
   13095  */
   13096 static int
   13097 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13098 {
   13099     int total = 0;
   13100     int equal, ret;
   13101     xmlXPathCompExprPtr comp;
   13102     xmlXPathObjectPtr arg1, arg2;
   13103     xmlNodePtr bak;
   13104     xmlDocPtr bakd;
   13105     int pp;
   13106     int cs;
   13107 
   13108     CHECK_ERROR0;
   13109     comp = ctxt->comp;
   13110     switch (op->op) {
   13111         case XPATH_OP_END:
   13112             return (0);
   13113         case XPATH_OP_AND:
   13114 	    bakd = ctxt->context->doc;
   13115 	    bak = ctxt->context->node;
   13116 	    pp = ctxt->context->proximityPosition;
   13117 	    cs = ctxt->context->contextSize;
   13118             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13119 	    CHECK_ERROR0;
   13120             xmlXPathBooleanFunction(ctxt, 1);
   13121             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13122                 return (total);
   13123             arg2 = valuePop(ctxt);
   13124 	    ctxt->context->doc = bakd;
   13125 	    ctxt->context->node = bak;
   13126 	    ctxt->context->proximityPosition = pp;
   13127 	    ctxt->context->contextSize = cs;
   13128             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13129 	    if (ctxt->error) {
   13130 		xmlXPathFreeObject(arg2);
   13131 		return(0);
   13132 	    }
   13133             xmlXPathBooleanFunction(ctxt, 1);
   13134             arg1 = valuePop(ctxt);
   13135             arg1->boolval &= arg2->boolval;
   13136             valuePush(ctxt, arg1);
   13137 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13138             return (total);
   13139         case XPATH_OP_OR:
   13140 	    bakd = ctxt->context->doc;
   13141 	    bak = ctxt->context->node;
   13142 	    pp = ctxt->context->proximityPosition;
   13143 	    cs = ctxt->context->contextSize;
   13144             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13145 	    CHECK_ERROR0;
   13146             xmlXPathBooleanFunction(ctxt, 1);
   13147             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13148                 return (total);
   13149             arg2 = valuePop(ctxt);
   13150 	    ctxt->context->doc = bakd;
   13151 	    ctxt->context->node = bak;
   13152 	    ctxt->context->proximityPosition = pp;
   13153 	    ctxt->context->contextSize = cs;
   13154             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13155 	    if (ctxt->error) {
   13156 		xmlXPathFreeObject(arg2);
   13157 		return(0);
   13158 	    }
   13159             xmlXPathBooleanFunction(ctxt, 1);
   13160             arg1 = valuePop(ctxt);
   13161             arg1->boolval |= arg2->boolval;
   13162             valuePush(ctxt, arg1);
   13163 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13164             return (total);
   13165         case XPATH_OP_EQUAL:
   13166 	    bakd = ctxt->context->doc;
   13167 	    bak = ctxt->context->node;
   13168 	    pp = ctxt->context->proximityPosition;
   13169 	    cs = ctxt->context->contextSize;
   13170             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13171 	    CHECK_ERROR0;
   13172 	    ctxt->context->doc = bakd;
   13173 	    ctxt->context->node = bak;
   13174 	    ctxt->context->proximityPosition = pp;
   13175 	    ctxt->context->contextSize = cs;
   13176             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13177 	    CHECK_ERROR0;
   13178 	    if (op->value)
   13179 		equal = xmlXPathEqualValues(ctxt);
   13180 	    else
   13181 		equal = xmlXPathNotEqualValues(ctxt);
   13182 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13183             return (total);
   13184         case XPATH_OP_CMP:
   13185 	    bakd = ctxt->context->doc;
   13186 	    bak = ctxt->context->node;
   13187 	    pp = ctxt->context->proximityPosition;
   13188 	    cs = ctxt->context->contextSize;
   13189             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13190 	    CHECK_ERROR0;
   13191 	    ctxt->context->doc = bakd;
   13192 	    ctxt->context->node = bak;
   13193 	    ctxt->context->proximityPosition = pp;
   13194 	    ctxt->context->contextSize = cs;
   13195             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13196 	    CHECK_ERROR0;
   13197             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13198 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13199             return (total);
   13200         case XPATH_OP_PLUS:
   13201 	    bakd = ctxt->context->doc;
   13202 	    bak = ctxt->context->node;
   13203 	    pp = ctxt->context->proximityPosition;
   13204 	    cs = ctxt->context->contextSize;
   13205             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13206 	    CHECK_ERROR0;
   13207             if (op->ch2 != -1) {
   13208 		ctxt->context->doc = bakd;
   13209 		ctxt->context->node = bak;
   13210 		ctxt->context->proximityPosition = pp;
   13211 		ctxt->context->contextSize = cs;
   13212                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13213 	    }
   13214 	    CHECK_ERROR0;
   13215             if (op->value == 0)
   13216                 xmlXPathSubValues(ctxt);
   13217             else if (op->value == 1)
   13218                 xmlXPathAddValues(ctxt);
   13219             else if (op->value == 2)
   13220                 xmlXPathValueFlipSign(ctxt);
   13221             else if (op->value == 3) {
   13222                 CAST_TO_NUMBER;
   13223                 CHECK_TYPE0(XPATH_NUMBER);
   13224             }
   13225             return (total);
   13226         case XPATH_OP_MULT:
   13227 	    bakd = ctxt->context->doc;
   13228 	    bak = ctxt->context->node;
   13229 	    pp = ctxt->context->proximityPosition;
   13230 	    cs = ctxt->context->contextSize;
   13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13232 	    CHECK_ERROR0;
   13233 	    ctxt->context->doc = bakd;
   13234 	    ctxt->context->node = bak;
   13235 	    ctxt->context->proximityPosition = pp;
   13236 	    ctxt->context->contextSize = cs;
   13237             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13238 	    CHECK_ERROR0;
   13239             if (op->value == 0)
   13240                 xmlXPathMultValues(ctxt);
   13241             else if (op->value == 1)
   13242                 xmlXPathDivValues(ctxt);
   13243             else if (op->value == 2)
   13244                 xmlXPathModValues(ctxt);
   13245             return (total);
   13246         case XPATH_OP_UNION:
   13247 	    bakd = ctxt->context->doc;
   13248 	    bak = ctxt->context->node;
   13249 	    pp = ctxt->context->proximityPosition;
   13250 	    cs = ctxt->context->contextSize;
   13251             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13252 	    CHECK_ERROR0;
   13253 	    ctxt->context->doc = bakd;
   13254 	    ctxt->context->node = bak;
   13255 	    ctxt->context->proximityPosition = pp;
   13256 	    ctxt->context->contextSize = cs;
   13257             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13258 	    CHECK_ERROR0;
   13259             CHECK_TYPE0(XPATH_NODESET);
   13260             arg2 = valuePop(ctxt);
   13261 
   13262             CHECK_TYPE0(XPATH_NODESET);
   13263             arg1 = valuePop(ctxt);
   13264 
   13265 	    if ((arg1->nodesetval == NULL) ||
   13266 		((arg2->nodesetval != NULL) &&
   13267 		 (arg2->nodesetval->nodeNr != 0)))
   13268 	    {
   13269 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13270 							arg2->nodesetval);
   13271 	    }
   13272 
   13273             valuePush(ctxt, arg1);
   13274 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13275             return (total);
   13276         case XPATH_OP_ROOT:
   13277             xmlXPathRoot(ctxt);
   13278             return (total);
   13279         case XPATH_OP_NODE:
   13280             if (op->ch1 != -1)
   13281                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13282 	    CHECK_ERROR0;
   13283             if (op->ch2 != -1)
   13284                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13285 	    CHECK_ERROR0;
   13286 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13287 		ctxt->context->node));
   13288             return (total);
   13289         case XPATH_OP_RESET:
   13290             if (op->ch1 != -1)
   13291                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13292 	    CHECK_ERROR0;
   13293             if (op->ch2 != -1)
   13294                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13295 	    CHECK_ERROR0;
   13296             ctxt->context->node = NULL;
   13297             return (total);
   13298         case XPATH_OP_COLLECT:{
   13299                 if (op->ch1 == -1)
   13300                     return (total);
   13301 
   13302                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13303 		CHECK_ERROR0;
   13304 
   13305                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13306                 return (total);
   13307             }
   13308         case XPATH_OP_VALUE:
   13309             valuePush(ctxt,
   13310                       xmlXPathCacheObjectCopy(ctxt->context,
   13311 			(xmlXPathObjectPtr) op->value4));
   13312             return (total);
   13313         case XPATH_OP_VARIABLE:{
   13314 		xmlXPathObjectPtr val;
   13315 
   13316                 if (op->ch1 != -1)
   13317                     total +=
   13318                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13319                 if (op->value5 == NULL) {
   13320 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13321 		    if (val == NULL) {
   13322 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13323 			return(0);
   13324 		    }
   13325                     valuePush(ctxt, val);
   13326 		} else {
   13327                     const xmlChar *URI;
   13328 
   13329                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13330                     if (URI == NULL) {
   13331                         xmlGenericError(xmlGenericErrorContext,
   13332             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13333                                     (char *) op->value4, (char *)op->value5);
   13334                         return (total);
   13335                     }
   13336 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13337                                                        op->value4, URI);
   13338 		    if (val == NULL) {
   13339 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13340 			return(0);
   13341 		    }
   13342                     valuePush(ctxt, val);
   13343                 }
   13344                 return (total);
   13345             }
   13346         case XPATH_OP_FUNCTION:{
   13347                 xmlXPathFunction func;
   13348                 const xmlChar *oldFunc, *oldFuncURI;
   13349 		int i;
   13350 
   13351                 if (op->ch1 != -1)
   13352                     total +=
   13353                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13354 		if (ctxt->valueNr < op->value) {
   13355 		    xmlGenericError(xmlGenericErrorContext,
   13356 			    "xmlXPathCompOpEval: parameter error\n");
   13357 		    ctxt->error = XPATH_INVALID_OPERAND;
   13358 		    return (total);
   13359 		}
   13360 		for (i = 0; i < op->value; i++)
   13361 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13362 			xmlGenericError(xmlGenericErrorContext,
   13363 				"xmlXPathCompOpEval: parameter error\n");
   13364 			ctxt->error = XPATH_INVALID_OPERAND;
   13365 			return (total);
   13366 		    }
   13367                 if (op->cache != NULL)
   13368                     XML_CAST_FPTR(func) = op->cache;
   13369                 else {
   13370                     const xmlChar *URI = NULL;
   13371 
   13372                     if (op->value5 == NULL)
   13373                         func =
   13374                             xmlXPathFunctionLookup(ctxt->context,
   13375                                                    op->value4);
   13376                     else {
   13377                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13378                         if (URI == NULL) {
   13379                             xmlGenericError(xmlGenericErrorContext,
   13380             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13381                                     (char *)op->value4, (char *)op->value5);
   13382                             return (total);
   13383                         }
   13384                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13385                                                         op->value4, URI);
   13386                     }
   13387                     if (func == NULL) {
   13388                         xmlGenericError(xmlGenericErrorContext,
   13389                                 "xmlXPathCompOpEval: function %s not found\n",
   13390                                         (char *)op->value4);
   13391                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13392                     }
   13393                     op->cache = XML_CAST_FPTR(func);
   13394                     op->cacheURI = (void *) URI;
   13395                 }
   13396                 oldFunc = ctxt->context->function;
   13397                 oldFuncURI = ctxt->context->functionURI;
   13398                 ctxt->context->function = op->value4;
   13399                 ctxt->context->functionURI = op->cacheURI;
   13400                 func(ctxt, op->value);
   13401                 ctxt->context->function = oldFunc;
   13402                 ctxt->context->functionURI = oldFuncURI;
   13403                 return (total);
   13404             }
   13405         case XPATH_OP_ARG:
   13406 	    bakd = ctxt->context->doc;
   13407 	    bak = ctxt->context->node;
   13408 	    pp = ctxt->context->proximityPosition;
   13409 	    cs = ctxt->context->contextSize;
   13410             if (op->ch1 != -1)
   13411                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13412 	    ctxt->context->contextSize = cs;
   13413 	    ctxt->context->proximityPosition = pp;
   13414 	    ctxt->context->node = bak;
   13415 	    ctxt->context->doc = bakd;
   13416 	    CHECK_ERROR0;
   13417             if (op->ch2 != -1) {
   13418                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13419 	        ctxt->context->doc = bakd;
   13420 	        ctxt->context->node = bak;
   13421 	        CHECK_ERROR0;
   13422 	    }
   13423             return (total);
   13424         case XPATH_OP_PREDICATE:
   13425         case XPATH_OP_FILTER:{
   13426                 xmlXPathObjectPtr res;
   13427                 xmlXPathObjectPtr obj, tmp;
   13428                 xmlNodeSetPtr newset = NULL;
   13429                 xmlNodeSetPtr oldset;
   13430                 xmlNodePtr oldnode;
   13431 		xmlDocPtr oldDoc;
   13432                 int i;
   13433 
   13434                 /*
   13435                  * Optimization for ()[1] selection i.e. the first elem
   13436                  */
   13437                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13438 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13439 		    /*
   13440 		    * FILTER TODO: Can we assume that the inner processing
   13441 		    *  will result in an ordered list if we have an
   13442 		    *  XPATH_OP_FILTER?
   13443 		    *  What about an additional field or flag on
   13444 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13445 		    *  to assume anything, so it would be more robust and
   13446 		    *  easier to optimize.
   13447 		    */
   13448                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13449 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13450 #else
   13451 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13452 #endif
   13453                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13454                     xmlXPathObjectPtr val;
   13455 
   13456                     val = comp->steps[op->ch2].value4;
   13457                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13458                         (val->floatval == 1.0)) {
   13459                         xmlNodePtr first = NULL;
   13460 
   13461                         total +=
   13462                             xmlXPathCompOpEvalFirst(ctxt,
   13463                                                     &comp->steps[op->ch1],
   13464                                                     &first);
   13465 			CHECK_ERROR0;
   13466                         /*
   13467                          * The nodeset should be in document order,
   13468                          * Keep only the first value
   13469                          */
   13470                         if ((ctxt->value != NULL) &&
   13471                             (ctxt->value->type == XPATH_NODESET) &&
   13472                             (ctxt->value->nodesetval != NULL) &&
   13473                             (ctxt->value->nodesetval->nodeNr > 1))
   13474                             ctxt->value->nodesetval->nodeNr = 1;
   13475                         return (total);
   13476                     }
   13477                 }
   13478                 /*
   13479                  * Optimization for ()[last()] selection i.e. the last elem
   13480                  */
   13481                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13482                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13483                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13484                     int f = comp->steps[op->ch2].ch1;
   13485 
   13486                     if ((f != -1) &&
   13487                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13488                         (comp->steps[f].value5 == NULL) &&
   13489                         (comp->steps[f].value == 0) &&
   13490                         (comp->steps[f].value4 != NULL) &&
   13491                         (xmlStrEqual
   13492                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13493                         xmlNodePtr last = NULL;
   13494 
   13495                         total +=
   13496                             xmlXPathCompOpEvalLast(ctxt,
   13497                                                    &comp->steps[op->ch1],
   13498                                                    &last);
   13499 			CHECK_ERROR0;
   13500                         /*
   13501                          * The nodeset should be in document order,
   13502                          * Keep only the last value
   13503                          */
   13504                         if ((ctxt->value != NULL) &&
   13505                             (ctxt->value->type == XPATH_NODESET) &&
   13506                             (ctxt->value->nodesetval != NULL) &&
   13507                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13508                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13509                             ctxt->value->nodesetval->nodeTab[0] =
   13510                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13511                                                                  value->
   13512                                                                  nodesetval->
   13513                                                                  nodeNr -
   13514                                                                  1];
   13515                             ctxt->value->nodesetval->nodeNr = 1;
   13516                         }
   13517                         return (total);
   13518                     }
   13519                 }
   13520 		/*
   13521 		* Process inner predicates first.
   13522 		* Example "index[parent::book][1]":
   13523 		* ...
   13524 		*   PREDICATE   <-- we are here "[1]"
   13525 		*     PREDICATE <-- process "[parent::book]" first
   13526 		*       SORT
   13527 		*         COLLECT  'parent' 'name' 'node' book
   13528 		*           NODE
   13529 		*     ELEM Object is a number : 1
   13530 		*/
   13531                 if (op->ch1 != -1)
   13532                     total +=
   13533                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13534 		CHECK_ERROR0;
   13535                 if (op->ch2 == -1)
   13536                     return (total);
   13537                 if (ctxt->value == NULL)
   13538                     return (total);
   13539 
   13540                 oldnode = ctxt->context->node;
   13541 
   13542 #ifdef LIBXML_XPTR_ENABLED
   13543                 /*
   13544                  * Hum are we filtering the result of an XPointer expression
   13545                  */
   13546                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13547                     xmlLocationSetPtr newlocset = NULL;
   13548                     xmlLocationSetPtr oldlocset;
   13549 
   13550                     /*
   13551                      * Extract the old locset, and then evaluate the result of the
   13552                      * expression for all the element in the locset. use it to grow
   13553                      * up a new locset.
   13554                      */
   13555                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13556                     obj = valuePop(ctxt);
   13557                     oldlocset = obj->user;
   13558                     ctxt->context->node = NULL;
   13559 
   13560                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13561                         ctxt->context->contextSize = 0;
   13562                         ctxt->context->proximityPosition = 0;
   13563                         if (op->ch2 != -1)
   13564                             total +=
   13565                                 xmlXPathCompOpEval(ctxt,
   13566                                                    &comp->steps[op->ch2]);
   13567                         res = valuePop(ctxt);
   13568                         if (res != NULL) {
   13569 			    xmlXPathReleaseObject(ctxt->context, res);
   13570 			}
   13571                         valuePush(ctxt, obj);
   13572                         CHECK_ERROR0;
   13573                         return (total);
   13574                     }
   13575                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13576 
   13577                     for (i = 0; i < oldlocset->locNr; i++) {
   13578                         /*
   13579                          * Run the evaluation with a node list made of a
   13580                          * single item in the nodelocset.
   13581                          */
   13582                         ctxt->context->node = oldlocset->locTab[i]->user;
   13583                         ctxt->context->contextSize = oldlocset->locNr;
   13584                         ctxt->context->proximityPosition = i + 1;
   13585 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13586 			    ctxt->context->node);
   13587                         valuePush(ctxt, tmp);
   13588 
   13589                         if (op->ch2 != -1)
   13590                             total +=
   13591                                 xmlXPathCompOpEval(ctxt,
   13592                                                    &comp->steps[op->ch2]);
   13593 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13594 			    xmlXPathFreeObject(obj);
   13595 			    return(0);
   13596 			}
   13597 
   13598                         /*
   13599                          * The result of the evaluation need to be tested to
   13600                          * decided whether the filter succeeded or not
   13601                          */
   13602                         res = valuePop(ctxt);
   13603                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13604                             xmlXPtrLocationSetAdd(newlocset,
   13605                                                   xmlXPathObjectCopy
   13606                                                   (oldlocset->locTab[i]));
   13607                         }
   13608 
   13609                         /*
   13610                          * Cleanup
   13611                          */
   13612                         if (res != NULL) {
   13613 			    xmlXPathReleaseObject(ctxt->context, res);
   13614 			}
   13615                         if (ctxt->value == tmp) {
   13616                             res = valuePop(ctxt);
   13617 			    xmlXPathReleaseObject(ctxt->context, res);
   13618                         }
   13619 
   13620                         ctxt->context->node = NULL;
   13621                     }
   13622 
   13623                     /*
   13624                      * The result is used as the new evaluation locset.
   13625                      */
   13626 		    xmlXPathReleaseObject(ctxt->context, obj);
   13627                     ctxt->context->node = NULL;
   13628                     ctxt->context->contextSize = -1;
   13629                     ctxt->context->proximityPosition = -1;
   13630                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13631                     ctxt->context->node = oldnode;
   13632                     return (total);
   13633                 }
   13634 #endif /* LIBXML_XPTR_ENABLED */
   13635 
   13636                 /*
   13637                  * Extract the old set, and then evaluate the result of the
   13638                  * expression for all the element in the set. use it to grow
   13639                  * up a new set.
   13640                  */
   13641                 CHECK_TYPE0(XPATH_NODESET);
   13642                 obj = valuePop(ctxt);
   13643                 oldset = obj->nodesetval;
   13644 
   13645                 oldnode = ctxt->context->node;
   13646 		oldDoc = ctxt->context->doc;
   13647                 ctxt->context->node = NULL;
   13648 
   13649                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13650                     ctxt->context->contextSize = 0;
   13651                     ctxt->context->proximityPosition = 0;
   13652 /*
   13653                     if (op->ch2 != -1)
   13654                         total +=
   13655                             xmlXPathCompOpEval(ctxt,
   13656                                                &comp->steps[op->ch2]);
   13657 		    CHECK_ERROR0;
   13658                     res = valuePop(ctxt);
   13659                     if (res != NULL)
   13660                         xmlXPathFreeObject(res);
   13661 */
   13662                     valuePush(ctxt, obj);
   13663                     ctxt->context->node = oldnode;
   13664                     CHECK_ERROR0;
   13665                 } else {
   13666 		    tmp = NULL;
   13667                     /*
   13668                      * Initialize the new set.
   13669 		     * Also set the xpath document in case things like
   13670 		     * key() evaluation are attempted on the predicate
   13671                      */
   13672                     newset = xmlXPathNodeSetCreate(NULL);
   13673 		    /*
   13674 		    * SPEC XPath 1.0:
   13675 		    *  "For each node in the node-set to be filtered, the
   13676 		    *  PredicateExpr is evaluated with that node as the
   13677 		    *  context node, with the number of nodes in the
   13678 		    *  node-set as the context size, and with the proximity
   13679 		    *  position of the node in the node-set with respect to
   13680 		    *  the axis as the context position;"
   13681 		    * @oldset is the node-set" to be filtered.
   13682 		    *
   13683 		    * SPEC XPath 1.0:
   13684 		    *  "only predicates change the context position and
   13685 		    *  context size (see [2.4 Predicates])."
   13686 		    * Example:
   13687 		    *   node-set  context pos
   13688 		    *    nA         1
   13689 		    *    nB         2
   13690 		    *    nC         3
   13691 		    *   After applying predicate [position() > 1] :
   13692 		    *   node-set  context pos
   13693 		    *    nB         1
   13694 		    *    nC         2
   13695 		    *
   13696 		    * removed the first node in the node-set, then
   13697 		    * the context position of the
   13698 		    */
   13699                     for (i = 0; i < oldset->nodeNr; i++) {
   13700                         /*
   13701                          * Run the evaluation with a node list made of
   13702                          * a single item in the nodeset.
   13703                          */
   13704                         ctxt->context->node = oldset->nodeTab[i];
   13705 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13706 			    (oldset->nodeTab[i]->doc != NULL))
   13707 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13708 			if (tmp == NULL) {
   13709 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13710 				ctxt->context->node);
   13711 			} else {
   13712 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13713 				ctxt->context->node);
   13714 			}
   13715                         valuePush(ctxt, tmp);
   13716                         ctxt->context->contextSize = oldset->nodeNr;
   13717                         ctxt->context->proximityPosition = i + 1;
   13718 			/*
   13719 			* Evaluate the predicate against the context node.
   13720 			* Can/should we optimize position() predicates
   13721 			* here (e.g. "[1]")?
   13722 			*/
   13723                         if (op->ch2 != -1)
   13724                             total +=
   13725                                 xmlXPathCompOpEval(ctxt,
   13726                                                    &comp->steps[op->ch2]);
   13727 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13728 			    xmlXPathFreeNodeSet(newset);
   13729 			    xmlXPathFreeObject(obj);
   13730 			    return(0);
   13731 			}
   13732 
   13733                         /*
   13734                          * The result of the evaluation needs to be tested to
   13735                          * decide whether the filter succeeded or not
   13736                          */
   13737 			/*
   13738 			* OPTIMIZE TODO: Can we use
   13739 			* xmlXPathNodeSetAdd*Unique()* instead?
   13740 			*/
   13741                         res = valuePop(ctxt);
   13742                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13743                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13744                         }
   13745 
   13746                         /*
   13747                          * Cleanup
   13748                          */
   13749                         if (res != NULL) {
   13750 			    xmlXPathReleaseObject(ctxt->context, res);
   13751 			}
   13752                         if (ctxt->value == tmp) {
   13753                             valuePop(ctxt);
   13754 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13755 			    /*
   13756 			    * Don't free the temporary nodeset
   13757 			    * in order to avoid massive recreation inside this
   13758 			    * loop.
   13759 			    */
   13760                         } else
   13761 			    tmp = NULL;
   13762                         ctxt->context->node = NULL;
   13763                     }
   13764 		    if (tmp != NULL)
   13765 			xmlXPathReleaseObject(ctxt->context, tmp);
   13766                     /*
   13767                      * The result is used as the new evaluation set.
   13768                      */
   13769 		    xmlXPathReleaseObject(ctxt->context, obj);
   13770                     ctxt->context->node = NULL;
   13771                     ctxt->context->contextSize = -1;
   13772                     ctxt->context->proximityPosition = -1;
   13773 		    /* may want to move this past the '}' later */
   13774 		    ctxt->context->doc = oldDoc;
   13775 		    valuePush(ctxt,
   13776 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13777                 }
   13778                 ctxt->context->node = oldnode;
   13779                 return (total);
   13780             }
   13781         case XPATH_OP_SORT:
   13782             if (op->ch1 != -1)
   13783                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13784 	    CHECK_ERROR0;
   13785             if ((ctxt->value != NULL) &&
   13786                 (ctxt->value->type == XPATH_NODESET) &&
   13787                 (ctxt->value->nodesetval != NULL) &&
   13788 		(ctxt->value->nodesetval->nodeNr > 1))
   13789 	    {
   13790                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13791 	    }
   13792             return (total);
   13793 #ifdef LIBXML_XPTR_ENABLED
   13794         case XPATH_OP_RANGETO:{
   13795                 xmlXPathObjectPtr range;
   13796                 xmlXPathObjectPtr res, obj;
   13797                 xmlXPathObjectPtr tmp;
   13798                 xmlLocationSetPtr newlocset = NULL;
   13799 		    xmlLocationSetPtr oldlocset;
   13800                 xmlNodeSetPtr oldset;
   13801                 int i, j;
   13802 
   13803                 if (op->ch1 != -1)
   13804                     total +=
   13805                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13806                 if (op->ch2 == -1)
   13807                     return (total);
   13808 
   13809                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13810                     /*
   13811                      * Extract the old locset, and then evaluate the result of the
   13812                      * expression for all the element in the locset. use it to grow
   13813                      * up a new locset.
   13814                      */
   13815                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13816                     obj = valuePop(ctxt);
   13817                     oldlocset = obj->user;
   13818 
   13819                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13820 		        ctxt->context->node = NULL;
   13821                         ctxt->context->contextSize = 0;
   13822                         ctxt->context->proximityPosition = 0;
   13823                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   13824                         res = valuePop(ctxt);
   13825                         if (res != NULL) {
   13826 			    xmlXPathReleaseObject(ctxt->context, res);
   13827 			}
   13828                         valuePush(ctxt, obj);
   13829                         CHECK_ERROR0;
   13830                         return (total);
   13831                     }
   13832                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13833 
   13834                     for (i = 0; i < oldlocset->locNr; i++) {
   13835                         /*
   13836                          * Run the evaluation with a node list made of a
   13837                          * single item in the nodelocset.
   13838                          */
   13839                         ctxt->context->node = oldlocset->locTab[i]->user;
   13840                         ctxt->context->contextSize = oldlocset->locNr;
   13841                         ctxt->context->proximityPosition = i + 1;
   13842 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13843 			    ctxt->context->node);
   13844                         valuePush(ctxt, tmp);
   13845 
   13846                         if (op->ch2 != -1)
   13847                             total +=
   13848                                 xmlXPathCompOpEval(ctxt,
   13849                                                    &comp->steps[op->ch2]);
   13850 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13851 			    xmlXPathFreeObject(obj);
   13852 			    return(0);
   13853 			}
   13854 
   13855                         res = valuePop(ctxt);
   13856 			if (res->type == XPATH_LOCATIONSET) {
   13857 			    xmlLocationSetPtr rloc =
   13858 			        (xmlLocationSetPtr)res->user;
   13859 			    for (j=0; j<rloc->locNr; j++) {
   13860 			        range = xmlXPtrNewRange(
   13861 				  oldlocset->locTab[i]->user,
   13862 				  oldlocset->locTab[i]->index,
   13863 				  rloc->locTab[j]->user2,
   13864 				  rloc->locTab[j]->index2);
   13865 				if (range != NULL) {
   13866 				    xmlXPtrLocationSetAdd(newlocset, range);
   13867 				}
   13868 			    }
   13869 			} else {
   13870 			    range = xmlXPtrNewRangeNodeObject(
   13871 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   13872                             if (range != NULL) {
   13873                                 xmlXPtrLocationSetAdd(newlocset,range);
   13874 			    }
   13875                         }
   13876 
   13877                         /*
   13878                          * Cleanup
   13879                          */
   13880                         if (res != NULL) {
   13881 			    xmlXPathReleaseObject(ctxt->context, res);
   13882 			}
   13883                         if (ctxt->value == tmp) {
   13884                             res = valuePop(ctxt);
   13885 			    xmlXPathReleaseObject(ctxt->context, res);
   13886                         }
   13887 
   13888                         ctxt->context->node = NULL;
   13889                     }
   13890 		} else {	/* Not a location set */
   13891                     CHECK_TYPE0(XPATH_NODESET);
   13892                     obj = valuePop(ctxt);
   13893                     oldset = obj->nodesetval;
   13894                     ctxt->context->node = NULL;
   13895 
   13896                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13897 
   13898                     if (oldset != NULL) {
   13899                         for (i = 0; i < oldset->nodeNr; i++) {
   13900                             /*
   13901                              * Run the evaluation with a node list made of a single item
   13902                              * in the nodeset.
   13903                              */
   13904                             ctxt->context->node = oldset->nodeTab[i];
   13905 			    /*
   13906 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   13907 			    */
   13908 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13909 				ctxt->context->node);
   13910                             valuePush(ctxt, tmp);
   13911 
   13912                             if (op->ch2 != -1)
   13913                                 total +=
   13914                                     xmlXPathCompOpEval(ctxt,
   13915                                                    &comp->steps[op->ch2]);
   13916 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13917 				xmlXPathFreeObject(obj);
   13918 				return(0);
   13919 			    }
   13920 
   13921                             res = valuePop(ctxt);
   13922                             range =
   13923                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   13924                                                       res);
   13925                             if (range != NULL) {
   13926                                 xmlXPtrLocationSetAdd(newlocset, range);
   13927                             }
   13928 
   13929                             /*
   13930                              * Cleanup
   13931                              */
   13932                             if (res != NULL) {
   13933 				xmlXPathReleaseObject(ctxt->context, res);
   13934 			    }
   13935                             if (ctxt->value == tmp) {
   13936                                 res = valuePop(ctxt);
   13937 				xmlXPathReleaseObject(ctxt->context, res);
   13938                             }
   13939 
   13940                             ctxt->context->node = NULL;
   13941                         }
   13942                     }
   13943                 }
   13944 
   13945                 /*
   13946                  * The result is used as the new evaluation set.
   13947                  */
   13948 		xmlXPathReleaseObject(ctxt->context, obj);
   13949                 ctxt->context->node = NULL;
   13950                 ctxt->context->contextSize = -1;
   13951                 ctxt->context->proximityPosition = -1;
   13952                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13953                 return (total);
   13954             }
   13955 #endif /* LIBXML_XPTR_ENABLED */
   13956     }
   13957     xmlGenericError(xmlGenericErrorContext,
   13958                     "XPath: unknown precompiled operation %d\n", op->op);
   13959     return (total);
   13960 }
   13961 
   13962 /**
   13963  * xmlXPathCompOpEvalToBoolean:
   13964  * @ctxt:  the XPath parser context
   13965  *
   13966  * Evaluates if the expression evaluates to true.
   13967  *
   13968  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   13969  */
   13970 static int
   13971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   13972 			    xmlXPathStepOpPtr op,
   13973 			    int isPredicate)
   13974 {
   13975     xmlXPathObjectPtr resObj = NULL;
   13976 
   13977 start:
   13978     /* comp = ctxt->comp; */
   13979     switch (op->op) {
   13980         case XPATH_OP_END:
   13981             return (0);
   13982 	case XPATH_OP_VALUE:
   13983 	    resObj = (xmlXPathObjectPtr) op->value4;
   13984 	    if (isPredicate)
   13985 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   13986 	    return(xmlXPathCastToBoolean(resObj));
   13987 	case XPATH_OP_SORT:
   13988 	    /*
   13989 	    * We don't need sorting for boolean results. Skip this one.
   13990 	    */
   13991             if (op->ch1 != -1) {
   13992 		op = &ctxt->comp->steps[op->ch1];
   13993 		goto start;
   13994 	    }
   13995 	    return(0);
   13996 	case XPATH_OP_COLLECT:
   13997 	    if (op->ch1 == -1)
   13998 		return(0);
   13999 
   14000             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14001 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14002 		return(-1);
   14003 
   14004             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14005 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14006 		return(-1);
   14007 
   14008 	    resObj = valuePop(ctxt);
   14009 	    if (resObj == NULL)
   14010 		return(-1);
   14011 	    break;
   14012 	default:
   14013 	    /*
   14014 	    * Fallback to call xmlXPathCompOpEval().
   14015 	    */
   14016 	    xmlXPathCompOpEval(ctxt, op);
   14017 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14018 		return(-1);
   14019 
   14020 	    resObj = valuePop(ctxt);
   14021 	    if (resObj == NULL)
   14022 		return(-1);
   14023 	    break;
   14024     }
   14025 
   14026     if (resObj) {
   14027 	int res;
   14028 
   14029 	if (resObj->type == XPATH_BOOLEAN) {
   14030 	    res = resObj->boolval;
   14031 	} else if (isPredicate) {
   14032 	    /*
   14033 	    * For predicates a result of type "number" is handled
   14034 	    * differently:
   14035 	    * SPEC XPath 1.0:
   14036 	    * "If the result is a number, the result will be converted
   14037 	    *  to true if the number is equal to the context position
   14038 	    *  and will be converted to false otherwise;"
   14039 	    */
   14040 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14041 	} else {
   14042 	    res = xmlXPathCastToBoolean(resObj);
   14043 	}
   14044 	xmlXPathReleaseObject(ctxt->context, resObj);
   14045 	return(res);
   14046     }
   14047 
   14048     return(0);
   14049 }
   14050 
   14051 #ifdef XPATH_STREAMING
   14052 /**
   14053  * xmlXPathRunStreamEval:
   14054  * @ctxt:  the XPath parser context with the compiled expression
   14055  *
   14056  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14057  */
   14058 static int
   14059 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14060 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14061 {
   14062     int max_depth, min_depth;
   14063     int from_root;
   14064     int ret, depth;
   14065     int eval_all_nodes;
   14066     xmlNodePtr cur = NULL, limit = NULL;
   14067     xmlStreamCtxtPtr patstream = NULL;
   14068 
   14069     int nb_nodes = 0;
   14070 
   14071     if ((ctxt == NULL) || (comp == NULL))
   14072         return(-1);
   14073     max_depth = xmlPatternMaxDepth(comp);
   14074     if (max_depth == -1)
   14075         return(-1);
   14076     if (max_depth == -2)
   14077         max_depth = 10000;
   14078     min_depth = xmlPatternMinDepth(comp);
   14079     if (min_depth == -1)
   14080         return(-1);
   14081     from_root = xmlPatternFromRoot(comp);
   14082     if (from_root < 0)
   14083         return(-1);
   14084 #if 0
   14085     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14086 #endif
   14087 
   14088     if (! toBool) {
   14089 	if (resultSeq == NULL)
   14090 	    return(-1);
   14091 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14092 	if (*resultSeq == NULL)
   14093 	    return(-1);
   14094     }
   14095 
   14096     /*
   14097      * handle the special cases of "/" amd "." being matched
   14098      */
   14099     if (min_depth == 0) {
   14100 	if (from_root) {
   14101 	    /* Select "/" */
   14102 	    if (toBool)
   14103 		return(1);
   14104 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14105 		(xmlNodePtr) ctxt->doc);
   14106 	} else {
   14107 	    /* Select "self::node()" */
   14108 	    if (toBool)
   14109 		return(1);
   14110 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14111 	}
   14112     }
   14113     if (max_depth == 0) {
   14114 	return(0);
   14115     }
   14116 
   14117     if (from_root) {
   14118         cur = (xmlNodePtr)ctxt->doc;
   14119     } else if (ctxt->node != NULL) {
   14120         switch (ctxt->node->type) {
   14121             case XML_ELEMENT_NODE:
   14122             case XML_DOCUMENT_NODE:
   14123             case XML_DOCUMENT_FRAG_NODE:
   14124             case XML_HTML_DOCUMENT_NODE:
   14125 #ifdef LIBXML_DOCB_ENABLED
   14126             case XML_DOCB_DOCUMENT_NODE:
   14127 #endif
   14128 	        cur = ctxt->node;
   14129 		break;
   14130             case XML_ATTRIBUTE_NODE:
   14131             case XML_TEXT_NODE:
   14132             case XML_CDATA_SECTION_NODE:
   14133             case XML_ENTITY_REF_NODE:
   14134             case XML_ENTITY_NODE:
   14135             case XML_PI_NODE:
   14136             case XML_COMMENT_NODE:
   14137             case XML_NOTATION_NODE:
   14138             case XML_DTD_NODE:
   14139             case XML_DOCUMENT_TYPE_NODE:
   14140             case XML_ELEMENT_DECL:
   14141             case XML_ATTRIBUTE_DECL:
   14142             case XML_ENTITY_DECL:
   14143             case XML_NAMESPACE_DECL:
   14144             case XML_XINCLUDE_START:
   14145             case XML_XINCLUDE_END:
   14146 		break;
   14147 	}
   14148 	limit = cur;
   14149     }
   14150     if (cur == NULL) {
   14151         return(0);
   14152     }
   14153 
   14154     patstream = xmlPatternGetStreamCtxt(comp);
   14155     if (patstream == NULL) {
   14156 	/*
   14157 	* QUESTION TODO: Is this an error?
   14158 	*/
   14159 	return(0);
   14160     }
   14161 
   14162     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14163 
   14164     if (from_root) {
   14165 	ret = xmlStreamPush(patstream, NULL, NULL);
   14166 	if (ret < 0) {
   14167 	} else if (ret == 1) {
   14168 	    if (toBool)
   14169 		goto return_1;
   14170 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14171 	}
   14172     }
   14173     depth = 0;
   14174     goto scan_children;
   14175 next_node:
   14176     do {
   14177         nb_nodes++;
   14178 
   14179 	switch (cur->type) {
   14180 	    case XML_ELEMENT_NODE:
   14181 	    case XML_TEXT_NODE:
   14182 	    case XML_CDATA_SECTION_NODE:
   14183 	    case XML_COMMENT_NODE:
   14184 	    case XML_PI_NODE:
   14185 		if (cur->type == XML_ELEMENT_NODE) {
   14186 		    ret = xmlStreamPush(patstream, cur->name,
   14187 				(cur->ns ? cur->ns->href : NULL));
   14188 		} else if (eval_all_nodes)
   14189 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14190 		else
   14191 		    break;
   14192 
   14193 		if (ret < 0) {
   14194 		    /* NOP. */
   14195 		} else if (ret == 1) {
   14196 		    if (toBool)
   14197 			goto return_1;
   14198 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14199 		}
   14200 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14201 		    ret = xmlStreamPop(patstream);
   14202 		    while (cur->next != NULL) {
   14203 			cur = cur->next;
   14204 			if ((cur->type != XML_ENTITY_DECL) &&
   14205 			    (cur->type != XML_DTD_NODE))
   14206 			    goto next_node;
   14207 		    }
   14208 		}
   14209 	    default:
   14210 		break;
   14211 	}
   14212 
   14213 scan_children:
   14214 	if ((cur->children != NULL) && (depth < max_depth)) {
   14215 	    /*
   14216 	     * Do not descend on entities declarations
   14217 	     */
   14218 	    if (cur->children->type != XML_ENTITY_DECL) {
   14219 		cur = cur->children;
   14220 		depth++;
   14221 		/*
   14222 		 * Skip DTDs
   14223 		 */
   14224 		if (cur->type != XML_DTD_NODE)
   14225 		    continue;
   14226 	    }
   14227 	}
   14228 
   14229 	if (cur == limit)
   14230 	    break;
   14231 
   14232 	while (cur->next != NULL) {
   14233 	    cur = cur->next;
   14234 	    if ((cur->type != XML_ENTITY_DECL) &&
   14235 		(cur->type != XML_DTD_NODE))
   14236 		goto next_node;
   14237 	}
   14238 
   14239 	do {
   14240 	    cur = cur->parent;
   14241 	    depth--;
   14242 	    if ((cur == NULL) || (cur == limit))
   14243 	        goto done;
   14244 	    if (cur->type == XML_ELEMENT_NODE) {
   14245 		ret = xmlStreamPop(patstream);
   14246 	    } else if ((eval_all_nodes) &&
   14247 		((cur->type == XML_TEXT_NODE) ||
   14248 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14249 		 (cur->type == XML_COMMENT_NODE) ||
   14250 		 (cur->type == XML_PI_NODE)))
   14251 	    {
   14252 		ret = xmlStreamPop(patstream);
   14253 	    }
   14254 	    if (cur->next != NULL) {
   14255 		cur = cur->next;
   14256 		break;
   14257 	    }
   14258 	} while (cur != NULL);
   14259 
   14260     } while ((cur != NULL) && (depth >= 0));
   14261 
   14262 done:
   14263 
   14264 #if 0
   14265     printf("stream eval: checked %d nodes selected %d\n",
   14266            nb_nodes, retObj->nodesetval->nodeNr);
   14267 #endif
   14268 
   14269     if (patstream)
   14270 	xmlFreeStreamCtxt(patstream);
   14271     return(0);
   14272 
   14273 return_1:
   14274     if (patstream)
   14275 	xmlFreeStreamCtxt(patstream);
   14276     return(1);
   14277 }
   14278 #endif /* XPATH_STREAMING */
   14279 
   14280 /**
   14281  * xmlXPathRunEval:
   14282  * @ctxt:  the XPath parser context with the compiled expression
   14283  * @toBool:  evaluate to a boolean result
   14284  *
   14285  * Evaluate the Precompiled XPath expression in the given context.
   14286  */
   14287 static int
   14288 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14289 {
   14290     xmlXPathCompExprPtr comp;
   14291 
   14292     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14293 	return(-1);
   14294 
   14295     if (ctxt->valueTab == NULL) {
   14296 	/* Allocate the value stack */
   14297 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14298 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14299 	if (ctxt->valueTab == NULL) {
   14300 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14301 	    xmlFree(ctxt);
   14302 	}
   14303 	ctxt->valueNr = 0;
   14304 	ctxt->valueMax = 10;
   14305 	ctxt->value = NULL;
   14306     }
   14307 #ifdef XPATH_STREAMING
   14308     if (ctxt->comp->stream) {
   14309 	int res;
   14310 
   14311 	if (toBool) {
   14312 	    /*
   14313 	    * Evaluation to boolean result.
   14314 	    */
   14315 	    res = xmlXPathRunStreamEval(ctxt->context,
   14316 		ctxt->comp->stream, NULL, 1);
   14317 	    if (res != -1)
   14318 		return(res);
   14319 	} else {
   14320 	    xmlXPathObjectPtr resObj = NULL;
   14321 
   14322 	    /*
   14323 	    * Evaluation to a sequence.
   14324 	    */
   14325 	    res = xmlXPathRunStreamEval(ctxt->context,
   14326 		ctxt->comp->stream, &resObj, 0);
   14327 
   14328 	    if ((res != -1) && (resObj != NULL)) {
   14329 		valuePush(ctxt, resObj);
   14330 		return(0);
   14331 	    }
   14332 	    if (resObj != NULL)
   14333 		xmlXPathReleaseObject(ctxt->context, resObj);
   14334 	}
   14335 	/*
   14336 	* QUESTION TODO: This falls back to normal XPath evaluation
   14337 	* if res == -1. Is this intended?
   14338 	*/
   14339     }
   14340 #endif
   14341     comp = ctxt->comp;
   14342     if (comp->last < 0) {
   14343 	xmlGenericError(xmlGenericErrorContext,
   14344 	    "xmlXPathRunEval: last is less than zero\n");
   14345 	return(-1);
   14346     }
   14347     if (toBool)
   14348 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14349 	    &comp->steps[comp->last], 0));
   14350     else
   14351 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14352 
   14353     return(0);
   14354 }
   14355 
   14356 /************************************************************************
   14357  *									*
   14358  *			Public interfaces				*
   14359  *									*
   14360  ************************************************************************/
   14361 
   14362 /**
   14363  * xmlXPathEvalPredicate:
   14364  * @ctxt:  the XPath context
   14365  * @res:  the Predicate Expression evaluation result
   14366  *
   14367  * Evaluate a predicate result for the current node.
   14368  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14369  * the result to a boolean. If the result is a number, the result will
   14370  * be converted to true if the number is equal to the position of the
   14371  * context node in the context node list (as returned by the position
   14372  * function) and will be converted to false otherwise; if the result
   14373  * is not a number, then the result will be converted as if by a call
   14374  * to the boolean function.
   14375  *
   14376  * Returns 1 if predicate is true, 0 otherwise
   14377  */
   14378 int
   14379 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14380     if ((ctxt == NULL) || (res == NULL)) return(0);
   14381     switch (res->type) {
   14382         case XPATH_BOOLEAN:
   14383 	    return(res->boolval);
   14384         case XPATH_NUMBER:
   14385 	    return(res->floatval == ctxt->proximityPosition);
   14386         case XPATH_NODESET:
   14387         case XPATH_XSLT_TREE:
   14388 	    if (res->nodesetval == NULL)
   14389 		return(0);
   14390 	    return(res->nodesetval->nodeNr != 0);
   14391         case XPATH_STRING:
   14392 	    return((res->stringval != NULL) &&
   14393 	           (xmlStrlen(res->stringval) != 0));
   14394         default:
   14395 	    STRANGE
   14396     }
   14397     return(0);
   14398 }
   14399 
   14400 /**
   14401  * xmlXPathEvaluatePredicateResult:
   14402  * @ctxt:  the XPath Parser context
   14403  * @res:  the Predicate Expression evaluation result
   14404  *
   14405  * Evaluate a predicate result for the current node.
   14406  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14407  * the result to a boolean. If the result is a number, the result will
   14408  * be converted to true if the number is equal to the position of the
   14409  * context node in the context node list (as returned by the position
   14410  * function) and will be converted to false otherwise; if the result
   14411  * is not a number, then the result will be converted as if by a call
   14412  * to the boolean function.
   14413  *
   14414  * Returns 1 if predicate is true, 0 otherwise
   14415  */
   14416 int
   14417 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14418                                 xmlXPathObjectPtr res) {
   14419     if ((ctxt == NULL) || (res == NULL)) return(0);
   14420     switch (res->type) {
   14421         case XPATH_BOOLEAN:
   14422 	    return(res->boolval);
   14423         case XPATH_NUMBER:
   14424 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14425 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14426 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14427 #else
   14428 	    return(res->floatval == ctxt->context->proximityPosition);
   14429 #endif
   14430         case XPATH_NODESET:
   14431         case XPATH_XSLT_TREE:
   14432 	    if (res->nodesetval == NULL)
   14433 		return(0);
   14434 	    return(res->nodesetval->nodeNr != 0);
   14435         case XPATH_STRING:
   14436 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14437 #ifdef LIBXML_XPTR_ENABLED
   14438 	case XPATH_LOCATIONSET:{
   14439 	    xmlLocationSetPtr ptr = res->user;
   14440 	    if (ptr == NULL)
   14441 	        return(0);
   14442 	    return (ptr->locNr != 0);
   14443 	    }
   14444 #endif
   14445         default:
   14446 	    STRANGE
   14447     }
   14448     return(0);
   14449 }
   14450 
   14451 #ifdef XPATH_STREAMING
   14452 /**
   14453  * xmlXPathTryStreamCompile:
   14454  * @ctxt: an XPath context
   14455  * @str:  the XPath expression
   14456  *
   14457  * Try to compile the XPath expression as a streamable subset.
   14458  *
   14459  * Returns the compiled expression or NULL if failed to compile.
   14460  */
   14461 static xmlXPathCompExprPtr
   14462 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14463     /*
   14464      * Optimization: use streaming patterns when the XPath expression can
   14465      * be compiled to a stream lookup
   14466      */
   14467     xmlPatternPtr stream;
   14468     xmlXPathCompExprPtr comp;
   14469     xmlDictPtr dict = NULL;
   14470     const xmlChar **namespaces = NULL;
   14471     xmlNsPtr ns;
   14472     int i, j;
   14473 
   14474     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14475         (!xmlStrchr(str, '@'))) {
   14476 	const xmlChar *tmp;
   14477 
   14478 	/*
   14479 	 * We don't try to handle expressions using the verbose axis
   14480 	 * specifiers ("::"), just the simplied form at this point.
   14481 	 * Additionally, if there is no list of namespaces available and
   14482 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14483 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14484 	 *  to have a list of namespaces at compilation time in order to
   14485 	 *  compile prefixed name tests.
   14486 	 */
   14487 	tmp = xmlStrchr(str, ':');
   14488 	if ((tmp != NULL) &&
   14489 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14490 	    return(NULL);
   14491 
   14492 	if (ctxt != NULL) {
   14493 	    dict = ctxt->dict;
   14494 	    if (ctxt->nsNr > 0) {
   14495 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14496 		if (namespaces == NULL) {
   14497 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14498 		    return(NULL);
   14499 		}
   14500 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14501 		    ns = ctxt->namespaces[j];
   14502 		    namespaces[i++] = ns->href;
   14503 		    namespaces[i++] = ns->prefix;
   14504 		}
   14505 		namespaces[i++] = NULL;
   14506 		namespaces[i++] = NULL;
   14507 	    }
   14508 	}
   14509 
   14510 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14511 			&namespaces[0]);
   14512 	if (namespaces != NULL) {
   14513 	    xmlFree((xmlChar **)namespaces);
   14514 	}
   14515 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14516 	    comp = xmlXPathNewCompExpr();
   14517 	    if (comp == NULL) {
   14518 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14519 		return(NULL);
   14520 	    }
   14521 	    comp->stream = stream;
   14522 	    comp->dict = dict;
   14523 	    if (comp->dict)
   14524 		xmlDictReference(comp->dict);
   14525 	    return(comp);
   14526 	}
   14527 	xmlFreePattern(stream);
   14528     }
   14529     return(NULL);
   14530 }
   14531 #endif /* XPATH_STREAMING */
   14532 
   14533 static int
   14534 xmlXPathCanRewriteDosExpression(xmlChar *expr)
   14535 {
   14536     if (expr == NULL)
   14537 	return(0);
   14538     do {
   14539         if ((*expr == '/') && (*(++expr) == '/'))
   14540 	    return(1);
   14541     } while (*expr++);
   14542     return(0);
   14543 }
   14544 static void
   14545 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14546 {
   14547     /*
   14548     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14549     * internal representation.
   14550     */
   14551     if (op->ch1 != -1) {
   14552 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14553 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
   14554 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
   14555 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
   14556 	{
   14557 	    /*
   14558 	    * This is a "child::foo"
   14559 	    */
   14560 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14561 
   14562 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14563 		(prevop->ch1 != -1) &&
   14564 		((xmlXPathAxisVal) prevop->value ==
   14565 		    AXIS_DESCENDANT_OR_SELF) &&
   14566 		(prevop->ch2 == -1) &&
   14567 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14568 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
   14569 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
   14570 	    {
   14571 		/*
   14572 		* This is a "/descendant-or-self::node()" without predicates.
   14573 		* Eliminate it.
   14574 		*/
   14575 		op->ch1 = prevop->ch1;
   14576 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
   14577 	    }
   14578 	}
   14579 	if (op->ch1 != -1)
   14580 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
   14581     }
   14582     if (op->ch2 != -1)
   14583 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
   14584 }
   14585 
   14586 /**
   14587  * xmlXPathCtxtCompile:
   14588  * @ctxt: an XPath context
   14589  * @str:  the XPath expression
   14590  *
   14591  * Compile an XPath expression
   14592  *
   14593  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14594  *         the caller has to free the object.
   14595  */
   14596 xmlXPathCompExprPtr
   14597 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14598     xmlXPathParserContextPtr pctxt;
   14599     xmlXPathCompExprPtr comp;
   14600 
   14601 #ifdef XPATH_STREAMING
   14602     comp = xmlXPathTryStreamCompile(ctxt, str);
   14603     if (comp != NULL)
   14604         return(comp);
   14605 #endif
   14606 
   14607     xmlXPathInit();
   14608 
   14609     pctxt = xmlXPathNewParserContext(str, ctxt);
   14610     if (pctxt == NULL)
   14611         return NULL;
   14612     xmlXPathCompileExpr(pctxt, 1);
   14613 
   14614     if( pctxt->error != XPATH_EXPRESSION_OK )
   14615     {
   14616         xmlXPathFreeParserContext(pctxt);
   14617         return(NULL);
   14618     }
   14619 
   14620     if (*pctxt->cur != 0) {
   14621 	/*
   14622 	 * aleksey: in some cases this line prints *second* error message
   14623 	 * (see bug #78858) and probably this should be fixed.
   14624 	 * However, we are not sure that all error messages are printed
   14625 	 * out in other places. It's not critical so we leave it as-is for now
   14626 	 */
   14627 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14628 	comp = NULL;
   14629     } else {
   14630 	comp = pctxt->comp;
   14631 	pctxt->comp = NULL;
   14632     }
   14633     xmlXPathFreeParserContext(pctxt);
   14634 
   14635     if (comp != NULL) {
   14636 	comp->expr = xmlStrdup(str);
   14637 #ifdef DEBUG_EVAL_COUNTS
   14638 	comp->string = xmlStrdup(str);
   14639 	comp->nb = 0;
   14640 #endif
   14641 	if ((comp->expr != NULL) &&
   14642 	    (comp->nbStep > 2) &&
   14643 	    (comp->last >= 0) &&
   14644 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
   14645 	{
   14646 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
   14647 	}
   14648     }
   14649     return(comp);
   14650 }
   14651 
   14652 /**
   14653  * xmlXPathCompile:
   14654  * @str:  the XPath expression
   14655  *
   14656  * Compile an XPath expression
   14657  *
   14658  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14659  *         the caller has to free the object.
   14660  */
   14661 xmlXPathCompExprPtr
   14662 xmlXPathCompile(const xmlChar *str) {
   14663     return(xmlXPathCtxtCompile(NULL, str));
   14664 }
   14665 
   14666 /**
   14667  * xmlXPathCompiledEvalInternal:
   14668  * @comp:  the compiled XPath expression
   14669  * @ctxt:  the XPath context
   14670  * @resObj: the resulting XPath object or NULL
   14671  * @toBool: 1 if only a boolean result is requested
   14672  *
   14673  * Evaluate the Precompiled XPath expression in the given context.
   14674  * The caller has to free @resObj.
   14675  *
   14676  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14677  *         the caller has to free the object.
   14678  */
   14679 static int
   14680 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14681 			     xmlXPathContextPtr ctxt,
   14682 			     xmlXPathObjectPtr *resObj,
   14683 			     int toBool)
   14684 {
   14685     xmlXPathParserContextPtr pctxt;
   14686 #ifndef LIBXML_THREAD_ENABLED
   14687     static int reentance = 0;
   14688 #endif
   14689     int res;
   14690 
   14691     CHECK_CTXT_NEG(ctxt)
   14692 
   14693     if (comp == NULL)
   14694 	return(-1);
   14695     xmlXPathInit();
   14696 
   14697 #ifndef LIBXML_THREAD_ENABLED
   14698     reentance++;
   14699     if (reentance > 1)
   14700 	xmlXPathDisableOptimizer = 1;
   14701 #endif
   14702 
   14703 #ifdef DEBUG_EVAL_COUNTS
   14704     comp->nb++;
   14705     if ((comp->string != NULL) && (comp->nb > 100)) {
   14706 	fprintf(stderr, "100 x %s\n", comp->string);
   14707 	comp->nb = 0;
   14708     }
   14709 #endif
   14710     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14711     res = xmlXPathRunEval(pctxt, toBool);
   14712 
   14713     if (resObj) {
   14714 	if (pctxt->value == NULL) {
   14715 	    xmlGenericError(xmlGenericErrorContext,
   14716 		"xmlXPathCompiledEval: evaluation failed\n");
   14717 	    *resObj = NULL;
   14718 	} else {
   14719 	    *resObj = valuePop(pctxt);
   14720 	}
   14721     }
   14722 
   14723     /*
   14724     * Pop all remaining objects from the stack.
   14725     */
   14726     if (pctxt->valueNr > 0) {
   14727 	xmlXPathObjectPtr tmp;
   14728 	int stack = 0;
   14729 
   14730 	do {
   14731 	    tmp = valuePop(pctxt);
   14732 	    if (tmp != NULL) {
   14733 		stack++;
   14734 		xmlXPathReleaseObject(ctxt, tmp);
   14735 	    }
   14736 	} while (tmp != NULL);
   14737 	if ((stack != 0) &&
   14738 	    ((toBool) || ((resObj) && (*resObj))))
   14739 	{
   14740 	    xmlGenericError(xmlGenericErrorContext,
   14741 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14742 		stack);
   14743 	}
   14744     }
   14745 
   14746     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14747 	xmlXPathFreeObject(*resObj);
   14748 	*resObj = NULL;
   14749     }
   14750     pctxt->comp = NULL;
   14751     xmlXPathFreeParserContext(pctxt);
   14752 #ifndef LIBXML_THREAD_ENABLED
   14753     reentance--;
   14754 #endif
   14755 
   14756     return(res);
   14757 }
   14758 
   14759 /**
   14760  * xmlXPathCompiledEval:
   14761  * @comp:  the compiled XPath expression
   14762  * @ctx:  the XPath context
   14763  *
   14764  * Evaluate the Precompiled XPath expression in the given context.
   14765  *
   14766  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14767  *         the caller has to free the object.
   14768  */
   14769 xmlXPathObjectPtr
   14770 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14771 {
   14772     xmlXPathObjectPtr res = NULL;
   14773 
   14774     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14775     return(res);
   14776 }
   14777 
   14778 /**
   14779  * xmlXPathCompiledEvalToBoolean:
   14780  * @comp:  the compiled XPath expression
   14781  * @ctxt:  the XPath context
   14782  *
   14783  * Applies the XPath boolean() function on the result of the given
   14784  * compiled expression.
   14785  *
   14786  * Returns 1 if the expression evaluated to true, 0 if to false and
   14787  *         -1 in API and internal errors.
   14788  */
   14789 int
   14790 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14791 			      xmlXPathContextPtr ctxt)
   14792 {
   14793     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14794 }
   14795 
   14796 /**
   14797  * xmlXPathEvalExpr:
   14798  * @ctxt:  the XPath Parser context
   14799  *
   14800  * Parse and evaluate an XPath expression in the given context,
   14801  * then push the result on the context stack
   14802  */
   14803 void
   14804 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14805 #ifdef XPATH_STREAMING
   14806     xmlXPathCompExprPtr comp;
   14807 #endif
   14808 
   14809     if (ctxt == NULL) return;
   14810 
   14811 #ifdef XPATH_STREAMING
   14812     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14813     if (comp != NULL) {
   14814         if (ctxt->comp != NULL)
   14815 	    xmlXPathFreeCompExpr(ctxt->comp);
   14816         ctxt->comp = comp;
   14817 	if (ctxt->cur != NULL)
   14818 	    while (*ctxt->cur != 0) ctxt->cur++;
   14819     } else
   14820 #endif
   14821     {
   14822 	xmlXPathCompileExpr(ctxt, 1);
   14823 	/*
   14824 	* In this scenario the expression string will sit in ctxt->base.
   14825 	*/
   14826 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   14827 	    (ctxt->comp != NULL) &&
   14828 	    (ctxt->base != NULL) &&
   14829 	    (ctxt->comp->nbStep > 2) &&
   14830 	    (ctxt->comp->last >= 0) &&
   14831 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
   14832 	{
   14833 	    xmlXPathRewriteDOSExpression(ctxt->comp,
   14834 		&ctxt->comp->steps[ctxt->comp->last]);
   14835 	}
   14836     }
   14837     CHECK_ERROR;
   14838     xmlXPathRunEval(ctxt, 0);
   14839 }
   14840 
   14841 /**
   14842  * xmlXPathEval:
   14843  * @str:  the XPath expression
   14844  * @ctx:  the XPath context
   14845  *
   14846  * Evaluate the XPath Location Path in the given context.
   14847  *
   14848  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14849  *         the caller has to free the object.
   14850  */
   14851 xmlXPathObjectPtr
   14852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   14853     xmlXPathParserContextPtr ctxt;
   14854     xmlXPathObjectPtr res, tmp, init = NULL;
   14855     int stack = 0;
   14856 
   14857     CHECK_CTXT(ctx)
   14858 
   14859     xmlXPathInit();
   14860 
   14861     ctxt = xmlXPathNewParserContext(str, ctx);
   14862     if (ctxt == NULL)
   14863         return NULL;
   14864     xmlXPathEvalExpr(ctxt);
   14865 
   14866     if (ctxt->value == NULL) {
   14867 	xmlGenericError(xmlGenericErrorContext,
   14868 		"xmlXPathEval: evaluation failed\n");
   14869 	res = NULL;
   14870     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   14871 #ifdef XPATH_STREAMING
   14872             && (ctxt->comp->stream == NULL)
   14873 #endif
   14874 	      ) {
   14875 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14876 	res = NULL;
   14877     } else {
   14878 	res = valuePop(ctxt);
   14879     }
   14880 
   14881     do {
   14882         tmp = valuePop(ctxt);
   14883 	if (tmp != NULL) {
   14884 	    if (tmp != init)
   14885 		stack++;
   14886 	    xmlXPathReleaseObject(ctx, tmp);
   14887         }
   14888     } while (tmp != NULL);
   14889     if ((stack != 0) && (res != NULL)) {
   14890 	xmlGenericError(xmlGenericErrorContext,
   14891 		"xmlXPathEval: %d object left on the stack\n",
   14892 	        stack);
   14893     }
   14894     if (ctxt->error != XPATH_EXPRESSION_OK) {
   14895 	xmlXPathFreeObject(res);
   14896 	res = NULL;
   14897     }
   14898 
   14899     xmlXPathFreeParserContext(ctxt);
   14900     return(res);
   14901 }
   14902 
   14903 /**
   14904  * xmlXPathEvalExpression:
   14905  * @str:  the XPath expression
   14906  * @ctxt:  the XPath context
   14907  *
   14908  * Evaluate the XPath expression in the given context.
   14909  *
   14910  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14911  *         the caller has to free the object.
   14912  */
   14913 xmlXPathObjectPtr
   14914 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   14915     xmlXPathParserContextPtr pctxt;
   14916     xmlXPathObjectPtr res, tmp;
   14917     int stack = 0;
   14918 
   14919     CHECK_CTXT(ctxt)
   14920 
   14921     xmlXPathInit();
   14922 
   14923     pctxt = xmlXPathNewParserContext(str, ctxt);
   14924     if (pctxt == NULL)
   14925         return NULL;
   14926     xmlXPathEvalExpr(pctxt);
   14927 
   14928     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   14929 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14930 	res = NULL;
   14931     } else {
   14932 	res = valuePop(pctxt);
   14933     }
   14934     do {
   14935         tmp = valuePop(pctxt);
   14936 	if (tmp != NULL) {
   14937 	    xmlXPathReleaseObject(ctxt, tmp);
   14938 	    stack++;
   14939 	}
   14940     } while (tmp != NULL);
   14941     if ((stack != 0) && (res != NULL)) {
   14942 	xmlGenericError(xmlGenericErrorContext,
   14943 		"xmlXPathEvalExpression: %d object left on the stack\n",
   14944 	        stack);
   14945     }
   14946     xmlXPathFreeParserContext(pctxt);
   14947     return(res);
   14948 }
   14949 
   14950 /************************************************************************
   14951  *									*
   14952  *	Extra functions not pertaining to the XPath spec		*
   14953  *									*
   14954  ************************************************************************/
   14955 /**
   14956  * xmlXPathEscapeUriFunction:
   14957  * @ctxt:  the XPath Parser context
   14958  * @nargs:  the number of arguments
   14959  *
   14960  * Implement the escape-uri() XPath function
   14961  *    string escape-uri(string $str, bool $escape-reserved)
   14962  *
   14963  * This function applies the URI escaping rules defined in section 2 of [RFC
   14964  * 2396] to the string supplied as $uri-part, which typically represents all
   14965  * or part of a URI. The effect of the function is to replace any special
   14966  * character in the string by an escape sequence of the form %xx%yy...,
   14967  * where xxyy... is the hexadecimal representation of the octets used to
   14968  * represent the character in UTF-8.
   14969  *
   14970  * The set of characters that are escaped depends on the setting of the
   14971  * boolean argument $escape-reserved.
   14972  *
   14973  * If $escape-reserved is true, all characters are escaped other than lower
   14974  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   14975  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   14976  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   14977  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   14978  * A-F).
   14979  *
   14980  * If $escape-reserved is false, the behavior differs in that characters
   14981  * referred to in [RFC 2396] as reserved characters are not escaped. These
   14982  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   14983  *
   14984  * [RFC 2396] does not define whether escaped URIs should use lower case or
   14985  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   14986  * compared using string comparison functions, this function must always use
   14987  * the upper-case letters A-F.
   14988  *
   14989  * Generally, $escape-reserved should be set to true when escaping a string
   14990  * that is to form a single part of a URI, and to false when escaping an
   14991  * entire URI or URI reference.
   14992  *
   14993  * In the case of non-ascii characters, the string is encoded according to
   14994  * utf-8 and then converted according to RFC 2396.
   14995  *
   14996  * Examples
   14997  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   14998  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   14999  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15000  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15001  *
   15002  */
   15003 static void
   15004 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15005     xmlXPathObjectPtr str;
   15006     int escape_reserved;
   15007     xmlBufferPtr target;
   15008     xmlChar *cptr;
   15009     xmlChar escape[4];
   15010 
   15011     CHECK_ARITY(2);
   15012 
   15013     escape_reserved = xmlXPathPopBoolean(ctxt);
   15014 
   15015     CAST_TO_STRING;
   15016     str = valuePop(ctxt);
   15017 
   15018     target = xmlBufferCreate();
   15019 
   15020     escape[0] = '%';
   15021     escape[3] = 0;
   15022 
   15023     if (target) {
   15024 	for (cptr = str->stringval; *cptr; cptr++) {
   15025 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15026 		(*cptr >= 'a' && *cptr <= 'z') ||
   15027 		(*cptr >= '0' && *cptr <= '9') ||
   15028 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15029 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15030 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15031 		(*cptr == '%' &&
   15032 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15033 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15034 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15035 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15036 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15037 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15038 		(!escape_reserved &&
   15039 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15040 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15041 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15042 		  *cptr == ','))) {
   15043 		xmlBufferAdd(target, cptr, 1);
   15044 	    } else {
   15045 		if ((*cptr >> 4) < 10)
   15046 		    escape[1] = '0' + (*cptr >> 4);
   15047 		else
   15048 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15049 		if ((*cptr & 0xF) < 10)
   15050 		    escape[2] = '0' + (*cptr & 0xF);
   15051 		else
   15052 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15053 
   15054 		xmlBufferAdd(target, &escape[0], 3);
   15055 	    }
   15056 	}
   15057     }
   15058     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15059 	xmlBufferContent(target)));
   15060     xmlBufferFree(target);
   15061     xmlXPathReleaseObject(ctxt->context, str);
   15062 }
   15063 
   15064 /**
   15065  * xmlXPathRegisterAllFunctions:
   15066  * @ctxt:  the XPath context
   15067  *
   15068  * Registers all default XPath functions in this context
   15069  */
   15070 void
   15071 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15072 {
   15073     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15074                          xmlXPathBooleanFunction);
   15075     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15076                          xmlXPathCeilingFunction);
   15077     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15078                          xmlXPathCountFunction);
   15079     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15080                          xmlXPathConcatFunction);
   15081     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15082                          xmlXPathContainsFunction);
   15083     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15084                          xmlXPathIdFunction);
   15085     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15086                          xmlXPathFalseFunction);
   15087     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15088                          xmlXPathFloorFunction);
   15089     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15090                          xmlXPathLastFunction);
   15091     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15092                          xmlXPathLangFunction);
   15093     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15094                          xmlXPathLocalNameFunction);
   15095     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15096                          xmlXPathNotFunction);
   15097     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15098                          xmlXPathNameFunction);
   15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15100                          xmlXPathNamespaceURIFunction);
   15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15102                          xmlXPathNormalizeFunction);
   15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15104                          xmlXPathNumberFunction);
   15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15106                          xmlXPathPositionFunction);
   15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15108                          xmlXPathRoundFunction);
   15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15110                          xmlXPathStringFunction);
   15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15112                          xmlXPathStringLengthFunction);
   15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15114                          xmlXPathStartsWithFunction);
   15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15116                          xmlXPathSubstringFunction);
   15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15118                          xmlXPathSubstringBeforeFunction);
   15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15120                          xmlXPathSubstringAfterFunction);
   15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15122                          xmlXPathSumFunction);
   15123     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15124                          xmlXPathTrueFunction);
   15125     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15126                          xmlXPathTranslateFunction);
   15127 
   15128     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15129 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15130                          xmlXPathEscapeUriFunction);
   15131 }
   15132 
   15133 #endif /* LIBXML_XPATH_ENABLED */
   15134 #define bottom_xpath
   15135 #include "elfgcchack.h"
   15136