Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * xpath.c: XML Path Language implementation
      3  *          XPath is a language for addressing parts of an XML document,
      4  *          designed to be used by both XSLT and XPointer
      5  *f
      6  * Reference: W3C Recommendation 16 November 1999
      7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
      8  * Public reference:
      9  *     http://www.w3.org/TR/xpath
     10  *
     11  * See Copyright for the status of this software
     12  *
     13  * Author: daniel (at) veillard.com
     14  *
     15  */
     16 
     17 #define IN_LIBXML
     18 #include "libxml.h"
     19 
     20 #include <string.h>
     21 
     22 #ifdef HAVE_SYS_TYPES_H
     23 #include <sys/types.h>
     24 #endif
     25 #ifdef HAVE_MATH_H
     26 #include <math.h>
     27 #endif
     28 #ifdef HAVE_FLOAT_H
     29 #include <float.h>
     30 #endif
     31 #ifdef HAVE_CTYPE_H
     32 #include <ctype.h>
     33 #endif
     34 #ifdef HAVE_SIGNAL_H
     35 #include <signal.h>
     36 #endif
     37 
     38 #include <libxml/xmlmemory.h>
     39 #include <libxml/tree.h>
     40 #include <libxml/valid.h>
     41 #include <libxml/xpath.h>
     42 #include <libxml/xpathInternals.h>
     43 #include <libxml/parserInternals.h>
     44 #include <libxml/hash.h>
     45 #ifdef LIBXML_XPTR_ENABLED
     46 #include <libxml/xpointer.h>
     47 #endif
     48 #ifdef LIBXML_DEBUG_ENABLED
     49 #include <libxml/debugXML.h>
     50 #endif
     51 #include <libxml/xmlerror.h>
     52 #include <libxml/threads.h>
     53 #include <libxml/globals.h>
     54 #ifdef LIBXML_PATTERN_ENABLED
     55 #include <libxml/pattern.h>
     56 #endif
     57 
     58 #ifdef LIBXML_PATTERN_ENABLED
     59 #define XPATH_STREAMING
     60 #endif
     61 
     62 #define TODO								\
     63     xmlGenericError(xmlGenericErrorContext,				\
     64 	    "Unimplemented block at %s:%d\n",				\
     65             __FILE__, __LINE__);
     66 
     67 /*
     68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
     69 * If defined, this will use xmlXPathCmpNodesExt() instead of
     70 * xmlXPathCmpNodes(). The new function is optimized comparison of
     71 * non-element nodes; actually it will speed up comparison only if
     72 * xmlXPathOrderDocElems() was called in order to index the elements of
     73 * a tree in document order; Libxslt does such an indexing, thus it will
     74 * benefit from this optimization.
     75 */
     76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
     77 
     78 /*
     79 * XP_OPTIMIZED_FILTER_FIRST:
     80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
     81 * in a way, that it stop evaluation at the first node.
     82 */
     83 #define XP_OPTIMIZED_FILTER_FIRST
     84 
     85 /*
     86 * XP_DEBUG_OBJ_USAGE:
     87 * Internal flag to enable tracking of how much XPath objects have been
     88 * created.
     89 */
     90 /* #define XP_DEBUG_OBJ_USAGE */
     91 
     92 /*
     93  * TODO:
     94  * There are a few spots where some tests are done which depend upon ascii
     95  * data.  These should be enhanced for full UTF8 support (see particularly
     96  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
     97  */
     98 
     99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
    100 
    101 /************************************************************************
    102  *									*
    103  *			Floating point stuff				*
    104  *									*
    105  ************************************************************************/
    106 
    107 #ifndef TRIO_REPLACE_STDIO
    108 #define TRIO_PUBLIC static
    109 #endif
    110 #include "trionan.c"
    111 
    112 /*
    113  * The lack of portability of this section of the libc is annoying !
    114  */
    115 double xmlXPathNAN = 0;
    116 double xmlXPathPINF = 1;
    117 double xmlXPathNINF = -1;
    118 static double xmlXPathNZERO = 0; /* not exported from headers */
    119 static int xmlXPathInitialized = 0;
    120 
    121 /**
    122  * xmlXPathInit:
    123  *
    124  * Initialize the XPath environment
    125  */
    126 void
    127 xmlXPathInit(void) {
    128     if (xmlXPathInitialized) return;
    129 
    130     xmlXPathPINF = trio_pinf();
    131     xmlXPathNINF = trio_ninf();
    132     xmlXPathNAN = trio_nan();
    133     xmlXPathNZERO = trio_nzero();
    134 
    135     xmlXPathInitialized = 1;
    136 }
    137 
    138 /**
    139  * xmlXPathIsNaN:
    140  * @val:  a double value
    141  *
    142  * Provides a portable isnan() function to detect whether a double
    143  * is a NotaNumber. Based on trio code
    144  * http://sourceforge.net/projects/ctrio/
    145  *
    146  * Returns 1 if the value is a NaN, 0 otherwise
    147  */
    148 int
    149 xmlXPathIsNaN(double val) {
    150     return(trio_isnan(val));
    151 }
    152 
    153 /**
    154  * xmlXPathIsInf:
    155  * @val:  a double value
    156  *
    157  * Provides a portable isinf() function to detect whether a double
    158  * is a +Infinite or -Infinite. Based on trio code
    159  * http://sourceforge.net/projects/ctrio/
    160  *
    161  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
    162  */
    163 int
    164 xmlXPathIsInf(double val) {
    165     return(trio_isinf(val));
    166 }
    167 
    168 #endif /* SCHEMAS or XPATH */
    169 #ifdef LIBXML_XPATH_ENABLED
    170 /**
    171  * xmlXPathGetSign:
    172  * @val:  a double value
    173  *
    174  * Provides a portable function to detect the sign of a double
    175  * Modified from trio code
    176  * http://sourceforge.net/projects/ctrio/
    177  *
    178  * Returns 1 if the value is Negative, 0 if positive
    179  */
    180 static int
    181 xmlXPathGetSign(double val) {
    182     return(trio_signbit(val));
    183 }
    184 
    185 
    186 /*
    187  * TODO: when compatibility allows remove all "fake node libxslt" strings
    188  *       the test should just be name[0] = ' '
    189  */
    190 #ifdef DEBUG_XPATH_EXPRESSION
    191 #define DEBUG_STEP
    192 #define DEBUG_EXPR
    193 #define DEBUG_EVAL_COUNTS
    194 #endif
    195 
    196 static xmlNs xmlXPathXMLNamespaceStruct = {
    197     NULL,
    198     XML_NAMESPACE_DECL,
    199     XML_XML_NAMESPACE,
    200     BAD_CAST "xml",
    201     NULL,
    202     NULL
    203 };
    204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    205 #ifndef LIBXML_THREAD_ENABLED
    206 /*
    207  * Optimizer is disabled only when threaded apps are detected while
    208  * the library ain't compiled for thread safety.
    209  */
    210 static int xmlXPathDisableOptimizer = 0;
    211 #endif
    212 
    213 /************************************************************************
    214  *									*
    215  *			Error handling routines				*
    216  *									*
    217  ************************************************************************/
    218 
    219 /**
    220  * XP_ERRORNULL:
    221  * @X:  the error code
    222  *
    223  * Macro to raise an XPath error and return NULL.
    224  */
    225 #define XP_ERRORNULL(X)							\
    226     { xmlXPathErr(ctxt, X); return(NULL); }
    227 
    228 /*
    229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    230  */
    231 static const char *xmlXPathErrorMessages[] = {
    232     "Ok\n",
    233     "Number encoding\n",
    234     "Unfinished literal\n",
    235     "Start of literal\n",
    236     "Expected $ for variable reference\n",
    237     "Undefined variable\n",
    238     "Invalid predicate\n",
    239     "Invalid expression\n",
    240     "Missing closing curly brace\n",
    241     "Unregistered function\n",
    242     "Invalid operand\n",
    243     "Invalid type\n",
    244     "Invalid number of arguments\n",
    245     "Invalid context size\n",
    246     "Invalid context position\n",
    247     "Memory allocation error\n",
    248     "Syntax error\n",
    249     "Resource error\n",
    250     "Sub resource error\n",
    251     "Undefined namespace prefix\n",
    252     "Encoding error\n",
    253     "Char out of XML range\n",
    254     "Invalid or incomplete context\n",
    255     "Stack usage errror\n",
    256     "?? Unknown error ??\n"	/* Must be last in the list! */
    257 };
    258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    259 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    260 /**
    261  * xmlXPathErrMemory:
    262  * @ctxt:  an XPath context
    263  * @extra:  extra informations
    264  *
    265  * Handle a redefinition of attribute error
    266  */
    267 static void
    268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    269 {
    270     if (ctxt != NULL) {
    271         if (extra) {
    272             xmlChar buf[200];
    273 
    274             xmlStrPrintf(buf, 200,
    275                          BAD_CAST "Memory allocation failed : %s\n",
    276                          extra);
    277             ctxt->lastError.message = (char *) xmlStrdup(buf);
    278         } else {
    279             ctxt->lastError.message = (char *)
    280 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    281         }
    282         ctxt->lastError.domain = XML_FROM_XPATH;
    283         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    284 	if (ctxt->error != NULL)
    285 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    286     } else {
    287         if (extra)
    288             __xmlRaiseError(NULL, NULL, NULL,
    289                             NULL, NULL, XML_FROM_XPATH,
    290                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    291                             extra, NULL, NULL, 0, 0,
    292                             "Memory allocation failed : %s\n", extra);
    293         else
    294             __xmlRaiseError(NULL, NULL, NULL,
    295                             NULL, NULL, XML_FROM_XPATH,
    296                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    297                             NULL, NULL, NULL, 0, 0,
    298                             "Memory allocation failed\n");
    299     }
    300 }
    301 
    302 /**
    303  * xmlXPathPErrMemory:
    304  * @ctxt:  an XPath parser context
    305  * @extra:  extra informations
    306  *
    307  * Handle a redefinition of attribute error
    308  */
    309 static void
    310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    311 {
    312     if (ctxt == NULL)
    313 	xmlXPathErrMemory(NULL, extra);
    314     else {
    315 	ctxt->error = XPATH_MEMORY_ERROR;
    316 	xmlXPathErrMemory(ctxt->context, extra);
    317     }
    318 }
    319 
    320 /**
    321  * xmlXPathErr:
    322  * @ctxt:  a XPath parser context
    323  * @error:  the error code
    324  *
    325  * Handle an XPath error
    326  */
    327 void
    328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    329 {
    330     if ((error < 0) || (error > MAXERRNO))
    331 	error = MAXERRNO;
    332     if (ctxt == NULL) {
    333 	__xmlRaiseError(NULL, NULL, NULL,
    334 			NULL, NULL, XML_FROM_XPATH,
    335 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    336 			XML_ERR_ERROR, NULL, 0,
    337 			NULL, NULL, NULL, 0, 0,
    338 			"%s", xmlXPathErrorMessages[error]);
    339 	return;
    340     }
    341     ctxt->error = error;
    342     if (ctxt->context == NULL) {
    343 	__xmlRaiseError(NULL, NULL, NULL,
    344 			NULL, NULL, XML_FROM_XPATH,
    345 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    346 			XML_ERR_ERROR, NULL, 0,
    347 			(const char *) ctxt->base, NULL, NULL,
    348 			ctxt->cur - ctxt->base, 0,
    349 			"%s", xmlXPathErrorMessages[error]);
    350 	return;
    351     }
    352 
    353     /* cleanup current last error */
    354     xmlResetError(&ctxt->context->lastError);
    355 
    356     ctxt->context->lastError.domain = XML_FROM_XPATH;
    357     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    358                            XPATH_EXPRESSION_OK;
    359     ctxt->context->lastError.level = XML_ERR_ERROR;
    360     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    361     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    362     ctxt->context->lastError.node = ctxt->context->debugNode;
    363     if (ctxt->context->error != NULL) {
    364 	ctxt->context->error(ctxt->context->userData,
    365 	                     &ctxt->context->lastError);
    366     } else {
    367 	__xmlRaiseError(NULL, NULL, NULL,
    368 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    369 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    370 			XML_ERR_ERROR, NULL, 0,
    371 			(const char *) ctxt->base, NULL, NULL,
    372 			ctxt->cur - ctxt->base, 0,
    373 			"%s", xmlXPathErrorMessages[error]);
    374     }
    375 
    376 }
    377 
    378 /**
    379  * xmlXPatherror:
    380  * @ctxt:  the XPath Parser context
    381  * @file:  the file name
    382  * @line:  the line number
    383  * @no:  the error number
    384  *
    385  * Formats an error message.
    386  */
    387 void
    388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    389               int line ATTRIBUTE_UNUSED, int no) {
    390     xmlXPathErr(ctxt, no);
    391 }
    392 
    393 /************************************************************************
    394  *									*
    395  *			Utilities					*
    396  *									*
    397  ************************************************************************/
    398 
    399 /**
    400  * xsltPointerList:
    401  *
    402  * Pointer-list for various purposes.
    403  */
    404 typedef struct _xmlPointerList xmlPointerList;
    405 typedef xmlPointerList *xmlPointerListPtr;
    406 struct _xmlPointerList {
    407     void **items;
    408     int number;
    409     int size;
    410 };
    411 /*
    412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    413 * and here, we should make the functions public.
    414 */
    415 static int
    416 xmlPointerListAddSize(xmlPointerListPtr list,
    417 		       void *item,
    418 		       int initialSize)
    419 {
    420     if (list->items == NULL) {
    421 	if (initialSize <= 0)
    422 	    initialSize = 1;
    423 	list->items = (void **) xmlMalloc(
    424 	    initialSize * sizeof(void *));
    425 	if (list->items == NULL) {
    426 	    xmlXPathErrMemory(NULL,
    427 		"xmlPointerListCreate: allocating item\n");
    428 	    return(-1);
    429 	}
    430 	list->number = 0;
    431 	list->size = initialSize;
    432     } else if (list->size <= list->number) {
    433 	list->size *= 2;
    434 	list->items = (void **) xmlRealloc(list->items,
    435 	    list->size * sizeof(void *));
    436 	if (list->items == NULL) {
    437 	    xmlXPathErrMemory(NULL,
    438 		"xmlPointerListCreate: re-allocating item\n");
    439 	    list->size = 0;
    440 	    return(-1);
    441 	}
    442     }
    443     list->items[list->number++] = item;
    444     return(0);
    445 }
    446 
    447 /**
    448  * xsltPointerListCreate:
    449  *
    450  * Creates an xsltPointerList structure.
    451  *
    452  * Returns a xsltPointerList structure or NULL in case of an error.
    453  */
    454 static xmlPointerListPtr
    455 xmlPointerListCreate(int initialSize)
    456 {
    457     xmlPointerListPtr ret;
    458 
    459     ret = xmlMalloc(sizeof(xmlPointerList));
    460     if (ret == NULL) {
    461 	xmlXPathErrMemory(NULL,
    462 	    "xmlPointerListCreate: allocating item\n");
    463 	return (NULL);
    464     }
    465     memset(ret, 0, sizeof(xmlPointerList));
    466     if (initialSize > 0) {
    467 	xmlPointerListAddSize(ret, NULL, initialSize);
    468 	ret->number = 0;
    469     }
    470     return (ret);
    471 }
    472 
    473 /**
    474  * xsltPointerListFree:
    475  *
    476  * Frees the xsltPointerList structure. This does not free
    477  * the content of the list.
    478  */
    479 static void
    480 xmlPointerListFree(xmlPointerListPtr list)
    481 {
    482     if (list == NULL)
    483 	return;
    484     if (list->items != NULL)
    485 	xmlFree(list->items);
    486     xmlFree(list);
    487 }
    488 
    489 /************************************************************************
    490  *									*
    491  *			Parser Types					*
    492  *									*
    493  ************************************************************************/
    494 
    495 /*
    496  * Types are private:
    497  */
    498 
    499 typedef enum {
    500     XPATH_OP_END=0,
    501     XPATH_OP_AND,
    502     XPATH_OP_OR,
    503     XPATH_OP_EQUAL,
    504     XPATH_OP_CMP,
    505     XPATH_OP_PLUS,
    506     XPATH_OP_MULT,
    507     XPATH_OP_UNION,
    508     XPATH_OP_ROOT,
    509     XPATH_OP_NODE,
    510     XPATH_OP_RESET, /* 10 */
    511     XPATH_OP_COLLECT,
    512     XPATH_OP_VALUE, /* 12 */
    513     XPATH_OP_VARIABLE,
    514     XPATH_OP_FUNCTION,
    515     XPATH_OP_ARG,
    516     XPATH_OP_PREDICATE,
    517     XPATH_OP_FILTER, /* 17 */
    518     XPATH_OP_SORT /* 18 */
    519 #ifdef LIBXML_XPTR_ENABLED
    520     ,XPATH_OP_RANGETO
    521 #endif
    522 } xmlXPathOp;
    523 
    524 typedef enum {
    525     AXIS_ANCESTOR = 1,
    526     AXIS_ANCESTOR_OR_SELF,
    527     AXIS_ATTRIBUTE,
    528     AXIS_CHILD,
    529     AXIS_DESCENDANT,
    530     AXIS_DESCENDANT_OR_SELF,
    531     AXIS_FOLLOWING,
    532     AXIS_FOLLOWING_SIBLING,
    533     AXIS_NAMESPACE,
    534     AXIS_PARENT,
    535     AXIS_PRECEDING,
    536     AXIS_PRECEDING_SIBLING,
    537     AXIS_SELF
    538 } xmlXPathAxisVal;
    539 
    540 typedef enum {
    541     NODE_TEST_NONE = 0,
    542     NODE_TEST_TYPE = 1,
    543     NODE_TEST_PI = 2,
    544     NODE_TEST_ALL = 3,
    545     NODE_TEST_NS = 4,
    546     NODE_TEST_NAME = 5
    547 } xmlXPathTestVal;
    548 
    549 typedef enum {
    550     NODE_TYPE_NODE = 0,
    551     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    552     NODE_TYPE_TEXT = XML_TEXT_NODE,
    553     NODE_TYPE_PI = XML_PI_NODE
    554 } xmlXPathTypeVal;
    555 
    556 #define XP_REWRITE_DOS_CHILD_ELEM 1
    557 
    558 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    559 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    560 struct _xmlXPathStepOp {
    561     xmlXPathOp op;		/* The identifier of the operation */
    562     int ch1;			/* First child */
    563     int ch2;			/* Second child */
    564     int value;
    565     int value2;
    566     int value3;
    567     void *value4;
    568     void *value5;
    569     void *cache;
    570     void *cacheURI;
    571     int rewriteType;
    572 };
    573 
    574 struct _xmlXPathCompExpr {
    575     int nbStep;			/* Number of steps in this expression */
    576     int maxStep;		/* Maximum number of steps allocated */
    577     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    578     int last;			/* index of last step in expression */
    579     xmlChar *expr;		/* the expression being computed */
    580     xmlDictPtr dict;		/* the dictionnary to use if any */
    581 #ifdef DEBUG_EVAL_COUNTS
    582     int nb;
    583     xmlChar *string;
    584 #endif
    585 #ifdef XPATH_STREAMING
    586     xmlPatternPtr stream;
    587 #endif
    588 };
    589 
    590 /************************************************************************
    591  *									*
    592  *			Forward declarations				*
    593  *									*
    594  ************************************************************************/
    595 static void
    596 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    597 static void
    598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    599 static int
    600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    601                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    602 static int
    603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    604 			    xmlXPathStepOpPtr op,
    605 			    int isPredicate);
    606 
    607 /************************************************************************
    608  *									*
    609  *			Parser Type functions				*
    610  *									*
    611  ************************************************************************/
    612 
    613 /**
    614  * xmlXPathNewCompExpr:
    615  *
    616  * Create a new Xpath component
    617  *
    618  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    619  */
    620 static xmlXPathCompExprPtr
    621 xmlXPathNewCompExpr(void) {
    622     xmlXPathCompExprPtr cur;
    623 
    624     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    625     if (cur == NULL) {
    626         xmlXPathErrMemory(NULL, "allocating component\n");
    627 	return(NULL);
    628     }
    629     memset(cur, 0, sizeof(xmlXPathCompExpr));
    630     cur->maxStep = 10;
    631     cur->nbStep = 0;
    632     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    633 	                                   sizeof(xmlXPathStepOp));
    634     if (cur->steps == NULL) {
    635         xmlXPathErrMemory(NULL, "allocating steps\n");
    636 	xmlFree(cur);
    637 	return(NULL);
    638     }
    639     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    640     cur->last = -1;
    641 #ifdef DEBUG_EVAL_COUNTS
    642     cur->nb = 0;
    643 #endif
    644     return(cur);
    645 }
    646 
    647 /**
    648  * xmlXPathFreeCompExpr:
    649  * @comp:  an XPATH comp
    650  *
    651  * Free up the memory allocated by @comp
    652  */
    653 void
    654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
    655 {
    656     xmlXPathStepOpPtr op;
    657     int i;
    658 
    659     if (comp == NULL)
    660         return;
    661     if (comp->dict == NULL) {
    662 	for (i = 0; i < comp->nbStep; i++) {
    663 	    op = &comp->steps[i];
    664 	    if (op->value4 != NULL) {
    665 		if (op->op == XPATH_OP_VALUE)
    666 		    xmlXPathFreeObject(op->value4);
    667 		else
    668 		    xmlFree(op->value4);
    669 	    }
    670 	    if (op->value5 != NULL)
    671 		xmlFree(op->value5);
    672 	}
    673     } else {
    674 	for (i = 0; i < comp->nbStep; i++) {
    675 	    op = &comp->steps[i];
    676 	    if (op->value4 != NULL) {
    677 		if (op->op == XPATH_OP_VALUE)
    678 		    xmlXPathFreeObject(op->value4);
    679 	    }
    680 	}
    681         xmlDictFree(comp->dict);
    682     }
    683     if (comp->steps != NULL) {
    684         xmlFree(comp->steps);
    685     }
    686 #ifdef DEBUG_EVAL_COUNTS
    687     if (comp->string != NULL) {
    688         xmlFree(comp->string);
    689     }
    690 #endif
    691 #ifdef XPATH_STREAMING
    692     if (comp->stream != NULL) {
    693         xmlFreePatternList(comp->stream);
    694     }
    695 #endif
    696     if (comp->expr != NULL) {
    697         xmlFree(comp->expr);
    698     }
    699 
    700     xmlFree(comp);
    701 }
    702 
    703 /**
    704  * xmlXPathCompExprAdd:
    705  * @comp:  the compiled expression
    706  * @ch1: first child index
    707  * @ch2: second child index
    708  * @op:  an op
    709  * @value:  the first int value
    710  * @value2:  the second int value
    711  * @value3:  the third int value
    712  * @value4:  the first string value
    713  * @value5:  the second string value
    714  *
    715  * Add a step to an XPath Compiled Expression
    716  *
    717  * Returns -1 in case of failure, the index otherwise
    718  */
    719 static int
    720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
    721    xmlXPathOp op, int value,
    722    int value2, int value3, void *value4, void *value5) {
    723     if (comp->nbStep >= comp->maxStep) {
    724 	xmlXPathStepOp *real;
    725 
    726 	comp->maxStep *= 2;
    727 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
    728 		                      comp->maxStep * sizeof(xmlXPathStepOp));
    729 	if (real == NULL) {
    730 	    comp->maxStep /= 2;
    731 	    xmlXPathErrMemory(NULL, "adding step\n");
    732 	    return(-1);
    733 	}
    734 	comp->steps = real;
    735     }
    736     comp->last = comp->nbStep;
    737     comp->steps[comp->nbStep].rewriteType = 0;
    738     comp->steps[comp->nbStep].ch1 = ch1;
    739     comp->steps[comp->nbStep].ch2 = ch2;
    740     comp->steps[comp->nbStep].op = op;
    741     comp->steps[comp->nbStep].value = value;
    742     comp->steps[comp->nbStep].value2 = value2;
    743     comp->steps[comp->nbStep].value3 = value3;
    744     if ((comp->dict != NULL) &&
    745         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
    746 	 (op == XPATH_OP_COLLECT))) {
    747         if (value4 != NULL) {
    748 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
    749 	        (void *)xmlDictLookup(comp->dict, value4, -1);
    750 	    xmlFree(value4);
    751 	} else
    752 	    comp->steps[comp->nbStep].value4 = NULL;
    753         if (value5 != NULL) {
    754 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
    755 	        (void *)xmlDictLookup(comp->dict, value5, -1);
    756 	    xmlFree(value5);
    757 	} else
    758 	    comp->steps[comp->nbStep].value5 = NULL;
    759     } else {
    760 	comp->steps[comp->nbStep].value4 = value4;
    761 	comp->steps[comp->nbStep].value5 = value5;
    762     }
    763     comp->steps[comp->nbStep].cache = NULL;
    764     return(comp->nbStep++);
    765 }
    766 
    767 /**
    768  * xmlXPathCompSwap:
    769  * @comp:  the compiled expression
    770  * @op: operation index
    771  *
    772  * Swaps 2 operations in the compiled expression
    773  */
    774 static void
    775 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
    776     int tmp;
    777 
    778 #ifndef LIBXML_THREAD_ENABLED
    779     /*
    780      * Since this manipulates possibly shared variables, this is
    781      * disabled if one detects that the library is used in a multithreaded
    782      * application
    783      */
    784     if (xmlXPathDisableOptimizer)
    785 	return;
    786 #endif
    787 
    788     tmp = op->ch1;
    789     op->ch1 = op->ch2;
    790     op->ch2 = tmp;
    791 }
    792 
    793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
    794     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
    795 	                (op), (val), (val2), (val3), (val4), (val5))
    796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
    797     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
    798 	                (op), (val), (val2), (val3), (val4), (val5))
    799 
    800 #define PUSH_LEAVE_EXPR(op, val, val2)					\
    801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
    802 
    803 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
    804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
    805 
    806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
    807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
    808 			(val), (val2), 0 ,NULL ,NULL)
    809 
    810 /************************************************************************
    811  *									*
    812  *		XPath object cache structures				*
    813  *									*
    814  ************************************************************************/
    815 
    816 /* #define XP_DEFAULT_CACHE_ON */
    817 
    818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
    819 
    820 typedef struct _xmlXPathContextCache xmlXPathContextCache;
    821 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
    822 struct _xmlXPathContextCache {
    823     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
    824     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
    825     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
    826     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
    827     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
    828     int maxNodeset;
    829     int maxString;
    830     int maxBoolean;
    831     int maxNumber;
    832     int maxMisc;
    833 #ifdef XP_DEBUG_OBJ_USAGE
    834     int dbgCachedAll;
    835     int dbgCachedNodeset;
    836     int dbgCachedString;
    837     int dbgCachedBool;
    838     int dbgCachedNumber;
    839     int dbgCachedPoint;
    840     int dbgCachedRange;
    841     int dbgCachedLocset;
    842     int dbgCachedUsers;
    843     int dbgCachedXSLTTree;
    844     int dbgCachedUndefined;
    845 
    846 
    847     int dbgReusedAll;
    848     int dbgReusedNodeset;
    849     int dbgReusedString;
    850     int dbgReusedBool;
    851     int dbgReusedNumber;
    852     int dbgReusedPoint;
    853     int dbgReusedRange;
    854     int dbgReusedLocset;
    855     int dbgReusedUsers;
    856     int dbgReusedXSLTTree;
    857     int dbgReusedUndefined;
    858 
    859 #endif
    860 };
    861 
    862 /************************************************************************
    863  *									*
    864  *		Debugging related functions				*
    865  *									*
    866  ************************************************************************/
    867 
    868 #define STRANGE							\
    869     xmlGenericError(xmlGenericErrorContext,				\
    870 	    "Internal error at %s:%d\n",				\
    871             __FILE__, __LINE__);
    872 
    873 #ifdef LIBXML_DEBUG_ENABLED
    874 static void
    875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
    876     int i;
    877     char shift[100];
    878 
    879     for (i = 0;((i < depth) && (i < 25));i++)
    880         shift[2 * i] = shift[2 * i + 1] = ' ';
    881     shift[2 * i] = shift[2 * i + 1] = 0;
    882     if (cur == NULL) {
    883 	fprintf(output, "%s", shift);
    884 	fprintf(output, "Node is NULL !\n");
    885 	return;
    886 
    887     }
    888 
    889     if ((cur->type == XML_DOCUMENT_NODE) ||
    890 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
    891 	fprintf(output, "%s", shift);
    892 	fprintf(output, " /\n");
    893     } else if (cur->type == XML_ATTRIBUTE_NODE)
    894 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
    895     else
    896 	xmlDebugDumpOneNode(output, cur, depth);
    897 }
    898 static void
    899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
    900     xmlNodePtr tmp;
    901     int i;
    902     char shift[100];
    903 
    904     for (i = 0;((i < depth) && (i < 25));i++)
    905         shift[2 * i] = shift[2 * i + 1] = ' ';
    906     shift[2 * i] = shift[2 * i + 1] = 0;
    907     if (cur == NULL) {
    908 	fprintf(output, "%s", shift);
    909 	fprintf(output, "Node is NULL !\n");
    910 	return;
    911 
    912     }
    913 
    914     while (cur != NULL) {
    915 	tmp = cur;
    916 	cur = cur->next;
    917 	xmlDebugDumpOneNode(output, tmp, depth);
    918     }
    919 }
    920 
    921 static void
    922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
    923     int i;
    924     char shift[100];
    925 
    926     for (i = 0;((i < depth) && (i < 25));i++)
    927         shift[2 * i] = shift[2 * i + 1] = ' ';
    928     shift[2 * i] = shift[2 * i + 1] = 0;
    929 
    930     if (cur == NULL) {
    931 	fprintf(output, "%s", shift);
    932 	fprintf(output, "NodeSet is NULL !\n");
    933 	return;
    934 
    935     }
    936 
    937     if (cur != NULL) {
    938 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
    939 	for (i = 0;i < cur->nodeNr;i++) {
    940 	    fprintf(output, "%s", shift);
    941 	    fprintf(output, "%d", i + 1);
    942 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
    943 	}
    944     }
    945 }
    946 
    947 static void
    948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
    949     int i;
    950     char shift[100];
    951 
    952     for (i = 0;((i < depth) && (i < 25));i++)
    953         shift[2 * i] = shift[2 * i + 1] = ' ';
    954     shift[2 * i] = shift[2 * i + 1] = 0;
    955 
    956     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
    957 	fprintf(output, "%s", shift);
    958 	fprintf(output, "Value Tree is NULL !\n");
    959 	return;
    960 
    961     }
    962 
    963     fprintf(output, "%s", shift);
    964     fprintf(output, "%d", i + 1);
    965     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
    966 }
    967 #if defined(LIBXML_XPTR_ENABLED)
    968 static void
    969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
    970     int i;
    971     char shift[100];
    972 
    973     for (i = 0;((i < depth) && (i < 25));i++)
    974         shift[2 * i] = shift[2 * i + 1] = ' ';
    975     shift[2 * i] = shift[2 * i + 1] = 0;
    976 
    977     if (cur == NULL) {
    978 	fprintf(output, "%s", shift);
    979 	fprintf(output, "LocationSet is NULL !\n");
    980 	return;
    981 
    982     }
    983 
    984     for (i = 0;i < cur->locNr;i++) {
    985 	fprintf(output, "%s", shift);
    986         fprintf(output, "%d : ", i + 1);
    987 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
    988     }
    989 }
    990 #endif /* LIBXML_XPTR_ENABLED */
    991 
    992 /**
    993  * xmlXPathDebugDumpObject:
    994  * @output:  the FILE * to dump the output
    995  * @cur:  the object to inspect
    996  * @depth:  indentation level
    997  *
    998  * Dump the content of the object for debugging purposes
    999  */
   1000 void
   1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1002     int i;
   1003     char shift[100];
   1004 
   1005     if (output == NULL) return;
   1006 
   1007     for (i = 0;((i < depth) && (i < 25));i++)
   1008         shift[2 * i] = shift[2 * i + 1] = ' ';
   1009     shift[2 * i] = shift[2 * i + 1] = 0;
   1010 
   1011 
   1012     fprintf(output, "%s", shift);
   1013 
   1014     if (cur == NULL) {
   1015         fprintf(output, "Object is empty (NULL)\n");
   1016 	return;
   1017     }
   1018     switch(cur->type) {
   1019         case XPATH_UNDEFINED:
   1020 	    fprintf(output, "Object is uninitialized\n");
   1021 	    break;
   1022         case XPATH_NODESET:
   1023 	    fprintf(output, "Object is a Node Set :\n");
   1024 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1025 	    break;
   1026 	case XPATH_XSLT_TREE:
   1027 	    fprintf(output, "Object is an XSLT value tree :\n");
   1028 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1029 	    break;
   1030         case XPATH_BOOLEAN:
   1031 	    fprintf(output, "Object is a Boolean : ");
   1032 	    if (cur->boolval) fprintf(output, "true\n");
   1033 	    else fprintf(output, "false\n");
   1034 	    break;
   1035         case XPATH_NUMBER:
   1036 	    switch (xmlXPathIsInf(cur->floatval)) {
   1037 	    case 1:
   1038 		fprintf(output, "Object is a number : Infinity\n");
   1039 		break;
   1040 	    case -1:
   1041 		fprintf(output, "Object is a number : -Infinity\n");
   1042 		break;
   1043 	    default:
   1044 		if (xmlXPathIsNaN(cur->floatval)) {
   1045 		    fprintf(output, "Object is a number : NaN\n");
   1046 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1047 		    fprintf(output, "Object is a number : 0\n");
   1048 		} else {
   1049 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1050 		}
   1051 	    }
   1052 	    break;
   1053         case XPATH_STRING:
   1054 	    fprintf(output, "Object is a string : ");
   1055 	    xmlDebugDumpString(output, cur->stringval);
   1056 	    fprintf(output, "\n");
   1057 	    break;
   1058 	case XPATH_POINT:
   1059 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1060 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1061 	    fprintf(output, "\n");
   1062 	    break;
   1063 	case XPATH_RANGE:
   1064 	    if ((cur->user2 == NULL) ||
   1065 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1066 		fprintf(output, "Object is a collapsed range :\n");
   1067 		fprintf(output, "%s", shift);
   1068 		if (cur->index >= 0)
   1069 		    fprintf(output, "index %d in ", cur->index);
   1070 		fprintf(output, "node\n");
   1071 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1072 			              depth + 1);
   1073 	    } else  {
   1074 		fprintf(output, "Object is a range :\n");
   1075 		fprintf(output, "%s", shift);
   1076 		fprintf(output, "From ");
   1077 		if (cur->index >= 0)
   1078 		    fprintf(output, "index %d in ", cur->index);
   1079 		fprintf(output, "node\n");
   1080 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1081 			              depth + 1);
   1082 		fprintf(output, "%s", shift);
   1083 		fprintf(output, "To ");
   1084 		if (cur->index2 >= 0)
   1085 		    fprintf(output, "index %d in ", cur->index2);
   1086 		fprintf(output, "node\n");
   1087 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1088 			              depth + 1);
   1089 		fprintf(output, "\n");
   1090 	    }
   1091 	    break;
   1092 	case XPATH_LOCATIONSET:
   1093 #if defined(LIBXML_XPTR_ENABLED)
   1094 	    fprintf(output, "Object is a Location Set:\n");
   1095 	    xmlXPathDebugDumpLocationSet(output,
   1096 		    (xmlLocationSetPtr) cur->user, depth);
   1097 #endif
   1098 	    break;
   1099 	case XPATH_USERS:
   1100 	    fprintf(output, "Object is user defined\n");
   1101 	    break;
   1102     }
   1103 }
   1104 
   1105 static void
   1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1107 	                     xmlXPathStepOpPtr op, int depth) {
   1108     int i;
   1109     char shift[100];
   1110 
   1111     for (i = 0;((i < depth) && (i < 25));i++)
   1112         shift[2 * i] = shift[2 * i + 1] = ' ';
   1113     shift[2 * i] = shift[2 * i + 1] = 0;
   1114 
   1115     fprintf(output, "%s", shift);
   1116     if (op == NULL) {
   1117 	fprintf(output, "Step is NULL\n");
   1118 	return;
   1119     }
   1120     switch (op->op) {
   1121         case XPATH_OP_END:
   1122 	    fprintf(output, "END"); break;
   1123         case XPATH_OP_AND:
   1124 	    fprintf(output, "AND"); break;
   1125         case XPATH_OP_OR:
   1126 	    fprintf(output, "OR"); break;
   1127         case XPATH_OP_EQUAL:
   1128 	     if (op->value)
   1129 		 fprintf(output, "EQUAL =");
   1130 	     else
   1131 		 fprintf(output, "EQUAL !=");
   1132 	     break;
   1133         case XPATH_OP_CMP:
   1134 	     if (op->value)
   1135 		 fprintf(output, "CMP <");
   1136 	     else
   1137 		 fprintf(output, "CMP >");
   1138 	     if (!op->value2)
   1139 		 fprintf(output, "=");
   1140 	     break;
   1141         case XPATH_OP_PLUS:
   1142 	     if (op->value == 0)
   1143 		 fprintf(output, "PLUS -");
   1144 	     else if (op->value == 1)
   1145 		 fprintf(output, "PLUS +");
   1146 	     else if (op->value == 2)
   1147 		 fprintf(output, "PLUS unary -");
   1148 	     else if (op->value == 3)
   1149 		 fprintf(output, "PLUS unary - -");
   1150 	     break;
   1151         case XPATH_OP_MULT:
   1152 	     if (op->value == 0)
   1153 		 fprintf(output, "MULT *");
   1154 	     else if (op->value == 1)
   1155 		 fprintf(output, "MULT div");
   1156 	     else
   1157 		 fprintf(output, "MULT mod");
   1158 	     break;
   1159         case XPATH_OP_UNION:
   1160 	     fprintf(output, "UNION"); break;
   1161         case XPATH_OP_ROOT:
   1162 	     fprintf(output, "ROOT"); break;
   1163         case XPATH_OP_NODE:
   1164 	     fprintf(output, "NODE"); break;
   1165         case XPATH_OP_RESET:
   1166 	     fprintf(output, "RESET"); break;
   1167         case XPATH_OP_SORT:
   1168 	     fprintf(output, "SORT"); break;
   1169         case XPATH_OP_COLLECT: {
   1170 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1171 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1172 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1173 	    const xmlChar *prefix = op->value4;
   1174 	    const xmlChar *name = op->value5;
   1175 
   1176 	    fprintf(output, "COLLECT ");
   1177 	    switch (axis) {
   1178 		case AXIS_ANCESTOR:
   1179 		    fprintf(output, " 'ancestors' "); break;
   1180 		case AXIS_ANCESTOR_OR_SELF:
   1181 		    fprintf(output, " 'ancestors-or-self' "); break;
   1182 		case AXIS_ATTRIBUTE:
   1183 		    fprintf(output, " 'attributes' "); break;
   1184 		case AXIS_CHILD:
   1185 		    fprintf(output, " 'child' "); break;
   1186 		case AXIS_DESCENDANT:
   1187 		    fprintf(output, " 'descendant' "); break;
   1188 		case AXIS_DESCENDANT_OR_SELF:
   1189 		    fprintf(output, " 'descendant-or-self' "); break;
   1190 		case AXIS_FOLLOWING:
   1191 		    fprintf(output, " 'following' "); break;
   1192 		case AXIS_FOLLOWING_SIBLING:
   1193 		    fprintf(output, " 'following-siblings' "); break;
   1194 		case AXIS_NAMESPACE:
   1195 		    fprintf(output, " 'namespace' "); break;
   1196 		case AXIS_PARENT:
   1197 		    fprintf(output, " 'parent' "); break;
   1198 		case AXIS_PRECEDING:
   1199 		    fprintf(output, " 'preceding' "); break;
   1200 		case AXIS_PRECEDING_SIBLING:
   1201 		    fprintf(output, " 'preceding-sibling' "); break;
   1202 		case AXIS_SELF:
   1203 		    fprintf(output, " 'self' "); break;
   1204 	    }
   1205 	    switch (test) {
   1206                 case NODE_TEST_NONE:
   1207 		    fprintf(output, "'none' "); break;
   1208                 case NODE_TEST_TYPE:
   1209 		    fprintf(output, "'type' "); break;
   1210                 case NODE_TEST_PI:
   1211 		    fprintf(output, "'PI' "); break;
   1212                 case NODE_TEST_ALL:
   1213 		    fprintf(output, "'all' "); break;
   1214                 case NODE_TEST_NS:
   1215 		    fprintf(output, "'namespace' "); break;
   1216                 case NODE_TEST_NAME:
   1217 		    fprintf(output, "'name' "); break;
   1218 	    }
   1219 	    switch (type) {
   1220                 case NODE_TYPE_NODE:
   1221 		    fprintf(output, "'node' "); break;
   1222                 case NODE_TYPE_COMMENT:
   1223 		    fprintf(output, "'comment' "); break;
   1224                 case NODE_TYPE_TEXT:
   1225 		    fprintf(output, "'text' "); break;
   1226                 case NODE_TYPE_PI:
   1227 		    fprintf(output, "'PI' "); break;
   1228 	    }
   1229 	    if (prefix != NULL)
   1230 		fprintf(output, "%s:", prefix);
   1231 	    if (name != NULL)
   1232 		fprintf(output, "%s", (const char *) name);
   1233 	    break;
   1234 
   1235         }
   1236 	case XPATH_OP_VALUE: {
   1237 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1238 
   1239 	    fprintf(output, "ELEM ");
   1240 	    xmlXPathDebugDumpObject(output, object, 0);
   1241 	    goto finish;
   1242 	}
   1243 	case XPATH_OP_VARIABLE: {
   1244 	    const xmlChar *prefix = op->value5;
   1245 	    const xmlChar *name = op->value4;
   1246 
   1247 	    if (prefix != NULL)
   1248 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1249 	    else
   1250 		fprintf(output, "VARIABLE %s", name);
   1251 	    break;
   1252 	}
   1253 	case XPATH_OP_FUNCTION: {
   1254 	    int nbargs = op->value;
   1255 	    const xmlChar *prefix = op->value5;
   1256 	    const xmlChar *name = op->value4;
   1257 
   1258 	    if (prefix != NULL)
   1259 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1260 			prefix, name, nbargs);
   1261 	    else
   1262 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1263 	    break;
   1264 	}
   1265         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1266         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1267         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1268 #ifdef LIBXML_XPTR_ENABLED
   1269         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1270 #endif
   1271 	default:
   1272         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1273     }
   1274     fprintf(output, "\n");
   1275 finish:
   1276     if (op->ch1 >= 0)
   1277 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1278     if (op->ch2 >= 0)
   1279 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1280 }
   1281 
   1282 /**
   1283  * xmlXPathDebugDumpCompExpr:
   1284  * @output:  the FILE * for the output
   1285  * @comp:  the precompiled XPath expression
   1286  * @depth:  the indentation level.
   1287  *
   1288  * Dumps the tree of the compiled XPath expression.
   1289  */
   1290 void
   1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1292 	                  int depth) {
   1293     int i;
   1294     char shift[100];
   1295 
   1296     if ((output == NULL) || (comp == NULL)) return;
   1297 
   1298     for (i = 0;((i < depth) && (i < 25));i++)
   1299         shift[2 * i] = shift[2 * i + 1] = ' ';
   1300     shift[2 * i] = shift[2 * i + 1] = 0;
   1301 
   1302     fprintf(output, "%s", shift);
   1303 
   1304     fprintf(output, "Compiled Expression : %d elements\n",
   1305 	    comp->nbStep);
   1306     i = comp->last;
   1307     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1308 }
   1309 
   1310 #ifdef XP_DEBUG_OBJ_USAGE
   1311 
   1312 /*
   1313 * XPath object usage related debugging variables.
   1314 */
   1315 static int xmlXPathDebugObjCounterUndefined = 0;
   1316 static int xmlXPathDebugObjCounterNodeset = 0;
   1317 static int xmlXPathDebugObjCounterBool = 0;
   1318 static int xmlXPathDebugObjCounterNumber = 0;
   1319 static int xmlXPathDebugObjCounterString = 0;
   1320 static int xmlXPathDebugObjCounterPoint = 0;
   1321 static int xmlXPathDebugObjCounterRange = 0;
   1322 static int xmlXPathDebugObjCounterLocset = 0;
   1323 static int xmlXPathDebugObjCounterUsers = 0;
   1324 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1325 static int xmlXPathDebugObjCounterAll = 0;
   1326 
   1327 static int xmlXPathDebugObjTotalUndefined = 0;
   1328 static int xmlXPathDebugObjTotalNodeset = 0;
   1329 static int xmlXPathDebugObjTotalBool = 0;
   1330 static int xmlXPathDebugObjTotalNumber = 0;
   1331 static int xmlXPathDebugObjTotalString = 0;
   1332 static int xmlXPathDebugObjTotalPoint = 0;
   1333 static int xmlXPathDebugObjTotalRange = 0;
   1334 static int xmlXPathDebugObjTotalLocset = 0;
   1335 static int xmlXPathDebugObjTotalUsers = 0;
   1336 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1337 static int xmlXPathDebugObjTotalAll = 0;
   1338 
   1339 static int xmlXPathDebugObjMaxUndefined = 0;
   1340 static int xmlXPathDebugObjMaxNodeset = 0;
   1341 static int xmlXPathDebugObjMaxBool = 0;
   1342 static int xmlXPathDebugObjMaxNumber = 0;
   1343 static int xmlXPathDebugObjMaxString = 0;
   1344 static int xmlXPathDebugObjMaxPoint = 0;
   1345 static int xmlXPathDebugObjMaxRange = 0;
   1346 static int xmlXPathDebugObjMaxLocset = 0;
   1347 static int xmlXPathDebugObjMaxUsers = 0;
   1348 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1349 static int xmlXPathDebugObjMaxAll = 0;
   1350 
   1351 /* REVISIT TODO: Make this static when committing */
   1352 static void
   1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1354 {
   1355     if (ctxt != NULL) {
   1356 	if (ctxt->cache != NULL) {
   1357 	    xmlXPathContextCachePtr cache =
   1358 		(xmlXPathContextCachePtr) ctxt->cache;
   1359 
   1360 	    cache->dbgCachedAll = 0;
   1361 	    cache->dbgCachedNodeset = 0;
   1362 	    cache->dbgCachedString = 0;
   1363 	    cache->dbgCachedBool = 0;
   1364 	    cache->dbgCachedNumber = 0;
   1365 	    cache->dbgCachedPoint = 0;
   1366 	    cache->dbgCachedRange = 0;
   1367 	    cache->dbgCachedLocset = 0;
   1368 	    cache->dbgCachedUsers = 0;
   1369 	    cache->dbgCachedXSLTTree = 0;
   1370 	    cache->dbgCachedUndefined = 0;
   1371 
   1372 	    cache->dbgReusedAll = 0;
   1373 	    cache->dbgReusedNodeset = 0;
   1374 	    cache->dbgReusedString = 0;
   1375 	    cache->dbgReusedBool = 0;
   1376 	    cache->dbgReusedNumber = 0;
   1377 	    cache->dbgReusedPoint = 0;
   1378 	    cache->dbgReusedRange = 0;
   1379 	    cache->dbgReusedLocset = 0;
   1380 	    cache->dbgReusedUsers = 0;
   1381 	    cache->dbgReusedXSLTTree = 0;
   1382 	    cache->dbgReusedUndefined = 0;
   1383 	}
   1384     }
   1385 
   1386     xmlXPathDebugObjCounterUndefined = 0;
   1387     xmlXPathDebugObjCounterNodeset = 0;
   1388     xmlXPathDebugObjCounterBool = 0;
   1389     xmlXPathDebugObjCounterNumber = 0;
   1390     xmlXPathDebugObjCounterString = 0;
   1391     xmlXPathDebugObjCounterPoint = 0;
   1392     xmlXPathDebugObjCounterRange = 0;
   1393     xmlXPathDebugObjCounterLocset = 0;
   1394     xmlXPathDebugObjCounterUsers = 0;
   1395     xmlXPathDebugObjCounterXSLTTree = 0;
   1396     xmlXPathDebugObjCounterAll = 0;
   1397 
   1398     xmlXPathDebugObjTotalUndefined = 0;
   1399     xmlXPathDebugObjTotalNodeset = 0;
   1400     xmlXPathDebugObjTotalBool = 0;
   1401     xmlXPathDebugObjTotalNumber = 0;
   1402     xmlXPathDebugObjTotalString = 0;
   1403     xmlXPathDebugObjTotalPoint = 0;
   1404     xmlXPathDebugObjTotalRange = 0;
   1405     xmlXPathDebugObjTotalLocset = 0;
   1406     xmlXPathDebugObjTotalUsers = 0;
   1407     xmlXPathDebugObjTotalXSLTTree = 0;
   1408     xmlXPathDebugObjTotalAll = 0;
   1409 
   1410     xmlXPathDebugObjMaxUndefined = 0;
   1411     xmlXPathDebugObjMaxNodeset = 0;
   1412     xmlXPathDebugObjMaxBool = 0;
   1413     xmlXPathDebugObjMaxNumber = 0;
   1414     xmlXPathDebugObjMaxString = 0;
   1415     xmlXPathDebugObjMaxPoint = 0;
   1416     xmlXPathDebugObjMaxRange = 0;
   1417     xmlXPathDebugObjMaxLocset = 0;
   1418     xmlXPathDebugObjMaxUsers = 0;
   1419     xmlXPathDebugObjMaxXSLTTree = 0;
   1420     xmlXPathDebugObjMaxAll = 0;
   1421 
   1422 }
   1423 
   1424 static void
   1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1426 			      xmlXPathObjectType objType)
   1427 {
   1428     int isCached = 0;
   1429 
   1430     if (ctxt != NULL) {
   1431 	if (ctxt->cache != NULL) {
   1432 	    xmlXPathContextCachePtr cache =
   1433 		(xmlXPathContextCachePtr) ctxt->cache;
   1434 
   1435 	    isCached = 1;
   1436 
   1437 	    cache->dbgReusedAll++;
   1438 	    switch (objType) {
   1439 		case XPATH_UNDEFINED:
   1440 		    cache->dbgReusedUndefined++;
   1441 		    break;
   1442 		case XPATH_NODESET:
   1443 		    cache->dbgReusedNodeset++;
   1444 		    break;
   1445 		case XPATH_BOOLEAN:
   1446 		    cache->dbgReusedBool++;
   1447 		    break;
   1448 		case XPATH_NUMBER:
   1449 		    cache->dbgReusedNumber++;
   1450 		    break;
   1451 		case XPATH_STRING:
   1452 		    cache->dbgReusedString++;
   1453 		    break;
   1454 		case XPATH_POINT:
   1455 		    cache->dbgReusedPoint++;
   1456 		    break;
   1457 		case XPATH_RANGE:
   1458 		    cache->dbgReusedRange++;
   1459 		    break;
   1460 		case XPATH_LOCATIONSET:
   1461 		    cache->dbgReusedLocset++;
   1462 		    break;
   1463 		case XPATH_USERS:
   1464 		    cache->dbgReusedUsers++;
   1465 		    break;
   1466 		case XPATH_XSLT_TREE:
   1467 		    cache->dbgReusedXSLTTree++;
   1468 		    break;
   1469 		default:
   1470 		    break;
   1471 	    }
   1472 	}
   1473     }
   1474 
   1475     switch (objType) {
   1476 	case XPATH_UNDEFINED:
   1477 	    if (! isCached)
   1478 		xmlXPathDebugObjTotalUndefined++;
   1479 	    xmlXPathDebugObjCounterUndefined++;
   1480 	    if (xmlXPathDebugObjCounterUndefined >
   1481 		xmlXPathDebugObjMaxUndefined)
   1482 		xmlXPathDebugObjMaxUndefined =
   1483 		    xmlXPathDebugObjCounterUndefined;
   1484 	    break;
   1485 	case XPATH_NODESET:
   1486 	    if (! isCached)
   1487 		xmlXPathDebugObjTotalNodeset++;
   1488 	    xmlXPathDebugObjCounterNodeset++;
   1489 	    if (xmlXPathDebugObjCounterNodeset >
   1490 		xmlXPathDebugObjMaxNodeset)
   1491 		xmlXPathDebugObjMaxNodeset =
   1492 		    xmlXPathDebugObjCounterNodeset;
   1493 	    break;
   1494 	case XPATH_BOOLEAN:
   1495 	    if (! isCached)
   1496 		xmlXPathDebugObjTotalBool++;
   1497 	    xmlXPathDebugObjCounterBool++;
   1498 	    if (xmlXPathDebugObjCounterBool >
   1499 		xmlXPathDebugObjMaxBool)
   1500 		xmlXPathDebugObjMaxBool =
   1501 		    xmlXPathDebugObjCounterBool;
   1502 	    break;
   1503 	case XPATH_NUMBER:
   1504 	    if (! isCached)
   1505 		xmlXPathDebugObjTotalNumber++;
   1506 	    xmlXPathDebugObjCounterNumber++;
   1507 	    if (xmlXPathDebugObjCounterNumber >
   1508 		xmlXPathDebugObjMaxNumber)
   1509 		xmlXPathDebugObjMaxNumber =
   1510 		    xmlXPathDebugObjCounterNumber;
   1511 	    break;
   1512 	case XPATH_STRING:
   1513 	    if (! isCached)
   1514 		xmlXPathDebugObjTotalString++;
   1515 	    xmlXPathDebugObjCounterString++;
   1516 	    if (xmlXPathDebugObjCounterString >
   1517 		xmlXPathDebugObjMaxString)
   1518 		xmlXPathDebugObjMaxString =
   1519 		    xmlXPathDebugObjCounterString;
   1520 	    break;
   1521 	case XPATH_POINT:
   1522 	    if (! isCached)
   1523 		xmlXPathDebugObjTotalPoint++;
   1524 	    xmlXPathDebugObjCounterPoint++;
   1525 	    if (xmlXPathDebugObjCounterPoint >
   1526 		xmlXPathDebugObjMaxPoint)
   1527 		xmlXPathDebugObjMaxPoint =
   1528 		    xmlXPathDebugObjCounterPoint;
   1529 	    break;
   1530 	case XPATH_RANGE:
   1531 	    if (! isCached)
   1532 		xmlXPathDebugObjTotalRange++;
   1533 	    xmlXPathDebugObjCounterRange++;
   1534 	    if (xmlXPathDebugObjCounterRange >
   1535 		xmlXPathDebugObjMaxRange)
   1536 		xmlXPathDebugObjMaxRange =
   1537 		    xmlXPathDebugObjCounterRange;
   1538 	    break;
   1539 	case XPATH_LOCATIONSET:
   1540 	    if (! isCached)
   1541 		xmlXPathDebugObjTotalLocset++;
   1542 	    xmlXPathDebugObjCounterLocset++;
   1543 	    if (xmlXPathDebugObjCounterLocset >
   1544 		xmlXPathDebugObjMaxLocset)
   1545 		xmlXPathDebugObjMaxLocset =
   1546 		    xmlXPathDebugObjCounterLocset;
   1547 	    break;
   1548 	case XPATH_USERS:
   1549 	    if (! isCached)
   1550 		xmlXPathDebugObjTotalUsers++;
   1551 	    xmlXPathDebugObjCounterUsers++;
   1552 	    if (xmlXPathDebugObjCounterUsers >
   1553 		xmlXPathDebugObjMaxUsers)
   1554 		xmlXPathDebugObjMaxUsers =
   1555 		    xmlXPathDebugObjCounterUsers;
   1556 	    break;
   1557 	case XPATH_XSLT_TREE:
   1558 	    if (! isCached)
   1559 		xmlXPathDebugObjTotalXSLTTree++;
   1560 	    xmlXPathDebugObjCounterXSLTTree++;
   1561 	    if (xmlXPathDebugObjCounterXSLTTree >
   1562 		xmlXPathDebugObjMaxXSLTTree)
   1563 		xmlXPathDebugObjMaxXSLTTree =
   1564 		    xmlXPathDebugObjCounterXSLTTree;
   1565 	    break;
   1566 	default:
   1567 	    break;
   1568     }
   1569     if (! isCached)
   1570 	xmlXPathDebugObjTotalAll++;
   1571     xmlXPathDebugObjCounterAll++;
   1572     if (xmlXPathDebugObjCounterAll >
   1573 	xmlXPathDebugObjMaxAll)
   1574 	xmlXPathDebugObjMaxAll =
   1575 	    xmlXPathDebugObjCounterAll;
   1576 }
   1577 
   1578 static void
   1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1580 			      xmlXPathObjectType objType)
   1581 {
   1582     int isCached = 0;
   1583 
   1584     if (ctxt != NULL) {
   1585 	if (ctxt->cache != NULL) {
   1586 	    xmlXPathContextCachePtr cache =
   1587 		(xmlXPathContextCachePtr) ctxt->cache;
   1588 
   1589 	    isCached = 1;
   1590 
   1591 	    cache->dbgCachedAll++;
   1592 	    switch (objType) {
   1593 		case XPATH_UNDEFINED:
   1594 		    cache->dbgCachedUndefined++;
   1595 		    break;
   1596 		case XPATH_NODESET:
   1597 		    cache->dbgCachedNodeset++;
   1598 		    break;
   1599 		case XPATH_BOOLEAN:
   1600 		    cache->dbgCachedBool++;
   1601 		    break;
   1602 		case XPATH_NUMBER:
   1603 		    cache->dbgCachedNumber++;
   1604 		    break;
   1605 		case XPATH_STRING:
   1606 		    cache->dbgCachedString++;
   1607 		    break;
   1608 		case XPATH_POINT:
   1609 		    cache->dbgCachedPoint++;
   1610 		    break;
   1611 		case XPATH_RANGE:
   1612 		    cache->dbgCachedRange++;
   1613 		    break;
   1614 		case XPATH_LOCATIONSET:
   1615 		    cache->dbgCachedLocset++;
   1616 		    break;
   1617 		case XPATH_USERS:
   1618 		    cache->dbgCachedUsers++;
   1619 		    break;
   1620 		case XPATH_XSLT_TREE:
   1621 		    cache->dbgCachedXSLTTree++;
   1622 		    break;
   1623 		default:
   1624 		    break;
   1625 	    }
   1626 
   1627 	}
   1628     }
   1629     switch (objType) {
   1630 	case XPATH_UNDEFINED:
   1631 	    xmlXPathDebugObjCounterUndefined--;
   1632 	    break;
   1633 	case XPATH_NODESET:
   1634 	    xmlXPathDebugObjCounterNodeset--;
   1635 	    break;
   1636 	case XPATH_BOOLEAN:
   1637 	    xmlXPathDebugObjCounterBool--;
   1638 	    break;
   1639 	case XPATH_NUMBER:
   1640 	    xmlXPathDebugObjCounterNumber--;
   1641 	    break;
   1642 	case XPATH_STRING:
   1643 	    xmlXPathDebugObjCounterString--;
   1644 	    break;
   1645 	case XPATH_POINT:
   1646 	    xmlXPathDebugObjCounterPoint--;
   1647 	    break;
   1648 	case XPATH_RANGE:
   1649 	    xmlXPathDebugObjCounterRange--;
   1650 	    break;
   1651 	case XPATH_LOCATIONSET:
   1652 	    xmlXPathDebugObjCounterLocset--;
   1653 	    break;
   1654 	case XPATH_USERS:
   1655 	    xmlXPathDebugObjCounterUsers--;
   1656 	    break;
   1657 	case XPATH_XSLT_TREE:
   1658 	    xmlXPathDebugObjCounterXSLTTree--;
   1659 	    break;
   1660 	default:
   1661 	    break;
   1662     }
   1663     xmlXPathDebugObjCounterAll--;
   1664 }
   1665 
   1666 /* REVISIT TODO: Make this static when committing */
   1667 static void
   1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   1669 {
   1670     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   1671 	reqXSLTTree, reqUndefined;
   1672     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   1673 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   1674     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   1675 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   1676     int leftObjs = xmlXPathDebugObjCounterAll;
   1677 
   1678     reqAll = xmlXPathDebugObjTotalAll;
   1679     reqNodeset = xmlXPathDebugObjTotalNodeset;
   1680     reqString = xmlXPathDebugObjTotalString;
   1681     reqBool = xmlXPathDebugObjTotalBool;
   1682     reqNumber = xmlXPathDebugObjTotalNumber;
   1683     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   1684     reqUndefined = xmlXPathDebugObjTotalUndefined;
   1685 
   1686     printf("# XPath object usage:\n");
   1687 
   1688     if (ctxt != NULL) {
   1689 	if (ctxt->cache != NULL) {
   1690 	    xmlXPathContextCachePtr cache =
   1691 		(xmlXPathContextCachePtr) ctxt->cache;
   1692 
   1693 	    reAll = cache->dbgReusedAll;
   1694 	    reqAll += reAll;
   1695 	    reNodeset = cache->dbgReusedNodeset;
   1696 	    reqNodeset += reNodeset;
   1697 	    reString = cache->dbgReusedString;
   1698 	    reqString += reString;
   1699 	    reBool = cache->dbgReusedBool;
   1700 	    reqBool += reBool;
   1701 	    reNumber = cache->dbgReusedNumber;
   1702 	    reqNumber += reNumber;
   1703 	    reXSLTTree = cache->dbgReusedXSLTTree;
   1704 	    reqXSLTTree += reXSLTTree;
   1705 	    reUndefined = cache->dbgReusedUndefined;
   1706 	    reqUndefined += reUndefined;
   1707 
   1708 	    caAll = cache->dbgCachedAll;
   1709 	    caBool = cache->dbgCachedBool;
   1710 	    caNodeset = cache->dbgCachedNodeset;
   1711 	    caString = cache->dbgCachedString;
   1712 	    caNumber = cache->dbgCachedNumber;
   1713 	    caXSLTTree = cache->dbgCachedXSLTTree;
   1714 	    caUndefined = cache->dbgCachedUndefined;
   1715 
   1716 	    if (cache->nodesetObjs)
   1717 		leftObjs -= cache->nodesetObjs->number;
   1718 	    if (cache->stringObjs)
   1719 		leftObjs -= cache->stringObjs->number;
   1720 	    if (cache->booleanObjs)
   1721 		leftObjs -= cache->booleanObjs->number;
   1722 	    if (cache->numberObjs)
   1723 		leftObjs -= cache->numberObjs->number;
   1724 	    if (cache->miscObjs)
   1725 		leftObjs -= cache->miscObjs->number;
   1726 	}
   1727     }
   1728 
   1729     printf("# all\n");
   1730     printf("#   total  : %d\n", reqAll);
   1731     printf("#   left  : %d\n", leftObjs);
   1732     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   1733     printf("#   reused : %d\n", reAll);
   1734     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   1735 
   1736     printf("# node-sets\n");
   1737     printf("#   total  : %d\n", reqNodeset);
   1738     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   1739     printf("#   reused : %d\n", reNodeset);
   1740     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   1741 
   1742     printf("# strings\n");
   1743     printf("#   total  : %d\n", reqString);
   1744     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   1745     printf("#   reused : %d\n", reString);
   1746     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   1747 
   1748     printf("# booleans\n");
   1749     printf("#   total  : %d\n", reqBool);
   1750     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   1751     printf("#   reused : %d\n", reBool);
   1752     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   1753 
   1754     printf("# numbers\n");
   1755     printf("#   total  : %d\n", reqNumber);
   1756     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   1757     printf("#   reused : %d\n", reNumber);
   1758     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   1759 
   1760     printf("# XSLT result tree fragments\n");
   1761     printf("#   total  : %d\n", reqXSLTTree);
   1762     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   1763     printf("#   reused : %d\n", reXSLTTree);
   1764     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   1765 
   1766     printf("# undefined\n");
   1767     printf("#   total  : %d\n", reqUndefined);
   1768     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   1769     printf("#   reused : %d\n", reUndefined);
   1770     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   1771 
   1772 }
   1773 
   1774 #endif /* XP_DEBUG_OBJ_USAGE */
   1775 
   1776 #endif /* LIBXML_DEBUG_ENABLED */
   1777 
   1778 /************************************************************************
   1779  *									*
   1780  *			XPath object caching				*
   1781  *									*
   1782  ************************************************************************/
   1783 
   1784 /**
   1785  * xmlXPathNewCache:
   1786  *
   1787  * Create a new object cache
   1788  *
   1789  * Returns the xmlXPathCache just allocated.
   1790  */
   1791 static xmlXPathContextCachePtr
   1792 xmlXPathNewCache(void)
   1793 {
   1794     xmlXPathContextCachePtr ret;
   1795 
   1796     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   1797     if (ret == NULL) {
   1798         xmlXPathErrMemory(NULL, "creating object cache\n");
   1799 	return(NULL);
   1800     }
   1801     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   1802     ret->maxNodeset = 100;
   1803     ret->maxString = 100;
   1804     ret->maxBoolean = 100;
   1805     ret->maxNumber = 100;
   1806     ret->maxMisc = 100;
   1807     return(ret);
   1808 }
   1809 
   1810 static void
   1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   1812 {
   1813     int i;
   1814     xmlXPathObjectPtr obj;
   1815 
   1816     if (list == NULL)
   1817 	return;
   1818 
   1819     for (i = 0; i < list->number; i++) {
   1820 	obj = list->items[i];
   1821 	/*
   1822 	* Note that it is already assured that we don't need to
   1823 	* look out for namespace nodes in the node-set.
   1824 	*/
   1825 	if (obj->nodesetval != NULL) {
   1826 	    if (obj->nodesetval->nodeTab != NULL)
   1827 		xmlFree(obj->nodesetval->nodeTab);
   1828 	    xmlFree(obj->nodesetval);
   1829 	}
   1830 	xmlFree(obj);
   1831 #ifdef XP_DEBUG_OBJ_USAGE
   1832 	xmlXPathDebugObjCounterAll--;
   1833 #endif
   1834     }
   1835     xmlPointerListFree(list);
   1836 }
   1837 
   1838 static void
   1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   1840 {
   1841     if (cache == NULL)
   1842 	return;
   1843     if (cache->nodesetObjs)
   1844 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   1845     if (cache->stringObjs)
   1846 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   1847     if (cache->booleanObjs)
   1848 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   1849     if (cache->numberObjs)
   1850 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   1851     if (cache->miscObjs)
   1852 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   1853     xmlFree(cache);
   1854 }
   1855 
   1856 /**
   1857  * xmlXPathContextSetCache:
   1858  *
   1859  * @ctxt:  the XPath context
   1860  * @active: enables/disables (creates/frees) the cache
   1861  * @value: a value with semantics dependant on @options
   1862  * @options: options (currently only the value 0 is used)
   1863  *
   1864  * Creates/frees an object cache on the XPath context.
   1865  * If activates XPath objects (xmlXPathObject) will be cached internally
   1866  * to be reused.
   1867  * @options:
   1868  *   0: This will set the XPath object caching:
   1869  *      @value:
   1870  *        This will set the maximum number of XPath objects
   1871  *        to be cached per slot
   1872  *        There are 5 slots for: node-set, string, number, boolean, and
   1873  *        misc objects. Use <0 for the default number (100).
   1874  *   Other values for @options have currently no effect.
   1875  *
   1876  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   1877  */
   1878 int
   1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   1880 			int active,
   1881 			int value,
   1882 			int options)
   1883 {
   1884     if (ctxt == NULL)
   1885 	return(-1);
   1886     if (active) {
   1887 	xmlXPathContextCachePtr cache;
   1888 
   1889 	if (ctxt->cache == NULL) {
   1890 	    ctxt->cache = xmlXPathNewCache();
   1891 	    if (ctxt->cache == NULL)
   1892 		return(-1);
   1893 	}
   1894 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   1895 	if (options == 0) {
   1896 	    if (value < 0)
   1897 		value = 100;
   1898 	    cache->maxNodeset = value;
   1899 	    cache->maxString = value;
   1900 	    cache->maxNumber = value;
   1901 	    cache->maxBoolean = value;
   1902 	    cache->maxMisc = value;
   1903 	}
   1904     } else if (ctxt->cache != NULL) {
   1905 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   1906 	ctxt->cache = NULL;
   1907     }
   1908     return(0);
   1909 }
   1910 
   1911 /**
   1912  * xmlXPathCacheWrapNodeSet:
   1913  * @ctxt: the XPath context
   1914  * @val:  the NodePtr value
   1915  *
   1916  * This is the cached version of xmlXPathWrapNodeSet().
   1917  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   1918  *
   1919  * Returns the created or reused object.
   1920  */
   1921 static xmlXPathObjectPtr
   1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   1923 {
   1924     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1925 	xmlXPathContextCachePtr cache =
   1926 	    (xmlXPathContextCachePtr) ctxt->cache;
   1927 
   1928 	if ((cache->miscObjs != NULL) &&
   1929 	    (cache->miscObjs->number != 0))
   1930 	{
   1931 	    xmlXPathObjectPtr ret;
   1932 
   1933 	    ret = (xmlXPathObjectPtr)
   1934 		cache->miscObjs->items[--cache->miscObjs->number];
   1935 	    ret->type = XPATH_NODESET;
   1936 	    ret->nodesetval = val;
   1937 #ifdef XP_DEBUG_OBJ_USAGE
   1938 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   1939 #endif
   1940 	    return(ret);
   1941 	}
   1942     }
   1943 
   1944     return(xmlXPathWrapNodeSet(val));
   1945 
   1946 }
   1947 
   1948 /**
   1949  * xmlXPathCacheWrapString:
   1950  * @ctxt: the XPath context
   1951  * @val:  the xmlChar * value
   1952  *
   1953  * This is the cached version of xmlXPathWrapString().
   1954  * Wraps the @val string into an XPath object.
   1955  *
   1956  * Returns the created or reused object.
   1957  */
   1958 static xmlXPathObjectPtr
   1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   1960 {
   1961     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   1962 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   1963 
   1964 	if ((cache->stringObjs != NULL) &&
   1965 	    (cache->stringObjs->number != 0))
   1966 	{
   1967 
   1968 	    xmlXPathObjectPtr ret;
   1969 
   1970 	    ret = (xmlXPathObjectPtr)
   1971 		cache->stringObjs->items[--cache->stringObjs->number];
   1972 	    ret->type = XPATH_STRING;
   1973 	    ret->stringval = val;
   1974 #ifdef XP_DEBUG_OBJ_USAGE
   1975 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1976 #endif
   1977 	    return(ret);
   1978 	} else if ((cache->miscObjs != NULL) &&
   1979 	    (cache->miscObjs->number != 0))
   1980 	{
   1981 	    xmlXPathObjectPtr ret;
   1982 	    /*
   1983 	    * Fallback to misc-cache.
   1984 	    */
   1985 	    ret = (xmlXPathObjectPtr)
   1986 		cache->miscObjs->items[--cache->miscObjs->number];
   1987 
   1988 	    ret->type = XPATH_STRING;
   1989 	    ret->stringval = val;
   1990 #ifdef XP_DEBUG_OBJ_USAGE
   1991 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   1992 #endif
   1993 	    return(ret);
   1994 	}
   1995     }
   1996     return(xmlXPathWrapString(val));
   1997 }
   1998 
   1999 /**
   2000  * xmlXPathCacheNewNodeSet:
   2001  * @ctxt: the XPath context
   2002  * @val:  the NodePtr value
   2003  *
   2004  * This is the cached version of xmlXPathNewNodeSet().
   2005  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2006  * it with the single Node @val
   2007  *
   2008  * Returns the created or reused object.
   2009  */
   2010 static xmlXPathObjectPtr
   2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2012 {
   2013     if ((ctxt != NULL) && (ctxt->cache)) {
   2014 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2015 
   2016 	if ((cache->nodesetObjs != NULL) &&
   2017 	    (cache->nodesetObjs->number != 0))
   2018 	{
   2019 	    xmlXPathObjectPtr ret;
   2020 	    /*
   2021 	    * Use the nodset-cache.
   2022 	    */
   2023 	    ret = (xmlXPathObjectPtr)
   2024 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2025 	    ret->type = XPATH_NODESET;
   2026 	    ret->boolval = 0;
   2027 	    if (val) {
   2028 		if ((ret->nodesetval->nodeMax == 0) ||
   2029 		    (val->type == XML_NAMESPACE_DECL))
   2030 		{
   2031 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2032 		} else {
   2033 		    ret->nodesetval->nodeTab[0] = val;
   2034 		    ret->nodesetval->nodeNr = 1;
   2035 		}
   2036 	    }
   2037 #ifdef XP_DEBUG_OBJ_USAGE
   2038 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2039 #endif
   2040 	    return(ret);
   2041 	} else if ((cache->miscObjs != NULL) &&
   2042 	    (cache->miscObjs->number != 0))
   2043 	{
   2044 	    xmlXPathObjectPtr ret;
   2045 	    /*
   2046 	    * Fallback to misc-cache.
   2047 	    */
   2048 
   2049 	    ret = (xmlXPathObjectPtr)
   2050 		cache->miscObjs->items[--cache->miscObjs->number];
   2051 
   2052 	    ret->type = XPATH_NODESET;
   2053 	    ret->boolval = 0;
   2054 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2055 #ifdef XP_DEBUG_OBJ_USAGE
   2056 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2057 #endif
   2058 	    return(ret);
   2059 	}
   2060     }
   2061     return(xmlXPathNewNodeSet(val));
   2062 }
   2063 
   2064 /**
   2065  * xmlXPathCacheNewCString:
   2066  * @ctxt: the XPath context
   2067  * @val:  the char * value
   2068  *
   2069  * This is the cached version of xmlXPathNewCString().
   2070  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2071  *
   2072  * Returns the created or reused object.
   2073  */
   2074 static xmlXPathObjectPtr
   2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2076 {
   2077     if ((ctxt != NULL) && (ctxt->cache)) {
   2078 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2079 
   2080 	if ((cache->stringObjs != NULL) &&
   2081 	    (cache->stringObjs->number != 0))
   2082 	{
   2083 	    xmlXPathObjectPtr ret;
   2084 
   2085 	    ret = (xmlXPathObjectPtr)
   2086 		cache->stringObjs->items[--cache->stringObjs->number];
   2087 
   2088 	    ret->type = XPATH_STRING;
   2089 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2090 #ifdef XP_DEBUG_OBJ_USAGE
   2091 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2092 #endif
   2093 	    return(ret);
   2094 	} else if ((cache->miscObjs != NULL) &&
   2095 	    (cache->miscObjs->number != 0))
   2096 	{
   2097 	    xmlXPathObjectPtr ret;
   2098 
   2099 	    ret = (xmlXPathObjectPtr)
   2100 		cache->miscObjs->items[--cache->miscObjs->number];
   2101 
   2102 	    ret->type = XPATH_STRING;
   2103 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2104 #ifdef XP_DEBUG_OBJ_USAGE
   2105 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2106 #endif
   2107 	    return(ret);
   2108 	}
   2109     }
   2110     return(xmlXPathNewCString(val));
   2111 }
   2112 
   2113 /**
   2114  * xmlXPathCacheNewString:
   2115  * @ctxt: the XPath context
   2116  * @val:  the xmlChar * value
   2117  *
   2118  * This is the cached version of xmlXPathNewString().
   2119  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2120  *
   2121  * Returns the created or reused object.
   2122  */
   2123 static xmlXPathObjectPtr
   2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2125 {
   2126     if ((ctxt != NULL) && (ctxt->cache)) {
   2127 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2128 
   2129 	if ((cache->stringObjs != NULL) &&
   2130 	    (cache->stringObjs->number != 0))
   2131 	{
   2132 	    xmlXPathObjectPtr ret;
   2133 
   2134 	    ret = (xmlXPathObjectPtr)
   2135 		cache->stringObjs->items[--cache->stringObjs->number];
   2136 	    ret->type = XPATH_STRING;
   2137 	    if (val != NULL)
   2138 		ret->stringval = xmlStrdup(val);
   2139 	    else
   2140 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2141 #ifdef XP_DEBUG_OBJ_USAGE
   2142 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2143 #endif
   2144 	    return(ret);
   2145 	} else if ((cache->miscObjs != NULL) &&
   2146 	    (cache->miscObjs->number != 0))
   2147 	{
   2148 	    xmlXPathObjectPtr ret;
   2149 
   2150 	    ret = (xmlXPathObjectPtr)
   2151 		cache->miscObjs->items[--cache->miscObjs->number];
   2152 
   2153 	    ret->type = XPATH_STRING;
   2154 	    if (val != NULL)
   2155 		ret->stringval = xmlStrdup(val);
   2156 	    else
   2157 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2158 #ifdef XP_DEBUG_OBJ_USAGE
   2159 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2160 #endif
   2161 	    return(ret);
   2162 	}
   2163     }
   2164     return(xmlXPathNewString(val));
   2165 }
   2166 
   2167 /**
   2168  * xmlXPathCacheNewBoolean:
   2169  * @ctxt: the XPath context
   2170  * @val:  the boolean value
   2171  *
   2172  * This is the cached version of xmlXPathNewBoolean().
   2173  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2174  *
   2175  * Returns the created or reused object.
   2176  */
   2177 static xmlXPathObjectPtr
   2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2179 {
   2180     if ((ctxt != NULL) && (ctxt->cache)) {
   2181 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2182 
   2183 	if ((cache->booleanObjs != NULL) &&
   2184 	    (cache->booleanObjs->number != 0))
   2185 	{
   2186 	    xmlXPathObjectPtr ret;
   2187 
   2188 	    ret = (xmlXPathObjectPtr)
   2189 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2190 	    ret->type = XPATH_BOOLEAN;
   2191 	    ret->boolval = (val != 0);
   2192 #ifdef XP_DEBUG_OBJ_USAGE
   2193 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2194 #endif
   2195 	    return(ret);
   2196 	} else if ((cache->miscObjs != NULL) &&
   2197 	    (cache->miscObjs->number != 0))
   2198 	{
   2199 	    xmlXPathObjectPtr ret;
   2200 
   2201 	    ret = (xmlXPathObjectPtr)
   2202 		cache->miscObjs->items[--cache->miscObjs->number];
   2203 
   2204 	    ret->type = XPATH_BOOLEAN;
   2205 	    ret->boolval = (val != 0);
   2206 #ifdef XP_DEBUG_OBJ_USAGE
   2207 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2208 #endif
   2209 	    return(ret);
   2210 	}
   2211     }
   2212     return(xmlXPathNewBoolean(val));
   2213 }
   2214 
   2215 /**
   2216  * xmlXPathCacheNewFloat:
   2217  * @ctxt: the XPath context
   2218  * @val:  the double value
   2219  *
   2220  * This is the cached version of xmlXPathNewFloat().
   2221  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2222  *
   2223  * Returns the created or reused object.
   2224  */
   2225 static xmlXPathObjectPtr
   2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2227 {
   2228      if ((ctxt != NULL) && (ctxt->cache)) {
   2229 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2230 
   2231 	if ((cache->numberObjs != NULL) &&
   2232 	    (cache->numberObjs->number != 0))
   2233 	{
   2234 	    xmlXPathObjectPtr ret;
   2235 
   2236 	    ret = (xmlXPathObjectPtr)
   2237 		cache->numberObjs->items[--cache->numberObjs->number];
   2238 	    ret->type = XPATH_NUMBER;
   2239 	    ret->floatval = val;
   2240 #ifdef XP_DEBUG_OBJ_USAGE
   2241 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2242 #endif
   2243 	    return(ret);
   2244 	} else if ((cache->miscObjs != NULL) &&
   2245 	    (cache->miscObjs->number != 0))
   2246 	{
   2247 	    xmlXPathObjectPtr ret;
   2248 
   2249 	    ret = (xmlXPathObjectPtr)
   2250 		cache->miscObjs->items[--cache->miscObjs->number];
   2251 
   2252 	    ret->type = XPATH_NUMBER;
   2253 	    ret->floatval = val;
   2254 #ifdef XP_DEBUG_OBJ_USAGE
   2255 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2256 #endif
   2257 	    return(ret);
   2258 	}
   2259     }
   2260     return(xmlXPathNewFloat(val));
   2261 }
   2262 
   2263 /**
   2264  * xmlXPathCacheConvertString:
   2265  * @ctxt: the XPath context
   2266  * @val:  an XPath object
   2267  *
   2268  * This is the cached version of xmlXPathConvertString().
   2269  * Converts an existing object to its string() equivalent
   2270  *
   2271  * Returns a created or reused object, the old one is freed (cached)
   2272  *         (or the operation is done directly on @val)
   2273  */
   2274 
   2275 static xmlXPathObjectPtr
   2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2277     xmlChar *res = NULL;
   2278 
   2279     if (val == NULL)
   2280 	return(xmlXPathCacheNewCString(ctxt, ""));
   2281 
   2282     switch (val->type) {
   2283     case XPATH_UNDEFINED:
   2284 #ifdef DEBUG_EXPR
   2285 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2286 #endif
   2287 	break;
   2288     case XPATH_NODESET:
   2289     case XPATH_XSLT_TREE:
   2290 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2291 	break;
   2292     case XPATH_STRING:
   2293 	return(val);
   2294     case XPATH_BOOLEAN:
   2295 	res = xmlXPathCastBooleanToString(val->boolval);
   2296 	break;
   2297     case XPATH_NUMBER:
   2298 	res = xmlXPathCastNumberToString(val->floatval);
   2299 	break;
   2300     case XPATH_USERS:
   2301     case XPATH_POINT:
   2302     case XPATH_RANGE:
   2303     case XPATH_LOCATIONSET:
   2304 	TODO;
   2305 	break;
   2306     }
   2307     xmlXPathReleaseObject(ctxt, val);
   2308     if (res == NULL)
   2309 	return(xmlXPathCacheNewCString(ctxt, ""));
   2310     return(xmlXPathCacheWrapString(ctxt, res));
   2311 }
   2312 
   2313 /**
   2314  * xmlXPathCacheObjectCopy:
   2315  * @ctxt: the XPath context
   2316  * @val:  the original object
   2317  *
   2318  * This is the cached version of xmlXPathObjectCopy().
   2319  * Acquire a copy of a given object
   2320  *
   2321  * Returns a created or reused created object.
   2322  */
   2323 static xmlXPathObjectPtr
   2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2325 {
   2326     if (val == NULL)
   2327 	return(NULL);
   2328 
   2329     if (XP_HAS_CACHE(ctxt)) {
   2330 	switch (val->type) {
   2331 	    case XPATH_NODESET:
   2332 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2333 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2334 	    case XPATH_STRING:
   2335 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2336 	    case XPATH_BOOLEAN:
   2337 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2338 	    case XPATH_NUMBER:
   2339 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2340 	    default:
   2341 		break;
   2342 	}
   2343     }
   2344     return(xmlXPathObjectCopy(val));
   2345 }
   2346 
   2347 /**
   2348  * xmlXPathCacheConvertBoolean:
   2349  * @ctxt: the XPath context
   2350  * @val:  an XPath object
   2351  *
   2352  * This is the cached version of xmlXPathConvertBoolean().
   2353  * Converts an existing object to its boolean() equivalent
   2354  *
   2355  * Returns a created or reused object, the old one is freed (or the operation
   2356  *         is done directly on @val)
   2357  */
   2358 static xmlXPathObjectPtr
   2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2360     xmlXPathObjectPtr ret;
   2361 
   2362     if (val == NULL)
   2363 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2364     if (val->type == XPATH_BOOLEAN)
   2365 	return(val);
   2366     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2367     xmlXPathReleaseObject(ctxt, val);
   2368     return(ret);
   2369 }
   2370 
   2371 /**
   2372  * xmlXPathCacheConvertNumber:
   2373  * @ctxt: the XPath context
   2374  * @val:  an XPath object
   2375  *
   2376  * This is the cached version of xmlXPathConvertNumber().
   2377  * Converts an existing object to its number() equivalent
   2378  *
   2379  * Returns a created or reused object, the old one is freed (or the operation
   2380  *         is done directly on @val)
   2381  */
   2382 static xmlXPathObjectPtr
   2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2384     xmlXPathObjectPtr ret;
   2385 
   2386     if (val == NULL)
   2387 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2388     if (val->type == XPATH_NUMBER)
   2389 	return(val);
   2390     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2391     xmlXPathReleaseObject(ctxt, val);
   2392     return(ret);
   2393 }
   2394 
   2395 /************************************************************************
   2396  *									*
   2397  *		Parser stacks related functions and macros		*
   2398  *									*
   2399  ************************************************************************/
   2400 
   2401 /**
   2402  * xmlXPathSetFrame:
   2403  * @ctxt: an XPath parser context
   2404  *
   2405  * Set the callee evaluation frame
   2406  *
   2407  * Returns the previous frame value to be restored once done
   2408  */
   2409 static int
   2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2411     int ret;
   2412 
   2413     if (ctxt == NULL)
   2414         return(0);
   2415     ret = ctxt->valueFrame;
   2416     ctxt->valueFrame = ctxt->valueNr;
   2417     return(ret);
   2418 }
   2419 
   2420 /**
   2421  * xmlXPathPopFrame:
   2422  * @ctxt: an XPath parser context
   2423  * @frame: the previous frame value
   2424  *
   2425  * Remove the callee evaluation frame
   2426  */
   2427 static void
   2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2429     if (ctxt == NULL)
   2430         return;
   2431     if (ctxt->valueNr < ctxt->valueFrame) {
   2432         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2433     }
   2434     ctxt->valueFrame = frame;
   2435 }
   2436 
   2437 /**
   2438  * valuePop:
   2439  * @ctxt: an XPath evaluation context
   2440  *
   2441  * Pops the top XPath object from the value stack
   2442  *
   2443  * Returns the XPath object just removed
   2444  */
   2445 xmlXPathObjectPtr
   2446 valuePop(xmlXPathParserContextPtr ctxt)
   2447 {
   2448     xmlXPathObjectPtr ret;
   2449 
   2450     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2451         return (NULL);
   2452 
   2453     if (ctxt->valueNr <= ctxt->valueFrame) {
   2454         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2455         return (NULL);
   2456     }
   2457 
   2458     ctxt->valueNr--;
   2459     if (ctxt->valueNr > 0)
   2460         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2461     else
   2462         ctxt->value = NULL;
   2463     ret = ctxt->valueTab[ctxt->valueNr];
   2464     ctxt->valueTab[ctxt->valueNr] = NULL;
   2465     return (ret);
   2466 }
   2467 /**
   2468  * valuePush:
   2469  * @ctxt:  an XPath evaluation context
   2470  * @value:  the XPath object
   2471  *
   2472  * Pushes a new XPath object on top of the value stack
   2473  *
   2474  * returns the number of items on the value stack
   2475  */
   2476 int
   2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2478 {
   2479     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2480     if (ctxt->valueNr >= ctxt->valueMax) {
   2481         xmlXPathObjectPtr *tmp;
   2482 
   2483         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2484                                              2 * ctxt->valueMax *
   2485                                              sizeof(ctxt->valueTab[0]));
   2486         if (tmp == NULL) {
   2487             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
   2488             ctxt->error = XPATH_MEMORY_ERROR;
   2489             return (0);
   2490         }
   2491         ctxt->valueMax *= 2;
   2492 	ctxt->valueTab = tmp;
   2493     }
   2494     ctxt->valueTab[ctxt->valueNr] = value;
   2495     ctxt->value = value;
   2496     return (ctxt->valueNr++);
   2497 }
   2498 
   2499 /**
   2500  * xmlXPathPopBoolean:
   2501  * @ctxt:  an XPath parser context
   2502  *
   2503  * Pops a boolean from the stack, handling conversion if needed.
   2504  * Check error with #xmlXPathCheckError.
   2505  *
   2506  * Returns the boolean
   2507  */
   2508 int
   2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2510     xmlXPathObjectPtr obj;
   2511     int ret;
   2512 
   2513     obj = valuePop(ctxt);
   2514     if (obj == NULL) {
   2515 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2516 	return(0);
   2517     }
   2518     if (obj->type != XPATH_BOOLEAN)
   2519 	ret = xmlXPathCastToBoolean(obj);
   2520     else
   2521         ret = obj->boolval;
   2522     xmlXPathReleaseObject(ctxt->context, obj);
   2523     return(ret);
   2524 }
   2525 
   2526 /**
   2527  * xmlXPathPopNumber:
   2528  * @ctxt:  an XPath parser context
   2529  *
   2530  * Pops a number from the stack, handling conversion if needed.
   2531  * Check error with #xmlXPathCheckError.
   2532  *
   2533  * Returns the number
   2534  */
   2535 double
   2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2537     xmlXPathObjectPtr obj;
   2538     double ret;
   2539 
   2540     obj = valuePop(ctxt);
   2541     if (obj == NULL) {
   2542 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2543 	return(0);
   2544     }
   2545     if (obj->type != XPATH_NUMBER)
   2546 	ret = xmlXPathCastToNumber(obj);
   2547     else
   2548         ret = obj->floatval;
   2549     xmlXPathReleaseObject(ctxt->context, obj);
   2550     return(ret);
   2551 }
   2552 
   2553 /**
   2554  * xmlXPathPopString:
   2555  * @ctxt:  an XPath parser context
   2556  *
   2557  * Pops a string from the stack, handling conversion if needed.
   2558  * Check error with #xmlXPathCheckError.
   2559  *
   2560  * Returns the string
   2561  */
   2562 xmlChar *
   2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2564     xmlXPathObjectPtr obj;
   2565     xmlChar * ret;
   2566 
   2567     obj = valuePop(ctxt);
   2568     if (obj == NULL) {
   2569 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2570 	return(NULL);
   2571     }
   2572     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2573     /* TODO: needs refactoring somewhere else */
   2574     if (obj->stringval == ret)
   2575 	obj->stringval = NULL;
   2576     xmlXPathReleaseObject(ctxt->context, obj);
   2577     return(ret);
   2578 }
   2579 
   2580 /**
   2581  * xmlXPathPopNodeSet:
   2582  * @ctxt:  an XPath parser context
   2583  *
   2584  * Pops a node-set from the stack, handling conversion if needed.
   2585  * Check error with #xmlXPathCheckError.
   2586  *
   2587  * Returns the node-set
   2588  */
   2589 xmlNodeSetPtr
   2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2591     xmlXPathObjectPtr obj;
   2592     xmlNodeSetPtr ret;
   2593 
   2594     if (ctxt == NULL) return(NULL);
   2595     if (ctxt->value == NULL) {
   2596 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2597 	return(NULL);
   2598     }
   2599     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2600 	xmlXPathSetTypeError(ctxt);
   2601 	return(NULL);
   2602     }
   2603     obj = valuePop(ctxt);
   2604     ret = obj->nodesetval;
   2605 #if 0
   2606     /* to fix memory leak of not clearing obj->user */
   2607     if (obj->boolval && obj->user != NULL)
   2608         xmlFreeNodeList((xmlNodePtr) obj->user);
   2609 #endif
   2610     obj->nodesetval = NULL;
   2611     xmlXPathReleaseObject(ctxt->context, obj);
   2612     return(ret);
   2613 }
   2614 
   2615 /**
   2616  * xmlXPathPopExternal:
   2617  * @ctxt:  an XPath parser context
   2618  *
   2619  * Pops an external object from the stack, handling conversion if needed.
   2620  * Check error with #xmlXPathCheckError.
   2621  *
   2622  * Returns the object
   2623  */
   2624 void *
   2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   2626     xmlXPathObjectPtr obj;
   2627     void * ret;
   2628 
   2629     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   2630 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2631 	return(NULL);
   2632     }
   2633     if (ctxt->value->type != XPATH_USERS) {
   2634 	xmlXPathSetTypeError(ctxt);
   2635 	return(NULL);
   2636     }
   2637     obj = valuePop(ctxt);
   2638     ret = obj->user;
   2639     obj->user = NULL;
   2640     xmlXPathReleaseObject(ctxt->context, obj);
   2641     return(ret);
   2642 }
   2643 
   2644 /*
   2645  * Macros for accessing the content. Those should be used only by the parser,
   2646  * and not exported.
   2647  *
   2648  * Dirty macros, i.e. one need to make assumption on the context to use them
   2649  *
   2650  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   2651  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   2652  *           in ISO-Latin or UTF-8.
   2653  *           This should be used internally by the parser
   2654  *           only to compare to ASCII values otherwise it would break when
   2655  *           running with UTF-8 encoding.
   2656  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   2657  *           to compare on ASCII based substring.
   2658  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   2659  *           strings within the parser.
   2660  *   CURRENT Returns the current char value, with the full decoding of
   2661  *           UTF-8 if we are using this mode. It returns an int.
   2662  *   NEXT    Skip to the next character, this does the proper decoding
   2663  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   2664  *           It returns the pointer to the current xmlChar.
   2665  */
   2666 
   2667 #define CUR (*ctxt->cur)
   2668 #define SKIP(val) ctxt->cur += (val)
   2669 #define NXT(val) ctxt->cur[(val)]
   2670 #define CUR_PTR ctxt->cur
   2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   2672 
   2673 #define COPY_BUF(l,b,i,v)                                              \
   2674     if (l == 1) b[i++] = (xmlChar) v;                                  \
   2675     else i += xmlCopyChar(l,&b[i],v)
   2676 
   2677 #define NEXTL(l)  ctxt->cur += l
   2678 
   2679 #define SKIP_BLANKS							\
   2680     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   2681 
   2682 #define CURRENT (*ctxt->cur)
   2683 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   2684 
   2685 
   2686 #ifndef DBL_DIG
   2687 #define DBL_DIG 16
   2688 #endif
   2689 #ifndef DBL_EPSILON
   2690 #define DBL_EPSILON 1E-9
   2691 #endif
   2692 
   2693 #define UPPER_DOUBLE 1E9
   2694 #define LOWER_DOUBLE 1E-5
   2695 #define	LOWER_DOUBLE_EXP 5
   2696 
   2697 #define INTEGER_DIGITS DBL_DIG
   2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   2699 #define EXPONENT_DIGITS (3 + 2)
   2700 
   2701 /**
   2702  * xmlXPathFormatNumber:
   2703  * @number:     number to format
   2704  * @buffer:     output buffer
   2705  * @buffersize: size of output buffer
   2706  *
   2707  * Convert the number into a string representation.
   2708  */
   2709 static void
   2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   2711 {
   2712     switch (xmlXPathIsInf(number)) {
   2713     case 1:
   2714 	if (buffersize > (int)sizeof("Infinity"))
   2715 	    snprintf(buffer, buffersize, "Infinity");
   2716 	break;
   2717     case -1:
   2718 	if (buffersize > (int)sizeof("-Infinity"))
   2719 	    snprintf(buffer, buffersize, "-Infinity");
   2720 	break;
   2721     default:
   2722 	if (xmlXPathIsNaN(number)) {
   2723 	    if (buffersize > (int)sizeof("NaN"))
   2724 		snprintf(buffer, buffersize, "NaN");
   2725 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   2726 	    snprintf(buffer, buffersize, "0");
   2727 	} else if (number == ((int) number)) {
   2728 	    char work[30];
   2729 	    char *ptr, *cur;
   2730 	    int value = (int) number;
   2731 
   2732             ptr = &buffer[0];
   2733 	    if (value == 0) {
   2734 		*ptr++ = '0';
   2735 	    } else {
   2736 		snprintf(work, 29, "%d", value);
   2737 		cur = &work[0];
   2738 		while ((*cur) && (ptr - buffer < buffersize)) {
   2739 		    *ptr++ = *cur++;
   2740 		}
   2741 	    }
   2742 	    if (ptr - buffer < buffersize) {
   2743 		*ptr = 0;
   2744 	    } else if (buffersize > 0) {
   2745 		ptr--;
   2746 		*ptr = 0;
   2747 	    }
   2748 	} else {
   2749 	    /*
   2750 	      For the dimension of work,
   2751 	          DBL_DIG is number of significant digits
   2752 		  EXPONENT is only needed for "scientific notation"
   2753 	          3 is sign, decimal point, and terminating zero
   2754 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   2755 	      Note that this dimension is slightly (a few characters)
   2756 	      larger than actually necessary.
   2757 	    */
   2758 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   2759 	    int integer_place, fraction_place;
   2760 	    char *ptr;
   2761 	    char *after_fraction;
   2762 	    double absolute_value;
   2763 	    int size;
   2764 
   2765 	    absolute_value = fabs(number);
   2766 
   2767 	    /*
   2768 	     * First choose format - scientific or regular floating point.
   2769 	     * In either case, result is in work, and after_fraction points
   2770 	     * just past the fractional part.
   2771 	    */
   2772 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   2773 		  (absolute_value < LOWER_DOUBLE)) &&
   2774 		 (absolute_value != 0.0) ) {
   2775 		/* Use scientific notation */
   2776 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   2777 		fraction_place = DBL_DIG - 1;
   2778 		size = snprintf(work, sizeof(work),"%*.*e",
   2779 			 integer_place, fraction_place, number);
   2780 		while ((size > 0) && (work[size] != 'e')) size--;
   2781 
   2782 	    }
   2783 	    else {
   2784 		/* Use regular notation */
   2785 		if (absolute_value > 0.0) {
   2786 		    integer_place = (int)log10(absolute_value);
   2787 		    if (integer_place > 0)
   2788 		        fraction_place = DBL_DIG - integer_place - 1;
   2789 		    else
   2790 		        fraction_place = DBL_DIG - integer_place;
   2791 		} else {
   2792 		    fraction_place = 1;
   2793 		}
   2794 		size = snprintf(work, sizeof(work), "%0.*f",
   2795 				fraction_place, number);
   2796 	    }
   2797 
   2798 	    /* Remove fractional trailing zeroes */
   2799 	    after_fraction = work + size;
   2800 	    ptr = after_fraction;
   2801 	    while (*(--ptr) == '0')
   2802 		;
   2803 	    if (*ptr != '.')
   2804 	        ptr++;
   2805 	    while ((*ptr++ = *after_fraction++) != 0);
   2806 
   2807 	    /* Finally copy result back to caller */
   2808 	    size = strlen(work) + 1;
   2809 	    if (size > buffersize && buffersize <= (int)sizeof(work)) {
   2810 		work[buffersize - 1] = 0;
   2811 		size = buffersize;
   2812 	    }
   2813 	    memmove(buffer, work, size);
   2814 	}
   2815 	break;
   2816     }
   2817 }
   2818 
   2819 
   2820 /************************************************************************
   2821  *									*
   2822  *			Routines to handle NodeSets			*
   2823  *									*
   2824  ************************************************************************/
   2825 
   2826 /**
   2827  * xmlXPathOrderDocElems:
   2828  * @doc:  an input document
   2829  *
   2830  * Call this routine to speed up XPath computation on static documents.
   2831  * This stamps all the element nodes with the document order
   2832  * Like for line information, the order is kept in the element->content
   2833  * field, the value stored is actually - the node number (starting at -1)
   2834  * to be able to differentiate from line numbers.
   2835  *
   2836  * Returns the number of elements found in the document or -1 in case
   2837  *    of error.
   2838  */
   2839 long
   2840 xmlXPathOrderDocElems(xmlDocPtr doc) {
   2841     long count = 0;
   2842     xmlNodePtr cur;
   2843 
   2844     if (doc == NULL)
   2845 	return(-1);
   2846     cur = doc->children;
   2847     while (cur != NULL) {
   2848 	if (cur->type == XML_ELEMENT_NODE) {
   2849 	    cur->content = (void *) (-(++count));
   2850 	    if (cur->children != NULL) {
   2851 		cur = cur->children;
   2852 		continue;
   2853 	    }
   2854 	}
   2855 	if (cur->next != NULL) {
   2856 	    cur = cur->next;
   2857 	    continue;
   2858 	}
   2859 	do {
   2860 	    cur = cur->parent;
   2861 	    if (cur == NULL)
   2862 		break;
   2863 	    if (cur == (xmlNodePtr) doc) {
   2864 		cur = NULL;
   2865 		break;
   2866 	    }
   2867 	    if (cur->next != NULL) {
   2868 		cur = cur->next;
   2869 		break;
   2870 	    }
   2871 	} while (cur != NULL);
   2872     }
   2873     return(count);
   2874 }
   2875 
   2876 /**
   2877  * xmlXPathCmpNodes:
   2878  * @node1:  the first node
   2879  * @node2:  the second node
   2880  *
   2881  * Compare two nodes w.r.t document order
   2882  *
   2883  * Returns -2 in case of error 1 if first point < second point, 0 if
   2884  *         it's the same node, -1 otherwise
   2885  */
   2886 int
   2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   2888     int depth1, depth2;
   2889     int attr1 = 0, attr2 = 0;
   2890     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   2891     xmlNodePtr cur, root;
   2892 
   2893     if ((node1 == NULL) || (node2 == NULL))
   2894 	return(-2);
   2895     /*
   2896      * a couple of optimizations which will avoid computations in most cases
   2897      */
   2898     if (node1 == node2)		/* trivial case */
   2899 	return(0);
   2900     if (node1->type == XML_ATTRIBUTE_NODE) {
   2901 	attr1 = 1;
   2902 	attrNode1 = node1;
   2903 	node1 = node1->parent;
   2904     }
   2905     if (node2->type == XML_ATTRIBUTE_NODE) {
   2906 	attr2 = 1;
   2907 	attrNode2 = node2;
   2908 	node2 = node2->parent;
   2909     }
   2910     if (node1 == node2) {
   2911 	if (attr1 == attr2) {
   2912 	    /* not required, but we keep attributes in order */
   2913 	    if (attr1 != 0) {
   2914 	        cur = attrNode2->prev;
   2915 		while (cur != NULL) {
   2916 		    if (cur == attrNode1)
   2917 		        return (1);
   2918 		    cur = cur->prev;
   2919 		}
   2920 		return (-1);
   2921 	    }
   2922 	    return(0);
   2923 	}
   2924 	if (attr2 == 1)
   2925 	    return(1);
   2926 	return(-1);
   2927     }
   2928     if ((node1->type == XML_NAMESPACE_DECL) ||
   2929         (node2->type == XML_NAMESPACE_DECL))
   2930 	return(1);
   2931     if (node1 == node2->prev)
   2932 	return(1);
   2933     if (node1 == node2->next)
   2934 	return(-1);
   2935 
   2936     /*
   2937      * Speedup using document order if availble.
   2938      */
   2939     if ((node1->type == XML_ELEMENT_NODE) &&
   2940 	(node2->type == XML_ELEMENT_NODE) &&
   2941 	(0 > (long) node1->content) &&
   2942 	(0 > (long) node2->content) &&
   2943 	(node1->doc == node2->doc)) {
   2944 	long l1, l2;
   2945 
   2946 	l1 = -((long) node1->content);
   2947 	l2 = -((long) node2->content);
   2948 	if (l1 < l2)
   2949 	    return(1);
   2950 	if (l1 > l2)
   2951 	    return(-1);
   2952     }
   2953 
   2954     /*
   2955      * compute depth to root
   2956      */
   2957     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   2958 	if (cur == node1)
   2959 	    return(1);
   2960 	depth2++;
   2961     }
   2962     root = cur;
   2963     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   2964 	if (cur == node2)
   2965 	    return(-1);
   2966 	depth1++;
   2967     }
   2968     /*
   2969      * Distinct document (or distinct entities :-( ) case.
   2970      */
   2971     if (root != cur) {
   2972 	return(-2);
   2973     }
   2974     /*
   2975      * get the nearest common ancestor.
   2976      */
   2977     while (depth1 > depth2) {
   2978 	depth1--;
   2979 	node1 = node1->parent;
   2980     }
   2981     while (depth2 > depth1) {
   2982 	depth2--;
   2983 	node2 = node2->parent;
   2984     }
   2985     while (node1->parent != node2->parent) {
   2986 	node1 = node1->parent;
   2987 	node2 = node2->parent;
   2988 	/* should not happen but just in case ... */
   2989 	if ((node1 == NULL) || (node2 == NULL))
   2990 	    return(-2);
   2991     }
   2992     /*
   2993      * Find who's first.
   2994      */
   2995     if (node1 == node2->prev)
   2996 	return(1);
   2997     if (node1 == node2->next)
   2998 	return(-1);
   2999     /*
   3000      * Speedup using document order if availble.
   3001      */
   3002     if ((node1->type == XML_ELEMENT_NODE) &&
   3003 	(node2->type == XML_ELEMENT_NODE) &&
   3004 	(0 > (long) node1->content) &&
   3005 	(0 > (long) node2->content) &&
   3006 	(node1->doc == node2->doc)) {
   3007 	long l1, l2;
   3008 
   3009 	l1 = -((long) node1->content);
   3010 	l2 = -((long) node2->content);
   3011 	if (l1 < l2)
   3012 	    return(1);
   3013 	if (l1 > l2)
   3014 	    return(-1);
   3015     }
   3016 
   3017     for (cur = node1->next;cur != NULL;cur = cur->next)
   3018 	if (cur == node2)
   3019 	    return(1);
   3020     return(-1); /* assume there is no sibling list corruption */
   3021 }
   3022 
   3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3024 /**
   3025  * xmlXPathCmpNodesExt:
   3026  * @node1:  the first node
   3027  * @node2:  the second node
   3028  *
   3029  * Compare two nodes w.r.t document order.
   3030  * This one is optimized for handling of non-element nodes.
   3031  *
   3032  * Returns -2 in case of error 1 if first point < second point, 0 if
   3033  *         it's the same node, -1 otherwise
   3034  */
   3035 static int
   3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
   3037     int depth1, depth2;
   3038     int misc = 0, precedence1 = 0, precedence2 = 0;
   3039     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
   3040     xmlNodePtr cur, root;
   3041     long l1, l2;
   3042 
   3043     if ((node1 == NULL) || (node2 == NULL))
   3044 	return(-2);
   3045 
   3046     if (node1 == node2)
   3047 	return(0);
   3048 
   3049     /*
   3050      * a couple of optimizations which will avoid computations in most cases
   3051      */
   3052     switch (node1->type) {
   3053 	case XML_ELEMENT_NODE:
   3054 	    if (node2->type == XML_ELEMENT_NODE) {
   3055 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
   3056 		    (0 > (long) node2->content) &&
   3057 		    (node1->doc == node2->doc))
   3058 		{
   3059 		    l1 = -((long) node1->content);
   3060 		    l2 = -((long) node2->content);
   3061 		    if (l1 < l2)
   3062 			return(1);
   3063 		    if (l1 > l2)
   3064 			return(-1);
   3065 		} else
   3066 		    goto turtle_comparison;
   3067 	    }
   3068 	    break;
   3069 	case XML_ATTRIBUTE_NODE:
   3070 	    precedence1 = 1; /* element is owner */
   3071 	    miscNode1 = node1;
   3072 	    node1 = node1->parent;
   3073 	    misc = 1;
   3074 	    break;
   3075 	case XML_TEXT_NODE:
   3076 	case XML_CDATA_SECTION_NODE:
   3077 	case XML_COMMENT_NODE:
   3078 	case XML_PI_NODE: {
   3079 	    miscNode1 = node1;
   3080 	    /*
   3081 	    * Find nearest element node.
   3082 	    */
   3083 	    if (node1->prev != NULL) {
   3084 		do {
   3085 		    node1 = node1->prev;
   3086 		    if (node1->type == XML_ELEMENT_NODE) {
   3087 			precedence1 = 3; /* element in prev-sibl axis */
   3088 			break;
   3089 		    }
   3090 		    if (node1->prev == NULL) {
   3091 			precedence1 = 2; /* element is parent */
   3092 			/*
   3093 			* URGENT TODO: Are there any cases, where the
   3094 			* parent of such a node is not an element node?
   3095 			*/
   3096 			node1 = node1->parent;
   3097 			break;
   3098 		    }
   3099 		} while (1);
   3100 	    } else {
   3101 		precedence1 = 2; /* element is parent */
   3102 		node1 = node1->parent;
   3103 	    }
   3104 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
   3105 		(0 <= (long) node1->content)) {
   3106 		/*
   3107 		* Fallback for whatever case.
   3108 		*/
   3109 		node1 = miscNode1;
   3110 		precedence1 = 0;
   3111 	    } else
   3112 		misc = 1;
   3113 	}
   3114 	    break;
   3115 	case XML_NAMESPACE_DECL:
   3116 	    /*
   3117 	    * TODO: why do we return 1 for namespace nodes?
   3118 	    */
   3119 	    return(1);
   3120 	default:
   3121 	    break;
   3122     }
   3123     switch (node2->type) {
   3124 	case XML_ELEMENT_NODE:
   3125 	    break;
   3126 	case XML_ATTRIBUTE_NODE:
   3127 	    precedence2 = 1; /* element is owner */
   3128 	    miscNode2 = node2;
   3129 	    node2 = node2->parent;
   3130 	    misc = 1;
   3131 	    break;
   3132 	case XML_TEXT_NODE:
   3133 	case XML_CDATA_SECTION_NODE:
   3134 	case XML_COMMENT_NODE:
   3135 	case XML_PI_NODE: {
   3136 	    miscNode2 = node2;
   3137 	    if (node2->prev != NULL) {
   3138 		do {
   3139 		    node2 = node2->prev;
   3140 		    if (node2->type == XML_ELEMENT_NODE) {
   3141 			precedence2 = 3; /* element in prev-sibl axis */
   3142 			break;
   3143 		    }
   3144 		    if (node2->prev == NULL) {
   3145 			precedence2 = 2; /* element is parent */
   3146 			node2 = node2->parent;
   3147 			break;
   3148 		    }
   3149 		} while (1);
   3150 	    } else {
   3151 		precedence2 = 2; /* element is parent */
   3152 		node2 = node2->parent;
   3153 	    }
   3154 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
   3155 		(0 <= (long) node1->content))
   3156 	    {
   3157 		node2 = miscNode2;
   3158 		precedence2 = 0;
   3159 	    } else
   3160 		misc = 1;
   3161 	}
   3162 	    break;
   3163 	case XML_NAMESPACE_DECL:
   3164 	    return(1);
   3165 	default:
   3166 	    break;
   3167     }
   3168     if (misc) {
   3169 	if (node1 == node2) {
   3170 	    if (precedence1 == precedence2) {
   3171 		/*
   3172 		* The ugly case; but normally there aren't many
   3173 		* adjacent non-element nodes around.
   3174 		*/
   3175 		cur = miscNode2->prev;
   3176 		while (cur != NULL) {
   3177 		    if (cur == miscNode1)
   3178 			return(1);
   3179 		    if (cur->type == XML_ELEMENT_NODE)
   3180 			return(-1);
   3181 		    cur = cur->prev;
   3182 		}
   3183 		return (-1);
   3184 	    } else {
   3185 		/*
   3186 		* Evaluate based on higher precedence wrt to the element.
   3187 		* TODO: This assumes attributes are sorted before content.
   3188 		*   Is this 100% correct?
   3189 		*/
   3190 		if (precedence1 < precedence2)
   3191 		    return(1);
   3192 		else
   3193 		    return(-1);
   3194 	    }
   3195 	}
   3196 	/*
   3197 	* Special case: One of the helper-elements is contained by the other.
   3198 	* <foo>
   3199 	*   <node2>
   3200 	*     <node1>Text-1(precedence1 == 2)</node1>
   3201 	*   </node2>
   3202 	*   Text-6(precedence2 == 3)
   3203 	* </foo>
   3204 	*/
   3205 	if ((precedence2 == 3) && (precedence1 > 1)) {
   3206 	    cur = node1->parent;
   3207 	    while (cur) {
   3208 		if (cur == node2)
   3209 		    return(1);
   3210 		cur = cur->parent;
   3211 	    }
   3212 	}
   3213 	if ((precedence1 == 3) && (precedence2 > 1)) {
   3214 	    cur = node2->parent;
   3215 	    while (cur) {
   3216 		if (cur == node1)
   3217 		    return(-1);
   3218 		cur = cur->parent;
   3219 	    }
   3220 	}
   3221     }
   3222 
   3223     /*
   3224      * Speedup using document order if availble.
   3225      */
   3226     if ((node1->type == XML_ELEMENT_NODE) &&
   3227 	(node2->type == XML_ELEMENT_NODE) &&
   3228 	(0 > (long) node1->content) &&
   3229 	(0 > (long) node2->content) &&
   3230 	(node1->doc == node2->doc)) {
   3231 
   3232 	l1 = -((long) node1->content);
   3233 	l2 = -((long) node2->content);
   3234 	if (l1 < l2)
   3235 	    return(1);
   3236 	if (l1 > l2)
   3237 	    return(-1);
   3238     }
   3239 
   3240 turtle_comparison:
   3241 
   3242     if (node1 == node2->prev)
   3243 	return(1);
   3244     if (node1 == node2->next)
   3245 	return(-1);
   3246     /*
   3247      * compute depth to root
   3248      */
   3249     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3250 	if (cur == node1)
   3251 	    return(1);
   3252 	depth2++;
   3253     }
   3254     root = cur;
   3255     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3256 	if (cur == node2)
   3257 	    return(-1);
   3258 	depth1++;
   3259     }
   3260     /*
   3261      * Distinct document (or distinct entities :-( ) case.
   3262      */
   3263     if (root != cur) {
   3264 	return(-2);
   3265     }
   3266     /*
   3267      * get the nearest common ancestor.
   3268      */
   3269     while (depth1 > depth2) {
   3270 	depth1--;
   3271 	node1 = node1->parent;
   3272     }
   3273     while (depth2 > depth1) {
   3274 	depth2--;
   3275 	node2 = node2->parent;
   3276     }
   3277     while (node1->parent != node2->parent) {
   3278 	node1 = node1->parent;
   3279 	node2 = node2->parent;
   3280 	/* should not happen but just in case ... */
   3281 	if ((node1 == NULL) || (node2 == NULL))
   3282 	    return(-2);
   3283     }
   3284     /*
   3285      * Find who's first.
   3286      */
   3287     if (node1 == node2->prev)
   3288 	return(1);
   3289     if (node1 == node2->next)
   3290 	return(-1);
   3291     /*
   3292      * Speedup using document order if availble.
   3293      */
   3294     if ((node1->type == XML_ELEMENT_NODE) &&
   3295 	(node2->type == XML_ELEMENT_NODE) &&
   3296 	(0 > (long) node1->content) &&
   3297 	(0 > (long) node2->content) &&
   3298 	(node1->doc == node2->doc)) {
   3299 
   3300 	l1 = -((long) node1->content);
   3301 	l2 = -((long) node2->content);
   3302 	if (l1 < l2)
   3303 	    return(1);
   3304 	if (l1 > l2)
   3305 	    return(-1);
   3306     }
   3307 
   3308     for (cur = node1->next;cur != NULL;cur = cur->next)
   3309 	if (cur == node2)
   3310 	    return(1);
   3311     return(-1); /* assume there is no sibling list corruption */
   3312 }
   3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
   3314 
   3315 /**
   3316  * xmlXPathNodeSetSort:
   3317  * @set:  the node set
   3318  *
   3319  * Sort the node set in document order
   3320  */
   3321 void
   3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3323     int i, j, incr, len;
   3324     xmlNodePtr tmp;
   3325 
   3326     if (set == NULL)
   3327 	return;
   3328 
   3329     /* Use Shell's sort to sort the node-set */
   3330     len = set->nodeNr;
   3331     for (incr = len / 2; incr > 0; incr /= 2) {
   3332 	for (i = incr; i < len; i++) {
   3333 	    j = i - incr;
   3334 	    while (j >= 0) {
   3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3336 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3337 			set->nodeTab[j + incr]) == -1)
   3338 #else
   3339 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3340 			set->nodeTab[j + incr]) == -1)
   3341 #endif
   3342 		{
   3343 		    tmp = set->nodeTab[j];
   3344 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3345 		    set->nodeTab[j + incr] = tmp;
   3346 		    j -= incr;
   3347 		} else
   3348 		    break;
   3349 	    }
   3350 	}
   3351     }
   3352 }
   3353 
   3354 #define XML_NODESET_DEFAULT	10
   3355 /**
   3356  * xmlXPathNodeSetDupNs:
   3357  * @node:  the parent node of the namespace XPath node
   3358  * @ns:  the libxml namespace declaration node.
   3359  *
   3360  * Namespace node in libxml don't match the XPath semantic. In a node set
   3361  * the namespace nodes are duplicated and the next pointer is set to the
   3362  * parent node in the XPath semantic.
   3363  *
   3364  * Returns the newly created object.
   3365  */
   3366 static xmlNodePtr
   3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3368     xmlNsPtr cur;
   3369 
   3370     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3371 	return(NULL);
   3372     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3373 	return((xmlNodePtr) ns);
   3374 
   3375     /*
   3376      * Allocate a new Namespace and fill the fields.
   3377      */
   3378     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3379     if (cur == NULL) {
   3380         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3381 	return(NULL);
   3382     }
   3383     memset(cur, 0, sizeof(xmlNs));
   3384     cur->type = XML_NAMESPACE_DECL;
   3385     if (ns->href != NULL)
   3386 	cur->href = xmlStrdup(ns->href);
   3387     if (ns->prefix != NULL)
   3388 	cur->prefix = xmlStrdup(ns->prefix);
   3389     cur->next = (xmlNsPtr) node;
   3390     return((xmlNodePtr) cur);
   3391 }
   3392 
   3393 /**
   3394  * xmlXPathNodeSetFreeNs:
   3395  * @ns:  the XPath namespace node found in a nodeset.
   3396  *
   3397  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3398  * the namespace nodes are duplicated and the next pointer is set to the
   3399  * parent node in the XPath semantic. Check if such a node needs to be freed
   3400  */
   3401 void
   3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3403     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3404 	return;
   3405 
   3406     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3407 	if (ns->href != NULL)
   3408 	    xmlFree((xmlChar *)ns->href);
   3409 	if (ns->prefix != NULL)
   3410 	    xmlFree((xmlChar *)ns->prefix);
   3411 	xmlFree(ns);
   3412     }
   3413 }
   3414 
   3415 /**
   3416  * xmlXPathNodeSetCreate:
   3417  * @val:  an initial xmlNodePtr, or NULL
   3418  *
   3419  * Create a new xmlNodeSetPtr of type double and of value @val
   3420  *
   3421  * Returns the newly created object.
   3422  */
   3423 xmlNodeSetPtr
   3424 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3425     xmlNodeSetPtr ret;
   3426 
   3427     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3428     if (ret == NULL) {
   3429         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3430 	return(NULL);
   3431     }
   3432     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3433     if (val != NULL) {
   3434         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3435 					     sizeof(xmlNodePtr));
   3436 	if (ret->nodeTab == NULL) {
   3437 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3438 	    xmlFree(ret);
   3439 	    return(NULL);
   3440 	}
   3441 	memset(ret->nodeTab, 0 ,
   3442 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3443         ret->nodeMax = XML_NODESET_DEFAULT;
   3444 	if (val->type == XML_NAMESPACE_DECL) {
   3445 	    xmlNsPtr ns = (xmlNsPtr) val;
   3446 
   3447 	    ret->nodeTab[ret->nodeNr++] =
   3448 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3449 	} else
   3450 	    ret->nodeTab[ret->nodeNr++] = val;
   3451     }
   3452     return(ret);
   3453 }
   3454 
   3455 /**
   3456  * xmlXPathNodeSetCreateSize:
   3457  * @size:  the initial size of the set
   3458  *
   3459  * Create a new xmlNodeSetPtr of type double and of value @val
   3460  *
   3461  * Returns the newly created object.
   3462  */
   3463 static xmlNodeSetPtr
   3464 xmlXPathNodeSetCreateSize(int size) {
   3465     xmlNodeSetPtr ret;
   3466 
   3467     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3468     if (ret == NULL) {
   3469         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3470 	return(NULL);
   3471     }
   3472     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3473     if (size < XML_NODESET_DEFAULT)
   3474 	size = XML_NODESET_DEFAULT;
   3475     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3476     if (ret->nodeTab == NULL) {
   3477 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3478 	xmlFree(ret);
   3479 	return(NULL);
   3480     }
   3481     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3482     ret->nodeMax = size;
   3483     return(ret);
   3484 }
   3485 
   3486 /**
   3487  * xmlXPathNodeSetContains:
   3488  * @cur:  the node-set
   3489  * @val:  the node
   3490  *
   3491  * checks whether @cur contains @val
   3492  *
   3493  * Returns true (1) if @cur contains @val, false (0) otherwise
   3494  */
   3495 int
   3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3497     int i;
   3498 
   3499     if ((cur == NULL) || (val == NULL)) return(0);
   3500     if (val->type == XML_NAMESPACE_DECL) {
   3501 	for (i = 0; i < cur->nodeNr; i++) {
   3502 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3503 		xmlNsPtr ns1, ns2;
   3504 
   3505 		ns1 = (xmlNsPtr) val;
   3506 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3507 		if (ns1 == ns2)
   3508 		    return(1);
   3509 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3510 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3511 		    return(1);
   3512 	    }
   3513 	}
   3514     } else {
   3515 	for (i = 0; i < cur->nodeNr; i++) {
   3516 	    if (cur->nodeTab[i] == val)
   3517 		return(1);
   3518 	}
   3519     }
   3520     return(0);
   3521 }
   3522 
   3523 /**
   3524  * xmlXPathNodeSetAddNs:
   3525  * @cur:  the initial node set
   3526  * @node:  the hosting node
   3527  * @ns:  a the namespace node
   3528  *
   3529  * add a new namespace node to an existing NodeSet
   3530  */
   3531 void
   3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3533     int i;
   3534 
   3535 
   3536     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3537         (ns->type != XML_NAMESPACE_DECL) ||
   3538 	(node->type != XML_ELEMENT_NODE))
   3539 	return;
   3540 
   3541     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3542     /*
   3543      * prevent duplicates
   3544      */
   3545     for (i = 0;i < cur->nodeNr;i++) {
   3546         if ((cur->nodeTab[i] != NULL) &&
   3547 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3548 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3549 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3550 	    return;
   3551     }
   3552 
   3553     /*
   3554      * grow the nodeTab if needed
   3555      */
   3556     if (cur->nodeMax == 0) {
   3557         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3558 					     sizeof(xmlNodePtr));
   3559 	if (cur->nodeTab == NULL) {
   3560 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3561 	    return;
   3562 	}
   3563 	memset(cur->nodeTab, 0 ,
   3564 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3565         cur->nodeMax = XML_NODESET_DEFAULT;
   3566     } else if (cur->nodeNr == cur->nodeMax) {
   3567         xmlNodePtr *temp;
   3568 
   3569 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3570 				      sizeof(xmlNodePtr));
   3571 	if (temp == NULL) {
   3572 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3573 	    return;
   3574 	}
   3575         cur->nodeMax *= 2;
   3576 	cur->nodeTab = temp;
   3577     }
   3578     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3579 }
   3580 
   3581 /**
   3582  * xmlXPathNodeSetAdd:
   3583  * @cur:  the initial node set
   3584  * @val:  a new xmlNodePtr
   3585  *
   3586  * add a new xmlNodePtr to an existing NodeSet
   3587  */
   3588 void
   3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3590     int i;
   3591 
   3592     if ((cur == NULL) || (val == NULL)) return;
   3593 
   3594 #if 0
   3595     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3596 	return;	/* an XSLT fake node */
   3597 #endif
   3598 
   3599     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3600     /*
   3601      * prevent duplcates
   3602      */
   3603     for (i = 0;i < cur->nodeNr;i++)
   3604         if (cur->nodeTab[i] == val) return;
   3605 
   3606     /*
   3607      * grow the nodeTab if needed
   3608      */
   3609     if (cur->nodeMax == 0) {
   3610         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3611 					     sizeof(xmlNodePtr));
   3612 	if (cur->nodeTab == NULL) {
   3613 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3614 	    return;
   3615 	}
   3616 	memset(cur->nodeTab, 0 ,
   3617 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3618         cur->nodeMax = XML_NODESET_DEFAULT;
   3619     } else if (cur->nodeNr == cur->nodeMax) {
   3620         xmlNodePtr *temp;
   3621 
   3622 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3623 				      sizeof(xmlNodePtr));
   3624 	if (temp == NULL) {
   3625 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3626 	    return;
   3627 	}
   3628         cur->nodeMax *= 2;
   3629 	cur->nodeTab = temp;
   3630     }
   3631     if (val->type == XML_NAMESPACE_DECL) {
   3632 	xmlNsPtr ns = (xmlNsPtr) val;
   3633 
   3634 	cur->nodeTab[cur->nodeNr++] =
   3635 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3636     } else
   3637 	cur->nodeTab[cur->nodeNr++] = val;
   3638 }
   3639 
   3640 /**
   3641  * xmlXPathNodeSetAddUnique:
   3642  * @cur:  the initial node set
   3643  * @val:  a new xmlNodePtr
   3644  *
   3645  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3646  * when we are sure the node is not already in the set.
   3647  */
   3648 void
   3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3650     if ((cur == NULL) || (val == NULL)) return;
   3651 
   3652 #if 0
   3653     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
   3654 	return;	/* an XSLT fake node */
   3655 #endif
   3656 
   3657     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3658     /*
   3659      * grow the nodeTab if needed
   3660      */
   3661     if (cur->nodeMax == 0) {
   3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3663 					     sizeof(xmlNodePtr));
   3664 	if (cur->nodeTab == NULL) {
   3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3666 	    return;
   3667 	}
   3668 	memset(cur->nodeTab, 0 ,
   3669 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3670         cur->nodeMax = XML_NODESET_DEFAULT;
   3671     } else if (cur->nodeNr == cur->nodeMax) {
   3672         xmlNodePtr *temp;
   3673 
   3674 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3675 				      sizeof(xmlNodePtr));
   3676 	if (temp == NULL) {
   3677 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3678 	    return;
   3679 	}
   3680 	cur->nodeTab = temp;
   3681         cur->nodeMax *= 2;
   3682     }
   3683     if (val->type == XML_NAMESPACE_DECL) {
   3684 	xmlNsPtr ns = (xmlNsPtr) val;
   3685 
   3686 	cur->nodeTab[cur->nodeNr++] =
   3687 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3688     } else
   3689 	cur->nodeTab[cur->nodeNr++] = val;
   3690 }
   3691 
   3692 /**
   3693  * xmlXPathNodeSetMerge:
   3694  * @val1:  the first NodeSet or NULL
   3695  * @val2:  the second NodeSet
   3696  *
   3697  * Merges two nodesets, all nodes from @val2 are added to @val1
   3698  * if @val1 is NULL, a new set is created and copied from @val2
   3699  *
   3700  * Returns @val1 once extended or NULL in case of error.
   3701  */
   3702 xmlNodeSetPtr
   3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3704     int i, j, initNr, skip;
   3705     xmlNodePtr n1, n2;
   3706 
   3707     if (val2 == NULL) return(val1);
   3708     if (val1 == NULL) {
   3709 	val1 = xmlXPathNodeSetCreate(NULL);
   3710     if (val1 == NULL)
   3711         return (NULL);
   3712 #if 0
   3713 	/*
   3714 	* TODO: The optimization won't work in every case, since
   3715 	*  those nasty namespace nodes need to be added with
   3716 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3717 	*  memcpy is not possible.
   3718 	*  If there was a flag on the nodesetval, indicating that
   3719 	*  some temporary nodes are in, that would be helpfull.
   3720 	*/
   3721 	/*
   3722 	* Optimization: Create an equally sized node-set
   3723 	* and memcpy the content.
   3724 	*/
   3725 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3726 	if (val1 == NULL)
   3727 	    return(NULL);
   3728 	if (val2->nodeNr != 0) {
   3729 	    if (val2->nodeNr == 1)
   3730 		*(val1->nodeTab) = *(val2->nodeTab);
   3731 	    else {
   3732 		memcpy(val1->nodeTab, val2->nodeTab,
   3733 		    val2->nodeNr * sizeof(xmlNodePtr));
   3734 	    }
   3735 	    val1->nodeNr = val2->nodeNr;
   3736 	}
   3737 	return(val1);
   3738 #endif
   3739     }
   3740 
   3741     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3742     initNr = val1->nodeNr;
   3743 
   3744     for (i = 0;i < val2->nodeNr;i++) {
   3745 	n2 = val2->nodeTab[i];
   3746 	/*
   3747 	 * check against duplicates
   3748 	 */
   3749 	skip = 0;
   3750 	for (j = 0; j < initNr; j++) {
   3751 	    n1 = val1->nodeTab[j];
   3752 	    if (n1 == n2) {
   3753 		skip = 1;
   3754 		break;
   3755 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3756 		       (n2->type == XML_NAMESPACE_DECL)) {
   3757 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3758 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3759 			((xmlNsPtr) n2)->prefix)))
   3760 		{
   3761 		    skip = 1;
   3762 		    break;
   3763 		}
   3764 	    }
   3765 	}
   3766 	if (skip)
   3767 	    continue;
   3768 
   3769 	/*
   3770 	 * grow the nodeTab if needed
   3771 	 */
   3772 	if (val1->nodeMax == 0) {
   3773 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3774 						    sizeof(xmlNodePtr));
   3775 	    if (val1->nodeTab == NULL) {
   3776 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3777 		return(NULL);
   3778 	    }
   3779 	    memset(val1->nodeTab, 0 ,
   3780 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3781 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3782 	} else if (val1->nodeNr == val1->nodeMax) {
   3783 	    xmlNodePtr *temp;
   3784 
   3785 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3786 					     sizeof(xmlNodePtr));
   3787 	    if (temp == NULL) {
   3788 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3789 		return(NULL);
   3790 	    }
   3791 	    val1->nodeTab = temp;
   3792 	    val1->nodeMax *= 2;
   3793 	}
   3794 	if (n2->type == XML_NAMESPACE_DECL) {
   3795 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3796 
   3797 	    val1->nodeTab[val1->nodeNr++] =
   3798 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3799 	} else
   3800 	    val1->nodeTab[val1->nodeNr++] = n2;
   3801     }
   3802 
   3803     return(val1);
   3804 }
   3805 
   3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3807 /**
   3808  * xmlXPathNodeSetMergeUnique:
   3809  * @val1:  the first NodeSet or NULL
   3810  * @val2:  the second NodeSet
   3811  *
   3812  * Merges two nodesets, all nodes from @val2 are added to @val1
   3813  * if @val1 is NULL, a new set is created and copied from @val2
   3814  *
   3815  * Returns @val1 once extended or NULL in case of error.
   3816  */
   3817 static xmlNodeSetPtr
   3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3819     int i;
   3820 
   3821     if (val2 == NULL) return(val1);
   3822     if (val1 == NULL) {
   3823 	val1 = xmlXPathNodeSetCreate(NULL);
   3824     }
   3825     if (val1 == NULL)
   3826         return (NULL);
   3827 
   3828     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3829 
   3830     for (i = 0;i < val2->nodeNr;i++) {
   3831 	/*
   3832 	 * grow the nodeTab if needed
   3833 	 */
   3834 	if (val1->nodeMax == 0) {
   3835 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3836 						    sizeof(xmlNodePtr));
   3837 	    if (val1->nodeTab == NULL) {
   3838 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3839 		return(NULL);
   3840 	    }
   3841 	    memset(val1->nodeTab, 0 ,
   3842 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3843 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3844 	} else if (val1->nodeNr == val1->nodeMax) {
   3845 	    xmlNodePtr *temp;
   3846 
   3847 	    val1->nodeMax *= 2;
   3848 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
   3849 					     sizeof(xmlNodePtr));
   3850 	    if (temp == NULL) {
   3851 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3852 		return(NULL);
   3853 	    }
   3854 	    val1->nodeTab = temp;
   3855 	}
   3856 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3857 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
   3858 
   3859 	    val1->nodeTab[val1->nodeNr++] =
   3860 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3861 	} else
   3862 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
   3863     }
   3864 
   3865     return(val1);
   3866 }
   3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
   3868 
   3869 /**
   3870  * xmlXPathNodeSetMergeAndClear:
   3871  * @set1:  the first NodeSet or NULL
   3872  * @set2:  the second NodeSet
   3873  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3874  *
   3875  * Merges two nodesets, all nodes from @set2 are added to @set1
   3876  * if @set1 is NULL, a new set is created and copied from @set2.
   3877  * Checks for duplicate nodes. Clears set2.
   3878  *
   3879  * Returns @set1 once extended or NULL in case of error.
   3880  */
   3881 static xmlNodeSetPtr
   3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3883 			     int hasNullEntries)
   3884 {
   3885     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3886 	/*
   3887 	* Note that doing a memcpy of the list, namespace nodes are
   3888 	* just assigned to set1, since set2 is cleared anyway.
   3889 	*/
   3890 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3891 	if (set1 == NULL)
   3892 	    return(NULL);
   3893 	if (set2->nodeNr != 0) {
   3894 	    memcpy(set1->nodeTab, set2->nodeTab,
   3895 		set2->nodeNr * sizeof(xmlNodePtr));
   3896 	    set1->nodeNr = set2->nodeNr;
   3897 	}
   3898     } else {
   3899 	int i, j, initNbSet1;
   3900 	xmlNodePtr n1, n2;
   3901 
   3902 	if (set1 == NULL)
   3903             set1 = xmlXPathNodeSetCreate(NULL);
   3904         if (set1 == NULL)
   3905             return (NULL);
   3906 
   3907 	initNbSet1 = set1->nodeNr;
   3908 	for (i = 0;i < set2->nodeNr;i++) {
   3909 	    n2 = set2->nodeTab[i];
   3910 	    /*
   3911 	    * Skip NULLed entries.
   3912 	    */
   3913 	    if (n2 == NULL)
   3914 		continue;
   3915 	    /*
   3916 	    * Skip duplicates.
   3917 	    */
   3918 	    for (j = 0; j < initNbSet1; j++) {
   3919 		n1 = set1->nodeTab[j];
   3920 		if (n1 == n2) {
   3921 		    goto skip_node;
   3922 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3923 		    (n2->type == XML_NAMESPACE_DECL))
   3924 		{
   3925 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3926 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3927 			((xmlNsPtr) n2)->prefix)))
   3928 		    {
   3929 			/*
   3930 			* Free the namespace node.
   3931 			*/
   3932 			set2->nodeTab[i] = NULL;
   3933 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3934 			goto skip_node;
   3935 		    }
   3936 		}
   3937 	    }
   3938 	    /*
   3939 	    * grow the nodeTab if needed
   3940 	    */
   3941 	    if (set1->nodeMax == 0) {
   3942 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3943 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   3944 		if (set1->nodeTab == NULL) {
   3945 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3946 		    return(NULL);
   3947 		}
   3948 		memset(set1->nodeTab, 0,
   3949 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3950 		set1->nodeMax = XML_NODESET_DEFAULT;
   3951 	    } else if (set1->nodeNr >= set1->nodeMax) {
   3952 		xmlNodePtr *temp;
   3953 
   3954 		temp = (xmlNodePtr *) xmlRealloc(
   3955 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   3956 		if (temp == NULL) {
   3957 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   3958 		    return(NULL);
   3959 		}
   3960 		set1->nodeTab = temp;
   3961 		set1->nodeMax *= 2;
   3962 	    }
   3963 	    if (n2->type == XML_NAMESPACE_DECL) {
   3964 		xmlNsPtr ns = (xmlNsPtr) n2;
   3965 
   3966 		set1->nodeTab[set1->nodeNr++] =
   3967 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3968 	    } else
   3969 		set1->nodeTab[set1->nodeNr++] = n2;
   3970 skip_node:
   3971 	    {}
   3972 	}
   3973     }
   3974     set2->nodeNr = 0;
   3975     return(set1);
   3976 }
   3977 
   3978 /**
   3979  * xmlXPathNodeSetMergeAndClearNoDupls:
   3980  * @set1:  the first NodeSet or NULL
   3981  * @set2:  the second NodeSet
   3982  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3983  *
   3984  * Merges two nodesets, all nodes from @set2 are added to @set1
   3985  * if @set1 is NULL, a new set is created and copied from @set2.
   3986  * Doesn't chack for duplicate nodes. Clears set2.
   3987  *
   3988  * Returns @set1 once extended or NULL in case of error.
   3989  */
   3990 static xmlNodeSetPtr
   3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3992 				    int hasNullEntries)
   3993 {
   3994     if (set2 == NULL)
   3995 	return(set1);
   3996     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3997 	/*
   3998 	* Note that doing a memcpy of the list, namespace nodes are
   3999 	* just assigned to set1, since set2 is cleared anyway.
   4000 	*/
   4001 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4002 	if (set1 == NULL)
   4003 	    return(NULL);
   4004 	if (set2->nodeNr != 0) {
   4005 	    memcpy(set1->nodeTab, set2->nodeTab,
   4006 		set2->nodeNr * sizeof(xmlNodePtr));
   4007 	    set1->nodeNr = set2->nodeNr;
   4008 	}
   4009     } else {
   4010 	int i;
   4011 	xmlNodePtr n2;
   4012 
   4013 	if (set1 == NULL)
   4014 	    set1 = xmlXPathNodeSetCreate(NULL);
   4015         if (set1 == NULL)
   4016             return (NULL);
   4017 
   4018 	for (i = 0;i < set2->nodeNr;i++) {
   4019 	    n2 = set2->nodeTab[i];
   4020 	    /*
   4021 	    * Skip NULLed entries.
   4022 	    */
   4023 	    if (n2 == NULL)
   4024 		continue;
   4025 	    if (set1->nodeMax == 0) {
   4026 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4027 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4028 		if (set1->nodeTab == NULL) {
   4029 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4030 		    return(NULL);
   4031 		}
   4032 		memset(set1->nodeTab, 0,
   4033 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4034 		set1->nodeMax = XML_NODESET_DEFAULT;
   4035 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4036 		xmlNodePtr *temp;
   4037 
   4038 		temp = (xmlNodePtr *) xmlRealloc(
   4039 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4040 		if (temp == NULL) {
   4041 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4042 		    return(NULL);
   4043 		}
   4044 		set1->nodeTab = temp;
   4045 		set1->nodeMax *= 2;
   4046 	    }
   4047 	    set1->nodeTab[set1->nodeNr++] = n2;
   4048 	}
   4049     }
   4050     set2->nodeNr = 0;
   4051     return(set1);
   4052 }
   4053 
   4054 /**
   4055  * xmlXPathNodeSetDel:
   4056  * @cur:  the initial node set
   4057  * @val:  an xmlNodePtr
   4058  *
   4059  * Removes an xmlNodePtr from an existing NodeSet
   4060  */
   4061 void
   4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4063     int i;
   4064 
   4065     if (cur == NULL) return;
   4066     if (val == NULL) return;
   4067 
   4068     /*
   4069      * find node in nodeTab
   4070      */
   4071     for (i = 0;i < cur->nodeNr;i++)
   4072         if (cur->nodeTab[i] == val) break;
   4073 
   4074     if (i >= cur->nodeNr) {	/* not found */
   4075 #ifdef DEBUG
   4076         xmlGenericError(xmlGenericErrorContext,
   4077 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4078 		val->name);
   4079 #endif
   4080         return;
   4081     }
   4082     if ((cur->nodeTab[i] != NULL) &&
   4083 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4084 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4085     cur->nodeNr--;
   4086     for (;i < cur->nodeNr;i++)
   4087         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4088     cur->nodeTab[cur->nodeNr] = NULL;
   4089 }
   4090 
   4091 /**
   4092  * xmlXPathNodeSetRemove:
   4093  * @cur:  the initial node set
   4094  * @val:  the index to remove
   4095  *
   4096  * Removes an entry from an existing NodeSet list.
   4097  */
   4098 void
   4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4100     if (cur == NULL) return;
   4101     if (val >= cur->nodeNr) return;
   4102     if ((cur->nodeTab[val] != NULL) &&
   4103 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4104 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4105     cur->nodeNr--;
   4106     for (;val < cur->nodeNr;val++)
   4107         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4108     cur->nodeTab[cur->nodeNr] = NULL;
   4109 }
   4110 
   4111 /**
   4112  * xmlXPathFreeNodeSet:
   4113  * @obj:  the xmlNodeSetPtr to free
   4114  *
   4115  * Free the NodeSet compound (not the actual nodes !).
   4116  */
   4117 void
   4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4119     if (obj == NULL) return;
   4120     if (obj->nodeTab != NULL) {
   4121 	int i;
   4122 
   4123 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4124 	for (i = 0;i < obj->nodeNr;i++)
   4125 	    if ((obj->nodeTab[i] != NULL) &&
   4126 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4127 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4128 	xmlFree(obj->nodeTab);
   4129     }
   4130     xmlFree(obj);
   4131 }
   4132 
   4133 /**
   4134  * xmlXPathNodeSetClear:
   4135  * @set:  the node set to clear
   4136  *
   4137  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4138  * are feed), but does *not* free the list itself. Sets the length of the
   4139  * list to 0.
   4140  */
   4141 static void
   4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4143 {
   4144     if ((set == NULL) || (set->nodeNr <= 0))
   4145 	return;
   4146     else if (hasNsNodes) {
   4147 	int i;
   4148 	xmlNodePtr node;
   4149 
   4150 	for (i = 0; i < set->nodeNr; i++) {
   4151 	    node = set->nodeTab[i];
   4152 	    if ((node != NULL) &&
   4153 		(node->type == XML_NAMESPACE_DECL))
   4154 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4155 	}
   4156     }
   4157     set->nodeNr = 0;
   4158 }
   4159 
   4160 /**
   4161  * xmlXPathNodeSetClearFromPos:
   4162  * @set: the node set to be cleared
   4163  * @pos: the start position to clear from
   4164  *
   4165  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4166  * are feed) starting with the entry at @pos, but does *not* free the list
   4167  * itself. Sets the length of the list to @pos.
   4168  */
   4169 static void
   4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4171 {
   4172     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4173 	return;
   4174     else if ((hasNsNodes)) {
   4175 	int i;
   4176 	xmlNodePtr node;
   4177 
   4178 	for (i = pos; i < set->nodeNr; i++) {
   4179 	    node = set->nodeTab[i];
   4180 	    if ((node != NULL) &&
   4181 		(node->type == XML_NAMESPACE_DECL))
   4182 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4183 	}
   4184     }
   4185     set->nodeNr = pos;
   4186 }
   4187 
   4188 /**
   4189  * xmlXPathFreeValueTree:
   4190  * @obj:  the xmlNodeSetPtr to free
   4191  *
   4192  * Free the NodeSet compound and the actual tree, this is different
   4193  * from xmlXPathFreeNodeSet()
   4194  */
   4195 static void
   4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4197     int i;
   4198 
   4199     if (obj == NULL) return;
   4200 
   4201     if (obj->nodeTab != NULL) {
   4202 	for (i = 0;i < obj->nodeNr;i++) {
   4203 	    if (obj->nodeTab[i] != NULL) {
   4204 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4205 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4206 		} else {
   4207 		    xmlFreeNodeList(obj->nodeTab[i]);
   4208 		}
   4209 	    }
   4210 	}
   4211 	xmlFree(obj->nodeTab);
   4212     }
   4213     xmlFree(obj);
   4214 }
   4215 
   4216 #if defined(DEBUG) || defined(DEBUG_STEP)
   4217 /**
   4218  * xmlGenericErrorContextNodeSet:
   4219  * @output:  a FILE * for the output
   4220  * @obj:  the xmlNodeSetPtr to display
   4221  *
   4222  * Quick display of a NodeSet
   4223  */
   4224 void
   4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4226     int i;
   4227 
   4228     if (output == NULL) output = xmlGenericErrorContext;
   4229     if (obj == NULL)  {
   4230         fprintf(output, "NodeSet == NULL !\n");
   4231 	return;
   4232     }
   4233     if (obj->nodeNr == 0) {
   4234         fprintf(output, "NodeSet is empty\n");
   4235 	return;
   4236     }
   4237     if (obj->nodeTab == NULL) {
   4238 	fprintf(output, " nodeTab == NULL !\n");
   4239 	return;
   4240     }
   4241     for (i = 0; i < obj->nodeNr; i++) {
   4242         if (obj->nodeTab[i] == NULL) {
   4243 	    fprintf(output, " NULL !\n");
   4244 	    return;
   4245         }
   4246 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4247 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4248 	    fprintf(output, " /");
   4249 	else if (obj->nodeTab[i]->name == NULL)
   4250 	    fprintf(output, " noname!");
   4251 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4252     }
   4253     fprintf(output, "\n");
   4254 }
   4255 #endif
   4256 
   4257 /**
   4258  * xmlXPathNewNodeSet:
   4259  * @val:  the NodePtr value
   4260  *
   4261  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4262  * it with the single Node @val
   4263  *
   4264  * Returns the newly created object.
   4265  */
   4266 xmlXPathObjectPtr
   4267 xmlXPathNewNodeSet(xmlNodePtr val) {
   4268     xmlXPathObjectPtr ret;
   4269 
   4270     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4271     if (ret == NULL) {
   4272         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4273 	return(NULL);
   4274     }
   4275     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4276     ret->type = XPATH_NODESET;
   4277     ret->boolval = 0;
   4278     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4279     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4280 #ifdef XP_DEBUG_OBJ_USAGE
   4281     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4282 #endif
   4283     return(ret);
   4284 }
   4285 
   4286 /**
   4287  * xmlXPathNewValueTree:
   4288  * @val:  the NodePtr value
   4289  *
   4290  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4291  * it with the tree root @val
   4292  *
   4293  * Returns the newly created object.
   4294  */
   4295 xmlXPathObjectPtr
   4296 xmlXPathNewValueTree(xmlNodePtr val) {
   4297     xmlXPathObjectPtr ret;
   4298 
   4299     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4300     if (ret == NULL) {
   4301         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4302 	return(NULL);
   4303     }
   4304     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4305     ret->type = XPATH_XSLT_TREE;
   4306     ret->boolval = 1;
   4307     ret->user = (void *) val;
   4308     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4309 #ifdef XP_DEBUG_OBJ_USAGE
   4310     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4311 #endif
   4312     return(ret);
   4313 }
   4314 
   4315 /**
   4316  * xmlXPathNewNodeSetList:
   4317  * @val:  an existing NodeSet
   4318  *
   4319  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4320  * it with the Nodeset @val
   4321  *
   4322  * Returns the newly created object.
   4323  */
   4324 xmlXPathObjectPtr
   4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4326 {
   4327     xmlXPathObjectPtr ret;
   4328     int i;
   4329 
   4330     if (val == NULL)
   4331         ret = NULL;
   4332     else if (val->nodeTab == NULL)
   4333         ret = xmlXPathNewNodeSet(NULL);
   4334     else {
   4335         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4336         if (ret)
   4337             for (i = 1; i < val->nodeNr; ++i)
   4338                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
   4339     }
   4340 
   4341     return (ret);
   4342 }
   4343 
   4344 /**
   4345  * xmlXPathWrapNodeSet:
   4346  * @val:  the NodePtr value
   4347  *
   4348  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4349  *
   4350  * Returns the newly created object.
   4351  */
   4352 xmlXPathObjectPtr
   4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4354     xmlXPathObjectPtr ret;
   4355 
   4356     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4357     if (ret == NULL) {
   4358         xmlXPathErrMemory(NULL, "creating node set object\n");
   4359 	return(NULL);
   4360     }
   4361     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4362     ret->type = XPATH_NODESET;
   4363     ret->nodesetval = val;
   4364 #ifdef XP_DEBUG_OBJ_USAGE
   4365     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4366 #endif
   4367     return(ret);
   4368 }
   4369 
   4370 /**
   4371  * xmlXPathFreeNodeSetList:
   4372  * @obj:  an existing NodeSetList object
   4373  *
   4374  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4375  * the list contrary to xmlXPathFreeObject().
   4376  */
   4377 void
   4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4379     if (obj == NULL) return;
   4380 #ifdef XP_DEBUG_OBJ_USAGE
   4381     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4382 #endif
   4383     xmlFree(obj);
   4384 }
   4385 
   4386 /**
   4387  * xmlXPathDifference:
   4388  * @nodes1:  a node-set
   4389  * @nodes2:  a node-set
   4390  *
   4391  * Implements the EXSLT - Sets difference() function:
   4392  *    node-set set:difference (node-set, node-set)
   4393  *
   4394  * Returns the difference between the two node sets, or nodes1 if
   4395  *         nodes2 is empty
   4396  */
   4397 xmlNodeSetPtr
   4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4399     xmlNodeSetPtr ret;
   4400     int i, l1;
   4401     xmlNodePtr cur;
   4402 
   4403     if (xmlXPathNodeSetIsEmpty(nodes2))
   4404 	return(nodes1);
   4405 
   4406     ret = xmlXPathNodeSetCreate(NULL);
   4407     if (xmlXPathNodeSetIsEmpty(nodes1))
   4408 	return(ret);
   4409 
   4410     l1 = xmlXPathNodeSetGetLength(nodes1);
   4411 
   4412     for (i = 0; i < l1; i++) {
   4413 	cur = xmlXPathNodeSetItem(nodes1, i);
   4414 	if (!xmlXPathNodeSetContains(nodes2, cur))
   4415 	    xmlXPathNodeSetAddUnique(ret, cur);
   4416     }
   4417     return(ret);
   4418 }
   4419 
   4420 /**
   4421  * xmlXPathIntersection:
   4422  * @nodes1:  a node-set
   4423  * @nodes2:  a node-set
   4424  *
   4425  * Implements the EXSLT - Sets intersection() function:
   4426  *    node-set set:intersection (node-set, node-set)
   4427  *
   4428  * Returns a node set comprising the nodes that are within both the
   4429  *         node sets passed as arguments
   4430  */
   4431 xmlNodeSetPtr
   4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4433     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4434     int i, l1;
   4435     xmlNodePtr cur;
   4436 
   4437     if (ret == NULL)
   4438         return(ret);
   4439     if (xmlXPathNodeSetIsEmpty(nodes1))
   4440 	return(ret);
   4441     if (xmlXPathNodeSetIsEmpty(nodes2))
   4442 	return(ret);
   4443 
   4444     l1 = xmlXPathNodeSetGetLength(nodes1);
   4445 
   4446     for (i = 0; i < l1; i++) {
   4447 	cur = xmlXPathNodeSetItem(nodes1, i);
   4448 	if (xmlXPathNodeSetContains(nodes2, cur))
   4449 	    xmlXPathNodeSetAddUnique(ret, cur);
   4450     }
   4451     return(ret);
   4452 }
   4453 
   4454 /**
   4455  * xmlXPathDistinctSorted:
   4456  * @nodes:  a node-set, sorted by document order
   4457  *
   4458  * Implements the EXSLT - Sets distinct() function:
   4459  *    node-set set:distinct (node-set)
   4460  *
   4461  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4462  *         it is empty
   4463  */
   4464 xmlNodeSetPtr
   4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4466     xmlNodeSetPtr ret;
   4467     xmlHashTablePtr hash;
   4468     int i, l;
   4469     xmlChar * strval;
   4470     xmlNodePtr cur;
   4471 
   4472     if (xmlXPathNodeSetIsEmpty(nodes))
   4473 	return(nodes);
   4474 
   4475     ret = xmlXPathNodeSetCreate(NULL);
   4476     if (ret == NULL)
   4477         return(ret);
   4478     l = xmlXPathNodeSetGetLength(nodes);
   4479     hash = xmlHashCreate (l);
   4480     for (i = 0; i < l; i++) {
   4481 	cur = xmlXPathNodeSetItem(nodes, i);
   4482 	strval = xmlXPathCastNodeToString(cur);
   4483 	if (xmlHashLookup(hash, strval) == NULL) {
   4484 	    xmlHashAddEntry(hash, strval, strval);
   4485 	    xmlXPathNodeSetAddUnique(ret, cur);
   4486 	} else {
   4487 	    xmlFree(strval);
   4488 	}
   4489     }
   4490     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4491     return(ret);
   4492 }
   4493 
   4494 /**
   4495  * xmlXPathDistinct:
   4496  * @nodes:  a node-set
   4497  *
   4498  * Implements the EXSLT - Sets distinct() function:
   4499  *    node-set set:distinct (node-set)
   4500  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4501  * is called with the sorted node-set
   4502  *
   4503  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4504  *         it is empty
   4505  */
   4506 xmlNodeSetPtr
   4507 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4508     if (xmlXPathNodeSetIsEmpty(nodes))
   4509 	return(nodes);
   4510 
   4511     xmlXPathNodeSetSort(nodes);
   4512     return(xmlXPathDistinctSorted(nodes));
   4513 }
   4514 
   4515 /**
   4516  * xmlXPathHasSameNodes:
   4517  * @nodes1:  a node-set
   4518  * @nodes2:  a node-set
   4519  *
   4520  * Implements the EXSLT - Sets has-same-nodes function:
   4521  *    boolean set:has-same-node(node-set, node-set)
   4522  *
   4523  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4524  *         otherwise
   4525  */
   4526 int
   4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4528     int i, l;
   4529     xmlNodePtr cur;
   4530 
   4531     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4532 	xmlXPathNodeSetIsEmpty(nodes2))
   4533 	return(0);
   4534 
   4535     l = xmlXPathNodeSetGetLength(nodes1);
   4536     for (i = 0; i < l; i++) {
   4537 	cur = xmlXPathNodeSetItem(nodes1, i);
   4538 	if (xmlXPathNodeSetContains(nodes2, cur))
   4539 	    return(1);
   4540     }
   4541     return(0);
   4542 }
   4543 
   4544 /**
   4545  * xmlXPathNodeLeadingSorted:
   4546  * @nodes: a node-set, sorted by document order
   4547  * @node: a node