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 if any */
   11740 	        tmp = valuePop(ctxt);
   11741 	        while (tmp != contextObj) {
   11742 	            /*
   11743 	             * Free up the result
   11744 	             * then pop off contextObj, which will be freed later
   11745 	             */
   11746 	             xmlXPathReleaseObject(xpctxt, tmp);
   11747 	             tmp = valuePop(ctxt);
   11748 	        }
   11749 		goto evaluation_error;
   11750 	    }
   11751 
   11752 	    if (res)
   11753 		pos++;
   11754 
   11755 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11756 		/*
   11757 		* Fits in the requested range.
   11758 		*/
   11759 		newContextSize++;
   11760 		if (minPos == maxPos) {
   11761 		    /*
   11762 		    * Only 1 node was requested.
   11763 		    */
   11764 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11765 			/*
   11766 			* As always: take care of those nasty
   11767 			* namespace nodes.
   11768 			*/
   11769 			set->nodeTab[i] = NULL;
   11770 		    }
   11771 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11772 		    set->nodeNr = 1;
   11773 		    set->nodeTab[0] = contextNode;
   11774 		    goto evaluation_exit;
   11775 		}
   11776 		if (pos == maxPos) {
   11777 		    /*
   11778 		    * We are done.
   11779 		    */
   11780 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11781 		    goto evaluation_exit;
   11782 		}
   11783 	    } else {
   11784 		/*
   11785 		* Remove the entry from the initial node set.
   11786 		*/
   11787 		set->nodeTab[i] = NULL;
   11788 		if (contextNode->type == XML_NAMESPACE_DECL)
   11789 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11790 	    }
   11791 	    if (exprRes != NULL) {
   11792 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11793 		exprRes = NULL;
   11794 	    }
   11795 	    if (ctxt->value == contextObj) {
   11796 		/*
   11797 		* Don't free the temporary XPath object holding the
   11798 		* context node, in order to avoid massive recreation
   11799 		* inside this loop.
   11800 		*/
   11801 		valuePop(ctxt);
   11802 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11803 	    } else {
   11804 		/*
   11805 		* The object was lost in the evaluation machinery.
   11806 		* Can this happen? Maybe in case of internal-errors.
   11807 		*/
   11808 		contextObj = NULL;
   11809 	    }
   11810 	}
   11811 	goto evaluation_exit;
   11812 
   11813 evaluation_error:
   11814 	xmlXPathNodeSetClear(set, hasNsNodes);
   11815 	newContextSize = 0;
   11816 
   11817 evaluation_exit:
   11818 	if (contextObj != NULL) {
   11819 	    if (ctxt->value == contextObj)
   11820 		valuePop(ctxt);
   11821 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11822 	}
   11823 	if (exprRes != NULL)
   11824 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11825 	/*
   11826 	* Reset/invalidate the context.
   11827 	*/
   11828 	xpctxt->node = oldContextNode;
   11829 	xpctxt->doc = oldContextDoc;
   11830 	xpctxt->contextSize = -1;
   11831 	xpctxt->proximityPosition = -1;
   11832 	return(newContextSize);
   11833     }
   11834     return(contextSize);
   11835 }
   11836 
   11837 static int
   11838 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11839 			    xmlXPathStepOpPtr op,
   11840 			    int *maxPos)
   11841 {
   11842 
   11843     xmlXPathStepOpPtr exprOp;
   11844 
   11845     /*
   11846     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   11847     */
   11848 
   11849     /*
   11850     * If not -1, then ch1 will point to:
   11851     * 1) For predicates (XPATH_OP_PREDICATE):
   11852     *    - an inner predicate operator
   11853     * 2) For filters (XPATH_OP_FILTER):
   11854     *    - an inner filter operater OR
   11855     *    - an expression selecting the node set.
   11856     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   11857     */
   11858     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   11859 	return(0);
   11860 
   11861     if (op->ch2 != -1) {
   11862 	exprOp = &ctxt->comp->steps[op->ch2];
   11863     } else
   11864 	return(0);
   11865 
   11866     if ((exprOp != NULL) &&
   11867 	(exprOp->op == XPATH_OP_VALUE) &&
   11868 	(exprOp->value4 != NULL) &&
   11869 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   11870     {
   11871 	/*
   11872 	* We have a "[n]" predicate here.
   11873 	* TODO: Unfortunately this simplistic test here is not
   11874 	* able to detect a position() predicate in compound
   11875 	* expressions like "[@attr = 'a" and position() = 1],
   11876 	* and even not the usage of position() in
   11877 	* "[position() = 1]"; thus - obviously - a position-range,
   11878 	* like it "[position() < 5]", is also not detected.
   11879 	* Maybe we could rewrite the AST to ease the optimization.
   11880 	*/
   11881 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   11882 
   11883 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   11884 	    (float) *maxPos)
   11885 	{
   11886 	    return(1);
   11887 	}
   11888     }
   11889     return(0);
   11890 }
   11891 
   11892 static int
   11893 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   11894                            xmlXPathStepOpPtr op,
   11895 			   xmlNodePtr * first, xmlNodePtr * last,
   11896 			   int toBool)
   11897 {
   11898 
   11899 #define XP_TEST_HIT \
   11900     if (hasAxisRange != 0) { \
   11901 	if (++pos == maxPos) { \
   11902 	    addNode(seq, cur); \
   11903 	goto axis_range_end; } \
   11904     } else { \
   11905 	addNode(seq, cur); \
   11906 	if (breakOnFirstHit) goto first_hit; }
   11907 
   11908 #define XP_TEST_HIT_NS \
   11909     if (hasAxisRange != 0) { \
   11910 	if (++pos == maxPos) { \
   11911 	    hasNsNodes = 1; \
   11912 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
   11913 	goto axis_range_end; } \
   11914     } else { \
   11915 	hasNsNodes = 1; \
   11916 	xmlXPathNodeSetAddNs(seq, \
   11917 	xpctxt->node, (xmlNsPtr) cur); \
   11918 	if (breakOnFirstHit) goto first_hit; }
   11919 
   11920     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   11921     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   11922     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   11923     const xmlChar *prefix = op->value4;
   11924     const xmlChar *name = op->value5;
   11925     const xmlChar *URI = NULL;
   11926 
   11927 #ifdef DEBUG_STEP
   11928     int nbMatches = 0, prevMatches = 0;
   11929 #endif
   11930     int total = 0, hasNsNodes = 0;
   11931     /* The popped object holding the context nodes */
   11932     xmlXPathObjectPtr obj;
   11933     /* The set of context nodes for the node tests */
   11934     xmlNodeSetPtr contextSeq;
   11935     int contextIdx;
   11936     xmlNodePtr contextNode;
   11937     /* The context node for a compound traversal */
   11938     xmlNodePtr outerContextNode;
   11939     /* The final resulting node set wrt to all context nodes */
   11940     xmlNodeSetPtr outSeq;
   11941     /*
   11942     * The temporary resulting node set wrt 1 context node.
   11943     * Used to feed predicate evaluation.
   11944     */
   11945     xmlNodeSetPtr seq;
   11946     xmlNodePtr cur;
   11947     /* First predicate operator */
   11948     xmlXPathStepOpPtr predOp;
   11949     int maxPos; /* The requested position() (when a "[n]" predicate) */
   11950     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   11951     int breakOnFirstHit;
   11952 
   11953     xmlXPathTraversalFunction next = NULL;
   11954     /* compound axis traversal */
   11955     xmlXPathTraversalFunctionExt outerNext = NULL;
   11956     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   11957     xmlXPathNodeSetMergeFunction mergeAndClear;
   11958     xmlNodePtr oldContextNode;
   11959     xmlXPathContextPtr xpctxt = ctxt->context;
   11960 
   11961 
   11962     CHECK_TYPE0(XPATH_NODESET);
   11963     obj = valuePop(ctxt);
   11964     /*
   11965     * Setup namespaces.
   11966     */
   11967     if (prefix != NULL) {
   11968         URI = xmlXPathNsLookup(xpctxt, prefix);
   11969         if (URI == NULL) {
   11970 	    xmlXPathReleaseObject(xpctxt, obj);
   11971             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11972 	}
   11973     }
   11974     /*
   11975     * Setup axis.
   11976     *
   11977     * MAYBE FUTURE TODO: merging optimizations:
   11978     * - If the nodes to be traversed wrt to the initial nodes and
   11979     *   the current axis cannot overlap, then we could avoid searching
   11980     *   for duplicates during the merge.
   11981     *   But the question is how/when to evaluate if they cannot overlap.
   11982     *   Example: if we know that for two initial nodes, the one is
   11983     *   not in the ancestor-or-self axis of the other, then we could safely
   11984     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   11985     *   the descendant-or-self axis.
   11986     */
   11987     addNode = xmlXPathNodeSetAdd;
   11988     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   11989     switch (axis) {
   11990         case AXIS_ANCESTOR:
   11991             first = NULL;
   11992             next = xmlXPathNextAncestor;
   11993             break;
   11994         case AXIS_ANCESTOR_OR_SELF:
   11995             first = NULL;
   11996             next = xmlXPathNextAncestorOrSelf;
   11997             break;
   11998         case AXIS_ATTRIBUTE:
   11999             first = NULL;
   12000 	    last = NULL;
   12001             next = xmlXPathNextAttribute;
   12002 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12003             break;
   12004         case AXIS_CHILD:
   12005 	    last = NULL;
   12006 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
   12007 		/*
   12008 		* This iterator will give us only nodes which can
   12009 		* hold element nodes.
   12010 		*/
   12011 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
   12012 	    }
   12013 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12014 		(type == NODE_TYPE_NODE))
   12015 	    {
   12016 		/*
   12017 		* Optimization if an element node type is 'element'.
   12018 		*/
   12019 		next = xmlXPathNextChildElement;
   12020 	    } else
   12021 		next = xmlXPathNextChild;
   12022 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12023             break;
   12024         case AXIS_DESCENDANT:
   12025 	    last = NULL;
   12026             next = xmlXPathNextDescendant;
   12027             break;
   12028         case AXIS_DESCENDANT_OR_SELF:
   12029 	    last = NULL;
   12030             next = xmlXPathNextDescendantOrSelf;
   12031             break;
   12032         case AXIS_FOLLOWING:
   12033 	    last = NULL;
   12034             next = xmlXPathNextFollowing;
   12035             break;
   12036         case AXIS_FOLLOWING_SIBLING:
   12037 	    last = NULL;
   12038             next = xmlXPathNextFollowingSibling;
   12039             break;
   12040         case AXIS_NAMESPACE:
   12041             first = NULL;
   12042 	    last = NULL;
   12043             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12044 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12045             break;
   12046         case AXIS_PARENT:
   12047             first = NULL;
   12048             next = xmlXPathNextParent;
   12049             break;
   12050         case AXIS_PRECEDING:
   12051             first = NULL;
   12052             next = xmlXPathNextPrecedingInternal;
   12053             break;
   12054         case AXIS_PRECEDING_SIBLING:
   12055             first = NULL;
   12056             next = xmlXPathNextPrecedingSibling;
   12057             break;
   12058         case AXIS_SELF:
   12059             first = NULL;
   12060 	    last = NULL;
   12061             next = xmlXPathNextSelf;
   12062 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12063             break;
   12064     }
   12065 
   12066 #ifdef DEBUG_STEP
   12067     xmlXPathDebugDumpStepAxis(op,
   12068 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12069 #endif
   12070 
   12071     if (next == NULL) {
   12072 	xmlXPathReleaseObject(xpctxt, obj);
   12073         return(0);
   12074     }
   12075     contextSeq = obj->nodesetval;
   12076     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12077 	xmlXPathReleaseObject(xpctxt, obj);
   12078         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12079         return(0);
   12080     }
   12081     /*
   12082     * Predicate optimization ---------------------------------------------
   12083     * If this step has a last predicate, which contains a position(),
   12084     * then we'll optimize (although not exactly "position()", but only
   12085     * the  short-hand form, i.e., "[n]".
   12086     *
   12087     * Example - expression "/foo[parent::bar][1]":
   12088     *
   12089     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12090     *   ROOT                               -- op->ch1
   12091     *   PREDICATE                          -- op->ch2 (predOp)
   12092     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12093     *       SORT
   12094     *         COLLECT  'parent' 'name' 'node' bar
   12095     *           NODE
   12096     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12097     *
   12098     */
   12099     maxPos = 0;
   12100     predOp = NULL;
   12101     hasPredicateRange = 0;
   12102     hasAxisRange = 0;
   12103     if (op->ch2 != -1) {
   12104 	/*
   12105 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12106 	*/
   12107 	predOp = &ctxt->comp->steps[op->ch2];
   12108 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12109 	    if (predOp->ch1 != -1) {
   12110 		/*
   12111 		* Use the next inner predicate operator.
   12112 		*/
   12113 		predOp = &ctxt->comp->steps[predOp->ch1];
   12114 		hasPredicateRange = 1;
   12115 	    } else {
   12116 		/*
   12117 		* There's no other predicate than the [n] predicate.
   12118 		*/
   12119 		predOp = NULL;
   12120 		hasAxisRange = 1;
   12121 	    }
   12122 	}
   12123     }
   12124     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12125     /*
   12126     * Axis traversal -----------------------------------------------------
   12127     */
   12128     /*
   12129      * 2.3 Node Tests
   12130      *  - For the attribute axis, the principal node type is attribute.
   12131      *  - For the namespace axis, the principal node type is namespace.
   12132      *  - For other axes, the principal node type is element.
   12133      *
   12134      * A node test * is true for any node of the
   12135      * principal node type. For example, child::* will
   12136      * select all element children of the context node
   12137      */
   12138     oldContextNode = xpctxt->node;
   12139     addNode = xmlXPathNodeSetAddUnique;
   12140     outSeq = NULL;
   12141     seq = NULL;
   12142     outerContextNode = NULL;
   12143     contextNode = NULL;
   12144     contextIdx = 0;
   12145 
   12146 
   12147     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
   12148 	if (outerNext != NULL) {
   12149 	    /*
   12150 	    * This is a compound traversal.
   12151 	    */
   12152 	    if (contextNode == NULL) {
   12153 		/*
   12154 		* Set the context for the outer traversal.
   12155 		*/
   12156 		outerContextNode = contextSeq->nodeTab[contextIdx++];
   12157 		contextNode = outerNext(NULL, outerContextNode);
   12158 	    } else
   12159 		contextNode = outerNext(contextNode, outerContextNode);
   12160 	    if (contextNode == NULL)
   12161 		continue;
   12162 	    /*
   12163 	    * Set the context for the main traversal.
   12164 	    */
   12165 	    xpctxt->node = contextNode;
   12166 	} else
   12167 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12168 
   12169 	if (seq == NULL) {
   12170 	    seq = xmlXPathNodeSetCreate(NULL);
   12171 	    if (seq == NULL) {
   12172 		total = 0;
   12173 		goto error;
   12174 	    }
   12175 	}
   12176 	/*
   12177 	* Traverse the axis and test the nodes.
   12178 	*/
   12179 	pos = 0;
   12180 	cur = NULL;
   12181 	hasNsNodes = 0;
   12182         do {
   12183             cur = next(ctxt, cur);
   12184             if (cur == NULL)
   12185                 break;
   12186 
   12187 	    /*
   12188 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12189 	    */
   12190             if ((first != NULL) && (*first != NULL)) {
   12191 		if (*first == cur)
   12192 		    break;
   12193 		if (((total % 256) == 0) &&
   12194 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12195 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12196 #else
   12197 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12198 #endif
   12199 		{
   12200 		    break;
   12201 		}
   12202 	    }
   12203 	    if ((last != NULL) && (*last != NULL)) {
   12204 		if (*last == cur)
   12205 		    break;
   12206 		if (((total % 256) == 0) &&
   12207 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12208 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12209 #else
   12210 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12211 #endif
   12212 		{
   12213 		    break;
   12214 		}
   12215 	    }
   12216 
   12217             total++;
   12218 
   12219 #ifdef DEBUG_STEP
   12220             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12221 #endif
   12222 
   12223 	    switch (test) {
   12224                 case NODE_TEST_NONE:
   12225 		    total = 0;
   12226                     STRANGE
   12227 		    goto error;
   12228                 case NODE_TEST_TYPE:
   12229 		    /*
   12230 		    * TODO: Don't we need to use
   12231 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12232 		    *  Surprisingly, some c14n tests fail, if we do this.
   12233 		    */
   12234 		    if (type == NODE_TYPE_NODE) {
   12235 			switch (cur->type) {
   12236 			    case XML_DOCUMENT_NODE:
   12237 			    case XML_HTML_DOCUMENT_NODE:
   12238 #ifdef LIBXML_DOCB_ENABLED
   12239 			    case XML_DOCB_DOCUMENT_NODE:
   12240 #endif
   12241 			    case XML_ELEMENT_NODE:
   12242 			    case XML_ATTRIBUTE_NODE:
   12243 			    case XML_PI_NODE:
   12244 			    case XML_COMMENT_NODE:
   12245 			    case XML_CDATA_SECTION_NODE:
   12246 			    case XML_TEXT_NODE:
   12247 			    case XML_NAMESPACE_DECL:
   12248 				XP_TEST_HIT
   12249 				break;
   12250 			    default:
   12251 				break;
   12252 			}
   12253 		    } else if (cur->type == type) {
   12254 			if (type == XML_NAMESPACE_DECL)
   12255 			    XP_TEST_HIT_NS
   12256 			else
   12257 			    XP_TEST_HIT
   12258 		    } else if ((type == NODE_TYPE_TEXT) &&
   12259 			 (cur->type == XML_CDATA_SECTION_NODE))
   12260 		    {
   12261 			XP_TEST_HIT
   12262 		    }
   12263 		    break;
   12264                 case NODE_TEST_PI:
   12265                     if ((cur->type == XML_PI_NODE) &&
   12266                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12267 		    {
   12268 			XP_TEST_HIT
   12269                     }
   12270                     break;
   12271                 case NODE_TEST_ALL:
   12272                     if (axis == AXIS_ATTRIBUTE) {
   12273                         if (cur->type == XML_ATTRIBUTE_NODE)
   12274 			{
   12275 			    XP_TEST_HIT
   12276                         }
   12277                     } else if (axis == AXIS_NAMESPACE) {
   12278                         if (cur->type == XML_NAMESPACE_DECL)
   12279 			{
   12280 			    XP_TEST_HIT_NS
   12281                         }
   12282                     } else {
   12283                         if (cur->type == XML_ELEMENT_NODE) {
   12284                             if (prefix == NULL)
   12285 			    {
   12286 				XP_TEST_HIT
   12287 
   12288                             } else if ((cur->ns != NULL) &&
   12289 				(xmlStrEqual(URI, cur->ns->href)))
   12290 			    {
   12291 				XP_TEST_HIT
   12292                             }
   12293                         }
   12294                     }
   12295                     break;
   12296                 case NODE_TEST_NS:{
   12297                         TODO;
   12298                         break;
   12299                     }
   12300                 case NODE_TEST_NAME:
   12301                     if (axis == AXIS_ATTRIBUTE) {
   12302                         if (cur->type != XML_ATTRIBUTE_NODE)
   12303 			    break;
   12304 		    } else if (axis == AXIS_NAMESPACE) {
   12305                         if (cur->type != XML_NAMESPACE_DECL)
   12306 			    break;
   12307 		    } else {
   12308 		        if (cur->type != XML_ELEMENT_NODE)
   12309 			    break;
   12310 		    }
   12311                     switch (cur->type) {
   12312                         case XML_ELEMENT_NODE:
   12313                             if (xmlStrEqual(name, cur->name)) {
   12314                                 if (prefix == NULL) {
   12315                                     if (cur->ns == NULL)
   12316 				    {
   12317 					XP_TEST_HIT
   12318                                     }
   12319                                 } else {
   12320                                     if ((cur->ns != NULL) &&
   12321                                         (xmlStrEqual(URI, cur->ns->href)))
   12322 				    {
   12323 					XP_TEST_HIT
   12324                                     }
   12325                                 }
   12326                             }
   12327                             break;
   12328                         case XML_ATTRIBUTE_NODE:{
   12329                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12330 
   12331                                 if (xmlStrEqual(name, attr->name)) {
   12332                                     if (prefix == NULL) {
   12333                                         if ((attr->ns == NULL) ||
   12334                                             (attr->ns->prefix == NULL))
   12335 					{
   12336 					    XP_TEST_HIT
   12337                                         }
   12338                                     } else {
   12339                                         if ((attr->ns != NULL) &&
   12340                                             (xmlStrEqual(URI,
   12341 					      attr->ns->href)))
   12342 					{
   12343 					    XP_TEST_HIT
   12344                                         }
   12345                                     }
   12346                                 }
   12347                                 break;
   12348                             }
   12349                         case XML_NAMESPACE_DECL:
   12350                             if (cur->type == XML_NAMESPACE_DECL) {
   12351                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12352 
   12353                                 if ((ns->prefix != NULL) && (name != NULL)
   12354                                     && (xmlStrEqual(ns->prefix, name)))
   12355 				{
   12356 				    XP_TEST_HIT_NS
   12357                                 }
   12358                             }
   12359                             break;
   12360                         default:
   12361                             break;
   12362                     }
   12363                     break;
   12364 	    } /* switch(test) */
   12365         } while (cur != NULL);
   12366 
   12367 	goto apply_predicates;
   12368 
   12369 axis_range_end: /* ----------------------------------------------------- */
   12370 	/*
   12371 	* We have a "/foo[n]", and position() = n was reached.
   12372 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12373 	* a duplicate-aware merge is still needed.
   12374 	* Merge with the result.
   12375 	*/
   12376 	if (outSeq == NULL) {
   12377 	    outSeq = seq;
   12378 	    seq = NULL;
   12379 	} else
   12380 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12381 	/*
   12382 	* Break if only a true/false result was requested.
   12383 	*/
   12384 	if (toBool)
   12385 	    break;
   12386 	continue;
   12387 
   12388 first_hit: /* ---------------------------------------------------------- */
   12389 	/*
   12390 	* Break if only a true/false result was requested and
   12391 	* no predicates existed and a node test succeeded.
   12392 	*/
   12393 	if (outSeq == NULL) {
   12394 	    outSeq = seq;
   12395 	    seq = NULL;
   12396 	} else
   12397 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12398 	break;
   12399 
   12400 #ifdef DEBUG_STEP
   12401 	if (seq != NULL)
   12402 	    nbMatches += seq->nodeNr;
   12403 #endif
   12404 
   12405 apply_predicates: /* --------------------------------------------------- */
   12406         /*
   12407 	* Apply predicates.
   12408 	*/
   12409         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12410 	    /*
   12411 	    * E.g. when we have a "/foo[some expression][n]".
   12412 	    */
   12413 	    /*
   12414 	    * QUESTION TODO: The old predicate evaluation took into
   12415 	    *  account location-sets.
   12416 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12417 	    *  Do we expect such a set here?
   12418 	    *  All what I learned now from the evaluation semantics
   12419 	    *  does not indicate that a location-set will be processed
   12420 	    *  here, so this looks OK.
   12421 	    */
   12422 	    /*
   12423 	    * Iterate over all predicates, starting with the outermost
   12424 	    * predicate.
   12425 	    * TODO: Problem: we cannot execute the inner predicates first
   12426 	    *  since we cannot go back *up* the operator tree!
   12427 	    *  Options we have:
   12428 	    *  1) Use of recursive functions (like is it currently done
   12429 	    *     via xmlXPathCompOpEval())
   12430 	    *  2) Add a predicate evaluation information stack to the
   12431 	    *     context struct
   12432 	    *  3) Change the way the operators are linked; we need a
   12433 	    *     "parent" field on xmlXPathStepOp
   12434 	    *
   12435 	    * For the moment, I'll try to solve this with a recursive
   12436 	    * function: xmlXPathCompOpEvalPredicate().
   12437 	    */
   12438 	    size = seq->nodeNr;
   12439 	    if (hasPredicateRange != 0)
   12440 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12441 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12442 	    else
   12443 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12444 		    predOp, seq, size, hasNsNodes);
   12445 
   12446 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12447 		total = 0;
   12448 		goto error;
   12449 	    }
   12450 	    /*
   12451 	    * Add the filtered set of nodes to the result node set.
   12452 	    */
   12453 	    if (newSize == 0) {
   12454 		/*
   12455 		* The predicates filtered all nodes out.
   12456 		*/
   12457 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12458 	    } else if (seq->nodeNr > 0) {
   12459 		/*
   12460 		* Add to result set.
   12461 		*/
   12462 		if (outSeq == NULL) {
   12463 		    if (size != newSize) {
   12464 			/*
   12465 			* We need to merge and clear here, since
   12466 			* the sequence will contained NULLed entries.
   12467 			*/
   12468 			outSeq = mergeAndClear(NULL, seq, 1);
   12469 		    } else {
   12470 			outSeq = seq;
   12471 			seq = NULL;
   12472 		    }
   12473 		} else
   12474 		    outSeq = mergeAndClear(outSeq, seq,
   12475 			(size != newSize) ? 1: 0);
   12476 		/*
   12477 		* Break if only a true/false result was requested.
   12478 		*/
   12479 		if (toBool)
   12480 		    break;
   12481 	    }
   12482         } else if (seq->nodeNr > 0) {
   12483 	    /*
   12484 	    * Add to result set.
   12485 	    */
   12486 	    if (outSeq == NULL) {
   12487 		outSeq = seq;
   12488 		seq = NULL;
   12489 	    } else {
   12490 		outSeq = mergeAndClear(outSeq, seq, 0);
   12491 	    }
   12492 	}
   12493     }
   12494 
   12495 error:
   12496     if ((obj->boolval) && (obj->user != NULL)) {
   12497 	/*
   12498 	* QUESTION TODO: What does this do and why?
   12499 	* TODO: Do we have to do this also for the "error"
   12500 	* cleanup further down?
   12501 	*/
   12502 	ctxt->value->boolval = 1;
   12503 	ctxt->value->user = obj->user;
   12504 	obj->user = NULL;
   12505 	obj->boolval = 0;
   12506     }
   12507     xmlXPathReleaseObject(xpctxt, obj);
   12508 
   12509     /*
   12510     * Ensure we return at least an emtpy set.
   12511     */
   12512     if (outSeq == NULL) {
   12513 	if ((seq != NULL) && (seq->nodeNr == 0))
   12514 	    outSeq = seq;
   12515 	else
   12516 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12517         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12518     }
   12519     if ((seq != NULL) && (seq != outSeq)) {
   12520 	 xmlXPathFreeNodeSet(seq);
   12521     }
   12522     /*
   12523     * Hand over the result. Better to push the set also in
   12524     * case of errors.
   12525     */
   12526     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12527     /*
   12528     * Reset the context node.
   12529     */
   12530     xpctxt->node = oldContextNode;
   12531 
   12532 #ifdef DEBUG_STEP
   12533     xmlGenericError(xmlGenericErrorContext,
   12534 	"\nExamined %d nodes, found %d nodes at that step\n",
   12535 	total, nbMatches);
   12536 #endif
   12537 
   12538     return(total);
   12539 }
   12540 
   12541 static int
   12542 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12543 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12544 
   12545 /**
   12546  * xmlXPathCompOpEvalFirst:
   12547  * @ctxt:  the XPath parser context with the compiled expression
   12548  * @op:  an XPath compiled operation
   12549  * @first:  the first elem found so far
   12550  *
   12551  * Evaluate the Precompiled XPath operation searching only the first
   12552  * element in document order
   12553  *
   12554  * Returns the number of examined objects.
   12555  */
   12556 static int
   12557 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12558                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12559 {
   12560     int total = 0, cur;
   12561     xmlXPathCompExprPtr comp;
   12562     xmlXPathObjectPtr arg1, arg2;
   12563 
   12564     CHECK_ERROR0;
   12565     comp = ctxt->comp;
   12566     switch (op->op) {
   12567         case XPATH_OP_END:
   12568             return (0);
   12569         case XPATH_OP_UNION:
   12570             total =
   12571                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12572                                         first);
   12573 	    CHECK_ERROR0;
   12574             if ((ctxt->value != NULL)
   12575                 && (ctxt->value->type == XPATH_NODESET)
   12576                 && (ctxt->value->nodesetval != NULL)
   12577                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12578                 /*
   12579                  * limit tree traversing to first node in the result
   12580                  */
   12581 		/*
   12582 		* OPTIMIZE TODO: This implicitely sorts
   12583 		*  the result, even if not needed. E.g. if the argument
   12584 		*  of the count() function, no sorting is needed.
   12585 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12586 		*  aready sorted?
   12587 		*/
   12588 		if (ctxt->value->nodesetval->nodeNr > 1)
   12589 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12590                 *first = ctxt->value->nodesetval->nodeTab[0];
   12591             }
   12592             cur =
   12593                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12594                                         first);
   12595 	    CHECK_ERROR0;
   12596             CHECK_TYPE0(XPATH_NODESET);
   12597             arg2 = valuePop(ctxt);
   12598 
   12599             CHECK_TYPE0(XPATH_NODESET);
   12600             arg1 = valuePop(ctxt);
   12601 
   12602             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12603                                                     arg2->nodesetval);
   12604             valuePush(ctxt, arg1);
   12605 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12606             /* optimizer */
   12607 	    if (total > cur)
   12608 		xmlXPathCompSwap(op);
   12609             return (total + cur);
   12610         case XPATH_OP_ROOT:
   12611             xmlXPathRoot(ctxt);
   12612             return (0);
   12613         case XPATH_OP_NODE:
   12614             if (op->ch1 != -1)
   12615                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12616 	    CHECK_ERROR0;
   12617             if (op->ch2 != -1)
   12618                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12619 	    CHECK_ERROR0;
   12620 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12621 		ctxt->context->node));
   12622             return (total);
   12623         case XPATH_OP_RESET:
   12624             if (op->ch1 != -1)
   12625                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12626 	    CHECK_ERROR0;
   12627             if (op->ch2 != -1)
   12628                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12629 	    CHECK_ERROR0;
   12630             ctxt->context->node = NULL;
   12631             return (total);
   12632         case XPATH_OP_COLLECT:{
   12633                 if (op->ch1 == -1)
   12634                     return (total);
   12635 
   12636                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12637 		CHECK_ERROR0;
   12638 
   12639                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12640                 return (total);
   12641             }
   12642         case XPATH_OP_VALUE:
   12643             valuePush(ctxt,
   12644                       xmlXPathCacheObjectCopy(ctxt->context,
   12645 			(xmlXPathObjectPtr) op->value4));
   12646             return (0);
   12647         case XPATH_OP_SORT:
   12648             if (op->ch1 != -1)
   12649                 total +=
   12650                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12651                                             first);
   12652 	    CHECK_ERROR0;
   12653             if ((ctxt->value != NULL)
   12654                 && (ctxt->value->type == XPATH_NODESET)
   12655                 && (ctxt->value->nodesetval != NULL)
   12656 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12657                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12658             return (total);
   12659 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12660 	case XPATH_OP_FILTER:
   12661                 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12662             return (total);
   12663 #endif
   12664         default:
   12665             return (xmlXPathCompOpEval(ctxt, op));
   12666     }
   12667 }
   12668 
   12669 /**
   12670  * xmlXPathCompOpEvalLast:
   12671  * @ctxt:  the XPath parser context with the compiled expression
   12672  * @op:  an XPath compiled operation
   12673  * @last:  the last elem found so far
   12674  *
   12675  * Evaluate the Precompiled XPath operation searching only the last
   12676  * element in document order
   12677  *
   12678  * Returns the number of nodes traversed
   12679  */
   12680 static int
   12681 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12682                        xmlNodePtr * last)
   12683 {
   12684     int total = 0, cur;
   12685     xmlXPathCompExprPtr comp;
   12686     xmlXPathObjectPtr arg1, arg2;
   12687     xmlNodePtr bak;
   12688     xmlDocPtr bakd;
   12689     int pp;
   12690     int cs;
   12691 
   12692     CHECK_ERROR0;
   12693     comp = ctxt->comp;
   12694     switch (op->op) {
   12695         case XPATH_OP_END:
   12696             return (0);
   12697         case XPATH_OP_UNION:
   12698 	    bakd = ctxt->context->doc;
   12699 	    bak = ctxt->context->node;
   12700 	    pp = ctxt->context->proximityPosition;
   12701 	    cs = ctxt->context->contextSize;
   12702             total =
   12703                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12704 	    CHECK_ERROR0;
   12705             if ((ctxt->value != NULL)
   12706                 && (ctxt->value->type == XPATH_NODESET)
   12707                 && (ctxt->value->nodesetval != NULL)
   12708                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12709                 /*
   12710                  * limit tree traversing to first node in the result
   12711                  */
   12712 		if (ctxt->value->nodesetval->nodeNr > 1)
   12713 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12714                 *last =
   12715                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12716                                                      nodesetval->nodeNr -
   12717                                                      1];
   12718             }
   12719 	    ctxt->context->doc = bakd;
   12720 	    ctxt->context->node = bak;
   12721 	    ctxt->context->proximityPosition = pp;
   12722 	    ctxt->context->contextSize = cs;
   12723             cur =
   12724                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12725 	    CHECK_ERROR0;
   12726             if ((ctxt->value != NULL)
   12727                 && (ctxt->value->type == XPATH_NODESET)
   12728                 && (ctxt->value->nodesetval != NULL)
   12729                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12730             }
   12731             CHECK_TYPE0(XPATH_NODESET);
   12732             arg2 = valuePop(ctxt);
   12733 
   12734             CHECK_TYPE0(XPATH_NODESET);
   12735             arg1 = valuePop(ctxt);
   12736 
   12737             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12738                                                     arg2->nodesetval);
   12739             valuePush(ctxt, arg1);
   12740 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12741             /* optimizer */
   12742 	    if (total > cur)
   12743 		xmlXPathCompSwap(op);
   12744             return (total + cur);
   12745         case XPATH_OP_ROOT:
   12746             xmlXPathRoot(ctxt);
   12747             return (0);
   12748         case XPATH_OP_NODE:
   12749             if (op->ch1 != -1)
   12750                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12751 	    CHECK_ERROR0;
   12752             if (op->ch2 != -1)
   12753                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12754 	    CHECK_ERROR0;
   12755 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12756 		ctxt->context->node));
   12757             return (total);
   12758         case XPATH_OP_RESET:
   12759             if (op->ch1 != -1)
   12760                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12761 	    CHECK_ERROR0;
   12762             if (op->ch2 != -1)
   12763                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12764 	    CHECK_ERROR0;
   12765             ctxt->context->node = NULL;
   12766             return (total);
   12767         case XPATH_OP_COLLECT:{
   12768                 if (op->ch1 == -1)
   12769                     return (0);
   12770 
   12771                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12772 		CHECK_ERROR0;
   12773 
   12774                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12775                 return (total);
   12776             }
   12777         case XPATH_OP_VALUE:
   12778             valuePush(ctxt,
   12779                       xmlXPathCacheObjectCopy(ctxt->context,
   12780 			(xmlXPathObjectPtr) op->value4));
   12781             return (0);
   12782         case XPATH_OP_SORT:
   12783             if (op->ch1 != -1)
   12784                 total +=
   12785                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12786                                            last);
   12787 	    CHECK_ERROR0;
   12788             if ((ctxt->value != NULL)
   12789                 && (ctxt->value->type == XPATH_NODESET)
   12790                 && (ctxt->value->nodesetval != NULL)
   12791 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12792                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12793             return (total);
   12794         default:
   12795             return (xmlXPathCompOpEval(ctxt, op));
   12796     }
   12797 }
   12798 
   12799 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12800 static int
   12801 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12802 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12803 {
   12804     int total = 0;
   12805     xmlXPathCompExprPtr comp;
   12806     xmlXPathObjectPtr res;
   12807     xmlXPathObjectPtr obj;
   12808     xmlNodeSetPtr oldset;
   12809     xmlNodePtr oldnode;
   12810     xmlDocPtr oldDoc;
   12811     int i;
   12812 
   12813     CHECK_ERROR0;
   12814     comp = ctxt->comp;
   12815     /*
   12816     * Optimization for ()[last()] selection i.e. the last elem
   12817     */
   12818     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12819 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12820 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12821 	int f = comp->steps[op->ch2].ch1;
   12822 
   12823 	if ((f != -1) &&
   12824 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12825 	    (comp->steps[f].value5 == NULL) &&
   12826 	    (comp->steps[f].value == 0) &&
   12827 	    (comp->steps[f].value4 != NULL) &&
   12828 	    (xmlStrEqual
   12829 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12830 	    xmlNodePtr last = NULL;
   12831 
   12832 	    total +=
   12833 		xmlXPathCompOpEvalLast(ctxt,
   12834 		    &comp->steps[op->ch1],
   12835 		    &last);
   12836 	    CHECK_ERROR0;
   12837 	    /*
   12838 	    * The nodeset should be in document order,
   12839 	    * Keep only the last value
   12840 	    */
   12841 	    if ((ctxt->value != NULL) &&
   12842 		(ctxt->value->type == XPATH_NODESET) &&
   12843 		(ctxt->value->nodesetval != NULL) &&
   12844 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12845 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12846 		ctxt->value->nodesetval->nodeTab[0] =
   12847 		    ctxt->value->nodesetval->nodeTab[ctxt->
   12848 		    value->
   12849 		    nodesetval->
   12850 		    nodeNr -
   12851 		    1];
   12852 		ctxt->value->nodesetval->nodeNr = 1;
   12853 		*first = *(ctxt->value->nodesetval->nodeTab);
   12854 	    }
   12855 	    return (total);
   12856 	}
   12857     }
   12858 
   12859     if (op->ch1 != -1)
   12860 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12861     CHECK_ERROR0;
   12862     if (op->ch2 == -1)
   12863 	return (total);
   12864     if (ctxt->value == NULL)
   12865 	return (total);
   12866 
   12867 #ifdef LIBXML_XPTR_ENABLED
   12868     oldnode = ctxt->context->node;
   12869     /*
   12870     * Hum are we filtering the result of an XPointer expression
   12871     */
   12872     if (ctxt->value->type == XPATH_LOCATIONSET) {
   12873 	xmlXPathObjectPtr tmp = NULL;
   12874 	xmlLocationSetPtr newlocset = NULL;
   12875 	xmlLocationSetPtr oldlocset;
   12876 
   12877 	/*
   12878 	* Extract the old locset, and then evaluate the result of the
   12879 	* expression for all the element in the locset. use it to grow
   12880 	* up a new locset.
   12881 	*/
   12882 	CHECK_TYPE0(XPATH_LOCATIONSET);
   12883 	obj = valuePop(ctxt);
   12884 	oldlocset = obj->user;
   12885 	ctxt->context->node = NULL;
   12886 
   12887 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   12888 	    ctxt->context->contextSize = 0;
   12889 	    ctxt->context->proximityPosition = 0;
   12890 	    if (op->ch2 != -1)
   12891 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12892 	    res = valuePop(ctxt);
   12893 	    if (res != NULL) {
   12894 		xmlXPathReleaseObject(ctxt->context, res);
   12895 	    }
   12896 	    valuePush(ctxt, obj);
   12897 	    CHECK_ERROR0;
   12898 	    return (total);
   12899 	}
   12900 	newlocset = xmlXPtrLocationSetCreate(NULL);
   12901 
   12902 	for (i = 0; i < oldlocset->locNr; i++) {
   12903 	    /*
   12904 	    * Run the evaluation with a node list made of a
   12905 	    * single item in the nodelocset.
   12906 	    */
   12907 	    ctxt->context->node = oldlocset->locTab[i]->user;
   12908 	    ctxt->context->contextSize = oldlocset->locNr;
   12909 	    ctxt->context->proximityPosition = i + 1;
   12910 	    if (tmp == NULL) {
   12911 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   12912 		    ctxt->context->node);
   12913 	    } else {
   12914 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   12915 		    ctxt->context->node);
   12916 	    }
   12917 	    valuePush(ctxt, tmp);
   12918 	    if (op->ch2 != -1)
   12919 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12920 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12921 		xmlXPathFreeObject(obj);
   12922 		return(0);
   12923 	    }
   12924 	    /*
   12925 	    * The result of the evaluation need to be tested to
   12926 	    * decided whether the filter succeeded or not
   12927 	    */
   12928 	    res = valuePop(ctxt);
   12929 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   12930 		xmlXPtrLocationSetAdd(newlocset,
   12931 		    xmlXPathCacheObjectCopy(ctxt->context,
   12932 			oldlocset->locTab[i]));
   12933 	    }
   12934 	    /*
   12935 	    * Cleanup
   12936 	    */
   12937 	    if (res != NULL) {
   12938 		xmlXPathReleaseObject(ctxt->context, res);
   12939 	    }
   12940 	    if (ctxt->value == tmp) {
   12941 		valuePop(ctxt);
   12942 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   12943 		/*
   12944 		* REVISIT TODO: Don't create a temporary nodeset
   12945 		* for everly iteration.
   12946 		*/
   12947 		/* OLD: xmlXPathFreeObject(res); */
   12948 	    } else
   12949 		tmp = NULL;
   12950 	    ctxt->context->node = NULL;
   12951 	    /*
   12952 	    * Only put the first node in the result, then leave.
   12953 	    */
   12954 	    if (newlocset->locNr > 0) {
   12955 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   12956 		break;
   12957 	    }
   12958 	}
   12959 	if (tmp != NULL) {
   12960 	    xmlXPathReleaseObject(ctxt->context, tmp);
   12961 	}
   12962 	/*
   12963 	* The result is used as the new evaluation locset.
   12964 	*/
   12965 	xmlXPathReleaseObject(ctxt->context, obj);
   12966 	ctxt->context->node = NULL;
   12967 	ctxt->context->contextSize = -1;
   12968 	ctxt->context->proximityPosition = -1;
   12969 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   12970 	ctxt->context->node = oldnode;
   12971 	return (total);
   12972     }
   12973 #endif /* LIBXML_XPTR_ENABLED */
   12974 
   12975     /*
   12976     * Extract the old set, and then evaluate the result of the
   12977     * expression for all the element in the set. use it to grow
   12978     * up a new set.
   12979     */
   12980     CHECK_TYPE0(XPATH_NODESET);
   12981     obj = valuePop(ctxt);
   12982     oldset = obj->nodesetval;
   12983 
   12984     oldnode = ctxt->context->node;
   12985     oldDoc = ctxt->context->doc;
   12986     ctxt->context->node = NULL;
   12987 
   12988     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   12989 	ctxt->context->contextSize = 0;
   12990 	ctxt->context->proximityPosition = 0;
   12991 	/* QUESTION TODO: Why was this code commented out?
   12992 	    if (op->ch2 != -1)
   12993 		total +=
   12994 		    xmlXPathCompOpEval(ctxt,
   12995 			&comp->steps[op->ch2]);
   12996 	    CHECK_ERROR0;
   12997 	    res = valuePop(ctxt);
   12998 	    if (res != NULL)
   12999 		xmlXPathFreeObject(res);
   13000 	*/
   13001 	valuePush(ctxt, obj);
   13002 	ctxt->context->node = oldnode;
   13003 	CHECK_ERROR0;
   13004     } else {
   13005 	xmlNodeSetPtr newset;
   13006 	xmlXPathObjectPtr tmp = NULL;
   13007 	/*
   13008 	* Initialize the new set.
   13009 	* Also set the xpath document in case things like
   13010 	* key() evaluation are attempted on the predicate
   13011 	*/
   13012 	newset = xmlXPathNodeSetCreate(NULL);
   13013         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13014 
   13015 	for (i = 0; i < oldset->nodeNr; i++) {
   13016 	    /*
   13017 	    * Run the evaluation with a node list made of
   13018 	    * a single item in the nodeset.
   13019 	    */
   13020 	    ctxt->context->node = oldset->nodeTab[i];
   13021 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13022 		(oldset->nodeTab[i]->doc != NULL))
   13023 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13024 	    if (tmp == NULL) {
   13025 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13026 		    ctxt->context->node);
   13027 	    } else {
   13028 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13029 		    ctxt->context->node);
   13030 	    }
   13031 	    valuePush(ctxt, tmp);
   13032 	    ctxt->context->contextSize = oldset->nodeNr;
   13033 	    ctxt->context->proximityPosition = i + 1;
   13034 	    if (op->ch2 != -1)
   13035 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13036 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13037 		xmlXPathFreeNodeSet(newset);
   13038 		xmlXPathFreeObject(obj);
   13039 		return(0);
   13040 	    }
   13041 	    /*
   13042 	    * The result of the evaluation needs to be tested to
   13043 	    * decide whether the filter succeeded or not
   13044 	    */
   13045 	    res = valuePop(ctxt);
   13046 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13047 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13048 	    }
   13049 	    /*
   13050 	    * Cleanup
   13051 	    */
   13052 	    if (res != NULL) {
   13053 		xmlXPathReleaseObject(ctxt->context, res);
   13054 	    }
   13055 	    if (ctxt->value == tmp) {
   13056 		valuePop(ctxt);
   13057 		/*
   13058 		* Don't free the temporary nodeset
   13059 		* in order to avoid massive recreation inside this
   13060 		* loop.
   13061 		*/
   13062 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13063 	    } else
   13064 		tmp = NULL;
   13065 	    ctxt->context->node = NULL;
   13066 	    /*
   13067 	    * Only put the first node in the result, then leave.
   13068 	    */
   13069 	    if (newset->nodeNr > 0) {
   13070 		*first = *(newset->nodeTab);
   13071 		break;
   13072 	    }
   13073 	}
   13074 	if (tmp != NULL) {
   13075 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13076 	}
   13077 	/*
   13078 	* The result is used as the new evaluation set.
   13079 	*/
   13080 	xmlXPathReleaseObject(ctxt->context, obj);
   13081 	ctxt->context->node = NULL;
   13082 	ctxt->context->contextSize = -1;
   13083 	ctxt->context->proximityPosition = -1;
   13084 	/* may want to move this past the '}' later */
   13085 	ctxt->context->doc = oldDoc;
   13086 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13087     }
   13088     ctxt->context->node = oldnode;
   13089     return(total);
   13090 }
   13091 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13092 
   13093 /**
   13094  * xmlXPathCompOpEval:
   13095  * @ctxt:  the XPath parser context with the compiled expression
   13096  * @op:  an XPath compiled operation
   13097  *
   13098  * Evaluate the Precompiled XPath operation
   13099  * Returns the number of nodes traversed
   13100  */
   13101 static int
   13102 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13103 {
   13104     int total = 0;
   13105     int equal, ret;
   13106     xmlXPathCompExprPtr comp;
   13107     xmlXPathObjectPtr arg1, arg2;
   13108     xmlNodePtr bak;
   13109     xmlDocPtr bakd;
   13110     int pp;
   13111     int cs;
   13112 
   13113     CHECK_ERROR0;
   13114     comp = ctxt->comp;
   13115     switch (op->op) {
   13116         case XPATH_OP_END:
   13117             return (0);
   13118         case XPATH_OP_AND:
   13119 	    bakd = ctxt->context->doc;
   13120 	    bak = ctxt->context->node;
   13121 	    pp = ctxt->context->proximityPosition;
   13122 	    cs = ctxt->context->contextSize;
   13123             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13124 	    CHECK_ERROR0;
   13125             xmlXPathBooleanFunction(ctxt, 1);
   13126             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13127                 return (total);
   13128             arg2 = valuePop(ctxt);
   13129 	    ctxt->context->doc = bakd;
   13130 	    ctxt->context->node = bak;
   13131 	    ctxt->context->proximityPosition = pp;
   13132 	    ctxt->context->contextSize = cs;
   13133             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13134 	    if (ctxt->error) {
   13135 		xmlXPathFreeObject(arg2);
   13136 		return(0);
   13137 	    }
   13138             xmlXPathBooleanFunction(ctxt, 1);
   13139             arg1 = valuePop(ctxt);
   13140             arg1->boolval &= arg2->boolval;
   13141             valuePush(ctxt, arg1);
   13142 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13143             return (total);
   13144         case XPATH_OP_OR:
   13145 	    bakd = ctxt->context->doc;
   13146 	    bak = ctxt->context->node;
   13147 	    pp = ctxt->context->proximityPosition;
   13148 	    cs = ctxt->context->contextSize;
   13149             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13150 	    CHECK_ERROR0;
   13151             xmlXPathBooleanFunction(ctxt, 1);
   13152             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13153                 return (total);
   13154             arg2 = valuePop(ctxt);
   13155 	    ctxt->context->doc = bakd;
   13156 	    ctxt->context->node = bak;
   13157 	    ctxt->context->proximityPosition = pp;
   13158 	    ctxt->context->contextSize = cs;
   13159             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13160 	    if (ctxt->error) {
   13161 		xmlXPathFreeObject(arg2);
   13162 		return(0);
   13163 	    }
   13164             xmlXPathBooleanFunction(ctxt, 1);
   13165             arg1 = valuePop(ctxt);
   13166             arg1->boolval |= arg2->boolval;
   13167             valuePush(ctxt, arg1);
   13168 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13169             return (total);
   13170         case XPATH_OP_EQUAL:
   13171 	    bakd = ctxt->context->doc;
   13172 	    bak = ctxt->context->node;
   13173 	    pp = ctxt->context->proximityPosition;
   13174 	    cs = ctxt->context->contextSize;
   13175             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13176 	    CHECK_ERROR0;
   13177 	    ctxt->context->doc = bakd;
   13178 	    ctxt->context->node = bak;
   13179 	    ctxt->context->proximityPosition = pp;
   13180 	    ctxt->context->contextSize = cs;
   13181             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13182 	    CHECK_ERROR0;
   13183 	    if (op->value)
   13184 		equal = xmlXPathEqualValues(ctxt);
   13185 	    else
   13186 		equal = xmlXPathNotEqualValues(ctxt);
   13187 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13188             return (total);
   13189         case XPATH_OP_CMP:
   13190 	    bakd = ctxt->context->doc;
   13191 	    bak = ctxt->context->node;
   13192 	    pp = ctxt->context->proximityPosition;
   13193 	    cs = ctxt->context->contextSize;
   13194             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13195 	    CHECK_ERROR0;
   13196 	    ctxt->context->doc = bakd;
   13197 	    ctxt->context->node = bak;
   13198 	    ctxt->context->proximityPosition = pp;
   13199 	    ctxt->context->contextSize = cs;
   13200             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13201 	    CHECK_ERROR0;
   13202             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13203 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13204             return (total);
   13205         case XPATH_OP_PLUS:
   13206 	    bakd = ctxt->context->doc;
   13207 	    bak = ctxt->context->node;
   13208 	    pp = ctxt->context->proximityPosition;
   13209 	    cs = ctxt->context->contextSize;
   13210             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13211 	    CHECK_ERROR0;
   13212             if (op->ch2 != -1) {
   13213 		ctxt->context->doc = bakd;
   13214 		ctxt->context->node = bak;
   13215 		ctxt->context->proximityPosition = pp;
   13216 		ctxt->context->contextSize = cs;
   13217                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13218 	    }
   13219 	    CHECK_ERROR0;
   13220             if (op->value == 0)
   13221                 xmlXPathSubValues(ctxt);
   13222             else if (op->value == 1)
   13223                 xmlXPathAddValues(ctxt);
   13224             else if (op->value == 2)
   13225                 xmlXPathValueFlipSign(ctxt);
   13226             else if (op->value == 3) {
   13227                 CAST_TO_NUMBER;
   13228                 CHECK_TYPE0(XPATH_NUMBER);
   13229             }
   13230             return (total);
   13231         case XPATH_OP_MULT:
   13232 	    bakd = ctxt->context->doc;
   13233 	    bak = ctxt->context->node;
   13234 	    pp = ctxt->context->proximityPosition;
   13235 	    cs = ctxt->context->contextSize;
   13236             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13237 	    CHECK_ERROR0;
   13238 	    ctxt->context->doc = bakd;
   13239 	    ctxt->context->node = bak;
   13240 	    ctxt->context->proximityPosition = pp;
   13241 	    ctxt->context->contextSize = cs;
   13242             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13243 	    CHECK_ERROR0;
   13244             if (op->value == 0)
   13245                 xmlXPathMultValues(ctxt);
   13246             else if (op->value == 1)
   13247                 xmlXPathDivValues(ctxt);
   13248             else if (op->value == 2)
   13249                 xmlXPathModValues(ctxt);
   13250             return (total);
   13251         case XPATH_OP_UNION:
   13252 	    bakd = ctxt->context->doc;
   13253 	    bak = ctxt->context->node;
   13254 	    pp = ctxt->context->proximityPosition;
   13255 	    cs = ctxt->context->contextSize;
   13256             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13257 	    CHECK_ERROR0;
   13258 	    ctxt->context->doc = bakd;
   13259 	    ctxt->context->node = bak;
   13260 	    ctxt->context->proximityPosition = pp;
   13261 	    ctxt->context->contextSize = cs;
   13262             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13263 	    CHECK_ERROR0;
   13264             CHECK_TYPE0(XPATH_NODESET);
   13265             arg2 = valuePop(ctxt);
   13266 
   13267             CHECK_TYPE0(XPATH_NODESET);
   13268             arg1 = valuePop(ctxt);
   13269 
   13270 	    if ((arg1->nodesetval == NULL) ||
   13271 		((arg2->nodesetval != NULL) &&
   13272 		 (arg2->nodesetval->nodeNr != 0)))
   13273 	    {
   13274 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13275 							arg2->nodesetval);
   13276 	    }
   13277 
   13278             valuePush(ctxt, arg1);
   13279 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13280             return (total);
   13281         case XPATH_OP_ROOT:
   13282             xmlXPathRoot(ctxt);
   13283             return (total);
   13284         case XPATH_OP_NODE:
   13285             if (op->ch1 != -1)
   13286                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13287 	    CHECK_ERROR0;
   13288             if (op->ch2 != -1)
   13289                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13290 	    CHECK_ERROR0;
   13291 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13292 		ctxt->context->node));
   13293             return (total);
   13294         case XPATH_OP_RESET:
   13295             if (op->ch1 != -1)
   13296                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13297 	    CHECK_ERROR0;
   13298             if (op->ch2 != -1)
   13299                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13300 	    CHECK_ERROR0;
   13301             ctxt->context->node = NULL;
   13302             return (total);
   13303         case XPATH_OP_COLLECT:{
   13304                 if (op->ch1 == -1)
   13305                     return (total);
   13306 
   13307                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13308 		CHECK_ERROR0;
   13309 
   13310                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13311                 return (total);
   13312             }
   13313         case XPATH_OP_VALUE:
   13314             valuePush(ctxt,
   13315                       xmlXPathCacheObjectCopy(ctxt->context,
   13316 			(xmlXPathObjectPtr) op->value4));
   13317             return (total);
   13318         case XPATH_OP_VARIABLE:{
   13319 		xmlXPathObjectPtr val;
   13320 
   13321                 if (op->ch1 != -1)
   13322                     total +=
   13323                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13324                 if (op->value5 == NULL) {
   13325 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13326 		    if (val == NULL) {
   13327 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13328 			return(0);
   13329 		    }
   13330                     valuePush(ctxt, val);
   13331 		} else {
   13332                     const xmlChar *URI;
   13333 
   13334                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13335                     if (URI == NULL) {
   13336                         xmlGenericError(xmlGenericErrorContext,
   13337             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13338                                     (char *) op->value4, (char *)op->value5);
   13339                         return (total);
   13340                     }
   13341 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13342                                                        op->value4, URI);
   13343 		    if (val == NULL) {
   13344 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13345 			return(0);
   13346 		    }
   13347                     valuePush(ctxt, val);
   13348                 }
   13349                 return (total);
   13350             }
   13351         case XPATH_OP_FUNCTION:{
   13352                 xmlXPathFunction func;
   13353                 const xmlChar *oldFunc, *oldFuncURI;
   13354 		int i;
   13355 
   13356                 if (op->ch1 != -1)
   13357                     total +=
   13358                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13359 		if (ctxt->valueNr < op->value) {
   13360 		    xmlGenericError(xmlGenericErrorContext,
   13361 			    "xmlXPathCompOpEval: parameter error\n");
   13362 		    ctxt->error = XPATH_INVALID_OPERAND;
   13363 		    return (total);
   13364 		}
   13365 		for (i = 0; i < op->value; i++)
   13366 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13367 			xmlGenericError(xmlGenericErrorContext,
   13368 				"xmlXPathCompOpEval: parameter error\n");
   13369 			ctxt->error = XPATH_INVALID_OPERAND;
   13370 			return (total);
   13371 		    }
   13372                 if (op->cache != NULL)
   13373                     XML_CAST_FPTR(func) = op->cache;
   13374                 else {
   13375                     const xmlChar *URI = NULL;
   13376 
   13377                     if (op->value5 == NULL)
   13378                         func =
   13379                             xmlXPathFunctionLookup(ctxt->context,
   13380                                                    op->value4);
   13381                     else {
   13382                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13383                         if (URI == NULL) {
   13384                             xmlGenericError(xmlGenericErrorContext,
   13385             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13386                                     (char *)op->value4, (char *)op->value5);
   13387                             return (total);
   13388                         }
   13389                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13390                                                         op->value4, URI);
   13391                     }
   13392                     if (func == NULL) {
   13393                         xmlGenericError(xmlGenericErrorContext,
   13394                                 "xmlXPathCompOpEval: function %s not found\n",
   13395                                         (char *)op->value4);
   13396                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13397                     }
   13398                     op->cache = XML_CAST_FPTR(func);
   13399                     op->cacheURI = (void *) URI;
   13400                 }
   13401                 oldFunc = ctxt->context->function;
   13402                 oldFuncURI = ctxt->context->functionURI;
   13403                 ctxt->context->function = op->value4;
   13404                 ctxt->context->functionURI = op->cacheURI;
   13405                 func(ctxt, op->value);
   13406                 ctxt->context->function = oldFunc;
   13407                 ctxt->context->functionURI = oldFuncURI;
   13408                 return (total);
   13409             }
   13410         case XPATH_OP_ARG:
   13411 	    bakd = ctxt->context->doc;
   13412 	    bak = ctxt->context->node;
   13413 	    pp = ctxt->context->proximityPosition;
   13414 	    cs = ctxt->context->contextSize;
   13415             if (op->ch1 != -1)
   13416                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13417 	    ctxt->context->contextSize = cs;
   13418 	    ctxt->context->proximityPosition = pp;
   13419 	    ctxt->context->node = bak;
   13420 	    ctxt->context->doc = bakd;
   13421 	    CHECK_ERROR0;
   13422             if (op->ch2 != -1) {
   13423                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13424 	        ctxt->context->doc = bakd;
   13425 	        ctxt->context->node = bak;
   13426 	        CHECK_ERROR0;
   13427 	    }
   13428             return (total);
   13429         case XPATH_OP_PREDICATE:
   13430         case XPATH_OP_FILTER:{
   13431                 xmlXPathObjectPtr res;
   13432                 xmlXPathObjectPtr obj, tmp;
   13433                 xmlNodeSetPtr newset = NULL;
   13434                 xmlNodeSetPtr oldset;
   13435                 xmlNodePtr oldnode;
   13436 		xmlDocPtr oldDoc;
   13437                 int i;
   13438 
   13439                 /*
   13440                  * Optimization for ()[1] selection i.e. the first elem
   13441                  */
   13442                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13443 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13444 		    /*
   13445 		    * FILTER TODO: Can we assume that the inner processing
   13446 		    *  will result in an ordered list if we have an
   13447 		    *  XPATH_OP_FILTER?
   13448 		    *  What about an additional field or flag on
   13449 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13450 		    *  to assume anything, so it would be more robust and
   13451 		    *  easier to optimize.
   13452 		    */
   13453                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13454 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13455 #else
   13456 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13457 #endif
   13458                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13459                     xmlXPathObjectPtr val;
   13460 
   13461                     val = comp->steps[op->ch2].value4;
   13462                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13463                         (val->floatval == 1.0)) {
   13464                         xmlNodePtr first = NULL;
   13465 
   13466                         total +=
   13467                             xmlXPathCompOpEvalFirst(ctxt,
   13468                                                     &comp->steps[op->ch1],
   13469                                                     &first);
   13470 			CHECK_ERROR0;
   13471                         /*
   13472                          * The nodeset should be in document order,
   13473                          * Keep only the first value
   13474                          */
   13475                         if ((ctxt->value != NULL) &&
   13476                             (ctxt->value->type == XPATH_NODESET) &&
   13477                             (ctxt->value->nodesetval != NULL) &&
   13478                             (ctxt->value->nodesetval->nodeNr > 1))
   13479                             ctxt->value->nodesetval->nodeNr = 1;
   13480                         return (total);
   13481                     }
   13482                 }
   13483                 /*
   13484                  * Optimization for ()[last()] selection i.e. the last elem
   13485                  */
   13486                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13487                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13488                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13489                     int f = comp->steps[op->ch2].ch1;
   13490 
   13491                     if ((f != -1) &&
   13492                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13493                         (comp->steps[f].value5 == NULL) &&
   13494                         (comp->steps[f].value == 0) &&
   13495                         (comp->steps[f].value4 != NULL) &&
   13496                         (xmlStrEqual
   13497                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13498                         xmlNodePtr last = NULL;
   13499 
   13500                         total +=
   13501                             xmlXPathCompOpEvalLast(ctxt,
   13502                                                    &comp->steps[op->ch1],
   13503                                                    &last);
   13504 			CHECK_ERROR0;
   13505                         /*
   13506                          * The nodeset should be in document order,
   13507                          * Keep only the last value
   13508                          */
   13509                         if ((ctxt->value != NULL) &&
   13510                             (ctxt->value->type == XPATH_NODESET) &&
   13511                             (ctxt->value->nodesetval != NULL) &&
   13512                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13513                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13514                             ctxt->value->nodesetval->nodeTab[0] =
   13515                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13516                                                                  value->
   13517                                                                  nodesetval->
   13518                                                                  nodeNr -
   13519                                                                  1];
   13520                             ctxt->value->nodesetval->nodeNr = 1;
   13521                         }
   13522                         return (total);
   13523                     }
   13524                 }
   13525 		/*
   13526 		* Process inner predicates first.
   13527 		* Example "index[parent::book][1]":
   13528 		* ...
   13529 		*   PREDICATE   <-- we are here "[1]"
   13530 		*     PREDICATE <-- process "[parent::book]" first
   13531 		*       SORT
   13532 		*         COLLECT  'parent' 'name' 'node' book
   13533 		*           NODE
   13534 		*     ELEM Object is a number : 1
   13535 		*/
   13536                 if (op->ch1 != -1)
   13537                     total +=
   13538                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13539 		CHECK_ERROR0;
   13540                 if (op->ch2 == -1)
   13541                     return (total);
   13542                 if (ctxt->value == NULL)
   13543                     return (total);
   13544 
   13545                 oldnode = ctxt->context->node;
   13546 
   13547 #ifdef LIBXML_XPTR_ENABLED
   13548                 /*
   13549                  * Hum are we filtering the result of an XPointer expression
   13550                  */
   13551                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13552                     xmlLocationSetPtr newlocset = NULL;
   13553                     xmlLocationSetPtr oldlocset;
   13554 
   13555                     /*
   13556                      * Extract the old locset, and then evaluate the result of the
   13557                      * expression for all the element in the locset. use it to grow
   13558                      * up a new locset.
   13559                      */
   13560                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13561                     obj = valuePop(ctxt);
   13562                     oldlocset = obj->user;
   13563                     ctxt->context->node = NULL;
   13564 
   13565                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13566                         ctxt->context->contextSize = 0;
   13567                         ctxt->context->proximityPosition = 0;
   13568                         if (op->ch2 != -1)
   13569                             total +=
   13570                                 xmlXPathCompOpEval(ctxt,
   13571                                                    &comp->steps[op->ch2]);
   13572                         res = valuePop(ctxt);
   13573                         if (res != NULL) {
   13574 			    xmlXPathReleaseObject(ctxt->context, res);
   13575 			}
   13576                         valuePush(ctxt, obj);
   13577                         CHECK_ERROR0;
   13578                         return (total);
   13579                     }
   13580                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13581 
   13582                     for (i = 0; i < oldlocset->locNr; i++) {
   13583                         /*
   13584                          * Run the evaluation with a node list made of a
   13585                          * single item in the nodelocset.
   13586                          */
   13587                         ctxt->context->node = oldlocset->locTab[i]->user;
   13588                         ctxt->context->contextSize = oldlocset->locNr;
   13589                         ctxt->context->proximityPosition = i + 1;
   13590 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13591 			    ctxt->context->node);
   13592                         valuePush(ctxt, tmp);
   13593 
   13594                         if (op->ch2 != -1)
   13595                             total +=
   13596                                 xmlXPathCompOpEval(ctxt,
   13597                                                    &comp->steps[op->ch2]);
   13598 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13599 			    xmlXPathFreeObject(obj);
   13600 			    return(0);
   13601 			}
   13602 
   13603                         /*
   13604                          * The result of the evaluation need to be tested to
   13605                          * decided whether the filter succeeded or not
   13606                          */
   13607                         res = valuePop(ctxt);
   13608                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13609                             xmlXPtrLocationSetAdd(newlocset,
   13610                                                   xmlXPathObjectCopy
   13611                                                   (oldlocset->locTab[i]));
   13612                         }
   13613 
   13614                         /*
   13615                          * Cleanup
   13616                          */
   13617                         if (res != NULL) {
   13618 			    xmlXPathReleaseObject(ctxt->context, res);
   13619 			}
   13620                         if (ctxt->value == tmp) {
   13621                             res = valuePop(ctxt);
   13622 			    xmlXPathReleaseObject(ctxt->context, res);
   13623                         }
   13624 
   13625                         ctxt->context->node = NULL;
   13626                     }
   13627 
   13628                     /*
   13629                      * The result is used as the new evaluation locset.
   13630                      */
   13631 		    xmlXPathReleaseObject(ctxt->context, obj);
   13632                     ctxt->context->node = NULL;
   13633                     ctxt->context->contextSize = -1;
   13634                     ctxt->context->proximityPosition = -1;
   13635                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13636                     ctxt->context->node = oldnode;
   13637                     return (total);
   13638                 }
   13639 #endif /* LIBXML_XPTR_ENABLED */
   13640 
   13641                 /*
   13642                  * Extract the old set, and then evaluate the result of the
   13643                  * expression for all the element in the set. use it to grow
   13644                  * up a new set.
   13645                  */
   13646                 CHECK_TYPE0(XPATH_NODESET);
   13647                 obj = valuePop(ctxt);
   13648                 oldset = obj->nodesetval;
   13649 
   13650                 oldnode = ctxt->context->node;
   13651 		oldDoc = ctxt->context->doc;
   13652                 ctxt->context->node = NULL;
   13653 
   13654                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13655                     ctxt->context->contextSize = 0;
   13656                     ctxt->context->proximityPosition = 0;
   13657 /*
   13658                     if (op->ch2 != -1)
   13659                         total +=
   13660                             xmlXPathCompOpEval(ctxt,
   13661                                                &comp->steps[op->ch2]);
   13662 		    CHECK_ERROR0;
   13663                     res = valuePop(ctxt);
   13664                     if (res != NULL)
   13665                         xmlXPathFreeObject(res);
   13666 */
   13667                     valuePush(ctxt, obj);
   13668                     ctxt->context->node = oldnode;
   13669                     CHECK_ERROR0;
   13670                 } else {
   13671 		    tmp = NULL;
   13672                     /*
   13673                      * Initialize the new set.
   13674 		     * Also set the xpath document in case things like
   13675 		     * key() evaluation are attempted on the predicate
   13676                      */
   13677                     newset = xmlXPathNodeSetCreate(NULL);
   13678 		    /*
   13679 		    * SPEC XPath 1.0:
   13680 		    *  "For each node in the node-set to be filtered, the
   13681 		    *  PredicateExpr is evaluated with that node as the
   13682 		    *  context node, with the number of nodes in the
   13683 		    *  node-set as the context size, and with the proximity
   13684 		    *  position of the node in the node-set with respect to
   13685 		    *  the axis as the context position;"
   13686 		    * @oldset is the node-set" to be filtered.
   13687 		    *
   13688 		    * SPEC XPath 1.0:
   13689 		    *  "only predicates change the context position and
   13690 		    *  context size (see [2.4 Predicates])."
   13691 		    * Example:
   13692 		    *   node-set  context pos
   13693 		    *    nA         1
   13694 		    *    nB         2
   13695 		    *    nC         3
   13696 		    *   After applying predicate [position() > 1] :
   13697 		    *   node-set  context pos
   13698 		    *    nB         1
   13699 		    *    nC         2
   13700 		    *
   13701 		    * removed the first node in the node-set, then
   13702 		    * the context position of the
   13703 		    */
   13704                     for (i = 0; i < oldset->nodeNr; i++) {
   13705                         /*
   13706                          * Run the evaluation with a node list made of
   13707                          * a single item in the nodeset.
   13708                          */
   13709                         ctxt->context->node = oldset->nodeTab[i];
   13710 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13711 			    (oldset->nodeTab[i]->doc != NULL))
   13712 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13713 			if (tmp == NULL) {
   13714 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13715 				ctxt->context->node);
   13716 			} else {
   13717 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13718 				ctxt->context->node);
   13719 			}
   13720                         valuePush(ctxt, tmp);
   13721                         ctxt->context->contextSize = oldset->nodeNr;
   13722                         ctxt->context->proximityPosition = i + 1;
   13723 			/*
   13724 			* Evaluate the predicate against the context node.
   13725 			* Can/should we optimize position() predicates
   13726 			* here (e.g. "[1]")?
   13727 			*/
   13728                         if (op->ch2 != -1)
   13729                             total +=
   13730                                 xmlXPathCompOpEval(ctxt,
   13731                                                    &comp->steps[op->ch2]);
   13732 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13733 			    xmlXPathFreeNodeSet(newset);
   13734 			    xmlXPathFreeObject(obj);
   13735 			    return(0);
   13736 			}
   13737 
   13738                         /*
   13739                          * The result of the evaluation needs to be tested to
   13740                          * decide whether the filter succeeded or not
   13741                          */
   13742 			/*
   13743 			* OPTIMIZE TODO: Can we use
   13744 			* xmlXPathNodeSetAdd*Unique()* instead?
   13745 			*/
   13746                         res = valuePop(ctxt);
   13747                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13748                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
   13749                         }
   13750 
   13751                         /*
   13752                          * Cleanup
   13753                          */
   13754                         if (res != NULL) {
   13755 			    xmlXPathReleaseObject(ctxt->context, res);
   13756 			}
   13757                         if (ctxt->value == tmp) {
   13758                             valuePop(ctxt);
   13759 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13760 			    /*
   13761 			    * Don't free the temporary nodeset
   13762 			    * in order to avoid massive recreation inside this
   13763 			    * loop.
   13764 			    */
   13765                         } else
   13766 			    tmp = NULL;
   13767                         ctxt->context->node = NULL;
   13768                     }
   13769 		    if (tmp != NULL)
   13770 			xmlXPathReleaseObject(ctxt->context, tmp);
   13771                     /*
   13772                      * The result is used as the new evaluation set.
   13773                      */
   13774 		    xmlXPathReleaseObject(ctxt->context, obj);
   13775                     ctxt->context->node = NULL;
   13776                     ctxt->context->contextSize = -1;
   13777                     ctxt->context->proximityPosition = -1;
   13778 		    /* may want to move this past the '}' later */
   13779 		    ctxt->context->doc = oldDoc;
   13780 		    valuePush(ctxt,
   13781 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13782                 }
   13783                 ctxt->context->node = oldnode;
   13784                 return (total);
   13785             }
   13786         case XPATH_OP_SORT:
   13787             if (op->ch1 != -1)
   13788                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13789 	    CHECK_ERROR0;
   13790             if ((ctxt->value != NULL) &&
   13791                 (ctxt->value->type == XPATH_NODESET) &&
   13792                 (ctxt->value->nodesetval != NULL) &&
   13793 		(ctxt->value->nodesetval->nodeNr > 1))
   13794 	    {
   13795                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13796 	    }
   13797             return (total);
   13798 #ifdef LIBXML_XPTR_ENABLED
   13799         case XPATH_OP_RANGETO:{
   13800                 xmlXPathObjectPtr range;
   13801                 xmlXPathObjectPtr res, obj;
   13802                 xmlXPathObjectPtr tmp;
   13803                 xmlLocationSetPtr newlocset = NULL;
   13804 		    xmlLocationSetPtr oldlocset;
   13805                 xmlNodeSetPtr oldset;
   13806                 int i, j;
   13807 
   13808                 if (op->ch1 != -1)
   13809                     total +=
   13810                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13811                 if (op->ch2 == -1)
   13812                     return (total);
   13813 
   13814                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13815                     /*
   13816                      * Extract the old locset, and then evaluate the result of the
   13817                      * expression for all the element in the locset. use it to grow
   13818                      * up a new locset.
   13819                      */
   13820                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13821                     obj = valuePop(ctxt);
   13822                     oldlocset = obj->user;
   13823 
   13824                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13825 		        ctxt->context->node = NULL;
   13826                         ctxt->context->contextSize = 0;
   13827                         ctxt->context->proximityPosition = 0;
   13828                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   13829                         res = valuePop(ctxt);
   13830                         if (res != NULL) {
   13831 			    xmlXPathReleaseObject(ctxt->context, res);
   13832 			}
   13833                         valuePush(ctxt, obj);
   13834                         CHECK_ERROR0;
   13835                         return (total);
   13836                     }
   13837                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13838 
   13839                     for (i = 0; i < oldlocset->locNr; i++) {
   13840                         /*
   13841                          * Run the evaluation with a node list made of a
   13842                          * single item in the nodelocset.
   13843                          */
   13844                         ctxt->context->node = oldlocset->locTab[i]->user;
   13845                         ctxt->context->contextSize = oldlocset->locNr;
   13846                         ctxt->context->proximityPosition = i + 1;
   13847 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13848 			    ctxt->context->node);
   13849                         valuePush(ctxt, tmp);
   13850 
   13851                         if (op->ch2 != -1)
   13852                             total +=
   13853                                 xmlXPathCompOpEval(ctxt,
   13854                                                    &comp->steps[op->ch2]);
   13855 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13856 			    xmlXPathFreeObject(obj);
   13857 			    return(0);
   13858 			}
   13859 
   13860                         res = valuePop(ctxt);
   13861 			if (res->type == XPATH_LOCATIONSET) {
   13862 			    xmlLocationSetPtr rloc =
   13863 			        (xmlLocationSetPtr)res->user;
   13864 			    for (j=0; j<rloc->locNr; j++) {
   13865 			        range = xmlXPtrNewRange(
   13866 				  oldlocset->locTab[i]->user,
   13867 				  oldlocset->locTab[i]->index,
   13868 				  rloc->locTab[j]->user2,
   13869 				  rloc->locTab[j]->index2);
   13870 				if (range != NULL) {
   13871 				    xmlXPtrLocationSetAdd(newlocset, range);
   13872 				}
   13873 			    }
   13874 			} else {
   13875 			    range = xmlXPtrNewRangeNodeObject(
   13876 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   13877                             if (range != NULL) {
   13878                                 xmlXPtrLocationSetAdd(newlocset,range);
   13879 			    }
   13880                         }
   13881 
   13882                         /*
   13883                          * Cleanup
   13884                          */
   13885                         if (res != NULL) {
   13886 			    xmlXPathReleaseObject(ctxt->context, res);
   13887 			}
   13888                         if (ctxt->value == tmp) {
   13889                             res = valuePop(ctxt);
   13890 			    xmlXPathReleaseObject(ctxt->context, res);
   13891                         }
   13892 
   13893                         ctxt->context->node = NULL;
   13894                     }
   13895 		} else {	/* Not a location set */
   13896                     CHECK_TYPE0(XPATH_NODESET);
   13897                     obj = valuePop(ctxt);
   13898                     oldset = obj->nodesetval;
   13899                     ctxt->context->node = NULL;
   13900 
   13901                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13902 
   13903                     if (oldset != NULL) {
   13904                         for (i = 0; i < oldset->nodeNr; i++) {
   13905                             /*
   13906                              * Run the evaluation with a node list made of a single item
   13907                              * in the nodeset.
   13908                              */
   13909                             ctxt->context->node = oldset->nodeTab[i];
   13910 			    /*
   13911 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   13912 			    */
   13913 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13914 				ctxt->context->node);
   13915                             valuePush(ctxt, tmp);
   13916 
   13917                             if (op->ch2 != -1)
   13918                                 total +=
   13919                                     xmlXPathCompOpEval(ctxt,
   13920                                                    &comp->steps[op->ch2]);
   13921 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13922 				xmlXPathFreeObject(obj);
   13923 				return(0);
   13924 			    }
   13925 
   13926                             res = valuePop(ctxt);
   13927                             range =
   13928                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   13929                                                       res);
   13930                             if (range != NULL) {
   13931                                 xmlXPtrLocationSetAdd(newlocset, range);
   13932                             }
   13933 
   13934                             /*
   13935                              * Cleanup
   13936                              */
   13937                             if (res != NULL) {
   13938 				xmlXPathReleaseObject(ctxt->context, res);
   13939 			    }
   13940                             if (ctxt->value == tmp) {
   13941                                 res = valuePop(ctxt);
   13942 				xmlXPathReleaseObject(ctxt->context, res);
   13943                             }
   13944 
   13945                             ctxt->context->node = NULL;
   13946                         }
   13947                     }
   13948                 }
   13949 
   13950                 /*
   13951                  * The result is used as the new evaluation set.
   13952                  */
   13953 		xmlXPathReleaseObject(ctxt->context, obj);
   13954                 ctxt->context->node = NULL;
   13955                 ctxt->context->contextSize = -1;
   13956                 ctxt->context->proximityPosition = -1;
   13957                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13958                 return (total);
   13959             }
   13960 #endif /* LIBXML_XPTR_ENABLED */
   13961     }
   13962     xmlGenericError(xmlGenericErrorContext,
   13963                     "XPath: unknown precompiled operation %d\n", op->op);
   13964     return (total);
   13965 }
   13966 
   13967 /**
   13968  * xmlXPathCompOpEvalToBoolean:
   13969  * @ctxt:  the XPath parser context
   13970  *
   13971  * Evaluates if the expression evaluates to true.
   13972  *
   13973  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   13974  */
   13975 static int
   13976 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   13977 			    xmlXPathStepOpPtr op,
   13978 			    int isPredicate)
   13979 {
   13980     xmlXPathObjectPtr resObj = NULL;
   13981 
   13982 start:
   13983     /* comp = ctxt->comp; */
   13984     switch (op->op) {
   13985         case XPATH_OP_END:
   13986             return (0);
   13987 	case XPATH_OP_VALUE:
   13988 	    resObj = (xmlXPathObjectPtr) op->value4;
   13989 	    if (isPredicate)
   13990 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   13991 	    return(xmlXPathCastToBoolean(resObj));
   13992 	case XPATH_OP_SORT:
   13993 	    /*
   13994 	    * We don't need sorting for boolean results. Skip this one.
   13995 	    */
   13996             if (op->ch1 != -1) {
   13997 		op = &ctxt->comp->steps[op->ch1];
   13998 		goto start;
   13999 	    }
   14000 	    return(0);
   14001 	case XPATH_OP_COLLECT:
   14002 	    if (op->ch1 == -1)
   14003 		return(0);
   14004 
   14005             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14006 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14007 		return(-1);
   14008 
   14009             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14010 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14011 		return(-1);
   14012 
   14013 	    resObj = valuePop(ctxt);
   14014 	    if (resObj == NULL)
   14015 		return(-1);
   14016 	    break;
   14017 	default:
   14018 	    /*
   14019 	    * Fallback to call xmlXPathCompOpEval().
   14020 	    */
   14021 	    xmlXPathCompOpEval(ctxt, op);
   14022 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14023 		return(-1);
   14024 
   14025 	    resObj = valuePop(ctxt);
   14026 	    if (resObj == NULL)
   14027 		return(-1);
   14028 	    break;
   14029     }
   14030 
   14031     if (resObj) {
   14032 	int res;
   14033 
   14034 	if (resObj->type == XPATH_BOOLEAN) {
   14035 	    res = resObj->boolval;
   14036 	} else if (isPredicate) {
   14037 	    /*
   14038 	    * For predicates a result of type "number" is handled
   14039 	    * differently:
   14040 	    * SPEC XPath 1.0:
   14041 	    * "If the result is a number, the result will be converted
   14042 	    *  to true if the number is equal to the context position
   14043 	    *  and will be converted to false otherwise;"
   14044 	    */
   14045 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14046 	} else {
   14047 	    res = xmlXPathCastToBoolean(resObj);
   14048 	}
   14049 	xmlXPathReleaseObject(ctxt->context, resObj);
   14050 	return(res);
   14051     }
   14052 
   14053     return(0);
   14054 }
   14055 
   14056 #ifdef XPATH_STREAMING
   14057 /**
   14058  * xmlXPathRunStreamEval:
   14059  * @ctxt:  the XPath parser context with the compiled expression
   14060  *
   14061  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14062  */
   14063 static int
   14064 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14065 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14066 {
   14067     int max_depth, min_depth;
   14068     int from_root;
   14069     int ret, depth;
   14070     int eval_all_nodes;
   14071     xmlNodePtr cur = NULL, limit = NULL;
   14072     xmlStreamCtxtPtr patstream = NULL;
   14073 
   14074     int nb_nodes = 0;
   14075 
   14076     if ((ctxt == NULL) || (comp == NULL))
   14077         return(-1);
   14078     max_depth = xmlPatternMaxDepth(comp);
   14079     if (max_depth == -1)
   14080         return(-1);
   14081     if (max_depth == -2)
   14082         max_depth = 10000;
   14083     min_depth = xmlPatternMinDepth(comp);
   14084     if (min_depth == -1)
   14085         return(-1);
   14086     from_root = xmlPatternFromRoot(comp);
   14087     if (from_root < 0)
   14088         return(-1);
   14089 #if 0
   14090     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14091 #endif
   14092 
   14093     if (! toBool) {
   14094 	if (resultSeq == NULL)
   14095 	    return(-1);
   14096 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14097 	if (*resultSeq == NULL)
   14098 	    return(-1);
   14099     }
   14100 
   14101     /*
   14102      * handle the special cases of "/" amd "." being matched
   14103      */
   14104     if (min_depth == 0) {
   14105 	if (from_root) {
   14106 	    /* Select "/" */
   14107 	    if (toBool)
   14108 		return(1);
   14109 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14110 		(xmlNodePtr) ctxt->doc);
   14111 	} else {
   14112 	    /* Select "self::node()" */
   14113 	    if (toBool)
   14114 		return(1);
   14115 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14116 	}
   14117     }
   14118     if (max_depth == 0) {
   14119 	return(0);
   14120     }
   14121 
   14122     if (from_root) {
   14123         cur = (xmlNodePtr)ctxt->doc;
   14124     } else if (ctxt->node != NULL) {
   14125         switch (ctxt->node->type) {
   14126             case XML_ELEMENT_NODE:
   14127             case XML_DOCUMENT_NODE:
   14128             case XML_DOCUMENT_FRAG_NODE:
   14129             case XML_HTML_DOCUMENT_NODE:
   14130 #ifdef LIBXML_DOCB_ENABLED
   14131             case XML_DOCB_DOCUMENT_NODE:
   14132 #endif
   14133 	        cur = ctxt->node;
   14134 		break;
   14135             case XML_ATTRIBUTE_NODE:
   14136             case XML_TEXT_NODE:
   14137             case XML_CDATA_SECTION_NODE:
   14138             case XML_ENTITY_REF_NODE:
   14139             case XML_ENTITY_NODE:
   14140             case XML_PI_NODE:
   14141             case XML_COMMENT_NODE:
   14142             case XML_NOTATION_NODE:
   14143             case XML_DTD_NODE:
   14144             case XML_DOCUMENT_TYPE_NODE:
   14145             case XML_ELEMENT_DECL:
   14146             case XML_ATTRIBUTE_DECL:
   14147             case XML_ENTITY_DECL:
   14148             case XML_NAMESPACE_DECL:
   14149             case XML_XINCLUDE_START:
   14150             case XML_XINCLUDE_END:
   14151 		break;
   14152 	}
   14153 	limit = cur;
   14154     }
   14155     if (cur == NULL) {
   14156         return(0);
   14157     }
   14158 
   14159     patstream = xmlPatternGetStreamCtxt(comp);
   14160     if (patstream == NULL) {
   14161 	/*
   14162 	* QUESTION TODO: Is this an error?
   14163 	*/
   14164 	return(0);
   14165     }
   14166 
   14167     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14168 
   14169     if (from_root) {
   14170 	ret = xmlStreamPush(patstream, NULL, NULL);
   14171 	if (ret < 0) {
   14172 	} else if (ret == 1) {
   14173 	    if (toBool)
   14174 		goto return_1;
   14175 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14176 	}
   14177     }
   14178     depth = 0;
   14179     goto scan_children;
   14180 next_node:
   14181     do {
   14182         nb_nodes++;
   14183 
   14184 	switch (cur->type) {
   14185 	    case XML_ELEMENT_NODE:
   14186 	    case XML_TEXT_NODE:
   14187 	    case XML_CDATA_SECTION_NODE:
   14188 	    case XML_COMMENT_NODE:
   14189 	    case XML_PI_NODE:
   14190 		if (cur->type == XML_ELEMENT_NODE) {
   14191 		    ret = xmlStreamPush(patstream, cur->name,
   14192 				(cur->ns ? cur->ns->href : NULL));
   14193 		} else if (eval_all_nodes)
   14194 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14195 		else
   14196 		    break;
   14197 
   14198 		if (ret < 0) {
   14199 		    /* NOP. */
   14200 		} else if (ret == 1) {
   14201 		    if (toBool)
   14202 			goto return_1;
   14203 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14204 		}
   14205 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14206 		    ret = xmlStreamPop(patstream);
   14207 		    while (cur->next != NULL) {
   14208 			cur = cur->next;
   14209 			if ((cur->type != XML_ENTITY_DECL) &&
   14210 			    (cur->type != XML_DTD_NODE))
   14211 			    goto next_node;
   14212 		    }
   14213 		}
   14214 	    default:
   14215 		break;
   14216 	}
   14217 
   14218 scan_children:
   14219 	if ((cur->children != NULL) && (depth < max_depth)) {
   14220 	    /*
   14221 	     * Do not descend on entities declarations
   14222 	     */
   14223 	    if (cur->children->type != XML_ENTITY_DECL) {
   14224 		cur = cur->children;
   14225 		depth++;
   14226 		/*
   14227 		 * Skip DTDs
   14228 		 */
   14229 		if (cur->type != XML_DTD_NODE)
   14230 		    continue;
   14231 	    }
   14232 	}
   14233 
   14234 	if (cur == limit)
   14235 	    break;
   14236 
   14237 	while (cur->next != NULL) {
   14238 	    cur = cur->next;
   14239 	    if ((cur->type != XML_ENTITY_DECL) &&
   14240 		(cur->type != XML_DTD_NODE))
   14241 		goto next_node;
   14242 	}
   14243 
   14244 	do {
   14245 	    cur = cur->parent;
   14246 	    depth--;
   14247 	    if ((cur == NULL) || (cur == limit))
   14248 	        goto done;
   14249 	    if (cur->type == XML_ELEMENT_NODE) {
   14250 		ret = xmlStreamPop(patstream);
   14251 	    } else if ((eval_all_nodes) &&
   14252 		((cur->type == XML_TEXT_NODE) ||
   14253 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14254 		 (cur->type == XML_COMMENT_NODE) ||
   14255 		 (cur->type == XML_PI_NODE)))
   14256 	    {
   14257 		ret = xmlStreamPop(patstream);
   14258 	    }
   14259 	    if (cur->next != NULL) {
   14260 		cur = cur->next;
   14261 		break;
   14262 	    }
   14263 	} while (cur != NULL);
   14264 
   14265     } while ((cur != NULL) && (depth >= 0));
   14266 
   14267 done:
   14268 
   14269 #if 0
   14270     printf("stream eval: checked %d nodes selected %d\n",
   14271            nb_nodes, retObj->nodesetval->nodeNr);
   14272 #endif
   14273 
   14274     if (patstream)
   14275 	xmlFreeStreamCtxt(patstream);
   14276     return(0);
   14277 
   14278 return_1:
   14279     if (patstream)
   14280 	xmlFreeStreamCtxt(patstream);
   14281     return(1);
   14282 }
   14283 #endif /* XPATH_STREAMING */
   14284 
   14285 /**
   14286  * xmlXPathRunEval:
   14287  * @ctxt:  the XPath parser context with the compiled expression
   14288  * @toBool:  evaluate to a boolean result
   14289  *
   14290  * Evaluate the Precompiled XPath expression in the given context.
   14291  */
   14292 static int
   14293 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14294 {
   14295     xmlXPathCompExprPtr comp;
   14296 
   14297     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14298 	return(-1);
   14299 
   14300     if (ctxt->valueTab == NULL) {
   14301 	/* Allocate the value stack */
   14302 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14303 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14304 	if (ctxt->valueTab == NULL) {
   14305 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14306 	    xmlFree(ctxt);
   14307 	}
   14308 	ctxt->valueNr = 0;
   14309 	ctxt->valueMax = 10;
   14310 	ctxt->value = NULL;
   14311     }
   14312 #ifdef XPATH_STREAMING
   14313     if (ctxt->comp->stream) {
   14314 	int res;
   14315 
   14316 	if (toBool) {
   14317 	    /*
   14318 	    * Evaluation to boolean result.
   14319 	    */
   14320 	    res = xmlXPathRunStreamEval(ctxt->context,
   14321 		ctxt->comp->stream, NULL, 1);
   14322 	    if (res != -1)
   14323 		return(res);
   14324 	} else {
   14325 	    xmlXPathObjectPtr resObj = NULL;
   14326 
   14327 	    /*
   14328 	    * Evaluation to a sequence.
   14329 	    */
   14330 	    res = xmlXPathRunStreamEval(ctxt->context,
   14331 		ctxt->comp->stream, &resObj, 0);
   14332 
   14333 	    if ((res != -1) && (resObj != NULL)) {
   14334 		valuePush(ctxt, resObj);
   14335 		return(0);
   14336 	    }
   14337 	    if (resObj != NULL)
   14338 		xmlXPathReleaseObject(ctxt->context, resObj);
   14339 	}
   14340 	/*
   14341 	* QUESTION TODO: This falls back to normal XPath evaluation
   14342 	* if res == -1. Is this intended?
   14343 	*/
   14344     }
   14345 #endif
   14346     comp = ctxt->comp;
   14347     if (comp->last < 0) {
   14348 	xmlGenericError(xmlGenericErrorContext,
   14349 	    "xmlXPathRunEval: last is less than zero\n");
   14350 	return(-1);
   14351     }
   14352     if (toBool)
   14353 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14354 	    &comp->steps[comp->last], 0));
   14355     else
   14356 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14357 
   14358     return(0);
   14359 }
   14360 
   14361 /************************************************************************
   14362  *									*
   14363  *			Public interfaces				*
   14364  *									*
   14365  ************************************************************************/
   14366 
   14367 /**
   14368  * xmlXPathEvalPredicate:
   14369  * @ctxt:  the XPath context
   14370  * @res:  the Predicate Expression evaluation result
   14371  *
   14372  * Evaluate a predicate result for the current node.
   14373  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14374  * the result to a boolean. If the result is a number, the result will
   14375  * be converted to true if the number is equal to the position of the
   14376  * context node in the context node list (as returned by the position
   14377  * function) and will be converted to false otherwise; if the result
   14378  * is not a number, then the result will be converted as if by a call
   14379  * to the boolean function.
   14380  *
   14381  * Returns 1 if predicate is true, 0 otherwise
   14382  */
   14383 int
   14384 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14385     if ((ctxt == NULL) || (res == NULL)) return(0);
   14386     switch (res->type) {
   14387         case XPATH_BOOLEAN:
   14388 	    return(res->boolval);
   14389         case XPATH_NUMBER:
   14390 	    return(res->floatval == ctxt->proximityPosition);
   14391         case XPATH_NODESET:
   14392         case XPATH_XSLT_TREE:
   14393 	    if (res->nodesetval == NULL)
   14394 		return(0);
   14395 	    return(res->nodesetval->nodeNr != 0);
   14396         case XPATH_STRING:
   14397 	    return((res->stringval != NULL) &&
   14398 	           (xmlStrlen(res->stringval) != 0));
   14399         default:
   14400 	    STRANGE
   14401     }
   14402     return(0);
   14403 }
   14404 
   14405 /**
   14406  * xmlXPathEvaluatePredicateResult:
   14407  * @ctxt:  the XPath Parser context
   14408  * @res:  the Predicate Expression evaluation result
   14409  *
   14410  * Evaluate a predicate result for the current node.
   14411  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14412  * the result to a boolean. If the result is a number, the result will
   14413  * be converted to true if the number is equal to the position of the
   14414  * context node in the context node list (as returned by the position
   14415  * function) and will be converted to false otherwise; if the result
   14416  * is not a number, then the result will be converted as if by a call
   14417  * to the boolean function.
   14418  *
   14419  * Returns 1 if predicate is true, 0 otherwise
   14420  */
   14421 int
   14422 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14423                                 xmlXPathObjectPtr res) {
   14424     if ((ctxt == NULL) || (res == NULL)) return(0);
   14425     switch (res->type) {
   14426         case XPATH_BOOLEAN:
   14427 	    return(res->boolval);
   14428         case XPATH_NUMBER:
   14429 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14430 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14431 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14432 #else
   14433 	    return(res->floatval == ctxt->context->proximityPosition);
   14434 #endif
   14435         case XPATH_NODESET:
   14436         case XPATH_XSLT_TREE:
   14437 	    if (res->nodesetval == NULL)
   14438 		return(0);
   14439 	    return(res->nodesetval->nodeNr != 0);
   14440         case XPATH_STRING:
   14441 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14442 #ifdef LIBXML_XPTR_ENABLED
   14443 	case XPATH_LOCATIONSET:{
   14444 	    xmlLocationSetPtr ptr = res->user;
   14445 	    if (ptr == NULL)
   14446 	        return(0);
   14447 	    return (ptr->locNr != 0);
   14448 	    }
   14449 #endif
   14450         default:
   14451 	    STRANGE
   14452     }
   14453     return(0);
   14454 }
   14455 
   14456 #ifdef XPATH_STREAMING
   14457 /**
   14458  * xmlXPathTryStreamCompile:
   14459  * @ctxt: an XPath context
   14460  * @str:  the XPath expression
   14461  *
   14462  * Try to compile the XPath expression as a streamable subset.
   14463  *
   14464  * Returns the compiled expression or NULL if failed to compile.
   14465  */
   14466 static xmlXPathCompExprPtr
   14467 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14468     /*
   14469      * Optimization: use streaming patterns when the XPath expression can
   14470      * be compiled to a stream lookup
   14471      */
   14472     xmlPatternPtr stream;
   14473     xmlXPathCompExprPtr comp;
   14474     xmlDictPtr dict = NULL;
   14475     const xmlChar **namespaces = NULL;
   14476     xmlNsPtr ns;
   14477     int i, j;
   14478 
   14479     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14480         (!xmlStrchr(str, '@'))) {
   14481 	const xmlChar *tmp;
   14482 
   14483 	/*
   14484 	 * We don't try to handle expressions using the verbose axis
   14485 	 * specifiers ("::"), just the simplied form at this point.
   14486 	 * Additionally, if there is no list of namespaces available and
   14487 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14488 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14489 	 *  to have a list of namespaces at compilation time in order to
   14490 	 *  compile prefixed name tests.
   14491 	 */
   14492 	tmp = xmlStrchr(str, ':');
   14493 	if ((tmp != NULL) &&
   14494 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14495 	    return(NULL);
   14496 
   14497 	if (ctxt != NULL) {
   14498 	    dict = ctxt->dict;
   14499 	    if (ctxt->nsNr > 0) {
   14500 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14501 		if (namespaces == NULL) {
   14502 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14503 		    return(NULL);
   14504 		}
   14505 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14506 		    ns = ctxt->namespaces[j];
   14507 		    namespaces[i++] = ns->href;
   14508 		    namespaces[i++] = ns->prefix;
   14509 		}
   14510 		namespaces[i++] = NULL;
   14511 		namespaces[i++] = NULL;
   14512 	    }
   14513 	}
   14514 
   14515 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14516 			&namespaces[0]);
   14517 	if (namespaces != NULL) {
   14518 	    xmlFree((xmlChar **)namespaces);
   14519 	}
   14520 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14521 	    comp = xmlXPathNewCompExpr();
   14522 	    if (comp == NULL) {
   14523 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14524 		return(NULL);
   14525 	    }
   14526 	    comp->stream = stream;
   14527 	    comp->dict = dict;
   14528 	    if (comp->dict)
   14529 		xmlDictReference(comp->dict);
   14530 	    return(comp);
   14531 	}
   14532 	xmlFreePattern(stream);
   14533     }
   14534     return(NULL);
   14535 }
   14536 #endif /* XPATH_STREAMING */
   14537 
   14538 static int
   14539 xmlXPathCanRewriteDosExpression(xmlChar *expr)
   14540 {
   14541     if (expr == NULL)
   14542 	return(0);
   14543     do {
   14544         if ((*expr == '/') && (*(++expr) == '/'))
   14545 	    return(1);
   14546     } while (*expr++);
   14547     return(0);
   14548 }
   14549 static void
   14550 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14551 {
   14552     /*
   14553     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14554     * internal representation.
   14555     */
   14556     if (op->ch1 != -1) {
   14557 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14558 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
   14559 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
   14560 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
   14561 	{
   14562 	    /*
   14563 	    * This is a "child::foo"
   14564 	    */
   14565 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14566 
   14567 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14568 		(prevop->ch1 != -1) &&
   14569 		((xmlXPathAxisVal) prevop->value ==
   14570 		    AXIS_DESCENDANT_OR_SELF) &&
   14571 		(prevop->ch2 == -1) &&
   14572 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14573 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
   14574 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
   14575 	    {
   14576 		/*
   14577 		* This is a "/descendant-or-self::node()" without predicates.
   14578 		* Eliminate it.
   14579 		*/
   14580 		op->ch1 = prevop->ch1;
   14581 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
   14582 	    }
   14583 	}
   14584 	if (op->ch1 != -1)
   14585 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
   14586     }
   14587     if (op->ch2 != -1)
   14588 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
   14589 }
   14590 
   14591 /**
   14592  * xmlXPathCtxtCompile:
   14593  * @ctxt: an XPath context
   14594  * @str:  the XPath expression
   14595  *
   14596  * Compile an XPath expression
   14597  *
   14598  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14599  *         the caller has to free the object.
   14600  */
   14601 xmlXPathCompExprPtr
   14602 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14603     xmlXPathParserContextPtr pctxt;
   14604     xmlXPathCompExprPtr comp;
   14605 
   14606 #ifdef XPATH_STREAMING
   14607     comp = xmlXPathTryStreamCompile(ctxt, str);
   14608     if (comp != NULL)
   14609         return(comp);
   14610 #endif
   14611 
   14612     xmlXPathInit();
   14613 
   14614     pctxt = xmlXPathNewParserContext(str, ctxt);
   14615     if (pctxt == NULL)
   14616         return NULL;
   14617     xmlXPathCompileExpr(pctxt, 1);
   14618 
   14619     if( pctxt->error != XPATH_EXPRESSION_OK )
   14620     {
   14621         xmlXPathFreeParserContext(pctxt);
   14622         return(NULL);
   14623     }
   14624 
   14625     if (*pctxt->cur != 0) {
   14626 	/*
   14627 	 * aleksey: in some cases this line prints *second* error message
   14628 	 * (see bug #78858) and probably this should be fixed.
   14629 	 * However, we are not sure that all error messages are printed
   14630 	 * out in other places. It's not critical so we leave it as-is for now
   14631 	 */
   14632 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14633 	comp = NULL;
   14634     } else {
   14635 	comp = pctxt->comp;
   14636 	pctxt->comp = NULL;
   14637     }
   14638     xmlXPathFreeParserContext(pctxt);
   14639 
   14640     if (comp != NULL) {
   14641 	comp->expr = xmlStrdup(str);
   14642 #ifdef DEBUG_EVAL_COUNTS
   14643 	comp->string = xmlStrdup(str);
   14644 	comp->nb = 0;
   14645 #endif
   14646 	if ((comp->expr != NULL) &&
   14647 	    (comp->nbStep > 2) &&
   14648 	    (comp->last >= 0) &&
   14649 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
   14650 	{
   14651 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
   14652 	}
   14653     }
   14654     return(comp);
   14655 }
   14656 
   14657 /**
   14658  * xmlXPathCompile:
   14659  * @str:  the XPath expression
   14660  *
   14661  * Compile an XPath expression
   14662  *
   14663  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14664  *         the caller has to free the object.
   14665  */
   14666 xmlXPathCompExprPtr
   14667 xmlXPathCompile(const xmlChar *str) {
   14668     return(xmlXPathCtxtCompile(NULL, str));
   14669 }
   14670 
   14671 /**
   14672  * xmlXPathCompiledEvalInternal:
   14673  * @comp:  the compiled XPath expression
   14674  * @ctxt:  the XPath context
   14675  * @resObj: the resulting XPath object or NULL
   14676  * @toBool: 1 if only a boolean result is requested
   14677  *
   14678  * Evaluate the Precompiled XPath expression in the given context.
   14679  * The caller has to free @resObj.
   14680  *
   14681  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14682  *         the caller has to free the object.
   14683  */
   14684 static int
   14685 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14686 			     xmlXPathContextPtr ctxt,
   14687 			     xmlXPathObjectPtr *resObj,
   14688 			     int toBool)
   14689 {
   14690     xmlXPathParserContextPtr pctxt;
   14691 #ifndef LIBXML_THREAD_ENABLED
   14692     static int reentance = 0;
   14693 #endif
   14694     int res;
   14695 
   14696     CHECK_CTXT_NEG(ctxt)
   14697 
   14698     if (comp == NULL)
   14699 	return(-1);
   14700     xmlXPathInit();
   14701 
   14702 #ifndef LIBXML_THREAD_ENABLED
   14703     reentance++;
   14704     if (reentance > 1)
   14705 	xmlXPathDisableOptimizer = 1;
   14706 #endif
   14707 
   14708 #ifdef DEBUG_EVAL_COUNTS
   14709     comp->nb++;
   14710     if ((comp->string != NULL) && (comp->nb > 100)) {
   14711 	fprintf(stderr, "100 x %s\n", comp->string);
   14712 	comp->nb = 0;
   14713     }
   14714 #endif
   14715     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14716     res = xmlXPathRunEval(pctxt, toBool);
   14717 
   14718     if (resObj) {
   14719 	if (pctxt->value == NULL) {
   14720 	    xmlGenericError(xmlGenericErrorContext,
   14721 		"xmlXPathCompiledEval: evaluation failed\n");
   14722 	    *resObj = NULL;
   14723 	} else {
   14724 	    *resObj = valuePop(pctxt);
   14725 	}
   14726     }
   14727 
   14728     /*
   14729     * Pop all remaining objects from the stack.
   14730     */
   14731     if (pctxt->valueNr > 0) {
   14732 	xmlXPathObjectPtr tmp;
   14733 	int stack = 0;
   14734 
   14735 	do {
   14736 	    tmp = valuePop(pctxt);
   14737 	    if (tmp != NULL) {
   14738 		stack++;
   14739 		xmlXPathReleaseObject(ctxt, tmp);
   14740 	    }
   14741 	} while (tmp != NULL);
   14742 	if ((stack != 0) &&
   14743 	    ((toBool) || ((resObj) && (*resObj))))
   14744 	{
   14745 	    xmlGenericError(xmlGenericErrorContext,
   14746 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14747 		stack);
   14748 	}
   14749     }
   14750 
   14751     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14752 	xmlXPathFreeObject(*resObj);
   14753 	*resObj = NULL;
   14754     }
   14755     pctxt->comp = NULL;
   14756     xmlXPathFreeParserContext(pctxt);
   14757 #ifndef LIBXML_THREAD_ENABLED
   14758     reentance--;
   14759 #endif
   14760 
   14761     return(res);
   14762 }
   14763 
   14764 /**
   14765  * xmlXPathCompiledEval:
   14766  * @comp:  the compiled XPath expression
   14767  * @ctx:  the XPath context
   14768  *
   14769  * Evaluate the Precompiled XPath expression in the given context.
   14770  *
   14771  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14772  *         the caller has to free the object.
   14773  */
   14774 xmlXPathObjectPtr
   14775 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14776 {
   14777     xmlXPathObjectPtr res = NULL;
   14778 
   14779     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14780     return(res);
   14781 }
   14782 
   14783 /**
   14784  * xmlXPathCompiledEvalToBoolean:
   14785  * @comp:  the compiled XPath expression
   14786  * @ctxt:  the XPath context
   14787  *
   14788  * Applies the XPath boolean() function on the result of the given
   14789  * compiled expression.
   14790  *
   14791  * Returns 1 if the expression evaluated to true, 0 if to false and
   14792  *         -1 in API and internal errors.
   14793  */
   14794 int
   14795 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14796 			      xmlXPathContextPtr ctxt)
   14797 {
   14798     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14799 }
   14800 
   14801 /**
   14802  * xmlXPathEvalExpr:
   14803  * @ctxt:  the XPath Parser context
   14804  *
   14805  * Parse and evaluate an XPath expression in the given context,
   14806  * then push the result on the context stack
   14807  */
   14808 void
   14809 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14810 #ifdef XPATH_STREAMING
   14811     xmlXPathCompExprPtr comp;
   14812 #endif
   14813 
   14814     if (ctxt == NULL) return;
   14815 
   14816 #ifdef XPATH_STREAMING
   14817     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14818     if (comp != NULL) {
   14819         if (ctxt->comp != NULL)
   14820 	    xmlXPathFreeCompExpr(ctxt->comp);
   14821         ctxt->comp = comp;
   14822 	if (ctxt->cur != NULL)
   14823 	    while (*ctxt->cur != 0) ctxt->cur++;
   14824     } else
   14825 #endif
   14826     {
   14827 	xmlXPathCompileExpr(ctxt, 1);
   14828 	/*
   14829 	* In this scenario the expression string will sit in ctxt->base.
   14830 	*/
   14831 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   14832 	    (ctxt->comp != NULL) &&
   14833 	    (ctxt->base != NULL) &&
   14834 	    (ctxt->comp->nbStep > 2) &&
   14835 	    (ctxt->comp->last >= 0) &&
   14836 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
   14837 	{
   14838 	    xmlXPathRewriteDOSExpression(ctxt->comp,
   14839 		&ctxt->comp->steps[ctxt->comp->last]);
   14840 	}
   14841     }
   14842     CHECK_ERROR;
   14843     xmlXPathRunEval(ctxt, 0);
   14844 }
   14845 
   14846 /**
   14847  * xmlXPathEval:
   14848  * @str:  the XPath expression
   14849  * @ctx:  the XPath context
   14850  *
   14851  * Evaluate the XPath Location Path in the given context.
   14852  *
   14853  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14854  *         the caller has to free the object.
   14855  */
   14856 xmlXPathObjectPtr
   14857 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   14858     xmlXPathParserContextPtr ctxt;
   14859     xmlXPathObjectPtr res, tmp, init = NULL;
   14860     int stack = 0;
   14861 
   14862     CHECK_CTXT(ctx)
   14863 
   14864     xmlXPathInit();
   14865 
   14866     ctxt = xmlXPathNewParserContext(str, ctx);
   14867     if (ctxt == NULL)
   14868         return NULL;
   14869     xmlXPathEvalExpr(ctxt);
   14870 
   14871     if (ctxt->value == NULL) {
   14872 	xmlGenericError(xmlGenericErrorContext,
   14873 		"xmlXPathEval: evaluation failed\n");
   14874 	res = NULL;
   14875     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   14876 #ifdef XPATH_STREAMING
   14877             && (ctxt->comp->stream == NULL)
   14878 #endif
   14879 	      ) {
   14880 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14881 	res = NULL;
   14882     } else {
   14883 	res = valuePop(ctxt);
   14884     }
   14885 
   14886     do {
   14887         tmp = valuePop(ctxt);
   14888 	if (tmp != NULL) {
   14889 	    if (tmp != init)
   14890 		stack++;
   14891 	    xmlXPathReleaseObject(ctx, tmp);
   14892         }
   14893     } while (tmp != NULL);
   14894     if ((stack != 0) && (res != NULL)) {
   14895 	xmlGenericError(xmlGenericErrorContext,
   14896 		"xmlXPathEval: %d object left on the stack\n",
   14897 	        stack);
   14898     }
   14899     if (ctxt->error != XPATH_EXPRESSION_OK) {
   14900 	xmlXPathFreeObject(res);
   14901 	res = NULL;
   14902     }
   14903 
   14904     xmlXPathFreeParserContext(ctxt);
   14905     return(res);
   14906 }
   14907 
   14908 /**
   14909  * xmlXPathEvalExpression:
   14910  * @str:  the XPath expression
   14911  * @ctxt:  the XPath context
   14912  *
   14913  * Evaluate the XPath expression in the given context.
   14914  *
   14915  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14916  *         the caller has to free the object.
   14917  */
   14918 xmlXPathObjectPtr
   14919 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   14920     xmlXPathParserContextPtr pctxt;
   14921     xmlXPathObjectPtr res, tmp;
   14922     int stack = 0;
   14923 
   14924     CHECK_CTXT(ctxt)
   14925 
   14926     xmlXPathInit();
   14927 
   14928     pctxt = xmlXPathNewParserContext(str, ctxt);
   14929     if (pctxt == NULL)
   14930         return NULL;
   14931     xmlXPathEvalExpr(pctxt);
   14932 
   14933     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   14934 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14935 	res = NULL;
   14936     } else {
   14937 	res = valuePop(pctxt);
   14938     }
   14939     do {
   14940         tmp = valuePop(pctxt);
   14941 	if (tmp != NULL) {
   14942 	    xmlXPathReleaseObject(ctxt, tmp);
   14943 	    stack++;
   14944 	}
   14945     } while (tmp != NULL);
   14946     if ((stack != 0) && (res != NULL)) {
   14947 	xmlGenericError(xmlGenericErrorContext,
   14948 		"xmlXPathEvalExpression: %d object left on the stack\n",
   14949 	        stack);
   14950     }
   14951     xmlXPathFreeParserContext(pctxt);
   14952     return(res);
   14953 }
   14954 
   14955 /************************************************************************
   14956  *									*
   14957  *	Extra functions not pertaining to the XPath spec		*
   14958  *									*
   14959  ************************************************************************/
   14960 /**
   14961  * xmlXPathEscapeUriFunction:
   14962  * @ctxt:  the XPath Parser context
   14963  * @nargs:  the number of arguments
   14964  *
   14965  * Implement the escape-uri() XPath function
   14966  *    string escape-uri(string $str, bool $escape-reserved)
   14967  *
   14968  * This function applies the URI escaping rules defined in section 2 of [RFC
   14969  * 2396] to the string supplied as $uri-part, which typically represents all
   14970  * or part of a URI. The effect of the function is to replace any special
   14971  * character in the string by an escape sequence of the form %xx%yy...,
   14972  * where xxyy... is the hexadecimal representation of the octets used to
   14973  * represent the character in UTF-8.
   14974  *
   14975  * The set of characters that are escaped depends on the setting of the
   14976  * boolean argument $escape-reserved.
   14977  *
   14978  * If $escape-reserved is true, all characters are escaped other than lower
   14979  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   14980  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   14981  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   14982  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   14983  * A-F).
   14984  *
   14985  * If $escape-reserved is false, the behavior differs in that characters
   14986  * referred to in [RFC 2396] as reserved characters are not escaped. These
   14987  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   14988  *
   14989  * [RFC 2396] does not define whether escaped URIs should use lower case or
   14990  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   14991  * compared using string comparison functions, this function must always use
   14992  * the upper-case letters A-F.
   14993  *
   14994  * Generally, $escape-reserved should be set to true when escaping a string
   14995  * that is to form a single part of a URI, and to false when escaping an
   14996  * entire URI or URI reference.
   14997  *
   14998  * In the case of non-ascii characters, the string is encoded according to
   14999  * utf-8 and then converted according to RFC 2396.
   15000  *
   15001  * Examples
   15002  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15003  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15004  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15005  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15006  *
   15007  */
   15008 static void
   15009 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15010     xmlXPathObjectPtr str;
   15011     int escape_reserved;
   15012     xmlBufferPtr target;
   15013     xmlChar *cptr;
   15014     xmlChar escape[4];
   15015 
   15016     CHECK_ARITY(2);
   15017 
   15018     escape_reserved = xmlXPathPopBoolean(ctxt);
   15019 
   15020     CAST_TO_STRING;
   15021     str = valuePop(ctxt);
   15022 
   15023     target = xmlBufferCreate();
   15024 
   15025     escape[0] = '%';
   15026     escape[3] = 0;
   15027 
   15028     if (target) {
   15029 	for (cptr = str->stringval; *cptr; cptr++) {
   15030 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15031 		(*cptr >= 'a' && *cptr <= 'z') ||
   15032 		(*cptr >= '0' && *cptr <= '9') ||
   15033 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15034 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15035 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15036 		(*cptr == '%' &&
   15037 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15038 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15039 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15040 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15041 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15042 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15043 		(!escape_reserved &&
   15044 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15045 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15046 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15047 		  *cptr == ','))) {
   15048 		xmlBufferAdd(target, cptr, 1);
   15049 	    } else {
   15050 		if ((*cptr >> 4) < 10)
   15051 		    escape[1] = '0' + (*cptr >> 4);
   15052 		else
   15053 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15054 		if ((*cptr & 0xF) < 10)
   15055 		    escape[2] = '0' + (*cptr & 0xF);
   15056 		else
   15057 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15058 
   15059 		xmlBufferAdd(target, &escape[0], 3);
   15060 	    }
   15061 	}
   15062     }
   15063     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15064 	xmlBufferContent(target)));
   15065     xmlBufferFree(target);
   15066     xmlXPathReleaseObject(ctxt->context, str);
   15067 }
   15068 
   15069 /**
   15070  * xmlXPathRegisterAllFunctions:
   15071  * @ctxt:  the XPath context
   15072  *
   15073  * Registers all default XPath functions in this context
   15074  */
   15075 void
   15076 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15077 {
   15078     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15079                          xmlXPathBooleanFunction);
   15080     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15081                          xmlXPathCeilingFunction);
   15082     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15083                          xmlXPathCountFunction);
   15084     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15085                          xmlXPathConcatFunction);
   15086     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15087                          xmlXPathContainsFunction);
   15088     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15089                          xmlXPathIdFunction);
   15090     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15091                          xmlXPathFalseFunction);
   15092     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15093                          xmlXPathFloorFunction);
   15094     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15095                          xmlXPathLastFunction);
   15096     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15097                          xmlXPathLangFunction);
   15098     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15099                          xmlXPathLocalNameFunction);
   15100     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15101                          xmlXPathNotFunction);
   15102     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15103                          xmlXPathNameFunction);
   15104     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15105                          xmlXPathNamespaceURIFunction);
   15106     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15107                          xmlXPathNormalizeFunction);
   15108     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15109                          xmlXPathNumberFunction);
   15110     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15111                          xmlXPathPositionFunction);
   15112     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15113                          xmlXPathRoundFunction);
   15114     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15115                          xmlXPathStringFunction);
   15116     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15117                          xmlXPathStringLengthFunction);
   15118     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15119                          xmlXPathStartsWithFunction);
   15120     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15121                          xmlXPathSubstringFunction);
   15122     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15123                          xmlXPathSubstringBeforeFunction);
   15124     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15125                          xmlXPathSubstringAfterFunction);
   15126     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15127                          xmlXPathSumFunction);
   15128     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15129                          xmlXPathTrueFunction);
   15130     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15131                          xmlXPathTranslateFunction);
   15132 
   15133     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15134 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15135                          xmlXPathEscapeUriFunction);
   15136 }
   15137 
   15138 #endif /* LIBXML_XPATH_ENABLED */
   15139 #define bottom_xpath
   15140 #include "elfgcchack.h"
   15141