File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xpath.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    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@veillard.com
   14:  *
   15:  */
   16: 
   17: #define IN_LIBXML
   18: #include "libxml.h"
   19: 
   20: #include <string.h>
   21: 
   22: #ifdef HAVE_SYS_TYPES_H
   23: #include <sys/types.h>
   24: #endif
   25: #ifdef HAVE_MATH_H
   26: #include <math.h>
   27: #endif
   28: #ifdef HAVE_FLOAT_H
   29: #include <float.h>
   30: #endif
   31: #ifdef HAVE_CTYPE_H
   32: #include <ctype.h>
   33: #endif
   34: #ifdef HAVE_SIGNAL_H
   35: #include <signal.h>
   36: #endif
   37: 
   38: #include <libxml/xmlmemory.h>
   39: #include <libxml/tree.h>
   40: #include <libxml/valid.h>
   41: #include <libxml/xpath.h>
   42: #include <libxml/xpathInternals.h>
   43: #include <libxml/parserInternals.h>
   44: #include <libxml/hash.h>
   45: #ifdef LIBXML_XPTR_ENABLED
   46: #include <libxml/xpointer.h>
   47: #endif
   48: #ifdef LIBXML_DEBUG_ENABLED
   49: #include <libxml/debugXML.h>
   50: #endif
   51: #include <libxml/xmlerror.h>
   52: #include <libxml/threads.h>
   53: #include <libxml/globals.h>
   54: #ifdef LIBXML_PATTERN_ENABLED
   55: #include <libxml/pattern.h>
   56: #endif
   57: 
   58: #include "buf.h"
   59: 
   60: #ifdef LIBXML_PATTERN_ENABLED
   61: #define XPATH_STREAMING
   62: #endif
   63: 
   64: #define TODO								\
   65:     xmlGenericError(xmlGenericErrorContext,				\
   66: 	    "Unimplemented block at %s:%d\n",				\
   67:             __FILE__, __LINE__);
   68: 
   69: /**
   70:  * WITH_TIM_SORT:
   71:  *
   72:  * Use the Timsort algorithm provided in timsort.h to sort
   73:  * nodeset as this is a great improvement over the old Shell sort
   74:  * used in xmlXPathNodeSetSort()
   75:  */
   76: #define WITH_TIM_SORT
   77: 
   78: /*
   79: * XP_OPTIMIZED_NON_ELEM_COMPARISON:
   80: * If defined, this will use xmlXPathCmpNodesExt() instead of
   81: * xmlXPathCmpNodes(). The new function is optimized comparison of
   82: * non-element nodes; actually it will speed up comparison only if
   83: * xmlXPathOrderDocElems() was called in order to index the elements of
   84: * a tree in document order; Libxslt does such an indexing, thus it will
   85: * benefit from this optimization.
   86: */
   87: #define XP_OPTIMIZED_NON_ELEM_COMPARISON
   88: 
   89: /*
   90: * XP_OPTIMIZED_FILTER_FIRST:
   91: * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
   92: * in a way, that it stop evaluation at the first node.
   93: */
   94: #define XP_OPTIMIZED_FILTER_FIRST
   95: 
   96: /*
   97: * XP_DEBUG_OBJ_USAGE:
   98: * Internal flag to enable tracking of how much XPath objects have been
   99: * created.
  100: */
  101: /* #define XP_DEBUG_OBJ_USAGE */
  102: 
  103: /*
  104:  * XPATH_MAX_STEPS:
  105:  * when compiling an XPath expression we arbitrary limit the maximum
  106:  * number of step operation in the compiled expression. 1000000 is
  107:  * an insanely large value which should never be reached under normal
  108:  * circumstances
  109:  */
  110: #define XPATH_MAX_STEPS 1000000
  111: 
  112: /*
  113:  * XPATH_MAX_STACK_DEPTH:
  114:  * when evaluating an XPath expression we arbitrary limit the maximum
  115:  * number of object allowed to be pushed on the stack. 1000000 is
  116:  * an insanely large value which should never be reached under normal
  117:  * circumstances
  118:  */
  119: #define XPATH_MAX_STACK_DEPTH 1000000
  120: 
  121: /*
  122:  * XPATH_MAX_NODESET_LENGTH:
  123:  * when evaluating an XPath expression nodesets are created and we
  124:  * arbitrary limit the maximum length of those node set. 10000000 is
  125:  * an insanely large value which should never be reached under normal
  126:  * circumstances, one would first need to construct an in memory tree
  127:  * with more than 10 millions nodes.
  128:  */
  129: #define XPATH_MAX_NODESET_LENGTH 10000000
  130: 
  131: /*
  132:  * TODO:
  133:  * There are a few spots where some tests are done which depend upon ascii
  134:  * data.  These should be enhanced for full UTF8 support (see particularly
  135:  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
  136:  */
  137: 
  138: /*
  139:  * Wrapper for the Timsort argorithm from timsort.h
  140:  */
  141: #ifdef WITH_TIM_SORT
  142: #define SORT_NAME libxml_domnode
  143: #define SORT_TYPE xmlNodePtr
  144: /**
  145:  * wrap_cmp:
  146:  * @x: a node
  147:  * @y: another node
  148:  *
  149:  * Comparison function for the Timsort implementation
  150:  *
  151:  * Returns -2 in case of error -1 if first point < second point, 0 if
  152:  *         it's the same node, +1 otherwise
  153:  */
  154: static
  155: int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
  156: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  157:     static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
  158:     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  159:     {
  160:         int res = xmlXPathCmpNodesExt(x, y);
  161:         return res == -2 ? res : -res;
  162:     }
  163: #else
  164:     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  165:     {
  166:         int res = xmlXPathCmpNodes(x, y);
  167:         return res == -2 ? res : -res;
  168:     }
  169: #endif
  170: #define SORT_CMP(x, y)  (wrap_cmp(x, y))
  171: #include "timsort.h"
  172: #endif /* WITH_TIM_SORT */
  173: 
  174: #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  175: 
  176: /************************************************************************
  177:  *									*
  178:  *			Floating point stuff				*
  179:  *									*
  180:  ************************************************************************/
  181: 
  182: #ifndef TRIO_REPLACE_STDIO
  183: #define TRIO_PUBLIC static
  184: #endif
  185: #include "trionan.c"
  186: 
  187: /*
  188:  * The lack of portability of this section of the libc is annoying !
  189:  */
  190: double xmlXPathNAN = 0;
  191: double xmlXPathPINF = 1;
  192: double xmlXPathNINF = -1;
  193: static double xmlXPathNZERO = 0; /* not exported from headers */
  194: static int xmlXPathInitialized = 0;
  195: 
  196: /**
  197:  * xmlXPathInit:
  198:  *
  199:  * Initialize the XPath environment
  200:  */
  201: void
  202: xmlXPathInit(void) {
  203:     if (xmlXPathInitialized) return;
  204: 
  205:     xmlXPathPINF = trio_pinf();
  206:     xmlXPathNINF = trio_ninf();
  207:     xmlXPathNAN = trio_nan();
  208:     xmlXPathNZERO = trio_nzero();
  209: 
  210:     xmlXPathInitialized = 1;
  211: }
  212: 
  213: /**
  214:  * xmlXPathIsNaN:
  215:  * @val:  a double value
  216:  *
  217:  * Provides a portable isnan() function to detect whether a double
  218:  * is a NotaNumber. Based on trio code
  219:  * http://sourceforge.net/projects/ctrio/
  220:  *
  221:  * Returns 1 if the value is a NaN, 0 otherwise
  222:  */
  223: int
  224: xmlXPathIsNaN(double val) {
  225:     return(trio_isnan(val));
  226: }
  227: 
  228: /**
  229:  * xmlXPathIsInf:
  230:  * @val:  a double value
  231:  *
  232:  * Provides a portable isinf() function to detect whether a double
  233:  * is a +Infinite or -Infinite. Based on trio code
  234:  * http://sourceforge.net/projects/ctrio/
  235:  *
  236:  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
  237:  */
  238: int
  239: xmlXPathIsInf(double val) {
  240:     return(trio_isinf(val));
  241: }
  242: 
  243: #endif /* SCHEMAS or XPATH */
  244: #ifdef LIBXML_XPATH_ENABLED
  245: /**
  246:  * xmlXPathGetSign:
  247:  * @val:  a double value
  248:  *
  249:  * Provides a portable function to detect the sign of a double
  250:  * Modified from trio code
  251:  * http://sourceforge.net/projects/ctrio/
  252:  *
  253:  * Returns 1 if the value is Negative, 0 if positive
  254:  */
  255: static int
  256: xmlXPathGetSign(double val) {
  257:     return(trio_signbit(val));
  258: }
  259: 
  260: 
  261: /*
  262:  * TODO: when compatibility allows remove all "fake node libxslt" strings
  263:  *       the test should just be name[0] = ' '
  264:  */
  265: #ifdef DEBUG_XPATH_EXPRESSION
  266: #define DEBUG_STEP
  267: #define DEBUG_EXPR
  268: #define DEBUG_EVAL_COUNTS
  269: #endif
  270: 
  271: static xmlNs xmlXPathXMLNamespaceStruct = {
  272:     NULL,
  273:     XML_NAMESPACE_DECL,
  274:     XML_XML_NAMESPACE,
  275:     BAD_CAST "xml",
  276:     NULL,
  277:     NULL
  278: };
  279: static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  280: #ifndef LIBXML_THREAD_ENABLED
  281: /*
  282:  * Optimizer is disabled only when threaded apps are detected while
  283:  * the library ain't compiled for thread safety.
  284:  */
  285: static int xmlXPathDisableOptimizer = 0;
  286: #endif
  287: 
  288: /************************************************************************
  289:  *									*
  290:  *			Error handling routines				*
  291:  *									*
  292:  ************************************************************************/
  293: 
  294: /**
  295:  * XP_ERRORNULL:
  296:  * @X:  the error code
  297:  *
  298:  * Macro to raise an XPath error and return NULL.
  299:  */
  300: #define XP_ERRORNULL(X)							\
  301:     { xmlXPathErr(ctxt, X); return(NULL); }
  302: 
  303: /*
  304:  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  305:  */
  306: static const char *xmlXPathErrorMessages[] = {
  307:     "Ok\n",
  308:     "Number encoding\n",
  309:     "Unfinished literal\n",
  310:     "Start of literal\n",
  311:     "Expected $ for variable reference\n",
  312:     "Undefined variable\n",
  313:     "Invalid predicate\n",
  314:     "Invalid expression\n",
  315:     "Missing closing curly brace\n",
  316:     "Unregistered function\n",
  317:     "Invalid operand\n",
  318:     "Invalid type\n",
  319:     "Invalid number of arguments\n",
  320:     "Invalid context size\n",
  321:     "Invalid context position\n",
  322:     "Memory allocation error\n",
  323:     "Syntax error\n",
  324:     "Resource error\n",
  325:     "Sub resource error\n",
  326:     "Undefined namespace prefix\n",
  327:     "Encoding error\n",
  328:     "Char out of XML range\n",
  329:     "Invalid or incomplete context\n",
  330:     "Stack usage errror\n",
  331:     "Forbidden variable\n",
  332:     "?? Unknown error ??\n"	/* Must be last in the list! */
  333: };
  334: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
  335: 		   sizeof(xmlXPathErrorMessages[0])) - 1)
  336: /**
  337:  * xmlXPathErrMemory:
  338:  * @ctxt:  an XPath context
  339:  * @extra:  extra informations
  340:  *
  341:  * Handle a redefinition of attribute error
  342:  */
  343: static void
  344: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  345: {
  346:     if (ctxt != NULL) {
  347:         if (extra) {
  348:             xmlChar buf[200];
  349: 
  350:             xmlStrPrintf(buf, 200,
  351:                          BAD_CAST "Memory allocation failed : %s\n",
  352:                          extra);
  353:             ctxt->lastError.message = (char *) xmlStrdup(buf);
  354:         } else {
  355:             ctxt->lastError.message = (char *)
  356: 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
  357:         }
  358:         ctxt->lastError.domain = XML_FROM_XPATH;
  359:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
  360: 	if (ctxt->error != NULL)
  361: 	    ctxt->error(ctxt->userData, &ctxt->lastError);
  362:     } else {
  363:         if (extra)
  364:             __xmlRaiseError(NULL, NULL, NULL,
  365:                             NULL, NULL, XML_FROM_XPATH,
  366:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  367:                             extra, NULL, NULL, 0, 0,
  368:                             "Memory allocation failed : %s\n", extra);
  369:         else
  370:             __xmlRaiseError(NULL, NULL, NULL,
  371:                             NULL, NULL, XML_FROM_XPATH,
  372:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  373:                             NULL, NULL, NULL, 0, 0,
  374:                             "Memory allocation failed\n");
  375:     }
  376: }
  377: 
  378: /**
  379:  * xmlXPathPErrMemory:
  380:  * @ctxt:  an XPath parser context
  381:  * @extra:  extra informations
  382:  *
  383:  * Handle a redefinition of attribute error
  384:  */
  385: static void
  386: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  387: {
  388:     if (ctxt == NULL)
  389: 	xmlXPathErrMemory(NULL, extra);
  390:     else {
  391: 	ctxt->error = XPATH_MEMORY_ERROR;
  392: 	xmlXPathErrMemory(ctxt->context, extra);
  393:     }
  394: }
  395: 
  396: /**
  397:  * xmlXPathErr:
  398:  * @ctxt:  a XPath parser context
  399:  * @error:  the error code
  400:  *
  401:  * Handle an XPath error
  402:  */
  403: void
  404: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  405: {
  406:     if ((error < 0) || (error > MAXERRNO))
  407: 	error = MAXERRNO;
  408:     if (ctxt == NULL) {
  409: 	__xmlRaiseError(NULL, NULL, NULL,
  410: 			NULL, NULL, XML_FROM_XPATH,
  411: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  412: 			XML_ERR_ERROR, NULL, 0,
  413: 			NULL, NULL, NULL, 0, 0,
  414: 			"%s", xmlXPathErrorMessages[error]);
  415: 	return;
  416:     }
  417:     ctxt->error = error;
  418:     if (ctxt->context == NULL) {
  419: 	__xmlRaiseError(NULL, NULL, NULL,
  420: 			NULL, NULL, XML_FROM_XPATH,
  421: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  422: 			XML_ERR_ERROR, NULL, 0,
  423: 			(const char *) ctxt->base, NULL, NULL,
  424: 			ctxt->cur - ctxt->base, 0,
  425: 			"%s", xmlXPathErrorMessages[error]);
  426: 	return;
  427:     }
  428: 
  429:     /* cleanup current last error */
  430:     xmlResetError(&ctxt->context->lastError);
  431: 
  432:     ctxt->context->lastError.domain = XML_FROM_XPATH;
  433:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  434:                            XPATH_EXPRESSION_OK;
  435:     ctxt->context->lastError.level = XML_ERR_ERROR;
  436:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  437:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  438:     ctxt->context->lastError.node = ctxt->context->debugNode;
  439:     if (ctxt->context->error != NULL) {
  440: 	ctxt->context->error(ctxt->context->userData,
  441: 	                     &ctxt->context->lastError);
  442:     } else {
  443: 	__xmlRaiseError(NULL, NULL, NULL,
  444: 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  445: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  446: 			XML_ERR_ERROR, NULL, 0,
  447: 			(const char *) ctxt->base, NULL, NULL,
  448: 			ctxt->cur - ctxt->base, 0,
  449: 			"%s", xmlXPathErrorMessages[error]);
  450:     }
  451: 
  452: }
  453: 
  454: /**
  455:  * xmlXPatherror:
  456:  * @ctxt:  the XPath Parser context
  457:  * @file:  the file name
  458:  * @line:  the line number
  459:  * @no:  the error number
  460:  *
  461:  * Formats an error message.
  462:  */
  463: void
  464: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  465:               int line ATTRIBUTE_UNUSED, int no) {
  466:     xmlXPathErr(ctxt, no);
  467: }
  468: 
  469: /************************************************************************
  470:  *									*
  471:  *			Utilities					*
  472:  *									*
  473:  ************************************************************************/
  474: 
  475: /**
  476:  * xsltPointerList:
  477:  *
  478:  * Pointer-list for various purposes.
  479:  */
  480: typedef struct _xmlPointerList xmlPointerList;
  481: typedef xmlPointerList *xmlPointerListPtr;
  482: struct _xmlPointerList {
  483:     void **items;
  484:     int number;
  485:     int size;
  486: };
  487: /*
  488: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  489: * and here, we should make the functions public.
  490: */
  491: static int
  492: xmlPointerListAddSize(xmlPointerListPtr list,
  493: 		       void *item,
  494: 		       int initialSize)
  495: {
  496:     if (list->items == NULL) {
  497: 	if (initialSize <= 0)
  498: 	    initialSize = 1;
  499: 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
  500: 	if (list->items == NULL) {
  501: 	    xmlXPathErrMemory(NULL,
  502: 		"xmlPointerListCreate: allocating item\n");
  503: 	    return(-1);
  504: 	}
  505: 	list->number = 0;
  506: 	list->size = initialSize;
  507:     } else if (list->size <= list->number) {
  508:         if (list->size > 50000000) {
  509: 	    xmlXPathErrMemory(NULL,
  510: 		"xmlPointerListAddSize: re-allocating item\n");
  511:             return(-1);
  512:         }
  513: 	list->size *= 2;
  514: 	list->items = (void **) xmlRealloc(list->items,
  515: 	    list->size * sizeof(void *));
  516: 	if (list->items == NULL) {
  517: 	    xmlXPathErrMemory(NULL,
  518: 		"xmlPointerListAddSize: re-allocating item\n");
  519: 	    list->size = 0;
  520: 	    return(-1);
  521: 	}
  522:     }
  523:     list->items[list->number++] = item;
  524:     return(0);
  525: }
  526: 
  527: /**
  528:  * xsltPointerListCreate:
  529:  *
  530:  * Creates an xsltPointerList structure.
  531:  *
  532:  * Returns a xsltPointerList structure or NULL in case of an error.
  533:  */
  534: static xmlPointerListPtr
  535: xmlPointerListCreate(int initialSize)
  536: {
  537:     xmlPointerListPtr ret;
  538: 
  539:     ret = xmlMalloc(sizeof(xmlPointerList));
  540:     if (ret == NULL) {
  541: 	xmlXPathErrMemory(NULL,
  542: 	    "xmlPointerListCreate: allocating item\n");
  543: 	return (NULL);
  544:     }
  545:     memset(ret, 0, sizeof(xmlPointerList));
  546:     if (initialSize > 0) {
  547: 	xmlPointerListAddSize(ret, NULL, initialSize);
  548: 	ret->number = 0;
  549:     }
  550:     return (ret);
  551: }
  552: 
  553: /**
  554:  * xsltPointerListFree:
  555:  *
  556:  * Frees the xsltPointerList structure. This does not free
  557:  * the content of the list.
  558:  */
  559: static void
  560: xmlPointerListFree(xmlPointerListPtr list)
  561: {
  562:     if (list == NULL)
  563: 	return;
  564:     if (list->items != NULL)
  565: 	xmlFree(list->items);
  566:     xmlFree(list);
  567: }
  568: 
  569: /************************************************************************
  570:  *									*
  571:  *			Parser Types					*
  572:  *									*
  573:  ************************************************************************/
  574: 
  575: /*
  576:  * Types are private:
  577:  */
  578: 
  579: typedef enum {
  580:     XPATH_OP_END=0,
  581:     XPATH_OP_AND,
  582:     XPATH_OP_OR,
  583:     XPATH_OP_EQUAL,
  584:     XPATH_OP_CMP,
  585:     XPATH_OP_PLUS,
  586:     XPATH_OP_MULT,
  587:     XPATH_OP_UNION,
  588:     XPATH_OP_ROOT,
  589:     XPATH_OP_NODE,
  590:     XPATH_OP_RESET, /* 10 */
  591:     XPATH_OP_COLLECT,
  592:     XPATH_OP_VALUE, /* 12 */
  593:     XPATH_OP_VARIABLE,
  594:     XPATH_OP_FUNCTION,
  595:     XPATH_OP_ARG,
  596:     XPATH_OP_PREDICATE,
  597:     XPATH_OP_FILTER, /* 17 */
  598:     XPATH_OP_SORT /* 18 */
  599: #ifdef LIBXML_XPTR_ENABLED
  600:     ,XPATH_OP_RANGETO
  601: #endif
  602: } xmlXPathOp;
  603: 
  604: typedef enum {
  605:     AXIS_ANCESTOR = 1,
  606:     AXIS_ANCESTOR_OR_SELF,
  607:     AXIS_ATTRIBUTE,
  608:     AXIS_CHILD,
  609:     AXIS_DESCENDANT,
  610:     AXIS_DESCENDANT_OR_SELF,
  611:     AXIS_FOLLOWING,
  612:     AXIS_FOLLOWING_SIBLING,
  613:     AXIS_NAMESPACE,
  614:     AXIS_PARENT,
  615:     AXIS_PRECEDING,
  616:     AXIS_PRECEDING_SIBLING,
  617:     AXIS_SELF
  618: } xmlXPathAxisVal;
  619: 
  620: typedef enum {
  621:     NODE_TEST_NONE = 0,
  622:     NODE_TEST_TYPE = 1,
  623:     NODE_TEST_PI = 2,
  624:     NODE_TEST_ALL = 3,
  625:     NODE_TEST_NS = 4,
  626:     NODE_TEST_NAME = 5
  627: } xmlXPathTestVal;
  628: 
  629: typedef enum {
  630:     NODE_TYPE_NODE = 0,
  631:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  632:     NODE_TYPE_TEXT = XML_TEXT_NODE,
  633:     NODE_TYPE_PI = XML_PI_NODE
  634: } xmlXPathTypeVal;
  635: 
  636: typedef struct _xmlXPathStepOp xmlXPathStepOp;
  637: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  638: struct _xmlXPathStepOp {
  639:     xmlXPathOp op;		/* The identifier of the operation */
  640:     int ch1;			/* First child */
  641:     int ch2;			/* Second child */
  642:     int value;
  643:     int value2;
  644:     int value3;
  645:     void *value4;
  646:     void *value5;
  647:     void *cache;
  648:     void *cacheURI;
  649: };
  650: 
  651: struct _xmlXPathCompExpr {
  652:     int nbStep;			/* Number of steps in this expression */
  653:     int maxStep;		/* Maximum number of steps allocated */
  654:     xmlXPathStepOp *steps;	/* ops for computation of this expression */
  655:     int last;			/* index of last step in expression */
  656:     xmlChar *expr;		/* the expression being computed */
  657:     xmlDictPtr dict;		/* the dictionnary to use if any */
  658: #ifdef DEBUG_EVAL_COUNTS
  659:     int nb;
  660:     xmlChar *string;
  661: #endif
  662: #ifdef XPATH_STREAMING
  663:     xmlPatternPtr stream;
  664: #endif
  665: };
  666: 
  667: /************************************************************************
  668:  *									*
  669:  *			Forward declarations				*
  670:  *									*
  671:  ************************************************************************/
  672: static void
  673: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  674: static void
  675: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  676: static int
  677: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  678:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
  679: static int
  680: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  681: 			    xmlXPathStepOpPtr op,
  682: 			    int isPredicate);
  683: 
  684: /************************************************************************
  685:  *									*
  686:  *			Parser Type functions				*
  687:  *									*
  688:  ************************************************************************/
  689: 
  690: /**
  691:  * xmlXPathNewCompExpr:
  692:  *
  693:  * Create a new Xpath component
  694:  *
  695:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  696:  */
  697: static xmlXPathCompExprPtr
  698: xmlXPathNewCompExpr(void) {
  699:     xmlXPathCompExprPtr cur;
  700: 
  701:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  702:     if (cur == NULL) {
  703:         xmlXPathErrMemory(NULL, "allocating component\n");
  704: 	return(NULL);
  705:     }
  706:     memset(cur, 0, sizeof(xmlXPathCompExpr));
  707:     cur->maxStep = 10;
  708:     cur->nbStep = 0;
  709:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  710: 	                                   sizeof(xmlXPathStepOp));
  711:     if (cur->steps == NULL) {
  712:         xmlXPathErrMemory(NULL, "allocating steps\n");
  713: 	xmlFree(cur);
  714: 	return(NULL);
  715:     }
  716:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  717:     cur->last = -1;
  718: #ifdef DEBUG_EVAL_COUNTS
  719:     cur->nb = 0;
  720: #endif
  721:     return(cur);
  722: }
  723: 
  724: /**
  725:  * xmlXPathFreeCompExpr:
  726:  * @comp:  an XPATH comp
  727:  *
  728:  * Free up the memory allocated by @comp
  729:  */
  730: void
  731: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  732: {
  733:     xmlXPathStepOpPtr op;
  734:     int i;
  735: 
  736:     if (comp == NULL)
  737:         return;
  738:     if (comp->dict == NULL) {
  739: 	for (i = 0; i < comp->nbStep; i++) {
  740: 	    op = &comp->steps[i];
  741: 	    if (op->value4 != NULL) {
  742: 		if (op->op == XPATH_OP_VALUE)
  743: 		    xmlXPathFreeObject(op->value4);
  744: 		else
  745: 		    xmlFree(op->value4);
  746: 	    }
  747: 	    if (op->value5 != NULL)
  748: 		xmlFree(op->value5);
  749: 	}
  750:     } else {
  751: 	for (i = 0; i < comp->nbStep; i++) {
  752: 	    op = &comp->steps[i];
  753: 	    if (op->value4 != NULL) {
  754: 		if (op->op == XPATH_OP_VALUE)
  755: 		    xmlXPathFreeObject(op->value4);
  756: 	    }
  757: 	}
  758:         xmlDictFree(comp->dict);
  759:     }
  760:     if (comp->steps != NULL) {
  761:         xmlFree(comp->steps);
  762:     }
  763: #ifdef DEBUG_EVAL_COUNTS
  764:     if (comp->string != NULL) {
  765:         xmlFree(comp->string);
  766:     }
  767: #endif
  768: #ifdef XPATH_STREAMING
  769:     if (comp->stream != NULL) {
  770:         xmlFreePatternList(comp->stream);
  771:     }
  772: #endif
  773:     if (comp->expr != NULL) {
  774:         xmlFree(comp->expr);
  775:     }
  776: 
  777:     xmlFree(comp);
  778: }
  779: 
  780: /**
  781:  * xmlXPathCompExprAdd:
  782:  * @comp:  the compiled expression
  783:  * @ch1: first child index
  784:  * @ch2: second child index
  785:  * @op:  an op
  786:  * @value:  the first int value
  787:  * @value2:  the second int value
  788:  * @value3:  the third int value
  789:  * @value4:  the first string value
  790:  * @value5:  the second string value
  791:  *
  792:  * Add a step to an XPath Compiled Expression
  793:  *
  794:  * Returns -1 in case of failure, the index otherwise
  795:  */
  796: static int
  797: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
  798:    xmlXPathOp op, int value,
  799:    int value2, int value3, void *value4, void *value5) {
  800:     if (comp->nbStep >= comp->maxStep) {
  801: 	xmlXPathStepOp *real;
  802: 
  803:         if (comp->maxStep >= XPATH_MAX_STEPS) {
  804: 	    xmlXPathErrMemory(NULL, "adding step\n");
  805: 	    return(-1);
  806:         }
  807: 	comp->maxStep *= 2;
  808: 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  809: 		                      comp->maxStep * sizeof(xmlXPathStepOp));
  810: 	if (real == NULL) {
  811: 	    comp->maxStep /= 2;
  812: 	    xmlXPathErrMemory(NULL, "adding step\n");
  813: 	    return(-1);
  814: 	}
  815: 	comp->steps = real;
  816:     }
  817:     comp->last = comp->nbStep;
  818:     comp->steps[comp->nbStep].ch1 = ch1;
  819:     comp->steps[comp->nbStep].ch2 = ch2;
  820:     comp->steps[comp->nbStep].op = op;
  821:     comp->steps[comp->nbStep].value = value;
  822:     comp->steps[comp->nbStep].value2 = value2;
  823:     comp->steps[comp->nbStep].value3 = value3;
  824:     if ((comp->dict != NULL) &&
  825:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  826: 	 (op == XPATH_OP_COLLECT))) {
  827:         if (value4 != NULL) {
  828: 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
  829: 	        (void *)xmlDictLookup(comp->dict, value4, -1);
  830: 	    xmlFree(value4);
  831: 	} else
  832: 	    comp->steps[comp->nbStep].value4 = NULL;
  833:         if (value5 != NULL) {
  834: 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
  835: 	        (void *)xmlDictLookup(comp->dict, value5, -1);
  836: 	    xmlFree(value5);
  837: 	} else
  838: 	    comp->steps[comp->nbStep].value5 = NULL;
  839:     } else {
  840: 	comp->steps[comp->nbStep].value4 = value4;
  841: 	comp->steps[comp->nbStep].value5 = value5;
  842:     }
  843:     comp->steps[comp->nbStep].cache = NULL;
  844:     return(comp->nbStep++);
  845: }
  846: 
  847: /**
  848:  * xmlXPathCompSwap:
  849:  * @comp:  the compiled expression
  850:  * @op: operation index
  851:  *
  852:  * Swaps 2 operations in the compiled expression
  853:  */
  854: static void
  855: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  856:     int tmp;
  857: 
  858: #ifndef LIBXML_THREAD_ENABLED
  859:     /*
  860:      * Since this manipulates possibly shared variables, this is
  861:      * disabled if one detects that the library is used in a multithreaded
  862:      * application
  863:      */
  864:     if (xmlXPathDisableOptimizer)
  865: 	return;
  866: #endif
  867: 
  868:     tmp = op->ch1;
  869:     op->ch1 = op->ch2;
  870:     op->ch2 = tmp;
  871: }
  872: 
  873: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
  874:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
  875: 	                (op), (val), (val2), (val3), (val4), (val5))
  876: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
  877:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
  878: 	                (op), (val), (val2), (val3), (val4), (val5))
  879: 
  880: #define PUSH_LEAVE_EXPR(op, val, val2)					\
  881: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  882: 
  883: #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
  884: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  885: 
  886: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
  887: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
  888: 			(val), (val2), 0 ,NULL ,NULL)
  889: 
  890: /************************************************************************
  891:  *									*
  892:  *		XPath object cache structures				*
  893:  *									*
  894:  ************************************************************************/
  895: 
  896: /* #define XP_DEFAULT_CACHE_ON */
  897: 
  898: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  899: 
  900: typedef struct _xmlXPathContextCache xmlXPathContextCache;
  901: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  902: struct _xmlXPathContextCache {
  903:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
  904:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
  905:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
  906:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
  907:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
  908:     int maxNodeset;
  909:     int maxString;
  910:     int maxBoolean;
  911:     int maxNumber;
  912:     int maxMisc;
  913: #ifdef XP_DEBUG_OBJ_USAGE
  914:     int dbgCachedAll;
  915:     int dbgCachedNodeset;
  916:     int dbgCachedString;
  917:     int dbgCachedBool;
  918:     int dbgCachedNumber;
  919:     int dbgCachedPoint;
  920:     int dbgCachedRange;
  921:     int dbgCachedLocset;
  922:     int dbgCachedUsers;
  923:     int dbgCachedXSLTTree;
  924:     int dbgCachedUndefined;
  925: 
  926: 
  927:     int dbgReusedAll;
  928:     int dbgReusedNodeset;
  929:     int dbgReusedString;
  930:     int dbgReusedBool;
  931:     int dbgReusedNumber;
  932:     int dbgReusedPoint;
  933:     int dbgReusedRange;
  934:     int dbgReusedLocset;
  935:     int dbgReusedUsers;
  936:     int dbgReusedXSLTTree;
  937:     int dbgReusedUndefined;
  938: 
  939: #endif
  940: };
  941: 
  942: /************************************************************************
  943:  *									*
  944:  *		Debugging related functions				*
  945:  *									*
  946:  ************************************************************************/
  947: 
  948: #define STRANGE							\
  949:     xmlGenericError(xmlGenericErrorContext,				\
  950: 	    "Internal error at %s:%d\n",				\
  951:             __FILE__, __LINE__);
  952: 
  953: #ifdef LIBXML_DEBUG_ENABLED
  954: static void
  955: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  956:     int i;
  957:     char shift[100];
  958: 
  959:     for (i = 0;((i < depth) && (i < 25));i++)
  960:         shift[2 * i] = shift[2 * i + 1] = ' ';
  961:     shift[2 * i] = shift[2 * i + 1] = 0;
  962:     if (cur == NULL) {
  963: 	fprintf(output, "%s", shift);
  964: 	fprintf(output, "Node is NULL !\n");
  965: 	return;
  966: 
  967:     }
  968: 
  969:     if ((cur->type == XML_DOCUMENT_NODE) ||
  970: 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
  971: 	fprintf(output, "%s", shift);
  972: 	fprintf(output, " /\n");
  973:     } else if (cur->type == XML_ATTRIBUTE_NODE)
  974: 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  975:     else
  976: 	xmlDebugDumpOneNode(output, cur, depth);
  977: }
  978: static void
  979: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  980:     xmlNodePtr tmp;
  981:     int i;
  982:     char shift[100];
  983: 
  984:     for (i = 0;((i < depth) && (i < 25));i++)
  985:         shift[2 * i] = shift[2 * i + 1] = ' ';
  986:     shift[2 * i] = shift[2 * i + 1] = 0;
  987:     if (cur == NULL) {
  988: 	fprintf(output, "%s", shift);
  989: 	fprintf(output, "Node is NULL !\n");
  990: 	return;
  991: 
  992:     }
  993: 
  994:     while (cur != NULL) {
  995: 	tmp = cur;
  996: 	cur = cur->next;
  997: 	xmlDebugDumpOneNode(output, tmp, depth);
  998:     }
  999: }
 1000: 
 1001: static void
 1002: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
 1003:     int i;
 1004:     char shift[100];
 1005: 
 1006:     for (i = 0;((i < depth) && (i < 25));i++)
 1007:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1008:     shift[2 * i] = shift[2 * i + 1] = 0;
 1009: 
 1010:     if (cur == NULL) {
 1011: 	fprintf(output, "%s", shift);
 1012: 	fprintf(output, "NodeSet is NULL !\n");
 1013: 	return;
 1014: 
 1015:     }
 1016: 
 1017:     if (cur != NULL) {
 1018: 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
 1019: 	for (i = 0;i < cur->nodeNr;i++) {
 1020: 	    fprintf(output, "%s", shift);
 1021: 	    fprintf(output, "%d", i + 1);
 1022: 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
 1023: 	}
 1024:     }
 1025: }
 1026: 
 1027: static void
 1028: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
 1029:     int i;
 1030:     char shift[100];
 1031: 
 1032:     for (i = 0;((i < depth) && (i < 25));i++)
 1033:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1034:     shift[2 * i] = shift[2 * i + 1] = 0;
 1035: 
 1036:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
 1037: 	fprintf(output, "%s", shift);
 1038: 	fprintf(output, "Value Tree is NULL !\n");
 1039: 	return;
 1040: 
 1041:     }
 1042: 
 1043:     fprintf(output, "%s", shift);
 1044:     fprintf(output, "%d", i + 1);
 1045:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
 1046: }
 1047: #if defined(LIBXML_XPTR_ENABLED)
 1048: static void
 1049: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
 1050:     int i;
 1051:     char shift[100];
 1052: 
 1053:     for (i = 0;((i < depth) && (i < 25));i++)
 1054:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1055:     shift[2 * i] = shift[2 * i + 1] = 0;
 1056: 
 1057:     if (cur == NULL) {
 1058: 	fprintf(output, "%s", shift);
 1059: 	fprintf(output, "LocationSet is NULL !\n");
 1060: 	return;
 1061: 
 1062:     }
 1063: 
 1064:     for (i = 0;i < cur->locNr;i++) {
 1065: 	fprintf(output, "%s", shift);
 1066:         fprintf(output, "%d : ", i + 1);
 1067: 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
 1068:     }
 1069: }
 1070: #endif /* LIBXML_XPTR_ENABLED */
 1071: 
 1072: /**
 1073:  * xmlXPathDebugDumpObject:
 1074:  * @output:  the FILE * to dump the output
 1075:  * @cur:  the object to inspect
 1076:  * @depth:  indentation level
 1077:  *
 1078:  * Dump the content of the object for debugging purposes
 1079:  */
 1080: void
 1081: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
 1082:     int i;
 1083:     char shift[100];
 1084: 
 1085:     if (output == NULL) return;
 1086: 
 1087:     for (i = 0;((i < depth) && (i < 25));i++)
 1088:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1089:     shift[2 * i] = shift[2 * i + 1] = 0;
 1090: 
 1091: 
 1092:     fprintf(output, "%s", shift);
 1093: 
 1094:     if (cur == NULL) {
 1095:         fprintf(output, "Object is empty (NULL)\n");
 1096: 	return;
 1097:     }
 1098:     switch(cur->type) {
 1099:         case XPATH_UNDEFINED:
 1100: 	    fprintf(output, "Object is uninitialized\n");
 1101: 	    break;
 1102:         case XPATH_NODESET:
 1103: 	    fprintf(output, "Object is a Node Set :\n");
 1104: 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
 1105: 	    break;
 1106: 	case XPATH_XSLT_TREE:
 1107: 	    fprintf(output, "Object is an XSLT value tree :\n");
 1108: 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
 1109: 	    break;
 1110:         case XPATH_BOOLEAN:
 1111: 	    fprintf(output, "Object is a Boolean : ");
 1112: 	    if (cur->boolval) fprintf(output, "true\n");
 1113: 	    else fprintf(output, "false\n");
 1114: 	    break;
 1115:         case XPATH_NUMBER:
 1116: 	    switch (xmlXPathIsInf(cur->floatval)) {
 1117: 	    case 1:
 1118: 		fprintf(output, "Object is a number : Infinity\n");
 1119: 		break;
 1120: 	    case -1:
 1121: 		fprintf(output, "Object is a number : -Infinity\n");
 1122: 		break;
 1123: 	    default:
 1124: 		if (xmlXPathIsNaN(cur->floatval)) {
 1125: 		    fprintf(output, "Object is a number : NaN\n");
 1126: 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
 1127: 		    fprintf(output, "Object is a number : 0\n");
 1128: 		} else {
 1129: 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
 1130: 		}
 1131: 	    }
 1132: 	    break;
 1133:         case XPATH_STRING:
 1134: 	    fprintf(output, "Object is a string : ");
 1135: 	    xmlDebugDumpString(output, cur->stringval);
 1136: 	    fprintf(output, "\n");
 1137: 	    break;
 1138: 	case XPATH_POINT:
 1139: 	    fprintf(output, "Object is a point : index %d in node", cur->index);
 1140: 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
 1141: 	    fprintf(output, "\n");
 1142: 	    break;
 1143: 	case XPATH_RANGE:
 1144: 	    if ((cur->user2 == NULL) ||
 1145: 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
 1146: 		fprintf(output, "Object is a collapsed range :\n");
 1147: 		fprintf(output, "%s", shift);
 1148: 		if (cur->index >= 0)
 1149: 		    fprintf(output, "index %d in ", cur->index);
 1150: 		fprintf(output, "node\n");
 1151: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1152: 			              depth + 1);
 1153: 	    } else  {
 1154: 		fprintf(output, "Object is a range :\n");
 1155: 		fprintf(output, "%s", shift);
 1156: 		fprintf(output, "From ");
 1157: 		if (cur->index >= 0)
 1158: 		    fprintf(output, "index %d in ", cur->index);
 1159: 		fprintf(output, "node\n");
 1160: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1161: 			              depth + 1);
 1162: 		fprintf(output, "%s", shift);
 1163: 		fprintf(output, "To ");
 1164: 		if (cur->index2 >= 0)
 1165: 		    fprintf(output, "index %d in ", cur->index2);
 1166: 		fprintf(output, "node\n");
 1167: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
 1168: 			              depth + 1);
 1169: 		fprintf(output, "\n");
 1170: 	    }
 1171: 	    break;
 1172: 	case XPATH_LOCATIONSET:
 1173: #if defined(LIBXML_XPTR_ENABLED)
 1174: 	    fprintf(output, "Object is a Location Set:\n");
 1175: 	    xmlXPathDebugDumpLocationSet(output,
 1176: 		    (xmlLocationSetPtr) cur->user, depth);
 1177: #endif
 1178: 	    break;
 1179: 	case XPATH_USERS:
 1180: 	    fprintf(output, "Object is user defined\n");
 1181: 	    break;
 1182:     }
 1183: }
 1184: 
 1185: static void
 1186: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
 1187: 	                     xmlXPathStepOpPtr op, int depth) {
 1188:     int i;
 1189:     char shift[100];
 1190: 
 1191:     for (i = 0;((i < depth) && (i < 25));i++)
 1192:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1193:     shift[2 * i] = shift[2 * i + 1] = 0;
 1194: 
 1195:     fprintf(output, "%s", shift);
 1196:     if (op == NULL) {
 1197: 	fprintf(output, "Step is NULL\n");
 1198: 	return;
 1199:     }
 1200:     switch (op->op) {
 1201:         case XPATH_OP_END:
 1202: 	    fprintf(output, "END"); break;
 1203:         case XPATH_OP_AND:
 1204: 	    fprintf(output, "AND"); break;
 1205:         case XPATH_OP_OR:
 1206: 	    fprintf(output, "OR"); break;
 1207:         case XPATH_OP_EQUAL:
 1208: 	     if (op->value)
 1209: 		 fprintf(output, "EQUAL =");
 1210: 	     else
 1211: 		 fprintf(output, "EQUAL !=");
 1212: 	     break;
 1213:         case XPATH_OP_CMP:
 1214: 	     if (op->value)
 1215: 		 fprintf(output, "CMP <");
 1216: 	     else
 1217: 		 fprintf(output, "CMP >");
 1218: 	     if (!op->value2)
 1219: 		 fprintf(output, "=");
 1220: 	     break;
 1221:         case XPATH_OP_PLUS:
 1222: 	     if (op->value == 0)
 1223: 		 fprintf(output, "PLUS -");
 1224: 	     else if (op->value == 1)
 1225: 		 fprintf(output, "PLUS +");
 1226: 	     else if (op->value == 2)
 1227: 		 fprintf(output, "PLUS unary -");
 1228: 	     else if (op->value == 3)
 1229: 		 fprintf(output, "PLUS unary - -");
 1230: 	     break;
 1231:         case XPATH_OP_MULT:
 1232: 	     if (op->value == 0)
 1233: 		 fprintf(output, "MULT *");
 1234: 	     else if (op->value == 1)
 1235: 		 fprintf(output, "MULT div");
 1236: 	     else
 1237: 		 fprintf(output, "MULT mod");
 1238: 	     break;
 1239:         case XPATH_OP_UNION:
 1240: 	     fprintf(output, "UNION"); break;
 1241:         case XPATH_OP_ROOT:
 1242: 	     fprintf(output, "ROOT"); break;
 1243:         case XPATH_OP_NODE:
 1244: 	     fprintf(output, "NODE"); break;
 1245:         case XPATH_OP_RESET:
 1246: 	     fprintf(output, "RESET"); break;
 1247:         case XPATH_OP_SORT:
 1248: 	     fprintf(output, "SORT"); break;
 1249:         case XPATH_OP_COLLECT: {
 1250: 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
 1251: 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
 1252: 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
 1253: 	    const xmlChar *prefix = op->value4;
 1254: 	    const xmlChar *name = op->value5;
 1255: 
 1256: 	    fprintf(output, "COLLECT ");
 1257: 	    switch (axis) {
 1258: 		case AXIS_ANCESTOR:
 1259: 		    fprintf(output, " 'ancestors' "); break;
 1260: 		case AXIS_ANCESTOR_OR_SELF:
 1261: 		    fprintf(output, " 'ancestors-or-self' "); break;
 1262: 		case AXIS_ATTRIBUTE:
 1263: 		    fprintf(output, " 'attributes' "); break;
 1264: 		case AXIS_CHILD:
 1265: 		    fprintf(output, " 'child' "); break;
 1266: 		case AXIS_DESCENDANT:
 1267: 		    fprintf(output, " 'descendant' "); break;
 1268: 		case AXIS_DESCENDANT_OR_SELF:
 1269: 		    fprintf(output, " 'descendant-or-self' "); break;
 1270: 		case AXIS_FOLLOWING:
 1271: 		    fprintf(output, " 'following' "); break;
 1272: 		case AXIS_FOLLOWING_SIBLING:
 1273: 		    fprintf(output, " 'following-siblings' "); break;
 1274: 		case AXIS_NAMESPACE:
 1275: 		    fprintf(output, " 'namespace' "); break;
 1276: 		case AXIS_PARENT:
 1277: 		    fprintf(output, " 'parent' "); break;
 1278: 		case AXIS_PRECEDING:
 1279: 		    fprintf(output, " 'preceding' "); break;
 1280: 		case AXIS_PRECEDING_SIBLING:
 1281: 		    fprintf(output, " 'preceding-sibling' "); break;
 1282: 		case AXIS_SELF:
 1283: 		    fprintf(output, " 'self' "); break;
 1284: 	    }
 1285: 	    switch (test) {
 1286:                 case NODE_TEST_NONE:
 1287: 		    fprintf(output, "'none' "); break;
 1288:                 case NODE_TEST_TYPE:
 1289: 		    fprintf(output, "'type' "); break;
 1290:                 case NODE_TEST_PI:
 1291: 		    fprintf(output, "'PI' "); break;
 1292:                 case NODE_TEST_ALL:
 1293: 		    fprintf(output, "'all' "); break;
 1294:                 case NODE_TEST_NS:
 1295: 		    fprintf(output, "'namespace' "); break;
 1296:                 case NODE_TEST_NAME:
 1297: 		    fprintf(output, "'name' "); break;
 1298: 	    }
 1299: 	    switch (type) {
 1300:                 case NODE_TYPE_NODE:
 1301: 		    fprintf(output, "'node' "); break;
 1302:                 case NODE_TYPE_COMMENT:
 1303: 		    fprintf(output, "'comment' "); break;
 1304:                 case NODE_TYPE_TEXT:
 1305: 		    fprintf(output, "'text' "); break;
 1306:                 case NODE_TYPE_PI:
 1307: 		    fprintf(output, "'PI' "); break;
 1308: 	    }
 1309: 	    if (prefix != NULL)
 1310: 		fprintf(output, "%s:", prefix);
 1311: 	    if (name != NULL)
 1312: 		fprintf(output, "%s", (const char *) name);
 1313: 	    break;
 1314: 
 1315:         }
 1316: 	case XPATH_OP_VALUE: {
 1317: 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
 1318: 
 1319: 	    fprintf(output, "ELEM ");
 1320: 	    xmlXPathDebugDumpObject(output, object, 0);
 1321: 	    goto finish;
 1322: 	}
 1323: 	case XPATH_OP_VARIABLE: {
 1324: 	    const xmlChar *prefix = op->value5;
 1325: 	    const xmlChar *name = op->value4;
 1326: 
 1327: 	    if (prefix != NULL)
 1328: 		fprintf(output, "VARIABLE %s:%s", prefix, name);
 1329: 	    else
 1330: 		fprintf(output, "VARIABLE %s", name);
 1331: 	    break;
 1332: 	}
 1333: 	case XPATH_OP_FUNCTION: {
 1334: 	    int nbargs = op->value;
 1335: 	    const xmlChar *prefix = op->value5;
 1336: 	    const xmlChar *name = op->value4;
 1337: 
 1338: 	    if (prefix != NULL)
 1339: 		fprintf(output, "FUNCTION %s:%s(%d args)",
 1340: 			prefix, name, nbargs);
 1341: 	    else
 1342: 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
 1343: 	    break;
 1344: 	}
 1345:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
 1346:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
 1347:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
 1348: #ifdef LIBXML_XPTR_ENABLED
 1349:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
 1350: #endif
 1351: 	default:
 1352:         fprintf(output, "UNKNOWN %d\n", op->op); return;
 1353:     }
 1354:     fprintf(output, "\n");
 1355: finish:
 1356:     if (op->ch1 >= 0)
 1357: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
 1358:     if (op->ch2 >= 0)
 1359: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
 1360: }
 1361: 
 1362: /**
 1363:  * xmlXPathDebugDumpCompExpr:
 1364:  * @output:  the FILE * for the output
 1365:  * @comp:  the precompiled XPath expression
 1366:  * @depth:  the indentation level.
 1367:  *
 1368:  * Dumps the tree of the compiled XPath expression.
 1369:  */
 1370: void
 1371: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
 1372: 	                  int depth) {
 1373:     int i;
 1374:     char shift[100];
 1375: 
 1376:     if ((output == NULL) || (comp == NULL)) return;
 1377: 
 1378:     for (i = 0;((i < depth) && (i < 25));i++)
 1379:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1380:     shift[2 * i] = shift[2 * i + 1] = 0;
 1381: 
 1382:     fprintf(output, "%s", shift);
 1383: 
 1384:     fprintf(output, "Compiled Expression : %d elements\n",
 1385: 	    comp->nbStep);
 1386:     i = comp->last;
 1387:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
 1388: }
 1389: 
 1390: #ifdef XP_DEBUG_OBJ_USAGE
 1391: 
 1392: /*
 1393: * XPath object usage related debugging variables.
 1394: */
 1395: static int xmlXPathDebugObjCounterUndefined = 0;
 1396: static int xmlXPathDebugObjCounterNodeset = 0;
 1397: static int xmlXPathDebugObjCounterBool = 0;
 1398: static int xmlXPathDebugObjCounterNumber = 0;
 1399: static int xmlXPathDebugObjCounterString = 0;
 1400: static int xmlXPathDebugObjCounterPoint = 0;
 1401: static int xmlXPathDebugObjCounterRange = 0;
 1402: static int xmlXPathDebugObjCounterLocset = 0;
 1403: static int xmlXPathDebugObjCounterUsers = 0;
 1404: static int xmlXPathDebugObjCounterXSLTTree = 0;
 1405: static int xmlXPathDebugObjCounterAll = 0;
 1406: 
 1407: static int xmlXPathDebugObjTotalUndefined = 0;
 1408: static int xmlXPathDebugObjTotalNodeset = 0;
 1409: static int xmlXPathDebugObjTotalBool = 0;
 1410: static int xmlXPathDebugObjTotalNumber = 0;
 1411: static int xmlXPathDebugObjTotalString = 0;
 1412: static int xmlXPathDebugObjTotalPoint = 0;
 1413: static int xmlXPathDebugObjTotalRange = 0;
 1414: static int xmlXPathDebugObjTotalLocset = 0;
 1415: static int xmlXPathDebugObjTotalUsers = 0;
 1416: static int xmlXPathDebugObjTotalXSLTTree = 0;
 1417: static int xmlXPathDebugObjTotalAll = 0;
 1418: 
 1419: static int xmlXPathDebugObjMaxUndefined = 0;
 1420: static int xmlXPathDebugObjMaxNodeset = 0;
 1421: static int xmlXPathDebugObjMaxBool = 0;
 1422: static int xmlXPathDebugObjMaxNumber = 0;
 1423: static int xmlXPathDebugObjMaxString = 0;
 1424: static int xmlXPathDebugObjMaxPoint = 0;
 1425: static int xmlXPathDebugObjMaxRange = 0;
 1426: static int xmlXPathDebugObjMaxLocset = 0;
 1427: static int xmlXPathDebugObjMaxUsers = 0;
 1428: static int xmlXPathDebugObjMaxXSLTTree = 0;
 1429: static int xmlXPathDebugObjMaxAll = 0;
 1430: 
 1431: /* REVISIT TODO: Make this static when committing */
 1432: static void
 1433: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
 1434: {
 1435:     if (ctxt != NULL) {
 1436: 	if (ctxt->cache != NULL) {
 1437: 	    xmlXPathContextCachePtr cache =
 1438: 		(xmlXPathContextCachePtr) ctxt->cache;
 1439: 
 1440: 	    cache->dbgCachedAll = 0;
 1441: 	    cache->dbgCachedNodeset = 0;
 1442: 	    cache->dbgCachedString = 0;
 1443: 	    cache->dbgCachedBool = 0;
 1444: 	    cache->dbgCachedNumber = 0;
 1445: 	    cache->dbgCachedPoint = 0;
 1446: 	    cache->dbgCachedRange = 0;
 1447: 	    cache->dbgCachedLocset = 0;
 1448: 	    cache->dbgCachedUsers = 0;
 1449: 	    cache->dbgCachedXSLTTree = 0;
 1450: 	    cache->dbgCachedUndefined = 0;
 1451: 
 1452: 	    cache->dbgReusedAll = 0;
 1453: 	    cache->dbgReusedNodeset = 0;
 1454: 	    cache->dbgReusedString = 0;
 1455: 	    cache->dbgReusedBool = 0;
 1456: 	    cache->dbgReusedNumber = 0;
 1457: 	    cache->dbgReusedPoint = 0;
 1458: 	    cache->dbgReusedRange = 0;
 1459: 	    cache->dbgReusedLocset = 0;
 1460: 	    cache->dbgReusedUsers = 0;
 1461: 	    cache->dbgReusedXSLTTree = 0;
 1462: 	    cache->dbgReusedUndefined = 0;
 1463: 	}
 1464:     }
 1465: 
 1466:     xmlXPathDebugObjCounterUndefined = 0;
 1467:     xmlXPathDebugObjCounterNodeset = 0;
 1468:     xmlXPathDebugObjCounterBool = 0;
 1469:     xmlXPathDebugObjCounterNumber = 0;
 1470:     xmlXPathDebugObjCounterString = 0;
 1471:     xmlXPathDebugObjCounterPoint = 0;
 1472:     xmlXPathDebugObjCounterRange = 0;
 1473:     xmlXPathDebugObjCounterLocset = 0;
 1474:     xmlXPathDebugObjCounterUsers = 0;
 1475:     xmlXPathDebugObjCounterXSLTTree = 0;
 1476:     xmlXPathDebugObjCounterAll = 0;
 1477: 
 1478:     xmlXPathDebugObjTotalUndefined = 0;
 1479:     xmlXPathDebugObjTotalNodeset = 0;
 1480:     xmlXPathDebugObjTotalBool = 0;
 1481:     xmlXPathDebugObjTotalNumber = 0;
 1482:     xmlXPathDebugObjTotalString = 0;
 1483:     xmlXPathDebugObjTotalPoint = 0;
 1484:     xmlXPathDebugObjTotalRange = 0;
 1485:     xmlXPathDebugObjTotalLocset = 0;
 1486:     xmlXPathDebugObjTotalUsers = 0;
 1487:     xmlXPathDebugObjTotalXSLTTree = 0;
 1488:     xmlXPathDebugObjTotalAll = 0;
 1489: 
 1490:     xmlXPathDebugObjMaxUndefined = 0;
 1491:     xmlXPathDebugObjMaxNodeset = 0;
 1492:     xmlXPathDebugObjMaxBool = 0;
 1493:     xmlXPathDebugObjMaxNumber = 0;
 1494:     xmlXPathDebugObjMaxString = 0;
 1495:     xmlXPathDebugObjMaxPoint = 0;
 1496:     xmlXPathDebugObjMaxRange = 0;
 1497:     xmlXPathDebugObjMaxLocset = 0;
 1498:     xmlXPathDebugObjMaxUsers = 0;
 1499:     xmlXPathDebugObjMaxXSLTTree = 0;
 1500:     xmlXPathDebugObjMaxAll = 0;
 1501: 
 1502: }
 1503: 
 1504: static void
 1505: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
 1506: 			      xmlXPathObjectType objType)
 1507: {
 1508:     int isCached = 0;
 1509: 
 1510:     if (ctxt != NULL) {
 1511: 	if (ctxt->cache != NULL) {
 1512: 	    xmlXPathContextCachePtr cache =
 1513: 		(xmlXPathContextCachePtr) ctxt->cache;
 1514: 
 1515: 	    isCached = 1;
 1516: 
 1517: 	    cache->dbgReusedAll++;
 1518: 	    switch (objType) {
 1519: 		case XPATH_UNDEFINED:
 1520: 		    cache->dbgReusedUndefined++;
 1521: 		    break;
 1522: 		case XPATH_NODESET:
 1523: 		    cache->dbgReusedNodeset++;
 1524: 		    break;
 1525: 		case XPATH_BOOLEAN:
 1526: 		    cache->dbgReusedBool++;
 1527: 		    break;
 1528: 		case XPATH_NUMBER:
 1529: 		    cache->dbgReusedNumber++;
 1530: 		    break;
 1531: 		case XPATH_STRING:
 1532: 		    cache->dbgReusedString++;
 1533: 		    break;
 1534: 		case XPATH_POINT:
 1535: 		    cache->dbgReusedPoint++;
 1536: 		    break;
 1537: 		case XPATH_RANGE:
 1538: 		    cache->dbgReusedRange++;
 1539: 		    break;
 1540: 		case XPATH_LOCATIONSET:
 1541: 		    cache->dbgReusedLocset++;
 1542: 		    break;
 1543: 		case XPATH_USERS:
 1544: 		    cache->dbgReusedUsers++;
 1545: 		    break;
 1546: 		case XPATH_XSLT_TREE:
 1547: 		    cache->dbgReusedXSLTTree++;
 1548: 		    break;
 1549: 		default:
 1550: 		    break;
 1551: 	    }
 1552: 	}
 1553:     }
 1554: 
 1555:     switch (objType) {
 1556: 	case XPATH_UNDEFINED:
 1557: 	    if (! isCached)
 1558: 		xmlXPathDebugObjTotalUndefined++;
 1559: 	    xmlXPathDebugObjCounterUndefined++;
 1560: 	    if (xmlXPathDebugObjCounterUndefined >
 1561: 		xmlXPathDebugObjMaxUndefined)
 1562: 		xmlXPathDebugObjMaxUndefined =
 1563: 		    xmlXPathDebugObjCounterUndefined;
 1564: 	    break;
 1565: 	case XPATH_NODESET:
 1566: 	    if (! isCached)
 1567: 		xmlXPathDebugObjTotalNodeset++;
 1568: 	    xmlXPathDebugObjCounterNodeset++;
 1569: 	    if (xmlXPathDebugObjCounterNodeset >
 1570: 		xmlXPathDebugObjMaxNodeset)
 1571: 		xmlXPathDebugObjMaxNodeset =
 1572: 		    xmlXPathDebugObjCounterNodeset;
 1573: 	    break;
 1574: 	case XPATH_BOOLEAN:
 1575: 	    if (! isCached)
 1576: 		xmlXPathDebugObjTotalBool++;
 1577: 	    xmlXPathDebugObjCounterBool++;
 1578: 	    if (xmlXPathDebugObjCounterBool >
 1579: 		xmlXPathDebugObjMaxBool)
 1580: 		xmlXPathDebugObjMaxBool =
 1581: 		    xmlXPathDebugObjCounterBool;
 1582: 	    break;
 1583: 	case XPATH_NUMBER:
 1584: 	    if (! isCached)
 1585: 		xmlXPathDebugObjTotalNumber++;
 1586: 	    xmlXPathDebugObjCounterNumber++;
 1587: 	    if (xmlXPathDebugObjCounterNumber >
 1588: 		xmlXPathDebugObjMaxNumber)
 1589: 		xmlXPathDebugObjMaxNumber =
 1590: 		    xmlXPathDebugObjCounterNumber;
 1591: 	    break;
 1592: 	case XPATH_STRING:
 1593: 	    if (! isCached)
 1594: 		xmlXPathDebugObjTotalString++;
 1595: 	    xmlXPathDebugObjCounterString++;
 1596: 	    if (xmlXPathDebugObjCounterString >
 1597: 		xmlXPathDebugObjMaxString)
 1598: 		xmlXPathDebugObjMaxString =
 1599: 		    xmlXPathDebugObjCounterString;
 1600: 	    break;
 1601: 	case XPATH_POINT:
 1602: 	    if (! isCached)
 1603: 		xmlXPathDebugObjTotalPoint++;
 1604: 	    xmlXPathDebugObjCounterPoint++;
 1605: 	    if (xmlXPathDebugObjCounterPoint >
 1606: 		xmlXPathDebugObjMaxPoint)
 1607: 		xmlXPathDebugObjMaxPoint =
 1608: 		    xmlXPathDebugObjCounterPoint;
 1609: 	    break;
 1610: 	case XPATH_RANGE:
 1611: 	    if (! isCached)
 1612: 		xmlXPathDebugObjTotalRange++;
 1613: 	    xmlXPathDebugObjCounterRange++;
 1614: 	    if (xmlXPathDebugObjCounterRange >
 1615: 		xmlXPathDebugObjMaxRange)
 1616: 		xmlXPathDebugObjMaxRange =
 1617: 		    xmlXPathDebugObjCounterRange;
 1618: 	    break;
 1619: 	case XPATH_LOCATIONSET:
 1620: 	    if (! isCached)
 1621: 		xmlXPathDebugObjTotalLocset++;
 1622: 	    xmlXPathDebugObjCounterLocset++;
 1623: 	    if (xmlXPathDebugObjCounterLocset >
 1624: 		xmlXPathDebugObjMaxLocset)
 1625: 		xmlXPathDebugObjMaxLocset =
 1626: 		    xmlXPathDebugObjCounterLocset;
 1627: 	    break;
 1628: 	case XPATH_USERS:
 1629: 	    if (! isCached)
 1630: 		xmlXPathDebugObjTotalUsers++;
 1631: 	    xmlXPathDebugObjCounterUsers++;
 1632: 	    if (xmlXPathDebugObjCounterUsers >
 1633: 		xmlXPathDebugObjMaxUsers)
 1634: 		xmlXPathDebugObjMaxUsers =
 1635: 		    xmlXPathDebugObjCounterUsers;
 1636: 	    break;
 1637: 	case XPATH_XSLT_TREE:
 1638: 	    if (! isCached)
 1639: 		xmlXPathDebugObjTotalXSLTTree++;
 1640: 	    xmlXPathDebugObjCounterXSLTTree++;
 1641: 	    if (xmlXPathDebugObjCounterXSLTTree >
 1642: 		xmlXPathDebugObjMaxXSLTTree)
 1643: 		xmlXPathDebugObjMaxXSLTTree =
 1644: 		    xmlXPathDebugObjCounterXSLTTree;
 1645: 	    break;
 1646: 	default:
 1647: 	    break;
 1648:     }
 1649:     if (! isCached)
 1650: 	xmlXPathDebugObjTotalAll++;
 1651:     xmlXPathDebugObjCounterAll++;
 1652:     if (xmlXPathDebugObjCounterAll >
 1653: 	xmlXPathDebugObjMaxAll)
 1654: 	xmlXPathDebugObjMaxAll =
 1655: 	    xmlXPathDebugObjCounterAll;
 1656: }
 1657: 
 1658: static void
 1659: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
 1660: 			      xmlXPathObjectType objType)
 1661: {
 1662:     int isCached = 0;
 1663: 
 1664:     if (ctxt != NULL) {
 1665: 	if (ctxt->cache != NULL) {
 1666: 	    xmlXPathContextCachePtr cache =
 1667: 		(xmlXPathContextCachePtr) ctxt->cache;
 1668: 
 1669: 	    isCached = 1;
 1670: 
 1671: 	    cache->dbgCachedAll++;
 1672: 	    switch (objType) {
 1673: 		case XPATH_UNDEFINED:
 1674: 		    cache->dbgCachedUndefined++;
 1675: 		    break;
 1676: 		case XPATH_NODESET:
 1677: 		    cache->dbgCachedNodeset++;
 1678: 		    break;
 1679: 		case XPATH_BOOLEAN:
 1680: 		    cache->dbgCachedBool++;
 1681: 		    break;
 1682: 		case XPATH_NUMBER:
 1683: 		    cache->dbgCachedNumber++;
 1684: 		    break;
 1685: 		case XPATH_STRING:
 1686: 		    cache->dbgCachedString++;
 1687: 		    break;
 1688: 		case XPATH_POINT:
 1689: 		    cache->dbgCachedPoint++;
 1690: 		    break;
 1691: 		case XPATH_RANGE:
 1692: 		    cache->dbgCachedRange++;
 1693: 		    break;
 1694: 		case XPATH_LOCATIONSET:
 1695: 		    cache->dbgCachedLocset++;
 1696: 		    break;
 1697: 		case XPATH_USERS:
 1698: 		    cache->dbgCachedUsers++;
 1699: 		    break;
 1700: 		case XPATH_XSLT_TREE:
 1701: 		    cache->dbgCachedXSLTTree++;
 1702: 		    break;
 1703: 		default:
 1704: 		    break;
 1705: 	    }
 1706: 
 1707: 	}
 1708:     }
 1709:     switch (objType) {
 1710: 	case XPATH_UNDEFINED:
 1711: 	    xmlXPathDebugObjCounterUndefined--;
 1712: 	    break;
 1713: 	case XPATH_NODESET:
 1714: 	    xmlXPathDebugObjCounterNodeset--;
 1715: 	    break;
 1716: 	case XPATH_BOOLEAN:
 1717: 	    xmlXPathDebugObjCounterBool--;
 1718: 	    break;
 1719: 	case XPATH_NUMBER:
 1720: 	    xmlXPathDebugObjCounterNumber--;
 1721: 	    break;
 1722: 	case XPATH_STRING:
 1723: 	    xmlXPathDebugObjCounterString--;
 1724: 	    break;
 1725: 	case XPATH_POINT:
 1726: 	    xmlXPathDebugObjCounterPoint--;
 1727: 	    break;
 1728: 	case XPATH_RANGE:
 1729: 	    xmlXPathDebugObjCounterRange--;
 1730: 	    break;
 1731: 	case XPATH_LOCATIONSET:
 1732: 	    xmlXPathDebugObjCounterLocset--;
 1733: 	    break;
 1734: 	case XPATH_USERS:
 1735: 	    xmlXPathDebugObjCounterUsers--;
 1736: 	    break;
 1737: 	case XPATH_XSLT_TREE:
 1738: 	    xmlXPathDebugObjCounterXSLTTree--;
 1739: 	    break;
 1740: 	default:
 1741: 	    break;
 1742:     }
 1743:     xmlXPathDebugObjCounterAll--;
 1744: }
 1745: 
 1746: /* REVISIT TODO: Make this static when committing */
 1747: static void
 1748: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
 1749: {
 1750:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
 1751: 	reqXSLTTree, reqUndefined;
 1752:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
 1753: 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
 1754:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
 1755: 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
 1756:     int leftObjs = xmlXPathDebugObjCounterAll;
 1757: 
 1758:     reqAll = xmlXPathDebugObjTotalAll;
 1759:     reqNodeset = xmlXPathDebugObjTotalNodeset;
 1760:     reqString = xmlXPathDebugObjTotalString;
 1761:     reqBool = xmlXPathDebugObjTotalBool;
 1762:     reqNumber = xmlXPathDebugObjTotalNumber;
 1763:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
 1764:     reqUndefined = xmlXPathDebugObjTotalUndefined;
 1765: 
 1766:     printf("# XPath object usage:\n");
 1767: 
 1768:     if (ctxt != NULL) {
 1769: 	if (ctxt->cache != NULL) {
 1770: 	    xmlXPathContextCachePtr cache =
 1771: 		(xmlXPathContextCachePtr) ctxt->cache;
 1772: 
 1773: 	    reAll = cache->dbgReusedAll;
 1774: 	    reqAll += reAll;
 1775: 	    reNodeset = cache->dbgReusedNodeset;
 1776: 	    reqNodeset += reNodeset;
 1777: 	    reString = cache->dbgReusedString;
 1778: 	    reqString += reString;
 1779: 	    reBool = cache->dbgReusedBool;
 1780: 	    reqBool += reBool;
 1781: 	    reNumber = cache->dbgReusedNumber;
 1782: 	    reqNumber += reNumber;
 1783: 	    reXSLTTree = cache->dbgReusedXSLTTree;
 1784: 	    reqXSLTTree += reXSLTTree;
 1785: 	    reUndefined = cache->dbgReusedUndefined;
 1786: 	    reqUndefined += reUndefined;
 1787: 
 1788: 	    caAll = cache->dbgCachedAll;
 1789: 	    caBool = cache->dbgCachedBool;
 1790: 	    caNodeset = cache->dbgCachedNodeset;
 1791: 	    caString = cache->dbgCachedString;
 1792: 	    caNumber = cache->dbgCachedNumber;
 1793: 	    caXSLTTree = cache->dbgCachedXSLTTree;
 1794: 	    caUndefined = cache->dbgCachedUndefined;
 1795: 
 1796: 	    if (cache->nodesetObjs)
 1797: 		leftObjs -= cache->nodesetObjs->number;
 1798: 	    if (cache->stringObjs)
 1799: 		leftObjs -= cache->stringObjs->number;
 1800: 	    if (cache->booleanObjs)
 1801: 		leftObjs -= cache->booleanObjs->number;
 1802: 	    if (cache->numberObjs)
 1803: 		leftObjs -= cache->numberObjs->number;
 1804: 	    if (cache->miscObjs)
 1805: 		leftObjs -= cache->miscObjs->number;
 1806: 	}
 1807:     }
 1808: 
 1809:     printf("# all\n");
 1810:     printf("#   total  : %d\n", reqAll);
 1811:     printf("#   left  : %d\n", leftObjs);
 1812:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
 1813:     printf("#   reused : %d\n", reAll);
 1814:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
 1815: 
 1816:     printf("# node-sets\n");
 1817:     printf("#   total  : %d\n", reqNodeset);
 1818:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
 1819:     printf("#   reused : %d\n", reNodeset);
 1820:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
 1821: 
 1822:     printf("# strings\n");
 1823:     printf("#   total  : %d\n", reqString);
 1824:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
 1825:     printf("#   reused : %d\n", reString);
 1826:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
 1827: 
 1828:     printf("# booleans\n");
 1829:     printf("#   total  : %d\n", reqBool);
 1830:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
 1831:     printf("#   reused : %d\n", reBool);
 1832:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
 1833: 
 1834:     printf("# numbers\n");
 1835:     printf("#   total  : %d\n", reqNumber);
 1836:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
 1837:     printf("#   reused : %d\n", reNumber);
 1838:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
 1839: 
 1840:     printf("# XSLT result tree fragments\n");
 1841:     printf("#   total  : %d\n", reqXSLTTree);
 1842:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
 1843:     printf("#   reused : %d\n", reXSLTTree);
 1844:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
 1845: 
 1846:     printf("# undefined\n");
 1847:     printf("#   total  : %d\n", reqUndefined);
 1848:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
 1849:     printf("#   reused : %d\n", reUndefined);
 1850:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
 1851: 
 1852: }
 1853: 
 1854: #endif /* XP_DEBUG_OBJ_USAGE */
 1855: 
 1856: #endif /* LIBXML_DEBUG_ENABLED */
 1857: 
 1858: /************************************************************************
 1859:  *									*
 1860:  *			XPath object caching				*
 1861:  *									*
 1862:  ************************************************************************/
 1863: 
 1864: /**
 1865:  * xmlXPathNewCache:
 1866:  *
 1867:  * Create a new object cache
 1868:  *
 1869:  * Returns the xmlXPathCache just allocated.
 1870:  */
 1871: static xmlXPathContextCachePtr
 1872: xmlXPathNewCache(void)
 1873: {
 1874:     xmlXPathContextCachePtr ret;
 1875: 
 1876:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
 1877:     if (ret == NULL) {
 1878:         xmlXPathErrMemory(NULL, "creating object cache\n");
 1879: 	return(NULL);
 1880:     }
 1881:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
 1882:     ret->maxNodeset = 100;
 1883:     ret->maxString = 100;
 1884:     ret->maxBoolean = 100;
 1885:     ret->maxNumber = 100;
 1886:     ret->maxMisc = 100;
 1887:     return(ret);
 1888: }
 1889: 
 1890: static void
 1891: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
 1892: {
 1893:     int i;
 1894:     xmlXPathObjectPtr obj;
 1895: 
 1896:     if (list == NULL)
 1897: 	return;
 1898: 
 1899:     for (i = 0; i < list->number; i++) {
 1900: 	obj = list->items[i];
 1901: 	/*
 1902: 	* Note that it is already assured that we don't need to
 1903: 	* look out for namespace nodes in the node-set.
 1904: 	*/
 1905: 	if (obj->nodesetval != NULL) {
 1906: 	    if (obj->nodesetval->nodeTab != NULL)
 1907: 		xmlFree(obj->nodesetval->nodeTab);
 1908: 	    xmlFree(obj->nodesetval);
 1909: 	}
 1910: 	xmlFree(obj);
 1911: #ifdef XP_DEBUG_OBJ_USAGE
 1912: 	xmlXPathDebugObjCounterAll--;
 1913: #endif
 1914:     }
 1915:     xmlPointerListFree(list);
 1916: }
 1917: 
 1918: static void
 1919: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
 1920: {
 1921:     if (cache == NULL)
 1922: 	return;
 1923:     if (cache->nodesetObjs)
 1924: 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
 1925:     if (cache->stringObjs)
 1926: 	xmlXPathCacheFreeObjectList(cache->stringObjs);
 1927:     if (cache->booleanObjs)
 1928: 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
 1929:     if (cache->numberObjs)
 1930: 	xmlXPathCacheFreeObjectList(cache->numberObjs);
 1931:     if (cache->miscObjs)
 1932: 	xmlXPathCacheFreeObjectList(cache->miscObjs);
 1933:     xmlFree(cache);
 1934: }
 1935: 
 1936: /**
 1937:  * xmlXPathContextSetCache:
 1938:  *
 1939:  * @ctxt:  the XPath context
 1940:  * @active: enables/disables (creates/frees) the cache
 1941:  * @value: a value with semantics dependant on @options
 1942:  * @options: options (currently only the value 0 is used)
 1943:  *
 1944:  * Creates/frees an object cache on the XPath context.
 1945:  * If activates XPath objects (xmlXPathObject) will be cached internally
 1946:  * to be reused.
 1947:  * @options:
 1948:  *   0: This will set the XPath object caching:
 1949:  *      @value:
 1950:  *        This will set the maximum number of XPath objects
 1951:  *        to be cached per slot
 1952:  *        There are 5 slots for: node-set, string, number, boolean, and
 1953:  *        misc objects. Use <0 for the default number (100).
 1954:  *   Other values for @options have currently no effect.
 1955:  *
 1956:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
 1957:  */
 1958: int
 1959: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
 1960: 			int active,
 1961: 			int value,
 1962: 			int options)
 1963: {
 1964:     if (ctxt == NULL)
 1965: 	return(-1);
 1966:     if (active) {
 1967: 	xmlXPathContextCachePtr cache;
 1968: 
 1969: 	if (ctxt->cache == NULL) {
 1970: 	    ctxt->cache = xmlXPathNewCache();
 1971: 	    if (ctxt->cache == NULL)
 1972: 		return(-1);
 1973: 	}
 1974: 	cache = (xmlXPathContextCachePtr) ctxt->cache;
 1975: 	if (options == 0) {
 1976: 	    if (value < 0)
 1977: 		value = 100;
 1978: 	    cache->maxNodeset = value;
 1979: 	    cache->maxString = value;
 1980: 	    cache->maxNumber = value;
 1981: 	    cache->maxBoolean = value;
 1982: 	    cache->maxMisc = value;
 1983: 	}
 1984:     } else if (ctxt->cache != NULL) {
 1985: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 1986: 	ctxt->cache = NULL;
 1987:     }
 1988:     return(0);
 1989: }
 1990: 
 1991: /**
 1992:  * xmlXPathCacheWrapNodeSet:
 1993:  * @ctxt: the XPath context
 1994:  * @val:  the NodePtr value
 1995:  *
 1996:  * This is the cached version of xmlXPathWrapNodeSet().
 1997:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 1998:  *
 1999:  * Returns the created or reused object.
 2000:  */
 2001: static xmlXPathObjectPtr
 2002: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
 2003: {
 2004:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 2005: 	xmlXPathContextCachePtr cache =
 2006: 	    (xmlXPathContextCachePtr) ctxt->cache;
 2007: 
 2008: 	if ((cache->miscObjs != NULL) &&
 2009: 	    (cache->miscObjs->number != 0))
 2010: 	{
 2011: 	    xmlXPathObjectPtr ret;
 2012: 
 2013: 	    ret = (xmlXPathObjectPtr)
 2014: 		cache->miscObjs->items[--cache->miscObjs->number];
 2015: 	    ret->type = XPATH_NODESET;
 2016: 	    ret->nodesetval = val;
 2017: #ifdef XP_DEBUG_OBJ_USAGE
 2018: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2019: #endif
 2020: 	    return(ret);
 2021: 	}
 2022:     }
 2023: 
 2024:     return(xmlXPathWrapNodeSet(val));
 2025: 
 2026: }
 2027: 
 2028: /**
 2029:  * xmlXPathCacheWrapString:
 2030:  * @ctxt: the XPath context
 2031:  * @val:  the xmlChar * value
 2032:  *
 2033:  * This is the cached version of xmlXPathWrapString().
 2034:  * Wraps the @val string into an XPath object.
 2035:  *
 2036:  * Returns the created or reused object.
 2037:  */
 2038: static xmlXPathObjectPtr
 2039: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
 2040: {
 2041:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 2042: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2043: 
 2044: 	if ((cache->stringObjs != NULL) &&
 2045: 	    (cache->stringObjs->number != 0))
 2046: 	{
 2047: 
 2048: 	    xmlXPathObjectPtr ret;
 2049: 
 2050: 	    ret = (xmlXPathObjectPtr)
 2051: 		cache->stringObjs->items[--cache->stringObjs->number];
 2052: 	    ret->type = XPATH_STRING;
 2053: 	    ret->stringval = val;
 2054: #ifdef XP_DEBUG_OBJ_USAGE
 2055: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2056: #endif
 2057: 	    return(ret);
 2058: 	} else if ((cache->miscObjs != NULL) &&
 2059: 	    (cache->miscObjs->number != 0))
 2060: 	{
 2061: 	    xmlXPathObjectPtr ret;
 2062: 	    /*
 2063: 	    * Fallback to misc-cache.
 2064: 	    */
 2065: 	    ret = (xmlXPathObjectPtr)
 2066: 		cache->miscObjs->items[--cache->miscObjs->number];
 2067: 
 2068: 	    ret->type = XPATH_STRING;
 2069: 	    ret->stringval = val;
 2070: #ifdef XP_DEBUG_OBJ_USAGE
 2071: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2072: #endif
 2073: 	    return(ret);
 2074: 	}
 2075:     }
 2076:     return(xmlXPathWrapString(val));
 2077: }
 2078: 
 2079: /**
 2080:  * xmlXPathCacheNewNodeSet:
 2081:  * @ctxt: the XPath context
 2082:  * @val:  the NodePtr value
 2083:  *
 2084:  * This is the cached version of xmlXPathNewNodeSet().
 2085:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
 2086:  * it with the single Node @val
 2087:  *
 2088:  * Returns the created or reused object.
 2089:  */
 2090: static xmlXPathObjectPtr
 2091: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
 2092: {
 2093:     if ((ctxt != NULL) && (ctxt->cache)) {
 2094: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2095: 
 2096: 	if ((cache->nodesetObjs != NULL) &&
 2097: 	    (cache->nodesetObjs->number != 0))
 2098: 	{
 2099: 	    xmlXPathObjectPtr ret;
 2100: 	    /*
 2101: 	    * Use the nodset-cache.
 2102: 	    */
 2103: 	    ret = (xmlXPathObjectPtr)
 2104: 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
 2105: 	    ret->type = XPATH_NODESET;
 2106: 	    ret->boolval = 0;
 2107: 	    if (val) {
 2108: 		if ((ret->nodesetval->nodeMax == 0) ||
 2109: 		    (val->type == XML_NAMESPACE_DECL))
 2110: 		{
 2111: 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
 2112: 		} else {
 2113: 		    ret->nodesetval->nodeTab[0] = val;
 2114: 		    ret->nodesetval->nodeNr = 1;
 2115: 		}
 2116: 	    }
 2117: #ifdef XP_DEBUG_OBJ_USAGE
 2118: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2119: #endif
 2120: 	    return(ret);
 2121: 	} else if ((cache->miscObjs != NULL) &&
 2122: 	    (cache->miscObjs->number != 0))
 2123: 	{
 2124: 	    xmlXPathObjectPtr ret;
 2125: 	    /*
 2126: 	    * Fallback to misc-cache.
 2127: 	    */
 2128: 
 2129: 	    ret = (xmlXPathObjectPtr)
 2130: 		cache->miscObjs->items[--cache->miscObjs->number];
 2131: 
 2132: 	    ret->type = XPATH_NODESET;
 2133: 	    ret->boolval = 0;
 2134: 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
 2135: 	    if (ret->nodesetval == NULL) {
 2136: 		ctxt->lastError.domain = XML_FROM_XPATH;
 2137: 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
 2138: 		return(NULL);
 2139: 	    }
 2140: #ifdef XP_DEBUG_OBJ_USAGE
 2141: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2142: #endif
 2143: 	    return(ret);
 2144: 	}
 2145:     }
 2146:     return(xmlXPathNewNodeSet(val));
 2147: }
 2148: 
 2149: /**
 2150:  * xmlXPathCacheNewCString:
 2151:  * @ctxt: the XPath context
 2152:  * @val:  the char * value
 2153:  *
 2154:  * This is the cached version of xmlXPathNewCString().
 2155:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2156:  *
 2157:  * Returns the created or reused object.
 2158:  */
 2159: static xmlXPathObjectPtr
 2160: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
 2161: {
 2162:     if ((ctxt != NULL) && (ctxt->cache)) {
 2163: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2164: 
 2165: 	if ((cache->stringObjs != NULL) &&
 2166: 	    (cache->stringObjs->number != 0))
 2167: 	{
 2168: 	    xmlXPathObjectPtr ret;
 2169: 
 2170: 	    ret = (xmlXPathObjectPtr)
 2171: 		cache->stringObjs->items[--cache->stringObjs->number];
 2172: 
 2173: 	    ret->type = XPATH_STRING;
 2174: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2175: #ifdef XP_DEBUG_OBJ_USAGE
 2176: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2177: #endif
 2178: 	    return(ret);
 2179: 	} else if ((cache->miscObjs != NULL) &&
 2180: 	    (cache->miscObjs->number != 0))
 2181: 	{
 2182: 	    xmlXPathObjectPtr ret;
 2183: 
 2184: 	    ret = (xmlXPathObjectPtr)
 2185: 		cache->miscObjs->items[--cache->miscObjs->number];
 2186: 
 2187: 	    ret->type = XPATH_STRING;
 2188: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2189: #ifdef XP_DEBUG_OBJ_USAGE
 2190: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2191: #endif
 2192: 	    return(ret);
 2193: 	}
 2194:     }
 2195:     return(xmlXPathNewCString(val));
 2196: }
 2197: 
 2198: /**
 2199:  * xmlXPathCacheNewString:
 2200:  * @ctxt: the XPath context
 2201:  * @val:  the xmlChar * value
 2202:  *
 2203:  * This is the cached version of xmlXPathNewString().
 2204:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2205:  *
 2206:  * Returns the created or reused object.
 2207:  */
 2208: static xmlXPathObjectPtr
 2209: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
 2210: {
 2211:     if ((ctxt != NULL) && (ctxt->cache)) {
 2212: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2213: 
 2214: 	if ((cache->stringObjs != NULL) &&
 2215: 	    (cache->stringObjs->number != 0))
 2216: 	{
 2217: 	    xmlXPathObjectPtr ret;
 2218: 
 2219: 	    ret = (xmlXPathObjectPtr)
 2220: 		cache->stringObjs->items[--cache->stringObjs->number];
 2221: 	    ret->type = XPATH_STRING;
 2222: 	    if (val != NULL)
 2223: 		ret->stringval = xmlStrdup(val);
 2224: 	    else
 2225: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2226: #ifdef XP_DEBUG_OBJ_USAGE
 2227: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2228: #endif
 2229: 	    return(ret);
 2230: 	} else if ((cache->miscObjs != NULL) &&
 2231: 	    (cache->miscObjs->number != 0))
 2232: 	{
 2233: 	    xmlXPathObjectPtr ret;
 2234: 
 2235: 	    ret = (xmlXPathObjectPtr)
 2236: 		cache->miscObjs->items[--cache->miscObjs->number];
 2237: 
 2238: 	    ret->type = XPATH_STRING;
 2239: 	    if (val != NULL)
 2240: 		ret->stringval = xmlStrdup(val);
 2241: 	    else
 2242: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2243: #ifdef XP_DEBUG_OBJ_USAGE
 2244: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2245: #endif
 2246: 	    return(ret);
 2247: 	}
 2248:     }
 2249:     return(xmlXPathNewString(val));
 2250: }
 2251: 
 2252: /**
 2253:  * xmlXPathCacheNewBoolean:
 2254:  * @ctxt: the XPath context
 2255:  * @val:  the boolean value
 2256:  *
 2257:  * This is the cached version of xmlXPathNewBoolean().
 2258:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
 2259:  *
 2260:  * Returns the created or reused object.
 2261:  */
 2262: static xmlXPathObjectPtr
 2263: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
 2264: {
 2265:     if ((ctxt != NULL) && (ctxt->cache)) {
 2266: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2267: 
 2268: 	if ((cache->booleanObjs != NULL) &&
 2269: 	    (cache->booleanObjs->number != 0))
 2270: 	{
 2271: 	    xmlXPathObjectPtr ret;
 2272: 
 2273: 	    ret = (xmlXPathObjectPtr)
 2274: 		cache->booleanObjs->items[--cache->booleanObjs->number];
 2275: 	    ret->type = XPATH_BOOLEAN;
 2276: 	    ret->boolval = (val != 0);
 2277: #ifdef XP_DEBUG_OBJ_USAGE
 2278: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2279: #endif
 2280: 	    return(ret);
 2281: 	} else if ((cache->miscObjs != NULL) &&
 2282: 	    (cache->miscObjs->number != 0))
 2283: 	{
 2284: 	    xmlXPathObjectPtr ret;
 2285: 
 2286: 	    ret = (xmlXPathObjectPtr)
 2287: 		cache->miscObjs->items[--cache->miscObjs->number];
 2288: 
 2289: 	    ret->type = XPATH_BOOLEAN;
 2290: 	    ret->boolval = (val != 0);
 2291: #ifdef XP_DEBUG_OBJ_USAGE
 2292: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2293: #endif
 2294: 	    return(ret);
 2295: 	}
 2296:     }
 2297:     return(xmlXPathNewBoolean(val));
 2298: }
 2299: 
 2300: /**
 2301:  * xmlXPathCacheNewFloat:
 2302:  * @ctxt: the XPath context
 2303:  * @val:  the double value
 2304:  *
 2305:  * This is the cached version of xmlXPathNewFloat().
 2306:  * Acquires an xmlXPathObjectPtr of type double and of value @val
 2307:  *
 2308:  * Returns the created or reused object.
 2309:  */
 2310: static xmlXPathObjectPtr
 2311: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
 2312: {
 2313:      if ((ctxt != NULL) && (ctxt->cache)) {
 2314: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2315: 
 2316: 	if ((cache->numberObjs != NULL) &&
 2317: 	    (cache->numberObjs->number != 0))
 2318: 	{
 2319: 	    xmlXPathObjectPtr ret;
 2320: 
 2321: 	    ret = (xmlXPathObjectPtr)
 2322: 		cache->numberObjs->items[--cache->numberObjs->number];
 2323: 	    ret->type = XPATH_NUMBER;
 2324: 	    ret->floatval = val;
 2325: #ifdef XP_DEBUG_OBJ_USAGE
 2326: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2327: #endif
 2328: 	    return(ret);
 2329: 	} else if ((cache->miscObjs != NULL) &&
 2330: 	    (cache->miscObjs->number != 0))
 2331: 	{
 2332: 	    xmlXPathObjectPtr ret;
 2333: 
 2334: 	    ret = (xmlXPathObjectPtr)
 2335: 		cache->miscObjs->items[--cache->miscObjs->number];
 2336: 
 2337: 	    ret->type = XPATH_NUMBER;
 2338: 	    ret->floatval = val;
 2339: #ifdef XP_DEBUG_OBJ_USAGE
 2340: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2341: #endif
 2342: 	    return(ret);
 2343: 	}
 2344:     }
 2345:     return(xmlXPathNewFloat(val));
 2346: }
 2347: 
 2348: /**
 2349:  * xmlXPathCacheConvertString:
 2350:  * @ctxt: the XPath context
 2351:  * @val:  an XPath object
 2352:  *
 2353:  * This is the cached version of xmlXPathConvertString().
 2354:  * Converts an existing object to its string() equivalent
 2355:  *
 2356:  * Returns a created or reused object, the old one is freed (cached)
 2357:  *         (or the operation is done directly on @val)
 2358:  */
 2359: 
 2360: static xmlXPathObjectPtr
 2361: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2362:     xmlChar *res = NULL;
 2363: 
 2364:     if (val == NULL)
 2365: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2366: 
 2367:     switch (val->type) {
 2368:     case XPATH_UNDEFINED:
 2369: #ifdef DEBUG_EXPR
 2370: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 2371: #endif
 2372: 	break;
 2373:     case XPATH_NODESET:
 2374:     case XPATH_XSLT_TREE:
 2375: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 2376: 	break;
 2377:     case XPATH_STRING:
 2378: 	return(val);
 2379:     case XPATH_BOOLEAN:
 2380: 	res = xmlXPathCastBooleanToString(val->boolval);
 2381: 	break;
 2382:     case XPATH_NUMBER:
 2383: 	res = xmlXPathCastNumberToString(val->floatval);
 2384: 	break;
 2385:     case XPATH_USERS:
 2386:     case XPATH_POINT:
 2387:     case XPATH_RANGE:
 2388:     case XPATH_LOCATIONSET:
 2389: 	TODO;
 2390: 	break;
 2391:     }
 2392:     xmlXPathReleaseObject(ctxt, val);
 2393:     if (res == NULL)
 2394: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2395:     return(xmlXPathCacheWrapString(ctxt, res));
 2396: }
 2397: 
 2398: /**
 2399:  * xmlXPathCacheObjectCopy:
 2400:  * @ctxt: the XPath context
 2401:  * @val:  the original object
 2402:  *
 2403:  * This is the cached version of xmlXPathObjectCopy().
 2404:  * Acquire a copy of a given object
 2405:  *
 2406:  * Returns a created or reused created object.
 2407:  */
 2408: static xmlXPathObjectPtr
 2409: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
 2410: {
 2411:     if (val == NULL)
 2412: 	return(NULL);
 2413: 
 2414:     if (XP_HAS_CACHE(ctxt)) {
 2415: 	switch (val->type) {
 2416: 	    case XPATH_NODESET:
 2417: 		return(xmlXPathCacheWrapNodeSet(ctxt,
 2418: 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
 2419: 	    case XPATH_STRING:
 2420: 		return(xmlXPathCacheNewString(ctxt, val->stringval));
 2421: 	    case XPATH_BOOLEAN:
 2422: 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
 2423: 	    case XPATH_NUMBER:
 2424: 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
 2425: 	    default:
 2426: 		break;
 2427: 	}
 2428:     }
 2429:     return(xmlXPathObjectCopy(val));
 2430: }
 2431: 
 2432: /**
 2433:  * xmlXPathCacheConvertBoolean:
 2434:  * @ctxt: the XPath context
 2435:  * @val:  an XPath object
 2436:  *
 2437:  * This is the cached version of xmlXPathConvertBoolean().
 2438:  * Converts an existing object to its boolean() equivalent
 2439:  *
 2440:  * Returns a created or reused object, the old one is freed (or the operation
 2441:  *         is done directly on @val)
 2442:  */
 2443: static xmlXPathObjectPtr
 2444: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2445:     xmlXPathObjectPtr ret;
 2446: 
 2447:     if (val == NULL)
 2448: 	return(xmlXPathCacheNewBoolean(ctxt, 0));
 2449:     if (val->type == XPATH_BOOLEAN)
 2450: 	return(val);
 2451:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
 2452:     xmlXPathReleaseObject(ctxt, val);
 2453:     return(ret);
 2454: }
 2455: 
 2456: /**
 2457:  * xmlXPathCacheConvertNumber:
 2458:  * @ctxt: the XPath context
 2459:  * @val:  an XPath object
 2460:  *
 2461:  * This is the cached version of xmlXPathConvertNumber().
 2462:  * Converts an existing object to its number() equivalent
 2463:  *
 2464:  * Returns a created or reused object, the old one is freed (or the operation
 2465:  *         is done directly on @val)
 2466:  */
 2467: static xmlXPathObjectPtr
 2468: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2469:     xmlXPathObjectPtr ret;
 2470: 
 2471:     if (val == NULL)
 2472: 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
 2473:     if (val->type == XPATH_NUMBER)
 2474: 	return(val);
 2475:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
 2476:     xmlXPathReleaseObject(ctxt, val);
 2477:     return(ret);
 2478: }
 2479: 
 2480: /************************************************************************
 2481:  *									*
 2482:  *		Parser stacks related functions and macros		*
 2483:  *									*
 2484:  ************************************************************************/
 2485: 
 2486: /**
 2487:  * xmlXPathSetFrame:
 2488:  * @ctxt: an XPath parser context
 2489:  *
 2490:  * Set the callee evaluation frame
 2491:  *
 2492:  * Returns the previous frame value to be restored once done
 2493:  */
 2494: static int
 2495: xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
 2496:     int ret;
 2497: 
 2498:     if (ctxt == NULL)
 2499:         return(0);
 2500:     ret = ctxt->valueFrame;
 2501:     ctxt->valueFrame = ctxt->valueNr;
 2502:     return(ret);
 2503: }
 2504: 
 2505: /**
 2506:  * xmlXPathPopFrame:
 2507:  * @ctxt: an XPath parser context
 2508:  * @frame: the previous frame value
 2509:  *
 2510:  * Remove the callee evaluation frame
 2511:  */
 2512: static void
 2513: xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
 2514:     if (ctxt == NULL)
 2515:         return;
 2516:     if (ctxt->valueNr < ctxt->valueFrame) {
 2517:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
 2518:     }
 2519:     ctxt->valueFrame = frame;
 2520: }
 2521: 
 2522: /**
 2523:  * valuePop:
 2524:  * @ctxt: an XPath evaluation context
 2525:  *
 2526:  * Pops the top XPath object from the value stack
 2527:  *
 2528:  * Returns the XPath object just removed
 2529:  */
 2530: xmlXPathObjectPtr
 2531: valuePop(xmlXPathParserContextPtr ctxt)
 2532: {
 2533:     xmlXPathObjectPtr ret;
 2534: 
 2535:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
 2536:         return (NULL);
 2537: 
 2538:     if (ctxt->valueNr <= ctxt->valueFrame) {
 2539:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
 2540:         return (NULL);
 2541:     }
 2542: 
 2543:     ctxt->valueNr--;
 2544:     if (ctxt->valueNr > 0)
 2545:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
 2546:     else
 2547:         ctxt->value = NULL;
 2548:     ret = ctxt->valueTab[ctxt->valueNr];
 2549:     ctxt->valueTab[ctxt->valueNr] = NULL;
 2550:     return (ret);
 2551: }
 2552: /**
 2553:  * valuePush:
 2554:  * @ctxt:  an XPath evaluation context
 2555:  * @value:  the XPath object
 2556:  *
 2557:  * Pushes a new XPath object on top of the value stack
 2558:  *
 2559:  * returns the number of items on the value stack
 2560:  */
 2561: int
 2562: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
 2563: {
 2564:     if ((ctxt == NULL) || (value == NULL)) return(-1);
 2565:     if (ctxt->valueNr >= ctxt->valueMax) {
 2566:         xmlXPathObjectPtr *tmp;
 2567: 
 2568:         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
 2569:             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
 2570:             ctxt->error = XPATH_MEMORY_ERROR;
 2571:             return (0);
 2572:         }
 2573:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
 2574:                                              2 * ctxt->valueMax *
 2575:                                              sizeof(ctxt->valueTab[0]));
 2576:         if (tmp == NULL) {
 2577:             xmlXPathErrMemory(NULL, "pushing value\n");
 2578:             ctxt->error = XPATH_MEMORY_ERROR;
 2579:             return (0);
 2580:         }
 2581:         ctxt->valueMax *= 2;
 2582: 	ctxt->valueTab = tmp;
 2583:     }
 2584:     ctxt->valueTab[ctxt->valueNr] = value;
 2585:     ctxt->value = value;
 2586:     return (ctxt->valueNr++);
 2587: }
 2588: 
 2589: /**
 2590:  * xmlXPathPopBoolean:
 2591:  * @ctxt:  an XPath parser context
 2592:  *
 2593:  * Pops a boolean from the stack, handling conversion if needed.
 2594:  * Check error with #xmlXPathCheckError.
 2595:  *
 2596:  * Returns the boolean
 2597:  */
 2598: int
 2599: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
 2600:     xmlXPathObjectPtr obj;
 2601:     int ret;
 2602: 
 2603:     obj = valuePop(ctxt);
 2604:     if (obj == NULL) {
 2605: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2606: 	return(0);
 2607:     }
 2608:     if (obj->type != XPATH_BOOLEAN)
 2609: 	ret = xmlXPathCastToBoolean(obj);
 2610:     else
 2611:         ret = obj->boolval;
 2612:     xmlXPathReleaseObject(ctxt->context, obj);
 2613:     return(ret);
 2614: }
 2615: 
 2616: /**
 2617:  * xmlXPathPopNumber:
 2618:  * @ctxt:  an XPath parser context
 2619:  *
 2620:  * Pops a number from the stack, handling conversion if needed.
 2621:  * Check error with #xmlXPathCheckError.
 2622:  *
 2623:  * Returns the number
 2624:  */
 2625: double
 2626: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
 2627:     xmlXPathObjectPtr obj;
 2628:     double ret;
 2629: 
 2630:     obj = valuePop(ctxt);
 2631:     if (obj == NULL) {
 2632: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2633: 	return(0);
 2634:     }
 2635:     if (obj->type != XPATH_NUMBER)
 2636: 	ret = xmlXPathCastToNumber(obj);
 2637:     else
 2638:         ret = obj->floatval;
 2639:     xmlXPathReleaseObject(ctxt->context, obj);
 2640:     return(ret);
 2641: }
 2642: 
 2643: /**
 2644:  * xmlXPathPopString:
 2645:  * @ctxt:  an XPath parser context
 2646:  *
 2647:  * Pops a string from the stack, handling conversion if needed.
 2648:  * Check error with #xmlXPathCheckError.
 2649:  *
 2650:  * Returns the string
 2651:  */
 2652: xmlChar *
 2653: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
 2654:     xmlXPathObjectPtr obj;
 2655:     xmlChar * ret;
 2656: 
 2657:     obj = valuePop(ctxt);
 2658:     if (obj == NULL) {
 2659: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2660: 	return(NULL);
 2661:     }
 2662:     ret = xmlXPathCastToString(obj);	/* this does required strdup */
 2663:     /* TODO: needs refactoring somewhere else */
 2664:     if (obj->stringval == ret)
 2665: 	obj->stringval = NULL;
 2666:     xmlXPathReleaseObject(ctxt->context, obj);
 2667:     return(ret);
 2668: }
 2669: 
 2670: /**
 2671:  * xmlXPathPopNodeSet:
 2672:  * @ctxt:  an XPath parser context
 2673:  *
 2674:  * Pops a node-set from the stack, handling conversion if needed.
 2675:  * Check error with #xmlXPathCheckError.
 2676:  *
 2677:  * Returns the node-set
 2678:  */
 2679: xmlNodeSetPtr
 2680: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
 2681:     xmlXPathObjectPtr obj;
 2682:     xmlNodeSetPtr ret;
 2683: 
 2684:     if (ctxt == NULL) return(NULL);
 2685:     if (ctxt->value == NULL) {
 2686: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2687: 	return(NULL);
 2688:     }
 2689:     if (!xmlXPathStackIsNodeSet(ctxt)) {
 2690: 	xmlXPathSetTypeError(ctxt);
 2691: 	return(NULL);
 2692:     }
 2693:     obj = valuePop(ctxt);
 2694:     ret = obj->nodesetval;
 2695: #if 0
 2696:     /* to fix memory leak of not clearing obj->user */
 2697:     if (obj->boolval && obj->user != NULL)
 2698:         xmlFreeNodeList((xmlNodePtr) obj->user);
 2699: #endif
 2700:     obj->nodesetval = NULL;
 2701:     xmlXPathReleaseObject(ctxt->context, obj);
 2702:     return(ret);
 2703: }
 2704: 
 2705: /**
 2706:  * xmlXPathPopExternal:
 2707:  * @ctxt:  an XPath parser context
 2708:  *
 2709:  * Pops an external object from the stack, handling conversion if needed.
 2710:  * Check error with #xmlXPathCheckError.
 2711:  *
 2712:  * Returns the object
 2713:  */
 2714: void *
 2715: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
 2716:     xmlXPathObjectPtr obj;
 2717:     void * ret;
 2718: 
 2719:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
 2720: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2721: 	return(NULL);
 2722:     }
 2723:     if (ctxt->value->type != XPATH_USERS) {
 2724: 	xmlXPathSetTypeError(ctxt);
 2725: 	return(NULL);
 2726:     }
 2727:     obj = valuePop(ctxt);
 2728:     ret = obj->user;
 2729:     obj->user = NULL;
 2730:     xmlXPathReleaseObject(ctxt->context, obj);
 2731:     return(ret);
 2732: }
 2733: 
 2734: /*
 2735:  * Macros for accessing the content. Those should be used only by the parser,
 2736:  * and not exported.
 2737:  *
 2738:  * Dirty macros, i.e. one need to make assumption on the context to use them
 2739:  *
 2740:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
 2741:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
 2742:  *           in ISO-Latin or UTF-8.
 2743:  *           This should be used internally by the parser
 2744:  *           only to compare to ASCII values otherwise it would break when
 2745:  *           running with UTF-8 encoding.
 2746:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
 2747:  *           to compare on ASCII based substring.
 2748:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
 2749:  *           strings within the parser.
 2750:  *   CURRENT Returns the current char value, with the full decoding of
 2751:  *           UTF-8 if we are using this mode. It returns an int.
 2752:  *   NEXT    Skip to the next character, this does the proper decoding
 2753:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
 2754:  *           It returns the pointer to the current xmlChar.
 2755:  */
 2756: 
 2757: #define CUR (*ctxt->cur)
 2758: #define SKIP(val) ctxt->cur += (val)
 2759: #define NXT(val) ctxt->cur[(val)]
 2760: #define CUR_PTR ctxt->cur
 2761: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
 2762: 
 2763: #define COPY_BUF(l,b,i,v)                                              \
 2764:     if (l == 1) b[i++] = (xmlChar) v;                                  \
 2765:     else i += xmlCopyChar(l,&b[i],v)
 2766: 
 2767: #define NEXTL(l)  ctxt->cur += l
 2768: 
 2769: #define SKIP_BLANKS							\
 2770:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
 2771: 
 2772: #define CURRENT (*ctxt->cur)
 2773: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
 2774: 
 2775: 
 2776: #ifndef DBL_DIG
 2777: #define DBL_DIG 16
 2778: #endif
 2779: #ifndef DBL_EPSILON
 2780: #define DBL_EPSILON 1E-9
 2781: #endif
 2782: 
 2783: #define UPPER_DOUBLE 1E9
 2784: #define LOWER_DOUBLE 1E-5
 2785: #define	LOWER_DOUBLE_EXP 5
 2786: 
 2787: #define INTEGER_DIGITS DBL_DIG
 2788: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
 2789: #define EXPONENT_DIGITS (3 + 2)
 2790: 
 2791: /**
 2792:  * xmlXPathFormatNumber:
 2793:  * @number:     number to format
 2794:  * @buffer:     output buffer
 2795:  * @buffersize: size of output buffer
 2796:  *
 2797:  * Convert the number into a string representation.
 2798:  */
 2799: static void
 2800: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
 2801: {
 2802:     switch (xmlXPathIsInf(number)) {
 2803:     case 1:
 2804: 	if (buffersize > (int)sizeof("Infinity"))
 2805: 	    snprintf(buffer, buffersize, "Infinity");
 2806: 	break;
 2807:     case -1:
 2808: 	if (buffersize > (int)sizeof("-Infinity"))
 2809: 	    snprintf(buffer, buffersize, "-Infinity");
 2810: 	break;
 2811:     default:
 2812: 	if (xmlXPathIsNaN(number)) {
 2813: 	    if (buffersize > (int)sizeof("NaN"))
 2814: 		snprintf(buffer, buffersize, "NaN");
 2815: 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
 2816: 	    snprintf(buffer, buffersize, "0");
 2817: 	} else if (number == ((int) number)) {
 2818: 	    char work[30];
 2819: 	    char *ptr, *cur;
 2820: 	    int value = (int) number;
 2821: 
 2822:             ptr = &buffer[0];
 2823: 	    if (value == 0) {
 2824: 		*ptr++ = '0';
 2825: 	    } else {
 2826: 		snprintf(work, 29, "%d", value);
 2827: 		cur = &work[0];
 2828: 		while ((*cur) && (ptr - buffer < buffersize)) {
 2829: 		    *ptr++ = *cur++;
 2830: 		}
 2831: 	    }
 2832: 	    if (ptr - buffer < buffersize) {
 2833: 		*ptr = 0;
 2834: 	    } else if (buffersize > 0) {
 2835: 		ptr--;
 2836: 		*ptr = 0;
 2837: 	    }
 2838: 	} else {
 2839: 	    /*
 2840: 	      For the dimension of work,
 2841: 	          DBL_DIG is number of significant digits
 2842: 		  EXPONENT is only needed for "scientific notation"
 2843: 	          3 is sign, decimal point, and terminating zero
 2844: 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
 2845: 	      Note that this dimension is slightly (a few characters)
 2846: 	      larger than actually necessary.
 2847: 	    */
 2848: 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
 2849: 	    int integer_place, fraction_place;
 2850: 	    char *ptr;
 2851: 	    char *after_fraction;
 2852: 	    double absolute_value;
 2853: 	    int size;
 2854: 
 2855: 	    absolute_value = fabs(number);
 2856: 
 2857: 	    /*
 2858: 	     * First choose format - scientific or regular floating point.
 2859: 	     * In either case, result is in work, and after_fraction points
 2860: 	     * just past the fractional part.
 2861: 	    */
 2862: 	    if ( ((absolute_value > UPPER_DOUBLE) ||
 2863: 		  (absolute_value < LOWER_DOUBLE)) &&
 2864: 		 (absolute_value != 0.0) ) {
 2865: 		/* Use scientific notation */
 2866: 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
 2867: 		fraction_place = DBL_DIG - 1;
 2868: 		size = snprintf(work, sizeof(work),"%*.*e",
 2869: 			 integer_place, fraction_place, number);
 2870: 		while ((size > 0) && (work[size] != 'e')) size--;
 2871: 
 2872: 	    }
 2873: 	    else {
 2874: 		/* Use regular notation */
 2875: 		if (absolute_value > 0.0) {
 2876: 		    integer_place = (int)log10(absolute_value);
 2877: 		    if (integer_place > 0)
 2878: 		        fraction_place = DBL_DIG - integer_place - 1;
 2879: 		    else
 2880: 		        fraction_place = DBL_DIG - integer_place;
 2881: 		} else {
 2882: 		    fraction_place = 1;
 2883: 		}
 2884: 		size = snprintf(work, sizeof(work), "%0.*f",
 2885: 				fraction_place, number);
 2886: 	    }
 2887: 
 2888: 	    /* Remove fractional trailing zeroes */
 2889: 	    after_fraction = work + size;
 2890: 	    ptr = after_fraction;
 2891: 	    while (*(--ptr) == '0')
 2892: 		;
 2893: 	    if (*ptr != '.')
 2894: 	        ptr++;
 2895: 	    while ((*ptr++ = *after_fraction++) != 0);
 2896: 
 2897: 	    /* Finally copy result back to caller */
 2898: 	    size = strlen(work) + 1;
 2899: 	    if (size > buffersize) {
 2900: 		work[buffersize - 1] = 0;
 2901: 		size = buffersize;
 2902: 	    }
 2903: 	    memmove(buffer, work, size);
 2904: 	}
 2905: 	break;
 2906:     }
 2907: }
 2908: 
 2909: 
 2910: /************************************************************************
 2911:  *									*
 2912:  *			Routines to handle NodeSets			*
 2913:  *									*
 2914:  ************************************************************************/
 2915: 
 2916: /**
 2917:  * xmlXPathOrderDocElems:
 2918:  * @doc:  an input document
 2919:  *
 2920:  * Call this routine to speed up XPath computation on static documents.
 2921:  * This stamps all the element nodes with the document order
 2922:  * Like for line information, the order is kept in the element->content
 2923:  * field, the value stored is actually - the node number (starting at -1)
 2924:  * to be able to differentiate from line numbers.
 2925:  *
 2926:  * Returns the number of elements found in the document or -1 in case
 2927:  *    of error.
 2928:  */
 2929: long
 2930: xmlXPathOrderDocElems(xmlDocPtr doc) {
 2931:     long count = 0;
 2932:     xmlNodePtr cur;
 2933: 
 2934:     if (doc == NULL)
 2935: 	return(-1);
 2936:     cur = doc->children;
 2937:     while (cur != NULL) {
 2938: 	if (cur->type == XML_ELEMENT_NODE) {
 2939: 	    cur->content = (void *) (-(++count));
 2940: 	    if (cur->children != NULL) {
 2941: 		cur = cur->children;
 2942: 		continue;
 2943: 	    }
 2944: 	}
 2945: 	if (cur->next != NULL) {
 2946: 	    cur = cur->next;
 2947: 	    continue;
 2948: 	}
 2949: 	do {
 2950: 	    cur = cur->parent;
 2951: 	    if (cur == NULL)
 2952: 		break;
 2953: 	    if (cur == (xmlNodePtr) doc) {
 2954: 		cur = NULL;
 2955: 		break;
 2956: 	    }
 2957: 	    if (cur->next != NULL) {
 2958: 		cur = cur->next;
 2959: 		break;
 2960: 	    }
 2961: 	} while (cur != NULL);
 2962:     }
 2963:     return(count);
 2964: }
 2965: 
 2966: /**
 2967:  * xmlXPathCmpNodes:
 2968:  * @node1:  the first node
 2969:  * @node2:  the second node
 2970:  *
 2971:  * Compare two nodes w.r.t document order
 2972:  *
 2973:  * Returns -2 in case of error 1 if first point < second point, 0 if
 2974:  *         it's the same node, -1 otherwise
 2975:  */
 2976: int
 2977: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
 2978:     int depth1, depth2;
 2979:     int attr1 = 0, attr2 = 0;
 2980:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
 2981:     xmlNodePtr cur, root;
 2982: 
 2983:     if ((node1 == NULL) || (node2 == NULL))
 2984: 	return(-2);
 2985:     /*
 2986:      * a couple of optimizations which will avoid computations in most cases
 2987:      */
 2988:     if (node1 == node2)		/* trivial case */
 2989: 	return(0);
 2990:     if (node1->type == XML_ATTRIBUTE_NODE) {
 2991: 	attr1 = 1;
 2992: 	attrNode1 = node1;
 2993: 	node1 = node1->parent;
 2994:     }
 2995:     if (node2->type == XML_ATTRIBUTE_NODE) {
 2996: 	attr2 = 1;
 2997: 	attrNode2 = node2;
 2998: 	node2 = node2->parent;
 2999:     }
 3000:     if (node1 == node2) {
 3001: 	if (attr1 == attr2) {
 3002: 	    /* not required, but we keep attributes in order */
 3003: 	    if (attr1 != 0) {
 3004: 	        cur = attrNode2->prev;
 3005: 		while (cur != NULL) {
 3006: 		    if (cur == attrNode1)
 3007: 		        return (1);
 3008: 		    cur = cur->prev;
 3009: 		}
 3010: 		return (-1);
 3011: 	    }
 3012: 	    return(0);
 3013: 	}
 3014: 	if (attr2 == 1)
 3015: 	    return(1);
 3016: 	return(-1);
 3017:     }
 3018:     if ((node1->type == XML_NAMESPACE_DECL) ||
 3019:         (node2->type == XML_NAMESPACE_DECL))
 3020: 	return(1);
 3021:     if (node1 == node2->prev)
 3022: 	return(1);
 3023:     if (node1 == node2->next)
 3024: 	return(-1);
 3025: 
 3026:     /*
 3027:      * Speedup using document order if availble.
 3028:      */
 3029:     if ((node1->type == XML_ELEMENT_NODE) &&
 3030: 	(node2->type == XML_ELEMENT_NODE) &&
 3031: 	(0 > (long) node1->content) &&
 3032: 	(0 > (long) node2->content) &&
 3033: 	(node1->doc == node2->doc)) {
 3034: 	long l1, l2;
 3035: 
 3036: 	l1 = -((long) node1->content);
 3037: 	l2 = -((long) node2->content);
 3038: 	if (l1 < l2)
 3039: 	    return(1);
 3040: 	if (l1 > l2)
 3041: 	    return(-1);
 3042:     }
 3043: 
 3044:     /*
 3045:      * compute depth to root
 3046:      */
 3047:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 3048: 	if (cur == node1)
 3049: 	    return(1);
 3050: 	depth2++;
 3051:     }
 3052:     root = cur;
 3053:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 3054: 	if (cur == node2)
 3055: 	    return(-1);
 3056: 	depth1++;
 3057:     }
 3058:     /*
 3059:      * Distinct document (or distinct entities :-( ) case.
 3060:      */
 3061:     if (root != cur) {
 3062: 	return(-2);
 3063:     }
 3064:     /*
 3065:      * get the nearest common ancestor.
 3066:      */
 3067:     while (depth1 > depth2) {
 3068: 	depth1--;
 3069: 	node1 = node1->parent;
 3070:     }
 3071:     while (depth2 > depth1) {
 3072: 	depth2--;
 3073: 	node2 = node2->parent;
 3074:     }
 3075:     while (node1->parent != node2->parent) {
 3076: 	node1 = node1->parent;
 3077: 	node2 = node2->parent;
 3078: 	/* should not happen but just in case ... */
 3079: 	if ((node1 == NULL) || (node2 == NULL))
 3080: 	    return(-2);
 3081:     }
 3082:     /*
 3083:      * Find who's first.
 3084:      */
 3085:     if (node1 == node2->prev)
 3086: 	return(1);
 3087:     if (node1 == node2->next)
 3088: 	return(-1);
 3089:     /*
 3090:      * Speedup using document order if availble.
 3091:      */
 3092:     if ((node1->type == XML_ELEMENT_NODE) &&
 3093: 	(node2->type == XML_ELEMENT_NODE) &&
 3094: 	(0 > (long) node1->content) &&
 3095: 	(0 > (long) node2->content) &&
 3096: 	(node1->doc == node2->doc)) {
 3097: 	long l1, l2;
 3098: 
 3099: 	l1 = -((long) node1->content);
 3100: 	l2 = -((long) node2->content);
 3101: 	if (l1 < l2)
 3102: 	    return(1);
 3103: 	if (l1 > l2)
 3104: 	    return(-1);
 3105:     }
 3106: 
 3107:     for (cur = node1->next;cur != NULL;cur = cur->next)
 3108: 	if (cur == node2)
 3109: 	    return(1);
 3110:     return(-1); /* assume there is no sibling list corruption */
 3111: }
 3112: 
 3113: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 3114: /**
 3115:  * xmlXPathCmpNodesExt:
 3116:  * @node1:  the first node
 3117:  * @node2:  the second node
 3118:  *
 3119:  * Compare two nodes w.r.t document order.
 3120:  * This one is optimized for handling of non-element nodes.
 3121:  *
 3122:  * Returns -2 in case of error 1 if first point < second point, 0 if
 3123:  *         it's the same node, -1 otherwise
 3124:  */
 3125: static int
 3126: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 3127:     int depth1, depth2;
 3128:     int misc = 0, precedence1 = 0, precedence2 = 0;
 3129:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
 3130:     xmlNodePtr cur, root;
 3131:     long l1, l2;
 3132: 
 3133:     if ((node1 == NULL) || (node2 == NULL))
 3134: 	return(-2);
 3135: 
 3136:     if (node1 == node2)
 3137: 	return(0);
 3138: 
 3139:     /*
 3140:      * a couple of optimizations which will avoid computations in most cases
 3141:      */
 3142:     switch (node1->type) {
 3143: 	case XML_ELEMENT_NODE:
 3144: 	    if (node2->type == XML_ELEMENT_NODE) {
 3145: 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
 3146: 		    (0 > (long) node2->content) &&
 3147: 		    (node1->doc == node2->doc))
 3148: 		{
 3149: 		    l1 = -((long) node1->content);
 3150: 		    l2 = -((long) node2->content);
 3151: 		    if (l1 < l2)
 3152: 			return(1);
 3153: 		    if (l1 > l2)
 3154: 			return(-1);
 3155: 		} else
 3156: 		    goto turtle_comparison;
 3157: 	    }
 3158: 	    break;
 3159: 	case XML_ATTRIBUTE_NODE:
 3160: 	    precedence1 = 1; /* element is owner */
 3161: 	    miscNode1 = node1;
 3162: 	    node1 = node1->parent;
 3163: 	    misc = 1;
 3164: 	    break;
 3165: 	case XML_TEXT_NODE:
 3166: 	case XML_CDATA_SECTION_NODE:
 3167: 	case XML_COMMENT_NODE:
 3168: 	case XML_PI_NODE: {
 3169: 	    miscNode1 = node1;
 3170: 	    /*
 3171: 	    * Find nearest element node.
 3172: 	    */
 3173: 	    if (node1->prev != NULL) {
 3174: 		do {
 3175: 		    node1 = node1->prev;
 3176: 		    if (node1->type == XML_ELEMENT_NODE) {
 3177: 			precedence1 = 3; /* element in prev-sibl axis */
 3178: 			break;
 3179: 		    }
 3180: 		    if (node1->prev == NULL) {
 3181: 			precedence1 = 2; /* element is parent */
 3182: 			/*
 3183: 			* URGENT TODO: Are there any cases, where the
 3184: 			* parent of such a node is not an element node?
 3185: 			*/
 3186: 			node1 = node1->parent;
 3187: 			break;
 3188: 		    }
 3189: 		} while (1);
 3190: 	    } else {
 3191: 		precedence1 = 2; /* element is parent */
 3192: 		node1 = node1->parent;
 3193: 	    }
 3194: 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
 3195: 		(0 <= (long) node1->content)) {
 3196: 		/*
 3197: 		* Fallback for whatever case.
 3198: 		*/
 3199: 		node1 = miscNode1;
 3200: 		precedence1 = 0;
 3201: 	    } else
 3202: 		misc = 1;
 3203: 	}
 3204: 	    break;
 3205: 	case XML_NAMESPACE_DECL:
 3206: 	    /*
 3207: 	    * TODO: why do we return 1 for namespace nodes?
 3208: 	    */
 3209: 	    return(1);
 3210: 	default:
 3211: 	    break;
 3212:     }
 3213:     switch (node2->type) {
 3214: 	case XML_ELEMENT_NODE:
 3215: 	    break;
 3216: 	case XML_ATTRIBUTE_NODE:
 3217: 	    precedence2 = 1; /* element is owner */
 3218: 	    miscNode2 = node2;
 3219: 	    node2 = node2->parent;
 3220: 	    misc = 1;
 3221: 	    break;
 3222: 	case XML_TEXT_NODE:
 3223: 	case XML_CDATA_SECTION_NODE:
 3224: 	case XML_COMMENT_NODE:
 3225: 	case XML_PI_NODE: {
 3226: 	    miscNode2 = node2;
 3227: 	    if (node2->prev != NULL) {
 3228: 		do {
 3229: 		    node2 = node2->prev;
 3230: 		    if (node2->type == XML_ELEMENT_NODE) {
 3231: 			precedence2 = 3; /* element in prev-sibl axis */
 3232: 			break;
 3233: 		    }
 3234: 		    if (node2->prev == NULL) {
 3235: 			precedence2 = 2; /* element is parent */
 3236: 			node2 = node2->parent;
 3237: 			break;
 3238: 		    }
 3239: 		} while (1);
 3240: 	    } else {
 3241: 		precedence2 = 2; /* element is parent */
 3242: 		node2 = node2->parent;
 3243: 	    }
 3244: 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
 3245: 		(0 <= (long) node1->content))
 3246: 	    {
 3247: 		node2 = miscNode2;
 3248: 		precedence2 = 0;
 3249: 	    } else
 3250: 		misc = 1;
 3251: 	}
 3252: 	    break;
 3253: 	case XML_NAMESPACE_DECL:
 3254: 	    return(1);
 3255: 	default:
 3256: 	    break;
 3257:     }
 3258:     if (misc) {
 3259: 	if (node1 == node2) {
 3260: 	    if (precedence1 == precedence2) {
 3261: 		/*
 3262: 		* The ugly case; but normally there aren't many
 3263: 		* adjacent non-element nodes around.
 3264: 		*/
 3265: 		cur = miscNode2->prev;
 3266: 		while (cur != NULL) {
 3267: 		    if (cur == miscNode1)
 3268: 			return(1);
 3269: 		    if (cur->type == XML_ELEMENT_NODE)
 3270: 			return(-1);
 3271: 		    cur = cur->prev;
 3272: 		}
 3273: 		return (-1);
 3274: 	    } else {
 3275: 		/*
 3276: 		* Evaluate based on higher precedence wrt to the element.
 3277: 		* TODO: This assumes attributes are sorted before content.
 3278: 		*   Is this 100% correct?
 3279: 		*/
 3280: 		if (precedence1 < precedence2)
 3281: 		    return(1);
 3282: 		else
 3283: 		    return(-1);
 3284: 	    }
 3285: 	}
 3286: 	/*
 3287: 	* Special case: One of the helper-elements is contained by the other.
 3288: 	* <foo>
 3289: 	*   <node2>
 3290: 	*     <node1>Text-1(precedence1 == 2)</node1>
 3291: 	*   </node2>
 3292: 	*   Text-6(precedence2 == 3)
 3293: 	* </foo>
 3294: 	*/
 3295: 	if ((precedence2 == 3) && (precedence1 > 1)) {
 3296: 	    cur = node1->parent;
 3297: 	    while (cur) {
 3298: 		if (cur == node2)
 3299: 		    return(1);
 3300: 		cur = cur->parent;
 3301: 	    }
 3302: 	}
 3303: 	if ((precedence1 == 3) && (precedence2 > 1)) {
 3304: 	    cur = node2->parent;
 3305: 	    while (cur) {
 3306: 		if (cur == node1)
 3307: 		    return(-1);
 3308: 		cur = cur->parent;
 3309: 	    }
 3310: 	}
 3311:     }
 3312: 
 3313:     /*
 3314:      * Speedup using document order if availble.
 3315:      */
 3316:     if ((node1->type == XML_ELEMENT_NODE) &&
 3317: 	(node2->type == XML_ELEMENT_NODE) &&
 3318: 	(0 > (long) node1->content) &&
 3319: 	(0 > (long) node2->content) &&
 3320: 	(node1->doc == node2->doc)) {
 3321: 
 3322: 	l1 = -((long) node1->content);
 3323: 	l2 = -((long) node2->content);
 3324: 	if (l1 < l2)
 3325: 	    return(1);
 3326: 	if (l1 > l2)
 3327: 	    return(-1);
 3328:     }
 3329: 
 3330: turtle_comparison:
 3331: 
 3332:     if (node1 == node2->prev)
 3333: 	return(1);
 3334:     if (node1 == node2->next)
 3335: 	return(-1);
 3336:     /*
 3337:      * compute depth to root
 3338:      */
 3339:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 3340: 	if (cur == node1)
 3341: 	    return(1);
 3342: 	depth2++;
 3343:     }
 3344:     root = cur;
 3345:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 3346: 	if (cur == node2)
 3347: 	    return(-1);
 3348: 	depth1++;
 3349:     }
 3350:     /*
 3351:      * Distinct document (or distinct entities :-( ) case.
 3352:      */
 3353:     if (root != cur) {
 3354: 	return(-2);
 3355:     }
 3356:     /*
 3357:      * get the nearest common ancestor.
 3358:      */
 3359:     while (depth1 > depth2) {
 3360: 	depth1--;
 3361: 	node1 = node1->parent;
 3362:     }
 3363:     while (depth2 > depth1) {
 3364: 	depth2--;
 3365: 	node2 = node2->parent;
 3366:     }
 3367:     while (node1->parent != node2->parent) {
 3368: 	node1 = node1->parent;
 3369: 	node2 = node2->parent;
 3370: 	/* should not happen but just in case ... */
 3371: 	if ((node1 == NULL) || (node2 == NULL))
 3372: 	    return(-2);
 3373:     }
 3374:     /*
 3375:      * Find who's first.
 3376:      */
 3377:     if (node1 == node2->prev)
 3378: 	return(1);
 3379:     if (node1 == node2->next)
 3380: 	return(-1);
 3381:     /*
 3382:      * Speedup using document order if availble.
 3383:      */
 3384:     if ((node1->type == XML_ELEMENT_NODE) &&
 3385: 	(node2->type == XML_ELEMENT_NODE) &&
 3386: 	(0 > (long) node1->content) &&
 3387: 	(0 > (long) node2->content) &&
 3388: 	(node1->doc == node2->doc)) {
 3389: 
 3390: 	l1 = -((long) node1->content);
 3391: 	l2 = -((long) node2->content);
 3392: 	if (l1 < l2)
 3393: 	    return(1);
 3394: 	if (l1 > l2)
 3395: 	    return(-1);
 3396:     }
 3397: 
 3398:     for (cur = node1->next;cur != NULL;cur = cur->next)
 3399: 	if (cur == node2)
 3400: 	    return(1);
 3401:     return(-1); /* assume there is no sibling list corruption */
 3402: }
 3403: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
 3404: 
 3405: /**
 3406:  * xmlXPathNodeSetSort:
 3407:  * @set:  the node set
 3408:  *
 3409:  * Sort the node set in document order
 3410:  */
 3411: void
 3412: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
 3413: #ifndef WITH_TIM_SORT
 3414:     int i, j, incr, len;
 3415:     xmlNodePtr tmp;
 3416: #endif
 3417: 
 3418:     if (set == NULL)
 3419: 	return;
 3420: 
 3421: #ifndef WITH_TIM_SORT
 3422:     /*
 3423:      * Use the old Shell's sort implementation to sort the node-set
 3424:      * Timsort ought to be quite faster
 3425:      */
 3426:     len = set->nodeNr;
 3427:     for (incr = len / 2; incr > 0; incr /= 2) {
 3428: 	for (i = incr; i < len; i++) {
 3429: 	    j = i - incr;
 3430: 	    while (j >= 0) {
 3431: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 3432: 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
 3433: 			set->nodeTab[j + incr]) == -1)
 3434: #else
 3435: 		if (xmlXPathCmpNodes(set->nodeTab[j],
 3436: 			set->nodeTab[j + incr]) == -1)
 3437: #endif
 3438: 		{
 3439: 		    tmp = set->nodeTab[j];
 3440: 		    set->nodeTab[j] = set->nodeTab[j + incr];
 3441: 		    set->nodeTab[j + incr] = tmp;
 3442: 		    j -= incr;
 3443: 		} else
 3444: 		    break;
 3445: 	    }
 3446: 	}
 3447:     }
 3448: #else /* WITH_TIM_SORT */
 3449:     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
 3450: #endif /* WITH_TIM_SORT */
 3451: }
 3452: 
 3453: #define XML_NODESET_DEFAULT	10
 3454: /**
 3455:  * xmlXPathNodeSetDupNs:
 3456:  * @node:  the parent node of the namespace XPath node
 3457:  * @ns:  the libxml namespace declaration node.
 3458:  *
 3459:  * Namespace node in libxml don't match the XPath semantic. In a node set
 3460:  * the namespace nodes are duplicated and the next pointer is set to the
 3461:  * parent node in the XPath semantic.
 3462:  *
 3463:  * Returns the newly created object.
 3464:  */
 3465: static xmlNodePtr
 3466: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
 3467:     xmlNsPtr cur;
 3468: 
 3469:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3470: 	return(NULL);
 3471:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
 3472: 	return((xmlNodePtr) ns);
 3473: 
 3474:     /*
 3475:      * Allocate a new Namespace and fill the fields.
 3476:      */
 3477:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
 3478:     if (cur == NULL) {
 3479:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
 3480: 	return(NULL);
 3481:     }
 3482:     memset(cur, 0, sizeof(xmlNs));
 3483:     cur->type = XML_NAMESPACE_DECL;
 3484:     if (ns->href != NULL)
 3485: 	cur->href = xmlStrdup(ns->href);
 3486:     if (ns->prefix != NULL)
 3487: 	cur->prefix = xmlStrdup(ns->prefix);
 3488:     cur->next = (xmlNsPtr) node;
 3489:     return((xmlNodePtr) cur);
 3490: }
 3491: 
 3492: /**
 3493:  * xmlXPathNodeSetFreeNs:
 3494:  * @ns:  the XPath namespace node found in a nodeset.
 3495:  *
 3496:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
 3497:  * the namespace nodes are duplicated and the next pointer is set to the
 3498:  * parent node in the XPath semantic. Check if such a node needs to be freed
 3499:  */
 3500: void
 3501: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
 3502:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3503: 	return;
 3504: 
 3505:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
 3506: 	if (ns->href != NULL)
 3507: 	    xmlFree((xmlChar *)ns->href);
 3508: 	if (ns->prefix != NULL)
 3509: 	    xmlFree((xmlChar *)ns->prefix);
 3510: 	xmlFree(ns);
 3511:     }
 3512: }
 3513: 
 3514: /**
 3515:  * xmlXPathNodeSetCreate:
 3516:  * @val:  an initial xmlNodePtr, or NULL
 3517:  *
 3518:  * Create a new xmlNodeSetPtr of type double and of value @val
 3519:  *
 3520:  * Returns the newly created object.
 3521:  */
 3522: xmlNodeSetPtr
 3523: xmlXPathNodeSetCreate(xmlNodePtr val) {
 3524:     xmlNodeSetPtr ret;
 3525: 
 3526:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3527:     if (ret == NULL) {
 3528:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3529: 	return(NULL);
 3530:     }
 3531:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3532:     if (val != NULL) {
 3533:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3534: 					     sizeof(xmlNodePtr));
 3535: 	if (ret->nodeTab == NULL) {
 3536: 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
 3537: 	    xmlFree(ret);
 3538: 	    return(NULL);
 3539: 	}
 3540: 	memset(ret->nodeTab, 0 ,
 3541: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3542:         ret->nodeMax = XML_NODESET_DEFAULT;
 3543: 	if (val->type == XML_NAMESPACE_DECL) {
 3544: 	    xmlNsPtr ns = (xmlNsPtr) val;
 3545: 
 3546: 	    ret->nodeTab[ret->nodeNr++] =
 3547: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3548: 	} else
 3549: 	    ret->nodeTab[ret->nodeNr++] = val;
 3550:     }
 3551:     return(ret);
 3552: }
 3553: 
 3554: /**
 3555:  * xmlXPathNodeSetCreateSize:
 3556:  * @size:  the initial size of the set
 3557:  *
 3558:  * Create a new xmlNodeSetPtr of type double and of value @val
 3559:  *
 3560:  * Returns the newly created object.
 3561:  */
 3562: static xmlNodeSetPtr
 3563: xmlXPathNodeSetCreateSize(int size) {
 3564:     xmlNodeSetPtr ret;
 3565: 
 3566:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3567:     if (ret == NULL) {
 3568:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3569: 	return(NULL);
 3570:     }
 3571:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3572:     if (size < XML_NODESET_DEFAULT)
 3573: 	size = XML_NODESET_DEFAULT;
 3574:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
 3575:     if (ret->nodeTab == NULL) {
 3576: 	xmlXPathErrMemory(NULL, "creating nodeset\n");
 3577: 	xmlFree(ret);
 3578: 	return(NULL);
 3579:     }
 3580:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
 3581:     ret->nodeMax = size;
 3582:     return(ret);
 3583: }
 3584: 
 3585: /**
 3586:  * xmlXPathNodeSetContains:
 3587:  * @cur:  the node-set
 3588:  * @val:  the node
 3589:  *
 3590:  * checks whether @cur contains @val
 3591:  *
 3592:  * Returns true (1) if @cur contains @val, false (0) otherwise
 3593:  */
 3594: int
 3595: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
 3596:     int i;
 3597: 
 3598:     if ((cur == NULL) || (val == NULL)) return(0);
 3599:     if (val->type == XML_NAMESPACE_DECL) {
 3600: 	for (i = 0; i < cur->nodeNr; i++) {
 3601: 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 3602: 		xmlNsPtr ns1, ns2;
 3603: 
 3604: 		ns1 = (xmlNsPtr) val;
 3605: 		ns2 = (xmlNsPtr) cur->nodeTab[i];
 3606: 		if (ns1 == ns2)
 3607: 		    return(1);
 3608: 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
 3609: 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
 3610: 		    return(1);
 3611: 	    }
 3612: 	}
 3613:     } else {
 3614: 	for (i = 0; i < cur->nodeNr; i++) {
 3615: 	    if (cur->nodeTab[i] == val)
 3616: 		return(1);
 3617: 	}
 3618:     }
 3619:     return(0);
 3620: }
 3621: 
 3622: /**
 3623:  * xmlXPathNodeSetAddNs:
 3624:  * @cur:  the initial node set
 3625:  * @node:  the hosting node
 3626:  * @ns:  a the namespace node
 3627:  *
 3628:  * add a new namespace node to an existing NodeSet
 3629:  *
 3630:  * Returns 0 in case of success and -1 in case of error
 3631:  */
 3632: int
 3633: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
 3634:     int i;
 3635: 
 3636: 
 3637:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
 3638:         (ns->type != XML_NAMESPACE_DECL) ||
 3639: 	(node->type != XML_ELEMENT_NODE))
 3640: 	return(-1);
 3641: 
 3642:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3643:     /*
 3644:      * prevent duplicates
 3645:      */
 3646:     for (i = 0;i < cur->nodeNr;i++) {
 3647:         if ((cur->nodeTab[i] != NULL) &&
 3648: 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
 3649: 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
 3650: 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
 3651: 	    return(0);
 3652:     }
 3653: 
 3654:     /*
 3655:      * grow the nodeTab if needed
 3656:      */
 3657:     if (cur->nodeMax == 0) {
 3658:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3659: 					     sizeof(xmlNodePtr));
 3660: 	if (cur->nodeTab == NULL) {
 3661: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3662: 	    return(-1);
 3663: 	}
 3664: 	memset(cur->nodeTab, 0 ,
 3665: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3666:         cur->nodeMax = XML_NODESET_DEFAULT;
 3667:     } else if (cur->nodeNr == cur->nodeMax) {
 3668:         xmlNodePtr *temp;
 3669: 
 3670:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 3671:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
 3672:             return(-1);
 3673:         }
 3674: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3675: 				      sizeof(xmlNodePtr));
 3676: 	if (temp == NULL) {
 3677: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3678: 	    return(-1);
 3679: 	}
 3680:         cur->nodeMax *= 2;
 3681: 	cur->nodeTab = temp;
 3682:     }
 3683:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
 3684:     return(0);
 3685: }
 3686: 
 3687: /**
 3688:  * xmlXPathNodeSetAdd:
 3689:  * @cur:  the initial node set
 3690:  * @val:  a new xmlNodePtr
 3691:  *
 3692:  * add a new xmlNodePtr to an existing NodeSet
 3693:  *
 3694:  * Returns 0 in case of success, and -1 in case of error
 3695:  */
 3696: int
 3697: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
 3698:     int i;
 3699: 
 3700:     if ((cur == NULL) || (val == NULL)) return(-1);
 3701: 
 3702:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3703:     /*
 3704:      * prevent duplcates
 3705:      */
 3706:     for (i = 0;i < cur->nodeNr;i++)
 3707:         if (cur->nodeTab[i] == val) return(0);
 3708: 
 3709:     /*
 3710:      * grow the nodeTab if needed
 3711:      */
 3712:     if (cur->nodeMax == 0) {
 3713:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3714: 					     sizeof(xmlNodePtr));
 3715: 	if (cur->nodeTab == NULL) {
 3716: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3717: 	    return(-1);
 3718: 	}
 3719: 	memset(cur->nodeTab, 0 ,
 3720: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3721:         cur->nodeMax = XML_NODESET_DEFAULT;
 3722:     } else if (cur->nodeNr == cur->nodeMax) {
 3723:         xmlNodePtr *temp;
 3724: 
 3725:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 3726:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
 3727:             return(-1);
 3728:         }
 3729: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3730: 				      sizeof(xmlNodePtr));
 3731: 	if (temp == NULL) {
 3732: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3733: 	    return(-1);
 3734: 	}
 3735:         cur->nodeMax *= 2;
 3736: 	cur->nodeTab = temp;
 3737:     }
 3738:     if (val->type == XML_NAMESPACE_DECL) {
 3739: 	xmlNsPtr ns = (xmlNsPtr) val;
 3740: 
 3741: 	cur->nodeTab[cur->nodeNr++] =
 3742: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3743:     } else
 3744: 	cur->nodeTab[cur->nodeNr++] = val;
 3745:     return(0);
 3746: }
 3747: 
 3748: /**
 3749:  * xmlXPathNodeSetAddUnique:
 3750:  * @cur:  the initial node set
 3751:  * @val:  a new xmlNodePtr
 3752:  *
 3753:  * add a new xmlNodePtr to an existing NodeSet, optimized version
 3754:  * when we are sure the node is not already in the set.
 3755:  *
 3756:  * Returns 0 in case of success and -1 in case of failure
 3757:  */
 3758: int
 3759: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
 3760:     if ((cur == NULL) || (val == NULL)) return(-1);
 3761: 
 3762:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3763:     /*
 3764:      * grow the nodeTab if needed
 3765:      */
 3766:     if (cur->nodeMax == 0) {
 3767:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3768: 					     sizeof(xmlNodePtr));
 3769: 	if (cur->nodeTab == NULL) {
 3770: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3771: 	    return(-1);
 3772: 	}
 3773: 	memset(cur->nodeTab, 0 ,
 3774: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3775:         cur->nodeMax = XML_NODESET_DEFAULT;
 3776:     } else if (cur->nodeNr == cur->nodeMax) {
 3777:         xmlNodePtr *temp;
 3778: 
 3779:         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 3780:             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
 3781:             return(-1);
 3782:         }
 3783: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3784: 				      sizeof(xmlNodePtr));
 3785: 	if (temp == NULL) {
 3786: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3787: 	    return(-1);
 3788: 	}
 3789: 	cur->nodeTab = temp;
 3790:         cur->nodeMax *= 2;
 3791:     }
 3792:     if (val->type == XML_NAMESPACE_DECL) {
 3793: 	xmlNsPtr ns = (xmlNsPtr) val;
 3794: 
 3795: 	cur->nodeTab[cur->nodeNr++] =
 3796: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3797:     } else
 3798: 	cur->nodeTab[cur->nodeNr++] = val;
 3799:     return(0);
 3800: }
 3801: 
 3802: /**
 3803:  * xmlXPathNodeSetMerge:
 3804:  * @val1:  the first NodeSet or NULL
 3805:  * @val2:  the second NodeSet
 3806:  *
 3807:  * Merges two nodesets, all nodes from @val2 are added to @val1
 3808:  * if @val1 is NULL, a new set is created and copied from @val2
 3809:  *
 3810:  * Returns @val1 once extended or NULL in case of error.
 3811:  */
 3812: xmlNodeSetPtr
 3813: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
 3814:     int i, j, initNr, skip;
 3815:     xmlNodePtr n1, n2;
 3816: 
 3817:     if (val2 == NULL) return(val1);
 3818:     if (val1 == NULL) {
 3819: 	val1 = xmlXPathNodeSetCreate(NULL);
 3820:     if (val1 == NULL)
 3821:         return (NULL);
 3822: #if 0
 3823: 	/*
 3824: 	* TODO: The optimization won't work in every case, since
 3825: 	*  those nasty namespace nodes need to be added with
 3826: 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
 3827: 	*  memcpy is not possible.
 3828: 	*  If there was a flag on the nodesetval, indicating that
 3829: 	*  some temporary nodes are in, that would be helpfull.
 3830: 	*/
 3831: 	/*
 3832: 	* Optimization: Create an equally sized node-set
 3833: 	* and memcpy the content.
 3834: 	*/
 3835: 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
 3836: 	if (val1 == NULL)
 3837: 	    return(NULL);
 3838: 	if (val2->nodeNr != 0) {
 3839: 	    if (val2->nodeNr == 1)
 3840: 		*(val1->nodeTab) = *(val2->nodeTab);
 3841: 	    else {
 3842: 		memcpy(val1->nodeTab, val2->nodeTab,
 3843: 		    val2->nodeNr * sizeof(xmlNodePtr));
 3844: 	    }
 3845: 	    val1->nodeNr = val2->nodeNr;
 3846: 	}
 3847: 	return(val1);
 3848: #endif
 3849:     }
 3850: 
 3851:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3852:     initNr = val1->nodeNr;
 3853: 
 3854:     for (i = 0;i < val2->nodeNr;i++) {
 3855: 	n2 = val2->nodeTab[i];
 3856: 	/*
 3857: 	 * check against duplicates
 3858: 	 */
 3859: 	skip = 0;
 3860: 	for (j = 0; j < initNr; j++) {
 3861: 	    n1 = val1->nodeTab[j];
 3862: 	    if (n1 == n2) {
 3863: 		skip = 1;
 3864: 		break;
 3865: 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
 3866: 		       (n2->type == XML_NAMESPACE_DECL)) {
 3867: 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3868: 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3869: 			((xmlNsPtr) n2)->prefix)))
 3870: 		{
 3871: 		    skip = 1;
 3872: 		    break;
 3873: 		}
 3874: 	    }
 3875: 	}
 3876: 	if (skip)
 3877: 	    continue;
 3878: 
 3879: 	/*
 3880: 	 * grow the nodeTab if needed
 3881: 	 */
 3882: 	if (val1->nodeMax == 0) {
 3883: 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3884: 						    sizeof(xmlNodePtr));
 3885: 	    if (val1->nodeTab == NULL) {
 3886: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3887: 		return(NULL);
 3888: 	    }
 3889: 	    memset(val1->nodeTab, 0 ,
 3890: 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3891: 	    val1->nodeMax = XML_NODESET_DEFAULT;
 3892: 	} else if (val1->nodeNr == val1->nodeMax) {
 3893: 	    xmlNodePtr *temp;
 3894: 
 3895:             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 3896:                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
 3897:                 return(NULL);
 3898:             }
 3899: 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
 3900: 					     sizeof(xmlNodePtr));
 3901: 	    if (temp == NULL) {
 3902: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3903: 		return(NULL);
 3904: 	    }
 3905: 	    val1->nodeTab = temp;
 3906: 	    val1->nodeMax *= 2;
 3907: 	}
 3908: 	if (n2->type == XML_NAMESPACE_DECL) {
 3909: 	    xmlNsPtr ns = (xmlNsPtr) n2;
 3910: 
 3911: 	    val1->nodeTab[val1->nodeNr++] =
 3912: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3913: 	} else
 3914: 	    val1->nodeTab[val1->nodeNr++] = n2;
 3915:     }
 3916: 
 3917:     return(val1);
 3918: }
 3919: 
 3920: 
 3921: /**
 3922:  * xmlXPathNodeSetMergeAndClear:
 3923:  * @set1:  the first NodeSet or NULL
 3924:  * @set2:  the second NodeSet
 3925:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 3926:  *
 3927:  * Merges two nodesets, all nodes from @set2 are added to @set1
 3928:  * if @set1 is NULL, a new set is created and copied from @set2.
 3929:  * Checks for duplicate nodes. Clears set2.
 3930:  *
 3931:  * Returns @set1 once extended or NULL in case of error.
 3932:  */
 3933: static xmlNodeSetPtr
 3934: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 3935: 			     int hasNullEntries)
 3936: {
 3937:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 3938: 	/*
 3939: 	* Note that doing a memcpy of the list, namespace nodes are
 3940: 	* just assigned to set1, since set2 is cleared anyway.
 3941: 	*/
 3942: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 3943: 	if (set1 == NULL)
 3944: 	    return(NULL);
 3945: 	if (set2->nodeNr != 0) {
 3946: 	    memcpy(set1->nodeTab, set2->nodeTab,
 3947: 		set2->nodeNr * sizeof(xmlNodePtr));
 3948: 	    set1->nodeNr = set2->nodeNr;
 3949: 	}
 3950:     } else {
 3951: 	int i, j, initNbSet1;
 3952: 	xmlNodePtr n1, n2;
 3953: 
 3954: 	if (set1 == NULL)
 3955:             set1 = xmlXPathNodeSetCreate(NULL);
 3956:         if (set1 == NULL)
 3957:             return (NULL);
 3958: 
 3959: 	initNbSet1 = set1->nodeNr;
 3960: 	for (i = 0;i < set2->nodeNr;i++) {
 3961: 	    n2 = set2->nodeTab[i];
 3962: 	    /*
 3963: 	    * Skip NULLed entries.
 3964: 	    */
 3965: 	    if (n2 == NULL)
 3966: 		continue;
 3967: 	    /*
 3968: 	    * Skip duplicates.
 3969: 	    */
 3970: 	    for (j = 0; j < initNbSet1; j++) {
 3971: 		n1 = set1->nodeTab[j];
 3972: 		if (n1 == n2) {
 3973: 		    goto skip_node;
 3974: 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
 3975: 		    (n2->type == XML_NAMESPACE_DECL))
 3976: 		{
 3977: 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3978: 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3979: 			((xmlNsPtr) n2)->prefix)))
 3980: 		    {
 3981: 			/*
 3982: 			* Free the namespace node.
 3983: 			*/
 3984: 			set2->nodeTab[i] = NULL;
 3985: 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
 3986: 			goto skip_node;
 3987: 		    }
 3988: 		}
 3989: 	    }
 3990: 	    /*
 3991: 	    * grow the nodeTab if needed
 3992: 	    */
 3993: 	    if (set1->nodeMax == 0) {
 3994: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 3995: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 3996: 		if (set1->nodeTab == NULL) {
 3997: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3998: 		    return(NULL);
 3999: 		}
 4000: 		memset(set1->nodeTab, 0,
 4001: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 4002: 		set1->nodeMax = XML_NODESET_DEFAULT;
 4003: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 4004: 		xmlNodePtr *temp;
 4005: 
 4006:                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 4007:                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
 4008:                     return(NULL);
 4009:                 }
 4010: 		temp = (xmlNodePtr *) xmlRealloc(
 4011: 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
 4012: 		if (temp == NULL) {
 4013: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 4014: 		    return(NULL);
 4015: 		}
 4016: 		set1->nodeTab = temp;
 4017: 		set1->nodeMax *= 2;
 4018: 	    }
 4019: 	    if (n2->type == XML_NAMESPACE_DECL) {
 4020: 		xmlNsPtr ns = (xmlNsPtr) n2;
 4021: 
 4022: 		set1->nodeTab[set1->nodeNr++] =
 4023: 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 4024: 	    } else
 4025: 		set1->nodeTab[set1->nodeNr++] = n2;
 4026: skip_node:
 4027: 	    {}
 4028: 	}
 4029:     }
 4030:     set2->nodeNr = 0;
 4031:     return(set1);
 4032: }
 4033: 
 4034: /**
 4035:  * xmlXPathNodeSetMergeAndClearNoDupls:
 4036:  * @set1:  the first NodeSet or NULL
 4037:  * @set2:  the second NodeSet
 4038:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 4039:  *
 4040:  * Merges two nodesets, all nodes from @set2 are added to @set1
 4041:  * if @set1 is NULL, a new set is created and copied from @set2.
 4042:  * Doesn't chack for duplicate nodes. Clears set2.
 4043:  *
 4044:  * Returns @set1 once extended or NULL in case of error.
 4045:  */
 4046: static xmlNodeSetPtr
 4047: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 4048: 				    int hasNullEntries)
 4049: {
 4050:     if (set2 == NULL)
 4051: 	return(set1);
 4052:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 4053: 	/*
 4054: 	* Note that doing a memcpy of the list, namespace nodes are
 4055: 	* just assigned to set1, since set2 is cleared anyway.
 4056: 	*/
 4057: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 4058: 	if (set1 == NULL)
 4059: 	    return(NULL);
 4060: 	if (set2->nodeNr != 0) {
 4061: 	    memcpy(set1->nodeTab, set2->nodeTab,
 4062: 		set2->nodeNr * sizeof(xmlNodePtr));
 4063: 	    set1->nodeNr = set2->nodeNr;
 4064: 	}
 4065:     } else {
 4066: 	int i;
 4067: 	xmlNodePtr n2;
 4068: 
 4069: 	if (set1 == NULL)
 4070: 	    set1 = xmlXPathNodeSetCreate(NULL);
 4071:         if (set1 == NULL)
 4072:             return (NULL);
 4073: 
 4074: 	for (i = 0;i < set2->nodeNr;i++) {
 4075: 	    n2 = set2->nodeTab[i];
 4076: 	    /*
 4077: 	    * Skip NULLed entries.
 4078: 	    */
 4079: 	    if (n2 == NULL)
 4080: 		continue;
 4081: 	    if (set1->nodeMax == 0) {
 4082: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 4083: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 4084: 		if (set1->nodeTab == NULL) {
 4085: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 4086: 		    return(NULL);
 4087: 		}
 4088: 		memset(set1->nodeTab, 0,
 4089: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 4090: 		set1->nodeMax = XML_NODESET_DEFAULT;
 4091: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 4092: 		xmlNodePtr *temp;
 4093: 
 4094:                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
 4095:                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
 4096:                     return(NULL);
 4097:                 }
 4098: 		temp = (xmlNodePtr *) xmlRealloc(
 4099: 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
 4100: 		if (temp == NULL) {
 4101: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 4102: 		    return(NULL);
 4103: 		}
 4104: 		set1->nodeTab = temp;
 4105: 		set1->nodeMax *= 2;
 4106: 	    }
 4107: 	    set1->nodeTab[set1->nodeNr++] = n2;
 4108: 	}
 4109:     }
 4110:     set2->nodeNr = 0;
 4111:     return(set1);
 4112: }
 4113: 
 4114: /**
 4115:  * xmlXPathNodeSetDel:
 4116:  * @cur:  the initial node set
 4117:  * @val:  an xmlNodePtr
 4118:  *
 4119:  * Removes an xmlNodePtr from an existing NodeSet
 4120:  */
 4121: void
 4122: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
 4123:     int i;
 4124: 
 4125:     if (cur == NULL) return;
 4126:     if (val == NULL) return;
 4127: 
 4128:     /*
 4129:      * find node in nodeTab
 4130:      */
 4131:     for (i = 0;i < cur->nodeNr;i++)
 4132:         if (cur->nodeTab[i] == val) break;
 4133: 
 4134:     if (i >= cur->nodeNr) {	/* not found */
 4135: #ifdef DEBUG
 4136:         xmlGenericError(xmlGenericErrorContext,
 4137: 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
 4138: 		val->name);
 4139: #endif
 4140:         return;
 4141:     }
 4142:     if ((cur->nodeTab[i] != NULL) &&
 4143: 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4144: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
 4145:     cur->nodeNr--;
 4146:     for (;i < cur->nodeNr;i++)
 4147:         cur->nodeTab[i] = cur->nodeTab[i + 1];
 4148:     cur->nodeTab[cur->nodeNr] = NULL;
 4149: }
 4150: 
 4151: /**
 4152:  * xmlXPathNodeSetRemove:
 4153:  * @cur:  the initial node set
 4154:  * @val:  the index to remove
 4155:  *
 4156:  * Removes an entry from an existing NodeSet list.
 4157:  */
 4158: void
 4159: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
 4160:     if (cur == NULL) return;
 4161:     if (val >= cur->nodeNr) return;
 4162:     if ((cur->nodeTab[val] != NULL) &&
 4163: 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
 4164: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
 4165:     cur->nodeNr--;
 4166:     for (;val < cur->nodeNr;val++)
 4167:         cur->nodeTab[val] = cur->nodeTab[val + 1];
 4168:     cur->nodeTab[cur->nodeNr] = NULL;
 4169: }
 4170: 
 4171: /**
 4172:  * xmlXPathFreeNodeSet:
 4173:  * @obj:  the xmlNodeSetPtr to free
 4174:  *
 4175:  * Free the NodeSet compound (not the actual nodes !).
 4176:  */
 4177: void
 4178: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
 4179:     if (obj == NULL) return;
 4180:     if (obj->nodeTab != NULL) {
 4181: 	int i;
 4182: 
 4183: 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4184: 	for (i = 0;i < obj->nodeNr;i++)
 4185: 	    if ((obj->nodeTab[i] != NULL) &&
 4186: 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4187: 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4188: 	xmlFree(obj->nodeTab);
 4189:     }
 4190:     xmlFree(obj);
 4191: }
 4192: 
 4193: /**
 4194:  * xmlXPathNodeSetClear:
 4195:  * @set:  the node set to clear
 4196:  *
 4197:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
 4198:  * are feed), but does *not* free the list itself. Sets the length of the
 4199:  * list to 0.
 4200:  */
 4201: static void
 4202: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
 4203: {
 4204:     if ((set == NULL) || (set->nodeNr <= 0))
 4205: 	return;
 4206:     else if (hasNsNodes) {
 4207: 	int i;
 4208: 	xmlNodePtr node;
 4209: 
 4210: 	for (i = 0; i < set->nodeNr; i++) {
 4211: 	    node = set->nodeTab[i];
 4212: 	    if ((node != NULL) &&
 4213: 		(node->type == XML_NAMESPACE_DECL))
 4214: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4215: 	}
 4216:     }
 4217:     set->nodeNr = 0;
 4218: }
 4219: 
 4220: /**
 4221:  * xmlXPathNodeSetClearFromPos:
 4222:  * @set: the node set to be cleared
 4223:  * @pos: the start position to clear from
 4224:  *
 4225:  * Clears the list from temporary XPath objects (e.g. namespace nodes
 4226:  * are feed) starting with the entry at @pos, but does *not* free the list
 4227:  * itself. Sets the length of the list to @pos.
 4228:  */
 4229: static void
 4230: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
 4231: {
 4232:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
 4233: 	return;
 4234:     else if ((hasNsNodes)) {
 4235: 	int i;
 4236: 	xmlNodePtr node;
 4237: 
 4238: 	for (i = pos; i < set->nodeNr; i++) {
 4239: 	    node = set->nodeTab[i];
 4240: 	    if ((node != NULL) &&
 4241: 		(node->type == XML_NAMESPACE_DECL))
 4242: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4243: 	}
 4244:     }
 4245:     set->nodeNr = pos;
 4246: }
 4247: 
 4248: /**
 4249:  * xmlXPathFreeValueTree:
 4250:  * @obj:  the xmlNodeSetPtr to free
 4251:  *
 4252:  * Free the NodeSet compound and the actual tree, this is different
 4253:  * from xmlXPathFreeNodeSet()
 4254:  */
 4255: static void
 4256: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
 4257:     int i;
 4258: 
 4259:     if (obj == NULL) return;
 4260: 
 4261:     if (obj->nodeTab != NULL) {
 4262: 	for (i = 0;i < obj->nodeNr;i++) {
 4263: 	    if (obj->nodeTab[i] != NULL) {
 4264: 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 4265: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4266: 		} else {
 4267: 		    xmlFreeNodeList(obj->nodeTab[i]);
 4268: 		}
 4269: 	    }
 4270: 	}
 4271: 	xmlFree(obj->nodeTab);
 4272:     }
 4273:     xmlFree(obj);
 4274: }
 4275: 
 4276: #if defined(DEBUG) || defined(DEBUG_STEP)
 4277: /**
 4278:  * xmlGenericErrorContextNodeSet:
 4279:  * @output:  a FILE * for the output
 4280:  * @obj:  the xmlNodeSetPtr to display
 4281:  *
 4282:  * Quick display of a NodeSet
 4283:  */
 4284: void
 4285: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
 4286:     int i;
 4287: 
 4288:     if (output == NULL) output = xmlGenericErrorContext;
 4289:     if (obj == NULL)  {
 4290:         fprintf(output, "NodeSet == NULL !\n");
 4291: 	return;
 4292:     }
 4293:     if (obj->nodeNr == 0) {
 4294:         fprintf(output, "NodeSet is empty\n");
 4295: 	return;
 4296:     }
 4297:     if (obj->nodeTab == NULL) {
 4298: 	fprintf(output, " nodeTab == NULL !\n");
 4299: 	return;
 4300:     }
 4301:     for (i = 0; i < obj->nodeNr; i++) {
 4302:         if (obj->nodeTab[i] == NULL) {
 4303: 	    fprintf(output, " NULL !\n");
 4304: 	    return;
 4305:         }
 4306: 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
 4307: 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
 4308: 	    fprintf(output, " /");
 4309: 	else if (obj->nodeTab[i]->name == NULL)
 4310: 	    fprintf(output, " noname!");
 4311: 	else fprintf(output, " %s", obj->nodeTab[i]->name);
 4312:     }
 4313:     fprintf(output, "\n");
 4314: }
 4315: #endif
 4316: 
 4317: /**
 4318:  * xmlXPathNewNodeSet:
 4319:  * @val:  the NodePtr value
 4320:  *
 4321:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4322:  * it with the single Node @val
 4323:  *
 4324:  * Returns the newly created object.
 4325:  */
 4326: xmlXPathObjectPtr
 4327: xmlXPathNewNodeSet(xmlNodePtr val) {
 4328:     xmlXPathObjectPtr ret;
 4329: 
 4330:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4331:     if (ret == NULL) {
 4332:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 4333: 	return(NULL);
 4334:     }
 4335:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4336:     ret->type = XPATH_NODESET;
 4337:     ret->boolval = 0;
 4338:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4339:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4340: #ifdef XP_DEBUG_OBJ_USAGE
 4341:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4342: #endif
 4343:     return(ret);
 4344: }
 4345: 
 4346: /**
 4347:  * xmlXPathNewValueTree:
 4348:  * @val:  the NodePtr value
 4349:  *
 4350:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
 4351:  * it with the tree root @val
 4352:  *
 4353:  * Returns the newly created object.
 4354:  */
 4355: xmlXPathObjectPtr
 4356: xmlXPathNewValueTree(xmlNodePtr val) {
 4357:     xmlXPathObjectPtr ret;
 4358: 
 4359:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4360:     if (ret == NULL) {
 4361:         xmlXPathErrMemory(NULL, "creating result value tree\n");
 4362: 	return(NULL);
 4363:     }
 4364:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4365:     ret->type = XPATH_XSLT_TREE;
 4366:     ret->boolval = 1;
 4367:     ret->user = (void *) val;
 4368:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4369: #ifdef XP_DEBUG_OBJ_USAGE
 4370:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
 4371: #endif
 4372:     return(ret);
 4373: }
 4374: 
 4375: /**
 4376:  * xmlXPathNewNodeSetList:
 4377:  * @val:  an existing NodeSet
 4378:  *
 4379:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4380:  * it with the Nodeset @val
 4381:  *
 4382:  * Returns the newly created object.
 4383:  */
 4384: xmlXPathObjectPtr
 4385: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
 4386: {
 4387:     xmlXPathObjectPtr ret;
 4388:     int i;
 4389: 
 4390:     if (val == NULL)
 4391:         ret = NULL;
 4392:     else if (val->nodeTab == NULL)
 4393:         ret = xmlXPathNewNodeSet(NULL);
 4394:     else {
 4395:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
 4396:         if (ret) {
 4397:             for (i = 1; i < val->nodeNr; ++i) {
 4398:                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
 4399: 		    < 0) break;
 4400: 	    }
 4401: 	}
 4402:     }
 4403: 
 4404:     return (ret);
 4405: }
 4406: 
 4407: /**
 4408:  * xmlXPathWrapNodeSet:
 4409:  * @val:  the NodePtr value
 4410:  *
 4411:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 4412:  *
 4413:  * Returns the newly created object.
 4414:  */
 4415: xmlXPathObjectPtr
 4416: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
 4417:     xmlXPathObjectPtr ret;
 4418: 
 4419:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4420:     if (ret == NULL) {
 4421:         xmlXPathErrMemory(NULL, "creating node set object\n");
 4422: 	return(NULL);
 4423:     }
 4424:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4425:     ret->type = XPATH_NODESET;
 4426:     ret->nodesetval = val;
 4427: #ifdef XP_DEBUG_OBJ_USAGE
 4428:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4429: #endif
 4430:     return(ret);
 4431: }
 4432: 
 4433: /**
 4434:  * xmlXPathFreeNodeSetList:
 4435:  * @obj:  an existing NodeSetList object
 4436:  *
 4437:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
 4438:  * the list contrary to xmlXPathFreeObject().
 4439:  */
 4440: void
 4441: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
 4442:     if (obj == NULL) return;
 4443: #ifdef XP_DEBUG_OBJ_USAGE
 4444:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 4445: #endif
 4446:     xmlFree(obj);
 4447: }
 4448: 
 4449: /**
 4450:  * xmlXPathDifference:
 4451:  * @nodes1:  a node-set
 4452:  * @nodes2:  a node-set
 4453:  *
 4454:  * Implements the EXSLT - Sets difference() function:
 4455:  *    node-set set:difference (node-set, node-set)
 4456:  *
 4457:  * Returns the difference between the two node sets, or nodes1 if
 4458:  *         nodes2 is empty
 4459:  */
 4460: xmlNodeSetPtr
 4461: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4462:     xmlNodeSetPtr ret;
 4463:     int i, l1;
 4464:     xmlNodePtr cur;
 4465: 
 4466:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4467: 	return(nodes1);
 4468: 
 4469:     ret = xmlXPathNodeSetCreate(NULL);
 4470:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4471: 	return(ret);
 4472: 
 4473:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4474: 
 4475:     for (i = 0; i < l1; i++) {
 4476: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4477: 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
 4478: 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 4479: 	        break;
 4480: 	}
 4481:     }
 4482:     return(ret);
 4483: }
 4484: 
 4485: /**
 4486:  * xmlXPathIntersection:
 4487:  * @nodes1:  a node-set
 4488:  * @nodes2:  a node-set
 4489:  *
 4490:  * Implements the EXSLT - Sets intersection() function:
 4491:  *    node-set set:intersection (node-set, node-set)
 4492:  *
 4493:  * Returns a node set comprising the nodes that are within both the
 4494:  *         node sets passed as arguments
 4495:  */
 4496: xmlNodeSetPtr
 4497: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4498:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
 4499:     int i, l1;
 4500:     xmlNodePtr cur;
 4501: 
 4502:     if (ret == NULL)
 4503:         return(ret);
 4504:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4505: 	return(ret);
 4506:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4507: 	return(ret);
 4508: 
 4509:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4510: 
 4511:     for (i = 0; i < l1; i++) {
 4512: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4513: 	if (xmlXPathNodeSetContains(nodes2, cur)) {
 4514: 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 4515: 	        break;
 4516: 	}
 4517:     }
 4518:     return(ret);
 4519: }
 4520: 
 4521: /**
 4522:  * xmlXPathDistinctSorted:
 4523:  * @nodes:  a node-set, sorted by document order
 4524:  *
 4525:  * Implements the EXSLT - Sets distinct() function:
 4526:  *    node-set set:distinct (node-set)
 4527:  *
 4528:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4529:  *         it is empty
 4530:  */
 4531: xmlNodeSetPtr
 4532: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
 4533:     xmlNodeSetPtr ret;
 4534:     xmlHashTablePtr hash;
 4535:     int i, l;
 4536:     xmlChar * strval;
 4537:     xmlNodePtr cur;
 4538: 
 4539:     if (xmlXPathNodeSetIsEmpty(nodes))
 4540: 	return(nodes);
 4541: 
 4542:     ret = xmlXPathNodeSetCreate(NULL);
 4543:     if (ret == NULL)
 4544:         return(ret);
 4545:     l = xmlXPathNodeSetGetLength(nodes);
 4546:     hash = xmlHashCreate (l);
 4547:     for (i = 0; i < l; i++) {
 4548: 	cur = xmlXPathNodeSetItem(nodes, i);
 4549: 	strval = xmlXPathCastNodeToString(cur);
 4550: 	if (xmlHashLookup(hash, strval) == NULL) {
 4551: 	    xmlHashAddEntry(hash, strval, strval);
 4552: 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 4553: 	        break;
 4554: 	} else {
 4555: 	    xmlFree(strval);
 4556: 	}
 4557:     }
 4558:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
 4559:     return(ret);
 4560: }
 4561: 
 4562: /**
 4563:  * xmlXPathDistinct:
 4564:  * @nodes:  a node-set
 4565:  *
 4566:  * Implements the EXSLT - Sets distinct() function:
 4567:  *    node-set set:distinct (node-set)
 4568:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
 4569:  * is called with the sorted node-set
 4570:  *
 4571:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4572:  *         it is empty
 4573:  */
 4574: xmlNodeSetPtr
 4575: xmlXPathDistinct (xmlNodeSetPtr nodes) {
 4576:     if (xmlXPathNodeSetIsEmpty(nodes))
 4577: 	return(nodes);
 4578: 
 4579:     xmlXPathNodeSetSort(nodes);
 4580:     return(xmlXPathDistinctSorted(nodes));
 4581: }
 4582: 
 4583: /**
 4584:  * xmlXPathHasSameNodes:
 4585:  * @nodes1:  a node-set
 4586:  * @nodes2:  a node-set
 4587:  *
 4588:  * Implements the EXSLT - Sets has-same-nodes function:
 4589:  *    boolean set:has-same-node(node-set, node-set)
 4590:  *
 4591:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
 4592:  *         otherwise
 4593:  */
 4594: int
 4595: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4596:     int i, l;
 4597:     xmlNodePtr cur;
 4598: 
 4599:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
 4600: 	xmlXPathNodeSetIsEmpty(nodes2))
 4601: 	return(0);
 4602: 
 4603:     l = xmlXPathNodeSetGetLength(nodes1);
 4604:     for (i = 0; i < l; i++) {
 4605: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4606: 	if (xmlXPathNodeSetContains(nodes2, cur))
 4607: 	    return(1);
 4608:     }
 4609:     return(0);
 4610: }
 4611: 
 4612: /**
 4613:  * xmlXPathNodeLeadingSorted:
 4614:  * @nodes: a node-set, sorted by document order
 4615:  * @node: a node
 4616:  *
 4617:  * Implements the EXSLT - Sets leading() function:
 4618:  *    node-set set:leading (node-set, node-set)
 4619:  *
 4620:  * Returns the nodes in @nodes that precede @node in document order,
 4621:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4622:  *         doesn't contain @node
 4623:  */
 4624: xmlNodeSetPtr
 4625: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4626:     int i, l;
 4627:     xmlNodePtr cur;
 4628:     xmlNodeSetPtr ret;
 4629: 
 4630:     if (node == NULL)
 4631: 	return(nodes);
 4632: 
 4633:     ret = xmlXPathNodeSetCreate(NULL);
 4634:     if (ret == NULL)
 4635:         return(ret);
 4636:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4637: 	(!xmlXPathNodeSetContains(nodes, node)))
 4638: 	return(ret);
 4639: 
 4640:     l = xmlXPathNodeSetGetLength(nodes);
 4641:     for (i = 0; i < l; i++) {
 4642: 	cur = xmlXPathNodeSetItem(nodes, i);
 4643: 	if (cur == node)
 4644: 	    break;
 4645: 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 4646: 	    break;
 4647:     }
 4648:     return(ret);
 4649: }
 4650: 
 4651: /**
 4652:  * xmlXPathNodeLeading:
 4653:  * @nodes:  a node-set
 4654:  * @node:  a node
 4655:  *
 4656:  * Implements the EXSLT - Sets leading() function:
 4657:  *    node-set set:leading (node-set, node-set)
 4658:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
 4659:  * is called.
 4660:  *
 4661:  * Returns the nodes in @nodes that precede @node in document order,
 4662:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4663:  *         doesn't contain @node
 4664:  */
 4665: xmlNodeSetPtr
 4666: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4667:     xmlXPathNodeSetSort(nodes);
 4668:     return(xmlXPathNodeLeadingSorted(nodes, node));
 4669: }
 4670: 
 4671: /**
 4672:  * xmlXPathLeadingSorted:
 4673:  * @nodes1:  a node-set, sorted by document order
 4674:  * @nodes2:  a node-set, sorted by document order
 4675:  *
 4676:  * Implements the EXSLT - Sets leading() function:
 4677:  *    node-set set:leading (node-set, node-set)
 4678:  *
 4679:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4680:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4681:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4682:  */
 4683: xmlNodeSetPtr
 4684: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4685:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4686: 	return(nodes1);
 4687:     return(xmlXPathNodeLeadingSorted(nodes1,
 4688: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4689: }
 4690: 
 4691: /**
 4692:  * xmlXPathLeading:
 4693:  * @nodes1:  a node-set
 4694:  * @nodes2:  a node-set
 4695:  *
 4696:  * Implements the EXSLT - Sets leading() function:
 4697:  *    node-set set:leading (node-set, node-set)
 4698:  * @nodes1 and @nodes2 are sorted by document order, then
 4699:  * #exslSetsLeadingSorted is called.
 4700:  *
 4701:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4702:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4703:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4704:  */
 4705: xmlNodeSetPtr
 4706: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4707:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4708: 	return(nodes1);
 4709:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4710: 	return(xmlXPathNodeSetCreate(NULL));
 4711:     xmlXPathNodeSetSort(nodes1);
 4712:     xmlXPathNodeSetSort(nodes2);
 4713:     return(xmlXPathNodeLeadingSorted(nodes1,
 4714: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4715: }
 4716: 
 4717: /**
 4718:  * xmlXPathNodeTrailingSorted:
 4719:  * @nodes: a node-set, sorted by document order
 4720:  * @node: a node
 4721:  *
 4722:  * Implements the EXSLT - Sets trailing() function:
 4723:  *    node-set set:trailing (node-set, node-set)
 4724:  *
 4725:  * Returns the nodes in @nodes that follow @node in document order,
 4726:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4727:  *         doesn't contain @node
 4728:  */
 4729: xmlNodeSetPtr
 4730: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4731:     int i, l;
 4732:     xmlNodePtr cur;
 4733:     xmlNodeSetPtr ret;
 4734: 
 4735:     if (node == NULL)
 4736: 	return(nodes);
 4737: 
 4738:     ret = xmlXPathNodeSetCreate(NULL);
 4739:     if (ret == NULL)
 4740:         return(ret);
 4741:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4742: 	(!xmlXPathNodeSetContains(nodes, node)))
 4743: 	return(ret);
 4744: 
 4745:     l = xmlXPathNodeSetGetLength(nodes);
 4746:     for (i = l - 1; i >= 0; i--) {
 4747: 	cur = xmlXPathNodeSetItem(nodes, i);
 4748: 	if (cur == node)
 4749: 	    break;
 4750: 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
 4751: 	    break;
 4752:     }
 4753:     xmlXPathNodeSetSort(ret);	/* bug 413451 */
 4754:     return(ret);
 4755: }
 4756: 
 4757: /**
 4758:  * xmlXPathNodeTrailing:
 4759:  * @nodes:  a node-set
 4760:  * @node:  a node
 4761:  *
 4762:  * Implements the EXSLT - Sets trailing() function:
 4763:  *    node-set set:trailing (node-set, node-set)
 4764:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
 4765:  * is called.
 4766:  *
 4767:  * Returns the nodes in @nodes that follow @node in document order,
 4768:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4769:  *         doesn't contain @node
 4770:  */
 4771: xmlNodeSetPtr
 4772: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4773:     xmlXPathNodeSetSort(nodes);
 4774:     return(xmlXPathNodeTrailingSorted(nodes, node));
 4775: }
 4776: 
 4777: /**
 4778:  * xmlXPathTrailingSorted:
 4779:  * @nodes1:  a node-set, sorted by document order
 4780:  * @nodes2:  a node-set, sorted by document order
 4781:  *
 4782:  * Implements the EXSLT - Sets trailing() function:
 4783:  *    node-set set:trailing (node-set, node-set)
 4784:  *
 4785:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4786:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4787:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4788:  */
 4789: xmlNodeSetPtr
 4790: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4791:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4792: 	return(nodes1);
 4793:     return(xmlXPathNodeTrailingSorted(nodes1,
 4794: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4795: }
 4796: 
 4797: /**
 4798:  * xmlXPathTrailing:
 4799:  * @nodes1:  a node-set
 4800:  * @nodes2:  a node-set
 4801:  *
 4802:  * Implements the EXSLT - Sets trailing() function:
 4803:  *    node-set set:trailing (node-set, node-set)
 4804:  * @nodes1 and @nodes2 are sorted by document order, then
 4805:  * #xmlXPathTrailingSorted is called.
 4806:  *
 4807:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4808:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4809:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4810:  */
 4811: xmlNodeSetPtr
 4812: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4813:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4814: 	return(nodes1);
 4815:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4816: 	return(xmlXPathNodeSetCreate(NULL));
 4817:     xmlXPathNodeSetSort(nodes1);
 4818:     xmlXPathNodeSetSort(nodes2);
 4819:     return(xmlXPathNodeTrailingSorted(nodes1,
 4820: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4821: }
 4822: 
 4823: /************************************************************************
 4824:  *									*
 4825:  *		Routines to handle extra functions			*
 4826:  *									*
 4827:  ************************************************************************/
 4828: 
 4829: /**
 4830:  * xmlXPathRegisterFunc:
 4831:  * @ctxt:  the XPath context
 4832:  * @name:  the function name
 4833:  * @f:  the function implementation or NULL
 4834:  *
 4835:  * Register a new function. If @f is NULL it unregisters the function
 4836:  *
 4837:  * Returns 0 in case of success, -1 in case of error
 4838:  */
 4839: int
 4840: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
 4841: 		     xmlXPathFunction f) {
 4842:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
 4843: }
 4844: 
 4845: /**
 4846:  * xmlXPathRegisterFuncNS:
 4847:  * @ctxt:  the XPath context
 4848:  * @name:  the function name
 4849:  * @ns_uri:  the function namespace URI
 4850:  * @f:  the function implementation or NULL
 4851:  *
 4852:  * Register a new function. If @f is NULL it unregisters the function
 4853:  *
 4854:  * Returns 0 in case of success, -1 in case of error
 4855:  */
 4856: int
 4857: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4858: 		       const xmlChar *ns_uri, xmlXPathFunction f) {
 4859:     if (ctxt == NULL)
 4860: 	return(-1);
 4861:     if (name == NULL)
 4862: 	return(-1);
 4863: 
 4864:     if (ctxt->funcHash == NULL)
 4865: 	ctxt->funcHash = xmlHashCreate(0);
 4866:     if (ctxt->funcHash == NULL)
 4867: 	return(-1);
 4868:     if (f == NULL)
 4869:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
 4870:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
 4871: }
 4872: 
 4873: /**
 4874:  * xmlXPathRegisterFuncLookup:
 4875:  * @ctxt:  the XPath context
 4876:  * @f:  the lookup function
 4877:  * @funcCtxt:  the lookup data
 4878:  *
 4879:  * Registers an external mechanism to do function lookup.
 4880:  */
 4881: void
 4882: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
 4883: 			    xmlXPathFuncLookupFunc f,
 4884: 			    void *funcCtxt) {
 4885:     if (ctxt == NULL)
 4886: 	return;
 4887:     ctxt->funcLookupFunc = f;
 4888:     ctxt->funcLookupData = funcCtxt;
 4889: }
 4890: 
 4891: /**
 4892:  * xmlXPathFunctionLookup:
 4893:  * @ctxt:  the XPath context
 4894:  * @name:  the function name
 4895:  *
 4896:  * Search in the Function array of the context for the given
 4897:  * function.
 4898:  *
 4899:  * Returns the xmlXPathFunction or NULL if not found
 4900:  */
 4901: xmlXPathFunction
 4902: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 4903:     if (ctxt == NULL)
 4904: 	return (NULL);
 4905: 
 4906:     if (ctxt->funcLookupFunc != NULL) {
 4907: 	xmlXPathFunction ret;
 4908: 	xmlXPathFuncLookupFunc f;
 4909: 
 4910: 	f = ctxt->funcLookupFunc;
 4911: 	ret = f(ctxt->funcLookupData, name, NULL);
 4912: 	if (ret != NULL)
 4913: 	    return(ret);
 4914:     }
 4915:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
 4916: }
 4917: 
 4918: /**
 4919:  * xmlXPathFunctionLookupNS:
 4920:  * @ctxt:  the XPath context
 4921:  * @name:  the function name
 4922:  * @ns_uri:  the function namespace URI
 4923:  *
 4924:  * Search in the Function array of the context for the given
 4925:  * function.
 4926:  *
 4927:  * Returns the xmlXPathFunction or NULL if not found
 4928:  */
 4929: xmlXPathFunction
 4930: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4931: 			 const xmlChar *ns_uri) {
 4932:     xmlXPathFunction ret;
 4933: 
 4934:     if (ctxt == NULL)
 4935: 	return(NULL);
 4936:     if (name == NULL)
 4937: 	return(NULL);
 4938: 
 4939:     if (ctxt->funcLookupFunc != NULL) {
 4940: 	xmlXPathFuncLookupFunc f;
 4941: 
 4942: 	f = ctxt->funcLookupFunc;
 4943: 	ret = f(ctxt->funcLookupData, name, ns_uri);
 4944: 	if (ret != NULL)
 4945: 	    return(ret);
 4946:     }
 4947: 
 4948:     if (ctxt->funcHash == NULL)
 4949: 	return(NULL);
 4950: 
 4951:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
 4952:     return(ret);
 4953: }
 4954: 
 4955: /**
 4956:  * xmlXPathRegisteredFuncsCleanup:
 4957:  * @ctxt:  the XPath context
 4958:  *
 4959:  * Cleanup the XPath context data associated to registered functions
 4960:  */
 4961: void
 4962: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
 4963:     if (ctxt == NULL)
 4964: 	return;
 4965: 
 4966:     xmlHashFree(ctxt->funcHash, NULL);
 4967:     ctxt->funcHash = NULL;
 4968: }
 4969: 
 4970: /************************************************************************
 4971:  *									*
 4972:  *			Routines to handle Variables			*
 4973:  *									*
 4974:  ************************************************************************/
 4975: 
 4976: /**
 4977:  * xmlXPathRegisterVariable:
 4978:  * @ctxt:  the XPath context
 4979:  * @name:  the variable name
 4980:  * @value:  the variable value or NULL
 4981:  *
 4982:  * Register a new variable value. If @value is NULL it unregisters
 4983:  * the variable
 4984:  *
 4985:  * Returns 0 in case of success, -1 in case of error
 4986:  */
 4987: int
 4988: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
 4989: 			 xmlXPathObjectPtr value) {
 4990:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
 4991: }
 4992: 
 4993: /**
 4994:  * xmlXPathRegisterVariableNS:
 4995:  * @ctxt:  the XPath context
 4996:  * @name:  the variable name
 4997:  * @ns_uri:  the variable namespace URI
 4998:  * @value:  the variable value or NULL
 4999:  *
 5000:  * Register a new variable value. If @value is NULL it unregisters
 5001:  * the variable
 5002:  *
 5003:  * Returns 0 in case of success, -1 in case of error
 5004:  */
 5005: int
 5006: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 5007: 			   const xmlChar *ns_uri,
 5008: 			   xmlXPathObjectPtr value) {
 5009:     if (ctxt == NULL)
 5010: 	return(-1);
 5011:     if (name == NULL)
 5012: 	return(-1);
 5013: 
 5014:     if (ctxt->varHash == NULL)
 5015: 	ctxt->varHash = xmlHashCreate(0);
 5016:     if (ctxt->varHash == NULL)
 5017: 	return(-1);
 5018:     if (value == NULL)
 5019:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
 5020: 	                           (xmlHashDeallocator)xmlXPathFreeObject));
 5021:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
 5022: 			       (void *) value,
 5023: 			       (xmlHashDeallocator)xmlXPathFreeObject));
 5024: }
 5025: 
 5026: /**
 5027:  * xmlXPathRegisterVariableLookup:
 5028:  * @ctxt:  the XPath context
 5029:  * @f:  the lookup function
 5030:  * @data:  the lookup data
 5031:  *
 5032:  * register an external mechanism to do variable lookup
 5033:  */
 5034: void
 5035: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
 5036: 	 xmlXPathVariableLookupFunc f, void *data) {
 5037:     if (ctxt == NULL)
 5038: 	return;
 5039:     ctxt->varLookupFunc = f;
 5040:     ctxt->varLookupData = data;
 5041: }
 5042: 
 5043: /**
 5044:  * xmlXPathVariableLookup:
 5045:  * @ctxt:  the XPath context
 5046:  * @name:  the variable name
 5047:  *
 5048:  * Search in the Variable array of the context for the given
 5049:  * variable value.
 5050:  *
 5051:  * Returns a copy of the value or NULL if not found
 5052:  */
 5053: xmlXPathObjectPtr
 5054: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 5055:     if (ctxt == NULL)
 5056: 	return(NULL);
 5057: 
 5058:     if (ctxt->varLookupFunc != NULL) {
 5059: 	xmlXPathObjectPtr ret;
 5060: 
 5061: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 5062: 	        (ctxt->varLookupData, name, NULL);
 5063: 	return(ret);
 5064:     }
 5065:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
 5066: }
 5067: 
 5068: /**
 5069:  * xmlXPathVariableLookupNS:
 5070:  * @ctxt:  the XPath context
 5071:  * @name:  the variable name
 5072:  * @ns_uri:  the variable namespace URI
 5073:  *
 5074:  * Search in the Variable array of the context for the given
 5075:  * variable value.
 5076:  *
 5077:  * Returns the a copy of the value or NULL if not found
 5078:  */
 5079: xmlXPathObjectPtr
 5080: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 5081: 			 const xmlChar *ns_uri) {
 5082:     if (ctxt == NULL)
 5083: 	return(NULL);
 5084: 
 5085:     if (ctxt->varLookupFunc != NULL) {
 5086: 	xmlXPathObjectPtr ret;
 5087: 
 5088: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 5089: 	        (ctxt->varLookupData, name, ns_uri);
 5090: 	if (ret != NULL) return(ret);
 5091:     }
 5092: 
 5093:     if (ctxt->varHash == NULL)
 5094: 	return(NULL);
 5095:     if (name == NULL)
 5096: 	return(NULL);
 5097: 
 5098:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
 5099: 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
 5100: }
 5101: 
 5102: /**
 5103:  * xmlXPathRegisteredVariablesCleanup:
 5104:  * @ctxt:  the XPath context
 5105:  *
 5106:  * Cleanup the XPath context data associated to registered variables
 5107:  */
 5108: void
 5109: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
 5110:     if (ctxt == NULL)
 5111: 	return;
 5112: 
 5113:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
 5114:     ctxt->varHash = NULL;
 5115: }
 5116: 
 5117: /**
 5118:  * xmlXPathRegisterNs:
 5119:  * @ctxt:  the XPath context
 5120:  * @prefix:  the namespace prefix cannot be NULL or empty string
 5121:  * @ns_uri:  the namespace name
 5122:  *
 5123:  * Register a new namespace. If @ns_uri is NULL it unregisters
 5124:  * the namespace
 5125:  *
 5126:  * Returns 0 in case of success, -1 in case of error
 5127:  */
 5128: int
 5129: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
 5130: 			   const xmlChar *ns_uri) {
 5131:     if (ctxt == NULL)
 5132: 	return(-1);
 5133:     if (prefix == NULL)
 5134: 	return(-1);
 5135:     if (prefix[0] == 0)
 5136: 	return(-1);
 5137: 
 5138:     if (ctxt->nsHash == NULL)
 5139: 	ctxt->nsHash = xmlHashCreate(10);
 5140:     if (ctxt->nsHash == NULL)
 5141: 	return(-1);
 5142:     if (ns_uri == NULL)
 5143:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
 5144: 	                          (xmlHashDeallocator)xmlFree));
 5145:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
 5146: 			      (xmlHashDeallocator)xmlFree));
 5147: }
 5148: 
 5149: /**
 5150:  * xmlXPathNsLookup:
 5151:  * @ctxt:  the XPath context
 5152:  * @prefix:  the namespace prefix value
 5153:  *
 5154:  * Search in the namespace declaration array of the context for the given
 5155:  * namespace name associated to the given prefix
 5156:  *
 5157:  * Returns the value or NULL if not found
 5158:  */
 5159: const xmlChar *
 5160: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
 5161:     if (ctxt == NULL)
 5162: 	return(NULL);
 5163:     if (prefix == NULL)
 5164: 	return(NULL);
 5165: 
 5166: #ifdef XML_XML_NAMESPACE
 5167:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
 5168: 	return(XML_XML_NAMESPACE);
 5169: #endif
 5170: 
 5171:     if (ctxt->namespaces != NULL) {
 5172: 	int i;
 5173: 
 5174: 	for (i = 0;i < ctxt->nsNr;i++) {
 5175: 	    if ((ctxt->namespaces[i] != NULL) &&
 5176: 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
 5177: 		return(ctxt->namespaces[i]->href);
 5178: 	}
 5179:     }
 5180: 
 5181:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
 5182: }
 5183: 
 5184: /**
 5185:  * xmlXPathRegisteredNsCleanup:
 5186:  * @ctxt:  the XPath context
 5187:  *
 5188:  * Cleanup the XPath context data associated to registered variables
 5189:  */
 5190: void
 5191: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
 5192:     if (ctxt == NULL)
 5193: 	return;
 5194: 
 5195:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
 5196:     ctxt->nsHash = NULL;
 5197: }
 5198: 
 5199: /************************************************************************
 5200:  *									*
 5201:  *			Routines to handle Values			*
 5202:  *									*
 5203:  ************************************************************************/
 5204: 
 5205: /* Allocations are terrible, one needs to optimize all this !!! */
 5206: 
 5207: /**
 5208:  * xmlXPathNewFloat:
 5209:  * @val:  the double value
 5210:  *
 5211:  * Create a new xmlXPathObjectPtr of type double and of value @val
 5212:  *
 5213:  * Returns the newly created object.
 5214:  */
 5215: xmlXPathObjectPtr
 5216: xmlXPathNewFloat(double val) {
 5217:     xmlXPathObjectPtr ret;
 5218: 
 5219:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5220:     if (ret == NULL) {
 5221:         xmlXPathErrMemory(NULL, "creating float object\n");
 5222: 	return(NULL);
 5223:     }
 5224:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5225:     ret->type = XPATH_NUMBER;
 5226:     ret->floatval = val;
 5227: #ifdef XP_DEBUG_OBJ_USAGE
 5228:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
 5229: #endif
 5230:     return(ret);
 5231: }
 5232: 
 5233: /**
 5234:  * xmlXPathNewBoolean:
 5235:  * @val:  the boolean value
 5236:  *
 5237:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
 5238:  *
 5239:  * Returns the newly created object.
 5240:  */
 5241: xmlXPathObjectPtr
 5242: xmlXPathNewBoolean(int val) {
 5243:     xmlXPathObjectPtr ret;
 5244: 
 5245:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5246:     if (ret == NULL) {
 5247:         xmlXPathErrMemory(NULL, "creating boolean object\n");
 5248: 	return(NULL);
 5249:     }
 5250:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5251:     ret->type = XPATH_BOOLEAN;
 5252:     ret->boolval = (val != 0);
 5253: #ifdef XP_DEBUG_OBJ_USAGE
 5254:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
 5255: #endif
 5256:     return(ret);
 5257: }
 5258: 
 5259: /**
 5260:  * xmlXPathNewString:
 5261:  * @val:  the xmlChar * value
 5262:  *
 5263:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5264:  *
 5265:  * Returns the newly created object.
 5266:  */
 5267: xmlXPathObjectPtr
 5268: xmlXPathNewString(const xmlChar *val) {
 5269:     xmlXPathObjectPtr ret;
 5270: 
 5271:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5272:     if (ret == NULL) {
 5273:         xmlXPathErrMemory(NULL, "creating string object\n");
 5274: 	return(NULL);
 5275:     }
 5276:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5277:     ret->type = XPATH_STRING;
 5278:     if (val != NULL)
 5279: 	ret->stringval = xmlStrdup(val);
 5280:     else
 5281: 	ret->stringval = xmlStrdup((const xmlChar *)"");
 5282: #ifdef XP_DEBUG_OBJ_USAGE
 5283:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5284: #endif
 5285:     return(ret);
 5286: }
 5287: 
 5288: /**
 5289:  * xmlXPathWrapString:
 5290:  * @val:  the xmlChar * value
 5291:  *
 5292:  * Wraps the @val string into an XPath object.
 5293:  *
 5294:  * Returns the newly created object.
 5295:  */
 5296: xmlXPathObjectPtr
 5297: xmlXPathWrapString (xmlChar *val) {
 5298:     xmlXPathObjectPtr ret;
 5299: 
 5300:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5301:     if (ret == NULL) {
 5302:         xmlXPathErrMemory(NULL, "creating string object\n");
 5303: 	return(NULL);
 5304:     }
 5305:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5306:     ret->type = XPATH_STRING;
 5307:     ret->stringval = val;
 5308: #ifdef XP_DEBUG_OBJ_USAGE
 5309:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5310: #endif
 5311:     return(ret);
 5312: }
 5313: 
 5314: /**
 5315:  * xmlXPathNewCString:
 5316:  * @val:  the char * value
 5317:  *
 5318:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5319:  *
 5320:  * Returns the newly created object.
 5321:  */
 5322: xmlXPathObjectPtr
 5323: xmlXPathNewCString(const char *val) {
 5324:     xmlXPathObjectPtr ret;
 5325: 
 5326:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5327:     if (ret == NULL) {
 5328:         xmlXPathErrMemory(NULL, "creating string object\n");
 5329: 	return(NULL);
 5330:     }
 5331:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5332:     ret->type = XPATH_STRING;
 5333:     ret->stringval = xmlStrdup(BAD_CAST val);
 5334: #ifdef XP_DEBUG_OBJ_USAGE
 5335:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5336: #endif
 5337:     return(ret);
 5338: }
 5339: 
 5340: /**
 5341:  * xmlXPathWrapCString:
 5342:  * @val:  the char * value
 5343:  *
 5344:  * Wraps a string into an XPath object.
 5345:  *
 5346:  * Returns the newly created object.
 5347:  */
 5348: xmlXPathObjectPtr
 5349: xmlXPathWrapCString (char * val) {
 5350:     return(xmlXPathWrapString((xmlChar *)(val)));
 5351: }
 5352: 
 5353: /**
 5354:  * xmlXPathWrapExternal:
 5355:  * @val:  the user data
 5356:  *
 5357:  * Wraps the @val data into an XPath object.
 5358:  *
 5359:  * Returns the newly created object.
 5360:  */
 5361: xmlXPathObjectPtr
 5362: xmlXPathWrapExternal (void *val) {
 5363:     xmlXPathObjectPtr ret;
 5364: 
 5365:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5366:     if (ret == NULL) {
 5367:         xmlXPathErrMemory(NULL, "creating user object\n");
 5368: 	return(NULL);
 5369:     }
 5370:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5371:     ret->type = XPATH_USERS;
 5372:     ret->user = val;
 5373: #ifdef XP_DEBUG_OBJ_USAGE
 5374:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
 5375: #endif
 5376:     return(ret);
 5377: }
 5378: 
 5379: /**
 5380:  * xmlXPathObjectCopy:
 5381:  * @val:  the original object
 5382:  *
 5383:  * allocate a new copy of a given object
 5384:  *
 5385:  * Returns the newly created object.
 5386:  */
 5387: xmlXPathObjectPtr
 5388: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
 5389:     xmlXPathObjectPtr ret;
 5390: 
 5391:     if (val == NULL)
 5392: 	return(NULL);
 5393: 
 5394:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5395:     if (ret == NULL) {
 5396:         xmlXPathErrMemory(NULL, "copying object\n");
 5397: 	return(NULL);
 5398:     }
 5399:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
 5400: #ifdef XP_DEBUG_OBJ_USAGE
 5401:     xmlXPathDebugObjUsageRequested(NULL, val->type);
 5402: #endif
 5403:     switch (val->type) {
 5404: 	case XPATH_BOOLEAN:
 5405: 	case XPATH_NUMBER:
 5406: 	case XPATH_POINT:
 5407: 	case XPATH_RANGE:
 5408: 	    break;
 5409: 	case XPATH_STRING:
 5410: 	    ret->stringval = xmlStrdup(val->stringval);
 5411: 	    break;
 5412: 	case XPATH_XSLT_TREE:
 5413: #if 0
 5414: /*
 5415:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
 5416:   this previous handling is no longer correct, and can cause some serious
 5417:   problems (ref. bug 145547)
 5418: */
 5419: 	    if ((val->nodesetval != NULL) &&
 5420: 		(val->nodesetval->nodeTab != NULL)) {
 5421: 		xmlNodePtr cur, tmp;
 5422: 		xmlDocPtr top;
 5423: 
 5424: 		ret->boolval = 1;
 5425: 		top =  xmlNewDoc(NULL);
 5426: 		top->name = (char *)
 5427: 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
 5428: 		ret->user = top;
 5429: 		if (top != NULL) {
 5430: 		    top->doc = top;
 5431: 		    cur = val->nodesetval->nodeTab[0]->children;
 5432: 		    while (cur != NULL) {
 5433: 			tmp = xmlDocCopyNode(cur, top, 1);
 5434: 			xmlAddChild((xmlNodePtr) top, tmp);
 5435: 			cur = cur->next;
 5436: 		    }
 5437: 		}
 5438: 
 5439: 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
 5440: 	    } else
 5441: 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
 5442: 	    /* Deallocate the copied tree value */
 5443: 	    break;
 5444: #endif
 5445: 	case XPATH_NODESET:
 5446: 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
 5447: 	    /* Do not deallocate the copied tree value */
 5448: 	    ret->boolval = 0;
 5449: 	    break;
 5450: 	case XPATH_LOCATIONSET:
 5451: #ifdef LIBXML_XPTR_ENABLED
 5452: 	{
 5453: 	    xmlLocationSetPtr loc = val->user;
 5454: 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
 5455: 	    break;
 5456: 	}
 5457: #endif
 5458:         case XPATH_USERS:
 5459: 	    ret->user = val->user;
 5460: 	    break;
 5461:         case XPATH_UNDEFINED:
 5462: 	    xmlGenericError(xmlGenericErrorContext,
 5463: 		    "xmlXPathObjectCopy: unsupported type %d\n",
 5464: 		    val->type);
 5465: 	    break;
 5466:     }
 5467:     return(ret);
 5468: }
 5469: 
 5470: /**
 5471:  * xmlXPathFreeObject:
 5472:  * @obj:  the object to free
 5473:  *
 5474:  * Free up an xmlXPathObjectPtr object.
 5475:  */
 5476: void
 5477: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
 5478:     if (obj == NULL) return;
 5479:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 5480: 	if (obj->boolval) {
 5481: #if 0
 5482: 	    if (obj->user != NULL) {
 5483:                 xmlXPathFreeNodeSet(obj->nodesetval);
 5484: 		xmlFreeNodeList((xmlNodePtr) obj->user);
 5485: 	    } else
 5486: #endif
 5487: 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
 5488: 	    if (obj->nodesetval != NULL)
 5489: 		xmlXPathFreeValueTree(obj->nodesetval);
 5490: 	} else {
 5491: 	    if (obj->nodesetval != NULL)
 5492: 		xmlXPathFreeNodeSet(obj->nodesetval);
 5493: 	}
 5494: #ifdef LIBXML_XPTR_ENABLED
 5495:     } else if (obj->type == XPATH_LOCATIONSET) {
 5496: 	if (obj->user != NULL)
 5497: 	    xmlXPtrFreeLocationSet(obj->user);
 5498: #endif
 5499:     } else if (obj->type == XPATH_STRING) {
 5500: 	if (obj->stringval != NULL)
 5501: 	    xmlFree(obj->stringval);
 5502:     }
 5503: #ifdef XP_DEBUG_OBJ_USAGE
 5504:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5505: #endif
 5506:     xmlFree(obj);
 5507: }
 5508: 
 5509: /**
 5510:  * xmlXPathReleaseObject:
 5511:  * @obj:  the xmlXPathObjectPtr to free or to cache
 5512:  *
 5513:  * Depending on the state of the cache this frees the given
 5514:  * XPath object or stores it in the cache.
 5515:  */
 5516: static void
 5517: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
 5518: {
 5519: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
 5520: 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
 5521:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
 5522: 
 5523: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
 5524: 
 5525:     if (obj == NULL)
 5526: 	return;
 5527:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
 5528: 	 xmlXPathFreeObject(obj);
 5529:     } else {
 5530: 	xmlXPathContextCachePtr cache =
 5531: 	    (xmlXPathContextCachePtr) ctxt->cache;
 5532: 
 5533: 	switch (obj->type) {
 5534: 	    case XPATH_NODESET:
 5535: 	    case XPATH_XSLT_TREE:
 5536: 		if (obj->nodesetval != NULL) {
 5537: 		    if (obj->boolval) {
 5538: 			/*
 5539: 			* It looks like the @boolval is used for
 5540: 			* evaluation if this an XSLT Result Tree Fragment.
 5541: 			* TODO: Check if this assumption is correct.
 5542: 			*/
 5543: 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
 5544: 			xmlXPathFreeValueTree(obj->nodesetval);
 5545: 			obj->nodesetval = NULL;
 5546: 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
 5547: 			(XP_CACHE_WANTS(cache->nodesetObjs,
 5548: 					cache->maxNodeset)))
 5549: 		    {
 5550: 			XP_CACHE_ADD(cache->nodesetObjs, obj);
 5551: 			goto obj_cached;
 5552: 		    } else {
 5553: 			xmlXPathFreeNodeSet(obj->nodesetval);
 5554: 			obj->nodesetval = NULL;
 5555: 		    }
 5556: 		}
 5557: 		break;
 5558: 	    case XPATH_STRING:
 5559: 		if (obj->stringval != NULL)
 5560: 		    xmlFree(obj->stringval);
 5561: 
 5562: 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
 5563: 		    XP_CACHE_ADD(cache->stringObjs, obj);
 5564: 		    goto obj_cached;
 5565: 		}
 5566: 		break;
 5567: 	    case XPATH_BOOLEAN:
 5568: 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
 5569: 		    XP_CACHE_ADD(cache->booleanObjs, obj);
 5570: 		    goto obj_cached;
 5571: 		}
 5572: 		break;
 5573: 	    case XPATH_NUMBER:
 5574: 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
 5575: 		    XP_CACHE_ADD(cache->numberObjs, obj);
 5576: 		    goto obj_cached;
 5577: 		}
 5578: 		break;
 5579: #ifdef LIBXML_XPTR_ENABLED
 5580: 	    case XPATH_LOCATIONSET:
 5581: 		if (obj->user != NULL) {
 5582: 		    xmlXPtrFreeLocationSet(obj->user);
 5583: 		}
 5584: 		goto free_obj;
 5585: #endif
 5586: 	    default:
 5587: 		goto free_obj;
 5588: 	}
 5589: 
 5590: 	/*
 5591: 	* Fallback to adding to the misc-objects slot.
 5592: 	*/
 5593: 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
 5594: 	    XP_CACHE_ADD(cache->miscObjs, obj);
 5595: 	} else
 5596: 	    goto free_obj;
 5597: 
 5598: obj_cached:
 5599: 
 5600: #ifdef XP_DEBUG_OBJ_USAGE
 5601: 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
 5602: #endif
 5603: 
 5604: 	if (obj->nodesetval != NULL) {
 5605: 	    xmlNodeSetPtr tmpset = obj->nodesetval;
 5606: 
 5607: 	    /*
 5608: 	    * TODO: Due to those nasty ns-nodes, we need to traverse
 5609: 	    *  the list and free the ns-nodes.
 5610: 	    * URGENT TODO: Check if it's actually slowing things down.
 5611: 	    *  Maybe we shouldn't try to preserve the list.
 5612: 	    */
 5613: 	    if (tmpset->nodeNr > 1) {
 5614: 		int i;
 5615: 		xmlNodePtr node;
 5616: 
 5617: 		for (i = 0; i < tmpset->nodeNr; i++) {
 5618: 		    node = tmpset->nodeTab[i];
 5619: 		    if ((node != NULL) &&
 5620: 			(node->type == XML_NAMESPACE_DECL))
 5621: 		    {
 5622: 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 5623: 		    }
 5624: 		}
 5625: 	    } else if (tmpset->nodeNr == 1) {
 5626: 		if ((tmpset->nodeTab[0] != NULL) &&
 5627: 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
 5628: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
 5629: 	    }
 5630: 	    tmpset->nodeNr = 0;
 5631: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5632: 	    obj->nodesetval = tmpset;
 5633: 	} else
 5634: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5635: 
 5636: 	return;
 5637: 
 5638: free_obj:
 5639: 	/*
 5640: 	* Cache is full; free the object.
 5641: 	*/
 5642: 	if (obj->nodesetval != NULL)
 5643: 	    xmlXPathFreeNodeSet(obj->nodesetval);
 5644: #ifdef XP_DEBUG_OBJ_USAGE
 5645: 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5646: #endif
 5647: 	xmlFree(obj);
 5648:     }
 5649:     return;
 5650: }
 5651: 
 5652: 
 5653: /************************************************************************
 5654:  *									*
 5655:  *			Type Casting Routines				*
 5656:  *									*
 5657:  ************************************************************************/
 5658: 
 5659: /**
 5660:  * xmlXPathCastBooleanToString:
 5661:  * @val:  a boolean
 5662:  *
 5663:  * Converts a boolean to its string value.
 5664:  *
 5665:  * Returns a newly allocated string.
 5666:  */
 5667: xmlChar *
 5668: xmlXPathCastBooleanToString (int val) {
 5669:     xmlChar *ret;
 5670:     if (val)
 5671: 	ret = xmlStrdup((const xmlChar *) "true");
 5672:     else
 5673: 	ret = xmlStrdup((const xmlChar *) "false");
 5674:     return(ret);
 5675: }
 5676: 
 5677: /**
 5678:  * xmlXPathCastNumberToString:
 5679:  * @val:  a number
 5680:  *
 5681:  * Converts a number to its string value.
 5682:  *
 5683:  * Returns a newly allocated string.
 5684:  */
 5685: xmlChar *
 5686: xmlXPathCastNumberToString (double val) {
 5687:     xmlChar *ret;
 5688:     switch (xmlXPathIsInf(val)) {
 5689:     case 1:
 5690: 	ret = xmlStrdup((const xmlChar *) "Infinity");
 5691: 	break;
 5692:     case -1:
 5693: 	ret = xmlStrdup((const xmlChar *) "-Infinity");
 5694: 	break;
 5695:     default:
 5696: 	if (xmlXPathIsNaN(val)) {
 5697: 	    ret = xmlStrdup((const xmlChar *) "NaN");
 5698: 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
 5699: 	    ret = xmlStrdup((const xmlChar *) "0");
 5700: 	} else {
 5701: 	    /* could be improved */
 5702: 	    char buf[100];
 5703: 	    xmlXPathFormatNumber(val, buf, 99);
 5704: 	    buf[99] = 0;
 5705: 	    ret = xmlStrdup((const xmlChar *) buf);
 5706: 	}
 5707:     }
 5708:     return(ret);
 5709: }
 5710: 
 5711: /**
 5712:  * xmlXPathCastNodeToString:
 5713:  * @node:  a node
 5714:  *
 5715:  * Converts a node to its string value.
 5716:  *
 5717:  * Returns a newly allocated string.
 5718:  */
 5719: xmlChar *
 5720: xmlXPathCastNodeToString (xmlNodePtr node) {
 5721: xmlChar *ret;
 5722:     if ((ret = xmlNodeGetContent(node)) == NULL)
 5723: 	ret = xmlStrdup((const xmlChar *) "");
 5724:     return(ret);
 5725: }
 5726: 
 5727: /**
 5728:  * xmlXPathCastNodeSetToString:
 5729:  * @ns:  a node-set
 5730:  *
 5731:  * Converts a node-set to its string value.
 5732:  *
 5733:  * Returns a newly allocated string.
 5734:  */
 5735: xmlChar *
 5736: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
 5737:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
 5738: 	return(xmlStrdup((const xmlChar *) ""));
 5739: 
 5740:     if (ns->nodeNr > 1)
 5741: 	xmlXPathNodeSetSort(ns);
 5742:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
 5743: }
 5744: 
 5745: /**
 5746:  * xmlXPathCastToString:
 5747:  * @val:  an XPath object
 5748:  *
 5749:  * Converts an existing object to its string() equivalent
 5750:  *
 5751:  * Returns the allocated string value of the object, NULL in case of error.
 5752:  *         It's up to the caller to free the string memory with xmlFree().
 5753:  */
 5754: xmlChar *
 5755: xmlXPathCastToString(xmlXPathObjectPtr val) {
 5756:     xmlChar *ret = NULL;
 5757: 
 5758:     if (val == NULL)
 5759: 	return(xmlStrdup((const xmlChar *) ""));
 5760:     switch (val->type) {
 5761: 	case XPATH_UNDEFINED:
 5762: #ifdef DEBUG_EXPR
 5763: 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
 5764: #endif
 5765: 	    ret = xmlStrdup((const xmlChar *) "");
 5766: 	    break;
 5767:         case XPATH_NODESET:
 5768:         case XPATH_XSLT_TREE:
 5769: 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
 5770: 	    break;
 5771: 	case XPATH_STRING:
 5772: 	    return(xmlStrdup(val->stringval));
 5773:         case XPATH_BOOLEAN:
 5774: 	    ret = xmlXPathCastBooleanToString(val->boolval);
 5775: 	    break;
 5776: 	case XPATH_NUMBER: {
 5777: 	    ret = xmlXPathCastNumberToString(val->floatval);
 5778: 	    break;
 5779: 	}
 5780: 	case XPATH_USERS:
 5781: 	case XPATH_POINT:
 5782: 	case XPATH_RANGE:
 5783: 	case XPATH_LOCATIONSET:
 5784: 	    TODO
 5785: 	    ret = xmlStrdup((const xmlChar *) "");
 5786: 	    break;
 5787:     }
 5788:     return(ret);
 5789: }
 5790: 
 5791: /**
 5792:  * xmlXPathConvertString:
 5793:  * @val:  an XPath object
 5794:  *
 5795:  * Converts an existing object to its string() equivalent
 5796:  *
 5797:  * Returns the new object, the old one is freed (or the operation
 5798:  *         is done directly on @val)
 5799:  */
 5800: xmlXPathObjectPtr
 5801: xmlXPathConvertString(xmlXPathObjectPtr val) {
 5802:     xmlChar *res = NULL;
 5803: 
 5804:     if (val == NULL)
 5805: 	return(xmlXPathNewCString(""));
 5806: 
 5807:     switch (val->type) {
 5808:     case XPATH_UNDEFINED:
 5809: #ifdef DEBUG_EXPR
 5810: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 5811: #endif
 5812: 	break;
 5813:     case XPATH_NODESET:
 5814:     case XPATH_XSLT_TREE:
 5815: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 5816: 	break;
 5817:     case XPATH_STRING:
 5818: 	return(val);
 5819:     case XPATH_BOOLEAN:
 5820: 	res = xmlXPathCastBooleanToString(val->boolval);
 5821: 	break;
 5822:     case XPATH_NUMBER:
 5823: 	res = xmlXPathCastNumberToString(val->floatval);
 5824: 	break;
 5825:     case XPATH_USERS:
 5826:     case XPATH_POINT:
 5827:     case XPATH_RANGE:
 5828:     case XPATH_LOCATIONSET:
 5829: 	TODO;
 5830: 	break;
 5831:     }
 5832:     xmlXPathFreeObject(val);
 5833:     if (res == NULL)
 5834: 	return(xmlXPathNewCString(""));
 5835:     return(xmlXPathWrapString(res));
 5836: }
 5837: 
 5838: /**
 5839:  * xmlXPathCastBooleanToNumber:
 5840:  * @val:  a boolean
 5841:  *
 5842:  * Converts a boolean to its number value
 5843:  *
 5844:  * Returns the number value
 5845:  */
 5846: double
 5847: xmlXPathCastBooleanToNumber(int val) {
 5848:     if (val)
 5849: 	return(1.0);
 5850:     return(0.0);
 5851: }
 5852: 
 5853: /**
 5854:  * xmlXPathCastStringToNumber:
 5855:  * @val:  a string
 5856:  *
 5857:  * Converts a string to its number value
 5858:  *
 5859:  * Returns the number value
 5860:  */
 5861: double
 5862: xmlXPathCastStringToNumber(const xmlChar * val) {
 5863:     return(xmlXPathStringEvalNumber(val));
 5864: }
 5865: 
 5866: /**
 5867:  * xmlXPathCastNodeToNumber:
 5868:  * @node:  a node
 5869:  *
 5870:  * Converts a node to its number value
 5871:  *
 5872:  * Returns the number value
 5873:  */
 5874: double
 5875: xmlXPathCastNodeToNumber (xmlNodePtr node) {
 5876:     xmlChar *strval;
 5877:     double ret;
 5878: 
 5879:     if (node == NULL)
 5880: 	return(xmlXPathNAN);
 5881:     strval = xmlXPathCastNodeToString(node);
 5882:     if (strval == NULL)
 5883: 	return(xmlXPathNAN);
 5884:     ret = xmlXPathCastStringToNumber(strval);
 5885:     xmlFree(strval);
 5886: 
 5887:     return(ret);
 5888: }
 5889: 
 5890: /**
 5891:  * xmlXPathCastNodeSetToNumber:
 5892:  * @ns:  a node-set
 5893:  *
 5894:  * Converts a node-set to its number value
 5895:  *
 5896:  * Returns the number value
 5897:  */
 5898: double
 5899: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
 5900:     xmlChar *str;
 5901:     double ret;
 5902: 
 5903:     if (ns == NULL)
 5904: 	return(xmlXPathNAN);
 5905:     str = xmlXPathCastNodeSetToString(ns);
 5906:     ret = xmlXPathCastStringToNumber(str);
 5907:     xmlFree(str);
 5908:     return(ret);
 5909: }
 5910: 
 5911: /**
 5912:  * xmlXPathCastToNumber:
 5913:  * @val:  an XPath object
 5914:  *
 5915:  * Converts an XPath object to its number value
 5916:  *
 5917:  * Returns the number value
 5918:  */
 5919: double
 5920: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
 5921:     double ret = 0.0;
 5922: 
 5923:     if (val == NULL)
 5924: 	return(xmlXPathNAN);
 5925:     switch (val->type) {
 5926:     case XPATH_UNDEFINED:
 5927: #ifdef DEGUB_EXPR
 5928: 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
 5929: #endif
 5930: 	ret = xmlXPathNAN;
 5931: 	break;
 5932:     case XPATH_NODESET:
 5933:     case XPATH_XSLT_TREE:
 5934: 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
 5935: 	break;
 5936:     case XPATH_STRING:
 5937: 	ret = xmlXPathCastStringToNumber(val->stringval);
 5938: 	break;
 5939:     case XPATH_NUMBER:
 5940: 	ret = val->floatval;
 5941: 	break;
 5942:     case XPATH_BOOLEAN:
 5943: 	ret = xmlXPathCastBooleanToNumber(val->boolval);
 5944: 	break;
 5945:     case XPATH_USERS:
 5946:     case XPATH_POINT:
 5947:     case XPATH_RANGE:
 5948:     case XPATH_LOCATIONSET:
 5949: 	TODO;
 5950: 	ret = xmlXPathNAN;
 5951: 	break;
 5952:     }
 5953:     return(ret);
 5954: }
 5955: 
 5956: /**
 5957:  * xmlXPathConvertNumber:
 5958:  * @val:  an XPath object
 5959:  *
 5960:  * Converts an existing object to its number() equivalent
 5961:  *
 5962:  * Returns the new object, the old one is freed (or the operation
 5963:  *         is done directly on @val)
 5964:  */
 5965: xmlXPathObjectPtr
 5966: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
 5967:     xmlXPathObjectPtr ret;
 5968: 
 5969:     if (val == NULL)
 5970: 	return(xmlXPathNewFloat(0.0));
 5971:     if (val->type == XPATH_NUMBER)
 5972: 	return(val);
 5973:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
 5974:     xmlXPathFreeObject(val);
 5975:     return(ret);
 5976: }
 5977: 
 5978: /**
 5979:  * xmlXPathCastNumberToBoolean:
 5980:  * @val:  a number
 5981:  *
 5982:  * Converts a number to its boolean value
 5983:  *
 5984:  * Returns the boolean value
 5985:  */
 5986: int
 5987: xmlXPathCastNumberToBoolean (double val) {
 5988:      if (xmlXPathIsNaN(val) || (val == 0.0))
 5989: 	 return(0);
 5990:      return(1);
 5991: }
 5992: 
 5993: /**
 5994:  * xmlXPathCastStringToBoolean:
 5995:  * @val:  a string
 5996:  *
 5997:  * Converts a string to its boolean value
 5998:  *
 5999:  * Returns the boolean value
 6000:  */
 6001: int
 6002: xmlXPathCastStringToBoolean (const xmlChar *val) {
 6003:     if ((val == NULL) || (xmlStrlen(val) == 0))
 6004: 	return(0);
 6005:     return(1);
 6006: }
 6007: 
 6008: /**
 6009:  * xmlXPathCastNodeSetToBoolean:
 6010:  * @ns:  a node-set
 6011:  *
 6012:  * Converts a node-set to its boolean value
 6013:  *
 6014:  * Returns the boolean value
 6015:  */
 6016: int
 6017: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
 6018:     if ((ns == NULL) || (ns->nodeNr == 0))
 6019: 	return(0);
 6020:     return(1);
 6021: }
 6022: 
 6023: /**
 6024:  * xmlXPathCastToBoolean:
 6025:  * @val:  an XPath object
 6026:  *
 6027:  * Converts an XPath object to its boolean value
 6028:  *
 6029:  * Returns the boolean value
 6030:  */
 6031: int
 6032: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
 6033:     int ret = 0;
 6034: 
 6035:     if (val == NULL)
 6036: 	return(0);
 6037:     switch (val->type) {
 6038:     case XPATH_UNDEFINED:
 6039: #ifdef DEBUG_EXPR
 6040: 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
 6041: #endif
 6042: 	ret = 0;
 6043: 	break;
 6044:     case XPATH_NODESET:
 6045:     case XPATH_XSLT_TREE:
 6046: 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
 6047: 	break;
 6048:     case XPATH_STRING:
 6049: 	ret = xmlXPathCastStringToBoolean(val->stringval);
 6050: 	break;
 6051:     case XPATH_NUMBER:
 6052: 	ret = xmlXPathCastNumberToBoolean(val->floatval);
 6053: 	break;
 6054:     case XPATH_BOOLEAN:
 6055: 	ret = val->boolval;
 6056: 	break;
 6057:     case XPATH_USERS:
 6058:     case XPATH_POINT:
 6059:     case XPATH_RANGE:
 6060:     case XPATH_LOCATIONSET:
 6061: 	TODO;
 6062: 	ret = 0;
 6063: 	break;
 6064:     }
 6065:     return(ret);
 6066: }
 6067: 
 6068: 
 6069: /**
 6070:  * xmlXPathConvertBoolean:
 6071:  * @val:  an XPath object
 6072:  *
 6073:  * Converts an existing object to its boolean() equivalent
 6074:  *
 6075:  * Returns the new object, the old one is freed (or the operation
 6076:  *         is done directly on @val)
 6077:  */
 6078: xmlXPathObjectPtr
 6079: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
 6080:     xmlXPathObjectPtr ret;
 6081: 
 6082:     if (val == NULL)
 6083: 	return(xmlXPathNewBoolean(0));
 6084:     if (val->type == XPATH_BOOLEAN)
 6085: 	return(val);
 6086:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
 6087:     xmlXPathFreeObject(val);
 6088:     return(ret);
 6089: }
 6090: 
 6091: /************************************************************************
 6092:  *									*
 6093:  *		Routines to handle XPath contexts			*
 6094:  *									*
 6095:  ************************************************************************/
 6096: 
 6097: /**
 6098:  * xmlXPathNewContext:
 6099:  * @doc:  the XML document
 6100:  *
 6101:  * Create a new xmlXPathContext
 6102:  *
 6103:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
 6104:  */
 6105: xmlXPathContextPtr
 6106: xmlXPathNewContext(xmlDocPtr doc) {
 6107:     xmlXPathContextPtr ret;
 6108: 
 6109:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
 6110:     if (ret == NULL) {
 6111:         xmlXPathErrMemory(NULL, "creating context\n");
 6112: 	return(NULL);
 6113:     }
 6114:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
 6115:     ret->doc = doc;
 6116:     ret->node = NULL;
 6117: 
 6118:     ret->varHash = NULL;
 6119: 
 6120:     ret->nb_types = 0;
 6121:     ret->max_types = 0;
 6122:     ret->types = NULL;
 6123: 
 6124:     ret->funcHash = xmlHashCreate(0);
 6125: 
 6126:     ret->nb_axis = 0;
 6127:     ret->max_axis = 0;
 6128:     ret->axis = NULL;
 6129: 
 6130:     ret->nsHash = NULL;
 6131:     ret->user = NULL;
 6132: 
 6133:     ret->contextSize = -1;
 6134:     ret->proximityPosition = -1;
 6135: 
 6136: #ifdef XP_DEFAULT_CACHE_ON
 6137:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
 6138: 	xmlXPathFreeContext(ret);
 6139: 	return(NULL);
 6140:     }
 6141: #endif
 6142: 
 6143:     xmlXPathRegisterAllFunctions(ret);
 6144: 
 6145:     return(ret);
 6146: }
 6147: 
 6148: /**
 6149:  * xmlXPathFreeContext:
 6150:  * @ctxt:  the context to free
 6151:  *
 6152:  * Free up an xmlXPathContext
 6153:  */
 6154: void
 6155: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
 6156:     if (ctxt == NULL) return;
 6157: 
 6158:     if (ctxt->cache != NULL)
 6159: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 6160:     xmlXPathRegisteredNsCleanup(ctxt);
 6161:     xmlXPathRegisteredFuncsCleanup(ctxt);
 6162:     xmlXPathRegisteredVariablesCleanup(ctxt);
 6163:     xmlResetError(&ctxt->lastError);
 6164:     xmlFree(ctxt);
 6165: }
 6166: 
 6167: /************************************************************************
 6168:  *									*
 6169:  *		Routines to handle XPath parser contexts		*
 6170:  *									*
 6171:  ************************************************************************/
 6172: 
 6173: #define CHECK_CTXT(ctxt)						\
 6174:     if (ctxt == NULL) {						\
 6175: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6176: 		NULL, NULL, XML_FROM_XPATH,				\
 6177: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6178: 		__FILE__, __LINE__,					\
 6179: 		NULL, NULL, NULL, 0, 0,					\
 6180: 		"NULL context pointer\n");				\
 6181: 	return(NULL);							\
 6182:     }									\
 6183: 
 6184: #define CHECK_CTXT_NEG(ctxt)						\
 6185:     if (ctxt == NULL) {						\
 6186: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6187: 		NULL, NULL, XML_FROM_XPATH,				\
 6188: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6189: 		__FILE__, __LINE__,					\
 6190: 		NULL, NULL, NULL, 0, 0,					\
 6191: 		"NULL context pointer\n");				\
 6192: 	return(-1);							\
 6193:     }									\
 6194: 
 6195: 
 6196: #define CHECK_CONTEXT(ctxt)						\
 6197:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
 6198:         (ctxt->doc->children == NULL)) {				\
 6199: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
 6200: 	return(NULL);							\
 6201:     }
 6202: 
 6203: 
 6204: /**
 6205:  * xmlXPathNewParserContext:
 6206:  * @str:  the XPath expression
 6207:  * @ctxt:  the XPath context
 6208:  *
 6209:  * Create a new xmlXPathParserContext
 6210:  *
 6211:  * Returns the xmlXPathParserContext just allocated.
 6212:  */
 6213: xmlXPathParserContextPtr
 6214: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
 6215:     xmlXPathParserContextPtr ret;
 6216: 
 6217:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6218:     if (ret == NULL) {
 6219:         xmlXPathErrMemory(ctxt, "creating parser context\n");
 6220: 	return(NULL);
 6221:     }
 6222:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6223:     ret->cur = ret->base = str;
 6224:     ret->context = ctxt;
 6225: 
 6226:     ret->comp = xmlXPathNewCompExpr();
 6227:     if (ret->comp == NULL) {
 6228: 	xmlFree(ret->valueTab);
 6229: 	xmlFree(ret);
 6230: 	return(NULL);
 6231:     }
 6232:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
 6233:         ret->comp->dict = ctxt->dict;
 6234: 	xmlDictReference(ret->comp->dict);
 6235:     }
 6236: 
 6237:     return(ret);
 6238: }
 6239: 
 6240: /**
 6241:  * xmlXPathCompParserContext:
 6242:  * @comp:  the XPath compiled expression
 6243:  * @ctxt:  the XPath context
 6244:  *
 6245:  * Create a new xmlXPathParserContext when processing a compiled expression
 6246:  *
 6247:  * Returns the xmlXPathParserContext just allocated.
 6248:  */
 6249: static xmlXPathParserContextPtr
 6250: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
 6251:     xmlXPathParserContextPtr ret;
 6252: 
 6253:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6254:     if (ret == NULL) {
 6255:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6256: 	return(NULL);
 6257:     }
 6258:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6259: 
 6260:     /* Allocate the value stack */
 6261:     ret->valueTab = (xmlXPathObjectPtr *)
 6262:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
 6263:     if (ret->valueTab == NULL) {
 6264: 	xmlFree(ret);
 6265: 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6266: 	return(NULL);
 6267:     }
 6268:     ret->valueNr = 0;
 6269:     ret->valueMax = 10;
 6270:     ret->value = NULL;
 6271:     ret->valueFrame = 0;
 6272: 
 6273:     ret->context = ctxt;
 6274:     ret->comp = comp;
 6275: 
 6276:     return(ret);
 6277: }
 6278: 
 6279: /**
 6280:  * xmlXPathFreeParserContext:
 6281:  * @ctxt:  the context to free
 6282:  *
 6283:  * Free up an xmlXPathParserContext
 6284:  */
 6285: void
 6286: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
 6287:     if (ctxt->valueTab != NULL) {
 6288:         xmlFree(ctxt->valueTab);
 6289:     }
 6290:     if (ctxt->comp != NULL) {
 6291: #ifdef XPATH_STREAMING
 6292: 	if (ctxt->comp->stream != NULL) {
 6293: 	    xmlFreePatternList(ctxt->comp->stream);
 6294: 	    ctxt->comp->stream = NULL;
 6295: 	}
 6296: #endif
 6297: 	xmlXPathFreeCompExpr(ctxt->comp);
 6298:     }
 6299:     xmlFree(ctxt);
 6300: }
 6301: 
 6302: /************************************************************************
 6303:  *									*
 6304:  *		The implicit core function library			*
 6305:  *									*
 6306:  ************************************************************************/
 6307: 
 6308: /**
 6309:  * xmlXPathNodeValHash:
 6310:  * @node:  a node pointer
 6311:  *
 6312:  * Function computing the beginning of the string value of the node,
 6313:  * used to speed up comparisons
 6314:  *
 6315:  * Returns an int usable as a hash
 6316:  */
 6317: static unsigned int
 6318: xmlXPathNodeValHash(xmlNodePtr node) {
 6319:     int len = 2;
 6320:     const xmlChar * string = NULL;
 6321:     xmlNodePtr tmp = NULL;
 6322:     unsigned int ret = 0;
 6323: 
 6324:     if (node == NULL)
 6325: 	return(0);
 6326: 
 6327:     if (node->type == XML_DOCUMENT_NODE) {
 6328: 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
 6329: 	if (tmp == NULL)
 6330: 	    node = node->children;
 6331: 	else
 6332: 	    node = tmp;
 6333: 
 6334: 	if (node == NULL)
 6335: 	    return(0);
 6336:     }
 6337: 
 6338:     switch (node->type) {
 6339: 	case XML_COMMENT_NODE:
 6340: 	case XML_PI_NODE:
 6341: 	case XML_CDATA_SECTION_NODE:
 6342: 	case XML_TEXT_NODE:
 6343: 	    string = node->content;
 6344: 	    if (string == NULL)
 6345: 		return(0);
 6346: 	    if (string[0] == 0)
 6347: 		return(0);
 6348: 	    return(((unsigned int) string[0]) +
 6349: 		   (((unsigned int) string[1]) << 8));
 6350: 	case XML_NAMESPACE_DECL:
 6351: 	    string = ((xmlNsPtr)node)->href;
 6352: 	    if (string == NULL)
 6353: 		return(0);
 6354: 	    if (string[0] == 0)
 6355: 		return(0);
 6356: 	    return(((unsigned int) string[0]) +
 6357: 		   (((unsigned int) string[1]) << 8));
 6358: 	case XML_ATTRIBUTE_NODE:
 6359: 	    tmp = ((xmlAttrPtr) node)->children;
 6360: 	    break;
 6361: 	case XML_ELEMENT_NODE:
 6362: 	    tmp = node->children;
 6363: 	    break;
 6364: 	default:
 6365: 	    return(0);
 6366:     }
 6367:     while (tmp != NULL) {
 6368: 	switch (tmp->type) {
 6369: 	    case XML_COMMENT_NODE:
 6370: 	    case XML_PI_NODE:
 6371: 	    case XML_CDATA_SECTION_NODE:
 6372: 	    case XML_TEXT_NODE:
 6373: 		string = tmp->content;
 6374: 		break;
 6375: 	    case XML_NAMESPACE_DECL:
 6376: 		string = ((xmlNsPtr)tmp)->href;
 6377: 		break;
 6378: 	    default:
 6379: 		break;
 6380: 	}
 6381: 	if ((string != NULL) && (string[0] != 0)) {
 6382: 	    if (len == 1) {
 6383: 		return(ret + (((unsigned int) string[0]) << 8));
 6384: 	    }
 6385: 	    if (string[1] == 0) {
 6386: 		len = 1;
 6387: 		ret = (unsigned int) string[0];
 6388: 	    } else {
 6389: 		return(((unsigned int) string[0]) +
 6390: 		       (((unsigned int) string[1]) << 8));
 6391: 	    }
 6392: 	}
 6393: 	/*
 6394: 	 * Skip to next node
 6395: 	 */
 6396: 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
 6397: 	    if (tmp->children->type != XML_ENTITY_DECL) {
 6398: 		tmp = tmp->children;
 6399: 		continue;
 6400: 	    }
 6401: 	}
 6402: 	if (tmp == node)
 6403: 	    break;
 6404: 
 6405: 	if (tmp->next != NULL) {
 6406: 	    tmp = tmp->next;
 6407: 	    continue;
 6408: 	}
 6409: 
 6410: 	do {
 6411: 	    tmp = tmp->parent;
 6412: 	    if (tmp == NULL)
 6413: 		break;
 6414: 	    if (tmp == node) {
 6415: 		tmp = NULL;
 6416: 		break;
 6417: 	    }
 6418: 	    if (tmp->next != NULL) {
 6419: 		tmp = tmp->next;
 6420: 		break;
 6421: 	    }
 6422: 	} while (tmp != NULL);
 6423:     }
 6424:     return(ret);
 6425: }
 6426: 
 6427: /**
 6428:  * xmlXPathStringHash:
 6429:  * @string:  a string
 6430:  *
 6431:  * Function computing the beginning of the string value of the node,
 6432:  * used to speed up comparisons
 6433:  *
 6434:  * Returns an int usable as a hash
 6435:  */
 6436: static unsigned int
 6437: xmlXPathStringHash(const xmlChar * string) {
 6438:     if (string == NULL)
 6439: 	return((unsigned int) 0);
 6440:     if (string[0] == 0)
 6441: 	return(0);
 6442:     return(((unsigned int) string[0]) +
 6443: 	   (((unsigned int) string[1]) << 8));
 6444: }
 6445: 
 6446: /**
 6447:  * xmlXPathCompareNodeSetFloat:
 6448:  * @ctxt:  the XPath Parser context
 6449:  * @inf:  less than (1) or greater than (0)
 6450:  * @strict:  is the comparison strict
 6451:  * @arg:  the node set
 6452:  * @f:  the value
 6453:  *
 6454:  * Implement the compare operation between a nodeset and a number
 6455:  *     @ns < @val    (1, 1, ...
 6456:  *     @ns <= @val   (1, 0, ...
 6457:  *     @ns > @val    (0, 1, ...
 6458:  *     @ns >= @val   (0, 0, ...
 6459:  *
 6460:  * If one object to be compared is a node-set and the other is a number,
 6461:  * then the comparison will be true if and only if there is a node in the
 6462:  * node-set such that the result of performing the comparison on the number
 6463:  * to be compared and on the result of converting the string-value of that
 6464:  * node to a number using the number function is true.
 6465:  *
 6466:  * Returns 0 or 1 depending on the results of the test.
 6467:  */
 6468: static int
 6469: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6470: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
 6471:     int i, ret = 0;
 6472:     xmlNodeSetPtr ns;
 6473:     xmlChar *str2;
 6474: 
 6475:     if ((f == NULL) || (arg == NULL) ||
 6476: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6477: 	xmlXPathReleaseObject(ctxt->context, arg);
 6478: 	xmlXPathReleaseObject(ctxt->context, f);
 6479:         return(0);
 6480:     }
 6481:     ns = arg->nodesetval;
 6482:     if (ns != NULL) {
 6483: 	for (i = 0;i < ns->nodeNr;i++) {
 6484: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6485: 	     if (str2 != NULL) {
 6486: 		 valuePush(ctxt,
 6487: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6488: 		 xmlFree(str2);
 6489: 		 xmlXPathNumberFunction(ctxt, 1);
 6490: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
 6491: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6492: 		 if (ret)
 6493: 		     break;
 6494: 	     }
 6495: 	}
 6496:     }
 6497:     xmlXPathReleaseObject(ctxt->context, arg);
 6498:     xmlXPathReleaseObject(ctxt->context, f);
 6499:     return(ret);
 6500: }
 6501: 
 6502: /**
 6503:  * xmlXPathCompareNodeSetString:
 6504:  * @ctxt:  the XPath Parser context
 6505:  * @inf:  less than (1) or greater than (0)
 6506:  * @strict:  is the comparison strict
 6507:  * @arg:  the node set
 6508:  * @s:  the value
 6509:  *
 6510:  * Implement the compare operation between a nodeset and a string
 6511:  *     @ns < @val    (1, 1, ...
 6512:  *     @ns <= @val   (1, 0, ...
 6513:  *     @ns > @val    (0, 1, ...
 6514:  *     @ns >= @val   (0, 0, ...
 6515:  *
 6516:  * If one object to be compared is a node-set and the other is a string,
 6517:  * then the comparison will be true if and only if there is a node in
 6518:  * the node-set such that the result of performing the comparison on the
 6519:  * string-value of the node and the other string is true.
 6520:  *
 6521:  * Returns 0 or 1 depending on the results of the test.
 6522:  */
 6523: static int
 6524: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6525: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
 6526:     int i, ret = 0;
 6527:     xmlNodeSetPtr ns;
 6528:     xmlChar *str2;
 6529: 
 6530:     if ((s == NULL) || (arg == NULL) ||
 6531: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6532: 	xmlXPathReleaseObject(ctxt->context, arg);
 6533: 	xmlXPathReleaseObject(ctxt->context, s);
 6534:         return(0);
 6535:     }
 6536:     ns = arg->nodesetval;
 6537:     if (ns != NULL) {
 6538: 	for (i = 0;i < ns->nodeNr;i++) {
 6539: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6540: 	     if (str2 != NULL) {
 6541: 		 valuePush(ctxt,
 6542: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6543: 		 xmlFree(str2);
 6544: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
 6545: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6546: 		 if (ret)
 6547: 		     break;
 6548: 	     }
 6549: 	}
 6550:     }
 6551:     xmlXPathReleaseObject(ctxt->context, arg);
 6552:     xmlXPathReleaseObject(ctxt->context, s);
 6553:     return(ret);
 6554: }
 6555: 
 6556: /**
 6557:  * xmlXPathCompareNodeSets:
 6558:  * @inf:  less than (1) or greater than (0)
 6559:  * @strict:  is the comparison strict
 6560:  * @arg1:  the first node set object
 6561:  * @arg2:  the second node set object
 6562:  *
 6563:  * Implement the compare operation on nodesets:
 6564:  *
 6565:  * If both objects to be compared are node-sets, then the comparison
 6566:  * will be true if and only if there is a node in the first node-set
 6567:  * and a node in the second node-set such that the result of performing
 6568:  * the comparison on the string-values of the two nodes is true.
 6569:  * ....
 6570:  * When neither object to be compared is a node-set and the operator
 6571:  * is <=, <, >= or >, then the objects are compared by converting both
 6572:  * objects to numbers and comparing the numbers according to IEEE 754.
 6573:  * ....
 6574:  * The number function converts its argument to a number as follows:
 6575:  *  - a string that consists of optional whitespace followed by an
 6576:  *    optional minus sign followed by a Number followed by whitespace
 6577:  *    is converted to the IEEE 754 number that is nearest (according
 6578:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
 6579:  *    represented by the string; any other string is converted to NaN
 6580:  *
 6581:  * Conclusion all nodes need to be converted first to their string value
 6582:  * and then the comparison must be done when possible
 6583:  */
 6584: static int
 6585: xmlXPathCompareNodeSets(int inf, int strict,
 6586: 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6587:     int i, j, init = 0;
 6588:     double val1;
 6589:     double *values2;
 6590:     int ret = 0;
 6591:     xmlNodeSetPtr ns1;
 6592:     xmlNodeSetPtr ns2;
 6593: 
 6594:     if ((arg1 == NULL) ||
 6595: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
 6596: 	xmlXPathFreeObject(arg2);
 6597:         return(0);
 6598:     }
 6599:     if ((arg2 == NULL) ||
 6600: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
 6601: 	xmlXPathFreeObject(arg1);
 6602: 	xmlXPathFreeObject(arg2);
 6603:         return(0);
 6604:     }
 6605: 
 6606:     ns1 = arg1->nodesetval;
 6607:     ns2 = arg2->nodesetval;
 6608: 
 6609:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
 6610: 	xmlXPathFreeObject(arg1);
 6611: 	xmlXPathFreeObject(arg2);
 6612: 	return(0);
 6613:     }
 6614:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
 6615: 	xmlXPathFreeObject(arg1);
 6616: 	xmlXPathFreeObject(arg2);
 6617: 	return(0);
 6618:     }
 6619: 
 6620:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
 6621:     if (values2 == NULL) {
 6622:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6623: 	xmlXPathFreeObject(arg1);
 6624: 	xmlXPathFreeObject(arg2);
 6625: 	return(0);
 6626:     }
 6627:     for (i = 0;i < ns1->nodeNr;i++) {
 6628: 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
 6629: 	if (xmlXPathIsNaN(val1))
 6630: 	    continue;
 6631: 	for (j = 0;j < ns2->nodeNr;j++) {
 6632: 	    if (init == 0) {
 6633: 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
 6634: 	    }
 6635: 	    if (xmlXPathIsNaN(values2[j]))
 6636: 		continue;
 6637: 	    if (inf && strict)
 6638: 		ret = (val1 < values2[j]);
 6639: 	    else if (inf && !strict)
 6640: 		ret = (val1 <= values2[j]);
 6641: 	    else if (!inf && strict)
 6642: 		ret = (val1 > values2[j]);
 6643: 	    else if (!inf && !strict)
 6644: 		ret = (val1 >= values2[j]);
 6645: 	    if (ret)
 6646: 		break;
 6647: 	}
 6648: 	if (ret)
 6649: 	    break;
 6650: 	init = 1;
 6651:     }
 6652:     xmlFree(values2);
 6653:     xmlXPathFreeObject(arg1);
 6654:     xmlXPathFreeObject(arg2);
 6655:     return(ret);
 6656: }
 6657: 
 6658: /**
 6659:  * xmlXPathCompareNodeSetValue:
 6660:  * @ctxt:  the XPath Parser context
 6661:  * @inf:  less than (1) or greater than (0)
 6662:  * @strict:  is the comparison strict
 6663:  * @arg:  the node set
 6664:  * @val:  the value
 6665:  *
 6666:  * Implement the compare operation between a nodeset and a value
 6667:  *     @ns < @val    (1, 1, ...
 6668:  *     @ns <= @val   (1, 0, ...
 6669:  *     @ns > @val    (0, 1, ...
 6670:  *     @ns >= @val   (0, 0, ...
 6671:  *
 6672:  * If one object to be compared is a node-set and the other is a boolean,
 6673:  * then the comparison will be true if and only if the result of performing
 6674:  * the comparison on the boolean and on the result of converting
 6675:  * the node-set to a boolean using the boolean function is true.
 6676:  *
 6677:  * Returns 0 or 1 depending on the results of the test.
 6678:  */
 6679: static int
 6680: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6681: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
 6682:     if ((val == NULL) || (arg == NULL) ||
 6683: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6684:         return(0);
 6685: 
 6686:     switch(val->type) {
 6687:         case XPATH_NUMBER:
 6688: 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
 6689:         case XPATH_NODESET:
 6690:         case XPATH_XSLT_TREE:
 6691: 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
 6692:         case XPATH_STRING:
 6693: 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
 6694:         case XPATH_BOOLEAN:
 6695: 	    valuePush(ctxt, arg);
 6696: 	    xmlXPathBooleanFunction(ctxt, 1);
 6697: 	    valuePush(ctxt, val);
 6698: 	    return(xmlXPathCompareValues(ctxt, inf, strict));
 6699: 	default:
 6700: 	    TODO
 6701:     }
 6702:     return(0);
 6703: }
 6704: 
 6705: /**
 6706:  * xmlXPathEqualNodeSetString:
 6707:  * @arg:  the nodeset object argument
 6708:  * @str:  the string to compare to.
 6709:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
 6710:  *
 6711:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6712:  * If one object to be compared is a node-set and the other is a string,
 6713:  * then the comparison will be true if and only if there is a node in
 6714:  * the node-set such that the result of performing the comparison on the
 6715:  * string-value of the node and the other string is true.
 6716:  *
 6717:  * Returns 0 or 1 depending on the results of the test.
 6718:  */
 6719: static int
 6720: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
 6721: {
 6722:     int i;
 6723:     xmlNodeSetPtr ns;
 6724:     xmlChar *str2;
 6725:     unsigned int hash;
 6726: 
 6727:     if ((str == NULL) || (arg == NULL) ||
 6728:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6729:         return (0);
 6730:     ns = arg->nodesetval;
 6731:     /*
 6732:      * A NULL nodeset compared with a string is always false
 6733:      * (since there is no node equal, and no node not equal)
 6734:      */
 6735:     if ((ns == NULL) || (ns->nodeNr <= 0) )
 6736:         return (0);
 6737:     hash = xmlXPathStringHash(str);
 6738:     for (i = 0; i < ns->nodeNr; i++) {
 6739:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
 6740:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
 6741:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
 6742:                 xmlFree(str2);
 6743: 		if (neq)
 6744: 		    continue;
 6745:                 return (1);
 6746: 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
 6747: 		if (neq)
 6748: 		    continue;
 6749:                 return (1);
 6750:             } else if (neq) {
 6751: 		if (str2 != NULL)
 6752: 		    xmlFree(str2);
 6753: 		return (1);
 6754: 	    }
 6755:             if (str2 != NULL)
 6756:                 xmlFree(str2);
 6757:         } else if (neq)
 6758: 	    return (1);
 6759:     }
 6760:     return (0);
 6761: }
 6762: 
 6763: /**
 6764:  * xmlXPathEqualNodeSetFloat:
 6765:  * @arg:  the nodeset object argument
 6766:  * @f:  the float to compare to
 6767:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
 6768:  *
 6769:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6770:  * If one object to be compared is a node-set and the other is a number,
 6771:  * then the comparison will be true if and only if there is a node in
 6772:  * the node-set such that the result of performing the comparison on the
 6773:  * number to be compared and on the result of converting the string-value
 6774:  * of that node to a number using the number function is true.
 6775:  *
 6776:  * Returns 0 or 1 depending on the results of the test.
 6777:  */
 6778: static int
 6779: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
 6780:     xmlXPathObjectPtr arg, double f, int neq) {
 6781:   int i, ret=0;
 6782:   xmlNodeSetPtr ns;
 6783:   xmlChar *str2;
 6784:   xmlXPathObjectPtr val;
 6785:   double v;
 6786: 
 6787:     if ((arg == NULL) ||
 6788: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6789:         return(0);
 6790: 
 6791:     ns = arg->nodesetval;
 6792:     if (ns != NULL) {
 6793: 	for (i=0;i<ns->nodeNr;i++) {
 6794: 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6795: 	    if (str2 != NULL) {
 6796: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
 6797: 		xmlFree(str2);
 6798: 		xmlXPathNumberFunction(ctxt, 1);
 6799: 		val = valuePop(ctxt);
 6800: 		v = val->floatval;
 6801: 		xmlXPathReleaseObject(ctxt->context, val);
 6802: 		if (!xmlXPathIsNaN(v)) {
 6803: 		    if ((!neq) && (v==f)) {
 6804: 			ret = 1;
 6805: 			break;
 6806: 		    } else if ((neq) && (v!=f)) {
 6807: 			ret = 1;
 6808: 			break;
 6809: 		    }
 6810: 		} else {	/* NaN is unequal to any value */
 6811: 		    if (neq)
 6812: 			ret = 1;
 6813: 		}
 6814: 	    }
 6815: 	}
 6816:     }
 6817: 
 6818:     return(ret);
 6819: }
 6820: 
 6821: 
 6822: /**
 6823:  * xmlXPathEqualNodeSets:
 6824:  * @arg1:  first nodeset object argument
 6825:  * @arg2:  second nodeset object argument
 6826:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
 6827:  *
 6828:  * Implement the equal / not equal operation on XPath nodesets:
 6829:  * @arg1 == @arg2  or  @arg1 != @arg2
 6830:  * If both objects to be compared are node-sets, then the comparison
 6831:  * will be true if and only if there is a node in the first node-set and
 6832:  * a node in the second node-set such that the result of performing the
 6833:  * comparison on the string-values of the two nodes is true.
 6834:  *
 6835:  * (needless to say, this is a costly operation)
 6836:  *
 6837:  * Returns 0 or 1 depending on the results of the test.
 6838:  */
 6839: static int
 6840: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
 6841:     int i, j;
 6842:     unsigned int *hashs1;
 6843:     unsigned int *hashs2;
 6844:     xmlChar **values1;
 6845:     xmlChar **values2;
 6846:     int ret = 0;
 6847:     xmlNodeSetPtr ns1;
 6848:     xmlNodeSetPtr ns2;
 6849: 
 6850:     if ((arg1 == NULL) ||
 6851: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
 6852:         return(0);
 6853:     if ((arg2 == NULL) ||
 6854: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
 6855:         return(0);
 6856: 
 6857:     ns1 = arg1->nodesetval;
 6858:     ns2 = arg2->nodesetval;
 6859: 
 6860:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
 6861: 	return(0);
 6862:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
 6863: 	return(0);
 6864: 
 6865:     /*
 6866:      * for equal, check if there is a node pertaining to both sets
 6867:      */
 6868:     if (neq == 0)
 6869: 	for (i = 0;i < ns1->nodeNr;i++)
 6870: 	    for (j = 0;j < ns2->nodeNr;j++)
 6871: 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
 6872: 		    return(1);
 6873: 
 6874:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
 6875:     if (values1 == NULL) {
 6876:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6877: 	return(0);
 6878:     }
 6879:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
 6880:     if (hashs1 == NULL) {
 6881:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6882: 	xmlFree(values1);
 6883: 	return(0);
 6884:     }
 6885:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
 6886:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
 6887:     if (values2 == NULL) {
 6888:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6889: 	xmlFree(hashs1);
 6890: 	xmlFree(values1);
 6891: 	return(0);
 6892:     }
 6893:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
 6894:     if (hashs2 == NULL) {
 6895:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6896: 	xmlFree(hashs1);
 6897: 	xmlFree(values1);
 6898: 	xmlFree(values2);
 6899: 	return(0);
 6900:     }
 6901:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
 6902:     for (i = 0;i < ns1->nodeNr;i++) {
 6903: 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
 6904: 	for (j = 0;j < ns2->nodeNr;j++) {
 6905: 	    if (i == 0)
 6906: 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
 6907: 	    if (hashs1[i] != hashs2[j]) {
 6908: 		if (neq) {
 6909: 		    ret = 1;
 6910: 		    break;
 6911: 		}
 6912: 	    }
 6913: 	    else {
 6914: 		if (values1[i] == NULL)
 6915: 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
 6916: 		if (values2[j] == NULL)
 6917: 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
 6918: 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
 6919: 		if (ret)
 6920: 		    break;
 6921: 	    }
 6922: 	}
 6923: 	if (ret)
 6924: 	    break;
 6925:     }
 6926:     for (i = 0;i < ns1->nodeNr;i++)
 6927: 	if (values1[i] != NULL)
 6928: 	    xmlFree(values1[i]);
 6929:     for (j = 0;j < ns2->nodeNr;j++)
 6930: 	if (values2[j] != NULL)
 6931: 	    xmlFree(values2[j]);
 6932:     xmlFree(values1);
 6933:     xmlFree(values2);
 6934:     xmlFree(hashs1);
 6935:     xmlFree(hashs2);
 6936:     return(ret);
 6937: }
 6938: 
 6939: static int
 6940: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
 6941:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6942:     int ret = 0;
 6943:     /*
 6944:      *At this point we are assured neither arg1 nor arg2
 6945:      *is a nodeset, so we can just pick the appropriate routine.
 6946:      */
 6947:     switch (arg1->type) {
 6948:         case XPATH_UNDEFINED:
 6949: #ifdef DEBUG_EXPR
 6950: 	    xmlGenericError(xmlGenericErrorContext,
 6951: 		    "Equal: undefined\n");
 6952: #endif
 6953: 	    break;
 6954:         case XPATH_BOOLEAN:
 6955: 	    switch (arg2->type) {
 6956: 	        case XPATH_UNDEFINED:
 6957: #ifdef DEBUG_EXPR
 6958: 		    xmlGenericError(xmlGenericErrorContext,
 6959: 			    "Equal: undefined\n");
 6960: #endif
 6961: 		    break;
 6962: 		case XPATH_BOOLEAN:
 6963: #ifdef DEBUG_EXPR
 6964: 		    xmlGenericError(xmlGenericErrorContext,
 6965: 			    "Equal: %d boolean %d \n",
 6966: 			    arg1->boolval, arg2->boolval);
 6967: #endif
 6968: 		    ret = (arg1->boolval == arg2->boolval);
 6969: 		    break;
 6970: 		case XPATH_NUMBER:
 6971: 		    ret = (arg1->boolval ==
 6972: 			   xmlXPathCastNumberToBoolean(arg2->floatval));
 6973: 		    break;
 6974: 		case XPATH_STRING:
 6975: 		    if ((arg2->stringval == NULL) ||
 6976: 			(arg2->stringval[0] == 0)) ret = 0;
 6977: 		    else
 6978: 			ret = 1;
 6979: 		    ret = (arg1->boolval == ret);
 6980: 		    break;
 6981: 		case XPATH_USERS:
 6982: 		case XPATH_POINT:
 6983: 		case XPATH_RANGE:
 6984: 		case XPATH_LOCATIONSET:
 6985: 		    TODO
 6986: 		    break;
 6987: 		case XPATH_NODESET:
 6988: 		case XPATH_XSLT_TREE:
 6989: 		    break;
 6990: 	    }
 6991: 	    break;
 6992:         case XPATH_NUMBER:
 6993: 	    switch (arg2->type) {
 6994: 	        case XPATH_UNDEFINED:
 6995: #ifdef DEBUG_EXPR
 6996: 		    xmlGenericError(xmlGenericErrorContext,
 6997: 			    "Equal: undefined\n");
 6998: #endif
 6999: 		    break;
 7000: 		case XPATH_BOOLEAN:
 7001: 		    ret = (arg2->boolval==
 7002: 			   xmlXPathCastNumberToBoolean(arg1->floatval));
 7003: 		    break;
 7004: 		case XPATH_STRING:
 7005: 		    valuePush(ctxt, arg2);
 7006: 		    xmlXPathNumberFunction(ctxt, 1);
 7007: 		    arg2 = valuePop(ctxt);
 7008: 		    /* no break on purpose */
 7009: 		case XPATH_NUMBER:
 7010: 		    /* Hand check NaN and Infinity equalities */
 7011: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 7012: 			    xmlXPathIsNaN(arg2->floatval)) {
 7013: 		        ret = 0;
 7014: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 7015: 		        if (xmlXPathIsInf(arg2->floatval) == 1)
 7016: 			    ret = 1;
 7017: 			else
 7018: 			    ret = 0;
 7019: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 7020: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 7021: 			    ret = 1;
 7022: 			else
 7023: 			    ret = 0;
 7024: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 7025: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 7026: 			    ret = 1;
 7027: 			else
 7028: 			    ret = 0;
 7029: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 7030: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 7031: 			    ret = 1;
 7032: 			else
 7033: 			    ret = 0;
 7034: 		    } else {
 7035: 		        ret = (arg1->floatval == arg2->floatval);
 7036: 		    }
 7037: 		    break;
 7038: 		case XPATH_USERS:
 7039: 		case XPATH_POINT:
 7040: 		case XPATH_RANGE:
 7041: 		case XPATH_LOCATIONSET:
 7042: 		    TODO
 7043: 		    break;
 7044: 		case XPATH_NODESET:
 7045: 		case XPATH_XSLT_TREE:
 7046: 		    break;
 7047: 	    }
 7048: 	    break;
 7049:         case XPATH_STRING:
 7050: 	    switch (arg2->type) {
 7051: 	        case XPATH_UNDEFINED:
 7052: #ifdef DEBUG_EXPR
 7053: 		    xmlGenericError(xmlGenericErrorContext,
 7054: 			    "Equal: undefined\n");
 7055: #endif
 7056: 		    break;
 7057: 		case XPATH_BOOLEAN:
 7058: 		    if ((arg1->stringval == NULL) ||
 7059: 			(arg1->stringval[0] == 0)) ret = 0;
 7060: 		    else
 7061: 			ret = 1;
 7062: 		    ret = (arg2->boolval == ret);
 7063: 		    break;
 7064: 		case XPATH_STRING:
 7065: 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
 7066: 		    break;
 7067: 		case XPATH_NUMBER:
 7068: 		    valuePush(ctxt, arg1);
 7069: 		    xmlXPathNumberFunction(ctxt, 1);
 7070: 		    arg1 = valuePop(ctxt);
 7071: 		    /* Hand check NaN and Infinity equalities */
 7072: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 7073: 			    xmlXPathIsNaN(arg2->floatval)) {
 7074: 		        ret = 0;
 7075: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 7076: 			if (xmlXPathIsInf(arg2->floatval) == 1)
 7077: 			    ret = 1;
 7078: 			else
 7079: 			    ret = 0;
 7080: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 7081: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 7082: 			    ret = 1;
 7083: 			else
 7084: 			    ret = 0;
 7085: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 7086: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 7087: 			    ret = 1;
 7088: 			else
 7089: 			    ret = 0;
 7090: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 7091: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 7092: 			    ret = 1;
 7093: 			else
 7094: 			    ret = 0;
 7095: 		    } else {
 7096: 		        ret = (arg1->floatval == arg2->floatval);
 7097: 		    }
 7098: 		    break;
 7099: 		case XPATH_USERS:
 7100: 		case XPATH_POINT:
 7101: 		case XPATH_RANGE:
 7102: 		case XPATH_LOCATIONSET:
 7103: 		    TODO
 7104: 		    break;
 7105: 		case XPATH_NODESET:
 7106: 		case XPATH_XSLT_TREE:
 7107: 		    break;
 7108: 	    }
 7109: 	    break;
 7110:         case XPATH_USERS:
 7111: 	case XPATH_POINT:
 7112: 	case XPATH_RANGE:
 7113: 	case XPATH_LOCATIONSET:
 7114: 	    TODO
 7115: 	    break;
 7116: 	case XPATH_NODESET:
 7117: 	case XPATH_XSLT_TREE:
 7118: 	    break;
 7119:     }
 7120:     xmlXPathReleaseObject(ctxt->context, arg1);
 7121:     xmlXPathReleaseObject(ctxt->context, arg2);
 7122:     return(ret);
 7123: }
 7124: 
 7125: /**
 7126:  * xmlXPathEqualValues:
 7127:  * @ctxt:  the XPath Parser context
 7128:  *
 7129:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7130:  *
 7131:  * Returns 0 or 1 depending on the results of the test.
 7132:  */
 7133: int
 7134: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
 7135:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7136:     int ret = 0;
 7137: 
 7138:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7139:     arg2 = valuePop(ctxt);
 7140:     arg1 = valuePop(ctxt);
 7141:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7142: 	if (arg1 != NULL)
 7143: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7144: 	else
 7145: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7146: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7147:     }
 7148: 
 7149:     if (arg1 == arg2) {
 7150: #ifdef DEBUG_EXPR
 7151:         xmlGenericError(xmlGenericErrorContext,
 7152: 		"Equal: by pointer\n");
 7153: #endif
 7154: 	xmlXPathFreeObject(arg1);
 7155:         return(1);
 7156:     }
 7157: 
 7158:     /*
 7159:      *If either argument is a nodeset, it's a 'special case'
 7160:      */
 7161:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7162:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7163: 	/*
 7164: 	 *Hack it to assure arg1 is the nodeset
 7165: 	 */
 7166: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7167: 		argtmp = arg2;
 7168: 		arg2 = arg1;
 7169: 		arg1 = argtmp;
 7170: 	}
 7171: 	switch (arg2->type) {
 7172: 	    case XPATH_UNDEFINED:
 7173: #ifdef DEBUG_EXPR
 7174: 		xmlGenericError(xmlGenericErrorContext,
 7175: 			"Equal: undefined\n");
 7176: #endif
 7177: 		break;
 7178: 	    case XPATH_NODESET:
 7179: 	    case XPATH_XSLT_TREE:
 7180: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
 7181: 		break;
 7182: 	    case XPATH_BOOLEAN:
 7183: 		if ((arg1->nodesetval == NULL) ||
 7184: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7185: 		else
 7186: 		    ret = 1;
 7187: 		ret = (ret == arg2->boolval);
 7188: 		break;
 7189: 	    case XPATH_NUMBER:
 7190: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
 7191: 		break;
 7192: 	    case XPATH_STRING:
 7193: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
 7194: 		break;
 7195: 	    case XPATH_USERS:
 7196: 	    case XPATH_POINT:
 7197: 	    case XPATH_RANGE:
 7198: 	    case XPATH_LOCATIONSET:
 7199: 		TODO
 7200: 		break;
 7201: 	}
 7202: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7203: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7204: 	return(ret);
 7205:     }
 7206: 
 7207:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7208: }
 7209: 
 7210: /**
 7211:  * xmlXPathNotEqualValues:
 7212:  * @ctxt:  the XPath Parser context
 7213:  *
 7214:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7215:  *
 7216:  * Returns 0 or 1 depending on the results of the test.
 7217:  */
 7218: int
 7219: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
 7220:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7221:     int ret = 0;
 7222: 
 7223:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7224:     arg2 = valuePop(ctxt);
 7225:     arg1 = valuePop(ctxt);
 7226:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7227: 	if (arg1 != NULL)
 7228: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7229: 	else
 7230: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7231: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7232:     }
 7233: 
 7234:     if (arg1 == arg2) {
 7235: #ifdef DEBUG_EXPR
 7236:         xmlGenericError(xmlGenericErrorContext,
 7237: 		"NotEqual: by pointer\n");
 7238: #endif
 7239: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7240:         return(0);
 7241:     }
 7242: 
 7243:     /*
 7244:      *If either argument is a nodeset, it's a 'special case'
 7245:      */
 7246:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7247:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7248: 	/*
 7249: 	 *Hack it to assure arg1 is the nodeset
 7250: 	 */
 7251: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7252: 		argtmp = arg2;
 7253: 		arg2 = arg1;
 7254: 		arg1 = argtmp;
 7255: 	}
 7256: 	switch (arg2->type) {
 7257: 	    case XPATH_UNDEFINED:
 7258: #ifdef DEBUG_EXPR
 7259: 		xmlGenericError(xmlGenericErrorContext,
 7260: 			"NotEqual: undefined\n");
 7261: #endif
 7262: 		break;
 7263: 	    case XPATH_NODESET:
 7264: 	    case XPATH_XSLT_TREE:
 7265: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
 7266: 		break;
 7267: 	    case XPATH_BOOLEAN:
 7268: 		if ((arg1->nodesetval == NULL) ||
 7269: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7270: 		else
 7271: 		    ret = 1;
 7272: 		ret = (ret != arg2->boolval);
 7273: 		break;
 7274: 	    case XPATH_NUMBER:
 7275: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
 7276: 		break;
 7277: 	    case XPATH_STRING:
 7278: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
 7279: 		break;
 7280: 	    case XPATH_USERS:
 7281: 	    case XPATH_POINT:
 7282: 	    case XPATH_RANGE:
 7283: 	    case XPATH_LOCATIONSET:
 7284: 		TODO
 7285: 		break;
 7286: 	}
 7287: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7288: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7289: 	return(ret);
 7290:     }
 7291: 
 7292:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7293: }
 7294: 
 7295: /**
 7296:  * xmlXPathCompareValues:
 7297:  * @ctxt:  the XPath Parser context
 7298:  * @inf:  less than (1) or greater than (0)
 7299:  * @strict:  is the comparison strict
 7300:  *
 7301:  * Implement the compare operation on XPath objects:
 7302:  *     @arg1 < @arg2    (1, 1, ...
 7303:  *     @arg1 <= @arg2   (1, 0, ...
 7304:  *     @arg1 > @arg2    (0, 1, ...
 7305:  *     @arg1 >= @arg2   (0, 0, ...
 7306:  *
 7307:  * When neither object to be compared is a node-set and the operator is
 7308:  * <=, <, >=, >, then the objects are compared by converted both objects
 7309:  * to numbers and comparing the numbers according to IEEE 754. The <
 7310:  * comparison will be true if and only if the first number is less than the
 7311:  * second number. The <= comparison will be true if and only if the first
 7312:  * number is less than or equal to the second number. The > comparison
 7313:  * will be true if and only if the first number is greater than the second
 7314:  * number. The >= comparison will be true if and only if the first number
 7315:  * is greater than or equal to the second number.
 7316:  *
 7317:  * Returns 1 if the comparison succeeded, 0 if it failed
 7318:  */
 7319: int
 7320: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
 7321:     int ret = 0, arg1i = 0, arg2i = 0;
 7322:     xmlXPathObjectPtr arg1, arg2;
 7323: 
 7324:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7325:     arg2 = valuePop(ctxt);
 7326:     arg1 = valuePop(ctxt);
 7327:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7328: 	if (arg1 != NULL)
 7329: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7330: 	else
 7331: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7332: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7333:     }
 7334: 
 7335:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7336:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7337: 	/*
 7338: 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
 7339: 	 * are not freed from within this routine; they will be freed from the
 7340: 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
 7341: 	 */
 7342: 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
 7343: 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
 7344: 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
 7345: 	} else {
 7346: 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7347: 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
 7348: 			                          arg1, arg2);
 7349: 	    } else {
 7350: 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
 7351: 			                          arg2, arg1);
 7352: 	    }
 7353: 	}
 7354: 	return(ret);
 7355:     }
 7356: 
 7357:     if (arg1->type != XPATH_NUMBER) {
 7358: 	valuePush(ctxt, arg1);
 7359: 	xmlXPathNumberFunction(ctxt, 1);
 7360: 	arg1 = valuePop(ctxt);
 7361:     }
 7362:     if (arg1->type != XPATH_NUMBER) {
 7363: 	xmlXPathFreeObject(arg1);
 7364: 	xmlXPathFreeObject(arg2);
 7365: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7366:     }
 7367:     if (arg2->type != XPATH_NUMBER) {
 7368: 	valuePush(ctxt, arg2);
 7369: 	xmlXPathNumberFunction(ctxt, 1);
 7370: 	arg2 = valuePop(ctxt);
 7371:     }
 7372:     if (arg2->type != XPATH_NUMBER) {
 7373: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7374: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7375: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7376:     }
 7377:     /*
 7378:      * Add tests for infinity and nan
 7379:      * => feedback on 3.4 for Inf and NaN
 7380:      */
 7381:     /* Hand check NaN and Infinity comparisons */
 7382:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
 7383: 	ret=0;
 7384:     } else {
 7385: 	arg1i=xmlXPathIsInf(arg1->floatval);
 7386: 	arg2i=xmlXPathIsInf(arg2->floatval);
 7387: 	if (inf && strict) {
 7388: 	    if ((arg1i == -1 && arg2i != -1) ||
 7389: 		(arg2i == 1 && arg1i != 1)) {
 7390: 		ret = 1;
 7391: 	    } else if (arg1i == 0 && arg2i == 0) {
 7392: 		ret = (arg1->floatval < arg2->floatval);
 7393: 	    } else {
 7394: 		ret = 0;
 7395: 	    }
 7396: 	}
 7397: 	else if (inf && !strict) {
 7398: 	    if (arg1i == -1 || arg2i == 1) {
 7399: 		ret = 1;
 7400: 	    } else if (arg1i == 0 && arg2i == 0) {
 7401: 		ret = (arg1->floatval <= arg2->floatval);
 7402: 	    } else {
 7403: 		ret = 0;
 7404: 	    }
 7405: 	}
 7406: 	else if (!inf && strict) {
 7407: 	    if ((arg1i == 1 && arg2i != 1) ||
 7408: 		(arg2i == -1 && arg1i != -1)) {
 7409: 		ret = 1;
 7410: 	    } else if (arg1i == 0 && arg2i == 0) {
 7411: 		ret = (arg1->floatval > arg2->floatval);
 7412: 	    } else {
 7413: 		ret = 0;
 7414: 	    }
 7415: 	}
 7416: 	else if (!inf && !strict) {
 7417: 	    if (arg1i == 1 || arg2i == -1) {
 7418: 		ret = 1;
 7419: 	    } else if (arg1i == 0 && arg2i == 0) {
 7420: 		ret = (arg1->floatval >= arg2->floatval);
 7421: 	    } else {
 7422: 		ret = 0;
 7423: 	    }
 7424: 	}
 7425:     }
 7426:     xmlXPathReleaseObject(ctxt->context, arg1);
 7427:     xmlXPathReleaseObject(ctxt->context, arg2);
 7428:     return(ret);
 7429: }
 7430: 
 7431: /**
 7432:  * xmlXPathValueFlipSign:
 7433:  * @ctxt:  the XPath Parser context
 7434:  *
 7435:  * Implement the unary - operation on an XPath object
 7436:  * The numeric operators convert their operands to numbers as if
 7437:  * by calling the number function.
 7438:  */
 7439: void
 7440: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
 7441:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
 7442:     CAST_TO_NUMBER;
 7443:     CHECK_TYPE(XPATH_NUMBER);
 7444:     if (xmlXPathIsNaN(ctxt->value->floatval))
 7445:         ctxt->value->floatval=xmlXPathNAN;
 7446:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
 7447:         ctxt->value->floatval=xmlXPathNINF;
 7448:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
 7449:         ctxt->value->floatval=xmlXPathPINF;
 7450:     else if (ctxt->value->floatval == 0) {
 7451:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
 7452: 	    ctxt->value->floatval = xmlXPathNZERO;
 7453: 	else
 7454: 	    ctxt->value->floatval = 0;
 7455:     }
 7456:     else
 7457:         ctxt->value->floatval = - ctxt->value->floatval;
 7458: }
 7459: 
 7460: /**
 7461:  * xmlXPathAddValues:
 7462:  * @ctxt:  the XPath Parser context
 7463:  *
 7464:  * Implement the add operation on XPath objects:
 7465:  * The numeric operators convert their operands to numbers as if
 7466:  * by calling the number function.
 7467:  */
 7468: void
 7469: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
 7470:     xmlXPathObjectPtr arg;
 7471:     double val;
 7472: 
 7473:     arg = valuePop(ctxt);
 7474:     if (arg == NULL)
 7475: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7476:     val = xmlXPathCastToNumber(arg);
 7477:     xmlXPathReleaseObject(ctxt->context, arg);
 7478:     CAST_TO_NUMBER;
 7479:     CHECK_TYPE(XPATH_NUMBER);
 7480:     ctxt->value->floatval += val;
 7481: }
 7482: 
 7483: /**
 7484:  * xmlXPathSubValues:
 7485:  * @ctxt:  the XPath Parser context
 7486:  *
 7487:  * Implement the subtraction operation on XPath objects:
 7488:  * The numeric operators convert their operands to numbers as if
 7489:  * by calling the number function.
 7490:  */
 7491: void
 7492: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
 7493:     xmlXPathObjectPtr arg;
 7494:     double val;
 7495: 
 7496:     arg = valuePop(ctxt);
 7497:     if (arg == NULL)
 7498: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7499:     val = xmlXPathCastToNumber(arg);
 7500:     xmlXPathReleaseObject(ctxt->context, arg);
 7501:     CAST_TO_NUMBER;
 7502:     CHECK_TYPE(XPATH_NUMBER);
 7503:     ctxt->value->floatval -= val;
 7504: }
 7505: 
 7506: /**
 7507:  * xmlXPathMultValues:
 7508:  * @ctxt:  the XPath Parser context
 7509:  *
 7510:  * Implement the multiply operation on XPath objects:
 7511:  * The numeric operators convert their operands to numbers as if
 7512:  * by calling the number function.
 7513:  */
 7514: void
 7515: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
 7516:     xmlXPathObjectPtr arg;
 7517:     double val;
 7518: 
 7519:     arg = valuePop(ctxt);
 7520:     if (arg == NULL)
 7521: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7522:     val = xmlXPathCastToNumber(arg);
 7523:     xmlXPathReleaseObject(ctxt->context, arg);
 7524:     CAST_TO_NUMBER;
 7525:     CHECK_TYPE(XPATH_NUMBER);
 7526:     ctxt->value->floatval *= val;
 7527: }
 7528: 
 7529: /**
 7530:  * xmlXPathDivValues:
 7531:  * @ctxt:  the XPath Parser context
 7532:  *
 7533:  * Implement the div operation on XPath objects @arg1 / @arg2:
 7534:  * The numeric operators convert their operands to numbers as if
 7535:  * by calling the number function.
 7536:  */
 7537: void
 7538: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
 7539:     xmlXPathObjectPtr arg;
 7540:     double val;
 7541: 
 7542:     arg = valuePop(ctxt);
 7543:     if (arg == NULL)
 7544: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7545:     val = xmlXPathCastToNumber(arg);
 7546:     xmlXPathReleaseObject(ctxt->context, arg);
 7547:     CAST_TO_NUMBER;
 7548:     CHECK_TYPE(XPATH_NUMBER);
 7549:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
 7550: 	ctxt->value->floatval = xmlXPathNAN;
 7551:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
 7552: 	if (ctxt->value->floatval == 0)
 7553: 	    ctxt->value->floatval = xmlXPathNAN;
 7554: 	else if (ctxt->value->floatval > 0)
 7555: 	    ctxt->value->floatval = xmlXPathNINF;
 7556: 	else if (ctxt->value->floatval < 0)
 7557: 	    ctxt->value->floatval = xmlXPathPINF;
 7558:     }
 7559:     else if (val == 0) {
 7560: 	if (ctxt->value->floatval == 0)
 7561: 	    ctxt->value->floatval = xmlXPathNAN;
 7562: 	else if (ctxt->value->floatval > 0)
 7563: 	    ctxt->value->floatval = xmlXPathPINF;
 7564: 	else if (ctxt->value->floatval < 0)
 7565: 	    ctxt->value->floatval = xmlXPathNINF;
 7566:     } else
 7567: 	ctxt->value->floatval /= val;
 7568: }
 7569: 
 7570: /**
 7571:  * xmlXPathModValues:
 7572:  * @ctxt:  the XPath Parser context
 7573:  *
 7574:  * Implement the mod operation on XPath objects: @arg1 / @arg2
 7575:  * The numeric operators convert their operands to numbers as if
 7576:  * by calling the number function.
 7577:  */
 7578: void
 7579: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
 7580:     xmlXPathObjectPtr arg;
 7581:     double arg1, arg2;
 7582: 
 7583:     arg = valuePop(ctxt);
 7584:     if (arg == NULL)
 7585: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7586:     arg2 = xmlXPathCastToNumber(arg);
 7587:     xmlXPathReleaseObject(ctxt->context, arg);
 7588:     CAST_TO_NUMBER;
 7589:     CHECK_TYPE(XPATH_NUMBER);
 7590:     arg1 = ctxt->value->floatval;
 7591:     if (arg2 == 0)
 7592: 	ctxt->value->floatval = xmlXPathNAN;
 7593:     else {
 7594: 	ctxt->value->floatval = fmod(arg1, arg2);
 7595:     }
 7596: }
 7597: 
 7598: /************************************************************************
 7599:  *									*
 7600:  *		The traversal functions					*
 7601:  *									*
 7602:  ************************************************************************/
 7603: 
 7604: /*
 7605:  * A traversal function enumerates nodes along an axis.
 7606:  * Initially it must be called with NULL, and it indicates
 7607:  * termination on the axis by returning NULL.
 7608:  */
 7609: typedef xmlNodePtr (*xmlXPathTraversalFunction)
 7610:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
 7611: 
 7612: /*
 7613:  * xmlXPathTraversalFunctionExt:
 7614:  * A traversal function enumerates nodes along an axis.
 7615:  * Initially it must be called with NULL, and it indicates
 7616:  * termination on the axis by returning NULL.
 7617:  * The context node of the traversal is specified via @contextNode.
 7618:  */
 7619: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
 7620:                     (xmlNodePtr cur, xmlNodePtr contextNode);
 7621: 
 7622: /*
 7623:  * xmlXPathNodeSetMergeFunction:
 7624:  * Used for merging node sets in xmlXPathCollectAndTest().
 7625:  */
 7626: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
 7627: 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
 7628: 
 7629: 
 7630: /**
 7631:  * xmlXPathNextSelf:
 7632:  * @ctxt:  the XPath Parser context
 7633:  * @cur:  the current node in the traversal
 7634:  *
 7635:  * Traversal function for the "self" direction
 7636:  * The self axis contains just the context node itself
 7637:  *
 7638:  * Returns the next element following that axis
 7639:  */
 7640: xmlNodePtr
 7641: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7642:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7643:     if (cur == NULL)
 7644:         return(ctxt->context->node);
 7645:     return(NULL);
 7646: }
 7647: 
 7648: /**
 7649:  * xmlXPathNextChild:
 7650:  * @ctxt:  the XPath Parser context
 7651:  * @cur:  the current node in the traversal
 7652:  *
 7653:  * Traversal function for the "child" direction
 7654:  * The child axis contains the children of the context node in document order.
 7655:  *
 7656:  * Returns the next element following that axis
 7657:  */
 7658: xmlNodePtr
 7659: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7660:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7661:     if (cur == NULL) {
 7662: 	if (ctxt->context->node == NULL) return(NULL);
 7663: 	switch (ctxt->context->node->type) {
 7664:             case XML_ELEMENT_NODE:
 7665:             case XML_TEXT_NODE:
 7666:             case XML_CDATA_SECTION_NODE:
 7667:             case XML_ENTITY_REF_NODE:
 7668:             case XML_ENTITY_NODE:
 7669:             case XML_PI_NODE:
 7670:             case XML_COMMENT_NODE:
 7671:             case XML_NOTATION_NODE:
 7672:             case XML_DTD_NODE:
 7673: 		return(ctxt->context->node->children);
 7674:             case XML_DOCUMENT_NODE:
 7675:             case XML_DOCUMENT_TYPE_NODE:
 7676:             case XML_DOCUMENT_FRAG_NODE:
 7677:             case XML_HTML_DOCUMENT_NODE:
 7678: #ifdef LIBXML_DOCB_ENABLED
 7679: 	    case XML_DOCB_DOCUMENT_NODE:
 7680: #endif
 7681: 		return(((xmlDocPtr) ctxt->context->node)->children);
 7682: 	    case XML_ELEMENT_DECL:
 7683: 	    case XML_ATTRIBUTE_DECL:
 7684: 	    case XML_ENTITY_DECL:
 7685:             case XML_ATTRIBUTE_NODE:
 7686: 	    case XML_NAMESPACE_DECL:
 7687: 	    case XML_XINCLUDE_START:
 7688: 	    case XML_XINCLUDE_END:
 7689: 		return(NULL);
 7690: 	}
 7691: 	return(NULL);
 7692:     }
 7693:     if ((cur->type == XML_DOCUMENT_NODE) ||
 7694:         (cur->type == XML_HTML_DOCUMENT_NODE))
 7695: 	return(NULL);
 7696:     return(cur->next);
 7697: }
 7698: 
 7699: /**
 7700:  * xmlXPathNextChildElement:
 7701:  * @ctxt:  the XPath Parser context
 7702:  * @cur:  the current node in the traversal
 7703:  *
 7704:  * Traversal function for the "child" direction and nodes of type element.
 7705:  * The child axis contains the children of the context node in document order.
 7706:  *
 7707:  * Returns the next element following that axis
 7708:  */
 7709: static xmlNodePtr
 7710: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7711:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7712:     if (cur == NULL) {
 7713: 	cur = ctxt->context->node;
 7714: 	if (cur == NULL) return(NULL);
 7715: 	/*
 7716: 	* Get the first element child.
 7717: 	*/
 7718: 	switch (cur->type) {
 7719:             case XML_ELEMENT_NODE:
 7720: 	    case XML_DOCUMENT_FRAG_NODE:
 7721: 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
 7722:             case XML_ENTITY_NODE:
 7723: 		cur = cur->children;
 7724: 		if (cur != NULL) {
 7725: 		    if (cur->type == XML_ELEMENT_NODE)
 7726: 			return(cur);
 7727: 		    do {
 7728: 			cur = cur->next;
 7729: 		    } while ((cur != NULL) &&
 7730: 			(cur->type != XML_ELEMENT_NODE));
 7731: 		    return(cur);
 7732: 		}
 7733: 		return(NULL);
 7734:             case XML_DOCUMENT_NODE:
 7735:             case XML_HTML_DOCUMENT_NODE:
 7736: #ifdef LIBXML_DOCB_ENABLED
 7737: 	    case XML_DOCB_DOCUMENT_NODE:
 7738: #endif
 7739: 		return(xmlDocGetRootElement((xmlDocPtr) cur));
 7740: 	    default:
 7741: 		return(NULL);
 7742: 	}
 7743: 	return(NULL);
 7744:     }
 7745:     /*
 7746:     * Get the next sibling element node.
 7747:     */
 7748:     switch (cur->type) {
 7749: 	case XML_ELEMENT_NODE:
 7750: 	case XML_TEXT_NODE:
 7751: 	case XML_ENTITY_REF_NODE:
 7752: 	case XML_ENTITY_NODE:
 7753: 	case XML_CDATA_SECTION_NODE:
 7754: 	case XML_PI_NODE:
 7755: 	case XML_COMMENT_NODE:
 7756: 	case XML_XINCLUDE_END:
 7757: 	    break;
 7758: 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
 7759: 	default:
 7760: 	    return(NULL);
 7761:     }
 7762:     if (cur->next != NULL) {
 7763: 	if (cur->next->type == XML_ELEMENT_NODE)
 7764: 	    return(cur->next);
 7765: 	cur = cur->next;
 7766: 	do {
 7767: 	    cur = cur->next;
 7768: 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
 7769: 	return(cur);
 7770:     }
 7771:     return(NULL);
 7772: }
 7773: 
 7774: #if 0
 7775: /**
 7776:  * xmlXPathNextDescendantOrSelfElemParent:
 7777:  * @ctxt:  the XPath Parser context
 7778:  * @cur:  the current node in the traversal
 7779:  *
 7780:  * Traversal function for the "descendant-or-self" axis.
 7781:  * Additionally it returns only nodes which can be parents of
 7782:  * element nodes.
 7783:  *
 7784:  *
 7785:  * Returns the next element following that axis
 7786:  */
 7787: static xmlNodePtr
 7788: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
 7789: 				       xmlNodePtr contextNode)
 7790: {
 7791:     if (cur == NULL) {
 7792: 	if (contextNode == NULL)
 7793: 	    return(NULL);
 7794: 	switch (contextNode->type) {
 7795: 	    case XML_ELEMENT_NODE:
 7796: 	    case XML_XINCLUDE_START:
 7797: 	    case XML_DOCUMENT_FRAG_NODE:
 7798: 	    case XML_DOCUMENT_NODE:
 7799: #ifdef LIBXML_DOCB_ENABLED
 7800: 	    case XML_DOCB_DOCUMENT_NODE:
 7801: #endif
 7802: 	    case XML_HTML_DOCUMENT_NODE:
 7803: 		return(contextNode);
 7804: 	    default:
 7805: 		return(NULL);
 7806: 	}
 7807: 	return(NULL);
 7808:     } else {
 7809: 	xmlNodePtr start = cur;
 7810: 
 7811: 	while (cur != NULL) {
 7812: 	    switch (cur->type) {
 7813: 		case XML_ELEMENT_NODE:
 7814: 		/* TODO: OK to have XInclude here? */
 7815: 		case XML_XINCLUDE_START:
 7816: 		case XML_DOCUMENT_FRAG_NODE:
 7817: 		    if (cur != start)
 7818: 			return(cur);
 7819: 		    if (cur->children != NULL) {
 7820: 			cur = cur->children;
 7821: 			continue;
 7822: 		    }
 7823: 		    break;
 7824: 		/* Not sure if we need those here. */
 7825: 		case XML_DOCUMENT_NODE:
 7826: #ifdef LIBXML_DOCB_ENABLED
 7827: 		case XML_DOCB_DOCUMENT_NODE:
 7828: #endif
 7829: 		case XML_HTML_DOCUMENT_NODE:
 7830: 		    if (cur != start)
 7831: 			return(cur);
 7832: 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
 7833: 		default:
 7834: 		    break;
 7835: 	    }
 7836: 
 7837: next_sibling:
 7838: 	    if ((cur == NULL) || (cur == contextNode))
 7839: 		return(NULL);
 7840: 	    if (cur->next != NULL) {
 7841: 		cur = cur->next;
 7842: 	    } else {
 7843: 		cur = cur->parent;
 7844: 		goto next_sibling;
 7845: 	    }
 7846: 	}
 7847:     }
 7848:     return(NULL);
 7849: }
 7850: #endif
 7851: 
 7852: /**
 7853:  * xmlXPathNextDescendant:
 7854:  * @ctxt:  the XPath Parser context
 7855:  * @cur:  the current node in the traversal
 7856:  *
 7857:  * Traversal function for the "descendant" direction
 7858:  * the descendant axis contains the descendants of the context node in document
 7859:  * order; a descendant is a child or a child of a child and so on.
 7860:  *
 7861:  * Returns the next element following that axis
 7862:  */
 7863: xmlNodePtr
 7864: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7865:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7866:     if (cur == NULL) {
 7867: 	if (ctxt->context->node == NULL)
 7868: 	    return(NULL);
 7869: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7870: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7871: 	    return(NULL);
 7872: 
 7873:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 7874: 	    return(ctxt->context->doc->children);
 7875:         return(ctxt->context->node->children);
 7876:     }
 7877: 
 7878:     if (cur->type == XML_NAMESPACE_DECL)
 7879:         return(NULL);
 7880:     if (cur->children != NULL) {
 7881: 	/*
 7882: 	 * Do not descend on entities declarations
 7883: 	 */
 7884: 	if (cur->children->type != XML_ENTITY_DECL) {
 7885: 	    cur = cur->children;
 7886: 	    /*
 7887: 	     * Skip DTDs
 7888: 	     */
 7889: 	    if (cur->type != XML_DTD_NODE)
 7890: 		return(cur);
 7891: 	}
 7892:     }
 7893: 
 7894:     if (cur == ctxt->context->node) return(NULL);
 7895: 
 7896:     while (cur->next != NULL) {
 7897: 	cur = cur->next;
 7898: 	if ((cur->type != XML_ENTITY_DECL) &&
 7899: 	    (cur->type != XML_DTD_NODE))
 7900: 	    return(cur);
 7901:     }
 7902: 
 7903:     do {
 7904:         cur = cur->parent;
 7905: 	if (cur == NULL) break;
 7906: 	if (cur == ctxt->context->node) return(NULL);
 7907: 	if (cur->next != NULL) {
 7908: 	    cur = cur->next;
 7909: 	    return(cur);
 7910: 	}
 7911:     } while (cur != NULL);
 7912:     return(cur);
 7913: }
 7914: 
 7915: /**
 7916:  * xmlXPathNextDescendantOrSelf:
 7917:  * @ctxt:  the XPath Parser context
 7918:  * @cur:  the current node in the traversal
 7919:  *
 7920:  * Traversal function for the "descendant-or-self" direction
 7921:  * the descendant-or-self axis contains the context node and the descendants
 7922:  * of the context node in document order; thus the context node is the first
 7923:  * node on the axis, and the first child of the context node is the second node
 7924:  * on the axis
 7925:  *
 7926:  * Returns the next element following that axis
 7927:  */
 7928: xmlNodePtr
 7929: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7930:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7931:     if (cur == NULL) {
 7932: 	if (ctxt->context->node == NULL)
 7933: 	    return(NULL);
 7934: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7935: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7936: 	    return(NULL);
 7937:         return(ctxt->context->node);
 7938:     }
 7939: 
 7940:     return(xmlXPathNextDescendant(ctxt, cur));
 7941: }
 7942: 
 7943: /**
 7944:  * xmlXPathNextParent:
 7945:  * @ctxt:  the XPath Parser context
 7946:  * @cur:  the current node in the traversal
 7947:  *
 7948:  * Traversal function for the "parent" direction
 7949:  * The parent axis contains the parent of the context node, if there is one.
 7950:  *
 7951:  * Returns the next element following that axis
 7952:  */
 7953: xmlNodePtr
 7954: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7955:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7956:     /*
 7957:      * the parent of an attribute or namespace node is the element
 7958:      * to which the attribute or namespace node is attached
 7959:      * Namespace handling !!!
 7960:      */
 7961:     if (cur == NULL) {
 7962: 	if (ctxt->context->node == NULL) return(NULL);
 7963: 	switch (ctxt->context->node->type) {
 7964:             case XML_ELEMENT_NODE:
 7965:             case XML_TEXT_NODE:
 7966:             case XML_CDATA_SECTION_NODE:
 7967:             case XML_ENTITY_REF_NODE:
 7968:             case XML_ENTITY_NODE:
 7969:             case XML_PI_NODE:
 7970:             case XML_COMMENT_NODE:
 7971:             case XML_NOTATION_NODE:
 7972:             case XML_DTD_NODE:
 7973: 	    case XML_ELEMENT_DECL:
 7974: 	    case XML_ATTRIBUTE_DECL:
 7975: 	    case XML_XINCLUDE_START:
 7976: 	    case XML_XINCLUDE_END:
 7977: 	    case XML_ENTITY_DECL:
 7978: 		if (ctxt->context->node->parent == NULL)
 7979: 		    return((xmlNodePtr) ctxt->context->doc);
 7980: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 7981: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 7982: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 7983: 				 BAD_CAST "fake node libxslt"))))
 7984: 		    return(NULL);
 7985: 		return(ctxt->context->node->parent);
 7986:             case XML_ATTRIBUTE_NODE: {
 7987: 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 7988: 
 7989: 		return(att->parent);
 7990: 	    }
 7991:             case XML_DOCUMENT_NODE:
 7992:             case XML_DOCUMENT_TYPE_NODE:
 7993:             case XML_DOCUMENT_FRAG_NODE:
 7994:             case XML_HTML_DOCUMENT_NODE:
 7995: #ifdef LIBXML_DOCB_ENABLED
 7996: 	    case XML_DOCB_DOCUMENT_NODE:
 7997: #endif
 7998:                 return(NULL);
 7999: 	    case XML_NAMESPACE_DECL: {
 8000: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 8001: 
 8002: 		if ((ns->next != NULL) &&
 8003: 		    (ns->next->type != XML_NAMESPACE_DECL))
 8004: 		    return((xmlNodePtr) ns->next);
 8005:                 return(NULL);
 8006: 	    }
 8007: 	}
 8008:     }
 8009:     return(NULL);
 8010: }
 8011: 
 8012: /**
 8013:  * xmlXPathNextAncestor:
 8014:  * @ctxt:  the XPath Parser context
 8015:  * @cur:  the current node in the traversal
 8016:  *
 8017:  * Traversal function for the "ancestor" direction
 8018:  * the ancestor axis contains the ancestors of the context node; the ancestors
 8019:  * of the context node consist of the parent of context node and the parent's
 8020:  * parent and so on; the nodes are ordered in reverse document order; thus the
 8021:  * parent is the first node on the axis, and the parent's parent is the second
 8022:  * node on the axis
 8023:  *
 8024:  * Returns the next element following that axis
 8025:  */
 8026: xmlNodePtr
 8027: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8028:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8029:     /*
 8030:      * the parent of an attribute or namespace node is the element
 8031:      * to which the attribute or namespace node is attached
 8032:      * !!!!!!!!!!!!!
 8033:      */
 8034:     if (cur == NULL) {
 8035: 	if (ctxt->context->node == NULL) return(NULL);
 8036: 	switch (ctxt->context->node->type) {
 8037:             case XML_ELEMENT_NODE:
 8038:             case XML_TEXT_NODE:
 8039:             case XML_CDATA_SECTION_NODE:
 8040:             case XML_ENTITY_REF_NODE:
 8041:             case XML_ENTITY_NODE:
 8042:             case XML_PI_NODE:
 8043:             case XML_COMMENT_NODE:
 8044: 	    case XML_DTD_NODE:
 8045: 	    case XML_ELEMENT_DECL:
 8046: 	    case XML_ATTRIBUTE_DECL:
 8047: 	    case XML_ENTITY_DECL:
 8048:             case XML_NOTATION_NODE:
 8049: 	    case XML_XINCLUDE_START:
 8050: 	    case XML_XINCLUDE_END:
 8051: 		if (ctxt->context->node->parent == NULL)
 8052: 		    return((xmlNodePtr) ctxt->context->doc);
 8053: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 8054: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 8055: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 8056: 				 BAD_CAST "fake node libxslt"))))
 8057: 		    return(NULL);
 8058: 		return(ctxt->context->node->parent);
 8059:             case XML_ATTRIBUTE_NODE: {
 8060: 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
 8061: 
 8062: 		return(tmp->parent);
 8063: 	    }
 8064:             case XML_DOCUMENT_NODE:
 8065:             case XML_DOCUMENT_TYPE_NODE:
 8066:             case XML_DOCUMENT_FRAG_NODE:
 8067:             case XML_HTML_DOCUMENT_NODE:
 8068: #ifdef LIBXML_DOCB_ENABLED
 8069: 	    case XML_DOCB_DOCUMENT_NODE:
 8070: #endif
 8071:                 return(NULL);
 8072: 	    case XML_NAMESPACE_DECL: {
 8073: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 8074: 
 8075: 		if ((ns->next != NULL) &&
 8076: 		    (ns->next->type != XML_NAMESPACE_DECL))
 8077: 		    return((xmlNodePtr) ns->next);
 8078: 		/* Bad, how did that namespace end up here ? */
 8079:                 return(NULL);
 8080: 	    }
 8081: 	}
 8082: 	return(NULL);
 8083:     }
 8084:     if (cur == ctxt->context->doc->children)
 8085: 	return((xmlNodePtr) ctxt->context->doc);
 8086:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8087: 	return(NULL);
 8088:     switch (cur->type) {
 8089: 	case XML_ELEMENT_NODE:
 8090: 	case XML_TEXT_NODE:
 8091: 	case XML_CDATA_SECTION_NODE:
 8092: 	case XML_ENTITY_REF_NODE:
 8093: 	case XML_ENTITY_NODE:
 8094: 	case XML_PI_NODE:
 8095: 	case XML_COMMENT_NODE:
 8096: 	case XML_NOTATION_NODE:
 8097: 	case XML_DTD_NODE:
 8098:         case XML_ELEMENT_DECL:
 8099:         case XML_ATTRIBUTE_DECL:
 8100:         case XML_ENTITY_DECL:
 8101: 	case XML_XINCLUDE_START:
 8102: 	case XML_XINCLUDE_END:
 8103: 	    if (cur->parent == NULL)
 8104: 		return(NULL);
 8105: 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
 8106: 		((cur->parent->name[0] == ' ') ||
 8107: 		 (xmlStrEqual(cur->parent->name,
 8108: 			      BAD_CAST "fake node libxslt"))))
 8109: 		return(NULL);
 8110: 	    return(cur->parent);
 8111: 	case XML_ATTRIBUTE_NODE: {
 8112: 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 8113: 
 8114: 	    return(att->parent);
 8115: 	}
 8116: 	case XML_NAMESPACE_DECL: {
 8117: 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 8118: 
 8119: 	    if ((ns->next != NULL) &&
 8120: 	        (ns->next->type != XML_NAMESPACE_DECL))
 8121: 	        return((xmlNodePtr) ns->next);
 8122: 	    /* Bad, how did that namespace end up here ? */
 8123:             return(NULL);
 8124: 	}
 8125: 	case XML_DOCUMENT_NODE:
 8126: 	case XML_DOCUMENT_TYPE_NODE:
 8127: 	case XML_DOCUMENT_FRAG_NODE:
 8128: 	case XML_HTML_DOCUMENT_NODE:
 8129: #ifdef LIBXML_DOCB_ENABLED
 8130: 	case XML_DOCB_DOCUMENT_NODE:
 8131: #endif
 8132: 	    return(NULL);
 8133:     }
 8134:     return(NULL);
 8135: }
 8136: 
 8137: /**
 8138:  * xmlXPathNextAncestorOrSelf:
 8139:  * @ctxt:  the XPath Parser context
 8140:  * @cur:  the current node in the traversal
 8141:  *
 8142:  * Traversal function for the "ancestor-or-self" direction
 8143:  * he ancestor-or-self axis contains the context node and ancestors of
 8144:  * the context node in reverse document order; thus the context node is
 8145:  * the first node on the axis, and the context node's parent the second;
 8146:  * parent here is defined the same as with the parent axis.
 8147:  *
 8148:  * Returns the next element following that axis
 8149:  */
 8150: xmlNodePtr
 8151: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8152:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8153:     if (cur == NULL)
 8154:         return(ctxt->context->node);
 8155:     return(xmlXPathNextAncestor(ctxt, cur));
 8156: }
 8157: 
 8158: /**
 8159:  * xmlXPathNextFollowingSibling:
 8160:  * @ctxt:  the XPath Parser context
 8161:  * @cur:  the current node in the traversal
 8162:  *
 8163:  * Traversal function for the "following-sibling" direction
 8164:  * The following-sibling axis contains the following siblings of the context
 8165:  * node in document order.
 8166:  *
 8167:  * Returns the next element following that axis
 8168:  */
 8169: xmlNodePtr
 8170: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8171:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8172:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8173: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8174: 	return(NULL);
 8175:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8176:         return(NULL);
 8177:     if (cur == NULL)
 8178:         return(ctxt->context->node->next);
 8179:     return(cur->next);
 8180: }
 8181: 
 8182: /**
 8183:  * xmlXPathNextPrecedingSibling:
 8184:  * @ctxt:  the XPath Parser context
 8185:  * @cur:  the current node in the traversal
 8186:  *
 8187:  * Traversal function for the "preceding-sibling" direction
 8188:  * The preceding-sibling axis contains the preceding siblings of the context
 8189:  * node in reverse document order; the first preceding sibling is first on the
 8190:  * axis; the sibling preceding that node is the second on the axis and so on.
 8191:  *
 8192:  * Returns the next element following that axis
 8193:  */
 8194: xmlNodePtr
 8195: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8196:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8197:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8198: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8199: 	return(NULL);
 8200:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8201:         return(NULL);
 8202:     if (cur == NULL)
 8203:         return(ctxt->context->node->prev);
 8204:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
 8205: 	cur = cur->prev;
 8206: 	if (cur == NULL)
 8207: 	    return(ctxt->context->node->prev);
 8208:     }
 8209:     return(cur->prev);
 8210: }
 8211: 
 8212: /**
 8213:  * xmlXPathNextFollowing:
 8214:  * @ctxt:  the XPath Parser context
 8215:  * @cur:  the current node in the traversal
 8216:  *
 8217:  * Traversal function for the "following" direction
 8218:  * The following axis contains all nodes in the same document as the context
 8219:  * node that are after the context node in document order, excluding any
 8220:  * descendants and excluding attribute nodes and namespace nodes; the nodes
 8221:  * are ordered in document order
 8222:  *
 8223:  * Returns the next element following that axis
 8224:  */
 8225: xmlNodePtr
 8226: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8227:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8228:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
 8229:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
 8230:         return(cur->children);
 8231: 
 8232:     if (cur == NULL) {
 8233:         cur = ctxt->context->node;
 8234:         if (cur->type == XML_NAMESPACE_DECL)
 8235:             return(NULL);
 8236:         if (cur->type == XML_ATTRIBUTE_NODE)
 8237:             cur = cur->parent;
 8238:     }
 8239:     if (cur == NULL) return(NULL) ; /* ERROR */
 8240:     if (cur->next != NULL) return(cur->next) ;
 8241:     do {
 8242:         cur = cur->parent;
 8243:         if (cur == NULL) break;
 8244:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
 8245:         if (cur->next != NULL) return(cur->next);
 8246:     } while (cur != NULL);
 8247:     return(cur);
 8248: }
 8249: 
 8250: /*
 8251:  * xmlXPathIsAncestor:
 8252:  * @ancestor:  the ancestor node
 8253:  * @node:  the current node
 8254:  *
 8255:  * Check that @ancestor is a @node's ancestor
 8256:  *
 8257:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
 8258:  */
 8259: static int
 8260: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
 8261:     if ((ancestor == NULL) || (node == NULL)) return(0);
 8262:     if (node->type == XML_NAMESPACE_DECL)
 8263:         return(0);
 8264:     if (ancestor->type == XML_NAMESPACE_DECL)
 8265:         return(0);
 8266:     /* nodes need to be in the same document */
 8267:     if (ancestor->doc != node->doc) return(0);
 8268:     /* avoid searching if ancestor or node is the root node */
 8269:     if (ancestor == (xmlNodePtr) node->doc) return(1);
 8270:     if (node == (xmlNodePtr) ancestor->doc) return(0);
 8271:     while (node->parent != NULL) {
 8272:         if (node->parent == ancestor)
 8273:             return(1);
 8274: 	node = node->parent;
 8275:     }
 8276:     return(0);
 8277: }
 8278: 
 8279: /**
 8280:  * xmlXPathNextPreceding:
 8281:  * @ctxt:  the XPath Parser context
 8282:  * @cur:  the current node in the traversal
 8283:  *
 8284:  * Traversal function for the "preceding" direction
 8285:  * the preceding axis contains all nodes in the same document as the context
 8286:  * node that are before the context node in document order, excluding any
 8287:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8288:  * ordered in reverse document order
 8289:  *
 8290:  * Returns the next element following that axis
 8291:  */
 8292: xmlNodePtr
 8293: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
 8294: {
 8295:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8296:     if (cur == NULL) {
 8297:         cur = ctxt->context->node;
 8298:         if (cur->type == XML_NAMESPACE_DECL)
 8299:             return(NULL);
 8300:         if (cur->type == XML_ATTRIBUTE_NODE)
 8301:             return(cur->parent);
 8302:     }
 8303:     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
 8304: 	return (NULL);
 8305:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8306: 	cur = cur->prev;
 8307:     do {
 8308:         if (cur->prev != NULL) {
 8309:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
 8310:             return (cur);
 8311:         }
 8312: 
 8313:         cur = cur->parent;
 8314:         if (cur == NULL)
 8315:             return (NULL);
 8316:         if (cur == ctxt->context->doc->children)
 8317:             return (NULL);
 8318:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
 8319:     return (cur);
 8320: }
 8321: 
 8322: /**
 8323:  * xmlXPathNextPrecedingInternal:
 8324:  * @ctxt:  the XPath Parser context
 8325:  * @cur:  the current node in the traversal
 8326:  *
 8327:  * Traversal function for the "preceding" direction
 8328:  * the preceding axis contains all nodes in the same document as the context
 8329:  * node that are before the context node in document order, excluding any
 8330:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8331:  * ordered in reverse document order
 8332:  * This is a faster implementation but internal only since it requires a
 8333:  * state kept in the parser context: ctxt->ancestor.
 8334:  *
 8335:  * Returns the next element following that axis
 8336:  */
 8337: static xmlNodePtr
 8338: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
 8339:                               xmlNodePtr cur)
 8340: {
 8341:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8342:     if (cur == NULL) {
 8343:         cur = ctxt->context->node;
 8344:         if (cur == NULL)
 8345:             return (NULL);
 8346:         if (cur->type == XML_NAMESPACE_DECL)
 8347:             return (NULL);
 8348:         ctxt->ancestor = cur->parent;
 8349:     }
 8350:     if (cur->type == XML_NAMESPACE_DECL)
 8351:         return(NULL);
 8352:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8353: 	cur = cur->prev;
 8354:     while (cur->prev == NULL) {
 8355:         cur = cur->parent;
 8356:         if (cur == NULL)
 8357:             return (NULL);
 8358:         if (cur == ctxt->context->doc->children)
 8359:             return (NULL);
 8360:         if (cur != ctxt->ancestor)
 8361:             return (cur);
 8362:         ctxt->ancestor = cur->parent;
 8363:     }
 8364:     cur = cur->prev;
 8365:     while (cur->last != NULL)
 8366:         cur = cur->last;
 8367:     return (cur);
 8368: }
 8369: 
 8370: /**
 8371:  * xmlXPathNextNamespace:
 8372:  * @ctxt:  the XPath Parser context
 8373:  * @cur:  the current attribute in the traversal
 8374:  *
 8375:  * Traversal function for the "namespace" direction
 8376:  * the namespace axis contains the namespace nodes of the context node;
 8377:  * the order of nodes on this axis is implementation-defined; the axis will
 8378:  * be empty unless the context node is an element
 8379:  *
 8380:  * We keep the XML namespace node at the end of the list.
 8381:  *
 8382:  * Returns the next element following that axis
 8383:  */
 8384: xmlNodePtr
 8385: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8386:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8387:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
 8388:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
 8389:         if (ctxt->context->tmpNsList != NULL)
 8390: 	    xmlFree(ctxt->context->tmpNsList);
 8391: 	ctxt->context->tmpNsList =
 8392: 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
 8393: 	ctxt->context->tmpNsNr = 0;
 8394: 	if (ctxt->context->tmpNsList != NULL) {
 8395: 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
 8396: 		ctxt->context->tmpNsNr++;
 8397: 	    }
 8398: 	}
 8399: 	return((xmlNodePtr) xmlXPathXMLNamespace);
 8400:     }
 8401:     if (ctxt->context->tmpNsNr > 0) {
 8402: 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
 8403:     } else {
 8404: 	if (ctxt->context->tmpNsList != NULL)
 8405: 	    xmlFree(ctxt->context->tmpNsList);
 8406: 	ctxt->context->tmpNsList = NULL;
 8407: 	return(NULL);
 8408:     }
 8409: }
 8410: 
 8411: /**
 8412:  * xmlXPathNextAttribute:
 8413:  * @ctxt:  the XPath Parser context
 8414:  * @cur:  the current attribute in the traversal
 8415:  *
 8416:  * Traversal function for the "attribute" direction
 8417:  * TODO: support DTD inherited default attributes
 8418:  *
 8419:  * Returns the next element following that axis
 8420:  */
 8421: xmlNodePtr
 8422: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8423:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8424:     if (ctxt->context->node == NULL)
 8425: 	return(NULL);
 8426:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
 8427: 	return(NULL);
 8428:     if (cur == NULL) {
 8429:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 8430: 	    return(NULL);
 8431:         return((xmlNodePtr)ctxt->context->node->properties);
 8432:     }
 8433:     return((xmlNodePtr)cur->next);
 8434: }
 8435: 
 8436: /************************************************************************
 8437:  *									*
 8438:  *		NodeTest Functions					*
 8439:  *									*
 8440:  ************************************************************************/
 8441: 
 8442: #define IS_FUNCTION			200
 8443: 
 8444: 
 8445: /************************************************************************
 8446:  *									*
 8447:  *		Implicit tree core function library			*
 8448:  *									*
 8449:  ************************************************************************/
 8450: 
 8451: /**
 8452:  * xmlXPathRoot:
 8453:  * @ctxt:  the XPath Parser context
 8454:  *
 8455:  * Initialize the context to the root of the document
 8456:  */
 8457: void
 8458: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
 8459:     if ((ctxt == NULL) || (ctxt->context == NULL))
 8460: 	return;
 8461:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
 8462:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8463: 	ctxt->context->node));
 8464: }
 8465: 
 8466: /************************************************************************
 8467:  *									*
 8468:  *		The explicit core function library			*
 8469:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
 8470:  *									*
 8471:  ************************************************************************/
 8472: 
 8473: 
 8474: /**
 8475:  * xmlXPathLastFunction:
 8476:  * @ctxt:  the XPath Parser context
 8477:  * @nargs:  the number of arguments
 8478:  *
 8479:  * Implement the last() XPath function
 8480:  *    number last()
 8481:  * The last function returns the number of nodes in the context node list.
 8482:  */
 8483: void
 8484: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8485:     CHECK_ARITY(0);
 8486:     if (ctxt->context->contextSize >= 0) {
 8487: 	valuePush(ctxt,
 8488: 	    xmlXPathCacheNewFloat(ctxt->context,
 8489: 		(double) ctxt->context->contextSize));
 8490: #ifdef DEBUG_EXPR
 8491: 	xmlGenericError(xmlGenericErrorContext,
 8492: 		"last() : %d\n", ctxt->context->contextSize);
 8493: #endif
 8494:     } else {
 8495: 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
 8496:     }
 8497: }
 8498: 
 8499: /**
 8500:  * xmlXPathPositionFunction:
 8501:  * @ctxt:  the XPath Parser context
 8502:  * @nargs:  the number of arguments
 8503:  *
 8504:  * Implement the position() XPath function
 8505:  *    number position()
 8506:  * The position function returns the position of the context node in the
 8507:  * context node list. The first position is 1, and so the last position
 8508:  * will be equal to last().
 8509:  */
 8510: void
 8511: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8512:     CHECK_ARITY(0);
 8513:     if (ctxt->context->proximityPosition >= 0) {
 8514: 	valuePush(ctxt,
 8515: 	      xmlXPathCacheNewFloat(ctxt->context,
 8516: 		(double) ctxt->context->proximityPosition));
 8517: #ifdef DEBUG_EXPR
 8518: 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
 8519: 		ctxt->context->proximityPosition);
 8520: #endif
 8521:     } else {
 8522: 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
 8523:     }
 8524: }
 8525: 
 8526: /**
 8527:  * xmlXPathCountFunction:
 8528:  * @ctxt:  the XPath Parser context
 8529:  * @nargs:  the number of arguments
 8530:  *
 8531:  * Implement the count() XPath function
 8532:  *    number count(node-set)
 8533:  */
 8534: void
 8535: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8536:     xmlXPathObjectPtr cur;
 8537: 
 8538:     CHECK_ARITY(1);
 8539:     if ((ctxt->value == NULL) ||
 8540: 	((ctxt->value->type != XPATH_NODESET) &&
 8541: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8542: 	XP_ERROR(XPATH_INVALID_TYPE);
 8543:     cur = valuePop(ctxt);
 8544: 
 8545:     if ((cur == NULL) || (cur->nodesetval == NULL))
 8546: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8547:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
 8548: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8549: 	    (double) cur->nodesetval->nodeNr));
 8550:     } else {
 8551: 	if ((cur->nodesetval->nodeNr != 1) ||
 8552: 	    (cur->nodesetval->nodeTab == NULL)) {
 8553: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8554: 	} else {
 8555: 	    xmlNodePtr tmp;
 8556: 	    int i = 0;
 8557: 
 8558: 	    tmp = cur->nodesetval->nodeTab[0];
 8559: 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
 8560: 		tmp = tmp->children;
 8561: 		while (tmp != NULL) {
 8562: 		    tmp = tmp->next;
 8563: 		    i++;
 8564: 		}
 8565: 	    }
 8566: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
 8567: 	}
 8568:     }
 8569:     xmlXPathReleaseObject(ctxt->context, cur);
 8570: }
 8571: 
 8572: /**
 8573:  * xmlXPathGetElementsByIds:
 8574:  * @doc:  the document
 8575:  * @ids:  a whitespace separated list of IDs
 8576:  *
 8577:  * Selects elements by their unique ID.
 8578:  *
 8579:  * Returns a node-set of selected elements.
 8580:  */
 8581: static xmlNodeSetPtr
 8582: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
 8583:     xmlNodeSetPtr ret;
 8584:     const xmlChar *cur = ids;
 8585:     xmlChar *ID;
 8586:     xmlAttrPtr attr;
 8587:     xmlNodePtr elem = NULL;
 8588: 
 8589:     if (ids == NULL) return(NULL);
 8590: 
 8591:     ret = xmlXPathNodeSetCreate(NULL);
 8592:     if (ret == NULL)
 8593:         return(ret);
 8594: 
 8595:     while (IS_BLANK_CH(*cur)) cur++;
 8596:     while (*cur != 0) {
 8597: 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
 8598: 	    cur++;
 8599: 
 8600:         ID = xmlStrndup(ids, cur - ids);
 8601: 	if (ID != NULL) {
 8602: 	    /*
 8603: 	     * We used to check the fact that the value passed
 8604: 	     * was an NCName, but this generated much troubles for
 8605: 	     * me and Aleksey Sanin, people blatantly violated that
 8606: 	     * constaint, like Visa3D spec.
 8607: 	     * if (xmlValidateNCName(ID, 1) == 0)
 8608: 	     */
 8609: 	    attr = xmlGetID(doc, ID);
 8610: 	    if (attr != NULL) {
 8611: 		if (attr->type == XML_ATTRIBUTE_NODE)
 8612: 		    elem = attr->parent;
 8613: 		else if (attr->type == XML_ELEMENT_NODE)
 8614: 		    elem = (xmlNodePtr) attr;
 8615: 		else
 8616: 		    elem = NULL;
 8617: 		if (elem != NULL)
 8618: 		    xmlXPathNodeSetAdd(ret, elem);
 8619: 	    }
 8620: 	    xmlFree(ID);
 8621: 	}
 8622: 
 8623: 	while (IS_BLANK_CH(*cur)) cur++;
 8624: 	ids = cur;
 8625:     }
 8626:     return(ret);
 8627: }
 8628: 
 8629: /**
 8630:  * xmlXPathIdFunction:
 8631:  * @ctxt:  the XPath Parser context
 8632:  * @nargs:  the number of arguments
 8633:  *
 8634:  * Implement the id() XPath function
 8635:  *    node-set id(object)
 8636:  * The id function selects elements by their unique ID
 8637:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
 8638:  * then the result is the union of the result of applying id to the
 8639:  * string value of each of the nodes in the argument node-set. When the
 8640:  * argument to id is of any other type, the argument is converted to a
 8641:  * string as if by a call to the string function; the string is split
 8642:  * into a whitespace-separated list of tokens (whitespace is any sequence
 8643:  * of characters matching the production S); the result is a node-set
 8644:  * containing the elements in the same document as the context node that
 8645:  * have a unique ID equal to any of the tokens in the list.
 8646:  */
 8647: void
 8648: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8649:     xmlChar *tokens;
 8650:     xmlNodeSetPtr ret;
 8651:     xmlXPathObjectPtr obj;
 8652: 
 8653:     CHECK_ARITY(1);
 8654:     obj = valuePop(ctxt);
 8655:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8656:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 8657: 	xmlNodeSetPtr ns;
 8658: 	int i;
 8659: 
 8660: 	ret = xmlXPathNodeSetCreate(NULL);
 8661:         /*
 8662:          * FIXME -- in an out-of-memory condition this will behave badly.
 8663:          * The solution is not clear -- we already popped an item from
 8664:          * ctxt, so the object is in a corrupt state.
 8665:          */
 8666: 
 8667: 	if (obj->nodesetval != NULL) {
 8668: 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 8669: 		tokens =
 8670: 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
 8671: 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
 8672: 		ret = xmlXPathNodeSetMerge(ret, ns);
 8673: 		xmlXPathFreeNodeSet(ns);
 8674: 		if (tokens != NULL)
 8675: 		    xmlFree(tokens);
 8676: 	    }
 8677: 	}
 8678: 	xmlXPathReleaseObject(ctxt->context, obj);
 8679: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8680: 	return;
 8681:     }
 8682:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
 8683:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
 8684:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8685:     xmlXPathReleaseObject(ctxt->context, obj);
 8686:     return;
 8687: }
 8688: 
 8689: /**
 8690:  * xmlXPathLocalNameFunction:
 8691:  * @ctxt:  the XPath Parser context
 8692:  * @nargs:  the number of arguments
 8693:  *
 8694:  * Implement the local-name() XPath function
 8695:  *    string local-name(node-set?)
 8696:  * The local-name function returns a string containing the local part
 8697:  * of the name of the node in the argument node-set that is first in
 8698:  * document order. If the node-set is empty or the first node has no
 8699:  * name, an empty string is returned. If the argument is omitted it
 8700:  * defaults to the context node.
 8701:  */
 8702: void
 8703: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8704:     xmlXPathObjectPtr cur;
 8705: 
 8706:     if (ctxt == NULL) return;
 8707: 
 8708:     if (nargs == 0) {
 8709: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8710: 	    ctxt->context->node));
 8711: 	nargs = 1;
 8712:     }
 8713: 
 8714:     CHECK_ARITY(1);
 8715:     if ((ctxt->value == NULL) ||
 8716: 	((ctxt->value->type != XPATH_NODESET) &&
 8717: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8718: 	XP_ERROR(XPATH_INVALID_TYPE);
 8719:     cur = valuePop(ctxt);
 8720: 
 8721:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8722: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8723:     } else {
 8724: 	int i = 0; /* Should be first in document order !!!!! */
 8725: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8726: 	case XML_ELEMENT_NODE:
 8727: 	case XML_ATTRIBUTE_NODE:
 8728: 	case XML_PI_NODE:
 8729: 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8730: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8731: 	    else
 8732: 		valuePush(ctxt,
 8733: 		      xmlXPathCacheNewString(ctxt->context,
 8734: 			cur->nodesetval->nodeTab[i]->name));
 8735: 	    break;
 8736: 	case XML_NAMESPACE_DECL:
 8737: 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8738: 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
 8739: 	    break;
 8740: 	default:
 8741: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8742: 	}
 8743:     }
 8744:     xmlXPathReleaseObject(ctxt->context, cur);
 8745: }
 8746: 
 8747: /**
 8748:  * xmlXPathNamespaceURIFunction:
 8749:  * @ctxt:  the XPath Parser context
 8750:  * @nargs:  the number of arguments
 8751:  *
 8752:  * Implement the namespace-uri() XPath function
 8753:  *    string namespace-uri(node-set?)
 8754:  * The namespace-uri function returns a string containing the
 8755:  * namespace URI of the expanded name of the node in the argument
 8756:  * node-set that is first in document order. If the node-set is empty,
 8757:  * the first node has no name, or the expanded name has no namespace
 8758:  * URI, an empty string is returned. If the argument is omitted it
 8759:  * defaults to the context node.
 8760:  */
 8761: void
 8762: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8763:     xmlXPathObjectPtr cur;
 8764: 
 8765:     if (ctxt == NULL) return;
 8766: 
 8767:     if (nargs == 0) {
 8768: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8769: 	    ctxt->context->node));
 8770: 	nargs = 1;
 8771:     }
 8772:     CHECK_ARITY(1);
 8773:     if ((ctxt->value == NULL) ||
 8774: 	((ctxt->value->type != XPATH_NODESET) &&
 8775: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8776: 	XP_ERROR(XPATH_INVALID_TYPE);
 8777:     cur = valuePop(ctxt);
 8778: 
 8779:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8780: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8781:     } else {
 8782: 	int i = 0; /* Should be first in document order !!!!! */
 8783: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8784: 	case XML_ELEMENT_NODE:
 8785: 	case XML_ATTRIBUTE_NODE:
 8786: 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
 8787: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8788: 	    else
 8789: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8790: 			  cur->nodesetval->nodeTab[i]->ns->href));
 8791: 	    break;
 8792: 	default:
 8793: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8794: 	}
 8795:     }
 8796:     xmlXPathReleaseObject(ctxt->context, cur);
 8797: }
 8798: 
 8799: /**
 8800:  * xmlXPathNameFunction:
 8801:  * @ctxt:  the XPath Parser context
 8802:  * @nargs:  the number of arguments
 8803:  *
 8804:  * Implement the name() XPath function
 8805:  *    string name(node-set?)
 8806:  * The name function returns a string containing a QName representing
 8807:  * the name of the node in the argument node-set that is first in document
 8808:  * order. The QName must represent the name with respect to the namespace
 8809:  * declarations in effect on the node whose name is being represented.
 8810:  * Typically, this will be the form in which the name occurred in the XML
 8811:  * source. This need not be the case if there are namespace declarations
 8812:  * in effect on the node that associate multiple prefixes with the same
 8813:  * namespace. However, an implementation may include information about
 8814:  * the original prefix in its representation of nodes; in this case, an
 8815:  * implementation can ensure that the returned string is always the same
 8816:  * as the QName used in the XML source. If the argument it omitted it
 8817:  * defaults to the context node.
 8818:  * Libxml keep the original prefix so the "real qualified name" used is
 8819:  * returned.
 8820:  */
 8821: static void
 8822: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
 8823: {
 8824:     xmlXPathObjectPtr cur;
 8825: 
 8826:     if (nargs == 0) {
 8827: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8828: 	    ctxt->context->node));
 8829:         nargs = 1;
 8830:     }
 8831: 
 8832:     CHECK_ARITY(1);
 8833:     if ((ctxt->value == NULL) ||
 8834:         ((ctxt->value->type != XPATH_NODESET) &&
 8835:          (ctxt->value->type != XPATH_XSLT_TREE)))
 8836:         XP_ERROR(XPATH_INVALID_TYPE);
 8837:     cur = valuePop(ctxt);
 8838: 
 8839:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8840:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8841:     } else {
 8842:         int i = 0;              /* Should be first in document order !!!!! */
 8843: 
 8844:         switch (cur->nodesetval->nodeTab[i]->type) {
 8845:             case XML_ELEMENT_NODE:
 8846:             case XML_ATTRIBUTE_NODE:
 8847: 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8848: 		    valuePush(ctxt,
 8849: 			xmlXPathCacheNewCString(ctxt->context, ""));
 8850: 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
 8851:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
 8852: 		    valuePush(ctxt,
 8853: 		        xmlXPathCacheNewString(ctxt->context,
 8854: 			    cur->nodesetval->nodeTab[i]->name));
 8855: 		} else {
 8856: 		    xmlChar *fullname;
 8857: 
 8858: 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
 8859: 				     cur->nodesetval->nodeTab[i]->ns->prefix,
 8860: 				     NULL, 0);
 8861: 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
 8862: 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
 8863: 		    if (fullname == NULL) {
 8864: 			XP_ERROR(XPATH_MEMORY_ERROR);
 8865: 		    }
 8866: 		    valuePush(ctxt, xmlXPathCacheWrapString(
 8867: 			ctxt->context, fullname));
 8868:                 }
 8869:                 break;
 8870:             default:
 8871: 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8872: 		    cur->nodesetval->nodeTab[i]));
 8873:                 xmlXPathLocalNameFunction(ctxt, 1);
 8874:         }
 8875:     }
 8876:     xmlXPathReleaseObject(ctxt->context, cur);
 8877: }
 8878: 
 8879: 
 8880: /**
 8881:  * xmlXPathStringFunction:
 8882:  * @ctxt:  the XPath Parser context
 8883:  * @nargs:  the number of arguments
 8884:  *
 8885:  * Implement the string() XPath function
 8886:  *    string string(object?)
 8887:  * The string function converts an object to a string as follows:
 8888:  *    - A node-set is converted to a string by returning the value of
 8889:  *      the node in the node-set that is first in document order.
 8890:  *      If the node-set is empty, an empty string is returned.
 8891:  *    - A number is converted to a string as follows
 8892:  *      + NaN is converted to the string NaN
 8893:  *      + positive zero is converted to the string 0
 8894:  *      + negative zero is converted to the string 0
 8895:  *      + positive infinity is converted to the string Infinity
 8896:  *      + negative infinity is converted to the string -Infinity
 8897:  *      + if the number is an integer, the number is represented in
 8898:  *        decimal form as a Number with no decimal point and no leading
 8899:  *        zeros, preceded by a minus sign (-) if the number is negative
 8900:  *      + otherwise, the number is represented in decimal form as a
 8901:  *        Number including a decimal point with at least one digit
 8902:  *        before the decimal point and at least one digit after the
 8903:  *        decimal point, preceded by a minus sign (-) if the number
 8904:  *        is negative; there must be no leading zeros before the decimal
 8905:  *        point apart possibly from the one required digit immediately
 8906:  *        before the decimal point; beyond the one required digit
 8907:  *        after the decimal point there must be as many, but only as
 8908:  *        many, more digits as are needed to uniquely distinguish the
 8909:  *        number from all other IEEE 754 numeric values.
 8910:  *    - The boolean false value is converted to the string false.
 8911:  *      The boolean true value is converted to the string true.
 8912:  *
 8913:  * If the argument is omitted, it defaults to a node-set with the
 8914:  * context node as its only member.
 8915:  */
 8916: void
 8917: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8918:     xmlXPathObjectPtr cur;
 8919: 
 8920:     if (ctxt == NULL) return;
 8921:     if (nargs == 0) {
 8922:     valuePush(ctxt,
 8923: 	xmlXPathCacheWrapString(ctxt->context,
 8924: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 8925: 	return;
 8926:     }
 8927: 
 8928:     CHECK_ARITY(1);
 8929:     cur = valuePop(ctxt);
 8930:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8931:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
 8932: }
 8933: 
 8934: /**
 8935:  * xmlXPathStringLengthFunction:
 8936:  * @ctxt:  the XPath Parser context
 8937:  * @nargs:  the number of arguments
 8938:  *
 8939:  * Implement the string-length() XPath function
 8940:  *    number string-length(string?)
 8941:  * The string-length returns the number of characters in the string
 8942:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
 8943:  * the context node converted to a string, in other words the value
 8944:  * of the context node.
 8945:  */
 8946: void
 8947: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8948:     xmlXPathObjectPtr cur;
 8949: 
 8950:     if (nargs == 0) {
 8951:         if ((ctxt == NULL) || (ctxt->context == NULL))
 8952: 	    return;
 8953: 	if (ctxt->context->node == NULL) {
 8954: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
 8955: 	} else {
 8956: 	    xmlChar *content;
 8957: 
 8958: 	    content = xmlXPathCastNodeToString(ctxt->context->node);
 8959: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8960: 		xmlUTF8Strlen(content)));
 8961: 	    xmlFree(content);
 8962: 	}
 8963: 	return;
 8964:     }
 8965:     CHECK_ARITY(1);
 8966:     CAST_TO_STRING;
 8967:     CHECK_TYPE(XPATH_STRING);
 8968:     cur = valuePop(ctxt);
 8969:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8970: 	xmlUTF8Strlen(cur->stringval)));
 8971:     xmlXPathReleaseObject(ctxt->context, cur);
 8972: }
 8973: 
 8974: /**
 8975:  * xmlXPathConcatFunction:
 8976:  * @ctxt:  the XPath Parser context
 8977:  * @nargs:  the number of arguments
 8978:  *
 8979:  * Implement the concat() XPath function
 8980:  *    string concat(string, string, string*)
 8981:  * The concat function returns the concatenation of its arguments.
 8982:  */
 8983: void
 8984: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8985:     xmlXPathObjectPtr cur, newobj;
 8986:     xmlChar *tmp;
 8987: 
 8988:     if (ctxt == NULL) return;
 8989:     if (nargs < 2) {
 8990: 	CHECK_ARITY(2);
 8991:     }
 8992: 
 8993:     CAST_TO_STRING;
 8994:     cur = valuePop(ctxt);
 8995:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
 8996: 	xmlXPathReleaseObject(ctxt->context, cur);
 8997: 	return;
 8998:     }
 8999:     nargs--;
 9000: 
 9001:     while (nargs > 0) {
 9002: 	CAST_TO_STRING;
 9003: 	newobj = valuePop(ctxt);
 9004: 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
 9005: 	    xmlXPathReleaseObject(ctxt->context, newobj);
 9006: 	    xmlXPathReleaseObject(ctxt->context, cur);
 9007: 	    XP_ERROR(XPATH_INVALID_TYPE);
 9008: 	}
 9009: 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
 9010: 	newobj->stringval = cur->stringval;
 9011: 	cur->stringval = tmp;
 9012: 	xmlXPathReleaseObject(ctxt->context, newobj);
 9013: 	nargs--;
 9014:     }
 9015:     valuePush(ctxt, cur);
 9016: }
 9017: 
 9018: /**
 9019:  * xmlXPathContainsFunction:
 9020:  * @ctxt:  the XPath Parser context
 9021:  * @nargs:  the number of arguments
 9022:  *
 9023:  * Implement the contains() XPath function
 9024:  *    boolean contains(string, string)
 9025:  * The contains function returns true if the first argument string
 9026:  * contains the second argument string, and otherwise returns false.
 9027:  */
 9028: void
 9029: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9030:     xmlXPathObjectPtr hay, needle;
 9031: 
 9032:     CHECK_ARITY(2);
 9033:     CAST_TO_STRING;
 9034:     CHECK_TYPE(XPATH_STRING);
 9035:     needle = valuePop(ctxt);
 9036:     CAST_TO_STRING;
 9037:     hay = valuePop(ctxt);
 9038: 
 9039:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 9040: 	xmlXPathReleaseObject(ctxt->context, hay);
 9041: 	xmlXPathReleaseObject(ctxt->context, needle);
 9042: 	XP_ERROR(XPATH_INVALID_TYPE);
 9043:     }
 9044:     if (xmlStrstr(hay->stringval, needle->stringval))
 9045: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9046:     else
 9047: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9048:     xmlXPathReleaseObject(ctxt->context, hay);
 9049:     xmlXPathReleaseObject(ctxt->context, needle);
 9050: }
 9051: 
 9052: /**
 9053:  * xmlXPathStartsWithFunction:
 9054:  * @ctxt:  the XPath Parser context
 9055:  * @nargs:  the number of arguments
 9056:  *
 9057:  * Implement the starts-with() XPath function
 9058:  *    boolean starts-with(string, string)
 9059:  * The starts-with function returns true if the first argument string
 9060:  * starts with the second argument string, and otherwise returns false.
 9061:  */
 9062: void
 9063: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9064:     xmlXPathObjectPtr hay, needle;
 9065:     int n;
 9066: 
 9067:     CHECK_ARITY(2);
 9068:     CAST_TO_STRING;
 9069:     CHECK_TYPE(XPATH_STRING);
 9070:     needle = valuePop(ctxt);
 9071:     CAST_TO_STRING;
 9072:     hay = valuePop(ctxt);
 9073: 
 9074:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 9075: 	xmlXPathReleaseObject(ctxt->context, hay);
 9076: 	xmlXPathReleaseObject(ctxt->context, needle);
 9077: 	XP_ERROR(XPATH_INVALID_TYPE);
 9078:     }
 9079:     n = xmlStrlen(needle->stringval);
 9080:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
 9081:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9082:     else
 9083:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9084:     xmlXPathReleaseObject(ctxt->context, hay);
 9085:     xmlXPathReleaseObject(ctxt->context, needle);
 9086: }
 9087: 
 9088: /**
 9089:  * xmlXPathSubstringFunction:
 9090:  * @ctxt:  the XPath Parser context
 9091:  * @nargs:  the number of arguments
 9092:  *
 9093:  * Implement the substring() XPath function
 9094:  *    string substring(string, number, number?)
 9095:  * The substring function returns the substring of the first argument
 9096:  * starting at the position specified in the second argument with
 9097:  * length specified in the third argument. For example,
 9098:  * substring("12345",2,3) returns "234". If the third argument is not
 9099:  * specified, it returns the substring starting at the position specified
 9100:  * in the second argument and continuing to the end of the string. For
 9101:  * example, substring("12345",2) returns "2345".  More precisely, each
 9102:  * character in the string (see [3.6 Strings]) is considered to have a
 9103:  * numeric position: the position of the first character is 1, the position
 9104:  * of the second character is 2 and so on. The returned substring contains
 9105:  * those characters for which the position of the character is greater than
 9106:  * or equal to the second argument and, if the third argument is specified,
 9107:  * less than the sum of the second and third arguments; the comparisons
 9108:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
 9109:  *  - substring("12345", 1.5, 2.6) returns "234"
 9110:  *  - substring("12345", 0, 3) returns "12"
 9111:  *  - substring("12345", 0 div 0, 3) returns ""
 9112:  *  - substring("12345", 1, 0 div 0) returns ""
 9113:  *  - substring("12345", -42, 1 div 0) returns "12345"
 9114:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
 9115:  */
 9116: void
 9117: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9118:     xmlXPathObjectPtr str, start, len;
 9119:     double le=0, in;
 9120:     int i, l, m;
 9121:     xmlChar *ret;
 9122: 
 9123:     if (nargs < 2) {
 9124: 	CHECK_ARITY(2);
 9125:     }
 9126:     if (nargs > 3) {
 9127: 	CHECK_ARITY(3);
 9128:     }
 9129:     /*
 9130:      * take care of possible last (position) argument
 9131:     */
 9132:     if (nargs == 3) {
 9133: 	CAST_TO_NUMBER;
 9134: 	CHECK_TYPE(XPATH_NUMBER);
 9135: 	len = valuePop(ctxt);
 9136: 	le = len->floatval;
 9137: 	xmlXPathReleaseObject(ctxt->context, len);
 9138:     }
 9139: 
 9140:     CAST_TO_NUMBER;
 9141:     CHECK_TYPE(XPATH_NUMBER);
 9142:     start = valuePop(ctxt);
 9143:     in = start->floatval;
 9144:     xmlXPathReleaseObject(ctxt->context, start);
 9145:     CAST_TO_STRING;
 9146:     CHECK_TYPE(XPATH_STRING);
 9147:     str = valuePop(ctxt);
 9148:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
 9149: 
 9150:     /*
 9151:      * If last pos not present, calculate last position
 9152:     */
 9153:     if (nargs != 3) {
 9154: 	le = (double)m;
 9155: 	if (in < 1.0)
 9156: 	    in = 1.0;
 9157:     }
 9158: 
 9159:     /* Need to check for the special cases where either
 9160:      * the index is NaN, the length is NaN, or both
 9161:      * arguments are infinity (relying on Inf + -Inf = NaN)
 9162:      */
 9163:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
 9164:         /*
 9165:          * To meet the requirements of the spec, the arguments
 9166: 	 * must be converted to integer format before
 9167: 	 * initial index calculations are done
 9168:          *
 9169:          * First we go to integer form, rounding up
 9170: 	 * and checking for special cases
 9171:          */
 9172:         i = (int) in;
 9173:         if (((double)i)+0.5 <= in) i++;
 9174: 
 9175: 	if (xmlXPathIsInf(le) == 1) {
 9176: 	    l = m;
 9177: 	    if (i < 1)
 9178: 		i = 1;
 9179: 	}
 9180: 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
 9181: 	    l = 0;
 9182: 	else {
 9183: 	    l = (int) le;
 9184: 	    if (((double)l)+0.5 <= le) l++;
 9185: 	}
 9186: 
 9187: 	/* Now we normalize inidices */
 9188:         i -= 1;
 9189:         l += i;
 9190:         if (i < 0)
 9191:             i = 0;
 9192:         if (l > m)
 9193:             l = m;
 9194: 
 9195:         /* number of chars to copy */
 9196:         l -= i;
 9197: 
 9198:         ret = xmlUTF8Strsub(str->stringval, i, l);
 9199:     }
 9200:     else {
 9201:         ret = NULL;
 9202:     }
 9203:     if (ret == NULL)
 9204: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 9205:     else {
 9206: 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
 9207: 	xmlFree(ret);
 9208:     }
 9209:     xmlXPathReleaseObject(ctxt->context, str);
 9210: }
 9211: 
 9212: /**
 9213:  * xmlXPathSubstringBeforeFunction:
 9214:  * @ctxt:  the XPath Parser context
 9215:  * @nargs:  the number of arguments
 9216:  *
 9217:  * Implement the substring-before() XPath function
 9218:  *    string substring-before(string, string)
 9219:  * The substring-before function returns the substring of the first
 9220:  * argument string that precedes the first occurrence of the second
 9221:  * argument string in the first argument string, or the empty string
 9222:  * if the first argument string does not contain the second argument
 9223:  * string. For example, substring-before("1999/04/01","/") returns 1999.
 9224:  */
 9225: void
 9226: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9227:   xmlXPathObjectPtr str;
 9228:   xmlXPathObjectPtr find;
 9229:   xmlBufPtr target;
 9230:   const xmlChar *point;
 9231:   int offset;
 9232: 
 9233:   CHECK_ARITY(2);
 9234:   CAST_TO_STRING;
 9235:   find = valuePop(ctxt);
 9236:   CAST_TO_STRING;
 9237:   str = valuePop(ctxt);
 9238: 
 9239:   target = xmlBufCreate();
 9240:   if (target) {
 9241:     point = xmlStrstr(str->stringval, find->stringval);
 9242:     if (point) {
 9243:       offset = (int)(point - str->stringval);
 9244:       xmlBufAdd(target, str->stringval, offset);
 9245:     }
 9246:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9247: 	xmlBufContent(target)));
 9248:     xmlBufFree(target);
 9249:   }
 9250:   xmlXPathReleaseObject(ctxt->context, str);
 9251:   xmlXPathReleaseObject(ctxt->context, find);
 9252: }
 9253: 
 9254: /**
 9255:  * xmlXPathSubstringAfterFunction:
 9256:  * @ctxt:  the XPath Parser context
 9257:  * @nargs:  the number of arguments
 9258:  *
 9259:  * Implement the substring-after() XPath function
 9260:  *    string substring-after(string, string)
 9261:  * The substring-after function returns the substring of the first
 9262:  * argument string that follows the first occurrence of the second
 9263:  * argument string in the first argument string, or the empty stringi
 9264:  * if the first argument string does not contain the second argument
 9265:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
 9266:  * and substring-after("1999/04/01","19") returns 99/04/01.
 9267:  */
 9268: void
 9269: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9270:   xmlXPathObjectPtr str;
 9271:   xmlXPathObjectPtr find;
 9272:   xmlBufPtr target;
 9273:   const xmlChar *point;
 9274:   int offset;
 9275: 
 9276:   CHECK_ARITY(2);
 9277:   CAST_TO_STRING;
 9278:   find = valuePop(ctxt);
 9279:   CAST_TO_STRING;
 9280:   str = valuePop(ctxt);
 9281: 
 9282:   target = xmlBufCreate();
 9283:   if (target) {
 9284:     point = xmlStrstr(str->stringval, find->stringval);
 9285:     if (point) {
 9286:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
 9287:       xmlBufAdd(target, &str->stringval[offset],
 9288: 		   xmlStrlen(str->stringval) - offset);
 9289:     }
 9290:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9291: 	xmlBufContent(target)));
 9292:     xmlBufFree(target);
 9293:   }
 9294:   xmlXPathReleaseObject(ctxt->context, str);
 9295:   xmlXPathReleaseObject(ctxt->context, find);
 9296: }
 9297: 
 9298: /**
 9299:  * xmlXPathNormalizeFunction:
 9300:  * @ctxt:  the XPath Parser context
 9301:  * @nargs:  the number of arguments
 9302:  *
 9303:  * Implement the normalize-space() XPath function
 9304:  *    string normalize-space(string?)
 9305:  * The normalize-space function returns the argument string with white
 9306:  * space normalized by stripping leading and trailing whitespace
 9307:  * and replacing sequences of whitespace characters by a single
 9308:  * space. Whitespace characters are the same allowed by the S production
 9309:  * in XML. If the argument is omitted, it defaults to the context
 9310:  * node converted to a string, in other words the value of the context node.
 9311:  */
 9312: void
 9313: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9314:   xmlXPathObjectPtr obj = NULL;
 9315:   xmlChar *source = NULL;
 9316:   xmlBufPtr target;
 9317:   xmlChar blank;
 9318: 
 9319:   if (ctxt == NULL) return;
 9320:   if (nargs == 0) {
 9321:     /* Use current context node */
 9322:       valuePush(ctxt,
 9323: 	  xmlXPathCacheWrapString(ctxt->context,
 9324: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 9325:     nargs = 1;
 9326:   }
 9327: 
 9328:   CHECK_ARITY(1);
 9329:   CAST_TO_STRING;
 9330:   CHECK_TYPE(XPATH_STRING);
 9331:   obj = valuePop(ctxt);
 9332:   source = obj->stringval;
 9333: 
 9334:   target = xmlBufCreate();
 9335:   if (target && source) {
 9336: 
 9337:     /* Skip leading whitespaces */
 9338:     while (IS_BLANK_CH(*source))
 9339:       source++;
 9340: 
 9341:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
 9342:     blank = 0;
 9343:     while (*source) {
 9344:       if (IS_BLANK_CH(*source)) {
 9345: 	blank = 0x20;
 9346:       } else {
 9347: 	if (blank) {
 9348: 	  xmlBufAdd(target, &blank, 1);
 9349: 	  blank = 0;
 9350: 	}
 9351: 	xmlBufAdd(target, source, 1);
 9352:       }
 9353:       source++;
 9354:     }
 9355:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9356: 	xmlBufContent(target)));
 9357:     xmlBufFree(target);
 9358:   }
 9359:   xmlXPathReleaseObject(ctxt->context, obj);
 9360: }
 9361: 
 9362: /**
 9363:  * xmlXPathTranslateFunction:
 9364:  * @ctxt:  the XPath Parser context
 9365:  * @nargs:  the number of arguments
 9366:  *
 9367:  * Implement the translate() XPath function
 9368:  *    string translate(string, string, string)
 9369:  * The translate function returns the first argument string with
 9370:  * occurrences of characters in the second argument string replaced
 9371:  * by the character at the corresponding position in the third argument
 9372:  * string. For example, translate("bar","abc","ABC") returns the string
 9373:  * BAr. If there is a character in the second argument string with no
 9374:  * character at a corresponding position in the third argument string
 9375:  * (because the second argument string is longer than the third argument
 9376:  * string), then occurrences of that character in the first argument
 9377:  * string are removed. For example, translate("--aaa--","abc-","ABC")
 9378:  * returns "AAA". If a character occurs more than once in second
 9379:  * argument string, then the first occurrence determines the replacement
 9380:  * character. If the third argument string is longer than the second
 9381:  * argument string, then excess characters are ignored.
 9382:  */
 9383: void
 9384: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9385:     xmlXPathObjectPtr str;
 9386:     xmlXPathObjectPtr from;
 9387:     xmlXPathObjectPtr to;
 9388:     xmlBufPtr target;
 9389:     int offset, max;
 9390:     xmlChar ch;
 9391:     const xmlChar *point;
 9392:     xmlChar *cptr;
 9393: 
 9394:     CHECK_ARITY(3);
 9395: 
 9396:     CAST_TO_STRING;
 9397:     to = valuePop(ctxt);
 9398:     CAST_TO_STRING;
 9399:     from = valuePop(ctxt);
 9400:     CAST_TO_STRING;
 9401:     str = valuePop(ctxt);
 9402: 
 9403:     target = xmlBufCreate();
 9404:     if (target) {
 9405: 	max = xmlUTF8Strlen(to->stringval);
 9406: 	for (cptr = str->stringval; (ch=*cptr); ) {
 9407: 	    offset = xmlUTF8Strloc(from->stringval, cptr);
 9408: 	    if (offset >= 0) {
 9409: 		if (offset < max) {
 9410: 		    point = xmlUTF8Strpos(to->stringval, offset);
 9411: 		    if (point)
 9412: 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
 9413: 		}
 9414: 	    } else
 9415: 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
 9416: 
 9417: 	    /* Step to next character in input */
 9418: 	    cptr++;
 9419: 	    if ( ch & 0x80 ) {
 9420: 		/* if not simple ascii, verify proper format */
 9421: 		if ( (ch & 0xc0) != 0xc0 ) {
 9422: 		    xmlGenericError(xmlGenericErrorContext,
 9423: 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9424:                     /* not asserting an XPath error is probably better */
 9425: 		    break;
 9426: 		}
 9427: 		/* then skip over remaining bytes for this char */
 9428: 		while ( (ch <<= 1) & 0x80 )
 9429: 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
 9430: 			xmlGenericError(xmlGenericErrorContext,
 9431: 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9432:                         /* not asserting an XPath error is probably better */
 9433: 			break;
 9434: 		    }
 9435: 		if (ch & 0x80) /* must have had error encountered */
 9436: 		    break;
 9437: 	    }
 9438: 	}
 9439:     }
 9440:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9441: 	xmlBufContent(target)));
 9442:     xmlBufFree(target);
 9443:     xmlXPathReleaseObject(ctxt->context, str);
 9444:     xmlXPathReleaseObject(ctxt->context, from);
 9445:     xmlXPathReleaseObject(ctxt->context, to);
 9446: }
 9447: 
 9448: /**
 9449:  * xmlXPathBooleanFunction:
 9450:  * @ctxt:  the XPath Parser context
 9451:  * @nargs:  the number of arguments
 9452:  *
 9453:  * Implement the boolean() XPath function
 9454:  *    boolean boolean(object)
 9455:  * The boolean function converts its argument to a boolean as follows:
 9456:  *    - a number is true if and only if it is neither positive or
 9457:  *      negative zero nor NaN
 9458:  *    - a node-set is true if and only if it is non-empty
 9459:  *    - a string is true if and only if its length is non-zero
 9460:  */
 9461: void
 9462: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9463:     xmlXPathObjectPtr cur;
 9464: 
 9465:     CHECK_ARITY(1);
 9466:     cur = valuePop(ctxt);
 9467:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 9468:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
 9469:     valuePush(ctxt, cur);
 9470: }
 9471: 
 9472: /**
 9473:  * xmlXPathNotFunction:
 9474:  * @ctxt:  the XPath Parser context
 9475:  * @nargs:  the number of arguments
 9476:  *
 9477:  * Implement the not() XPath function
 9478:  *    boolean not(boolean)
 9479:  * The not function returns true if its argument is false,
 9480:  * and false otherwise.
 9481:  */
 9482: void
 9483: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9484:     CHECK_ARITY(1);
 9485:     CAST_TO_BOOLEAN;
 9486:     CHECK_TYPE(XPATH_BOOLEAN);
 9487:     ctxt->value->boolval = ! ctxt->value->boolval;
 9488: }
 9489: 
 9490: /**
 9491:  * xmlXPathTrueFunction:
 9492:  * @ctxt:  the XPath Parser context
 9493:  * @nargs:  the number of arguments
 9494:  *
 9495:  * Implement the true() XPath function
 9496:  *    boolean true()
 9497:  */
 9498: void
 9499: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9500:     CHECK_ARITY(0);
 9501:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9502: }
 9503: 
 9504: /**
 9505:  * xmlXPathFalseFunction:
 9506:  * @ctxt:  the XPath Parser context
 9507:  * @nargs:  the number of arguments
 9508:  *
 9509:  * Implement the false() XPath function
 9510:  *    boolean false()
 9511:  */
 9512: void
 9513: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9514:     CHECK_ARITY(0);
 9515:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9516: }
 9517: 
 9518: /**
 9519:  * xmlXPathLangFunction:
 9520:  * @ctxt:  the XPath Parser context
 9521:  * @nargs:  the number of arguments
 9522:  *
 9523:  * Implement the lang() XPath function
 9524:  *    boolean lang(string)
 9525:  * The lang function returns true or false depending on whether the
 9526:  * language of the context node as specified by xml:lang attributes
 9527:  * is the same as or is a sublanguage of the language specified by
 9528:  * the argument string. The language of the context node is determined
 9529:  * by the value of the xml:lang attribute on the context node, or, if
 9530:  * the context node has no xml:lang attribute, by the value of the
 9531:  * xml:lang attribute on the nearest ancestor of the context node that
 9532:  * has an xml:lang attribute. If there is no such attribute, then lang
 9533:  * returns false. If there is such an attribute, then lang returns
 9534:  * true if the attribute value is equal to the argument ignoring case,
 9535:  * or if there is some suffix starting with - such that the attribute
 9536:  * value is equal to the argument ignoring that suffix of the attribute
 9537:  * value and ignoring case.
 9538:  */
 9539: void
 9540: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9541:     xmlXPathObjectPtr val = NULL;
 9542:     const xmlChar *theLang = NULL;
 9543:     const xmlChar *lang;
 9544:     int ret = 0;
 9545:     int i;
 9546: 
 9547:     CHECK_ARITY(1);
 9548:     CAST_TO_STRING;
 9549:     CHECK_TYPE(XPATH_STRING);
 9550:     val = valuePop(ctxt);
 9551:     lang = val->stringval;
 9552:     theLang = xmlNodeGetLang(ctxt->context->node);
 9553:     if ((theLang != NULL) && (lang != NULL)) {
 9554:         for (i = 0;lang[i] != 0;i++)
 9555: 	    if (toupper(lang[i]) != toupper(theLang[i]))
 9556: 	        goto not_equal;
 9557: 	if ((theLang[i] == 0) || (theLang[i] == '-'))
 9558: 	    ret = 1;
 9559:     }
 9560: not_equal:
 9561:     if (theLang != NULL)
 9562: 	xmlFree((void *)theLang);
 9563: 
 9564:     xmlXPathReleaseObject(ctxt->context, val);
 9565:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
 9566: }
 9567: 
 9568: /**
 9569:  * xmlXPathNumberFunction:
 9570:  * @ctxt:  the XPath Parser context
 9571:  * @nargs:  the number of arguments
 9572:  *
 9573:  * Implement the number() XPath function
 9574:  *    number number(object?)
 9575:  */
 9576: void
 9577: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9578:     xmlXPathObjectPtr cur;
 9579:     double res;
 9580: 
 9581:     if (ctxt == NULL) return;
 9582:     if (nargs == 0) {
 9583: 	if (ctxt->context->node == NULL) {
 9584: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
 9585: 	} else {
 9586: 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
 9587: 
 9588: 	    res = xmlXPathStringEvalNumber(content);
 9589: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9590: 	    xmlFree(content);
 9591: 	}
 9592: 	return;
 9593:     }
 9594: 
 9595:     CHECK_ARITY(1);
 9596:     cur = valuePop(ctxt);
 9597:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
 9598: }
 9599: 
 9600: /**
 9601:  * xmlXPathSumFunction:
 9602:  * @ctxt:  the XPath Parser context
 9603:  * @nargs:  the number of arguments
 9604:  *
 9605:  * Implement the sum() XPath function
 9606:  *    number sum(node-set)
 9607:  * The sum function returns the sum of the values of the nodes in
 9608:  * the argument node-set.
 9609:  */
 9610: void
 9611: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9612:     xmlXPathObjectPtr cur;
 9613:     int i;
 9614:     double res = 0.0;
 9615: 
 9616:     CHECK_ARITY(1);
 9617:     if ((ctxt->value == NULL) ||
 9618: 	((ctxt->value->type != XPATH_NODESET) &&
 9619: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 9620: 	XP_ERROR(XPATH_INVALID_TYPE);
 9621:     cur = valuePop(ctxt);
 9622: 
 9623:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
 9624: 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
 9625: 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
 9626: 	}
 9627:     }
 9628:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9629:     xmlXPathReleaseObject(ctxt->context, cur);
 9630: }
 9631: 
 9632: /*
 9633:  * To assure working code on multiple platforms, we want to only depend
 9634:  * upon the characteristic truncation of converting a floating point value
 9635:  * to an integer.  Unfortunately, because of the different storage sizes
 9636:  * of our internal floating point value (double) and integer (int), we
 9637:  * can't directly convert (see bug 301162).  This macro is a messy
 9638:  * 'workaround'
 9639:  */
 9640: #define XTRUNC(f, v)            \
 9641:     f = fmod((v), INT_MAX);     \
 9642:     f = (v) - (f) + (double)((int)(f));
 9643: 
 9644: /**
 9645:  * xmlXPathFloorFunction:
 9646:  * @ctxt:  the XPath Parser context
 9647:  * @nargs:  the number of arguments
 9648:  *
 9649:  * Implement the floor() XPath function
 9650:  *    number floor(number)
 9651:  * The floor function returns the largest (closest to positive infinity)
 9652:  * number that is not greater than the argument and that is an integer.
 9653:  */
 9654: void
 9655: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9656:     double f;
 9657: 
 9658:     CHECK_ARITY(1);
 9659:     CAST_TO_NUMBER;
 9660:     CHECK_TYPE(XPATH_NUMBER);
 9661: 
 9662:     XTRUNC(f, ctxt->value->floatval);
 9663:     if (f != ctxt->value->floatval) {
 9664: 	if (ctxt->value->floatval > 0)
 9665: 	    ctxt->value->floatval = f;
 9666: 	else
 9667: 	    ctxt->value->floatval = f - 1;
 9668:     }
 9669: }
 9670: 
 9671: /**
 9672:  * xmlXPathCeilingFunction:
 9673:  * @ctxt:  the XPath Parser context
 9674:  * @nargs:  the number of arguments
 9675:  *
 9676:  * Implement the ceiling() XPath function
 9677:  *    number ceiling(number)
 9678:  * The ceiling function returns the smallest (closest to negative infinity)
 9679:  * number that is not less than the argument and that is an integer.
 9680:  */
 9681: void
 9682: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9683:     double f;
 9684: 
 9685:     CHECK_ARITY(1);
 9686:     CAST_TO_NUMBER;
 9687:     CHECK_TYPE(XPATH_NUMBER);
 9688: 
 9689: #if 0
 9690:     ctxt->value->floatval = ceil(ctxt->value->floatval);
 9691: #else
 9692:     XTRUNC(f, ctxt->value->floatval);
 9693:     if (f != ctxt->value->floatval) {
 9694: 	if (ctxt->value->floatval > 0)
 9695: 	    ctxt->value->floatval = f + 1;
 9696: 	else {
 9697: 	    if (ctxt->value->floatval < 0 && f == 0)
 9698: 	        ctxt->value->floatval = xmlXPathNZERO;
 9699: 	    else
 9700: 	        ctxt->value->floatval = f;
 9701: 	}
 9702: 
 9703:     }
 9704: #endif
 9705: }
 9706: 
 9707: /**
 9708:  * xmlXPathRoundFunction:
 9709:  * @ctxt:  the XPath Parser context
 9710:  * @nargs:  the number of arguments
 9711:  *
 9712:  * Implement the round() XPath function
 9713:  *    number round(number)
 9714:  * The round function returns the number that is closest to the
 9715:  * argument and that is an integer. If there are two such numbers,
 9716:  * then the one that is even is returned.
 9717:  */
 9718: void
 9719: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9720:     double f;
 9721: 
 9722:     CHECK_ARITY(1);
 9723:     CAST_TO_NUMBER;
 9724:     CHECK_TYPE(XPATH_NUMBER);
 9725: 
 9726:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
 9727: 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
 9728: 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
 9729: 	(ctxt->value->floatval == 0.0))
 9730: 	return;
 9731: 
 9732:     XTRUNC(f, ctxt->value->floatval);
 9733:     if (ctxt->value->floatval < 0) {
 9734: 	if (ctxt->value->floatval < f - 0.5)
 9735: 	    ctxt->value->floatval = f - 1;
 9736: 	else
 9737: 	    ctxt->value->floatval = f;
 9738: 	if (ctxt->value->floatval == 0)
 9739: 	    ctxt->value->floatval = xmlXPathNZERO;
 9740:     } else {
 9741: 	if (ctxt->value->floatval < f + 0.5)
 9742: 	    ctxt->value->floatval = f;
 9743: 	else
 9744: 	    ctxt->value->floatval = f + 1;
 9745:     }
 9746: }
 9747: 
 9748: /************************************************************************
 9749:  *									*
 9750:  *			The Parser					*
 9751:  *									*
 9752:  ************************************************************************/
 9753: 
 9754: /*
 9755:  * a few forward declarations since we use a recursive call based
 9756:  * implementation.
 9757:  */
 9758: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
 9759: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
 9760: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
 9761: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
 9762: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
 9763: 	                                  int qualified);
 9764: 
 9765: /**
 9766:  * xmlXPathCurrentChar:
 9767:  * @ctxt:  the XPath parser context
 9768:  * @cur:  pointer to the beginning of the char
 9769:  * @len:  pointer to the length of the char read
 9770:  *
 9771:  * The current char value, if using UTF-8 this may actually span multiple
 9772:  * bytes in the input buffer.
 9773:  *
 9774:  * Returns the current char value and its length
 9775:  */
 9776: 
 9777: static int
 9778: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
 9779:     unsigned char c;
 9780:     unsigned int val;
 9781:     const xmlChar *cur;
 9782: 
 9783:     if (ctxt == NULL)
 9784: 	return(0);
 9785:     cur = ctxt->cur;
 9786: 
 9787:     /*
 9788:      * We are supposed to handle UTF8, check it's valid
 9789:      * From rfc2044: encoding of the Unicode values on UTF-8:
 9790:      *
 9791:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
 9792:      * 0000 0000-0000 007F   0xxxxxxx
 9793:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
 9794:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
 9795:      *
 9796:      * Check for the 0x110000 limit too
 9797:      */
 9798:     c = *cur;
 9799:     if (c & 0x80) {
 9800: 	if ((cur[1] & 0xc0) != 0x80)
 9801: 	    goto encoding_error;
 9802: 	if ((c & 0xe0) == 0xe0) {
 9803: 
 9804: 	    if ((cur[2] & 0xc0) != 0x80)
 9805: 		goto encoding_error;
 9806: 	    if ((c & 0xf0) == 0xf0) {
 9807: 		if (((c & 0xf8) != 0xf0) ||
 9808: 		    ((cur[3] & 0xc0) != 0x80))
 9809: 		    goto encoding_error;
 9810: 		/* 4-byte code */
 9811: 		*len = 4;
 9812: 		val = (cur[0] & 0x7) << 18;
 9813: 		val |= (cur[1] & 0x3f) << 12;
 9814: 		val |= (cur[2] & 0x3f) << 6;
 9815: 		val |= cur[3] & 0x3f;
 9816: 	    } else {
 9817: 	      /* 3-byte code */
 9818: 		*len = 3;
 9819: 		val = (cur[0] & 0xf) << 12;
 9820: 		val |= (cur[1] & 0x3f) << 6;
 9821: 		val |= cur[2] & 0x3f;
 9822: 	    }
 9823: 	} else {
 9824: 	  /* 2-byte code */
 9825: 	    *len = 2;
 9826: 	    val = (cur[0] & 0x1f) << 6;
 9827: 	    val |= cur[1] & 0x3f;
 9828: 	}
 9829: 	if (!IS_CHAR(val)) {
 9830: 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
 9831: 	}
 9832: 	return(val);
 9833:     } else {
 9834: 	/* 1-byte code */
 9835: 	*len = 1;
 9836: 	return((int) *cur);
 9837:     }
 9838: encoding_error:
 9839:     /*
 9840:      * If we detect an UTF8 error that probably means that the
 9841:      * input encoding didn't get properly advertised in the
 9842:      * declaration header. Report the error and switch the encoding
 9843:      * to ISO-Latin-1 (if you don't like this policy, just declare the
 9844:      * encoding !)
 9845:      */
 9846:     *len = 0;
 9847:     XP_ERROR0(XPATH_ENCODING_ERROR);
 9848: }
 9849: 
 9850: /**
 9851:  * xmlXPathParseNCName:
 9852:  * @ctxt:  the XPath Parser context
 9853:  *
 9854:  * parse an XML namespace non qualified name.
 9855:  *
 9856:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
 9857:  *
 9858:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
 9859:  *                       CombiningChar | Extender
 9860:  *
 9861:  * Returns the namespace name or NULL
 9862:  */
 9863: 
 9864: xmlChar *
 9865: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
 9866:     const xmlChar *in;
 9867:     xmlChar *ret;
 9868:     int count = 0;
 9869: 
 9870:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9871:     /*
 9872:      * Accelerator for simple ASCII names
 9873:      */
 9874:     in = ctxt->cur;
 9875:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9876: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9877: 	(*in == '_')) {
 9878: 	in++;
 9879: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9880: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9881: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9882: 	       (*in == '_') || (*in == '.') ||
 9883: 	       (*in == '-'))
 9884: 	    in++;
 9885: 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
 9886:             (*in == '[') || (*in == ']') || (*in == ':') ||
 9887:             (*in == '@') || (*in == '*')) {
 9888: 	    count = in - ctxt->cur;
 9889: 	    if (count == 0)
 9890: 		return(NULL);
 9891: 	    ret = xmlStrndup(ctxt->cur, count);
 9892: 	    ctxt->cur = in;
 9893: 	    return(ret);
 9894: 	}
 9895:     }
 9896:     return(xmlXPathParseNameComplex(ctxt, 0));
 9897: }
 9898: 
 9899: 
 9900: /**
 9901:  * xmlXPathParseQName:
 9902:  * @ctxt:  the XPath Parser context
 9903:  * @prefix:  a xmlChar **
 9904:  *
 9905:  * parse an XML qualified name
 9906:  *
 9907:  * [NS 5] QName ::= (Prefix ':')? LocalPart
 9908:  *
 9909:  * [NS 6] Prefix ::= NCName
 9910:  *
 9911:  * [NS 7] LocalPart ::= NCName
 9912:  *
 9913:  * Returns the function returns the local part, and prefix is updated
 9914:  *   to get the Prefix if any.
 9915:  */
 9916: 
 9917: static xmlChar *
 9918: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
 9919:     xmlChar *ret = NULL;
 9920: 
 9921:     *prefix = NULL;
 9922:     ret = xmlXPathParseNCName(ctxt);
 9923:     if (ret && CUR == ':') {
 9924:         *prefix = ret;
 9925: 	NEXT;
 9926: 	ret = xmlXPathParseNCName(ctxt);
 9927:     }
 9928:     return(ret);
 9929: }
 9930: 
 9931: /**
 9932:  * xmlXPathParseName:
 9933:  * @ctxt:  the XPath Parser context
 9934:  *
 9935:  * parse an XML name
 9936:  *
 9937:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
 9938:  *                  CombiningChar | Extender
 9939:  *
 9940:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
 9941:  *
 9942:  * Returns the namespace name or NULL
 9943:  */
 9944: 
 9945: xmlChar *
 9946: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
 9947:     const xmlChar *in;
 9948:     xmlChar *ret;
 9949:     size_t count = 0;
 9950: 
 9951:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9952:     /*
 9953:      * Accelerator for simple ASCII names
 9954:      */
 9955:     in = ctxt->cur;
 9956:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9957: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9958: 	(*in == '_') || (*in == ':')) {
 9959: 	in++;
 9960: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9961: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9962: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9963: 	       (*in == '_') || (*in == '-') ||
 9964: 	       (*in == ':') || (*in == '.'))
 9965: 	    in++;
 9966: 	if ((*in > 0) && (*in < 0x80)) {
 9967: 	    count = in - ctxt->cur;
 9968:             if (count > XML_MAX_NAME_LENGTH) {
 9969:                 ctxt->cur = in;
 9970:                 XP_ERRORNULL(XPATH_EXPR_ERROR);
 9971:             }
 9972: 	    ret = xmlStrndup(ctxt->cur, count);
 9973: 	    ctxt->cur = in;
 9974: 	    return(ret);
 9975: 	}
 9976:     }
 9977:     return(xmlXPathParseNameComplex(ctxt, 1));
 9978: }
 9979: 
 9980: static xmlChar *
 9981: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
 9982:     xmlChar buf[XML_MAX_NAMELEN + 5];
 9983:     int len = 0, l;
 9984:     int c;
 9985: 
 9986:     /*
 9987:      * Handler for more complex cases
 9988:      */
 9989:     c = CUR_CHAR(l);
 9990:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
 9991:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
 9992:         (c == '*') || /* accelerators */
 9993: 	(!IS_LETTER(c) && (c != '_') &&
 9994:          ((qualified) && (c != ':')))) {
 9995: 	return(NULL);
 9996:     }
 9997: 
 9998:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
 9999: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10000:             (c == '.') || (c == '-') ||
10001: 	    (c == '_') || ((qualified) && (c == ':')) ||
10002: 	    (IS_COMBINING(c)) ||
10003: 	    (IS_EXTENDER(c)))) {
10004: 	COPY_BUF(l,buf,len,c);
10005: 	NEXTL(l);
10006: 	c = CUR_CHAR(l);
10007: 	if (len >= XML_MAX_NAMELEN) {
10008: 	    /*
10009: 	     * Okay someone managed to make a huge name, so he's ready to pay
10010: 	     * for the processing speed.
10011: 	     */
10012: 	    xmlChar *buffer;
10013: 	    int max = len * 2;
10014: 
10015:             if (len > XML_MAX_NAME_LENGTH) {
10016:                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10017:             }
10018: 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10019: 	    if (buffer == NULL) {
10020: 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10021: 	    }
10022: 	    memcpy(buffer, buf, len);
10023: 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10024: 		   (c == '.') || (c == '-') ||
10025: 		   (c == '_') || ((qualified) && (c == ':')) ||
10026: 		   (IS_COMBINING(c)) ||
10027: 		   (IS_EXTENDER(c))) {
10028: 		if (len + 10 > max) {
10029:                     if (max > XML_MAX_NAME_LENGTH) {
10030:                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10031:                     }
10032: 		    max *= 2;
10033: 		    buffer = (xmlChar *) xmlRealloc(buffer,
10034: 			                            max * sizeof(xmlChar));
10035: 		    if (buffer == NULL) {
10036: 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037: 		    }
10038: 		}
10039: 		COPY_BUF(l,buffer,len,c);
10040: 		NEXTL(l);
10041: 		c = CUR_CHAR(l);
10042: 	    }
10043: 	    buffer[len] = 0;
10044: 	    return(buffer);
10045: 	}
10046:     }
10047:     if (len == 0)
10048: 	return(NULL);
10049:     return(xmlStrndup(buf, len));
10050: }
10051: 
10052: #define MAX_FRAC 20
10053: 
10054: /*
10055:  * These are used as divisors for the fractional part of a number.
10056:  * Since the table includes 1.0 (representing '0' fractional digits),
10057:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10058:  */
10059: static double my_pow10[MAX_FRAC+1] = {
10060:     1.0, 10.0, 100.0, 1000.0, 10000.0,
10061:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10062:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10063:     100000000000000.0,
10064:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10065:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10066: };
10067: 
10068: /**
10069:  * xmlXPathStringEvalNumber:
10070:  * @str:  A string to scan
10071:  *
10072:  *  [30a]  Float  ::= Number ('e' Digits?)?
10073:  *
10074:  *  [30]   Number ::=   Digits ('.' Digits?)?
10075:  *                    | '.' Digits
10076:  *  [31]   Digits ::=   [0-9]+
10077:  *
10078:  * Compile a Number in the string
10079:  * In complement of the Number expression, this function also handles
10080:  * negative values : '-' Number.
10081:  *
10082:  * Returns the double value.
10083:  */
10084: double
10085: xmlXPathStringEvalNumber(const xmlChar *str) {
10086:     const xmlChar *cur = str;
10087:     double ret;
10088:     int ok = 0;
10089:     int isneg = 0;
10090:     int exponent = 0;
10091:     int is_exponent_negative = 0;
10092: #ifdef __GNUC__
10093:     unsigned long tmp = 0;
10094:     double temp;
10095: #endif
10096:     if (cur == NULL) return(0);
10097:     while (IS_BLANK_CH(*cur)) cur++;
10098:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10099:         return(xmlXPathNAN);
10100:     }
10101:     if (*cur == '-') {
10102: 	isneg = 1;
10103: 	cur++;
10104:     }
10105: 
10106: #ifdef __GNUC__
10107:     /*
10108:      * tmp/temp is a workaround against a gcc compiler bug
10109:      * http://veillard.com/gcc.bug
10110:      */
10111:     ret = 0;
10112:     while ((*cur >= '0') && (*cur <= '9')) {
10113: 	ret = ret * 10;
10114: 	tmp = (*cur - '0');
10115: 	ok = 1;
10116: 	cur++;
10117: 	temp = (double) tmp;
10118: 	ret = ret + temp;
10119:     }
10120: #else
10121:     ret = 0;
10122:     while ((*cur >= '0') && (*cur <= '9')) {
10123: 	ret = ret * 10 + (*cur - '0');
10124: 	ok = 1;
10125: 	cur++;
10126:     }
10127: #endif
10128: 
10129:     if (*cur == '.') {
10130: 	int v, frac = 0;
10131: 	double fraction = 0;
10132: 
10133:         cur++;
10134: 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10135: 	    return(xmlXPathNAN);
10136: 	}
10137: 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10138: 	    v = (*cur - '0');
10139: 	    fraction = fraction * 10 + v;
10140: 	    frac = frac + 1;
10141: 	    cur++;
10142: 	}
10143: 	fraction /= my_pow10[frac];
10144: 	ret = ret + fraction;
10145: 	while ((*cur >= '0') && (*cur <= '9'))
10146: 	    cur++;
10147:     }
10148:     if ((*cur == 'e') || (*cur == 'E')) {
10149:       cur++;
10150:       if (*cur == '-') {
10151: 	is_exponent_negative = 1;
10152: 	cur++;
10153:       } else if (*cur == '+') {
10154:         cur++;
10155:       }
10156:       while ((*cur >= '0') && (*cur <= '9')) {
10157: 	exponent = exponent * 10 + (*cur - '0');
10158: 	cur++;
10159:       }
10160:     }
10161:     while (IS_BLANK_CH(*cur)) cur++;
10162:     if (*cur != 0) return(xmlXPathNAN);
10163:     if (isneg) ret = -ret;
10164:     if (is_exponent_negative) exponent = -exponent;
10165:     ret *= pow(10.0, (double)exponent);
10166:     return(ret);
10167: }
10168: 
10169: /**
10170:  * xmlXPathCompNumber:
10171:  * @ctxt:  the XPath Parser context
10172:  *
10173:  *  [30]   Number ::=   Digits ('.' Digits?)?
10174:  *                    | '.' Digits
10175:  *  [31]   Digits ::=   [0-9]+
10176:  *
10177:  * Compile a Number, then push it on the stack
10178:  *
10179:  */
10180: static void
10181: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10182: {
10183:     double ret = 0.0;
10184:     int ok = 0;
10185:     int exponent = 0;
10186:     int is_exponent_negative = 0;
10187: #ifdef __GNUC__
10188:     unsigned long tmp = 0;
10189:     double temp;
10190: #endif
10191: 
10192:     CHECK_ERROR;
10193:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10194:         XP_ERROR(XPATH_NUMBER_ERROR);
10195:     }
10196: #ifdef __GNUC__
10197:     /*
10198:      * tmp/temp is a workaround against a gcc compiler bug
10199:      * http://veillard.com/gcc.bug
10200:      */
10201:     ret = 0;
10202:     while ((CUR >= '0') && (CUR <= '9')) {
10203: 	ret = ret * 10;
10204: 	tmp = (CUR - '0');
10205:         ok = 1;
10206:         NEXT;
10207: 	temp = (double) tmp;
10208: 	ret = ret + temp;
10209:     }
10210: #else
10211:     ret = 0;
10212:     while ((CUR >= '0') && (CUR <= '9')) {
10213: 	ret = ret * 10 + (CUR - '0');
10214: 	ok = 1;
10215: 	NEXT;
10216:     }
10217: #endif
10218:     if (CUR == '.') {
10219: 	int v, frac = 0;
10220: 	double fraction = 0;
10221: 
10222:         NEXT;
10223:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10224:             XP_ERROR(XPATH_NUMBER_ERROR);
10225:         }
10226:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10227: 	    v = (CUR - '0');
10228: 	    fraction = fraction * 10 + v;
10229: 	    frac = frac + 1;
10230:             NEXT;
10231:         }
10232:         fraction /= my_pow10[frac];
10233:         ret = ret + fraction;
10234:         while ((CUR >= '0') && (CUR <= '9'))
10235:             NEXT;
10236:     }
10237:     if ((CUR == 'e') || (CUR == 'E')) {
10238:         NEXT;
10239:         if (CUR == '-') {
10240:             is_exponent_negative = 1;
10241:             NEXT;
10242:         } else if (CUR == '+') {
10243: 	    NEXT;
10244: 	}
10245:         while ((CUR >= '0') && (CUR <= '9')) {
10246:             exponent = exponent * 10 + (CUR - '0');
10247:             NEXT;
10248:         }
10249:         if (is_exponent_negative)
10250:             exponent = -exponent;
10251:         ret *= pow(10.0, (double) exponent);
10252:     }
10253:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10254:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10255: }
10256: 
10257: /**
10258:  * xmlXPathParseLiteral:
10259:  * @ctxt:  the XPath Parser context
10260:  *
10261:  * Parse a Literal
10262:  *
10263:  *  [29]   Literal ::=   '"' [^"]* '"'
10264:  *                    | "'" [^']* "'"
10265:  *
10266:  * Returns the value found or NULL in case of error
10267:  */
10268: static xmlChar *
10269: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10270:     const xmlChar *q;
10271:     xmlChar *ret = NULL;
10272: 
10273:     if (CUR == '"') {
10274:         NEXT;
10275: 	q = CUR_PTR;
10276: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10277: 	    NEXT;
10278: 	if (!IS_CHAR_CH(CUR)) {
10279: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10280: 	} else {
10281: 	    ret = xmlStrndup(q, CUR_PTR - q);
10282: 	    NEXT;
10283:         }
10284:     } else if (CUR == '\'') {
10285:         NEXT;
10286: 	q = CUR_PTR;
10287: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10288: 	    NEXT;
10289: 	if (!IS_CHAR_CH(CUR)) {
10290: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10291: 	} else {
10292: 	    ret = xmlStrndup(q, CUR_PTR - q);
10293: 	    NEXT;
10294:         }
10295:     } else {
10296: 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10297:     }
10298:     return(ret);
10299: }
10300: 
10301: /**
10302:  * xmlXPathCompLiteral:
10303:  * @ctxt:  the XPath Parser context
10304:  *
10305:  * Parse a Literal and push it on the stack.
10306:  *
10307:  *  [29]   Literal ::=   '"' [^"]* '"'
10308:  *                    | "'" [^']* "'"
10309:  *
10310:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10311:  */
10312: static void
10313: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10314:     const xmlChar *q;
10315:     xmlChar *ret = NULL;
10316: 
10317:     if (CUR == '"') {
10318:         NEXT;
10319: 	q = CUR_PTR;
10320: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10321: 	    NEXT;
10322: 	if (!IS_CHAR_CH(CUR)) {
10323: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10324: 	} else {
10325: 	    ret = xmlStrndup(q, CUR_PTR - q);
10326: 	    NEXT;
10327:         }
10328:     } else if (CUR == '\'') {
10329:         NEXT;
10330: 	q = CUR_PTR;
10331: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10332: 	    NEXT;
10333: 	if (!IS_CHAR_CH(CUR)) {
10334: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10335: 	} else {
10336: 	    ret = xmlStrndup(q, CUR_PTR - q);
10337: 	    NEXT;
10338:         }
10339:     } else {
10340: 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10341:     }
10342:     if (ret == NULL) return;
10343:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10344: 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10345:     xmlFree(ret);
10346: }
10347: 
10348: /**
10349:  * xmlXPathCompVariableReference:
10350:  * @ctxt:  the XPath Parser context
10351:  *
10352:  * Parse a VariableReference, evaluate it and push it on the stack.
10353:  *
10354:  * The variable bindings consist of a mapping from variable names
10355:  * to variable values. The value of a variable is an object, which can be
10356:  * of any of the types that are possible for the value of an expression,
10357:  * and may also be of additional types not specified here.
10358:  *
10359:  * Early evaluation is possible since:
10360:  * The variable bindings [...] used to evaluate a subexpression are
10361:  * always the same as those used to evaluate the containing expression.
10362:  *
10363:  *  [36]   VariableReference ::=   '$' QName
10364:  */
10365: static void
10366: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10367:     xmlChar *name;
10368:     xmlChar *prefix;
10369: 
10370:     SKIP_BLANKS;
10371:     if (CUR != '$') {
10372: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10373:     }
10374:     NEXT;
10375:     name = xmlXPathParseQName(ctxt, &prefix);
10376:     if (name == NULL) {
10377: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378:     }
10379:     ctxt->comp->last = -1;
10380:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381: 	           name, prefix);
10382:     SKIP_BLANKS;
10383:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384: 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385:     }
10386: }
10387: 
10388: /**
10389:  * xmlXPathIsNodeType:
10390:  * @name:  a name string
10391:  *
10392:  * Is the name given a NodeType one.
10393:  *
10394:  *  [38]   NodeType ::=   'comment'
10395:  *                    | 'text'
10396:  *                    | 'processing-instruction'
10397:  *                    | 'node'
10398:  *
10399:  * Returns 1 if true 0 otherwise
10400:  */
10401: int
10402: xmlXPathIsNodeType(const xmlChar *name) {
10403:     if (name == NULL)
10404: 	return(0);
10405: 
10406:     if (xmlStrEqual(name, BAD_CAST "node"))
10407: 	return(1);
10408:     if (xmlStrEqual(name, BAD_CAST "text"))
10409: 	return(1);
10410:     if (xmlStrEqual(name, BAD_CAST "comment"))
10411: 	return(1);
10412:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413: 	return(1);
10414:     return(0);
10415: }
10416: 
10417: /**
10418:  * xmlXPathCompFunctionCall:
10419:  * @ctxt:  the XPath Parser context
10420:  *
10421:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422:  *  [17]   Argument ::=   Expr
10423:  *
10424:  * Compile a function call, the evaluation of all arguments are
10425:  * pushed on the stack
10426:  */
10427: static void
10428: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429:     xmlChar *name;
10430:     xmlChar *prefix;
10431:     int nbargs = 0;
10432:     int sort = 1;
10433: 
10434:     name = xmlXPathParseQName(ctxt, &prefix);
10435:     if (name == NULL) {
10436: 	xmlFree(prefix);
10437: 	XP_ERROR(XPATH_EXPR_ERROR);
10438:     }
10439:     SKIP_BLANKS;
10440: #ifdef DEBUG_EXPR
10441:     if (prefix == NULL)
10442: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443: 			name);
10444:     else
10445: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446: 			prefix, name);
10447: #endif
10448: 
10449:     if (CUR != '(') {
10450: 	XP_ERROR(XPATH_EXPR_ERROR);
10451:     }
10452:     NEXT;
10453:     SKIP_BLANKS;
10454: 
10455:     /*
10456:     * Optimization for count(): we don't need the node-set to be sorted.
10457:     */
10458:     if ((prefix == NULL) && (name[0] == 'c') &&
10459: 	xmlStrEqual(name, BAD_CAST "count"))
10460:     {
10461: 	sort = 0;
10462:     }
10463:     ctxt->comp->last = -1;
10464:     if (CUR != ')') {
10465: 	while (CUR != 0) {
10466: 	    int op1 = ctxt->comp->last;
10467: 	    ctxt->comp->last = -1;
10468: 	    xmlXPathCompileExpr(ctxt, sort);
10469: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10470: 		xmlFree(name);
10471: 		xmlFree(prefix);
10472: 		return;
10473: 	    }
10474: 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10475: 	    nbargs++;
10476: 	    if (CUR == ')') break;
10477: 	    if (CUR != ',') {
10478: 		XP_ERROR(XPATH_EXPR_ERROR);
10479: 	    }
10480: 	    NEXT;
10481: 	    SKIP_BLANKS;
10482: 	}
10483:     }
10484:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10485: 	           name, prefix);
10486:     NEXT;
10487:     SKIP_BLANKS;
10488: }
10489: 
10490: /**
10491:  * xmlXPathCompPrimaryExpr:
10492:  * @ctxt:  the XPath Parser context
10493:  *
10494:  *  [15]   PrimaryExpr ::=   VariableReference
10495:  *                | '(' Expr ')'
10496:  *                | Literal
10497:  *                | Number
10498:  *                | FunctionCall
10499:  *
10500:  * Compile a primary expression.
10501:  */
10502: static void
10503: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10504:     SKIP_BLANKS;
10505:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10506:     else if (CUR == '(') {
10507: 	NEXT;
10508: 	SKIP_BLANKS;
10509: 	xmlXPathCompileExpr(ctxt, 1);
10510: 	CHECK_ERROR;
10511: 	if (CUR != ')') {
10512: 	    XP_ERROR(XPATH_EXPR_ERROR);
10513: 	}
10514: 	NEXT;
10515: 	SKIP_BLANKS;
10516:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10517: 	xmlXPathCompNumber(ctxt);
10518:     } else if ((CUR == '\'') || (CUR == '"')) {
10519: 	xmlXPathCompLiteral(ctxt);
10520:     } else {
10521: 	xmlXPathCompFunctionCall(ctxt);
10522:     }
10523:     SKIP_BLANKS;
10524: }
10525: 
10526: /**
10527:  * xmlXPathCompFilterExpr:
10528:  * @ctxt:  the XPath Parser context
10529:  *
10530:  *  [20]   FilterExpr ::=   PrimaryExpr
10531:  *               | FilterExpr Predicate
10532:  *
10533:  * Compile a filter expression.
10534:  * Square brackets are used to filter expressions in the same way that
10535:  * they are used in location paths. It is an error if the expression to
10536:  * be filtered does not evaluate to a node-set. The context node list
10537:  * used for evaluating the expression in square brackets is the node-set
10538:  * to be filtered listed in document order.
10539:  */
10540: 
10541: static void
10542: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10543:     xmlXPathCompPrimaryExpr(ctxt);
10544:     CHECK_ERROR;
10545:     SKIP_BLANKS;
10546: 
10547:     while (CUR == '[') {
10548: 	xmlXPathCompPredicate(ctxt, 1);
10549: 	SKIP_BLANKS;
10550:     }
10551: 
10552: 
10553: }
10554: 
10555: /**
10556:  * xmlXPathScanName:
10557:  * @ctxt:  the XPath Parser context
10558:  *
10559:  * Trickery: parse an XML name but without consuming the input flow
10560:  * Needed to avoid insanity in the parser state.
10561:  *
10562:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10563:  *                  CombiningChar | Extender
10564:  *
10565:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10566:  *
10567:  * [6] Names ::= Name (S Name)*
10568:  *
10569:  * Returns the Name parsed or NULL
10570:  */
10571: 
10572: static xmlChar *
10573: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10574:     int len = 0, l;
10575:     int c;
10576:     const xmlChar *cur;
10577:     xmlChar *ret;
10578: 
10579:     cur = ctxt->cur;
10580: 
10581:     c = CUR_CHAR(l);
10582:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10583: 	(!IS_LETTER(c) && (c != '_') &&
10584:          (c != ':'))) {
10585: 	return(NULL);
10586:     }
10587: 
10588:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10589: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10590:             (c == '.') || (c == '-') ||
10591: 	    (c == '_') || (c == ':') ||
10592: 	    (IS_COMBINING(c)) ||
10593: 	    (IS_EXTENDER(c)))) {
10594: 	len += l;
10595: 	NEXTL(l);
10596: 	c = CUR_CHAR(l);
10597:     }
10598:     ret = xmlStrndup(cur, ctxt->cur - cur);
10599:     ctxt->cur = cur;
10600:     return(ret);
10601: }
10602: 
10603: /**
10604:  * xmlXPathCompPathExpr:
10605:  * @ctxt:  the XPath Parser context
10606:  *
10607:  *  [19]   PathExpr ::=   LocationPath
10608:  *               | FilterExpr
10609:  *               | FilterExpr '/' RelativeLocationPath
10610:  *               | FilterExpr '//' RelativeLocationPath
10611:  *
10612:  * Compile a path expression.
10613:  * The / operator and // operators combine an arbitrary expression
10614:  * and a relative location path. It is an error if the expression
10615:  * does not evaluate to a node-set.
10616:  * The / operator does composition in the same way as when / is
10617:  * used in a location path. As in location paths, // is short for
10618:  * /descendant-or-self::node()/.
10619:  */
10620: 
10621: static void
10622: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10623:     int lc = 1;           /* Should we branch to LocationPath ?         */
10624:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10625: 
10626:     SKIP_BLANKS;
10627:     if ((CUR == '$') || (CUR == '(') ||
10628: 	(IS_ASCII_DIGIT(CUR)) ||
10629:         (CUR == '\'') || (CUR == '"') ||
10630: 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10631: 	lc = 0;
10632:     } else if (CUR == '*') {
10633: 	/* relative or absolute location path */
10634: 	lc = 1;
10635:     } else if (CUR == '/') {
10636: 	/* relative or absolute location path */
10637: 	lc = 1;
10638:     } else if (CUR == '@') {
10639: 	/* relative abbreviated attribute location path */
10640: 	lc = 1;
10641:     } else if (CUR == '.') {
10642: 	/* relative abbreviated attribute location path */
10643: 	lc = 1;
10644:     } else {
10645: 	/*
10646: 	 * Problem is finding if we have a name here whether it's:
10647: 	 *   - a nodetype
10648: 	 *   - a function call in which case it's followed by '('
10649: 	 *   - an axis in which case it's followed by ':'
10650: 	 *   - a element name
10651: 	 * We do an a priori analysis here rather than having to
10652: 	 * maintain parsed token content through the recursive function
10653: 	 * calls. This looks uglier but makes the code easier to
10654: 	 * read/write/debug.
10655: 	 */
10656: 	SKIP_BLANKS;
10657: 	name = xmlXPathScanName(ctxt);
10658: 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10659: #ifdef DEBUG_STEP
10660: 	    xmlGenericError(xmlGenericErrorContext,
10661: 		    "PathExpr: Axis\n");
10662: #endif
10663: 	    lc = 1;
10664: 	    xmlFree(name);
10665: 	} else if (name != NULL) {
10666: 	    int len =xmlStrlen(name);
10667: 
10668: 
10669: 	    while (NXT(len) != 0) {
10670: 		if (NXT(len) == '/') {
10671: 		    /* element name */
10672: #ifdef DEBUG_STEP
10673: 		    xmlGenericError(xmlGenericErrorContext,
10674: 			    "PathExpr: AbbrRelLocation\n");
10675: #endif
10676: 		    lc = 1;
10677: 		    break;
10678: 		} else if (IS_BLANK_CH(NXT(len))) {
10679: 		    /* ignore blanks */
10680: 		    ;
10681: 		} else if (NXT(len) == ':') {
10682: #ifdef DEBUG_STEP
10683: 		    xmlGenericError(xmlGenericErrorContext,
10684: 			    "PathExpr: AbbrRelLocation\n");
10685: #endif
10686: 		    lc = 1;
10687: 		    break;
10688: 		} else if ((NXT(len) == '(')) {
10689: 		    /* Note Type or Function */
10690: 		    if (xmlXPathIsNodeType(name)) {
10691: #ifdef DEBUG_STEP
10692: 		        xmlGenericError(xmlGenericErrorContext,
10693: 				"PathExpr: Type search\n");
10694: #endif
10695: 			lc = 1;
10696: 		    } else {
10697: #ifdef DEBUG_STEP
10698: 		        xmlGenericError(xmlGenericErrorContext,
10699: 				"PathExpr: function call\n");
10700: #endif
10701: 			lc = 0;
10702: 		    }
10703:                     break;
10704: 		} else if ((NXT(len) == '[')) {
10705: 		    /* element name */
10706: #ifdef DEBUG_STEP
10707: 		    xmlGenericError(xmlGenericErrorContext,
10708: 			    "PathExpr: AbbrRelLocation\n");
10709: #endif
10710: 		    lc = 1;
10711: 		    break;
10712: 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10713: 			   (NXT(len) == '=')) {
10714: 		    lc = 1;
10715: 		    break;
10716: 		} else {
10717: 		    lc = 1;
10718: 		    break;
10719: 		}
10720: 		len++;
10721: 	    }
10722: 	    if (NXT(len) == 0) {
10723: #ifdef DEBUG_STEP
10724: 		xmlGenericError(xmlGenericErrorContext,
10725: 			"PathExpr: AbbrRelLocation\n");
10726: #endif
10727: 		/* element name */
10728: 		lc = 1;
10729: 	    }
10730: 	    xmlFree(name);
10731: 	} else {
10732: 	    /* make sure all cases are covered explicitly */
10733: 	    XP_ERROR(XPATH_EXPR_ERROR);
10734: 	}
10735:     }
10736: 
10737:     if (lc) {
10738: 	if (CUR == '/') {
10739: 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10740: 	} else {
10741: 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10742: 	}
10743: 	xmlXPathCompLocationPath(ctxt);
10744:     } else {
10745: 	xmlXPathCompFilterExpr(ctxt);
10746: 	CHECK_ERROR;
10747: 	if ((CUR == '/') && (NXT(1) == '/')) {
10748: 	    SKIP(2);
10749: 	    SKIP_BLANKS;
10750: 
10751: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10752: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10753: 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10754: 
10755: 	    xmlXPathCompRelativeLocationPath(ctxt);
10756: 	} else if (CUR == '/') {
10757: 	    xmlXPathCompRelativeLocationPath(ctxt);
10758: 	}
10759:     }
10760:     SKIP_BLANKS;
10761: }
10762: 
10763: /**
10764:  * xmlXPathCompUnionExpr:
10765:  * @ctxt:  the XPath Parser context
10766:  *
10767:  *  [18]   UnionExpr ::=   PathExpr
10768:  *               | UnionExpr '|' PathExpr
10769:  *
10770:  * Compile an union expression.
10771:  */
10772: 
10773: static void
10774: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10775:     xmlXPathCompPathExpr(ctxt);
10776:     CHECK_ERROR;
10777:     SKIP_BLANKS;
10778:     while (CUR == '|') {
10779: 	int op1 = ctxt->comp->last;
10780: 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10781: 
10782: 	NEXT;
10783: 	SKIP_BLANKS;
10784: 	xmlXPathCompPathExpr(ctxt);
10785: 
10786: 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10787: 
10788: 	SKIP_BLANKS;
10789:     }
10790: }
10791: 
10792: /**
10793:  * xmlXPathCompUnaryExpr:
10794:  * @ctxt:  the XPath Parser context
10795:  *
10796:  *  [27]   UnaryExpr ::=   UnionExpr
10797:  *                   | '-' UnaryExpr
10798:  *
10799:  * Compile an unary expression.
10800:  */
10801: 
10802: static void
10803: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10804:     int minus = 0;
10805:     int found = 0;
10806: 
10807:     SKIP_BLANKS;
10808:     while (CUR == '-') {
10809:         minus = 1 - minus;
10810: 	found = 1;
10811: 	NEXT;
10812: 	SKIP_BLANKS;
10813:     }
10814: 
10815:     xmlXPathCompUnionExpr(ctxt);
10816:     CHECK_ERROR;
10817:     if (found) {
10818: 	if (minus)
10819: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10820: 	else
10821: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10822:     }
10823: }
10824: 
10825: /**
10826:  * xmlXPathCompMultiplicativeExpr:
10827:  * @ctxt:  the XPath Parser context
10828:  *
10829:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10830:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10831:  *                   | MultiplicativeExpr 'div' UnaryExpr
10832:  *                   | MultiplicativeExpr 'mod' UnaryExpr
10833:  *  [34]   MultiplyOperator ::=   '*'
10834:  *
10835:  * Compile an Additive expression.
10836:  */
10837: 
10838: static void
10839: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10840:     xmlXPathCompUnaryExpr(ctxt);
10841:     CHECK_ERROR;
10842:     SKIP_BLANKS;
10843:     while ((CUR == '*') ||
10844:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10845:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10846: 	int op = -1;
10847: 	int op1 = ctxt->comp->last;
10848: 
10849:         if (CUR == '*') {
10850: 	    op = 0;
10851: 	    NEXT;
10852: 	} else if (CUR == 'd') {
10853: 	    op = 1;
10854: 	    SKIP(3);
10855: 	} else if (CUR == 'm') {
10856: 	    op = 2;
10857: 	    SKIP(3);
10858: 	}
10859: 	SKIP_BLANKS;
10860:         xmlXPathCompUnaryExpr(ctxt);
10861: 	CHECK_ERROR;
10862: 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10863: 	SKIP_BLANKS;
10864:     }
10865: }
10866: 
10867: /**
10868:  * xmlXPathCompAdditiveExpr:
10869:  * @ctxt:  the XPath Parser context
10870:  *
10871:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10872:  *                   | AdditiveExpr '+' MultiplicativeExpr
10873:  *                   | AdditiveExpr '-' MultiplicativeExpr
10874:  *
10875:  * Compile an Additive expression.
10876:  */
10877: 
10878: static void
10879: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10880: 
10881:     xmlXPathCompMultiplicativeExpr(ctxt);
10882:     CHECK_ERROR;
10883:     SKIP_BLANKS;
10884:     while ((CUR == '+') || (CUR == '-')) {
10885: 	int plus;
10886: 	int op1 = ctxt->comp->last;
10887: 
10888:         if (CUR == '+') plus = 1;
10889: 	else plus = 0;
10890: 	NEXT;
10891: 	SKIP_BLANKS;
10892:         xmlXPathCompMultiplicativeExpr(ctxt);
10893: 	CHECK_ERROR;
10894: 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10895: 	SKIP_BLANKS;
10896:     }
10897: }
10898: 
10899: /**
10900:  * xmlXPathCompRelationalExpr:
10901:  * @ctxt:  the XPath Parser context
10902:  *
10903:  *  [24]   RelationalExpr ::=   AdditiveExpr
10904:  *                 | RelationalExpr '<' AdditiveExpr
10905:  *                 | RelationalExpr '>' AdditiveExpr
10906:  *                 | RelationalExpr '<=' AdditiveExpr
10907:  *                 | RelationalExpr '>=' AdditiveExpr
10908:  *
10909:  *  A <= B > C is allowed ? Answer from James, yes with
10910:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10911:  *  which is basically what got implemented.
10912:  *
10913:  * Compile a Relational expression, then push the result
10914:  * on the stack
10915:  */
10916: 
10917: static void
10918: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10919:     xmlXPathCompAdditiveExpr(ctxt);
10920:     CHECK_ERROR;
10921:     SKIP_BLANKS;
10922:     while ((CUR == '<') ||
10923:            (CUR == '>') ||
10924:            ((CUR == '<') && (NXT(1) == '=')) ||
10925:            ((CUR == '>') && (NXT(1) == '='))) {
10926: 	int inf, strict;
10927: 	int op1 = ctxt->comp->last;
10928: 
10929:         if (CUR == '<') inf = 1;
10930: 	else inf = 0;
10931: 	if (NXT(1) == '=') strict = 0;
10932: 	else strict = 1;
10933: 	NEXT;
10934: 	if (!strict) NEXT;
10935: 	SKIP_BLANKS;
10936:         xmlXPathCompAdditiveExpr(ctxt);
10937: 	CHECK_ERROR;
10938: 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10939: 	SKIP_BLANKS;
10940:     }
10941: }
10942: 
10943: /**
10944:  * xmlXPathCompEqualityExpr:
10945:  * @ctxt:  the XPath Parser context
10946:  *
10947:  *  [23]   EqualityExpr ::=   RelationalExpr
10948:  *                 | EqualityExpr '=' RelationalExpr
10949:  *                 | EqualityExpr '!=' RelationalExpr
10950:  *
10951:  *  A != B != C is allowed ? Answer from James, yes with
10952:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10953:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10954:  *  which is basically what got implemented.
10955:  *
10956:  * Compile an Equality expression.
10957:  *
10958:  */
10959: static void
10960: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10961:     xmlXPathCompRelationalExpr(ctxt);
10962:     CHECK_ERROR;
10963:     SKIP_BLANKS;
10964:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10965: 	int eq;
10966: 	int op1 = ctxt->comp->last;
10967: 
10968:         if (CUR == '=') eq = 1;
10969: 	else eq = 0;
10970: 	NEXT;
10971: 	if (!eq) NEXT;
10972: 	SKIP_BLANKS;
10973:         xmlXPathCompRelationalExpr(ctxt);
10974: 	CHECK_ERROR;
10975: 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10976: 	SKIP_BLANKS;
10977:     }
10978: }
10979: 
10980: /**
10981:  * xmlXPathCompAndExpr:
10982:  * @ctxt:  the XPath Parser context
10983:  *
10984:  *  [22]   AndExpr ::=   EqualityExpr
10985:  *                 | AndExpr 'and' EqualityExpr
10986:  *
10987:  * Compile an AND expression.
10988:  *
10989:  */
10990: static void
10991: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10992:     xmlXPathCompEqualityExpr(ctxt);
10993:     CHECK_ERROR;
10994:     SKIP_BLANKS;
10995:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10996: 	int op1 = ctxt->comp->last;
10997:         SKIP(3);
10998: 	SKIP_BLANKS;
10999:         xmlXPathCompEqualityExpr(ctxt);
11000: 	CHECK_ERROR;
11001: 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11002: 	SKIP_BLANKS;
11003:     }
11004: }
11005: 
11006: /**
11007:  * xmlXPathCompileExpr:
11008:  * @ctxt:  the XPath Parser context
11009:  *
11010:  *  [14]   Expr ::=   OrExpr
11011:  *  [21]   OrExpr ::=   AndExpr
11012:  *                 | OrExpr 'or' AndExpr
11013:  *
11014:  * Parse and compile an expression
11015:  */
11016: static void
11017: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11018:     xmlXPathCompAndExpr(ctxt);
11019:     CHECK_ERROR;
11020:     SKIP_BLANKS;
11021:     while ((CUR == 'o') && (NXT(1) == 'r')) {
11022: 	int op1 = ctxt->comp->last;
11023:         SKIP(2);
11024: 	SKIP_BLANKS;
11025:         xmlXPathCompAndExpr(ctxt);
11026: 	CHECK_ERROR;
11027: 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11028: 	SKIP_BLANKS;
11029:     }
11030:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11031: 	/* more ops could be optimized too */
11032: 	/*
11033: 	* This is the main place to eliminate sorting for
11034: 	* operations which don't require a sorted node-set.
11035: 	* E.g. count().
11036: 	*/
11037: 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11038:     }
11039: }
11040: 
11041: /**
11042:  * xmlXPathCompPredicate:
11043:  * @ctxt:  the XPath Parser context
11044:  * @filter:  act as a filter
11045:  *
11046:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11047:  *  [9]   PredicateExpr ::=   Expr
11048:  *
11049:  * Compile a predicate expression
11050:  */
11051: static void
11052: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11053:     int op1 = ctxt->comp->last;
11054: 
11055:     SKIP_BLANKS;
11056:     if (CUR != '[') {
11057: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11058:     }
11059:     NEXT;
11060:     SKIP_BLANKS;
11061: 
11062:     ctxt->comp->last = -1;
11063:     /*
11064:     * This call to xmlXPathCompileExpr() will deactivate sorting
11065:     * of the predicate result.
11066:     * TODO: Sorting is still activated for filters, since I'm not
11067:     *  sure if needed. Normally sorting should not be needed, since
11068:     *  a filter can only diminish the number of items in a sequence,
11069:     *  but won't change its order; so if the initial sequence is sorted,
11070:     *  subsequent sorting is not needed.
11071:     */
11072:     if (! filter)
11073: 	xmlXPathCompileExpr(ctxt, 0);
11074:     else
11075: 	xmlXPathCompileExpr(ctxt, 1);
11076:     CHECK_ERROR;
11077: 
11078:     if (CUR != ']') {
11079: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11080:     }
11081: 
11082:     if (filter)
11083: 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11084:     else
11085: 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11086: 
11087:     NEXT;
11088:     SKIP_BLANKS;
11089: }
11090: 
11091: /**
11092:  * xmlXPathCompNodeTest:
11093:  * @ctxt:  the XPath Parser context
11094:  * @test:  pointer to a xmlXPathTestVal
11095:  * @type:  pointer to a xmlXPathTypeVal
11096:  * @prefix:  placeholder for a possible name prefix
11097:  *
11098:  * [7] NodeTest ::=   NameTest
11099:  *		    | NodeType '(' ')'
11100:  *		    | 'processing-instruction' '(' Literal ')'
11101:  *
11102:  * [37] NameTest ::=  '*'
11103:  *		    | NCName ':' '*'
11104:  *		    | QName
11105:  * [38] NodeType ::= 'comment'
11106:  *		   | 'text'
11107:  *		   | 'processing-instruction'
11108:  *		   | 'node'
11109:  *
11110:  * Returns the name found and updates @test, @type and @prefix appropriately
11111:  */
11112: static xmlChar *
11113: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11114: 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11115: 		     xmlChar *name) {
11116:     int blanks;
11117: 
11118:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11119: 	STRANGE;
11120: 	return(NULL);
11121:     }
11122:     *type = (xmlXPathTypeVal) 0;
11123:     *test = (xmlXPathTestVal) 0;
11124:     *prefix = NULL;
11125:     SKIP_BLANKS;
11126: 
11127:     if ((name == NULL) && (CUR == '*')) {
11128: 	/*
11129: 	 * All elements
11130: 	 */
11131: 	NEXT;
11132: 	*test = NODE_TEST_ALL;
11133: 	return(NULL);
11134:     }
11135: 
11136:     if (name == NULL)
11137: 	name = xmlXPathParseNCName(ctxt);
11138:     if (name == NULL) {
11139: 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11140:     }
11141: 
11142:     blanks = IS_BLANK_CH(CUR);
11143:     SKIP_BLANKS;
11144:     if (CUR == '(') {
11145: 	NEXT;
11146: 	/*
11147: 	 * NodeType or PI search
11148: 	 */
11149: 	if (xmlStrEqual(name, BAD_CAST "comment"))
11150: 	    *type = NODE_TYPE_COMMENT;
11151: 	else if (xmlStrEqual(name, BAD_CAST "node"))
11152: 	    *type = NODE_TYPE_NODE;
11153: 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11154: 	    *type = NODE_TYPE_PI;
11155: 	else if (xmlStrEqual(name, BAD_CAST "text"))
11156: 	    *type = NODE_TYPE_TEXT;
11157: 	else {
11158: 	    if (name != NULL)
11159: 		xmlFree(name);
11160: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11161: 	}
11162: 
11163: 	*test = NODE_TEST_TYPE;
11164: 
11165: 	SKIP_BLANKS;
11166: 	if (*type == NODE_TYPE_PI) {
11167: 	    /*
11168: 	     * Specific case: search a PI by name.
11169: 	     */
11170: 	    if (name != NULL)
11171: 		xmlFree(name);
11172: 	    name = NULL;
11173: 	    if (CUR != ')') {
11174: 		name = xmlXPathParseLiteral(ctxt);
11175: 		CHECK_ERROR NULL;
11176: 		*test = NODE_TEST_PI;
11177: 		SKIP_BLANKS;
11178: 	    }
11179: 	}
11180: 	if (CUR != ')') {
11181: 	    if (name != NULL)
11182: 		xmlFree(name);
11183: 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11184: 	}
11185: 	NEXT;
11186: 	return(name);
11187:     }
11188:     *test = NODE_TEST_NAME;
11189:     if ((!blanks) && (CUR == ':')) {
11190: 	NEXT;
11191: 
11192: 	/*
11193: 	 * Since currently the parser context don't have a
11194: 	 * namespace list associated:
11195: 	 * The namespace name for this prefix can be computed
11196: 	 * only at evaluation time. The compilation is done
11197: 	 * outside of any context.
11198: 	 */
11199: #if 0
11200: 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11201: 	if (name != NULL)
11202: 	    xmlFree(name);
11203: 	if (*prefix == NULL) {
11204: 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11205: 	}
11206: #else
11207: 	*prefix = name;
11208: #endif
11209: 
11210: 	if (CUR == '*') {
11211: 	    /*
11212: 	     * All elements
11213: 	     */
11214: 	    NEXT;
11215: 	    *test = NODE_TEST_ALL;
11216: 	    return(NULL);
11217: 	}
11218: 
11219: 	name = xmlXPathParseNCName(ctxt);
11220: 	if (name == NULL) {
11221: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11222: 	}
11223:     }
11224:     return(name);
11225: }
11226: 
11227: /**
11228:  * xmlXPathIsAxisName:
11229:  * @name:  a preparsed name token
11230:  *
11231:  * [6] AxisName ::=   'ancestor'
11232:  *                  | 'ancestor-or-self'
11233:  *                  | 'attribute'
11234:  *                  | 'child'
11235:  *                  | 'descendant'
11236:  *                  | 'descendant-or-self'
11237:  *                  | 'following'
11238:  *                  | 'following-sibling'
11239:  *                  | 'namespace'
11240:  *                  | 'parent'
11241:  *                  | 'preceding'
11242:  *                  | 'preceding-sibling'
11243:  *                  | 'self'
11244:  *
11245:  * Returns the axis or 0
11246:  */
11247: static xmlXPathAxisVal
11248: xmlXPathIsAxisName(const xmlChar *name) {
11249:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11250:     switch (name[0]) {
11251: 	case 'a':
11252: 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11253: 		ret = AXIS_ANCESTOR;
11254: 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11255: 		ret = AXIS_ANCESTOR_OR_SELF;
11256: 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11257: 		ret = AXIS_ATTRIBUTE;
11258: 	    break;
11259: 	case 'c':
11260: 	    if (xmlStrEqual(name, BAD_CAST "child"))
11261: 		ret = AXIS_CHILD;
11262: 	    break;
11263: 	case 'd':
11264: 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11265: 		ret = AXIS_DESCENDANT;
11266: 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11267: 		ret = AXIS_DESCENDANT_OR_SELF;
11268: 	    break;
11269: 	case 'f':
11270: 	    if (xmlStrEqual(name, BAD_CAST "following"))
11271: 		ret = AXIS_FOLLOWING;
11272: 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11273: 		ret = AXIS_FOLLOWING_SIBLING;
11274: 	    break;
11275: 	case 'n':
11276: 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11277: 		ret = AXIS_NAMESPACE;
11278: 	    break;
11279: 	case 'p':
11280: 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11281: 		ret = AXIS_PARENT;
11282: 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11283: 		ret = AXIS_PRECEDING;
11284: 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11285: 		ret = AXIS_PRECEDING_SIBLING;
11286: 	    break;
11287: 	case 's':
11288: 	    if (xmlStrEqual(name, BAD_CAST "self"))
11289: 		ret = AXIS_SELF;
11290: 	    break;
11291:     }
11292:     return(ret);
11293: }
11294: 
11295: /**
11296:  * xmlXPathCompStep:
11297:  * @ctxt:  the XPath Parser context
11298:  *
11299:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11300:  *                  | AbbreviatedStep
11301:  *
11302:  * [12] AbbreviatedStep ::=   '.' | '..'
11303:  *
11304:  * [5] AxisSpecifier ::= AxisName '::'
11305:  *                  | AbbreviatedAxisSpecifier
11306:  *
11307:  * [13] AbbreviatedAxisSpecifier ::= '@'?
11308:  *
11309:  * Modified for XPtr range support as:
11310:  *
11311:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11312:  *                     | AbbreviatedStep
11313:  *                     | 'range-to' '(' Expr ')' Predicate*
11314:  *
11315:  * Compile one step in a Location Path
11316:  * A location step of . is short for self::node(). This is
11317:  * particularly useful in conjunction with //. For example, the
11318:  * location path .//para is short for
11319:  * self::node()/descendant-or-self::node()/child::para
11320:  * and so will select all para descendant elements of the context
11321:  * node.
11322:  * Similarly, a location step of .. is short for parent::node().
11323:  * For example, ../title is short for parent::node()/child::title
11324:  * and so will select the title children of the parent of the context
11325:  * node.
11326:  */
11327: static void
11328: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11329: #ifdef LIBXML_XPTR_ENABLED
11330:     int rangeto = 0;
11331:     int op2 = -1;
11332: #endif
11333: 
11334:     SKIP_BLANKS;
11335:     if ((CUR == '.') && (NXT(1) == '.')) {
11336: 	SKIP(2);
11337: 	SKIP_BLANKS;
11338: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11339: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11340:     } else if (CUR == '.') {
11341: 	NEXT;
11342: 	SKIP_BLANKS;
11343:     } else {
11344: 	xmlChar *name = NULL;
11345: 	const xmlChar *prefix = NULL;
11346: 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11347: 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11348: 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11349: 	int op1;
11350: 
11351: 	/*
11352: 	 * The modification needed for XPointer change to the production
11353: 	 */
11354: #ifdef LIBXML_XPTR_ENABLED
11355: 	if (ctxt->xptr) {
11356: 	    name = xmlXPathParseNCName(ctxt);
11357: 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11358:                 op2 = ctxt->comp->last;
11359: 		xmlFree(name);
11360: 		SKIP_BLANKS;
11361: 		if (CUR != '(') {
11362: 		    XP_ERROR(XPATH_EXPR_ERROR);
11363: 		}
11364: 		NEXT;
11365: 		SKIP_BLANKS;
11366: 
11367: 		xmlXPathCompileExpr(ctxt, 1);
11368: 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11369: 		CHECK_ERROR;
11370: 
11371: 		SKIP_BLANKS;
11372: 		if (CUR != ')') {
11373: 		    XP_ERROR(XPATH_EXPR_ERROR);
11374: 		}
11375: 		NEXT;
11376: 		rangeto = 1;
11377: 		goto eval_predicates;
11378: 	    }
11379: 	}
11380: #endif
11381: 	if (CUR == '*') {
11382: 	    axis = AXIS_CHILD;
11383: 	} else {
11384: 	    if (name == NULL)
11385: 		name = xmlXPathParseNCName(ctxt);
11386: 	    if (name != NULL) {
11387: 		axis = xmlXPathIsAxisName(name);
11388: 		if (axis != 0) {
11389: 		    SKIP_BLANKS;
11390: 		    if ((CUR == ':') && (NXT(1) == ':')) {
11391: 			SKIP(2);
11392: 			xmlFree(name);
11393: 			name = NULL;
11394: 		    } else {
11395: 			/* an element name can conflict with an axis one :-\ */
11396: 			axis = AXIS_CHILD;
11397: 		    }
11398: 		} else {
11399: 		    axis = AXIS_CHILD;
11400: 		}
11401: 	    } else if (CUR == '@') {
11402: 		NEXT;
11403: 		axis = AXIS_ATTRIBUTE;
11404: 	    } else {
11405: 		axis = AXIS_CHILD;
11406: 	    }
11407: 	}
11408: 
11409:         if (ctxt->error != XPATH_EXPRESSION_OK) {
11410:             xmlFree(name);
11411:             return;
11412:         }
11413: 
11414: 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11415: 	if (test == 0)
11416: 	    return;
11417: 
11418:         if ((prefix != NULL) && (ctxt->context != NULL) &&
11419: 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11420: 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11421: 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11422: 	    }
11423: 	}
11424: #ifdef DEBUG_STEP
11425: 	xmlGenericError(xmlGenericErrorContext,
11426: 		"Basis : computing new set\n");
11427: #endif
11428: 
11429: #ifdef DEBUG_STEP
11430: 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11431: 	if (ctxt->value == NULL)
11432: 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11433: 	else if (ctxt->value->nodesetval == NULL)
11434: 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11435: 	else
11436: 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11437: #endif
11438: 
11439: #ifdef LIBXML_XPTR_ENABLED
11440: eval_predicates:
11441: #endif
11442: 	op1 = ctxt->comp->last;
11443: 	ctxt->comp->last = -1;
11444: 
11445: 	SKIP_BLANKS;
11446: 	while (CUR == '[') {
11447: 	    xmlXPathCompPredicate(ctxt, 0);
11448: 	}
11449: 
11450: #ifdef LIBXML_XPTR_ENABLED
11451: 	if (rangeto) {
11452: 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11453: 	} else
11454: #endif
11455: 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11456: 			   test, type, (void *)prefix, (void *)name);
11457: 
11458:     }
11459: #ifdef DEBUG_STEP
11460:     xmlGenericError(xmlGenericErrorContext, "Step : ");
11461:     if (ctxt->value == NULL)
11462: 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11463:     else if (ctxt->value->nodesetval == NULL)
11464: 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11465:     else
11466: 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11467: 		ctxt->value->nodesetval);
11468: #endif
11469: }
11470: 
11471: /**
11472:  * xmlXPathCompRelativeLocationPath:
11473:  * @ctxt:  the XPath Parser context
11474:  *
11475:  *  [3]   RelativeLocationPath ::=   Step
11476:  *                     | RelativeLocationPath '/' Step
11477:  *                     | AbbreviatedRelativeLocationPath
11478:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11479:  *
11480:  * Compile a relative location path.
11481:  */
11482: static void
11483: xmlXPathCompRelativeLocationPath
11484: (xmlXPathParserContextPtr ctxt) {
11485:     SKIP_BLANKS;
11486:     if ((CUR == '/') && (NXT(1) == '/')) {
11487: 	SKIP(2);
11488: 	SKIP_BLANKS;
11489: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11490: 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11491:     } else if (CUR == '/') {
11492: 	    NEXT;
11493: 	SKIP_BLANKS;
11494:     }
11495:     xmlXPathCompStep(ctxt);
11496:     CHECK_ERROR;
11497:     SKIP_BLANKS;
11498:     while (CUR == '/') {
11499: 	if ((CUR == '/') && (NXT(1) == '/')) {
11500: 	    SKIP(2);
11501: 	    SKIP_BLANKS;
11502: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11503: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11504: 	    xmlXPathCompStep(ctxt);
11505: 	} else if (CUR == '/') {
11506: 	    NEXT;
11507: 	    SKIP_BLANKS;
11508: 	    xmlXPathCompStep(ctxt);
11509: 	}
11510: 	SKIP_BLANKS;
11511:     }
11512: }
11513: 
11514: /**
11515:  * xmlXPathCompLocationPath:
11516:  * @ctxt:  the XPath Parser context
11517:  *
11518:  *  [1]   LocationPath ::=   RelativeLocationPath
11519:  *                     | AbsoluteLocationPath
11520:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11521:  *                     | AbbreviatedAbsoluteLocationPath
11522:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11523:  *                           '//' RelativeLocationPath
11524:  *
11525:  * Compile a location path
11526:  *
11527:  * // is short for /descendant-or-self::node()/. For example,
11528:  * //para is short for /descendant-or-self::node()/child::para and
11529:  * so will select any para element in the document (even a para element
11530:  * that is a document element will be selected by //para since the
11531:  * document element node is a child of the root node); div//para is
11532:  * short for div/descendant-or-self::node()/child::para and so will
11533:  * select all para descendants of div children.
11534:  */
11535: static void
11536: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11537:     SKIP_BLANKS;
11538:     if (CUR != '/') {
11539:         xmlXPathCompRelativeLocationPath(ctxt);
11540:     } else {
11541: 	while (CUR == '/') {
11542: 	    if ((CUR == '/') && (NXT(1) == '/')) {
11543: 		SKIP(2);
11544: 		SKIP_BLANKS;
11545: 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11546: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11547: 		xmlXPathCompRelativeLocationPath(ctxt);
11548: 	    } else if (CUR == '/') {
11549: 		NEXT;
11550: 		SKIP_BLANKS;
11551: 		if ((CUR != 0 ) &&
11552: 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11553: 		     (CUR == '@') || (CUR == '*')))
11554: 		    xmlXPathCompRelativeLocationPath(ctxt);
11555: 	    }
11556: 	    CHECK_ERROR;
11557: 	}
11558:     }
11559: }
11560: 
11561: /************************************************************************
11562:  *									*
11563:  *		XPath precompiled expression evaluation			*
11564:  *									*
11565:  ************************************************************************/
11566: 
11567: static int
11568: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11569: 
11570: #ifdef DEBUG_STEP
11571: static void
11572: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11573: 			  int nbNodes)
11574: {
11575:     xmlGenericError(xmlGenericErrorContext, "new step : ");
11576:     switch (op->value) {
11577:         case AXIS_ANCESTOR:
11578:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11579:             break;
11580:         case AXIS_ANCESTOR_OR_SELF:
11581:             xmlGenericError(xmlGenericErrorContext,
11582:                             "axis 'ancestors-or-self' ");
11583:             break;
11584:         case AXIS_ATTRIBUTE:
11585:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11586:             break;
11587:         case AXIS_CHILD:
11588:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11589:             break;
11590:         case AXIS_DESCENDANT:
11591:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11592:             break;
11593:         case AXIS_DESCENDANT_OR_SELF:
11594:             xmlGenericError(xmlGenericErrorContext,
11595:                             "axis 'descendant-or-self' ");
11596:             break;
11597:         case AXIS_FOLLOWING:
11598:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11599:             break;
11600:         case AXIS_FOLLOWING_SIBLING:
11601:             xmlGenericError(xmlGenericErrorContext,
11602:                             "axis 'following-siblings' ");
11603:             break;
11604:         case AXIS_NAMESPACE:
11605:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11606:             break;
11607:         case AXIS_PARENT:
11608:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11609:             break;
11610:         case AXIS_PRECEDING:
11611:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11612:             break;
11613:         case AXIS_PRECEDING_SIBLING:
11614:             xmlGenericError(xmlGenericErrorContext,
11615:                             "axis 'preceding-sibling' ");
11616:             break;
11617:         case AXIS_SELF:
11618:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11619:             break;
11620:     }
11621:     xmlGenericError(xmlGenericErrorContext,
11622: 	" context contains %d nodes\n", nbNodes);
11623:     switch (op->value2) {
11624:         case NODE_TEST_NONE:
11625:             xmlGenericError(xmlGenericErrorContext,
11626:                             "           searching for none !!!\n");
11627:             break;
11628:         case NODE_TEST_TYPE:
11629:             xmlGenericError(xmlGenericErrorContext,
11630:                             "           searching for type %d\n", op->value3);
11631:             break;
11632:         case NODE_TEST_PI:
11633:             xmlGenericError(xmlGenericErrorContext,
11634:                             "           searching for PI !!!\n");
11635:             break;
11636:         case NODE_TEST_ALL:
11637:             xmlGenericError(xmlGenericErrorContext,
11638:                             "           searching for *\n");
11639:             break;
11640:         case NODE_TEST_NS:
11641:             xmlGenericError(xmlGenericErrorContext,
11642:                             "           searching for namespace %s\n",
11643:                             op->value5);
11644:             break;
11645:         case NODE_TEST_NAME:
11646:             xmlGenericError(xmlGenericErrorContext,
11647:                             "           searching for name %s\n", op->value5);
11648:             if (op->value4)
11649:                 xmlGenericError(xmlGenericErrorContext,
11650:                                 "           with namespace %s\n", op->value4);
11651:             break;
11652:     }
11653:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11654: }
11655: #endif /* DEBUG_STEP */
11656: 
11657: static int
11658: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11659: 			    xmlXPathStepOpPtr op,
11660: 			    xmlNodeSetPtr set,
11661: 			    int contextSize,
11662: 			    int hasNsNodes)
11663: {
11664:     if (op->ch1 != -1) {
11665: 	xmlXPathCompExprPtr comp = ctxt->comp;
11666: 	/*
11667: 	* Process inner predicates first.
11668: 	*/
11669: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11670: 	    /*
11671: 	    * TODO: raise an internal error.
11672: 	    */
11673: 	}
11674: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11675: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11676: 	CHECK_ERROR0;
11677: 	if (contextSize <= 0)
11678: 	    return(0);
11679:     }
11680:     if (op->ch2 != -1) {
11681: 	xmlXPathContextPtr xpctxt = ctxt->context;
11682: 	xmlNodePtr contextNode, oldContextNode;
11683: 	xmlDocPtr oldContextDoc;
11684: 	int i, res, contextPos = 0, newContextSize;
11685: 	xmlXPathStepOpPtr exprOp;
11686: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11687: 
11688: #ifdef LIBXML_XPTR_ENABLED
11689: 	/*
11690: 	* URGENT TODO: Check the following:
11691: 	*  We don't expect location sets if evaluating prediates, right?
11692: 	*  Only filters should expect location sets, right?
11693: 	*/
11694: #endif
11695: 	/*
11696: 	* SPEC XPath 1.0:
11697: 	*  "For each node in the node-set to be filtered, the
11698: 	*  PredicateExpr is evaluated with that node as the
11699: 	*  context node, with the number of nodes in the
11700: 	*  node-set as the context size, and with the proximity
11701: 	*  position of the node in the node-set with respect to
11702: 	*  the axis as the context position;"
11703: 	* @oldset is the node-set" to be filtered.
11704: 	*
11705: 	* SPEC XPath 1.0:
11706: 	*  "only predicates change the context position and
11707: 	*  context size (see [2.4 Predicates])."
11708: 	* Example:
11709: 	*   node-set  context pos
11710: 	*    nA         1
11711: 	*    nB         2
11712: 	*    nC         3
11713: 	*   After applying predicate [position() > 1] :
11714: 	*   node-set  context pos
11715: 	*    nB         1
11716: 	*    nC         2
11717: 	*/
11718: 	oldContextNode = xpctxt->node;
11719: 	oldContextDoc = xpctxt->doc;
11720: 	/*
11721: 	* Get the expression of this predicate.
11722: 	*/
11723: 	exprOp = &ctxt->comp->steps[op->ch2];
11724: 	newContextSize = 0;
11725: 	for (i = 0; i < set->nodeNr; i++) {
11726: 	    if (set->nodeTab[i] == NULL)
11727: 		continue;
11728: 
11729: 	    contextNode = set->nodeTab[i];
11730: 	    xpctxt->node = contextNode;
11731: 	    xpctxt->contextSize = contextSize;
11732: 	    xpctxt->proximityPosition = ++contextPos;
11733: 
11734: 	    /*
11735: 	    * Also set the xpath document in case things like
11736: 	    * key() are evaluated in the predicate.
11737: 	    */
11738: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11739: 		(contextNode->doc != NULL))
11740: 		xpctxt->doc = contextNode->doc;
11741: 	    /*
11742: 	    * Evaluate the predicate expression with 1 context node
11743: 	    * at a time; this node is packaged into a node set; this
11744: 	    * node set is handed over to the evaluation mechanism.
11745: 	    */
11746: 	    if (contextObj == NULL)
11747: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11748: 	    else {
11749: 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11750: 		    contextNode) < 0) {
11751: 		    ctxt->error = XPATH_MEMORY_ERROR;
11752: 		    goto evaluation_exit;
11753: 		}
11754: 	    }
11755: 
11756: 	    valuePush(ctxt, contextObj);
11757: 
11758: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11759: 
11760: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11761: 		xmlXPathNodeSetClear(set, hasNsNodes);
11762: 		newContextSize = 0;
11763: 		goto evaluation_exit;
11764: 	    }
11765: 
11766: 	    if (res != 0) {
11767: 		newContextSize++;
11768: 	    } else {
11769: 		/*
11770: 		* Remove the entry from the initial node set.
11771: 		*/
11772: 		set->nodeTab[i] = NULL;
11773: 		if (contextNode->type == XML_NAMESPACE_DECL)
11774: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11775: 	    }
11776: 	    if (ctxt->value == contextObj) {
11777: 		/*
11778: 		* Don't free the temporary XPath object holding the
11779: 		* context node, in order to avoid massive recreation
11780: 		* inside this loop.
11781: 		*/
11782: 		valuePop(ctxt);
11783: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11784: 	    } else {
11785: 		/*
11786: 		* TODO: The object was lost in the evaluation machinery.
11787: 		*  Can this happen? Maybe in internal-error cases.
11788: 		*/
11789: 		contextObj = NULL;
11790: 	    }
11791: 	}
11792: 
11793: 	if (contextObj != NULL) {
11794: 	    if (ctxt->value == contextObj)
11795: 		valuePop(ctxt);
11796: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11797: 	}
11798: evaluation_exit:
11799: 	if (exprRes != NULL)
11800: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11801: 	/*
11802: 	* Reset/invalidate the context.
11803: 	*/
11804: 	xpctxt->node = oldContextNode;
11805: 	xpctxt->doc = oldContextDoc;
11806: 	xpctxt->contextSize = -1;
11807: 	xpctxt->proximityPosition = -1;
11808: 	return(newContextSize);
11809:     }
11810:     return(contextSize);
11811: }
11812: 
11813: static int
11814: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11815: 				      xmlXPathStepOpPtr op,
11816: 				      xmlNodeSetPtr set,
11817: 				      int contextSize,
11818: 				      int minPos,
11819: 				      int maxPos,
11820: 				      int hasNsNodes)
11821: {
11822:     if (op->ch1 != -1) {
11823: 	xmlXPathCompExprPtr comp = ctxt->comp;
11824: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11825: 	    /*
11826: 	    * TODO: raise an internal error.
11827: 	    */
11828: 	}
11829: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11830: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11831: 	CHECK_ERROR0;
11832: 	if (contextSize <= 0)
11833: 	    return(0);
11834:     }
11835:     /*
11836:     * Check if the node set contains a sufficient number of nodes for
11837:     * the requested range.
11838:     */
11839:     if (contextSize < minPos) {
11840: 	xmlXPathNodeSetClear(set, hasNsNodes);
11841: 	return(0);
11842:     }
11843:     if (op->ch2 == -1) {
11844: 	/*
11845: 	* TODO: Can this ever happen?
11846: 	*/
11847: 	return (contextSize);
11848:     } else {
11849: 	xmlDocPtr oldContextDoc;
11850: 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11851: 	xmlXPathStepOpPtr exprOp;
11852: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11853: 	xmlNodePtr oldContextNode, contextNode = NULL;
11854: 	xmlXPathContextPtr xpctxt = ctxt->context;
11855:         int frame;
11856: 
11857: #ifdef LIBXML_XPTR_ENABLED
11858: 	    /*
11859: 	    * URGENT TODO: Check the following:
11860: 	    *  We don't expect location sets if evaluating prediates, right?
11861: 	    *  Only filters should expect location sets, right?
11862: 	*/
11863: #endif /* LIBXML_XPTR_ENABLED */
11864: 
11865: 	/*
11866: 	* Save old context.
11867: 	*/
11868: 	oldContextNode = xpctxt->node;
11869: 	oldContextDoc = xpctxt->doc;
11870: 	/*
11871: 	* Get the expression of this predicate.
11872: 	*/
11873: 	exprOp = &ctxt->comp->steps[op->ch2];
11874: 	for (i = 0; i < set->nodeNr; i++) {
11875:             xmlXPathObjectPtr tmp;
11876: 
11877: 	    if (set->nodeTab[i] == NULL)
11878: 		continue;
11879: 
11880: 	    contextNode = set->nodeTab[i];
11881: 	    xpctxt->node = contextNode;
11882: 	    xpctxt->contextSize = contextSize;
11883: 	    xpctxt->proximityPosition = ++contextPos;
11884: 
11885: 	    /*
11886: 	    * Initialize the new set.
11887: 	    * Also set the xpath document in case things like
11888: 	    * key() evaluation are attempted on the predicate
11889: 	    */
11890: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11891: 		(contextNode->doc != NULL))
11892: 		xpctxt->doc = contextNode->doc;
11893: 	    /*
11894: 	    * Evaluate the predicate expression with 1 context node
11895: 	    * at a time; this node is packaged into a node set; this
11896: 	    * node set is handed over to the evaluation mechanism.
11897: 	    */
11898: 	    if (contextObj == NULL)
11899: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11900: 	    else {
11901: 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11902: 		    contextNode) < 0) {
11903: 		    ctxt->error = XPATH_MEMORY_ERROR;
11904: 		    goto evaluation_exit;
11905: 		}
11906: 	    }
11907: 
11908:             frame = xmlXPathSetFrame(ctxt);
11909: 	    valuePush(ctxt, contextObj);
11910: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11911:             tmp = valuePop(ctxt);
11912:             xmlXPathPopFrame(ctxt, frame);
11913: 
11914: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11915:                 while (tmp != contextObj) {
11916:                     /*
11917:                      * Free up the result
11918:                      * then pop off contextObj, which will be freed later
11919:                      */
11920:                     xmlXPathReleaseObject(xpctxt, tmp);
11921:                     tmp = valuePop(ctxt);
11922:                 }
11923: 		goto evaluation_error;
11924: 	    }
11925:             /* push the result back onto the stack */
11926:             valuePush(ctxt, tmp);
11927: 
11928: 	    if (res)
11929: 		pos++;
11930: 
11931: 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11932: 		/*
11933: 		* Fits in the requested range.
11934: 		*/
11935: 		newContextSize++;
11936: 		if (minPos == maxPos) {
11937: 		    /*
11938: 		    * Only 1 node was requested.
11939: 		    */
11940: 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11941: 			/*
11942: 			* As always: take care of those nasty
11943: 			* namespace nodes.
11944: 			*/
11945: 			set->nodeTab[i] = NULL;
11946: 		    }
11947: 		    xmlXPathNodeSetClear(set, hasNsNodes);
11948: 		    set->nodeNr = 1;
11949: 		    set->nodeTab[0] = contextNode;
11950: 		    goto evaluation_exit;
11951: 		}
11952: 		if (pos == maxPos) {
11953: 		    /*
11954: 		    * We are done.
11955: 		    */
11956: 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11957: 		    goto evaluation_exit;
11958: 		}
11959: 	    } else {
11960: 		/*
11961: 		* Remove the entry from the initial node set.
11962: 		*/
11963: 		set->nodeTab[i] = NULL;
11964: 		if (contextNode->type == XML_NAMESPACE_DECL)
11965: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11966: 	    }
11967: 	    if (exprRes != NULL) {
11968: 		xmlXPathReleaseObject(ctxt->context, exprRes);
11969: 		exprRes = NULL;
11970: 	    }
11971: 	    if (ctxt->value == contextObj) {
11972: 		/*
11973: 		* Don't free the temporary XPath object holding the
11974: 		* context node, in order to avoid massive recreation
11975: 		* inside this loop.
11976: 		*/
11977: 		valuePop(ctxt);
11978: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11979: 	    } else {
11980: 		/*
11981: 		* The object was lost in the evaluation machinery.
11982: 		* Can this happen? Maybe in case of internal-errors.
11983: 		*/
11984: 		contextObj = NULL;
11985: 	    }
11986: 	}
11987: 	goto evaluation_exit;
11988: 
11989: evaluation_error:
11990: 	xmlXPathNodeSetClear(set, hasNsNodes);
11991: 	newContextSize = 0;
11992: 
11993: evaluation_exit:
11994: 	if (contextObj != NULL) {
11995: 	    if (ctxt->value == contextObj)
11996: 		valuePop(ctxt);
11997: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11998: 	}
11999: 	if (exprRes != NULL)
12000: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
12001: 	/*
12002: 	* Reset/invalidate the context.
12003: 	*/
12004: 	xpctxt->node = oldContextNode;
12005: 	xpctxt->doc = oldContextDoc;
12006: 	xpctxt->contextSize = -1;
12007: 	xpctxt->proximityPosition = -1;
12008: 	return(newContextSize);
12009:     }
12010:     return(contextSize);
12011: }
12012: 
12013: static int
12014: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12015: 			    xmlXPathStepOpPtr op,
12016: 			    int *maxPos)
12017: {
12018: 
12019:     xmlXPathStepOpPtr exprOp;
12020: 
12021:     /*
12022:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12023:     */
12024: 
12025:     /*
12026:     * If not -1, then ch1 will point to:
12027:     * 1) For predicates (XPATH_OP_PREDICATE):
12028:     *    - an inner predicate operator
12029:     * 2) For filters (XPATH_OP_FILTER):
12030:     *    - an inner filter operater OR
12031:     *    - an expression selecting the node set.
12032:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12033:     */
12034:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12035: 	return(0);
12036: 
12037:     if (op->ch2 != -1) {
12038: 	exprOp = &ctxt->comp->steps[op->ch2];
12039:     } else
12040: 	return(0);
12041: 
12042:     if ((exprOp != NULL) &&
12043: 	(exprOp->op == XPATH_OP_VALUE) &&
12044: 	(exprOp->value4 != NULL) &&
12045: 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12046:     {
12047: 	/*
12048: 	* We have a "[n]" predicate here.
12049: 	* TODO: Unfortunately this simplistic test here is not
12050: 	* able to detect a position() predicate in compound
12051: 	* expressions like "[@attr = 'a" and position() = 1],
12052: 	* and even not the usage of position() in
12053: 	* "[position() = 1]"; thus - obviously - a position-range,
12054: 	* like it "[position() < 5]", is also not detected.
12055: 	* Maybe we could rewrite the AST to ease the optimization.
12056: 	*/
12057: 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12058: 
12059: 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12060: 	    (float) *maxPos)
12061: 	{
12062: 	    return(1);
12063: 	}
12064:     }
12065:     return(0);
12066: }
12067: 
12068: static int
12069: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12070:                            xmlXPathStepOpPtr op,
12071: 			   xmlNodePtr * first, xmlNodePtr * last,
12072: 			   int toBool)
12073: {
12074: 
12075: #define XP_TEST_HIT \
12076:     if (hasAxisRange != 0) { \
12077: 	if (++pos == maxPos) { \
12078: 	    if (addNode(seq, cur) < 0) \
12079: 	        ctxt->error = XPATH_MEMORY_ERROR; \
12080: 	    goto axis_range_end; } \
12081:     } else { \
12082: 	if (addNode(seq, cur) < 0) \
12083: 	    ctxt->error = XPATH_MEMORY_ERROR; \
12084: 	if (breakOnFirstHit) goto first_hit; }
12085: 
12086: #define XP_TEST_HIT_NS \
12087:     if (hasAxisRange != 0) { \
12088: 	if (++pos == maxPos) { \
12089: 	    hasNsNodes = 1; \
12090: 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12091: 	        ctxt->error = XPATH_MEMORY_ERROR; \
12092: 	goto axis_range_end; } \
12093:     } else { \
12094: 	hasNsNodes = 1; \
12095: 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096: 	    ctxt->error = XPATH_MEMORY_ERROR; \
12097: 	if (breakOnFirstHit) goto first_hit; }
12098: 
12099:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12100:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12101:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12102:     const xmlChar *prefix = op->value4;
12103:     const xmlChar *name = op->value5;
12104:     const xmlChar *URI = NULL;
12105: 
12106: #ifdef DEBUG_STEP
12107:     int nbMatches = 0, prevMatches = 0;
12108: #endif
12109:     int total = 0, hasNsNodes = 0;
12110:     /* The popped object holding the context nodes */
12111:     xmlXPathObjectPtr obj;
12112:     /* The set of context nodes for the node tests */
12113:     xmlNodeSetPtr contextSeq;
12114:     int contextIdx;
12115:     xmlNodePtr contextNode;
12116:     /* The final resulting node set wrt to all context nodes */
12117:     xmlNodeSetPtr outSeq;
12118:     /*
12119:     * The temporary resulting node set wrt 1 context node.
12120:     * Used to feed predicate evaluation.
12121:     */
12122:     xmlNodeSetPtr seq;
12123:     xmlNodePtr cur;
12124:     /* First predicate operator */
12125:     xmlXPathStepOpPtr predOp;
12126:     int maxPos; /* The requested position() (when a "[n]" predicate) */
12127:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12128:     int breakOnFirstHit;
12129: 
12130:     xmlXPathTraversalFunction next = NULL;
12131:     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12132:     xmlXPathNodeSetMergeFunction mergeAndClear;
12133:     xmlNodePtr oldContextNode;
12134:     xmlXPathContextPtr xpctxt = ctxt->context;
12135: 
12136: 
12137:     CHECK_TYPE0(XPATH_NODESET);
12138:     obj = valuePop(ctxt);
12139:     /*
12140:     * Setup namespaces.
12141:     */
12142:     if (prefix != NULL) {
12143:         URI = xmlXPathNsLookup(xpctxt, prefix);
12144:         if (URI == NULL) {
12145: 	    xmlXPathReleaseObject(xpctxt, obj);
12146:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12147: 	}
12148:     }
12149:     /*
12150:     * Setup axis.
12151:     *
12152:     * MAYBE FUTURE TODO: merging optimizations:
12153:     * - If the nodes to be traversed wrt to the initial nodes and
12154:     *   the current axis cannot overlap, then we could avoid searching
12155:     *   for duplicates during the merge.
12156:     *   But the question is how/when to evaluate if they cannot overlap.
12157:     *   Example: if we know that for two initial nodes, the one is
12158:     *   not in the ancestor-or-self axis of the other, then we could safely
12159:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160:     *   the descendant-or-self axis.
12161:     */
12162:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12163:     switch (axis) {
12164:         case AXIS_ANCESTOR:
12165:             first = NULL;
12166:             next = xmlXPathNextAncestor;
12167:             break;
12168:         case AXIS_ANCESTOR_OR_SELF:
12169:             first = NULL;
12170:             next = xmlXPathNextAncestorOrSelf;
12171:             break;
12172:         case AXIS_ATTRIBUTE:
12173:             first = NULL;
12174: 	    last = NULL;
12175:             next = xmlXPathNextAttribute;
12176: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177:             break;
12178:         case AXIS_CHILD:
12179: 	    last = NULL;
12180: 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12181: 		(type == NODE_TYPE_NODE))
12182: 	    {
12183: 		/*
12184: 		* Optimization if an element node type is 'element'.
12185: 		*/
12186: 		next = xmlXPathNextChildElement;
12187: 	    } else
12188: 		next = xmlXPathNextChild;
12189: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12190:             break;
12191:         case AXIS_DESCENDANT:
12192: 	    last = NULL;
12193:             next = xmlXPathNextDescendant;
12194:             break;
12195:         case AXIS_DESCENDANT_OR_SELF:
12196: 	    last = NULL;
12197:             next = xmlXPathNextDescendantOrSelf;
12198:             break;
12199:         case AXIS_FOLLOWING:
12200: 	    last = NULL;
12201:             next = xmlXPathNextFollowing;
12202:             break;
12203:         case AXIS_FOLLOWING_SIBLING:
12204: 	    last = NULL;
12205:             next = xmlXPathNextFollowingSibling;
12206:             break;
12207:         case AXIS_NAMESPACE:
12208:             first = NULL;
12209: 	    last = NULL;
12210:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12211: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212:             break;
12213:         case AXIS_PARENT:
12214:             first = NULL;
12215:             next = xmlXPathNextParent;
12216:             break;
12217:         case AXIS_PRECEDING:
12218:             first = NULL;
12219:             next = xmlXPathNextPrecedingInternal;
12220:             break;
12221:         case AXIS_PRECEDING_SIBLING:
12222:             first = NULL;
12223:             next = xmlXPathNextPrecedingSibling;
12224:             break;
12225:         case AXIS_SELF:
12226:             first = NULL;
12227: 	    last = NULL;
12228:             next = xmlXPathNextSelf;
12229: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12230:             break;
12231:     }
12232: 
12233: #ifdef DEBUG_STEP
12234:     xmlXPathDebugDumpStepAxis(op,
12235: 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12236: #endif
12237: 
12238:     if (next == NULL) {
12239: 	xmlXPathReleaseObject(xpctxt, obj);
12240:         return(0);
12241:     }
12242:     contextSeq = obj->nodesetval;
12243:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12244: 	xmlXPathReleaseObject(xpctxt, obj);
12245:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12246:         return(0);
12247:     }
12248:     /*
12249:     * Predicate optimization ---------------------------------------------
12250:     * If this step has a last predicate, which contains a position(),
12251:     * then we'll optimize (although not exactly "position()", but only
12252:     * the  short-hand form, i.e., "[n]".
12253:     *
12254:     * Example - expression "/foo[parent::bar][1]":
12255:     *
12256:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12257:     *   ROOT                               -- op->ch1
12258:     *   PREDICATE                          -- op->ch2 (predOp)
12259:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12260:     *       SORT
12261:     *         COLLECT  'parent' 'name' 'node' bar
12262:     *           NODE
12263:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12264:     *
12265:     */
12266:     maxPos = 0;
12267:     predOp = NULL;
12268:     hasPredicateRange = 0;
12269:     hasAxisRange = 0;
12270:     if (op->ch2 != -1) {
12271: 	/*
12272: 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12273: 	*/
12274: 	predOp = &ctxt->comp->steps[op->ch2];
12275: 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12276: 	    if (predOp->ch1 != -1) {
12277: 		/*
12278: 		* Use the next inner predicate operator.
12279: 		*/
12280: 		predOp = &ctxt->comp->steps[predOp->ch1];
12281: 		hasPredicateRange = 1;
12282: 	    } else {
12283: 		/*
12284: 		* There's no other predicate than the [n] predicate.
12285: 		*/
12286: 		predOp = NULL;
12287: 		hasAxisRange = 1;
12288: 	    }
12289: 	}
12290:     }
12291:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12292:     /*
12293:     * Axis traversal -----------------------------------------------------
12294:     */
12295:     /*
12296:      * 2.3 Node Tests
12297:      *  - For the attribute axis, the principal node type is attribute.
12298:      *  - For the namespace axis, the principal node type is namespace.
12299:      *  - For other axes, the principal node type is element.
12300:      *
12301:      * A node test * is true for any node of the
12302:      * principal node type. For example, child::* will
12303:      * select all element children of the context node
12304:      */
12305:     oldContextNode = xpctxt->node;
12306:     addNode = xmlXPathNodeSetAddUnique;
12307:     outSeq = NULL;
12308:     seq = NULL;
12309:     contextNode = NULL;
12310:     contextIdx = 0;
12311: 
12312: 
12313:     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12314:            (ctxt->error == XPATH_EXPRESSION_OK)) {
12315: 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12316: 
12317: 	if (seq == NULL) {
12318: 	    seq = xmlXPathNodeSetCreate(NULL);
12319: 	    if (seq == NULL) {
12320: 		total = 0;
12321: 		goto error;
12322: 	    }
12323: 	}
12324: 	/*
12325: 	* Traverse the axis and test the nodes.
12326: 	*/
12327: 	pos = 0;
12328: 	cur = NULL;
12329: 	hasNsNodes = 0;
12330:         do {
12331:             cur = next(ctxt, cur);
12332:             if (cur == NULL)
12333:                 break;
12334: 
12335: 	    /*
12336: 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12337: 	    */
12338:             if ((first != NULL) && (*first != NULL)) {
12339: 		if (*first == cur)
12340: 		    break;
12341: 		if (((total % 256) == 0) &&
12342: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343: 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12344: #else
12345: 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12346: #endif
12347: 		{
12348: 		    break;
12349: 		}
12350: 	    }
12351: 	    if ((last != NULL) && (*last != NULL)) {
12352: 		if (*last == cur)
12353: 		    break;
12354: 		if (((total % 256) == 0) &&
12355: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12356: 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12357: #else
12358: 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12359: #endif
12360: 		{
12361: 		    break;
12362: 		}
12363: 	    }
12364: 
12365:             total++;
12366: 
12367: #ifdef DEBUG_STEP
12368:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12369: #endif
12370: 
12371: 	    switch (test) {
12372:                 case NODE_TEST_NONE:
12373: 		    total = 0;
12374:                     STRANGE
12375: 		    goto error;
12376:                 case NODE_TEST_TYPE:
12377: 		    /*
12378: 		    * TODO: Don't we need to use
12379: 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12380: 		    *  Surprisingly, some c14n tests fail, if we do this.
12381: 		    */
12382: 		    if (type == NODE_TYPE_NODE) {
12383: 			switch (cur->type) {
12384: 			    case XML_DOCUMENT_NODE:
12385: 			    case XML_HTML_DOCUMENT_NODE:
12386: #ifdef LIBXML_DOCB_ENABLED
12387: 			    case XML_DOCB_DOCUMENT_NODE:
12388: #endif
12389: 			    case XML_ELEMENT_NODE:
12390: 			    case XML_ATTRIBUTE_NODE:
12391: 			    case XML_PI_NODE:
12392: 			    case XML_COMMENT_NODE:
12393: 			    case XML_CDATA_SECTION_NODE:
12394: 			    case XML_TEXT_NODE:
12395: 			    case XML_NAMESPACE_DECL:
12396: 				XP_TEST_HIT
12397: 				break;
12398: 			    default:
12399: 				break;
12400: 			}
12401: 		    } else if (cur->type == type) {
12402: 			if (cur->type == XML_NAMESPACE_DECL)
12403: 			    XP_TEST_HIT_NS
12404: 			else
12405: 			    XP_TEST_HIT
12406: 		    } else if ((type == NODE_TYPE_TEXT) &&
12407: 			 (cur->type == XML_CDATA_SECTION_NODE))
12408: 		    {
12409: 			XP_TEST_HIT
12410: 		    }
12411: 		    break;
12412:                 case NODE_TEST_PI:
12413:                     if ((cur->type == XML_PI_NODE) &&
12414:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12415: 		    {
12416: 			XP_TEST_HIT
12417:                     }
12418:                     break;
12419:                 case NODE_TEST_ALL:
12420:                     if (axis == AXIS_ATTRIBUTE) {
12421:                         if (cur->type == XML_ATTRIBUTE_NODE)
12422: 			{
12423: 			    XP_TEST_HIT
12424:                         }
12425:                     } else if (axis == AXIS_NAMESPACE) {
12426:                         if (cur->type == XML_NAMESPACE_DECL)
12427: 			{
12428: 			    XP_TEST_HIT_NS
12429:                         }
12430:                     } else {
12431:                         if (cur->type == XML_ELEMENT_NODE) {
12432:                             if (prefix == NULL)
12433: 			    {
12434: 				XP_TEST_HIT
12435: 
12436:                             } else if ((cur->ns != NULL) &&
12437: 				(xmlStrEqual(URI, cur->ns->href)))
12438: 			    {
12439: 				XP_TEST_HIT
12440:                             }
12441:                         }
12442:                     }
12443:                     break;
12444:                 case NODE_TEST_NS:{
12445:                         TODO;
12446:                         break;
12447:                     }
12448:                 case NODE_TEST_NAME:
12449:                     if (axis == AXIS_ATTRIBUTE) {
12450:                         if (cur->type != XML_ATTRIBUTE_NODE)
12451: 			    break;
12452: 		    } else if (axis == AXIS_NAMESPACE) {
12453:                         if (cur->type != XML_NAMESPACE_DECL)
12454: 			    break;
12455: 		    } else {
12456: 		        if (cur->type != XML_ELEMENT_NODE)
12457: 			    break;
12458: 		    }
12459:                     switch (cur->type) {
12460:                         case XML_ELEMENT_NODE:
12461:                             if (xmlStrEqual(name, cur->name)) {
12462:                                 if (prefix == NULL) {
12463:                                     if (cur->ns == NULL)
12464: 				    {
12465: 					XP_TEST_HIT
12466:                                     }
12467:                                 } else {
12468:                                     if ((cur->ns != NULL) &&
12469:                                         (xmlStrEqual(URI, cur->ns->href)))
12470: 				    {
12471: 					XP_TEST_HIT
12472:                                     }
12473:                                 }
12474:                             }
12475:                             break;
12476:                         case XML_ATTRIBUTE_NODE:{
12477:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12478: 
12479:                                 if (xmlStrEqual(name, attr->name)) {
12480:                                     if (prefix == NULL) {
12481:                                         if ((attr->ns == NULL) ||
12482:                                             (attr->ns->prefix == NULL))
12483: 					{
12484: 					    XP_TEST_HIT
12485:                                         }
12486:                                     } else {
12487:                                         if ((attr->ns != NULL) &&
12488:                                             (xmlStrEqual(URI,
12489: 					      attr->ns->href)))
12490: 					{
12491: 					    XP_TEST_HIT
12492:                                         }
12493:                                     }
12494:                                 }
12495:                                 break;
12496:                             }
12497:                         case XML_NAMESPACE_DECL:
12498:                             if (cur->type == XML_NAMESPACE_DECL) {
12499:                                 xmlNsPtr ns = (xmlNsPtr) cur;
12500: 
12501:                                 if ((ns->prefix != NULL) && (name != NULL)
12502:                                     && (xmlStrEqual(ns->prefix, name)))
12503: 				{
12504: 				    XP_TEST_HIT_NS
12505:                                 }
12506:                             }
12507:                             break;
12508:                         default:
12509:                             break;
12510:                     }
12511:                     break;
12512: 	    } /* switch(test) */
12513:         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12514: 
12515: 	goto apply_predicates;
12516: 
12517: axis_range_end: /* ----------------------------------------------------- */
12518: 	/*
12519: 	* We have a "/foo[n]", and position() = n was reached.
12520: 	* Note that we can have as well "/foo/::parent::foo[1]", so
12521: 	* a duplicate-aware merge is still needed.
12522: 	* Merge with the result.
12523: 	*/
12524: 	if (outSeq == NULL) {
12525: 	    outSeq = seq;
12526: 	    seq = NULL;
12527: 	} else
12528: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12529: 	/*
12530: 	* Break if only a true/false result was requested.
12531: 	*/
12532: 	if (toBool)
12533: 	    break;
12534: 	continue;
12535: 
12536: first_hit: /* ---------------------------------------------------------- */
12537: 	/*
12538: 	* Break if only a true/false result was requested and
12539: 	* no predicates existed and a node test succeeded.
12540: 	*/
12541: 	if (outSeq == NULL) {
12542: 	    outSeq = seq;
12543: 	    seq = NULL;
12544: 	} else
12545: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12546: 	break;
12547: 
12548: #ifdef DEBUG_STEP
12549: 	if (seq != NULL)
12550: 	    nbMatches += seq->nodeNr;
12551: #endif
12552: 
12553: apply_predicates: /* --------------------------------------------------- */
12554:         if (ctxt->error != XPATH_EXPRESSION_OK)
12555: 	    goto error;
12556: 
12557:         /*
12558: 	* Apply predicates.
12559: 	*/
12560:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12561: 	    /*
12562: 	    * E.g. when we have a "/foo[some expression][n]".
12563: 	    */
12564: 	    /*
12565: 	    * QUESTION TODO: The old predicate evaluation took into
12566: 	    *  account location-sets.
12567: 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568: 	    *  Do we expect such a set here?
12569: 	    *  All what I learned now from the evaluation semantics
12570: 	    *  does not indicate that a location-set will be processed
12571: 	    *  here, so this looks OK.
12572: 	    */
12573: 	    /*
12574: 	    * Iterate over all predicates, starting with the outermost
12575: 	    * predicate.
12576: 	    * TODO: Problem: we cannot execute the inner predicates first
12577: 	    *  since we cannot go back *up* the operator tree!
12578: 	    *  Options we have:
12579: 	    *  1) Use of recursive functions (like is it currently done
12580: 	    *     via xmlXPathCompOpEval())
12581: 	    *  2) Add a predicate evaluation information stack to the
12582: 	    *     context struct
12583: 	    *  3) Change the way the operators are linked; we need a
12584: 	    *     "parent" field on xmlXPathStepOp
12585: 	    *
12586: 	    * For the moment, I'll try to solve this with a recursive
12587: 	    * function: xmlXPathCompOpEvalPredicate().
12588: 	    */
12589: 	    size = seq->nodeNr;
12590: 	    if (hasPredicateRange != 0)
12591: 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12592: 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12593: 	    else
12594: 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12595: 		    predOp, seq, size, hasNsNodes);
12596: 
12597: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12598: 		total = 0;
12599: 		goto error;
12600: 	    }
12601: 	    /*
12602: 	    * Add the filtered set of nodes to the result node set.
12603: 	    */
12604: 	    if (newSize == 0) {
12605: 		/*
12606: 		* The predicates filtered all nodes out.
12607: 		*/
12608: 		xmlXPathNodeSetClear(seq, hasNsNodes);
12609: 	    } else if (seq->nodeNr > 0) {
12610: 		/*
12611: 		* Add to result set.
12612: 		*/
12613: 		if (outSeq == NULL) {
12614: 		    if (size != newSize) {
12615: 			/*
12616: 			* We need to merge and clear here, since
12617: 			* the sequence will contained NULLed entries.
12618: 			*/
12619: 			outSeq = mergeAndClear(NULL, seq, 1);
12620: 		    } else {
12621: 			outSeq = seq;
12622: 			seq = NULL;
12623: 		    }
12624: 		} else
12625: 		    outSeq = mergeAndClear(outSeq, seq,
12626: 			(size != newSize) ? 1: 0);
12627: 		/*
12628: 		* Break if only a true/false result was requested.
12629: 		*/
12630: 		if (toBool)
12631: 		    break;
12632: 	    }
12633:         } else if (seq->nodeNr > 0) {
12634: 	    /*
12635: 	    * Add to result set.
12636: 	    */
12637: 	    if (outSeq == NULL) {
12638: 		outSeq = seq;
12639: 		seq = NULL;
12640: 	    } else {
12641: 		outSeq = mergeAndClear(outSeq, seq, 0);
12642: 	    }
12643: 	}
12644:     }
12645: 
12646: error:
12647:     if ((obj->boolval) && (obj->user != NULL)) {
12648: 	/*
12649: 	* QUESTION TODO: What does this do and why?
12650: 	* TODO: Do we have to do this also for the "error"
12651: 	* cleanup further down?
12652: 	*/
12653: 	ctxt->value->boolval = 1;
12654: 	ctxt->value->user = obj->user;
12655: 	obj->user = NULL;
12656: 	obj->boolval = 0;
12657:     }
12658:     xmlXPathReleaseObject(xpctxt, obj);
12659: 
12660:     /*
12661:     * Ensure we return at least an emtpy set.
12662:     */
12663:     if (outSeq == NULL) {
12664: 	if ((seq != NULL) && (seq->nodeNr == 0))
12665: 	    outSeq = seq;
12666: 	else
12667: 	    outSeq = xmlXPathNodeSetCreate(NULL);
12668:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12669:     }
12670:     if ((seq != NULL) && (seq != outSeq)) {
12671: 	 xmlXPathFreeNodeSet(seq);
12672:     }
12673:     /*
12674:     * Hand over the result. Better to push the set also in
12675:     * case of errors.
12676:     */
12677:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12678:     /*
12679:     * Reset the context node.
12680:     */
12681:     xpctxt->node = oldContextNode;
12682: 
12683: #ifdef DEBUG_STEP
12684:     xmlGenericError(xmlGenericErrorContext,
12685: 	"\nExamined %d nodes, found %d nodes at that step\n",
12686: 	total, nbMatches);
12687: #endif
12688: 
12689:     return(total);
12690: }
12691: 
12692: static int
12693: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12694: 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12695: 
12696: /**
12697:  * xmlXPathCompOpEvalFirst:
12698:  * @ctxt:  the XPath parser context with the compiled expression
12699:  * @op:  an XPath compiled operation
12700:  * @first:  the first elem found so far
12701:  *
12702:  * Evaluate the Precompiled XPath operation searching only the first
12703:  * element in document order
12704:  *
12705:  * Returns the number of examined objects.
12706:  */
12707: static int
12708: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12709:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12710: {
12711:     int total = 0, cur;
12712:     xmlXPathCompExprPtr comp;
12713:     xmlXPathObjectPtr arg1, arg2;
12714: 
12715:     CHECK_ERROR0;
12716:     comp = ctxt->comp;
12717:     switch (op->op) {
12718:         case XPATH_OP_END:
12719:             return (0);
12720:         case XPATH_OP_UNION:
12721:             total =
12722:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12723:                                         first);
12724: 	    CHECK_ERROR0;
12725:             if ((ctxt->value != NULL)
12726:                 && (ctxt->value->type == XPATH_NODESET)
12727:                 && (ctxt->value->nodesetval != NULL)
12728:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12729:                 /*
12730:                  * limit tree traversing to first node in the result
12731:                  */
12732: 		/*
12733: 		* OPTIMIZE TODO: This implicitely sorts
12734: 		*  the result, even if not needed. E.g. if the argument
12735: 		*  of the count() function, no sorting is needed.
12736: 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12737: 		*  aready sorted?
12738: 		*/
12739: 		if (ctxt->value->nodesetval->nodeNr > 1)
12740: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741:                 *first = ctxt->value->nodesetval->nodeTab[0];
12742:             }
12743:             cur =
12744:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12745:                                         first);
12746: 	    CHECK_ERROR0;
12747:             CHECK_TYPE0(XPATH_NODESET);
12748:             arg2 = valuePop(ctxt);
12749: 
12750:             CHECK_TYPE0(XPATH_NODESET);
12751:             arg1 = valuePop(ctxt);
12752: 
12753:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12754:                                                     arg2->nodesetval);
12755:             valuePush(ctxt, arg1);
12756: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12757:             /* optimizer */
12758: 	    if (total > cur)
12759: 		xmlXPathCompSwap(op);
12760:             return (total + cur);
12761:         case XPATH_OP_ROOT:
12762:             xmlXPathRoot(ctxt);
12763:             return (0);
12764:         case XPATH_OP_NODE:
12765:             if (op->ch1 != -1)
12766:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767: 	    CHECK_ERROR0;
12768:             if (op->ch2 != -1)
12769:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12770: 	    CHECK_ERROR0;
12771: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12772: 		ctxt->context->node));
12773:             return (total);
12774:         case XPATH_OP_RESET:
12775:             if (op->ch1 != -1)
12776:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12777: 	    CHECK_ERROR0;
12778:             if (op->ch2 != -1)
12779:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12780: 	    CHECK_ERROR0;
12781:             ctxt->context->node = NULL;
12782:             return (total);
12783:         case XPATH_OP_COLLECT:{
12784:                 if (op->ch1 == -1)
12785:                     return (total);
12786: 
12787:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788: 		CHECK_ERROR0;
12789: 
12790:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791:                 return (total);
12792:             }
12793:         case XPATH_OP_VALUE:
12794:             valuePush(ctxt,
12795:                       xmlXPathCacheObjectCopy(ctxt->context,
12796: 			(xmlXPathObjectPtr) op->value4));
12797:             return (0);
12798:         case XPATH_OP_SORT:
12799:             if (op->ch1 != -1)
12800:                 total +=
12801:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802:                                             first);
12803: 	    CHECK_ERROR0;
12804:             if ((ctxt->value != NULL)
12805:                 && (ctxt->value->type == XPATH_NODESET)
12806:                 && (ctxt->value->nodesetval != NULL)
12807: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12808:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809:             return (total);
12810: #ifdef XP_OPTIMIZED_FILTER_FIRST
12811: 	case XPATH_OP_FILTER:
12812:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813:             return (total);
12814: #endif
12815:         default:
12816:             return (xmlXPathCompOpEval(ctxt, op));
12817:     }
12818: }
12819: 
12820: /**
12821:  * xmlXPathCompOpEvalLast:
12822:  * @ctxt:  the XPath parser context with the compiled expression
12823:  * @op:  an XPath compiled operation
12824:  * @last:  the last elem found so far
12825:  *
12826:  * Evaluate the Precompiled XPath operation searching only the last
12827:  * element in document order
12828:  *
12829:  * Returns the number of nodes traversed
12830:  */
12831: static int
12832: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833:                        xmlNodePtr * last)
12834: {
12835:     int total = 0, cur;
12836:     xmlXPathCompExprPtr comp;
12837:     xmlXPathObjectPtr arg1, arg2;
12838:     xmlNodePtr bak;
12839:     xmlDocPtr bakd;
12840:     int pp;
12841:     int cs;
12842: 
12843:     CHECK_ERROR0;
12844:     comp = ctxt->comp;
12845:     switch (op->op) {
12846:         case XPATH_OP_END:
12847:             return (0);
12848:         case XPATH_OP_UNION:
12849: 	    bakd = ctxt->context->doc;
12850: 	    bak = ctxt->context->node;
12851: 	    pp = ctxt->context->proximityPosition;
12852: 	    cs = ctxt->context->contextSize;
12853:             total =
12854:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12855: 	    CHECK_ERROR0;
12856:             if ((ctxt->value != NULL)
12857:                 && (ctxt->value->type == XPATH_NODESET)
12858:                 && (ctxt->value->nodesetval != NULL)
12859:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12860:                 /*
12861:                  * limit tree traversing to first node in the result
12862:                  */
12863: 		if (ctxt->value->nodesetval->nodeNr > 1)
12864: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12865:                 *last =
12866:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12867:                                                      nodesetval->nodeNr -
12868:                                                      1];
12869:             }
12870: 	    ctxt->context->doc = bakd;
12871: 	    ctxt->context->node = bak;
12872: 	    ctxt->context->proximityPosition = pp;
12873: 	    ctxt->context->contextSize = cs;
12874:             cur =
12875:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12876: 	    CHECK_ERROR0;
12877:             if ((ctxt->value != NULL)
12878:                 && (ctxt->value->type == XPATH_NODESET)
12879:                 && (ctxt->value->nodesetval != NULL)
12880:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12881:             }
12882:             CHECK_TYPE0(XPATH_NODESET);
12883:             arg2 = valuePop(ctxt);
12884: 
12885:             CHECK_TYPE0(XPATH_NODESET);
12886:             arg1 = valuePop(ctxt);
12887: 
12888:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12889:                                                     arg2->nodesetval);
12890:             valuePush(ctxt, arg1);
12891: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12892:             /* optimizer */
12893: 	    if (total > cur)
12894: 		xmlXPathCompSwap(op);
12895:             return (total + cur);
12896:         case XPATH_OP_ROOT:
12897:             xmlXPathRoot(ctxt);
12898:             return (0);
12899:         case XPATH_OP_NODE:
12900:             if (op->ch1 != -1)
12901:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12902: 	    CHECK_ERROR0;
12903:             if (op->ch2 != -1)
12904:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12905: 	    CHECK_ERROR0;
12906: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12907: 		ctxt->context->node));
12908:             return (total);
12909:         case XPATH_OP_RESET:
12910:             if (op->ch1 != -1)
12911:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12912: 	    CHECK_ERROR0;
12913:             if (op->ch2 != -1)
12914:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915: 	    CHECK_ERROR0;
12916:             ctxt->context->node = NULL;
12917:             return (total);
12918:         case XPATH_OP_COLLECT:{
12919:                 if (op->ch1 == -1)
12920:                     return (0);
12921: 
12922:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923: 		CHECK_ERROR0;
12924: 
12925:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12926:                 return (total);
12927:             }
12928:         case XPATH_OP_VALUE:
12929:             valuePush(ctxt,
12930:                       xmlXPathCacheObjectCopy(ctxt->context,
12931: 			(xmlXPathObjectPtr) op->value4));
12932:             return (0);
12933:         case XPATH_OP_SORT:
12934:             if (op->ch1 != -1)
12935:                 total +=
12936:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12937:                                            last);
12938: 	    CHECK_ERROR0;
12939:             if ((ctxt->value != NULL)
12940:                 && (ctxt->value->type == XPATH_NODESET)
12941:                 && (ctxt->value->nodesetval != NULL)
12942: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12943:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12944:             return (total);
12945:         default:
12946:             return (xmlXPathCompOpEval(ctxt, op));
12947:     }
12948: }
12949: 
12950: #ifdef XP_OPTIMIZED_FILTER_FIRST
12951: static int
12952: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12953: 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12954: {
12955:     int total = 0;
12956:     xmlXPathCompExprPtr comp;
12957:     xmlXPathObjectPtr res;
12958:     xmlXPathObjectPtr obj;
12959:     xmlNodeSetPtr oldset;
12960:     xmlNodePtr oldnode;
12961:     xmlDocPtr oldDoc;
12962:     int i;
12963: 
12964:     CHECK_ERROR0;
12965:     comp = ctxt->comp;
12966:     /*
12967:     * Optimization for ()[last()] selection i.e. the last elem
12968:     */
12969:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12970: 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12971: 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12972: 	int f = comp->steps[op->ch2].ch1;
12973: 
12974: 	if ((f != -1) &&
12975: 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12976: 	    (comp->steps[f].value5 == NULL) &&
12977: 	    (comp->steps[f].value == 0) &&
12978: 	    (comp->steps[f].value4 != NULL) &&
12979: 	    (xmlStrEqual
12980: 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12981: 	    xmlNodePtr last = NULL;
12982: 
12983: 	    total +=
12984: 		xmlXPathCompOpEvalLast(ctxt,
12985: 		    &comp->steps[op->ch1],
12986: 		    &last);
12987: 	    CHECK_ERROR0;
12988: 	    /*
12989: 	    * The nodeset should be in document order,
12990: 	    * Keep only the last value
12991: 	    */
12992: 	    if ((ctxt->value != NULL) &&
12993: 		(ctxt->value->type == XPATH_NODESET) &&
12994: 		(ctxt->value->nodesetval != NULL) &&
12995: 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12996: 		(ctxt->value->nodesetval->nodeNr > 1)) {
12997: 		ctxt->value->nodesetval->nodeTab[0] =
12998: 		    ctxt->value->nodesetval->nodeTab[ctxt->
12999: 		    value->
13000: 		    nodesetval->
13001: 		    nodeNr -
13002: 		    1];
13003: 		ctxt->value->nodesetval->nodeNr = 1;
13004: 		*first = *(ctxt->value->nodesetval->nodeTab);
13005: 	    }
13006: 	    return (total);
13007: 	}
13008:     }
13009: 
13010:     if (op->ch1 != -1)
13011: 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012:     CHECK_ERROR0;
13013:     if (op->ch2 == -1)
13014: 	return (total);
13015:     if (ctxt->value == NULL)
13016: 	return (total);
13017: 
13018: #ifdef LIBXML_XPTR_ENABLED
13019:     oldnode = ctxt->context->node;
13020:     /*
13021:     * Hum are we filtering the result of an XPointer expression
13022:     */
13023:     if (ctxt->value->type == XPATH_LOCATIONSET) {
13024: 	xmlXPathObjectPtr tmp = NULL;
13025: 	xmlLocationSetPtr newlocset = NULL;
13026: 	xmlLocationSetPtr oldlocset;
13027: 
13028: 	/*
13029: 	* Extract the old locset, and then evaluate the result of the
13030: 	* expression for all the element in the locset. use it to grow
13031: 	* up a new locset.
13032: 	*/
13033: 	CHECK_TYPE0(XPATH_LOCATIONSET);
13034: 	obj = valuePop(ctxt);
13035: 	oldlocset = obj->user;
13036: 	ctxt->context->node = NULL;
13037: 
13038: 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13039: 	    ctxt->context->contextSize = 0;
13040: 	    ctxt->context->proximityPosition = 0;
13041: 	    if (op->ch2 != -1)
13042: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13043: 	    res = valuePop(ctxt);
13044: 	    if (res != NULL) {
13045: 		xmlXPathReleaseObject(ctxt->context, res);
13046: 	    }
13047: 	    valuePush(ctxt, obj);
13048: 	    CHECK_ERROR0;
13049: 	    return (total);
13050: 	}
13051: 	newlocset = xmlXPtrLocationSetCreate(NULL);
13052: 
13053: 	for (i = 0; i < oldlocset->locNr; i++) {
13054: 	    /*
13055: 	    * Run the evaluation with a node list made of a
13056: 	    * single item in the nodelocset.
13057: 	    */
13058: 	    ctxt->context->node = oldlocset->locTab[i]->user;
13059: 	    ctxt->context->contextSize = oldlocset->locNr;
13060: 	    ctxt->context->proximityPosition = i + 1;
13061: 	    if (tmp == NULL) {
13062: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13063: 		    ctxt->context->node);
13064: 	    } else {
13065: 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13066: 		                             ctxt->context->node) < 0) {
13067: 		    ctxt->error = XPATH_MEMORY_ERROR;
13068: 		}
13069: 	    }
13070: 	    valuePush(ctxt, tmp);
13071: 	    if (op->ch2 != -1)
13072: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13073: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13074: 		xmlXPathFreeObject(obj);
13075: 		return(0);
13076: 	    }
13077: 	    /*
13078: 	    * The result of the evaluation need to be tested to
13079: 	    * decided whether the filter succeeded or not
13080: 	    */
13081: 	    res = valuePop(ctxt);
13082: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13083: 		xmlXPtrLocationSetAdd(newlocset,
13084: 		    xmlXPathCacheObjectCopy(ctxt->context,
13085: 			oldlocset->locTab[i]));
13086: 	    }
13087: 	    /*
13088: 	    * Cleanup
13089: 	    */
13090: 	    if (res != NULL) {
13091: 		xmlXPathReleaseObject(ctxt->context, res);
13092: 	    }
13093: 	    if (ctxt->value == tmp) {
13094: 		valuePop(ctxt);
13095: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13096: 		/*
13097: 		* REVISIT TODO: Don't create a temporary nodeset
13098: 		* for everly iteration.
13099: 		*/
13100: 		/* OLD: xmlXPathFreeObject(res); */
13101: 	    } else
13102: 		tmp = NULL;
13103: 	    ctxt->context->node = NULL;
13104: 	    /*
13105: 	    * Only put the first node in the result, then leave.
13106: 	    */
13107: 	    if (newlocset->locNr > 0) {
13108: 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13109: 		break;
13110: 	    }
13111: 	}
13112: 	if (tmp != NULL) {
13113: 	    xmlXPathReleaseObject(ctxt->context, tmp);
13114: 	}
13115: 	/*
13116: 	* The result is used as the new evaluation locset.
13117: 	*/
13118: 	xmlXPathReleaseObject(ctxt->context, obj);
13119: 	ctxt->context->node = NULL;
13120: 	ctxt->context->contextSize = -1;
13121: 	ctxt->context->proximityPosition = -1;
13122: 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13123: 	ctxt->context->node = oldnode;
13124: 	return (total);
13125:     }
13126: #endif /* LIBXML_XPTR_ENABLED */
13127: 
13128:     /*
13129:     * Extract the old set, and then evaluate the result of the
13130:     * expression for all the element in the set. use it to grow
13131:     * up a new set.
13132:     */
13133:     CHECK_TYPE0(XPATH_NODESET);
13134:     obj = valuePop(ctxt);
13135:     oldset = obj->nodesetval;
13136: 
13137:     oldnode = ctxt->context->node;
13138:     oldDoc = ctxt->context->doc;
13139:     ctxt->context->node = NULL;
13140: 
13141:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13142: 	ctxt->context->contextSize = 0;
13143: 	ctxt->context->proximityPosition = 0;
13144: 	/* QUESTION TODO: Why was this code commented out?
13145: 	    if (op->ch2 != -1)
13146: 		total +=
13147: 		    xmlXPathCompOpEval(ctxt,
13148: 			&comp->steps[op->ch2]);
13149: 	    CHECK_ERROR0;
13150: 	    res = valuePop(ctxt);
13151: 	    if (res != NULL)
13152: 		xmlXPathFreeObject(res);
13153: 	*/
13154: 	valuePush(ctxt, obj);
13155: 	ctxt->context->node = oldnode;
13156: 	CHECK_ERROR0;
13157:     } else {
13158: 	xmlNodeSetPtr newset;
13159: 	xmlXPathObjectPtr tmp = NULL;
13160: 	/*
13161: 	* Initialize the new set.
13162: 	* Also set the xpath document in case things like
13163: 	* key() evaluation are attempted on the predicate
13164: 	*/
13165: 	newset = xmlXPathNodeSetCreate(NULL);
13166:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13167: 
13168: 	for (i = 0; i < oldset->nodeNr; i++) {
13169: 	    /*
13170: 	    * Run the evaluation with a node list made of
13171: 	    * a single item in the nodeset.
13172: 	    */
13173: 	    ctxt->context->node = oldset->nodeTab[i];
13174: 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13175: 		(oldset->nodeTab[i]->doc != NULL))
13176: 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13177: 	    if (tmp == NULL) {
13178: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13179: 		    ctxt->context->node);
13180: 	    } else {
13181: 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13182: 		                             ctxt->context->node) < 0) {
13183: 		    ctxt->error = XPATH_MEMORY_ERROR;
13184: 		}
13185: 	    }
13186: 	    valuePush(ctxt, tmp);
13187: 	    ctxt->context->contextSize = oldset->nodeNr;
13188: 	    ctxt->context->proximityPosition = i + 1;
13189: 	    if (op->ch2 != -1)
13190: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13191: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13192: 		xmlXPathFreeNodeSet(newset);
13193: 		xmlXPathFreeObject(obj);
13194: 		return(0);
13195: 	    }
13196: 	    /*
13197: 	    * The result of the evaluation needs to be tested to
13198: 	    * decide whether the filter succeeded or not
13199: 	    */
13200: 	    res = valuePop(ctxt);
13201: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13202: 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13203: 		    ctxt->error = XPATH_MEMORY_ERROR;
13204: 	    }
13205: 	    /*
13206: 	    * Cleanup
13207: 	    */
13208: 	    if (res != NULL) {
13209: 		xmlXPathReleaseObject(ctxt->context, res);
13210: 	    }
13211: 	    if (ctxt->value == tmp) {
13212: 		valuePop(ctxt);
13213: 		/*
13214: 		* Don't free the temporary nodeset
13215: 		* in order to avoid massive recreation inside this
13216: 		* loop.
13217: 		*/
13218: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13219: 	    } else
13220: 		tmp = NULL;
13221: 	    ctxt->context->node = NULL;
13222: 	    /*
13223: 	    * Only put the first node in the result, then leave.
13224: 	    */
13225: 	    if (newset->nodeNr > 0) {
13226: 		*first = *(newset->nodeTab);
13227: 		break;
13228: 	    }
13229: 	}
13230: 	if (tmp != NULL) {
13231: 	    xmlXPathReleaseObject(ctxt->context, tmp);
13232: 	}
13233: 	/*
13234: 	* The result is used as the new evaluation set.
13235: 	*/
13236: 	xmlXPathReleaseObject(ctxt->context, obj);
13237: 	ctxt->context->node = NULL;
13238: 	ctxt->context->contextSize = -1;
13239: 	ctxt->context->proximityPosition = -1;
13240: 	/* may want to move this past the '}' later */
13241: 	ctxt->context->doc = oldDoc;
13242: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13243:     }
13244:     ctxt->context->node = oldnode;
13245:     return(total);
13246: }
13247: #endif /* XP_OPTIMIZED_FILTER_FIRST */
13248: 
13249: /**
13250:  * xmlXPathCompOpEval:
13251:  * @ctxt:  the XPath parser context with the compiled expression
13252:  * @op:  an XPath compiled operation
13253:  *
13254:  * Evaluate the Precompiled XPath operation
13255:  * Returns the number of nodes traversed
13256:  */
13257: static int
13258: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13259: {
13260:     int total = 0;
13261:     int equal, ret;
13262:     xmlXPathCompExprPtr comp;
13263:     xmlXPathObjectPtr arg1, arg2;
13264:     xmlNodePtr bak;
13265:     xmlDocPtr bakd;
13266:     int pp;
13267:     int cs;
13268: 
13269:     CHECK_ERROR0;
13270:     comp = ctxt->comp;
13271:     switch (op->op) {
13272:         case XPATH_OP_END:
13273:             return (0);
13274:         case XPATH_OP_AND:
13275: 	    bakd = ctxt->context->doc;
13276: 	    bak = ctxt->context->node;
13277: 	    pp = ctxt->context->proximityPosition;
13278: 	    cs = ctxt->context->contextSize;
13279:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13280: 	    CHECK_ERROR0;
13281:             xmlXPathBooleanFunction(ctxt, 1);
13282:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13283:                 return (total);
13284:             arg2 = valuePop(ctxt);
13285: 	    ctxt->context->doc = bakd;
13286: 	    ctxt->context->node = bak;
13287: 	    ctxt->context->proximityPosition = pp;
13288: 	    ctxt->context->contextSize = cs;
13289:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290: 	    if (ctxt->error) {
13291: 		xmlXPathFreeObject(arg2);
13292: 		return(0);
13293: 	    }
13294:             xmlXPathBooleanFunction(ctxt, 1);
13295:             arg1 = valuePop(ctxt);
13296:             arg1->boolval &= arg2->boolval;
13297:             valuePush(ctxt, arg1);
13298: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13299:             return (total);
13300:         case XPATH_OP_OR:
13301: 	    bakd = ctxt->context->doc;
13302: 	    bak = ctxt->context->node;
13303: 	    pp = ctxt->context->proximityPosition;
13304: 	    cs = ctxt->context->contextSize;
13305:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13306: 	    CHECK_ERROR0;
13307:             xmlXPathBooleanFunction(ctxt, 1);
13308:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13309:                 return (total);
13310:             arg2 = valuePop(ctxt);
13311: 	    ctxt->context->doc = bakd;
13312: 	    ctxt->context->node = bak;
13313: 	    ctxt->context->proximityPosition = pp;
13314: 	    ctxt->context->contextSize = cs;
13315:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13316: 	    if (ctxt->error) {
13317: 		xmlXPathFreeObject(arg2);
13318: 		return(0);
13319: 	    }
13320:             xmlXPathBooleanFunction(ctxt, 1);
13321:             arg1 = valuePop(ctxt);
13322:             arg1->boolval |= arg2->boolval;
13323:             valuePush(ctxt, arg1);
13324: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13325:             return (total);
13326:         case XPATH_OP_EQUAL:
13327: 	    bakd = ctxt->context->doc;
13328: 	    bak = ctxt->context->node;
13329: 	    pp = ctxt->context->proximityPosition;
13330: 	    cs = ctxt->context->contextSize;
13331:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332: 	    CHECK_ERROR0;
13333: 	    ctxt->context->doc = bakd;
13334: 	    ctxt->context->node = bak;
13335: 	    ctxt->context->proximityPosition = pp;
13336: 	    ctxt->context->contextSize = cs;
13337:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13338: 	    CHECK_ERROR0;
13339: 	    if (op->value)
13340: 		equal = xmlXPathEqualValues(ctxt);
13341: 	    else
13342: 		equal = xmlXPathNotEqualValues(ctxt);
13343: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13344:             return (total);
13345:         case XPATH_OP_CMP:
13346: 	    bakd = ctxt->context->doc;
13347: 	    bak = ctxt->context->node;
13348: 	    pp = ctxt->context->proximityPosition;
13349: 	    cs = ctxt->context->contextSize;
13350:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351: 	    CHECK_ERROR0;
13352: 	    ctxt->context->doc = bakd;
13353: 	    ctxt->context->node = bak;
13354: 	    ctxt->context->proximityPosition = pp;
13355: 	    ctxt->context->contextSize = cs;
13356:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13357: 	    CHECK_ERROR0;
13358:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13359: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13360:             return (total);
13361:         case XPATH_OP_PLUS:
13362: 	    bakd = ctxt->context->doc;
13363: 	    bak = ctxt->context->node;
13364: 	    pp = ctxt->context->proximityPosition;
13365: 	    cs = ctxt->context->contextSize;
13366:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367: 	    CHECK_ERROR0;
13368:             if (op->ch2 != -1) {
13369: 		ctxt->context->doc = bakd;
13370: 		ctxt->context->node = bak;
13371: 		ctxt->context->proximityPosition = pp;
13372: 		ctxt->context->contextSize = cs;
13373:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13374: 	    }
13375: 	    CHECK_ERROR0;
13376:             if (op->value == 0)
13377:                 xmlXPathSubValues(ctxt);
13378:             else if (op->value == 1)
13379:                 xmlXPathAddValues(ctxt);
13380:             else if (op->value == 2)
13381:                 xmlXPathValueFlipSign(ctxt);
13382:             else if (op->value == 3) {
13383:                 CAST_TO_NUMBER;
13384:                 CHECK_TYPE0(XPATH_NUMBER);
13385:             }
13386:             return (total);
13387:         case XPATH_OP_MULT:
13388: 	    bakd = ctxt->context->doc;
13389: 	    bak = ctxt->context->node;
13390: 	    pp = ctxt->context->proximityPosition;
13391: 	    cs = ctxt->context->contextSize;
13392:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13393: 	    CHECK_ERROR0;
13394: 	    ctxt->context->doc = bakd;
13395: 	    ctxt->context->node = bak;
13396: 	    ctxt->context->proximityPosition = pp;
13397: 	    ctxt->context->contextSize = cs;
13398:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13399: 	    CHECK_ERROR0;
13400:             if (op->value == 0)
13401:                 xmlXPathMultValues(ctxt);
13402:             else if (op->value == 1)
13403:                 xmlXPathDivValues(ctxt);
13404:             else if (op->value == 2)
13405:                 xmlXPathModValues(ctxt);
13406:             return (total);
13407:         case XPATH_OP_UNION:
13408: 	    bakd = ctxt->context->doc;
13409: 	    bak = ctxt->context->node;
13410: 	    pp = ctxt->context->proximityPosition;
13411: 	    cs = ctxt->context->contextSize;
13412:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13413: 	    CHECK_ERROR0;
13414: 	    ctxt->context->doc = bakd;
13415: 	    ctxt->context->node = bak;
13416: 	    ctxt->context->proximityPosition = pp;
13417: 	    ctxt->context->contextSize = cs;
13418:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419: 	    CHECK_ERROR0;
13420:             CHECK_TYPE0(XPATH_NODESET);
13421:             arg2 = valuePop(ctxt);
13422: 
13423:             CHECK_TYPE0(XPATH_NODESET);
13424:             arg1 = valuePop(ctxt);
13425: 
13426: 	    if ((arg1->nodesetval == NULL) ||
13427: 		((arg2->nodesetval != NULL) &&
13428: 		 (arg2->nodesetval->nodeNr != 0)))
13429: 	    {
13430: 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13431: 							arg2->nodesetval);
13432: 	    }
13433: 
13434:             valuePush(ctxt, arg1);
13435: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13436:             return (total);
13437:         case XPATH_OP_ROOT:
13438:             xmlXPathRoot(ctxt);
13439:             return (total);
13440:         case XPATH_OP_NODE:
13441:             if (op->ch1 != -1)
13442:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13443: 	    CHECK_ERROR0;
13444:             if (op->ch2 != -1)
13445:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13446: 	    CHECK_ERROR0;
13447: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13448: 		ctxt->context->node));
13449:             return (total);
13450:         case XPATH_OP_RESET:
13451:             if (op->ch1 != -1)
13452:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13453: 	    CHECK_ERROR0;
13454:             if (op->ch2 != -1)
13455:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13456: 	    CHECK_ERROR0;
13457:             ctxt->context->node = NULL;
13458:             return (total);
13459:         case XPATH_OP_COLLECT:{
13460:                 if (op->ch1 == -1)
13461:                     return (total);
13462: 
13463:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13464: 		CHECK_ERROR0;
13465: 
13466:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13467:                 return (total);
13468:             }
13469:         case XPATH_OP_VALUE:
13470:             valuePush(ctxt,
13471:                       xmlXPathCacheObjectCopy(ctxt->context,
13472: 			(xmlXPathObjectPtr) op->value4));
13473:             return (total);
13474:         case XPATH_OP_VARIABLE:{
13475: 		xmlXPathObjectPtr val;
13476: 
13477:                 if (op->ch1 != -1)
13478:                     total +=
13479:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13480:                 if (op->value5 == NULL) {
13481: 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13482: 		    if (val == NULL) {
13483: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13484: 			return(0);
13485: 		    }
13486:                     valuePush(ctxt, val);
13487: 		} else {
13488:                     const xmlChar *URI;
13489: 
13490:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13491:                     if (URI == NULL) {
13492:                         xmlGenericError(xmlGenericErrorContext,
13493:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494:                                     (char *) op->value4, (char *)op->value5);
13495:                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13496:                         return (total);
13497:                     }
13498: 		    val = xmlXPathVariableLookupNS(ctxt->context,
13499:                                                        op->value4, URI);
13500: 		    if (val == NULL) {
13501: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13502: 			return(0);
13503: 		    }
13504:                     valuePush(ctxt, val);
13505:                 }
13506:                 return (total);
13507:             }
13508:         case XPATH_OP_FUNCTION:{
13509:                 xmlXPathFunction func;
13510:                 const xmlChar *oldFunc, *oldFuncURI;
13511: 		int i;
13512:                 int frame;
13513: 
13514:                 frame = xmlXPathSetFrame(ctxt);
13515:                 if (op->ch1 != -1)
13516:                     total +=
13517:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13518: 		if (ctxt->valueNr < op->value) {
13519: 		    xmlGenericError(xmlGenericErrorContext,
13520: 			    "xmlXPathCompOpEval: parameter error\n");
13521: 		    ctxt->error = XPATH_INVALID_OPERAND;
13522:                     xmlXPathPopFrame(ctxt, frame);
13523: 		    return (total);
13524: 		}
13525: 		for (i = 0; i < op->value; i++) {
13526: 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13527: 			xmlGenericError(xmlGenericErrorContext,
13528: 				"xmlXPathCompOpEval: parameter error\n");
13529: 			ctxt->error = XPATH_INVALID_OPERAND;
13530:                         xmlXPathPopFrame(ctxt, frame);
13531: 			return (total);
13532: 		    }
13533:                 }
13534:                 if (op->cache != NULL)
13535:                     XML_CAST_FPTR(func) = op->cache;
13536:                 else {
13537:                     const xmlChar *URI = NULL;
13538: 
13539:                     if (op->value5 == NULL)
13540:                         func =
13541:                             xmlXPathFunctionLookup(ctxt->context,
13542:                                                    op->value4);
13543:                     else {
13544:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13545:                         if (URI == NULL) {
13546:                             xmlGenericError(xmlGenericErrorContext,
13547:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548:                                     (char *)op->value4, (char *)op->value5);
13549:                             xmlXPathPopFrame(ctxt, frame);
13550:                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13551:                             return (total);
13552:                         }
13553:                         func = xmlXPathFunctionLookupNS(ctxt->context,
13554:                                                         op->value4, URI);
13555:                     }
13556:                     if (func == NULL) {
13557:                         xmlGenericError(xmlGenericErrorContext,
13558:                                 "xmlXPathCompOpEval: function %s not found\n",
13559:                                         (char *)op->value4);
13560:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13561:                     }
13562:                     op->cache = XML_CAST_FPTR(func);
13563:                     op->cacheURI = (void *) URI;
13564:                 }
13565:                 oldFunc = ctxt->context->function;
13566:                 oldFuncURI = ctxt->context->functionURI;
13567:                 ctxt->context->function = op->value4;
13568:                 ctxt->context->functionURI = op->cacheURI;
13569:                 func(ctxt, op->value);
13570:                 ctxt->context->function = oldFunc;
13571:                 ctxt->context->functionURI = oldFuncURI;
13572:                 xmlXPathPopFrame(ctxt, frame);
13573:                 return (total);
13574:             }
13575:         case XPATH_OP_ARG:
13576: 	    bakd = ctxt->context->doc;
13577: 	    bak = ctxt->context->node;
13578: 	    pp = ctxt->context->proximityPosition;
13579: 	    cs = ctxt->context->contextSize;
13580:             if (op->ch1 != -1)
13581:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13582: 	    ctxt->context->contextSize = cs;
13583: 	    ctxt->context->proximityPosition = pp;
13584: 	    ctxt->context->node = bak;
13585: 	    ctxt->context->doc = bakd;
13586: 	    CHECK_ERROR0;
13587:             if (op->ch2 != -1) {
13588:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13589: 	        ctxt->context->doc = bakd;
13590: 	        ctxt->context->node = bak;
13591: 	        CHECK_ERROR0;
13592: 	    }
13593:             return (total);
13594:         case XPATH_OP_PREDICATE:
13595:         case XPATH_OP_FILTER:{
13596:                 xmlXPathObjectPtr res;
13597:                 xmlXPathObjectPtr obj, tmp;
13598:                 xmlNodeSetPtr newset = NULL;
13599:                 xmlNodeSetPtr oldset;
13600:                 xmlNodePtr oldnode;
13601: 		xmlDocPtr oldDoc;
13602:                 int i;
13603: 
13604:                 /*
13605:                  * Optimization for ()[1] selection i.e. the first elem
13606:                  */
13607:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13608: #ifdef XP_OPTIMIZED_FILTER_FIRST
13609: 		    /*
13610: 		    * FILTER TODO: Can we assume that the inner processing
13611: 		    *  will result in an ordered list if we have an
13612: 		    *  XPATH_OP_FILTER?
13613: 		    *  What about an additional field or flag on
13614: 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13615: 		    *  to assume anything, so it would be more robust and
13616: 		    *  easier to optimize.
13617: 		    */
13618:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13619: 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13620: #else
13621: 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13622: #endif
13623:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13624:                     xmlXPathObjectPtr val;
13625: 
13626:                     val = comp->steps[op->ch2].value4;
13627:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13628:                         (val->floatval == 1.0)) {
13629:                         xmlNodePtr first = NULL;
13630: 
13631:                         total +=
13632:                             xmlXPathCompOpEvalFirst(ctxt,
13633:                                                     &comp->steps[op->ch1],
13634:                                                     &first);
13635: 			CHECK_ERROR0;
13636:                         /*
13637:                          * The nodeset should be in document order,
13638:                          * Keep only the first value
13639:                          */
13640:                         if ((ctxt->value != NULL) &&
13641:                             (ctxt->value->type == XPATH_NODESET) &&
13642:                             (ctxt->value->nodesetval != NULL) &&
13643:                             (ctxt->value->nodesetval->nodeNr > 1))
13644:                             ctxt->value->nodesetval->nodeNr = 1;
13645:                         return (total);
13646:                     }
13647:                 }
13648:                 /*
13649:                  * Optimization for ()[last()] selection i.e. the last elem
13650:                  */
13651:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13652:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13654:                     int f = comp->steps[op->ch2].ch1;
13655: 
13656:                     if ((f != -1) &&
13657:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13658:                         (comp->steps[f].value5 == NULL) &&
13659:                         (comp->steps[f].value == 0) &&
13660:                         (comp->steps[f].value4 != NULL) &&
13661:                         (xmlStrEqual
13662:                          (comp->steps[f].value4, BAD_CAST "last"))) {
13663:                         xmlNodePtr last = NULL;
13664: 
13665:                         total +=
13666:                             xmlXPathCompOpEvalLast(ctxt,
13667:                                                    &comp->steps[op->ch1],
13668:                                                    &last);
13669: 			CHECK_ERROR0;
13670:                         /*
13671:                          * The nodeset should be in document order,
13672:                          * Keep only the last value
13673:                          */
13674:                         if ((ctxt->value != NULL) &&
13675:                             (ctxt->value->type == XPATH_NODESET) &&
13676:                             (ctxt->value->nodesetval != NULL) &&
13677:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13678:                             (ctxt->value->nodesetval->nodeNr > 1)) {
13679:                             ctxt->value->nodesetval->nodeTab[0] =
13680:                                 ctxt->value->nodesetval->nodeTab[ctxt->
13681:                                                                  value->
13682:                                                                  nodesetval->
13683:                                                                  nodeNr -
13684:                                                                  1];
13685:                             ctxt->value->nodesetval->nodeNr = 1;
13686:                         }
13687:                         return (total);
13688:                     }
13689:                 }
13690: 		/*
13691: 		* Process inner predicates first.
13692: 		* Example "index[parent::book][1]":
13693: 		* ...
13694: 		*   PREDICATE   <-- we are here "[1]"
13695: 		*     PREDICATE <-- process "[parent::book]" first
13696: 		*       SORT
13697: 		*         COLLECT  'parent' 'name' 'node' book
13698: 		*           NODE
13699: 		*     ELEM Object is a number : 1
13700: 		*/
13701:                 if (op->ch1 != -1)
13702:                     total +=
13703:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13704: 		CHECK_ERROR0;
13705:                 if (op->ch2 == -1)
13706:                     return (total);
13707:                 if (ctxt->value == NULL)
13708:                     return (total);
13709: 
13710:                 oldnode = ctxt->context->node;
13711: 
13712: #ifdef LIBXML_XPTR_ENABLED
13713:                 /*
13714:                  * Hum are we filtering the result of an XPointer expression
13715:                  */
13716:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13717:                     xmlLocationSetPtr newlocset = NULL;
13718:                     xmlLocationSetPtr oldlocset;
13719: 
13720:                     /*
13721:                      * Extract the old locset, and then evaluate the result of the
13722:                      * expression for all the element in the locset. use it to grow
13723:                      * up a new locset.
13724:                      */
13725:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13726:                     obj = valuePop(ctxt);
13727:                     oldlocset = obj->user;
13728:                     ctxt->context->node = NULL;
13729: 
13730:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13731:                         ctxt->context->contextSize = 0;
13732:                         ctxt->context->proximityPosition = 0;
13733:                         if (op->ch2 != -1)
13734:                             total +=
13735:                                 xmlXPathCompOpEval(ctxt,
13736:                                                    &comp->steps[op->ch2]);
13737:                         res = valuePop(ctxt);
13738:                         if (res != NULL) {
13739: 			    xmlXPathReleaseObject(ctxt->context, res);
13740: 			}
13741:                         valuePush(ctxt, obj);
13742:                         CHECK_ERROR0;
13743:                         return (total);
13744:                     }
13745:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13746: 
13747:                     for (i = 0; i < oldlocset->locNr; i++) {
13748:                         /*
13749:                          * Run the evaluation with a node list made of a
13750:                          * single item in the nodelocset.
13751:                          */
13752:                         ctxt->context->node = oldlocset->locTab[i]->user;
13753:                         ctxt->context->contextSize = oldlocset->locNr;
13754:                         ctxt->context->proximityPosition = i + 1;
13755: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13756: 			    ctxt->context->node);
13757:                         valuePush(ctxt, tmp);
13758: 
13759:                         if (op->ch2 != -1)
13760:                             total +=
13761:                                 xmlXPathCompOpEval(ctxt,
13762:                                                    &comp->steps[op->ch2]);
13763: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13764: 			    xmlXPathFreeObject(obj);
13765: 			    return(0);
13766: 			}
13767: 
13768:                         /*
13769:                          * The result of the evaluation need to be tested to
13770:                          * decided whether the filter succeeded or not
13771:                          */
13772:                         res = valuePop(ctxt);
13773:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13774:                             xmlXPtrLocationSetAdd(newlocset,
13775:                                                   xmlXPathObjectCopy
13776:                                                   (oldlocset->locTab[i]));
13777:                         }
13778: 
13779:                         /*
13780:                          * Cleanup
13781:                          */
13782:                         if (res != NULL) {
13783: 			    xmlXPathReleaseObject(ctxt->context, res);
13784: 			}
13785:                         if (ctxt->value == tmp) {
13786:                             res = valuePop(ctxt);
13787: 			    xmlXPathReleaseObject(ctxt->context, res);
13788:                         }
13789: 
13790:                         ctxt->context->node = NULL;
13791:                     }
13792: 
13793:                     /*
13794:                      * The result is used as the new evaluation locset.
13795:                      */
13796: 		    xmlXPathReleaseObject(ctxt->context, obj);
13797:                     ctxt->context->node = NULL;
13798:                     ctxt->context->contextSize = -1;
13799:                     ctxt->context->proximityPosition = -1;
13800:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13801:                     ctxt->context->node = oldnode;
13802:                     return (total);
13803:                 }
13804: #endif /* LIBXML_XPTR_ENABLED */
13805: 
13806:                 /*
13807:                  * Extract the old set, and then evaluate the result of the
13808:                  * expression for all the element in the set. use it to grow
13809:                  * up a new set.
13810:                  */
13811:                 CHECK_TYPE0(XPATH_NODESET);
13812:                 obj = valuePop(ctxt);
13813:                 oldset = obj->nodesetval;
13814: 
13815:                 oldnode = ctxt->context->node;
13816: 		oldDoc = ctxt->context->doc;
13817:                 ctxt->context->node = NULL;
13818: 
13819:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13820:                     ctxt->context->contextSize = 0;
13821:                     ctxt->context->proximityPosition = 0;
13822: /*
13823:                     if (op->ch2 != -1)
13824:                         total +=
13825:                             xmlXPathCompOpEval(ctxt,
13826:                                                &comp->steps[op->ch2]);
13827: 		    CHECK_ERROR0;
13828:                     res = valuePop(ctxt);
13829:                     if (res != NULL)
13830:                         xmlXPathFreeObject(res);
13831: */
13832:                     valuePush(ctxt, obj);
13833:                     ctxt->context->node = oldnode;
13834:                     CHECK_ERROR0;
13835:                 } else {
13836: 		    tmp = NULL;
13837:                     /*
13838:                      * Initialize the new set.
13839: 		     * Also set the xpath document in case things like
13840: 		     * key() evaluation are attempted on the predicate
13841:                      */
13842:                     newset = xmlXPathNodeSetCreate(NULL);
13843: 		    /*
13844: 		    * SPEC XPath 1.0:
13845: 		    *  "For each node in the node-set to be filtered, the
13846: 		    *  PredicateExpr is evaluated with that node as the
13847: 		    *  context node, with the number of nodes in the
13848: 		    *  node-set as the context size, and with the proximity
13849: 		    *  position of the node in the node-set with respect to
13850: 		    *  the axis as the context position;"
13851: 		    * @oldset is the node-set" to be filtered.
13852: 		    *
13853: 		    * SPEC XPath 1.0:
13854: 		    *  "only predicates change the context position and
13855: 		    *  context size (see [2.4 Predicates])."
13856: 		    * Example:
13857: 		    *   node-set  context pos
13858: 		    *    nA         1
13859: 		    *    nB         2
13860: 		    *    nC         3
13861: 		    *   After applying predicate [position() > 1] :
13862: 		    *   node-set  context pos
13863: 		    *    nB         1
13864: 		    *    nC         2
13865: 		    *
13866: 		    * removed the first node in the node-set, then
13867: 		    * the context position of the
13868: 		    */
13869:                     for (i = 0; i < oldset->nodeNr; i++) {
13870:                         /*
13871:                          * Run the evaluation with a node list made of
13872:                          * a single item in the nodeset.
13873:                          */
13874:                         ctxt->context->node = oldset->nodeTab[i];
13875: 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13876: 			    (oldset->nodeTab[i]->doc != NULL))
13877: 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13878: 			if (tmp == NULL) {
13879: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13880: 				ctxt->context->node);
13881: 			} else {
13882: 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13883: 				               ctxt->context->node) < 0) {
13884: 				ctxt->error = XPATH_MEMORY_ERROR;
13885: 			    }
13886: 			}
13887:                         valuePush(ctxt, tmp);
13888:                         ctxt->context->contextSize = oldset->nodeNr;
13889:                         ctxt->context->proximityPosition = i + 1;
13890: 			/*
13891: 			* Evaluate the predicate against the context node.
13892: 			* Can/should we optimize position() predicates
13893: 			* here (e.g. "[1]")?
13894: 			*/
13895:                         if (op->ch2 != -1)
13896:                             total +=
13897:                                 xmlXPathCompOpEval(ctxt,
13898:                                                    &comp->steps[op->ch2]);
13899: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13900: 			    xmlXPathFreeNodeSet(newset);
13901: 			    xmlXPathFreeObject(obj);
13902: 			    return(0);
13903: 			}
13904: 
13905:                         /*
13906:                          * The result of the evaluation needs to be tested to
13907:                          * decide whether the filter succeeded or not
13908:                          */
13909: 			/*
13910: 			* OPTIMIZE TODO: Can we use
13911: 			* xmlXPathNodeSetAdd*Unique()* instead?
13912: 			*/
13913:                         res = valuePop(ctxt);
13914:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13915:                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13916: 			        < 0)
13917: 				ctxt->error = XPATH_MEMORY_ERROR;
13918:                         }
13919: 
13920:                         /*
13921:                          * Cleanup
13922:                          */
13923:                         if (res != NULL) {
13924: 			    xmlXPathReleaseObject(ctxt->context, res);
13925: 			}
13926:                         if (ctxt->value == tmp) {
13927:                             valuePop(ctxt);
13928: 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13929: 			    /*
13930: 			    * Don't free the temporary nodeset
13931: 			    * in order to avoid massive recreation inside this
13932: 			    * loop.
13933: 			    */
13934:                         } else
13935: 			    tmp = NULL;
13936:                         ctxt->context->node = NULL;
13937:                     }
13938: 		    if (tmp != NULL)
13939: 			xmlXPathReleaseObject(ctxt->context, tmp);
13940:                     /*
13941:                      * The result is used as the new evaluation set.
13942:                      */
13943: 		    xmlXPathReleaseObject(ctxt->context, obj);
13944:                     ctxt->context->node = NULL;
13945:                     ctxt->context->contextSize = -1;
13946:                     ctxt->context->proximityPosition = -1;
13947: 		    /* may want to move this past the '}' later */
13948: 		    ctxt->context->doc = oldDoc;
13949: 		    valuePush(ctxt,
13950: 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13951:                 }
13952:                 ctxt->context->node = oldnode;
13953:                 return (total);
13954:             }
13955:         case XPATH_OP_SORT:
13956:             if (op->ch1 != -1)
13957:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13958: 	    CHECK_ERROR0;
13959:             if ((ctxt->value != NULL) &&
13960:                 (ctxt->value->type == XPATH_NODESET) &&
13961:                 (ctxt->value->nodesetval != NULL) &&
13962: 		(ctxt->value->nodesetval->nodeNr > 1))
13963: 	    {
13964:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13965: 	    }
13966:             return (total);
13967: #ifdef LIBXML_XPTR_ENABLED
13968:         case XPATH_OP_RANGETO:{
13969:                 xmlXPathObjectPtr range;
13970:                 xmlXPathObjectPtr res, obj;
13971:                 xmlXPathObjectPtr tmp;
13972:                 xmlLocationSetPtr newlocset = NULL;
13973: 		    xmlLocationSetPtr oldlocset;
13974:                 xmlNodeSetPtr oldset;
13975:                 int i, j;
13976: 
13977:                 if (op->ch1 != -1)
13978:                     total +=
13979:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13980:                 if (op->ch2 == -1)
13981:                     return (total);
13982: 
13983:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13984:                     /*
13985:                      * Extract the old locset, and then evaluate the result of the
13986:                      * expression for all the element in the locset. use it to grow
13987:                      * up a new locset.
13988:                      */
13989:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13990:                     obj = valuePop(ctxt);
13991:                     oldlocset = obj->user;
13992: 
13993:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13994: 		        ctxt->context->node = NULL;
13995:                         ctxt->context->contextSize = 0;
13996:                         ctxt->context->proximityPosition = 0;
13997:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13998:                         res = valuePop(ctxt);
13999:                         if (res != NULL) {
14000: 			    xmlXPathReleaseObject(ctxt->context, res);
14001: 			}
14002:                         valuePush(ctxt, obj);
14003:                         CHECK_ERROR0;
14004:                         return (total);
14005:                     }
14006:                     newlocset = xmlXPtrLocationSetCreate(NULL);
14007: 
14008:                     for (i = 0; i < oldlocset->locNr; i++) {
14009:                         /*
14010:                          * Run the evaluation with a node list made of a
14011:                          * single item in the nodelocset.
14012:                          */
14013:                         ctxt->context->node = oldlocset->locTab[i]->user;
14014:                         ctxt->context->contextSize = oldlocset->locNr;
14015:                         ctxt->context->proximityPosition = i + 1;
14016: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14017: 			    ctxt->context->node);
14018:                         valuePush(ctxt, tmp);
14019: 
14020:                         if (op->ch2 != -1)
14021:                             total +=
14022:                                 xmlXPathCompOpEval(ctxt,
14023:                                                    &comp->steps[op->ch2]);
14024: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
14025: 			    xmlXPathFreeObject(obj);
14026: 			    return(0);
14027: 			}
14028: 
14029:                         res = valuePop(ctxt);
14030: 			if (res->type == XPATH_LOCATIONSET) {
14031: 			    xmlLocationSetPtr rloc =
14032: 			        (xmlLocationSetPtr)res->user;
14033: 			    for (j=0; j<rloc->locNr; j++) {
14034: 			        range = xmlXPtrNewRange(
14035: 				  oldlocset->locTab[i]->user,
14036: 				  oldlocset->locTab[i]->index,
14037: 				  rloc->locTab[j]->user2,
14038: 				  rloc->locTab[j]->index2);
14039: 				if (range != NULL) {
14040: 				    xmlXPtrLocationSetAdd(newlocset, range);
14041: 				}
14042: 			    }
14043: 			} else {
14044: 			    range = xmlXPtrNewRangeNodeObject(
14045: 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14046:                             if (range != NULL) {
14047:                                 xmlXPtrLocationSetAdd(newlocset,range);
14048: 			    }
14049:                         }
14050: 
14051:                         /*
14052:                          * Cleanup
14053:                          */
14054:                         if (res != NULL) {
14055: 			    xmlXPathReleaseObject(ctxt->context, res);
14056: 			}
14057:                         if (ctxt->value == tmp) {
14058:                             res = valuePop(ctxt);
14059: 			    xmlXPathReleaseObject(ctxt->context, res);
14060:                         }
14061: 
14062:                         ctxt->context->node = NULL;
14063:                     }
14064: 		} else {	/* Not a location set */
14065:                     CHECK_TYPE0(XPATH_NODESET);
14066:                     obj = valuePop(ctxt);
14067:                     oldset = obj->nodesetval;
14068:                     ctxt->context->node = NULL;
14069: 
14070:                     newlocset = xmlXPtrLocationSetCreate(NULL);
14071: 
14072:                     if (oldset != NULL) {
14073:                         for (i = 0; i < oldset->nodeNr; i++) {
14074:                             /*
14075:                              * Run the evaluation with a node list made of a single item
14076:                              * in the nodeset.
14077:                              */
14078:                             ctxt->context->node = oldset->nodeTab[i];
14079: 			    /*
14080: 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14081: 			    */
14082: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14083: 				ctxt->context->node);
14084:                             valuePush(ctxt, tmp);
14085: 
14086:                             if (op->ch2 != -1)
14087:                                 total +=
14088:                                     xmlXPathCompOpEval(ctxt,
14089:                                                    &comp->steps[op->ch2]);
14090: 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14091: 				xmlXPathFreeObject(obj);
14092: 				return(0);
14093: 			    }
14094: 
14095:                             res = valuePop(ctxt);
14096:                             range =
14097:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14098:                                                       res);
14099:                             if (range != NULL) {
14100:                                 xmlXPtrLocationSetAdd(newlocset, range);
14101:                             }
14102: 
14103:                             /*
14104:                              * Cleanup
14105:                              */
14106:                             if (res != NULL) {
14107: 				xmlXPathReleaseObject(ctxt->context, res);
14108: 			    }
14109:                             if (ctxt->value == tmp) {
14110:                                 res = valuePop(ctxt);
14111: 				xmlXPathReleaseObject(ctxt->context, res);
14112:                             }
14113: 
14114:                             ctxt->context->node = NULL;
14115:                         }
14116:                     }
14117:                 }
14118: 
14119:                 /*
14120:                  * The result is used as the new evaluation set.
14121:                  */
14122: 		xmlXPathReleaseObject(ctxt->context, obj);
14123:                 ctxt->context->node = NULL;
14124:                 ctxt->context->contextSize = -1;
14125:                 ctxt->context->proximityPosition = -1;
14126:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14127:                 return (total);
14128:             }
14129: #endif /* LIBXML_XPTR_ENABLED */
14130:     }
14131:     xmlGenericError(xmlGenericErrorContext,
14132:                     "XPath: unknown precompiled operation %d\n", op->op);
14133:     ctxt->error = XPATH_INVALID_OPERAND;
14134:     return (total);
14135: }
14136: 
14137: /**
14138:  * xmlXPathCompOpEvalToBoolean:
14139:  * @ctxt:  the XPath parser context
14140:  *
14141:  * Evaluates if the expression evaluates to true.
14142:  *
14143:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14144:  */
14145: static int
14146: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14147: 			    xmlXPathStepOpPtr op,
14148: 			    int isPredicate)
14149: {
14150:     xmlXPathObjectPtr resObj = NULL;
14151: 
14152: start:
14153:     /* comp = ctxt->comp; */
14154:     switch (op->op) {
14155:         case XPATH_OP_END:
14156:             return (0);
14157: 	case XPATH_OP_VALUE:
14158: 	    resObj = (xmlXPathObjectPtr) op->value4;
14159: 	    if (isPredicate)
14160: 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14161: 	    return(xmlXPathCastToBoolean(resObj));
14162: 	case XPATH_OP_SORT:
14163: 	    /*
14164: 	    * We don't need sorting for boolean results. Skip this one.
14165: 	    */
14166:             if (op->ch1 != -1) {
14167: 		op = &ctxt->comp->steps[op->ch1];
14168: 		goto start;
14169: 	    }
14170: 	    return(0);
14171: 	case XPATH_OP_COLLECT:
14172: 	    if (op->ch1 == -1)
14173: 		return(0);
14174: 
14175:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14176: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14177: 		return(-1);
14178: 
14179:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14180: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14181: 		return(-1);
14182: 
14183: 	    resObj = valuePop(ctxt);
14184: 	    if (resObj == NULL)
14185: 		return(-1);
14186: 	    break;
14187: 	default:
14188: 	    /*
14189: 	    * Fallback to call xmlXPathCompOpEval().
14190: 	    */
14191: 	    xmlXPathCompOpEval(ctxt, op);
14192: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14193: 		return(-1);
14194: 
14195: 	    resObj = valuePop(ctxt);
14196: 	    if (resObj == NULL)
14197: 		return(-1);
14198: 	    break;
14199:     }
14200: 
14201:     if (resObj) {
14202: 	int res;
14203: 
14204: 	if (resObj->type == XPATH_BOOLEAN) {
14205: 	    res = resObj->boolval;
14206: 	} else if (isPredicate) {
14207: 	    /*
14208: 	    * For predicates a result of type "number" is handled
14209: 	    * differently:
14210: 	    * SPEC XPath 1.0:
14211: 	    * "If the result is a number, the result will be converted
14212: 	    *  to true if the number is equal to the context position
14213: 	    *  and will be converted to false otherwise;"
14214: 	    */
14215: 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14216: 	} else {
14217: 	    res = xmlXPathCastToBoolean(resObj);
14218: 	}
14219: 	xmlXPathReleaseObject(ctxt->context, resObj);
14220: 	return(res);
14221:     }
14222: 
14223:     return(0);
14224: }
14225: 
14226: #ifdef XPATH_STREAMING
14227: /**
14228:  * xmlXPathRunStreamEval:
14229:  * @ctxt:  the XPath parser context with the compiled expression
14230:  *
14231:  * Evaluate the Precompiled Streamable XPath expression in the given context.
14232:  */
14233: static int
14234: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14235: 		      xmlXPathObjectPtr *resultSeq, int toBool)
14236: {
14237:     int max_depth, min_depth;
14238:     int from_root;
14239:     int ret, depth;
14240:     int eval_all_nodes;
14241:     xmlNodePtr cur = NULL, limit = NULL;
14242:     xmlStreamCtxtPtr patstream = NULL;
14243: 
14244:     int nb_nodes = 0;
14245: 
14246:     if ((ctxt == NULL) || (comp == NULL))
14247:         return(-1);
14248:     max_depth = xmlPatternMaxDepth(comp);
14249:     if (max_depth == -1)
14250:         return(-1);
14251:     if (max_depth == -2)
14252:         max_depth = 10000;
14253:     min_depth = xmlPatternMinDepth(comp);
14254:     if (min_depth == -1)
14255:         return(-1);
14256:     from_root = xmlPatternFromRoot(comp);
14257:     if (from_root < 0)
14258:         return(-1);
14259: #if 0
14260:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14261: #endif
14262: 
14263:     if (! toBool) {
14264: 	if (resultSeq == NULL)
14265: 	    return(-1);
14266: 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14267: 	if (*resultSeq == NULL)
14268: 	    return(-1);
14269:     }
14270: 
14271:     /*
14272:      * handle the special cases of "/" amd "." being matched
14273:      */
14274:     if (min_depth == 0) {
14275: 	if (from_root) {
14276: 	    /* Select "/" */
14277: 	    if (toBool)
14278: 		return(1);
14279: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14280: 		                     (xmlNodePtr) ctxt->doc);
14281: 	} else {
14282: 	    /* Select "self::node()" */
14283: 	    if (toBool)
14284: 		return(1);
14285: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14286: 	}
14287:     }
14288:     if (max_depth == 0) {
14289: 	return(0);
14290:     }
14291: 
14292:     if (from_root) {
14293:         cur = (xmlNodePtr)ctxt->doc;
14294:     } else if (ctxt->node != NULL) {
14295:         switch (ctxt->node->type) {
14296:             case XML_ELEMENT_NODE:
14297:             case XML_DOCUMENT_NODE:
14298:             case XML_DOCUMENT_FRAG_NODE:
14299:             case XML_HTML_DOCUMENT_NODE:
14300: #ifdef LIBXML_DOCB_ENABLED
14301:             case XML_DOCB_DOCUMENT_NODE:
14302: #endif
14303: 	        cur = ctxt->node;
14304: 		break;
14305:             case XML_ATTRIBUTE_NODE:
14306:             case XML_TEXT_NODE:
14307:             case XML_CDATA_SECTION_NODE:
14308:             case XML_ENTITY_REF_NODE:
14309:             case XML_ENTITY_NODE:
14310:             case XML_PI_NODE:
14311:             case XML_COMMENT_NODE:
14312:             case XML_NOTATION_NODE:
14313:             case XML_DTD_NODE:
14314:             case XML_DOCUMENT_TYPE_NODE:
14315:             case XML_ELEMENT_DECL:
14316:             case XML_ATTRIBUTE_DECL:
14317:             case XML_ENTITY_DECL:
14318:             case XML_NAMESPACE_DECL:
14319:             case XML_XINCLUDE_START:
14320:             case XML_XINCLUDE_END:
14321: 		break;
14322: 	}
14323: 	limit = cur;
14324:     }
14325:     if (cur == NULL) {
14326:         return(0);
14327:     }
14328: 
14329:     patstream = xmlPatternGetStreamCtxt(comp);
14330:     if (patstream == NULL) {
14331: 	/*
14332: 	* QUESTION TODO: Is this an error?
14333: 	*/
14334: 	return(0);
14335:     }
14336: 
14337:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14338: 
14339:     if (from_root) {
14340: 	ret = xmlStreamPush(patstream, NULL, NULL);
14341: 	if (ret < 0) {
14342: 	} else if (ret == 1) {
14343: 	    if (toBool)
14344: 		goto return_1;
14345: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14346: 	}
14347:     }
14348:     depth = 0;
14349:     goto scan_children;
14350: next_node:
14351:     do {
14352:         nb_nodes++;
14353: 
14354: 	switch (cur->type) {
14355: 	    case XML_ELEMENT_NODE:
14356: 	    case XML_TEXT_NODE:
14357: 	    case XML_CDATA_SECTION_NODE:
14358: 	    case XML_COMMENT_NODE:
14359: 	    case XML_PI_NODE:
14360: 		if (cur->type == XML_ELEMENT_NODE) {
14361: 		    ret = xmlStreamPush(patstream, cur->name,
14362: 				(cur->ns ? cur->ns->href : NULL));
14363: 		} else if (eval_all_nodes)
14364: 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14365: 		else
14366: 		    break;
14367: 
14368: 		if (ret < 0) {
14369: 		    /* NOP. */
14370: 		} else if (ret == 1) {
14371: 		    if (toBool)
14372: 			goto return_1;
14373: 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14374: 		        < 0) {
14375: 			ctxt->lastError.domain = XML_FROM_XPATH;
14376: 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14377: 		    }
14378: 		}
14379: 		if ((cur->children == NULL) || (depth >= max_depth)) {
14380: 		    ret = xmlStreamPop(patstream);
14381: 		    while (cur->next != NULL) {
14382: 			cur = cur->next;
14383: 			if ((cur->type != XML_ENTITY_DECL) &&
14384: 			    (cur->type != XML_DTD_NODE))
14385: 			    goto next_node;
14386: 		    }
14387: 		}
14388: 	    default:
14389: 		break;
14390: 	}
14391: 
14392: scan_children:
14393: 	if (cur->type == XML_NAMESPACE_DECL) break;
14394: 	if ((cur->children != NULL) && (depth < max_depth)) {
14395: 	    /*
14396: 	     * Do not descend on entities declarations
14397: 	     */
14398: 	    if (cur->children->type != XML_ENTITY_DECL) {
14399: 		cur = cur->children;
14400: 		depth++;
14401: 		/*
14402: 		 * Skip DTDs
14403: 		 */
14404: 		if (cur->type != XML_DTD_NODE)
14405: 		    continue;
14406: 	    }
14407: 	}
14408: 
14409: 	if (cur == limit)
14410: 	    break;
14411: 
14412: 	while (cur->next != NULL) {
14413: 	    cur = cur->next;
14414: 	    if ((cur->type != XML_ENTITY_DECL) &&
14415: 		(cur->type != XML_DTD_NODE))
14416: 		goto next_node;
14417: 	}
14418: 
14419: 	do {
14420: 	    cur = cur->parent;
14421: 	    depth--;
14422: 	    if ((cur == NULL) || (cur == limit))
14423: 	        goto done;
14424: 	    if (cur->type == XML_ELEMENT_NODE) {
14425: 		ret = xmlStreamPop(patstream);
14426: 	    } else if ((eval_all_nodes) &&
14427: 		((cur->type == XML_TEXT_NODE) ||
14428: 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14429: 		 (cur->type == XML_COMMENT_NODE) ||
14430: 		 (cur->type == XML_PI_NODE)))
14431: 	    {
14432: 		ret = xmlStreamPop(patstream);
14433: 	    }
14434: 	    if (cur->next != NULL) {
14435: 		cur = cur->next;
14436: 		break;
14437: 	    }
14438: 	} while (cur != NULL);
14439: 
14440:     } while ((cur != NULL) && (depth >= 0));
14441: 
14442: done:
14443: 
14444: #if 0
14445:     printf("stream eval: checked %d nodes selected %d\n",
14446:            nb_nodes, retObj->nodesetval->nodeNr);
14447: #endif
14448: 
14449:     if (patstream)
14450: 	xmlFreeStreamCtxt(patstream);
14451:     return(0);
14452: 
14453: return_1:
14454:     if (patstream)
14455: 	xmlFreeStreamCtxt(patstream);
14456:     return(1);
14457: }
14458: #endif /* XPATH_STREAMING */
14459: 
14460: /**
14461:  * xmlXPathRunEval:
14462:  * @ctxt:  the XPath parser context with the compiled expression
14463:  * @toBool:  evaluate to a boolean result
14464:  *
14465:  * Evaluate the Precompiled XPath expression in the given context.
14466:  */
14467: static int
14468: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14469: {
14470:     xmlXPathCompExprPtr comp;
14471: 
14472:     if ((ctxt == NULL) || (ctxt->comp == NULL))
14473: 	return(-1);
14474: 
14475:     if (ctxt->valueTab == NULL) {
14476: 	/* Allocate the value stack */
14477: 	ctxt->valueTab = (xmlXPathObjectPtr *)
14478: 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14479: 	if (ctxt->valueTab == NULL) {
14480: 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14481: 	    xmlFree(ctxt);
14482: 	}
14483: 	ctxt->valueNr = 0;
14484: 	ctxt->valueMax = 10;
14485: 	ctxt->value = NULL;
14486:         ctxt->valueFrame = 0;
14487:     }
14488: #ifdef XPATH_STREAMING
14489:     if (ctxt->comp->stream) {
14490: 	int res;
14491: 
14492: 	if (toBool) {
14493: 	    /*
14494: 	    * Evaluation to boolean result.
14495: 	    */
14496: 	    res = xmlXPathRunStreamEval(ctxt->context,
14497: 		ctxt->comp->stream, NULL, 1);
14498: 	    if (res != -1)
14499: 		return(res);
14500: 	} else {
14501: 	    xmlXPathObjectPtr resObj = NULL;
14502: 
14503: 	    /*
14504: 	    * Evaluation to a sequence.
14505: 	    */
14506: 	    res = xmlXPathRunStreamEval(ctxt->context,
14507: 		ctxt->comp->stream, &resObj, 0);
14508: 
14509: 	    if ((res != -1) && (resObj != NULL)) {
14510: 		valuePush(ctxt, resObj);
14511: 		return(0);
14512: 	    }
14513: 	    if (resObj != NULL)
14514: 		xmlXPathReleaseObject(ctxt->context, resObj);
14515: 	}
14516: 	/*
14517: 	* QUESTION TODO: This falls back to normal XPath evaluation
14518: 	* if res == -1. Is this intended?
14519: 	*/
14520:     }
14521: #endif
14522:     comp = ctxt->comp;
14523:     if (comp->last < 0) {
14524: 	xmlGenericError(xmlGenericErrorContext,
14525: 	    "xmlXPathRunEval: last is less than zero\n");
14526: 	return(-1);
14527:     }
14528:     if (toBool)
14529: 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14530: 	    &comp->steps[comp->last], 0));
14531:     else
14532: 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14533: 
14534:     return(0);
14535: }
14536: 
14537: /************************************************************************
14538:  *									*
14539:  *			Public interfaces				*
14540:  *									*
14541:  ************************************************************************/
14542: 
14543: /**
14544:  * xmlXPathEvalPredicate:
14545:  * @ctxt:  the XPath context
14546:  * @res:  the Predicate Expression evaluation result
14547:  *
14548:  * Evaluate a predicate result for the current node.
14549:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14550:  * the result to a boolean. If the result is a number, the result will
14551:  * be converted to true if the number is equal to the position of the
14552:  * context node in the context node list (as returned by the position
14553:  * function) and will be converted to false otherwise; if the result
14554:  * is not a number, then the result will be converted as if by a call
14555:  * to the boolean function.
14556:  *
14557:  * Returns 1 if predicate is true, 0 otherwise
14558:  */
14559: int
14560: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14561:     if ((ctxt == NULL) || (res == NULL)) return(0);
14562:     switch (res->type) {
14563:         case XPATH_BOOLEAN:
14564: 	    return(res->boolval);
14565:         case XPATH_NUMBER:
14566: 	    return(res->floatval == ctxt->proximityPosition);
14567:         case XPATH_NODESET:
14568:         case XPATH_XSLT_TREE:
14569: 	    if (res->nodesetval == NULL)
14570: 		return(0);
14571: 	    return(res->nodesetval->nodeNr != 0);
14572:         case XPATH_STRING:
14573: 	    return((res->stringval != NULL) &&
14574: 	           (xmlStrlen(res->stringval) != 0));
14575:         default:
14576: 	    STRANGE
14577:     }
14578:     return(0);
14579: }
14580: 
14581: /**
14582:  * xmlXPathEvaluatePredicateResult:
14583:  * @ctxt:  the XPath Parser context
14584:  * @res:  the Predicate Expression evaluation result
14585:  *
14586:  * Evaluate a predicate result for the current node.
14587:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14588:  * the result to a boolean. If the result is a number, the result will
14589:  * be converted to true if the number is equal to the position of the
14590:  * context node in the context node list (as returned by the position
14591:  * function) and will be converted to false otherwise; if the result
14592:  * is not a number, then the result will be converted as if by a call
14593:  * to the boolean function.
14594:  *
14595:  * Returns 1 if predicate is true, 0 otherwise
14596:  */
14597: int
14598: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14599:                                 xmlXPathObjectPtr res) {
14600:     if ((ctxt == NULL) || (res == NULL)) return(0);
14601:     switch (res->type) {
14602:         case XPATH_BOOLEAN:
14603: 	    return(res->boolval);
14604:         case XPATH_NUMBER:
14605: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14606: 	    return((res->floatval == ctxt->context->proximityPosition) &&
14607: 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14608: #else
14609: 	    return(res->floatval == ctxt->context->proximityPosition);
14610: #endif
14611:         case XPATH_NODESET:
14612:         case XPATH_XSLT_TREE:
14613: 	    if (res->nodesetval == NULL)
14614: 		return(0);
14615: 	    return(res->nodesetval->nodeNr != 0);
14616:         case XPATH_STRING:
14617: 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14618: #ifdef LIBXML_XPTR_ENABLED
14619: 	case XPATH_LOCATIONSET:{
14620: 	    xmlLocationSetPtr ptr = res->user;
14621: 	    if (ptr == NULL)
14622: 	        return(0);
14623: 	    return (ptr->locNr != 0);
14624: 	    }
14625: #endif
14626:         default:
14627: 	    STRANGE
14628:     }
14629:     return(0);
14630: }
14631: 
14632: #ifdef XPATH_STREAMING
14633: /**
14634:  * xmlXPathTryStreamCompile:
14635:  * @ctxt: an XPath context
14636:  * @str:  the XPath expression
14637:  *
14638:  * Try to compile the XPath expression as a streamable subset.
14639:  *
14640:  * Returns the compiled expression or NULL if failed to compile.
14641:  */
14642: static xmlXPathCompExprPtr
14643: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14644:     /*
14645:      * Optimization: use streaming patterns when the XPath expression can
14646:      * be compiled to a stream lookup
14647:      */
14648:     xmlPatternPtr stream;
14649:     xmlXPathCompExprPtr comp;
14650:     xmlDictPtr dict = NULL;
14651:     const xmlChar **namespaces = NULL;
14652:     xmlNsPtr ns;
14653:     int i, j;
14654: 
14655:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14656:         (!xmlStrchr(str, '@'))) {
14657: 	const xmlChar *tmp;
14658: 
14659: 	/*
14660: 	 * We don't try to handle expressions using the verbose axis
14661: 	 * specifiers ("::"), just the simplied form at this point.
14662: 	 * Additionally, if there is no list of namespaces available and
14663: 	 *  there's a ":" in the expression, indicating a prefixed QName,
14664: 	 *  then we won't try to compile either. xmlPatterncompile() needs
14665: 	 *  to have a list of namespaces at compilation time in order to
14666: 	 *  compile prefixed name tests.
14667: 	 */
14668: 	tmp = xmlStrchr(str, ':');
14669: 	if ((tmp != NULL) &&
14670: 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14671: 	    return(NULL);
14672: 
14673: 	if (ctxt != NULL) {
14674: 	    dict = ctxt->dict;
14675: 	    if (ctxt->nsNr > 0) {
14676: 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14677: 		if (namespaces == NULL) {
14678: 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14679: 		    return(NULL);
14680: 		}
14681: 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14682: 		    ns = ctxt->namespaces[j];
14683: 		    namespaces[i++] = ns->href;
14684: 		    namespaces[i++] = ns->prefix;
14685: 		}
14686: 		namespaces[i++] = NULL;
14687: 		namespaces[i] = NULL;
14688: 	    }
14689: 	}
14690: 
14691: 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14692: 			&namespaces[0]);
14693: 	if (namespaces != NULL) {
14694: 	    xmlFree((xmlChar **)namespaces);
14695: 	}
14696: 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14697: 	    comp = xmlXPathNewCompExpr();
14698: 	    if (comp == NULL) {
14699: 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14700: 		return(NULL);
14701: 	    }
14702: 	    comp->stream = stream;
14703: 	    comp->dict = dict;
14704: 	    if (comp->dict)
14705: 		xmlDictReference(comp->dict);
14706: 	    return(comp);
14707: 	}
14708: 	xmlFreePattern(stream);
14709:     }
14710:     return(NULL);
14711: }
14712: #endif /* XPATH_STREAMING */
14713: 
14714: static void
14715: xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14716: {
14717:     /*
14718:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719:     * internal representation.
14720:     */
14721: 
14722:     if ((op->ch1 != -1) &&
14723:         (op->op == XPATH_OP_COLLECT /* 11 */))
14724:     {
14725:         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14726: 
14727:         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14728:             ((xmlXPathAxisVal) prevop->value ==
14729:                 AXIS_DESCENDANT_OR_SELF) &&
14730:             (prevop->ch2 == -1) &&
14731:             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14732:             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14733:         {
14734:             /*
14735:             * This is a "descendant-or-self::node()" without predicates.
14736:             * Try to eliminate it.
14737:             */
14738: 
14739:             switch ((xmlXPathAxisVal) op->value) {
14740:                 case AXIS_CHILD:
14741:                 case AXIS_DESCENDANT:
14742:                     /*
14743:                     * Convert "descendant-or-self::node()/child::" or
14744:                     * "descendant-or-self::node()/descendant::" to
14745:                     * "descendant::"
14746:                     */
14747:                     op->ch1   = prevop->ch1;
14748:                     op->value = AXIS_DESCENDANT;
14749:                     break;
14750:                 case AXIS_SELF:
14751:                 case AXIS_DESCENDANT_OR_SELF:
14752:                     /*
14753:                     * Convert "descendant-or-self::node()/self::" or
14754:                     * "descendant-or-self::node()/descendant-or-self::" to
14755:                     * to "descendant-or-self::"
14756:                     */
14757:                     op->ch1   = prevop->ch1;
14758:                     op->value = AXIS_DESCENDANT_OR_SELF;
14759:                     break;
14760:                 default:
14761:                     break;
14762:             }
14763: 	}
14764:     }
14765: 
14766:     /* Recurse */
14767:     if (op->ch1 != -1)
14768:         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14769:     if (op->ch2 != -1)
14770: 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14771: }
14772: 
14773: /**
14774:  * xmlXPathCtxtCompile:
14775:  * @ctxt: an XPath context
14776:  * @str:  the XPath expression
14777:  *
14778:  * Compile an XPath expression
14779:  *
14780:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781:  *         the caller has to free the object.
14782:  */
14783: xmlXPathCompExprPtr
14784: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14785:     xmlXPathParserContextPtr pctxt;
14786:     xmlXPathCompExprPtr comp;
14787: 
14788: #ifdef XPATH_STREAMING
14789:     comp = xmlXPathTryStreamCompile(ctxt, str);
14790:     if (comp != NULL)
14791:         return(comp);
14792: #endif
14793: 
14794:     xmlXPathInit();
14795: 
14796:     pctxt = xmlXPathNewParserContext(str, ctxt);
14797:     if (pctxt == NULL)
14798:         return NULL;
14799:     xmlXPathCompileExpr(pctxt, 1);
14800: 
14801:     if( pctxt->error != XPATH_EXPRESSION_OK )
14802:     {
14803:         xmlXPathFreeParserContext(pctxt);
14804:         return(NULL);
14805:     }
14806: 
14807:     if (*pctxt->cur != 0) {
14808: 	/*
14809: 	 * aleksey: in some cases this line prints *second* error message
14810: 	 * (see bug #78858) and probably this should be fixed.
14811: 	 * However, we are not sure that all error messages are printed
14812: 	 * out in other places. It's not critical so we leave it as-is for now
14813: 	 */
14814: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14815: 	comp = NULL;
14816:     } else {
14817: 	comp = pctxt->comp;
14818: 	pctxt->comp = NULL;
14819:     }
14820:     xmlXPathFreeParserContext(pctxt);
14821: 
14822:     if (comp != NULL) {
14823: 	comp->expr = xmlStrdup(str);
14824: #ifdef DEBUG_EVAL_COUNTS
14825: 	comp->string = xmlStrdup(str);
14826: 	comp->nb = 0;
14827: #endif
14828: 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14829: 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14830: 	}
14831:     }
14832:     return(comp);
14833: }
14834: 
14835: /**
14836:  * xmlXPathCompile:
14837:  * @str:  the XPath expression
14838:  *
14839:  * Compile an XPath expression
14840:  *
14841:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14842:  *         the caller has to free the object.
14843:  */
14844: xmlXPathCompExprPtr
14845: xmlXPathCompile(const xmlChar *str) {
14846:     return(xmlXPathCtxtCompile(NULL, str));
14847: }
14848: 
14849: /**
14850:  * xmlXPathCompiledEvalInternal:
14851:  * @comp:  the compiled XPath expression
14852:  * @ctxt:  the XPath context
14853:  * @resObj: the resulting XPath object or NULL
14854:  * @toBool: 1 if only a boolean result is requested
14855:  *
14856:  * Evaluate the Precompiled XPath expression in the given context.
14857:  * The caller has to free @resObj.
14858:  *
14859:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860:  *         the caller has to free the object.
14861:  */
14862: static int
14863: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14864: 			     xmlXPathContextPtr ctxt,
14865: 			     xmlXPathObjectPtr *resObj,
14866: 			     int toBool)
14867: {
14868:     xmlXPathParserContextPtr pctxt;
14869: #ifndef LIBXML_THREAD_ENABLED
14870:     static int reentance = 0;
14871: #endif
14872:     int res;
14873: 
14874:     CHECK_CTXT_NEG(ctxt)
14875: 
14876:     if (comp == NULL)
14877: 	return(-1);
14878:     xmlXPathInit();
14879: 
14880: #ifndef LIBXML_THREAD_ENABLED
14881:     reentance++;
14882:     if (reentance > 1)
14883: 	xmlXPathDisableOptimizer = 1;
14884: #endif
14885: 
14886: #ifdef DEBUG_EVAL_COUNTS
14887:     comp->nb++;
14888:     if ((comp->string != NULL) && (comp->nb > 100)) {
14889: 	fprintf(stderr, "100 x %s\n", comp->string);
14890: 	comp->nb = 0;
14891:     }
14892: #endif
14893:     pctxt = xmlXPathCompParserContext(comp, ctxt);
14894:     res = xmlXPathRunEval(pctxt, toBool);
14895: 
14896:     if (resObj) {
14897: 	if (pctxt->value == NULL) {
14898: 	    xmlGenericError(xmlGenericErrorContext,
14899: 		"xmlXPathCompiledEval: evaluation failed\n");
14900: 	    *resObj = NULL;
14901: 	} else {
14902: 	    *resObj = valuePop(pctxt);
14903: 	}
14904:     }
14905: 
14906:     /*
14907:     * Pop all remaining objects from the stack.
14908:     */
14909:     if (pctxt->valueNr > 0) {
14910: 	xmlXPathObjectPtr tmp;
14911: 	int stack = 0;
14912: 
14913: 	do {
14914: 	    tmp = valuePop(pctxt);
14915: 	    if (tmp != NULL) {
14916: 		stack++;
14917: 		xmlXPathReleaseObject(ctxt, tmp);
14918: 	    }
14919: 	} while (tmp != NULL);
14920: 	if ((stack != 0) &&
14921: 	    ((toBool) || ((resObj) && (*resObj))))
14922: 	{
14923: 	    xmlGenericError(xmlGenericErrorContext,
14924: 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14925: 		stack);
14926: 	}
14927:     }
14928: 
14929:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14930: 	xmlXPathFreeObject(*resObj);
14931: 	*resObj = NULL;
14932:     }
14933:     pctxt->comp = NULL;
14934:     xmlXPathFreeParserContext(pctxt);
14935: #ifndef LIBXML_THREAD_ENABLED
14936:     reentance--;
14937: #endif
14938: 
14939:     return(res);
14940: }
14941: 
14942: /**
14943:  * xmlXPathCompiledEval:
14944:  * @comp:  the compiled XPath expression
14945:  * @ctx:  the XPath context
14946:  *
14947:  * Evaluate the Precompiled XPath expression in the given context.
14948:  *
14949:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950:  *         the caller has to free the object.
14951:  */
14952: xmlXPathObjectPtr
14953: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14954: {
14955:     xmlXPathObjectPtr res = NULL;
14956: 
14957:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14958:     return(res);
14959: }
14960: 
14961: /**
14962:  * xmlXPathCompiledEvalToBoolean:
14963:  * @comp:  the compiled XPath expression
14964:  * @ctxt:  the XPath context
14965:  *
14966:  * Applies the XPath boolean() function on the result of the given
14967:  * compiled expression.
14968:  *
14969:  * Returns 1 if the expression evaluated to true, 0 if to false and
14970:  *         -1 in API and internal errors.
14971:  */
14972: int
14973: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14974: 			      xmlXPathContextPtr ctxt)
14975: {
14976:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14977: }
14978: 
14979: /**
14980:  * xmlXPathEvalExpr:
14981:  * @ctxt:  the XPath Parser context
14982:  *
14983:  * Parse and evaluate an XPath expression in the given context,
14984:  * then push the result on the context stack
14985:  */
14986: void
14987: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14988: #ifdef XPATH_STREAMING
14989:     xmlXPathCompExprPtr comp;
14990: #endif
14991: 
14992:     if (ctxt == NULL) return;
14993: 
14994: #ifdef XPATH_STREAMING
14995:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14996:     if (comp != NULL) {
14997:         if (ctxt->comp != NULL)
14998: 	    xmlXPathFreeCompExpr(ctxt->comp);
14999:         ctxt->comp = comp;
15000: 	if (ctxt->cur != NULL)
15001: 	    while (*ctxt->cur != 0) ctxt->cur++;
15002:     } else
15003: #endif
15004:     {
15005: 	xmlXPathCompileExpr(ctxt, 1);
15006: 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15007: 	    (ctxt->comp != NULL) &&
15008: 	    (ctxt->comp->nbStep > 1) &&
15009: 	    (ctxt->comp->last >= 0))
15010: 	{
15011: 	    xmlXPathOptimizeExpression(ctxt->comp,
15012: 		&ctxt->comp->steps[ctxt->comp->last]);
15013: 	}
15014:     }
15015:     CHECK_ERROR;
15016:     xmlXPathRunEval(ctxt, 0);
15017: }
15018: 
15019: /**
15020:  * xmlXPathEval:
15021:  * @str:  the XPath expression
15022:  * @ctx:  the XPath context
15023:  *
15024:  * Evaluate the XPath Location Path in the given context.
15025:  *
15026:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027:  *         the caller has to free the object.
15028:  */
15029: xmlXPathObjectPtr
15030: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031:     xmlXPathParserContextPtr ctxt;
15032:     xmlXPathObjectPtr res, tmp, init = NULL;
15033:     int stack = 0;
15034: 
15035:     CHECK_CTXT(ctx)
15036: 
15037:     xmlXPathInit();
15038: 
15039:     ctxt = xmlXPathNewParserContext(str, ctx);
15040:     if (ctxt == NULL)
15041:         return NULL;
15042:     xmlXPathEvalExpr(ctxt);
15043: 
15044:     if (ctxt->value == NULL) {
15045: 	xmlGenericError(xmlGenericErrorContext,
15046: 		"xmlXPathEval: evaluation failed\n");
15047: 	res = NULL;
15048:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15049: #ifdef XPATH_STREAMING
15050:             && (ctxt->comp->stream == NULL)
15051: #endif
15052: 	      ) {
15053: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15054: 	res = NULL;
15055:     } else {
15056: 	res = valuePop(ctxt);
15057:     }
15058: 
15059:     do {
15060:         tmp = valuePop(ctxt);
15061: 	if (tmp != NULL) {
15062: 	    if (tmp != init)
15063: 		stack++;
15064: 	    xmlXPathReleaseObject(ctx, tmp);
15065:         }
15066:     } while (tmp != NULL);
15067:     if ((stack != 0) && (res != NULL)) {
15068: 	xmlGenericError(xmlGenericErrorContext,
15069: 		"xmlXPathEval: %d object left on the stack\n",
15070: 	        stack);
15071:     }
15072:     if (ctxt->error != XPATH_EXPRESSION_OK) {
15073: 	xmlXPathFreeObject(res);
15074: 	res = NULL;
15075:     }
15076: 
15077:     xmlXPathFreeParserContext(ctxt);
15078:     return(res);
15079: }
15080: 
15081: /**
15082:  * xmlXPathSetContextNode:
15083:  * @node: the node to to use as the context node
15084:  * @ctx:  the XPath context
15085:  *
15086:  * Sets 'node' as the context node. The node must be in the same
15087:  * document as that associated with the context.
15088:  *
15089:  * Returns -1 in case of error or 0 if successful
15090:  */
15091: int
15092: xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15093:     if ((node == NULL) || (ctx == NULL))
15094:         return(-1);
15095: 
15096:     if (node->doc == ctx->doc) {
15097:         ctx->node = node;
15098: 	return(0);
15099:     }
15100:     return(-1);
15101: }
15102: 
15103: /**
15104:  * xmlXPathNodeEval:
15105:  * @node: the node to to use as the context node
15106:  * @str:  the XPath expression
15107:  * @ctx:  the XPath context
15108:  *
15109:  * Evaluate the XPath Location Path in the given context. The node 'node'
15110:  * is set as the context node. The context node is not restored.
15111:  *
15112:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15113:  *         the caller has to free the object.
15114:  */
15115: xmlXPathObjectPtr
15116: xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15117:     if (str == NULL)
15118:         return(NULL);
15119:     if (xmlXPathSetContextNode(node, ctx) < 0)
15120:         return(NULL);
15121:     return(xmlXPathEval(str, ctx));
15122: }
15123: 
15124: /**
15125:  * xmlXPathEvalExpression:
15126:  * @str:  the XPath expression
15127:  * @ctxt:  the XPath context
15128:  *
15129:  * Evaluate the XPath expression in the given context.
15130:  *
15131:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15132:  *         the caller has to free the object.
15133:  */
15134: xmlXPathObjectPtr
15135: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15136:     xmlXPathParserContextPtr pctxt;
15137:     xmlXPathObjectPtr res, tmp;
15138:     int stack = 0;
15139: 
15140:     CHECK_CTXT(ctxt)
15141: 
15142:     xmlXPathInit();
15143: 
15144:     pctxt = xmlXPathNewParserContext(str, ctxt);
15145:     if (pctxt == NULL)
15146:         return NULL;
15147:     xmlXPathEvalExpr(pctxt);
15148: 
15149:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15150: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15151: 	res = NULL;
15152:     } else {
15153: 	res = valuePop(pctxt);
15154:     }
15155:     do {
15156:         tmp = valuePop(pctxt);
15157: 	if (tmp != NULL) {
15158: 	    xmlXPathReleaseObject(ctxt, tmp);
15159: 	    stack++;
15160: 	}
15161:     } while (tmp != NULL);
15162:     if ((stack != 0) && (res != NULL)) {
15163: 	xmlGenericError(xmlGenericErrorContext,
15164: 		"xmlXPathEvalExpression: %d object left on the stack\n",
15165: 	        stack);
15166:     }
15167:     xmlXPathFreeParserContext(pctxt);
15168:     return(res);
15169: }
15170: 
15171: /************************************************************************
15172:  *									*
15173:  *	Extra functions not pertaining to the XPath spec		*
15174:  *									*
15175:  ************************************************************************/
15176: /**
15177:  * xmlXPathEscapeUriFunction:
15178:  * @ctxt:  the XPath Parser context
15179:  * @nargs:  the number of arguments
15180:  *
15181:  * Implement the escape-uri() XPath function
15182:  *    string escape-uri(string $str, bool $escape-reserved)
15183:  *
15184:  * This function applies the URI escaping rules defined in section 2 of [RFC
15185:  * 2396] to the string supplied as $uri-part, which typically represents all
15186:  * or part of a URI. The effect of the function is to replace any special
15187:  * character in the string by an escape sequence of the form %xx%yy...,
15188:  * where xxyy... is the hexadecimal representation of the octets used to
15189:  * represent the character in UTF-8.
15190:  *
15191:  * The set of characters that are escaped depends on the setting of the
15192:  * boolean argument $escape-reserved.
15193:  *
15194:  * If $escape-reserved is true, all characters are escaped other than lower
15195:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15196:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15197:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15198:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15199:  * A-F).
15200:  *
15201:  * If $escape-reserved is false, the behavior differs in that characters
15202:  * referred to in [RFC 2396] as reserved characters are not escaped. These
15203:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15204:  *
15205:  * [RFC 2396] does not define whether escaped URIs should use lower case or
15206:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15207:  * compared using string comparison functions, this function must always use
15208:  * the upper-case letters A-F.
15209:  *
15210:  * Generally, $escape-reserved should be set to true when escaping a string
15211:  * that is to form a single part of a URI, and to false when escaping an
15212:  * entire URI or URI reference.
15213:  *
15214:  * In the case of non-ascii characters, the string is encoded according to
15215:  * utf-8 and then converted according to RFC 2396.
15216:  *
15217:  * Examples
15218:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15219:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15220:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15221:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15222:  *
15223:  */
15224: static void
15225: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15226:     xmlXPathObjectPtr str;
15227:     int escape_reserved;
15228:     xmlBufPtr target;
15229:     xmlChar *cptr;
15230:     xmlChar escape[4];
15231: 
15232:     CHECK_ARITY(2);
15233: 
15234:     escape_reserved = xmlXPathPopBoolean(ctxt);
15235: 
15236:     CAST_TO_STRING;
15237:     str = valuePop(ctxt);
15238: 
15239:     target = xmlBufCreate();
15240: 
15241:     escape[0] = '%';
15242:     escape[3] = 0;
15243: 
15244:     if (target) {
15245: 	for (cptr = str->stringval; *cptr; cptr++) {
15246: 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15247: 		(*cptr >= 'a' && *cptr <= 'z') ||
15248: 		(*cptr >= '0' && *cptr <= '9') ||
15249: 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15250: 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15251: 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15252: 		(*cptr == '%' &&
15253: 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15254: 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15255: 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15256: 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15257: 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15258: 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15259: 		(!escape_reserved &&
15260: 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15261: 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15262: 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15263: 		  *cptr == ','))) {
15264: 		xmlBufAdd(target, cptr, 1);
15265: 	    } else {
15266: 		if ((*cptr >> 4) < 10)
15267: 		    escape[1] = '0' + (*cptr >> 4);
15268: 		else
15269: 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15270: 		if ((*cptr & 0xF) < 10)
15271: 		    escape[2] = '0' + (*cptr & 0xF);
15272: 		else
15273: 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15274: 
15275: 		xmlBufAdd(target, &escape[0], 3);
15276: 	    }
15277: 	}
15278:     }
15279:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15280: 	xmlBufContent(target)));
15281:     xmlBufFree(target);
15282:     xmlXPathReleaseObject(ctxt->context, str);
15283: }
15284: 
15285: /**
15286:  * xmlXPathRegisterAllFunctions:
15287:  * @ctxt:  the XPath context
15288:  *
15289:  * Registers all default XPath functions in this context
15290:  */
15291: void
15292: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15293: {
15294:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15295:                          xmlXPathBooleanFunction);
15296:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15297:                          xmlXPathCeilingFunction);
15298:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15299:                          xmlXPathCountFunction);
15300:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15301:                          xmlXPathConcatFunction);
15302:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15303:                          xmlXPathContainsFunction);
15304:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15305:                          xmlXPathIdFunction);
15306:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15307:                          xmlXPathFalseFunction);
15308:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15309:                          xmlXPathFloorFunction);
15310:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15311:                          xmlXPathLastFunction);
15312:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15313:                          xmlXPathLangFunction);
15314:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15315:                          xmlXPathLocalNameFunction);
15316:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15317:                          xmlXPathNotFunction);
15318:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15319:                          xmlXPathNameFunction);
15320:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15321:                          xmlXPathNamespaceURIFunction);
15322:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15323:                          xmlXPathNormalizeFunction);
15324:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15325:                          xmlXPathNumberFunction);
15326:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15327:                          xmlXPathPositionFunction);
15328:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15329:                          xmlXPathRoundFunction);
15330:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15331:                          xmlXPathStringFunction);
15332:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15333:                          xmlXPathStringLengthFunction);
15334:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15335:                          xmlXPathStartsWithFunction);
15336:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15337:                          xmlXPathSubstringFunction);
15338:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15339:                          xmlXPathSubstringBeforeFunction);
15340:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15341:                          xmlXPathSubstringAfterFunction);
15342:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15343:                          xmlXPathSumFunction);
15344:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15345:                          xmlXPathTrueFunction);
15346:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15347:                          xmlXPathTranslateFunction);
15348: 
15349:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15350: 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15351:                          xmlXPathEscapeUriFunction);
15352: }
15353: 
15354: #endif /* LIBXML_XPATH_ENABLED */
15355: #define bottom_xpath
15356: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>