File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xpath.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

    1: /*
    2:  * xpath.c: XML Path Language implementation
    3:  *          XPath is a language for addressing parts of an XML document,
    4:  *          designed to be used by both XSLT and XPointer
    5:  *f
    6:  * Reference: W3C Recommendation 16 November 1999
    7:  *     http://www.w3.org/TR/1999/REC-xpath-19991116
    8:  * Public reference:
    9:  *     http://www.w3.org/TR/xpath
   10:  *
   11:  * See Copyright for the status of this software
   12:  *
   13:  * Author: daniel@veillard.com
   14:  *
   15:  */
   16: 
   17: #define IN_LIBXML
   18: #include "libxml.h"
   19: 
   20: #include <string.h>
   21: 
   22: #ifdef HAVE_SYS_TYPES_H
   23: #include <sys/types.h>
   24: #endif
   25: #ifdef HAVE_MATH_H
   26: #include <math.h>
   27: #endif
   28: #ifdef HAVE_FLOAT_H
   29: #include <float.h>
   30: #endif
   31: #ifdef HAVE_CTYPE_H
   32: #include <ctype.h>
   33: #endif
   34: #ifdef HAVE_SIGNAL_H
   35: #include <signal.h>
   36: #endif
   37: 
   38: #include <libxml/xmlmemory.h>
   39: #include <libxml/tree.h>
   40: #include <libxml/valid.h>
   41: #include <libxml/xpath.h>
   42: #include <libxml/xpathInternals.h>
   43: #include <libxml/parserInternals.h>
   44: #include <libxml/hash.h>
   45: #ifdef LIBXML_XPTR_ENABLED
   46: #include <libxml/xpointer.h>
   47: #endif
   48: #ifdef LIBXML_DEBUG_ENABLED
   49: #include <libxml/debugXML.h>
   50: #endif
   51: #include <libxml/xmlerror.h>
   52: #include <libxml/threads.h>
   53: #include <libxml/globals.h>
   54: #ifdef LIBXML_PATTERN_ENABLED
   55: #include <libxml/pattern.h>
   56: #endif
   57: 
   58: #ifdef LIBXML_PATTERN_ENABLED
   59: #define XPATH_STREAMING
   60: #endif
   61: 
   62: #define TODO								\
   63:     xmlGenericError(xmlGenericErrorContext,				\
   64: 	    "Unimplemented block at %s:%d\n",				\
   65:             __FILE__, __LINE__);
   66: 
   67: /*
   68: * XP_OPTIMIZED_NON_ELEM_COMPARISON:
   69: * If defined, this will use xmlXPathCmpNodesExt() instead of
   70: * xmlXPathCmpNodes(). The new function is optimized comparison of
   71: * non-element nodes; actually it will speed up comparison only if
   72: * xmlXPathOrderDocElems() was called in order to index the elements of
   73: * a tree in document order; Libxslt does such an indexing, thus it will
   74: * benefit from this optimization.
   75: */
   76: #define XP_OPTIMIZED_NON_ELEM_COMPARISON
   77: 
   78: /*
   79: * XP_OPTIMIZED_FILTER_FIRST:
   80: * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
   81: * in a way, that it stop evaluation at the first node.
   82: */
   83: #define XP_OPTIMIZED_FILTER_FIRST
   84: 
   85: /*
   86: * XP_DEBUG_OBJ_USAGE:
   87: * Internal flag to enable tracking of how much XPath objects have been
   88: * created.
   89: */
   90: /* #define XP_DEBUG_OBJ_USAGE */
   91: 
   92: /*
   93:  * TODO:
   94:  * There are a few spots where some tests are done which depend upon ascii
   95:  * data.  These should be enhanced for full UTF8 support (see particularly
   96:  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
   97:  */
   98: 
   99: #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  100: 
  101: /************************************************************************
  102:  *									*
  103:  *			Floating point stuff				*
  104:  *									*
  105:  ************************************************************************/
  106: 
  107: #ifndef TRIO_REPLACE_STDIO
  108: #define TRIO_PUBLIC static
  109: #endif
  110: #include "trionan.c"
  111: 
  112: /*
  113:  * The lack of portability of this section of the libc is annoying !
  114:  */
  115: double xmlXPathNAN = 0;
  116: double xmlXPathPINF = 1;
  117: double xmlXPathNINF = -1;
  118: static double xmlXPathNZERO = 0; /* not exported from headers */
  119: static int xmlXPathInitialized = 0;
  120: 
  121: /**
  122:  * xmlXPathInit:
  123:  *
  124:  * Initialize the XPath environment
  125:  */
  126: void
  127: xmlXPathInit(void) {
  128:     if (xmlXPathInitialized) return;
  129: 
  130:     xmlXPathPINF = trio_pinf();
  131:     xmlXPathNINF = trio_ninf();
  132:     xmlXPathNAN = trio_nan();
  133:     xmlXPathNZERO = trio_nzero();
  134: 
  135:     xmlXPathInitialized = 1;
  136: }
  137: 
  138: /**
  139:  * xmlXPathIsNaN:
  140:  * @val:  a double value
  141:  *
  142:  * Provides a portable isnan() function to detect whether a double
  143:  * is a NotaNumber. Based on trio code
  144:  * http://sourceforge.net/projects/ctrio/
  145:  *
  146:  * Returns 1 if the value is a NaN, 0 otherwise
  147:  */
  148: int
  149: xmlXPathIsNaN(double val) {
  150:     return(trio_isnan(val));
  151: }
  152: 
  153: /**
  154:  * xmlXPathIsInf:
  155:  * @val:  a double value
  156:  *
  157:  * Provides a portable isinf() function to detect whether a double
  158:  * is a +Infinite or -Infinite. Based on trio code
  159:  * http://sourceforge.net/projects/ctrio/
  160:  *
  161:  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
  162:  */
  163: int
  164: xmlXPathIsInf(double val) {
  165:     return(trio_isinf(val));
  166: }
  167: 
  168: #endif /* SCHEMAS or XPATH */
  169: #ifdef LIBXML_XPATH_ENABLED
  170: /**
  171:  * xmlXPathGetSign:
  172:  * @val:  a double value
  173:  *
  174:  * Provides a portable function to detect the sign of a double
  175:  * Modified from trio code
  176:  * http://sourceforge.net/projects/ctrio/
  177:  *
  178:  * Returns 1 if the value is Negative, 0 if positive
  179:  */
  180: static int
  181: xmlXPathGetSign(double val) {
  182:     return(trio_signbit(val));
  183: }
  184: 
  185: 
  186: /*
  187:  * TODO: when compatibility allows remove all "fake node libxslt" strings
  188:  *       the test should just be name[0] = ' '
  189:  */
  190: #ifdef DEBUG_XPATH_EXPRESSION
  191: #define DEBUG_STEP
  192: #define DEBUG_EXPR
  193: #define DEBUG_EVAL_COUNTS
  194: #endif
  195: 
  196: static xmlNs xmlXPathXMLNamespaceStruct = {
  197:     NULL,
  198:     XML_NAMESPACE_DECL,
  199:     XML_XML_NAMESPACE,
  200:     BAD_CAST "xml",
  201:     NULL,
  202:     NULL
  203: };
  204: static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  205: #ifndef LIBXML_THREAD_ENABLED
  206: /*
  207:  * Optimizer is disabled only when threaded apps are detected while
  208:  * the library ain't compiled for thread safety.
  209:  */
  210: static int xmlXPathDisableOptimizer = 0;
  211: #endif
  212: 
  213: /************************************************************************
  214:  *									*
  215:  *			Error handling routines				*
  216:  *									*
  217:  ************************************************************************/
  218: 
  219: /**
  220:  * XP_ERRORNULL:
  221:  * @X:  the error code
  222:  *
  223:  * Macro to raise an XPath error and return NULL.
  224:  */
  225: #define XP_ERRORNULL(X)							\
  226:     { xmlXPathErr(ctxt, X); return(NULL); }
  227: 
  228: /*
  229:  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  230:  */
  231: static const char *xmlXPathErrorMessages[] = {
  232:     "Ok\n",
  233:     "Number encoding\n",
  234:     "Unfinished literal\n",
  235:     "Start of literal\n",
  236:     "Expected $ for variable reference\n",
  237:     "Undefined variable\n",
  238:     "Invalid predicate\n",
  239:     "Invalid expression\n",
  240:     "Missing closing curly brace\n",
  241:     "Unregistered function\n",
  242:     "Invalid operand\n",
  243:     "Invalid type\n",
  244:     "Invalid number of arguments\n",
  245:     "Invalid context size\n",
  246:     "Invalid context position\n",
  247:     "Memory allocation error\n",
  248:     "Syntax error\n",
  249:     "Resource error\n",
  250:     "Sub resource error\n",
  251:     "Undefined namespace prefix\n",
  252:     "Encoding error\n",
  253:     "Char out of XML range\n",
  254:     "Invalid or incomplete context\n",
  255:     "?? Unknown error ??\n"	/* Must be last in the list! */
  256: };
  257: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
  258: 		   sizeof(xmlXPathErrorMessages[0])) - 1)
  259: /**
  260:  * xmlXPathErrMemory:
  261:  * @ctxt:  an XPath context
  262:  * @extra:  extra informations
  263:  *
  264:  * Handle a redefinition of attribute error
  265:  */
  266: static void
  267: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  268: {
  269:     if (ctxt != NULL) {
  270:         if (extra) {
  271:             xmlChar buf[200];
  272: 
  273:             xmlStrPrintf(buf, 200,
  274:                          BAD_CAST "Memory allocation failed : %s\n",
  275:                          extra);
  276:             ctxt->lastError.message = (char *) xmlStrdup(buf);
  277:         } else {
  278:             ctxt->lastError.message = (char *)
  279: 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
  280:         }
  281:         ctxt->lastError.domain = XML_FROM_XPATH;
  282:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
  283: 	if (ctxt->error != NULL)
  284: 	    ctxt->error(ctxt->userData, &ctxt->lastError);
  285:     } else {
  286:         if (extra)
  287:             __xmlRaiseError(NULL, NULL, NULL,
  288:                             NULL, NULL, XML_FROM_XPATH,
  289:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  290:                             extra, NULL, NULL, 0, 0,
  291:                             "Memory allocation failed : %s\n", extra);
  292:         else
  293:             __xmlRaiseError(NULL, NULL, NULL,
  294:                             NULL, NULL, XML_FROM_XPATH,
  295:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  296:                             NULL, NULL, NULL, 0, 0,
  297:                             "Memory allocation failed\n");
  298:     }
  299: }
  300: 
  301: /**
  302:  * xmlXPathPErrMemory:
  303:  * @ctxt:  an XPath parser context
  304:  * @extra:  extra informations
  305:  *
  306:  * Handle a redefinition of attribute error
  307:  */
  308: static void
  309: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  310: {
  311:     if (ctxt == NULL)
  312: 	xmlXPathErrMemory(NULL, extra);
  313:     else {
  314: 	ctxt->error = XPATH_MEMORY_ERROR;
  315: 	xmlXPathErrMemory(ctxt->context, extra);
  316:     }
  317: }
  318: 
  319: /**
  320:  * xmlXPathErr:
  321:  * @ctxt:  a XPath parser context
  322:  * @error:  the error code
  323:  *
  324:  * Handle an XPath error
  325:  */
  326: void
  327: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  328: {
  329:     if ((error < 0) || (error > MAXERRNO))
  330: 	error = MAXERRNO;
  331:     if (ctxt == NULL) {
  332: 	__xmlRaiseError(NULL, NULL, NULL,
  333: 			NULL, NULL, XML_FROM_XPATH,
  334: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  335: 			XML_ERR_ERROR, NULL, 0,
  336: 			NULL, NULL, NULL, 0, 0,
  337: 			"%s", xmlXPathErrorMessages[error]);
  338: 	return;
  339:     }
  340:     ctxt->error = error;
  341:     if (ctxt->context == NULL) {
  342: 	__xmlRaiseError(NULL, NULL, NULL,
  343: 			NULL, NULL, XML_FROM_XPATH,
  344: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  345: 			XML_ERR_ERROR, NULL, 0,
  346: 			(const char *) ctxt->base, NULL, NULL,
  347: 			ctxt->cur - ctxt->base, 0,
  348: 			"%s", xmlXPathErrorMessages[error]);
  349: 	return;
  350:     }
  351: 
  352:     /* cleanup current last error */
  353:     xmlResetError(&ctxt->context->lastError);
  354: 
  355:     ctxt->context->lastError.domain = XML_FROM_XPATH;
  356:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  357:                            XPATH_EXPRESSION_OK;
  358:     ctxt->context->lastError.level = XML_ERR_ERROR;
  359:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  360:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  361:     ctxt->context->lastError.node = ctxt->context->debugNode;
  362:     if (ctxt->context->error != NULL) {
  363: 	ctxt->context->error(ctxt->context->userData,
  364: 	                     &ctxt->context->lastError);
  365:     } else {
  366: 	__xmlRaiseError(NULL, NULL, NULL,
  367: 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  368: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  369: 			XML_ERR_ERROR, NULL, 0,
  370: 			(const char *) ctxt->base, NULL, NULL,
  371: 			ctxt->cur - ctxt->base, 0,
  372: 			"%s", xmlXPathErrorMessages[error]);
  373:     }
  374: 
  375: }
  376: 
  377: /**
  378:  * xmlXPatherror:
  379:  * @ctxt:  the XPath Parser context
  380:  * @file:  the file name
  381:  * @line:  the line number
  382:  * @no:  the error number
  383:  *
  384:  * Formats an error message.
  385:  */
  386: void
  387: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  388:               int line ATTRIBUTE_UNUSED, int no) {
  389:     xmlXPathErr(ctxt, no);
  390: }
  391: 
  392: /************************************************************************
  393:  *									*
  394:  *			Utilities					*
  395:  *									*
  396:  ************************************************************************/
  397: 
  398: /**
  399:  * xsltPointerList:
  400:  *
  401:  * Pointer-list for various purposes.
  402:  */
  403: typedef struct _xmlPointerList xmlPointerList;
  404: typedef xmlPointerList *xmlPointerListPtr;
  405: struct _xmlPointerList {
  406:     void **items;
  407:     int number;
  408:     int size;
  409: };
  410: /*
  411: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  412: * and here, we should make the functions public.
  413: */
  414: static int
  415: xmlPointerListAddSize(xmlPointerListPtr list,
  416: 		       void *item,
  417: 		       int initialSize)
  418: {
  419:     if (list->items == NULL) {
  420: 	if (initialSize <= 0)
  421: 	    initialSize = 1;
  422: 	list->items = (void **) xmlMalloc(
  423: 	    initialSize * sizeof(void *));
  424: 	if (list->items == NULL) {
  425: 	    xmlXPathErrMemory(NULL,
  426: 		"xmlPointerListCreate: allocating item\n");
  427: 	    return(-1);
  428: 	}
  429: 	list->number = 0;
  430: 	list->size = initialSize;
  431:     } else if (list->size <= list->number) {
  432: 	list->size *= 2;
  433: 	list->items = (void **) xmlRealloc(list->items,
  434: 	    list->size * sizeof(void *));
  435: 	if (list->items == NULL) {
  436: 	    xmlXPathErrMemory(NULL,
  437: 		"xmlPointerListCreate: re-allocating item\n");
  438: 	    list->size = 0;
  439: 	    return(-1);
  440: 	}
  441:     }
  442:     list->items[list->number++] = item;
  443:     return(0);
  444: }
  445: 
  446: /**
  447:  * xsltPointerListCreate:
  448:  *
  449:  * Creates an xsltPointerList structure.
  450:  *
  451:  * Returns a xsltPointerList structure or NULL in case of an error.
  452:  */
  453: static xmlPointerListPtr
  454: xmlPointerListCreate(int initialSize)
  455: {
  456:     xmlPointerListPtr ret;
  457: 
  458:     ret = xmlMalloc(sizeof(xmlPointerList));
  459:     if (ret == NULL) {
  460: 	xmlXPathErrMemory(NULL,
  461: 	    "xmlPointerListCreate: allocating item\n");
  462: 	return (NULL);
  463:     }
  464:     memset(ret, 0, sizeof(xmlPointerList));
  465:     if (initialSize > 0) {
  466: 	xmlPointerListAddSize(ret, NULL, initialSize);
  467: 	ret->number = 0;
  468:     }
  469:     return (ret);
  470: }
  471: 
  472: /**
  473:  * xsltPointerListFree:
  474:  *
  475:  * Frees the xsltPointerList structure. This does not free
  476:  * the content of the list.
  477:  */
  478: static void
  479: xmlPointerListFree(xmlPointerListPtr list)
  480: {
  481:     if (list == NULL)
  482: 	return;
  483:     if (list->items != NULL)
  484: 	xmlFree(list->items);
  485:     xmlFree(list);
  486: }
  487: 
  488: /************************************************************************
  489:  *									*
  490:  *			Parser Types					*
  491:  *									*
  492:  ************************************************************************/
  493: 
  494: /*
  495:  * Types are private:
  496:  */
  497: 
  498: typedef enum {
  499:     XPATH_OP_END=0,
  500:     XPATH_OP_AND,
  501:     XPATH_OP_OR,
  502:     XPATH_OP_EQUAL,
  503:     XPATH_OP_CMP,
  504:     XPATH_OP_PLUS,
  505:     XPATH_OP_MULT,
  506:     XPATH_OP_UNION,
  507:     XPATH_OP_ROOT,
  508:     XPATH_OP_NODE,
  509:     XPATH_OP_RESET, /* 10 */
  510:     XPATH_OP_COLLECT,
  511:     XPATH_OP_VALUE, /* 12 */
  512:     XPATH_OP_VARIABLE,
  513:     XPATH_OP_FUNCTION,
  514:     XPATH_OP_ARG,
  515:     XPATH_OP_PREDICATE,
  516:     XPATH_OP_FILTER, /* 17 */
  517:     XPATH_OP_SORT /* 18 */
  518: #ifdef LIBXML_XPTR_ENABLED
  519:     ,XPATH_OP_RANGETO
  520: #endif
  521: } xmlXPathOp;
  522: 
  523: typedef enum {
  524:     AXIS_ANCESTOR = 1,
  525:     AXIS_ANCESTOR_OR_SELF,
  526:     AXIS_ATTRIBUTE,
  527:     AXIS_CHILD,
  528:     AXIS_DESCENDANT,
  529:     AXIS_DESCENDANT_OR_SELF,
  530:     AXIS_FOLLOWING,
  531:     AXIS_FOLLOWING_SIBLING,
  532:     AXIS_NAMESPACE,
  533:     AXIS_PARENT,
  534:     AXIS_PRECEDING,
  535:     AXIS_PRECEDING_SIBLING,
  536:     AXIS_SELF
  537: } xmlXPathAxisVal;
  538: 
  539: typedef enum {
  540:     NODE_TEST_NONE = 0,
  541:     NODE_TEST_TYPE = 1,
  542:     NODE_TEST_PI = 2,
  543:     NODE_TEST_ALL = 3,
  544:     NODE_TEST_NS = 4,
  545:     NODE_TEST_NAME = 5
  546: } xmlXPathTestVal;
  547: 
  548: typedef enum {
  549:     NODE_TYPE_NODE = 0,
  550:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  551:     NODE_TYPE_TEXT = XML_TEXT_NODE,
  552:     NODE_TYPE_PI = XML_PI_NODE
  553: } xmlXPathTypeVal;
  554: 
  555: #define XP_REWRITE_DOS_CHILD_ELEM 1
  556: 
  557: typedef struct _xmlXPathStepOp xmlXPathStepOp;
  558: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  559: struct _xmlXPathStepOp {
  560:     xmlXPathOp op;		/* The identifier of the operation */
  561:     int ch1;			/* First child */
  562:     int ch2;			/* Second child */
  563:     int value;
  564:     int value2;
  565:     int value3;
  566:     void *value4;
  567:     void *value5;
  568:     void *cache;
  569:     void *cacheURI;
  570:     int rewriteType;
  571: };
  572: 
  573: struct _xmlXPathCompExpr {
  574:     int nbStep;			/* Number of steps in this expression */
  575:     int maxStep;		/* Maximum number of steps allocated */
  576:     xmlXPathStepOp *steps;	/* ops for computation of this expression */
  577:     int last;			/* index of last step in expression */
  578:     xmlChar *expr;		/* the expression being computed */
  579:     xmlDictPtr dict;		/* the dictionnary to use if any */
  580: #ifdef DEBUG_EVAL_COUNTS
  581:     int nb;
  582:     xmlChar *string;
  583: #endif
  584: #ifdef XPATH_STREAMING
  585:     xmlPatternPtr stream;
  586: #endif
  587: };
  588: 
  589: /************************************************************************
  590:  *									*
  591:  *			Forward declarations				*
  592:  *									*
  593:  ************************************************************************/
  594: static void
  595: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  596: static void
  597: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  598: static int
  599: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  600:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
  601: static int
  602: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  603: 			    xmlXPathStepOpPtr op,
  604: 			    int isPredicate);
  605: 
  606: /************************************************************************
  607:  *									*
  608:  *			Parser Type functions				*
  609:  *									*
  610:  ************************************************************************/
  611: 
  612: /**
  613:  * xmlXPathNewCompExpr:
  614:  *
  615:  * Create a new Xpath component
  616:  *
  617:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  618:  */
  619: static xmlXPathCompExprPtr
  620: xmlXPathNewCompExpr(void) {
  621:     xmlXPathCompExprPtr cur;
  622: 
  623:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  624:     if (cur == NULL) {
  625:         xmlXPathErrMemory(NULL, "allocating component\n");
  626: 	return(NULL);
  627:     }
  628:     memset(cur, 0, sizeof(xmlXPathCompExpr));
  629:     cur->maxStep = 10;
  630:     cur->nbStep = 0;
  631:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  632: 	                                   sizeof(xmlXPathStepOp));
  633:     if (cur->steps == NULL) {
  634:         xmlXPathErrMemory(NULL, "allocating steps\n");
  635: 	xmlFree(cur);
  636: 	return(NULL);
  637:     }
  638:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  639:     cur->last = -1;
  640: #ifdef DEBUG_EVAL_COUNTS
  641:     cur->nb = 0;
  642: #endif
  643:     return(cur);
  644: }
  645: 
  646: /**
  647:  * xmlXPathFreeCompExpr:
  648:  * @comp:  an XPATH comp
  649:  *
  650:  * Free up the memory allocated by @comp
  651:  */
  652: void
  653: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  654: {
  655:     xmlXPathStepOpPtr op;
  656:     int i;
  657: 
  658:     if (comp == NULL)
  659:         return;
  660:     if (comp->dict == NULL) {
  661: 	for (i = 0; i < comp->nbStep; i++) {
  662: 	    op = &comp->steps[i];
  663: 	    if (op->value4 != NULL) {
  664: 		if (op->op == XPATH_OP_VALUE)
  665: 		    xmlXPathFreeObject(op->value4);
  666: 		else
  667: 		    xmlFree(op->value4);
  668: 	    }
  669: 	    if (op->value5 != NULL)
  670: 		xmlFree(op->value5);
  671: 	}
  672:     } else {
  673: 	for (i = 0; i < comp->nbStep; i++) {
  674: 	    op = &comp->steps[i];
  675: 	    if (op->value4 != NULL) {
  676: 		if (op->op == XPATH_OP_VALUE)
  677: 		    xmlXPathFreeObject(op->value4);
  678: 	    }
  679: 	}
  680:         xmlDictFree(comp->dict);
  681:     }
  682:     if (comp->steps != NULL) {
  683:         xmlFree(comp->steps);
  684:     }
  685: #ifdef DEBUG_EVAL_COUNTS
  686:     if (comp->string != NULL) {
  687:         xmlFree(comp->string);
  688:     }
  689: #endif
  690: #ifdef XPATH_STREAMING
  691:     if (comp->stream != NULL) {
  692:         xmlFreePatternList(comp->stream);
  693:     }
  694: #endif
  695:     if (comp->expr != NULL) {
  696:         xmlFree(comp->expr);
  697:     }
  698: 
  699:     xmlFree(comp);
  700: }
  701: 
  702: /**
  703:  * xmlXPathCompExprAdd:
  704:  * @comp:  the compiled expression
  705:  * @ch1: first child index
  706:  * @ch2: second child index
  707:  * @op:  an op
  708:  * @value:  the first int value
  709:  * @value2:  the second int value
  710:  * @value3:  the third int value
  711:  * @value4:  the first string value
  712:  * @value5:  the second string value
  713:  *
  714:  * Add a step to an XPath Compiled Expression
  715:  *
  716:  * Returns -1 in case of failure, the index otherwise
  717:  */
  718: static int
  719: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
  720:    xmlXPathOp op, int value,
  721:    int value2, int value3, void *value4, void *value5) {
  722:     if (comp->nbStep >= comp->maxStep) {
  723: 	xmlXPathStepOp *real;
  724: 
  725: 	comp->maxStep *= 2;
  726: 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  727: 		                      comp->maxStep * sizeof(xmlXPathStepOp));
  728: 	if (real == NULL) {
  729: 	    comp->maxStep /= 2;
  730: 	    xmlXPathErrMemory(NULL, "adding step\n");
  731: 	    return(-1);
  732: 	}
  733: 	comp->steps = real;
  734:     }
  735:     comp->last = comp->nbStep;
  736:     comp->steps[comp->nbStep].rewriteType = 0;
  737:     comp->steps[comp->nbStep].ch1 = ch1;
  738:     comp->steps[comp->nbStep].ch2 = ch2;
  739:     comp->steps[comp->nbStep].op = op;
  740:     comp->steps[comp->nbStep].value = value;
  741:     comp->steps[comp->nbStep].value2 = value2;
  742:     comp->steps[comp->nbStep].value3 = value3;
  743:     if ((comp->dict != NULL) &&
  744:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  745: 	 (op == XPATH_OP_COLLECT))) {
  746:         if (value4 != NULL) {
  747: 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
  748: 	        (void *)xmlDictLookup(comp->dict, value4, -1);
  749: 	    xmlFree(value4);
  750: 	} else
  751: 	    comp->steps[comp->nbStep].value4 = NULL;
  752:         if (value5 != NULL) {
  753: 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
  754: 	        (void *)xmlDictLookup(comp->dict, value5, -1);
  755: 	    xmlFree(value5);
  756: 	} else
  757: 	    comp->steps[comp->nbStep].value5 = NULL;
  758:     } else {
  759: 	comp->steps[comp->nbStep].value4 = value4;
  760: 	comp->steps[comp->nbStep].value5 = value5;
  761:     }
  762:     comp->steps[comp->nbStep].cache = NULL;
  763:     return(comp->nbStep++);
  764: }
  765: 
  766: /**
  767:  * xmlXPathCompSwap:
  768:  * @comp:  the compiled expression
  769:  * @op: operation index
  770:  *
  771:  * Swaps 2 operations in the compiled expression
  772:  */
  773: static void
  774: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  775:     int tmp;
  776: 
  777: #ifndef LIBXML_THREAD_ENABLED
  778:     /*
  779:      * Since this manipulates possibly shared variables, this is
  780:      * disabled if one detects that the library is used in a multithreaded
  781:      * application
  782:      */
  783:     if (xmlXPathDisableOptimizer)
  784: 	return;
  785: #endif
  786: 
  787:     tmp = op->ch1;
  788:     op->ch1 = op->ch2;
  789:     op->ch2 = tmp;
  790: }
  791: 
  792: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
  793:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
  794: 	                (op), (val), (val2), (val3), (val4), (val5))
  795: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
  796:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
  797: 	                (op), (val), (val2), (val3), (val4), (val5))
  798: 
  799: #define PUSH_LEAVE_EXPR(op, val, val2)					\
  800: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  801: 
  802: #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
  803: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  804: 
  805: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
  806: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
  807: 			(val), (val2), 0 ,NULL ,NULL)
  808: 
  809: /************************************************************************
  810:  *									*
  811:  *		XPath object cache structures				*
  812:  *									*
  813:  ************************************************************************/
  814: 
  815: /* #define XP_DEFAULT_CACHE_ON */
  816: 
  817: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  818: 
  819: typedef struct _xmlXPathContextCache xmlXPathContextCache;
  820: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  821: struct _xmlXPathContextCache {
  822:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
  823:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
  824:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
  825:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
  826:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
  827:     int maxNodeset;
  828:     int maxString;
  829:     int maxBoolean;
  830:     int maxNumber;
  831:     int maxMisc;
  832: #ifdef XP_DEBUG_OBJ_USAGE
  833:     int dbgCachedAll;
  834:     int dbgCachedNodeset;
  835:     int dbgCachedString;
  836:     int dbgCachedBool;
  837:     int dbgCachedNumber;
  838:     int dbgCachedPoint;
  839:     int dbgCachedRange;
  840:     int dbgCachedLocset;
  841:     int dbgCachedUsers;
  842:     int dbgCachedXSLTTree;
  843:     int dbgCachedUndefined;
  844: 
  845: 
  846:     int dbgReusedAll;
  847:     int dbgReusedNodeset;
  848:     int dbgReusedString;
  849:     int dbgReusedBool;
  850:     int dbgReusedNumber;
  851:     int dbgReusedPoint;
  852:     int dbgReusedRange;
  853:     int dbgReusedLocset;
  854:     int dbgReusedUsers;
  855:     int dbgReusedXSLTTree;
  856:     int dbgReusedUndefined;
  857: 
  858: #endif
  859: };
  860: 
  861: /************************************************************************
  862:  *									*
  863:  *		Debugging related functions				*
  864:  *									*
  865:  ************************************************************************/
  866: 
  867: #define STRANGE							\
  868:     xmlGenericError(xmlGenericErrorContext,				\
  869: 	    "Internal error at %s:%d\n",				\
  870:             __FILE__, __LINE__);
  871: 
  872: #ifdef LIBXML_DEBUG_ENABLED
  873: static void
  874: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  875:     int i;
  876:     char shift[100];
  877: 
  878:     for (i = 0;((i < depth) && (i < 25));i++)
  879:         shift[2 * i] = shift[2 * i + 1] = ' ';
  880:     shift[2 * i] = shift[2 * i + 1] = 0;
  881:     if (cur == NULL) {
  882: 	fprintf(output, "%s", shift);
  883: 	fprintf(output, "Node is NULL !\n");
  884: 	return;
  885: 
  886:     }
  887: 
  888:     if ((cur->type == XML_DOCUMENT_NODE) ||
  889: 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
  890: 	fprintf(output, "%s", shift);
  891: 	fprintf(output, " /\n");
  892:     } else if (cur->type == XML_ATTRIBUTE_NODE)
  893: 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  894:     else
  895: 	xmlDebugDumpOneNode(output, cur, depth);
  896: }
  897: static void
  898: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  899:     xmlNodePtr tmp;
  900:     int i;
  901:     char shift[100];
  902: 
  903:     for (i = 0;((i < depth) && (i < 25));i++)
  904:         shift[2 * i] = shift[2 * i + 1] = ' ';
  905:     shift[2 * i] = shift[2 * i + 1] = 0;
  906:     if (cur == NULL) {
  907: 	fprintf(output, "%s", shift);
  908: 	fprintf(output, "Node is NULL !\n");
  909: 	return;
  910: 
  911:     }
  912: 
  913:     while (cur != NULL) {
  914: 	tmp = cur;
  915: 	cur = cur->next;
  916: 	xmlDebugDumpOneNode(output, tmp, depth);
  917:     }
  918: }
  919: 
  920: static void
  921: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  922:     int i;
  923:     char shift[100];
  924: 
  925:     for (i = 0;((i < depth) && (i < 25));i++)
  926:         shift[2 * i] = shift[2 * i + 1] = ' ';
  927:     shift[2 * i] = shift[2 * i + 1] = 0;
  928: 
  929:     if (cur == NULL) {
  930: 	fprintf(output, "%s", shift);
  931: 	fprintf(output, "NodeSet is NULL !\n");
  932: 	return;
  933: 
  934:     }
  935: 
  936:     if (cur != NULL) {
  937: 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  938: 	for (i = 0;i < cur->nodeNr;i++) {
  939: 	    fprintf(output, "%s", shift);
  940: 	    fprintf(output, "%d", i + 1);
  941: 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  942: 	}
  943:     }
  944: }
  945: 
  946: static void
  947: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  948:     int i;
  949:     char shift[100];
  950: 
  951:     for (i = 0;((i < depth) && (i < 25));i++)
  952:         shift[2 * i] = shift[2 * i + 1] = ' ';
  953:     shift[2 * i] = shift[2 * i + 1] = 0;
  954: 
  955:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  956: 	fprintf(output, "%s", shift);
  957: 	fprintf(output, "Value Tree is NULL !\n");
  958: 	return;
  959: 
  960:     }
  961: 
  962:     fprintf(output, "%s", shift);
  963:     fprintf(output, "%d", i + 1);
  964:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  965: }
  966: #if defined(LIBXML_XPTR_ENABLED)
  967: static void
  968: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  969:     int i;
  970:     char shift[100];
  971: 
  972:     for (i = 0;((i < depth) && (i < 25));i++)
  973:         shift[2 * i] = shift[2 * i + 1] = ' ';
  974:     shift[2 * i] = shift[2 * i + 1] = 0;
  975: 
  976:     if (cur == NULL) {
  977: 	fprintf(output, "%s", shift);
  978: 	fprintf(output, "LocationSet is NULL !\n");
  979: 	return;
  980: 
  981:     }
  982: 
  983:     for (i = 0;i < cur->locNr;i++) {
  984: 	fprintf(output, "%s", shift);
  985:         fprintf(output, "%d : ", i + 1);
  986: 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  987:     }
  988: }
  989: #endif /* LIBXML_XPTR_ENABLED */
  990: 
  991: /**
  992:  * xmlXPathDebugDumpObject:
  993:  * @output:  the FILE * to dump the output
  994:  * @cur:  the object to inspect
  995:  * @depth:  indentation level
  996:  *
  997:  * Dump the content of the object for debugging purposes
  998:  */
  999: void
 1000: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
 1001:     int i;
 1002:     char shift[100];
 1003: 
 1004:     if (output == NULL) return;
 1005: 
 1006:     for (i = 0;((i < depth) && (i < 25));i++)
 1007:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1008:     shift[2 * i] = shift[2 * i + 1] = 0;
 1009: 
 1010: 
 1011:     fprintf(output, "%s", shift);
 1012: 
 1013:     if (cur == NULL) {
 1014:         fprintf(output, "Object is empty (NULL)\n");
 1015: 	return;
 1016:     }
 1017:     switch(cur->type) {
 1018:         case XPATH_UNDEFINED:
 1019: 	    fprintf(output, "Object is uninitialized\n");
 1020: 	    break;
 1021:         case XPATH_NODESET:
 1022: 	    fprintf(output, "Object is a Node Set :\n");
 1023: 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
 1024: 	    break;
 1025: 	case XPATH_XSLT_TREE:
 1026: 	    fprintf(output, "Object is an XSLT value tree :\n");
 1027: 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
 1028: 	    break;
 1029:         case XPATH_BOOLEAN:
 1030: 	    fprintf(output, "Object is a Boolean : ");
 1031: 	    if (cur->boolval) fprintf(output, "true\n");
 1032: 	    else fprintf(output, "false\n");
 1033: 	    break;
 1034:         case XPATH_NUMBER:
 1035: 	    switch (xmlXPathIsInf(cur->floatval)) {
 1036: 	    case 1:
 1037: 		fprintf(output, "Object is a number : Infinity\n");
 1038: 		break;
 1039: 	    case -1:
 1040: 		fprintf(output, "Object is a number : -Infinity\n");
 1041: 		break;
 1042: 	    default:
 1043: 		if (xmlXPathIsNaN(cur->floatval)) {
 1044: 		    fprintf(output, "Object is a number : NaN\n");
 1045: 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
 1046: 		    fprintf(output, "Object is a number : 0\n");
 1047: 		} else {
 1048: 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
 1049: 		}
 1050: 	    }
 1051: 	    break;
 1052:         case XPATH_STRING:
 1053: 	    fprintf(output, "Object is a string : ");
 1054: 	    xmlDebugDumpString(output, cur->stringval);
 1055: 	    fprintf(output, "\n");
 1056: 	    break;
 1057: 	case XPATH_POINT:
 1058: 	    fprintf(output, "Object is a point : index %d in node", cur->index);
 1059: 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
 1060: 	    fprintf(output, "\n");
 1061: 	    break;
 1062: 	case XPATH_RANGE:
 1063: 	    if ((cur->user2 == NULL) ||
 1064: 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
 1065: 		fprintf(output, "Object is a collapsed range :\n");
 1066: 		fprintf(output, "%s", shift);
 1067: 		if (cur->index >= 0)
 1068: 		    fprintf(output, "index %d in ", cur->index);
 1069: 		fprintf(output, "node\n");
 1070: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1071: 			              depth + 1);
 1072: 	    } else  {
 1073: 		fprintf(output, "Object is a range :\n");
 1074: 		fprintf(output, "%s", shift);
 1075: 		fprintf(output, "From ");
 1076: 		if (cur->index >= 0)
 1077: 		    fprintf(output, "index %d in ", cur->index);
 1078: 		fprintf(output, "node\n");
 1079: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1080: 			              depth + 1);
 1081: 		fprintf(output, "%s", shift);
 1082: 		fprintf(output, "To ");
 1083: 		if (cur->index2 >= 0)
 1084: 		    fprintf(output, "index %d in ", cur->index2);
 1085: 		fprintf(output, "node\n");
 1086: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
 1087: 			              depth + 1);
 1088: 		fprintf(output, "\n");
 1089: 	    }
 1090: 	    break;
 1091: 	case XPATH_LOCATIONSET:
 1092: #if defined(LIBXML_XPTR_ENABLED)
 1093: 	    fprintf(output, "Object is a Location Set:\n");
 1094: 	    xmlXPathDebugDumpLocationSet(output,
 1095: 		    (xmlLocationSetPtr) cur->user, depth);
 1096: #endif
 1097: 	    break;
 1098: 	case XPATH_USERS:
 1099: 	    fprintf(output, "Object is user defined\n");
 1100: 	    break;
 1101:     }
 1102: }
 1103: 
 1104: static void
 1105: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
 1106: 	                     xmlXPathStepOpPtr op, int depth) {
 1107:     int i;
 1108:     char shift[100];
 1109: 
 1110:     for (i = 0;((i < depth) && (i < 25));i++)
 1111:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1112:     shift[2 * i] = shift[2 * i + 1] = 0;
 1113: 
 1114:     fprintf(output, "%s", shift);
 1115:     if (op == NULL) {
 1116: 	fprintf(output, "Step is NULL\n");
 1117: 	return;
 1118:     }
 1119:     switch (op->op) {
 1120:         case XPATH_OP_END:
 1121: 	    fprintf(output, "END"); break;
 1122:         case XPATH_OP_AND:
 1123: 	    fprintf(output, "AND"); break;
 1124:         case XPATH_OP_OR:
 1125: 	    fprintf(output, "OR"); break;
 1126:         case XPATH_OP_EQUAL:
 1127: 	     if (op->value)
 1128: 		 fprintf(output, "EQUAL =");
 1129: 	     else
 1130: 		 fprintf(output, "EQUAL !=");
 1131: 	     break;
 1132:         case XPATH_OP_CMP:
 1133: 	     if (op->value)
 1134: 		 fprintf(output, "CMP <");
 1135: 	     else
 1136: 		 fprintf(output, "CMP >");
 1137: 	     if (!op->value2)
 1138: 		 fprintf(output, "=");
 1139: 	     break;
 1140:         case XPATH_OP_PLUS:
 1141: 	     if (op->value == 0)
 1142: 		 fprintf(output, "PLUS -");
 1143: 	     else if (op->value == 1)
 1144: 		 fprintf(output, "PLUS +");
 1145: 	     else if (op->value == 2)
 1146: 		 fprintf(output, "PLUS unary -");
 1147: 	     else if (op->value == 3)
 1148: 		 fprintf(output, "PLUS unary - -");
 1149: 	     break;
 1150:         case XPATH_OP_MULT:
 1151: 	     if (op->value == 0)
 1152: 		 fprintf(output, "MULT *");
 1153: 	     else if (op->value == 1)
 1154: 		 fprintf(output, "MULT div");
 1155: 	     else
 1156: 		 fprintf(output, "MULT mod");
 1157: 	     break;
 1158:         case XPATH_OP_UNION:
 1159: 	     fprintf(output, "UNION"); break;
 1160:         case XPATH_OP_ROOT:
 1161: 	     fprintf(output, "ROOT"); break;
 1162:         case XPATH_OP_NODE:
 1163: 	     fprintf(output, "NODE"); break;
 1164:         case XPATH_OP_RESET:
 1165: 	     fprintf(output, "RESET"); break;
 1166:         case XPATH_OP_SORT:
 1167: 	     fprintf(output, "SORT"); break;
 1168:         case XPATH_OP_COLLECT: {
 1169: 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
 1170: 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
 1171: 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
 1172: 	    const xmlChar *prefix = op->value4;
 1173: 	    const xmlChar *name = op->value5;
 1174: 
 1175: 	    fprintf(output, "COLLECT ");
 1176: 	    switch (axis) {
 1177: 		case AXIS_ANCESTOR:
 1178: 		    fprintf(output, " 'ancestors' "); break;
 1179: 		case AXIS_ANCESTOR_OR_SELF:
 1180: 		    fprintf(output, " 'ancestors-or-self' "); break;
 1181: 		case AXIS_ATTRIBUTE:
 1182: 		    fprintf(output, " 'attributes' "); break;
 1183: 		case AXIS_CHILD:
 1184: 		    fprintf(output, " 'child' "); break;
 1185: 		case AXIS_DESCENDANT:
 1186: 		    fprintf(output, " 'descendant' "); break;
 1187: 		case AXIS_DESCENDANT_OR_SELF:
 1188: 		    fprintf(output, " 'descendant-or-self' "); break;
 1189: 		case AXIS_FOLLOWING:
 1190: 		    fprintf(output, " 'following' "); break;
 1191: 		case AXIS_FOLLOWING_SIBLING:
 1192: 		    fprintf(output, " 'following-siblings' "); break;
 1193: 		case AXIS_NAMESPACE:
 1194: 		    fprintf(output, " 'namespace' "); break;
 1195: 		case AXIS_PARENT:
 1196: 		    fprintf(output, " 'parent' "); break;
 1197: 		case AXIS_PRECEDING:
 1198: 		    fprintf(output, " 'preceding' "); break;
 1199: 		case AXIS_PRECEDING_SIBLING:
 1200: 		    fprintf(output, " 'preceding-sibling' "); break;
 1201: 		case AXIS_SELF:
 1202: 		    fprintf(output, " 'self' "); break;
 1203: 	    }
 1204: 	    switch (test) {
 1205:                 case NODE_TEST_NONE:
 1206: 		    fprintf(output, "'none' "); break;
 1207:                 case NODE_TEST_TYPE:
 1208: 		    fprintf(output, "'type' "); break;
 1209:                 case NODE_TEST_PI:
 1210: 		    fprintf(output, "'PI' "); break;
 1211:                 case NODE_TEST_ALL:
 1212: 		    fprintf(output, "'all' "); break;
 1213:                 case NODE_TEST_NS:
 1214: 		    fprintf(output, "'namespace' "); break;
 1215:                 case NODE_TEST_NAME:
 1216: 		    fprintf(output, "'name' "); break;
 1217: 	    }
 1218: 	    switch (type) {
 1219:                 case NODE_TYPE_NODE:
 1220: 		    fprintf(output, "'node' "); break;
 1221:                 case NODE_TYPE_COMMENT:
 1222: 		    fprintf(output, "'comment' "); break;
 1223:                 case NODE_TYPE_TEXT:
 1224: 		    fprintf(output, "'text' "); break;
 1225:                 case NODE_TYPE_PI:
 1226: 		    fprintf(output, "'PI' "); break;
 1227: 	    }
 1228: 	    if (prefix != NULL)
 1229: 		fprintf(output, "%s:", prefix);
 1230: 	    if (name != NULL)
 1231: 		fprintf(output, "%s", (const char *) name);
 1232: 	    break;
 1233: 
 1234:         }
 1235: 	case XPATH_OP_VALUE: {
 1236: 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
 1237: 
 1238: 	    fprintf(output, "ELEM ");
 1239: 	    xmlXPathDebugDumpObject(output, object, 0);
 1240: 	    goto finish;
 1241: 	}
 1242: 	case XPATH_OP_VARIABLE: {
 1243: 	    const xmlChar *prefix = op->value5;
 1244: 	    const xmlChar *name = op->value4;
 1245: 
 1246: 	    if (prefix != NULL)
 1247: 		fprintf(output, "VARIABLE %s:%s", prefix, name);
 1248: 	    else
 1249: 		fprintf(output, "VARIABLE %s", name);
 1250: 	    break;
 1251: 	}
 1252: 	case XPATH_OP_FUNCTION: {
 1253: 	    int nbargs = op->value;
 1254: 	    const xmlChar *prefix = op->value5;
 1255: 	    const xmlChar *name = op->value4;
 1256: 
 1257: 	    if (prefix != NULL)
 1258: 		fprintf(output, "FUNCTION %s:%s(%d args)",
 1259: 			prefix, name, nbargs);
 1260: 	    else
 1261: 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
 1262: 	    break;
 1263: 	}
 1264:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
 1265:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
 1266:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
 1267: #ifdef LIBXML_XPTR_ENABLED
 1268:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
 1269: #endif
 1270: 	default:
 1271:         fprintf(output, "UNKNOWN %d\n", op->op); return;
 1272:     }
 1273:     fprintf(output, "\n");
 1274: finish:
 1275:     if (op->ch1 >= 0)
 1276: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
 1277:     if (op->ch2 >= 0)
 1278: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
 1279: }
 1280: 
 1281: /**
 1282:  * xmlXPathDebugDumpCompExpr:
 1283:  * @output:  the FILE * for the output
 1284:  * @comp:  the precompiled XPath expression
 1285:  * @depth:  the indentation level.
 1286:  *
 1287:  * Dumps the tree of the compiled XPath expression.
 1288:  */
 1289: void
 1290: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
 1291: 	                  int depth) {
 1292:     int i;
 1293:     char shift[100];
 1294: 
 1295:     if ((output == NULL) || (comp == NULL)) return;
 1296: 
 1297:     for (i = 0;((i < depth) && (i < 25));i++)
 1298:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1299:     shift[2 * i] = shift[2 * i + 1] = 0;
 1300: 
 1301:     fprintf(output, "%s", shift);
 1302: 
 1303:     fprintf(output, "Compiled Expression : %d elements\n",
 1304: 	    comp->nbStep);
 1305:     i = comp->last;
 1306:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
 1307: }
 1308: 
 1309: #ifdef XP_DEBUG_OBJ_USAGE
 1310: 
 1311: /*
 1312: * XPath object usage related debugging variables.
 1313: */
 1314: static int xmlXPathDebugObjCounterUndefined = 0;
 1315: static int xmlXPathDebugObjCounterNodeset = 0;
 1316: static int xmlXPathDebugObjCounterBool = 0;
 1317: static int xmlXPathDebugObjCounterNumber = 0;
 1318: static int xmlXPathDebugObjCounterString = 0;
 1319: static int xmlXPathDebugObjCounterPoint = 0;
 1320: static int xmlXPathDebugObjCounterRange = 0;
 1321: static int xmlXPathDebugObjCounterLocset = 0;
 1322: static int xmlXPathDebugObjCounterUsers = 0;
 1323: static int xmlXPathDebugObjCounterXSLTTree = 0;
 1324: static int xmlXPathDebugObjCounterAll = 0;
 1325: 
 1326: static int xmlXPathDebugObjTotalUndefined = 0;
 1327: static int xmlXPathDebugObjTotalNodeset = 0;
 1328: static int xmlXPathDebugObjTotalBool = 0;
 1329: static int xmlXPathDebugObjTotalNumber = 0;
 1330: static int xmlXPathDebugObjTotalString = 0;
 1331: static int xmlXPathDebugObjTotalPoint = 0;
 1332: static int xmlXPathDebugObjTotalRange = 0;
 1333: static int xmlXPathDebugObjTotalLocset = 0;
 1334: static int xmlXPathDebugObjTotalUsers = 0;
 1335: static int xmlXPathDebugObjTotalXSLTTree = 0;
 1336: static int xmlXPathDebugObjTotalAll = 0;
 1337: 
 1338: static int xmlXPathDebugObjMaxUndefined = 0;
 1339: static int xmlXPathDebugObjMaxNodeset = 0;
 1340: static int xmlXPathDebugObjMaxBool = 0;
 1341: static int xmlXPathDebugObjMaxNumber = 0;
 1342: static int xmlXPathDebugObjMaxString = 0;
 1343: static int xmlXPathDebugObjMaxPoint = 0;
 1344: static int xmlXPathDebugObjMaxRange = 0;
 1345: static int xmlXPathDebugObjMaxLocset = 0;
 1346: static int xmlXPathDebugObjMaxUsers = 0;
 1347: static int xmlXPathDebugObjMaxXSLTTree = 0;
 1348: static int xmlXPathDebugObjMaxAll = 0;
 1349: 
 1350: /* REVISIT TODO: Make this static when committing */
 1351: static void
 1352: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
 1353: {
 1354:     if (ctxt != NULL) {
 1355: 	if (ctxt->cache != NULL) {
 1356: 	    xmlXPathContextCachePtr cache =
 1357: 		(xmlXPathContextCachePtr) ctxt->cache;
 1358: 
 1359: 	    cache->dbgCachedAll = 0;
 1360: 	    cache->dbgCachedNodeset = 0;
 1361: 	    cache->dbgCachedString = 0;
 1362: 	    cache->dbgCachedBool = 0;
 1363: 	    cache->dbgCachedNumber = 0;
 1364: 	    cache->dbgCachedPoint = 0;
 1365: 	    cache->dbgCachedRange = 0;
 1366: 	    cache->dbgCachedLocset = 0;
 1367: 	    cache->dbgCachedUsers = 0;
 1368: 	    cache->dbgCachedXSLTTree = 0;
 1369: 	    cache->dbgCachedUndefined = 0;
 1370: 
 1371: 	    cache->dbgReusedAll = 0;
 1372: 	    cache->dbgReusedNodeset = 0;
 1373: 	    cache->dbgReusedString = 0;
 1374: 	    cache->dbgReusedBool = 0;
 1375: 	    cache->dbgReusedNumber = 0;
 1376: 	    cache->dbgReusedPoint = 0;
 1377: 	    cache->dbgReusedRange = 0;
 1378: 	    cache->dbgReusedLocset = 0;
 1379: 	    cache->dbgReusedUsers = 0;
 1380: 	    cache->dbgReusedXSLTTree = 0;
 1381: 	    cache->dbgReusedUndefined = 0;
 1382: 	}
 1383:     }
 1384: 
 1385:     xmlXPathDebugObjCounterUndefined = 0;
 1386:     xmlXPathDebugObjCounterNodeset = 0;
 1387:     xmlXPathDebugObjCounterBool = 0;
 1388:     xmlXPathDebugObjCounterNumber = 0;
 1389:     xmlXPathDebugObjCounterString = 0;
 1390:     xmlXPathDebugObjCounterPoint = 0;
 1391:     xmlXPathDebugObjCounterRange = 0;
 1392:     xmlXPathDebugObjCounterLocset = 0;
 1393:     xmlXPathDebugObjCounterUsers = 0;
 1394:     xmlXPathDebugObjCounterXSLTTree = 0;
 1395:     xmlXPathDebugObjCounterAll = 0;
 1396: 
 1397:     xmlXPathDebugObjTotalUndefined = 0;
 1398:     xmlXPathDebugObjTotalNodeset = 0;
 1399:     xmlXPathDebugObjTotalBool = 0;
 1400:     xmlXPathDebugObjTotalNumber = 0;
 1401:     xmlXPathDebugObjTotalString = 0;
 1402:     xmlXPathDebugObjTotalPoint = 0;
 1403:     xmlXPathDebugObjTotalRange = 0;
 1404:     xmlXPathDebugObjTotalLocset = 0;
 1405:     xmlXPathDebugObjTotalUsers = 0;
 1406:     xmlXPathDebugObjTotalXSLTTree = 0;
 1407:     xmlXPathDebugObjTotalAll = 0;
 1408: 
 1409:     xmlXPathDebugObjMaxUndefined = 0;
 1410:     xmlXPathDebugObjMaxNodeset = 0;
 1411:     xmlXPathDebugObjMaxBool = 0;
 1412:     xmlXPathDebugObjMaxNumber = 0;
 1413:     xmlXPathDebugObjMaxString = 0;
 1414:     xmlXPathDebugObjMaxPoint = 0;
 1415:     xmlXPathDebugObjMaxRange = 0;
 1416:     xmlXPathDebugObjMaxLocset = 0;
 1417:     xmlXPathDebugObjMaxUsers = 0;
 1418:     xmlXPathDebugObjMaxXSLTTree = 0;
 1419:     xmlXPathDebugObjMaxAll = 0;
 1420: 
 1421: }
 1422: 
 1423: static void
 1424: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
 1425: 			      xmlXPathObjectType objType)
 1426: {
 1427:     int isCached = 0;
 1428: 
 1429:     if (ctxt != NULL) {
 1430: 	if (ctxt->cache != NULL) {
 1431: 	    xmlXPathContextCachePtr cache =
 1432: 		(xmlXPathContextCachePtr) ctxt->cache;
 1433: 
 1434: 	    isCached = 1;
 1435: 
 1436: 	    cache->dbgReusedAll++;
 1437: 	    switch (objType) {
 1438: 		case XPATH_UNDEFINED:
 1439: 		    cache->dbgReusedUndefined++;
 1440: 		    break;
 1441: 		case XPATH_NODESET:
 1442: 		    cache->dbgReusedNodeset++;
 1443: 		    break;
 1444: 		case XPATH_BOOLEAN:
 1445: 		    cache->dbgReusedBool++;
 1446: 		    break;
 1447: 		case XPATH_NUMBER:
 1448: 		    cache->dbgReusedNumber++;
 1449: 		    break;
 1450: 		case XPATH_STRING:
 1451: 		    cache->dbgReusedString++;
 1452: 		    break;
 1453: 		case XPATH_POINT:
 1454: 		    cache->dbgReusedPoint++;
 1455: 		    break;
 1456: 		case XPATH_RANGE:
 1457: 		    cache->dbgReusedRange++;
 1458: 		    break;
 1459: 		case XPATH_LOCATIONSET:
 1460: 		    cache->dbgReusedLocset++;
 1461: 		    break;
 1462: 		case XPATH_USERS:
 1463: 		    cache->dbgReusedUsers++;
 1464: 		    break;
 1465: 		case XPATH_XSLT_TREE:
 1466: 		    cache->dbgReusedXSLTTree++;
 1467: 		    break;
 1468: 		default:
 1469: 		    break;
 1470: 	    }
 1471: 	}
 1472:     }
 1473: 
 1474:     switch (objType) {
 1475: 	case XPATH_UNDEFINED:
 1476: 	    if (! isCached)
 1477: 		xmlXPathDebugObjTotalUndefined++;
 1478: 	    xmlXPathDebugObjCounterUndefined++;
 1479: 	    if (xmlXPathDebugObjCounterUndefined >
 1480: 		xmlXPathDebugObjMaxUndefined)
 1481: 		xmlXPathDebugObjMaxUndefined =
 1482: 		    xmlXPathDebugObjCounterUndefined;
 1483: 	    break;
 1484: 	case XPATH_NODESET:
 1485: 	    if (! isCached)
 1486: 		xmlXPathDebugObjTotalNodeset++;
 1487: 	    xmlXPathDebugObjCounterNodeset++;
 1488: 	    if (xmlXPathDebugObjCounterNodeset >
 1489: 		xmlXPathDebugObjMaxNodeset)
 1490: 		xmlXPathDebugObjMaxNodeset =
 1491: 		    xmlXPathDebugObjCounterNodeset;
 1492: 	    break;
 1493: 	case XPATH_BOOLEAN:
 1494: 	    if (! isCached)
 1495: 		xmlXPathDebugObjTotalBool++;
 1496: 	    xmlXPathDebugObjCounterBool++;
 1497: 	    if (xmlXPathDebugObjCounterBool >
 1498: 		xmlXPathDebugObjMaxBool)
 1499: 		xmlXPathDebugObjMaxBool =
 1500: 		    xmlXPathDebugObjCounterBool;
 1501: 	    break;
 1502: 	case XPATH_NUMBER:
 1503: 	    if (! isCached)
 1504: 		xmlXPathDebugObjTotalNumber++;
 1505: 	    xmlXPathDebugObjCounterNumber++;
 1506: 	    if (xmlXPathDebugObjCounterNumber >
 1507: 		xmlXPathDebugObjMaxNumber)
 1508: 		xmlXPathDebugObjMaxNumber =
 1509: 		    xmlXPathDebugObjCounterNumber;
 1510: 	    break;
 1511: 	case XPATH_STRING:
 1512: 	    if (! isCached)
 1513: 		xmlXPathDebugObjTotalString++;
 1514: 	    xmlXPathDebugObjCounterString++;
 1515: 	    if (xmlXPathDebugObjCounterString >
 1516: 		xmlXPathDebugObjMaxString)
 1517: 		xmlXPathDebugObjMaxString =
 1518: 		    xmlXPathDebugObjCounterString;
 1519: 	    break;
 1520: 	case XPATH_POINT:
 1521: 	    if (! isCached)
 1522: 		xmlXPathDebugObjTotalPoint++;
 1523: 	    xmlXPathDebugObjCounterPoint++;
 1524: 	    if (xmlXPathDebugObjCounterPoint >
 1525: 		xmlXPathDebugObjMaxPoint)
 1526: 		xmlXPathDebugObjMaxPoint =
 1527: 		    xmlXPathDebugObjCounterPoint;
 1528: 	    break;
 1529: 	case XPATH_RANGE:
 1530: 	    if (! isCached)
 1531: 		xmlXPathDebugObjTotalRange++;
 1532: 	    xmlXPathDebugObjCounterRange++;
 1533: 	    if (xmlXPathDebugObjCounterRange >
 1534: 		xmlXPathDebugObjMaxRange)
 1535: 		xmlXPathDebugObjMaxRange =
 1536: 		    xmlXPathDebugObjCounterRange;
 1537: 	    break;
 1538: 	case XPATH_LOCATIONSET:
 1539: 	    if (! isCached)
 1540: 		xmlXPathDebugObjTotalLocset++;
 1541: 	    xmlXPathDebugObjCounterLocset++;
 1542: 	    if (xmlXPathDebugObjCounterLocset >
 1543: 		xmlXPathDebugObjMaxLocset)
 1544: 		xmlXPathDebugObjMaxLocset =
 1545: 		    xmlXPathDebugObjCounterLocset;
 1546: 	    break;
 1547: 	case XPATH_USERS:
 1548: 	    if (! isCached)
 1549: 		xmlXPathDebugObjTotalUsers++;
 1550: 	    xmlXPathDebugObjCounterUsers++;
 1551: 	    if (xmlXPathDebugObjCounterUsers >
 1552: 		xmlXPathDebugObjMaxUsers)
 1553: 		xmlXPathDebugObjMaxUsers =
 1554: 		    xmlXPathDebugObjCounterUsers;
 1555: 	    break;
 1556: 	case XPATH_XSLT_TREE:
 1557: 	    if (! isCached)
 1558: 		xmlXPathDebugObjTotalXSLTTree++;
 1559: 	    xmlXPathDebugObjCounterXSLTTree++;
 1560: 	    if (xmlXPathDebugObjCounterXSLTTree >
 1561: 		xmlXPathDebugObjMaxXSLTTree)
 1562: 		xmlXPathDebugObjMaxXSLTTree =
 1563: 		    xmlXPathDebugObjCounterXSLTTree;
 1564: 	    break;
 1565: 	default:
 1566: 	    break;
 1567:     }
 1568:     if (! isCached)
 1569: 	xmlXPathDebugObjTotalAll++;
 1570:     xmlXPathDebugObjCounterAll++;
 1571:     if (xmlXPathDebugObjCounterAll >
 1572: 	xmlXPathDebugObjMaxAll)
 1573: 	xmlXPathDebugObjMaxAll =
 1574: 	    xmlXPathDebugObjCounterAll;
 1575: }
 1576: 
 1577: static void
 1578: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
 1579: 			      xmlXPathObjectType objType)
 1580: {
 1581:     int isCached = 0;
 1582: 
 1583:     if (ctxt != NULL) {
 1584: 	if (ctxt->cache != NULL) {
 1585: 	    xmlXPathContextCachePtr cache =
 1586: 		(xmlXPathContextCachePtr) ctxt->cache;
 1587: 
 1588: 	    isCached = 1;
 1589: 
 1590: 	    cache->dbgCachedAll++;
 1591: 	    switch (objType) {
 1592: 		case XPATH_UNDEFINED:
 1593: 		    cache->dbgCachedUndefined++;
 1594: 		    break;
 1595: 		case XPATH_NODESET:
 1596: 		    cache->dbgCachedNodeset++;
 1597: 		    break;
 1598: 		case XPATH_BOOLEAN:
 1599: 		    cache->dbgCachedBool++;
 1600: 		    break;
 1601: 		case XPATH_NUMBER:
 1602: 		    cache->dbgCachedNumber++;
 1603: 		    break;
 1604: 		case XPATH_STRING:
 1605: 		    cache->dbgCachedString++;
 1606: 		    break;
 1607: 		case XPATH_POINT:
 1608: 		    cache->dbgCachedPoint++;
 1609: 		    break;
 1610: 		case XPATH_RANGE:
 1611: 		    cache->dbgCachedRange++;
 1612: 		    break;
 1613: 		case XPATH_LOCATIONSET:
 1614: 		    cache->dbgCachedLocset++;
 1615: 		    break;
 1616: 		case XPATH_USERS:
 1617: 		    cache->dbgCachedUsers++;
 1618: 		    break;
 1619: 		case XPATH_XSLT_TREE:
 1620: 		    cache->dbgCachedXSLTTree++;
 1621: 		    break;
 1622: 		default:
 1623: 		    break;
 1624: 	    }
 1625: 
 1626: 	}
 1627:     }
 1628:     switch (objType) {
 1629: 	case XPATH_UNDEFINED:
 1630: 	    xmlXPathDebugObjCounterUndefined--;
 1631: 	    break;
 1632: 	case XPATH_NODESET:
 1633: 	    xmlXPathDebugObjCounterNodeset--;
 1634: 	    break;
 1635: 	case XPATH_BOOLEAN:
 1636: 	    xmlXPathDebugObjCounterBool--;
 1637: 	    break;
 1638: 	case XPATH_NUMBER:
 1639: 	    xmlXPathDebugObjCounterNumber--;
 1640: 	    break;
 1641: 	case XPATH_STRING:
 1642: 	    xmlXPathDebugObjCounterString--;
 1643: 	    break;
 1644: 	case XPATH_POINT:
 1645: 	    xmlXPathDebugObjCounterPoint--;
 1646: 	    break;
 1647: 	case XPATH_RANGE:
 1648: 	    xmlXPathDebugObjCounterRange--;
 1649: 	    break;
 1650: 	case XPATH_LOCATIONSET:
 1651: 	    xmlXPathDebugObjCounterLocset--;
 1652: 	    break;
 1653: 	case XPATH_USERS:
 1654: 	    xmlXPathDebugObjCounterUsers--;
 1655: 	    break;
 1656: 	case XPATH_XSLT_TREE:
 1657: 	    xmlXPathDebugObjCounterXSLTTree--;
 1658: 	    break;
 1659: 	default:
 1660: 	    break;
 1661:     }
 1662:     xmlXPathDebugObjCounterAll--;
 1663: }
 1664: 
 1665: /* REVISIT TODO: Make this static when committing */
 1666: static void
 1667: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
 1668: {
 1669:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
 1670: 	reqXSLTTree, reqUndefined;
 1671:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
 1672: 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
 1673:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
 1674: 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
 1675:     int leftObjs = xmlXPathDebugObjCounterAll;
 1676: 
 1677:     reqAll = xmlXPathDebugObjTotalAll;
 1678:     reqNodeset = xmlXPathDebugObjTotalNodeset;
 1679:     reqString = xmlXPathDebugObjTotalString;
 1680:     reqBool = xmlXPathDebugObjTotalBool;
 1681:     reqNumber = xmlXPathDebugObjTotalNumber;
 1682:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
 1683:     reqUndefined = xmlXPathDebugObjTotalUndefined;
 1684: 
 1685:     printf("# XPath object usage:\n");
 1686: 
 1687:     if (ctxt != NULL) {
 1688: 	if (ctxt->cache != NULL) {
 1689: 	    xmlXPathContextCachePtr cache =
 1690: 		(xmlXPathContextCachePtr) ctxt->cache;
 1691: 
 1692: 	    reAll = cache->dbgReusedAll;
 1693: 	    reqAll += reAll;
 1694: 	    reNodeset = cache->dbgReusedNodeset;
 1695: 	    reqNodeset += reNodeset;
 1696: 	    reString = cache->dbgReusedString;
 1697: 	    reqString += reString;
 1698: 	    reBool = cache->dbgReusedBool;
 1699: 	    reqBool += reBool;
 1700: 	    reNumber = cache->dbgReusedNumber;
 1701: 	    reqNumber += reNumber;
 1702: 	    reXSLTTree = cache->dbgReusedXSLTTree;
 1703: 	    reqXSLTTree += reXSLTTree;
 1704: 	    reUndefined = cache->dbgReusedUndefined;
 1705: 	    reqUndefined += reUndefined;
 1706: 
 1707: 	    caAll = cache->dbgCachedAll;
 1708: 	    caBool = cache->dbgCachedBool;
 1709: 	    caNodeset = cache->dbgCachedNodeset;
 1710: 	    caString = cache->dbgCachedString;
 1711: 	    caNumber = cache->dbgCachedNumber;
 1712: 	    caXSLTTree = cache->dbgCachedXSLTTree;
 1713: 	    caUndefined = cache->dbgCachedUndefined;
 1714: 
 1715: 	    if (cache->nodesetObjs)
 1716: 		leftObjs -= cache->nodesetObjs->number;
 1717: 	    if (cache->stringObjs)
 1718: 		leftObjs -= cache->stringObjs->number;
 1719: 	    if (cache->booleanObjs)
 1720: 		leftObjs -= cache->booleanObjs->number;
 1721: 	    if (cache->numberObjs)
 1722: 		leftObjs -= cache->numberObjs->number;
 1723: 	    if (cache->miscObjs)
 1724: 		leftObjs -= cache->miscObjs->number;
 1725: 	}
 1726:     }
 1727: 
 1728:     printf("# all\n");
 1729:     printf("#   total  : %d\n", reqAll);
 1730:     printf("#   left  : %d\n", leftObjs);
 1731:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
 1732:     printf("#   reused : %d\n", reAll);
 1733:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
 1734: 
 1735:     printf("# node-sets\n");
 1736:     printf("#   total  : %d\n", reqNodeset);
 1737:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
 1738:     printf("#   reused : %d\n", reNodeset);
 1739:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
 1740: 
 1741:     printf("# strings\n");
 1742:     printf("#   total  : %d\n", reqString);
 1743:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
 1744:     printf("#   reused : %d\n", reString);
 1745:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
 1746: 
 1747:     printf("# booleans\n");
 1748:     printf("#   total  : %d\n", reqBool);
 1749:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
 1750:     printf("#   reused : %d\n", reBool);
 1751:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
 1752: 
 1753:     printf("# numbers\n");
 1754:     printf("#   total  : %d\n", reqNumber);
 1755:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
 1756:     printf("#   reused : %d\n", reNumber);
 1757:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
 1758: 
 1759:     printf("# XSLT result tree fragments\n");
 1760:     printf("#   total  : %d\n", reqXSLTTree);
 1761:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
 1762:     printf("#   reused : %d\n", reXSLTTree);
 1763:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
 1764: 
 1765:     printf("# undefined\n");
 1766:     printf("#   total  : %d\n", reqUndefined);
 1767:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
 1768:     printf("#   reused : %d\n", reUndefined);
 1769:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
 1770: 
 1771: }
 1772: 
 1773: #endif /* XP_DEBUG_OBJ_USAGE */
 1774: 
 1775: #endif /* LIBXML_DEBUG_ENABLED */
 1776: 
 1777: /************************************************************************
 1778:  *									*
 1779:  *			XPath object caching				*
 1780:  *									*
 1781:  ************************************************************************/
 1782: 
 1783: /**
 1784:  * xmlXPathNewCache:
 1785:  *
 1786:  * Create a new object cache
 1787:  *
 1788:  * Returns the xmlXPathCache just allocated.
 1789:  */
 1790: static xmlXPathContextCachePtr
 1791: xmlXPathNewCache(void)
 1792: {
 1793:     xmlXPathContextCachePtr ret;
 1794: 
 1795:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
 1796:     if (ret == NULL) {
 1797:         xmlXPathErrMemory(NULL, "creating object cache\n");
 1798: 	return(NULL);
 1799:     }
 1800:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
 1801:     ret->maxNodeset = 100;
 1802:     ret->maxString = 100;
 1803:     ret->maxBoolean = 100;
 1804:     ret->maxNumber = 100;
 1805:     ret->maxMisc = 100;
 1806:     return(ret);
 1807: }
 1808: 
 1809: static void
 1810: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
 1811: {
 1812:     int i;
 1813:     xmlXPathObjectPtr obj;
 1814: 
 1815:     if (list == NULL)
 1816: 	return;
 1817: 
 1818:     for (i = 0; i < list->number; i++) {
 1819: 	obj = list->items[i];
 1820: 	/*
 1821: 	* Note that it is already assured that we don't need to
 1822: 	* look out for namespace nodes in the node-set.
 1823: 	*/
 1824: 	if (obj->nodesetval != NULL) {
 1825: 	    if (obj->nodesetval->nodeTab != NULL)
 1826: 		xmlFree(obj->nodesetval->nodeTab);
 1827: 	    xmlFree(obj->nodesetval);
 1828: 	}
 1829: 	xmlFree(obj);
 1830: #ifdef XP_DEBUG_OBJ_USAGE
 1831: 	xmlXPathDebugObjCounterAll--;
 1832: #endif
 1833:     }
 1834:     xmlPointerListFree(list);
 1835: }
 1836: 
 1837: static void
 1838: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
 1839: {
 1840:     if (cache == NULL)
 1841: 	return;
 1842:     if (cache->nodesetObjs)
 1843: 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
 1844:     if (cache->stringObjs)
 1845: 	xmlXPathCacheFreeObjectList(cache->stringObjs);
 1846:     if (cache->booleanObjs)
 1847: 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
 1848:     if (cache->numberObjs)
 1849: 	xmlXPathCacheFreeObjectList(cache->numberObjs);
 1850:     if (cache->miscObjs)
 1851: 	xmlXPathCacheFreeObjectList(cache->miscObjs);
 1852:     xmlFree(cache);
 1853: }
 1854: 
 1855: /**
 1856:  * xmlXPathContextSetCache:
 1857:  *
 1858:  * @ctxt:  the XPath context
 1859:  * @active: enables/disables (creates/frees) the cache
 1860:  * @value: a value with semantics dependant on @options
 1861:  * @options: options (currently only the value 0 is used)
 1862:  *
 1863:  * Creates/frees an object cache on the XPath context.
 1864:  * If activates XPath objects (xmlXPathObject) will be cached internally
 1865:  * to be reused.
 1866:  * @options:
 1867:  *   0: This will set the XPath object caching:
 1868:  *      @value:
 1869:  *        This will set the maximum number of XPath objects
 1870:  *        to be cached per slot
 1871:  *        There are 5 slots for: node-set, string, number, boolean, and
 1872:  *        misc objects. Use <0 for the default number (100).
 1873:  *   Other values for @options have currently no effect.
 1874:  *
 1875:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
 1876:  */
 1877: int
 1878: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
 1879: 			int active,
 1880: 			int value,
 1881: 			int options)
 1882: {
 1883:     if (ctxt == NULL)
 1884: 	return(-1);
 1885:     if (active) {
 1886: 	xmlXPathContextCachePtr cache;
 1887: 
 1888: 	if (ctxt->cache == NULL) {
 1889: 	    ctxt->cache = xmlXPathNewCache();
 1890: 	    if (ctxt->cache == NULL)
 1891: 		return(-1);
 1892: 	}
 1893: 	cache = (xmlXPathContextCachePtr) ctxt->cache;
 1894: 	if (options == 0) {
 1895: 	    if (value < 0)
 1896: 		value = 100;
 1897: 	    cache->maxNodeset = value;
 1898: 	    cache->maxString = value;
 1899: 	    cache->maxNumber = value;
 1900: 	    cache->maxBoolean = value;
 1901: 	    cache->maxMisc = value;
 1902: 	}
 1903:     } else if (ctxt->cache != NULL) {
 1904: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 1905: 	ctxt->cache = NULL;
 1906:     }
 1907:     return(0);
 1908: }
 1909: 
 1910: /**
 1911:  * xmlXPathCacheWrapNodeSet:
 1912:  * @ctxt: the XPath context
 1913:  * @val:  the NodePtr value
 1914:  *
 1915:  * This is the cached version of xmlXPathWrapNodeSet().
 1916:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 1917:  *
 1918:  * Returns the created or reused object.
 1919:  */
 1920: static xmlXPathObjectPtr
 1921: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
 1922: {
 1923:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 1924: 	xmlXPathContextCachePtr cache =
 1925: 	    (xmlXPathContextCachePtr) ctxt->cache;
 1926: 
 1927: 	if ((cache->miscObjs != NULL) &&
 1928: 	    (cache->miscObjs->number != 0))
 1929: 	{
 1930: 	    xmlXPathObjectPtr ret;
 1931: 
 1932: 	    ret = (xmlXPathObjectPtr)
 1933: 		cache->miscObjs->items[--cache->miscObjs->number];
 1934: 	    ret->type = XPATH_NODESET;
 1935: 	    ret->nodesetval = val;
 1936: #ifdef XP_DEBUG_OBJ_USAGE
 1937: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 1938: #endif
 1939: 	    return(ret);
 1940: 	}
 1941:     }
 1942: 
 1943:     return(xmlXPathWrapNodeSet(val));
 1944: 
 1945: }
 1946: 
 1947: /**
 1948:  * xmlXPathCacheWrapString:
 1949:  * @ctxt: the XPath context
 1950:  * @val:  the xmlChar * value
 1951:  *
 1952:  * This is the cached version of xmlXPathWrapString().
 1953:  * Wraps the @val string into an XPath object.
 1954:  *
 1955:  * Returns the created or reused object.
 1956:  */
 1957: static xmlXPathObjectPtr
 1958: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
 1959: {
 1960:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 1961: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 1962: 
 1963: 	if ((cache->stringObjs != NULL) &&
 1964: 	    (cache->stringObjs->number != 0))
 1965: 	{
 1966: 
 1967: 	    xmlXPathObjectPtr ret;
 1968: 
 1969: 	    ret = (xmlXPathObjectPtr)
 1970: 		cache->stringObjs->items[--cache->stringObjs->number];
 1971: 	    ret->type = XPATH_STRING;
 1972: 	    ret->stringval = val;
 1973: #ifdef XP_DEBUG_OBJ_USAGE
 1974: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 1975: #endif
 1976: 	    return(ret);
 1977: 	} else if ((cache->miscObjs != NULL) &&
 1978: 	    (cache->miscObjs->number != 0))
 1979: 	{
 1980: 	    xmlXPathObjectPtr ret;
 1981: 	    /*
 1982: 	    * Fallback to misc-cache.
 1983: 	    */
 1984: 	    ret = (xmlXPathObjectPtr)
 1985: 		cache->miscObjs->items[--cache->miscObjs->number];
 1986: 
 1987: 	    ret->type = XPATH_STRING;
 1988: 	    ret->stringval = val;
 1989: #ifdef XP_DEBUG_OBJ_USAGE
 1990: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 1991: #endif
 1992: 	    return(ret);
 1993: 	}
 1994:     }
 1995:     return(xmlXPathWrapString(val));
 1996: }
 1997: 
 1998: /**
 1999:  * xmlXPathCacheNewNodeSet:
 2000:  * @ctxt: the XPath context
 2001:  * @val:  the NodePtr value
 2002:  *
 2003:  * This is the cached version of xmlXPathNewNodeSet().
 2004:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
 2005:  * it with the single Node @val
 2006:  *
 2007:  * Returns the created or reused object.
 2008:  */
 2009: static xmlXPathObjectPtr
 2010: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
 2011: {
 2012:     if ((ctxt != NULL) && (ctxt->cache)) {
 2013: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2014: 
 2015: 	if ((cache->nodesetObjs != NULL) &&
 2016: 	    (cache->nodesetObjs->number != 0))
 2017: 	{
 2018: 	    xmlXPathObjectPtr ret;
 2019: 	    /*
 2020: 	    * Use the nodset-cache.
 2021: 	    */
 2022: 	    ret = (xmlXPathObjectPtr)
 2023: 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
 2024: 	    ret->type = XPATH_NODESET;
 2025: 	    ret->boolval = 0;
 2026: 	    if (val) {
 2027: 		if ((ret->nodesetval->nodeMax == 0) ||
 2028: 		    (val->type == XML_NAMESPACE_DECL))
 2029: 		{
 2030: 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
 2031: 		} else {
 2032: 		    ret->nodesetval->nodeTab[0] = val;
 2033: 		    ret->nodesetval->nodeNr = 1;
 2034: 		}
 2035: 	    }
 2036: #ifdef XP_DEBUG_OBJ_USAGE
 2037: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2038: #endif
 2039: 	    return(ret);
 2040: 	} else if ((cache->miscObjs != NULL) &&
 2041: 	    (cache->miscObjs->number != 0))
 2042: 	{
 2043: 	    xmlXPathObjectPtr ret;
 2044: 	    /*
 2045: 	    * Fallback to misc-cache.
 2046: 	    */
 2047: 
 2048: 	    ret = (xmlXPathObjectPtr)
 2049: 		cache->miscObjs->items[--cache->miscObjs->number];
 2050: 
 2051: 	    ret->type = XPATH_NODESET;
 2052: 	    ret->boolval = 0;
 2053: 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
 2054: #ifdef XP_DEBUG_OBJ_USAGE
 2055: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2056: #endif
 2057: 	    return(ret);
 2058: 	}
 2059:     }
 2060:     return(xmlXPathNewNodeSet(val));
 2061: }
 2062: 
 2063: /**
 2064:  * xmlXPathCacheNewCString:
 2065:  * @ctxt: the XPath context
 2066:  * @val:  the char * value
 2067:  *
 2068:  * This is the cached version of xmlXPathNewCString().
 2069:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2070:  *
 2071:  * Returns the created or reused object.
 2072:  */
 2073: static xmlXPathObjectPtr
 2074: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
 2075: {
 2076:     if ((ctxt != NULL) && (ctxt->cache)) {
 2077: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2078: 
 2079: 	if ((cache->stringObjs != NULL) &&
 2080: 	    (cache->stringObjs->number != 0))
 2081: 	{
 2082: 	    xmlXPathObjectPtr ret;
 2083: 
 2084: 	    ret = (xmlXPathObjectPtr)
 2085: 		cache->stringObjs->items[--cache->stringObjs->number];
 2086: 
 2087: 	    ret->type = XPATH_STRING;
 2088: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2089: #ifdef XP_DEBUG_OBJ_USAGE
 2090: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2091: #endif
 2092: 	    return(ret);
 2093: 	} else if ((cache->miscObjs != NULL) &&
 2094: 	    (cache->miscObjs->number != 0))
 2095: 	{
 2096: 	    xmlXPathObjectPtr ret;
 2097: 
 2098: 	    ret = (xmlXPathObjectPtr)
 2099: 		cache->miscObjs->items[--cache->miscObjs->number];
 2100: 
 2101: 	    ret->type = XPATH_STRING;
 2102: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2103: #ifdef XP_DEBUG_OBJ_USAGE
 2104: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2105: #endif
 2106: 	    return(ret);
 2107: 	}
 2108:     }
 2109:     return(xmlXPathNewCString(val));
 2110: }
 2111: 
 2112: /**
 2113:  * xmlXPathCacheNewString:
 2114:  * @ctxt: the XPath context
 2115:  * @val:  the xmlChar * value
 2116:  *
 2117:  * This is the cached version of xmlXPathNewString().
 2118:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2119:  *
 2120:  * Returns the created or reused object.
 2121:  */
 2122: static xmlXPathObjectPtr
 2123: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
 2124: {
 2125:     if ((ctxt != NULL) && (ctxt->cache)) {
 2126: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2127: 
 2128: 	if ((cache->stringObjs != NULL) &&
 2129: 	    (cache->stringObjs->number != 0))
 2130: 	{
 2131: 	    xmlXPathObjectPtr ret;
 2132: 
 2133: 	    ret = (xmlXPathObjectPtr)
 2134: 		cache->stringObjs->items[--cache->stringObjs->number];
 2135: 	    ret->type = XPATH_STRING;
 2136: 	    if (val != NULL)
 2137: 		ret->stringval = xmlStrdup(val);
 2138: 	    else
 2139: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2140: #ifdef XP_DEBUG_OBJ_USAGE
 2141: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2142: #endif
 2143: 	    return(ret);
 2144: 	} else if ((cache->miscObjs != NULL) &&
 2145: 	    (cache->miscObjs->number != 0))
 2146: 	{
 2147: 	    xmlXPathObjectPtr ret;
 2148: 
 2149: 	    ret = (xmlXPathObjectPtr)
 2150: 		cache->miscObjs->items[--cache->miscObjs->number];
 2151: 
 2152: 	    ret->type = XPATH_STRING;
 2153: 	    if (val != NULL)
 2154: 		ret->stringval = xmlStrdup(val);
 2155: 	    else
 2156: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2157: #ifdef XP_DEBUG_OBJ_USAGE
 2158: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2159: #endif
 2160: 	    return(ret);
 2161: 	}
 2162:     }
 2163:     return(xmlXPathNewString(val));
 2164: }
 2165: 
 2166: /**
 2167:  * xmlXPathCacheNewBoolean:
 2168:  * @ctxt: the XPath context
 2169:  * @val:  the boolean value
 2170:  *
 2171:  * This is the cached version of xmlXPathNewBoolean().
 2172:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
 2173:  *
 2174:  * Returns the created or reused object.
 2175:  */
 2176: static xmlXPathObjectPtr
 2177: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
 2178: {
 2179:     if ((ctxt != NULL) && (ctxt->cache)) {
 2180: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2181: 
 2182: 	if ((cache->booleanObjs != NULL) &&
 2183: 	    (cache->booleanObjs->number != 0))
 2184: 	{
 2185: 	    xmlXPathObjectPtr ret;
 2186: 
 2187: 	    ret = (xmlXPathObjectPtr)
 2188: 		cache->booleanObjs->items[--cache->booleanObjs->number];
 2189: 	    ret->type = XPATH_BOOLEAN;
 2190: 	    ret->boolval = (val != 0);
 2191: #ifdef XP_DEBUG_OBJ_USAGE
 2192: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2193: #endif
 2194: 	    return(ret);
 2195: 	} else if ((cache->miscObjs != NULL) &&
 2196: 	    (cache->miscObjs->number != 0))
 2197: 	{
 2198: 	    xmlXPathObjectPtr ret;
 2199: 
 2200: 	    ret = (xmlXPathObjectPtr)
 2201: 		cache->miscObjs->items[--cache->miscObjs->number];
 2202: 
 2203: 	    ret->type = XPATH_BOOLEAN;
 2204: 	    ret->boolval = (val != 0);
 2205: #ifdef XP_DEBUG_OBJ_USAGE
 2206: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2207: #endif
 2208: 	    return(ret);
 2209: 	}
 2210:     }
 2211:     return(xmlXPathNewBoolean(val));
 2212: }
 2213: 
 2214: /**
 2215:  * xmlXPathCacheNewFloat:
 2216:  * @ctxt: the XPath context
 2217:  * @val:  the double value
 2218:  *
 2219:  * This is the cached version of xmlXPathNewFloat().
 2220:  * Acquires an xmlXPathObjectPtr of type double and of value @val
 2221:  *
 2222:  * Returns the created or reused object.
 2223:  */
 2224: static xmlXPathObjectPtr
 2225: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
 2226: {
 2227:      if ((ctxt != NULL) && (ctxt->cache)) {
 2228: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2229: 
 2230: 	if ((cache->numberObjs != NULL) &&
 2231: 	    (cache->numberObjs->number != 0))
 2232: 	{
 2233: 	    xmlXPathObjectPtr ret;
 2234: 
 2235: 	    ret = (xmlXPathObjectPtr)
 2236: 		cache->numberObjs->items[--cache->numberObjs->number];
 2237: 	    ret->type = XPATH_NUMBER;
 2238: 	    ret->floatval = val;
 2239: #ifdef XP_DEBUG_OBJ_USAGE
 2240: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2241: #endif
 2242: 	    return(ret);
 2243: 	} else if ((cache->miscObjs != NULL) &&
 2244: 	    (cache->miscObjs->number != 0))
 2245: 	{
 2246: 	    xmlXPathObjectPtr ret;
 2247: 
 2248: 	    ret = (xmlXPathObjectPtr)
 2249: 		cache->miscObjs->items[--cache->miscObjs->number];
 2250: 
 2251: 	    ret->type = XPATH_NUMBER;
 2252: 	    ret->floatval = val;
 2253: #ifdef XP_DEBUG_OBJ_USAGE
 2254: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2255: #endif
 2256: 	    return(ret);
 2257: 	}
 2258:     }
 2259:     return(xmlXPathNewFloat(val));
 2260: }
 2261: 
 2262: /**
 2263:  * xmlXPathCacheConvertString:
 2264:  * @ctxt: the XPath context
 2265:  * @val:  an XPath object
 2266:  *
 2267:  * This is the cached version of xmlXPathConvertString().
 2268:  * Converts an existing object to its string() equivalent
 2269:  *
 2270:  * Returns a created or reused object, the old one is freed (cached)
 2271:  *         (or the operation is done directly on @val)
 2272:  */
 2273: 
 2274: static xmlXPathObjectPtr
 2275: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2276:     xmlChar *res = NULL;
 2277: 
 2278:     if (val == NULL)
 2279: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2280: 
 2281:     switch (val->type) {
 2282:     case XPATH_UNDEFINED:
 2283: #ifdef DEBUG_EXPR
 2284: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 2285: #endif
 2286: 	break;
 2287:     case XPATH_NODESET:
 2288:     case XPATH_XSLT_TREE:
 2289: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 2290: 	break;
 2291:     case XPATH_STRING:
 2292: 	return(val);
 2293:     case XPATH_BOOLEAN:
 2294: 	res = xmlXPathCastBooleanToString(val->boolval);
 2295: 	break;
 2296:     case XPATH_NUMBER:
 2297: 	res = xmlXPathCastNumberToString(val->floatval);
 2298: 	break;
 2299:     case XPATH_USERS:
 2300:     case XPATH_POINT:
 2301:     case XPATH_RANGE:
 2302:     case XPATH_LOCATIONSET:
 2303: 	TODO;
 2304: 	break;
 2305:     }
 2306:     xmlXPathReleaseObject(ctxt, val);
 2307:     if (res == NULL)
 2308: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2309:     return(xmlXPathCacheWrapString(ctxt, res));
 2310: }
 2311: 
 2312: /**
 2313:  * xmlXPathCacheObjectCopy:
 2314:  * @ctxt: the XPath context
 2315:  * @val:  the original object
 2316:  *
 2317:  * This is the cached version of xmlXPathObjectCopy().
 2318:  * Acquire a copy of a given object
 2319:  *
 2320:  * Returns a created or reused created object.
 2321:  */
 2322: static xmlXPathObjectPtr
 2323: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
 2324: {
 2325:     if (val == NULL)
 2326: 	return(NULL);
 2327: 
 2328:     if (XP_HAS_CACHE(ctxt)) {
 2329: 	switch (val->type) {
 2330: 	    case XPATH_NODESET:
 2331: 		return(xmlXPathCacheWrapNodeSet(ctxt,
 2332: 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
 2333: 	    case XPATH_STRING:
 2334: 		return(xmlXPathCacheNewString(ctxt, val->stringval));
 2335: 	    case XPATH_BOOLEAN:
 2336: 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
 2337: 	    case XPATH_NUMBER:
 2338: 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
 2339: 	    default:
 2340: 		break;
 2341: 	}
 2342:     }
 2343:     return(xmlXPathObjectCopy(val));
 2344: }
 2345: 
 2346: /**
 2347:  * xmlXPathCacheConvertBoolean:
 2348:  * @ctxt: the XPath context
 2349:  * @val:  an XPath object
 2350:  *
 2351:  * This is the cached version of xmlXPathConvertBoolean().
 2352:  * Converts an existing object to its boolean() equivalent
 2353:  *
 2354:  * Returns a created or reused object, the old one is freed (or the operation
 2355:  *         is done directly on @val)
 2356:  */
 2357: static xmlXPathObjectPtr
 2358: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2359:     xmlXPathObjectPtr ret;
 2360: 
 2361:     if (val == NULL)
 2362: 	return(xmlXPathCacheNewBoolean(ctxt, 0));
 2363:     if (val->type == XPATH_BOOLEAN)
 2364: 	return(val);
 2365:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
 2366:     xmlXPathReleaseObject(ctxt, val);
 2367:     return(ret);
 2368: }
 2369: 
 2370: /**
 2371:  * xmlXPathCacheConvertNumber:
 2372:  * @ctxt: the XPath context
 2373:  * @val:  an XPath object
 2374:  *
 2375:  * This is the cached version of xmlXPathConvertNumber().
 2376:  * Converts an existing object to its number() equivalent
 2377:  *
 2378:  * Returns a created or reused object, the old one is freed (or the operation
 2379:  *         is done directly on @val)
 2380:  */
 2381: static xmlXPathObjectPtr
 2382: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2383:     xmlXPathObjectPtr ret;
 2384: 
 2385:     if (val == NULL)
 2386: 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
 2387:     if (val->type == XPATH_NUMBER)
 2388: 	return(val);
 2389:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
 2390:     xmlXPathReleaseObject(ctxt, val);
 2391:     return(ret);
 2392: }
 2393: 
 2394: /************************************************************************
 2395:  *									*
 2396:  *		Parser stacks related functions and macros		*
 2397:  *									*
 2398:  ************************************************************************/
 2399: 
 2400: /**
 2401:  * valuePop:
 2402:  * @ctxt: an XPath evaluation context
 2403:  *
 2404:  * Pops the top XPath object from the value stack
 2405:  *
 2406:  * Returns the XPath object just removed
 2407:  */
 2408: xmlXPathObjectPtr
 2409: valuePop(xmlXPathParserContextPtr ctxt)
 2410: {
 2411:     xmlXPathObjectPtr ret;
 2412: 
 2413:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
 2414:         return (NULL);
 2415:     ctxt->valueNr--;
 2416:     if (ctxt->valueNr > 0)
 2417:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
 2418:     else
 2419:         ctxt->value = NULL;
 2420:     ret = ctxt->valueTab[ctxt->valueNr];
 2421:     ctxt->valueTab[ctxt->valueNr] = NULL;
 2422:     return (ret);
 2423: }
 2424: /**
 2425:  * valuePush:
 2426:  * @ctxt:  an XPath evaluation context
 2427:  * @value:  the XPath object
 2428:  *
 2429:  * Pushes a new XPath object on top of the value stack
 2430:  *
 2431:  * returns the number of items on the value stack
 2432:  */
 2433: int
 2434: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
 2435: {
 2436:     if ((ctxt == NULL) || (value == NULL)) return(-1);
 2437:     if (ctxt->valueNr >= ctxt->valueMax) {
 2438:         xmlXPathObjectPtr *tmp;
 2439: 
 2440:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
 2441:                                              2 * ctxt->valueMax *
 2442:                                              sizeof(ctxt->valueTab[0]));
 2443:         if (tmp == NULL) {
 2444:             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
 2445:             return (0);
 2446:         }
 2447:         ctxt->valueMax *= 2;
 2448: 	ctxt->valueTab = tmp;
 2449:     }
 2450:     ctxt->valueTab[ctxt->valueNr] = value;
 2451:     ctxt->value = value;
 2452:     return (ctxt->valueNr++);
 2453: }
 2454: 
 2455: /**
 2456:  * xmlXPathPopBoolean:
 2457:  * @ctxt:  an XPath parser context
 2458:  *
 2459:  * Pops a boolean from the stack, handling conversion if needed.
 2460:  * Check error with #xmlXPathCheckError.
 2461:  *
 2462:  * Returns the boolean
 2463:  */
 2464: int
 2465: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
 2466:     xmlXPathObjectPtr obj;
 2467:     int ret;
 2468: 
 2469:     obj = valuePop(ctxt);
 2470:     if (obj == NULL) {
 2471: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2472: 	return(0);
 2473:     }
 2474:     if (obj->type != XPATH_BOOLEAN)
 2475: 	ret = xmlXPathCastToBoolean(obj);
 2476:     else
 2477:         ret = obj->boolval;
 2478:     xmlXPathReleaseObject(ctxt->context, obj);
 2479:     return(ret);
 2480: }
 2481: 
 2482: /**
 2483:  * xmlXPathPopNumber:
 2484:  * @ctxt:  an XPath parser context
 2485:  *
 2486:  * Pops a number from the stack, handling conversion if needed.
 2487:  * Check error with #xmlXPathCheckError.
 2488:  *
 2489:  * Returns the number
 2490:  */
 2491: double
 2492: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
 2493:     xmlXPathObjectPtr obj;
 2494:     double ret;
 2495: 
 2496:     obj = valuePop(ctxt);
 2497:     if (obj == NULL) {
 2498: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2499: 	return(0);
 2500:     }
 2501:     if (obj->type != XPATH_NUMBER)
 2502: 	ret = xmlXPathCastToNumber(obj);
 2503:     else
 2504:         ret = obj->floatval;
 2505:     xmlXPathReleaseObject(ctxt->context, obj);
 2506:     return(ret);
 2507: }
 2508: 
 2509: /**
 2510:  * xmlXPathPopString:
 2511:  * @ctxt:  an XPath parser context
 2512:  *
 2513:  * Pops a string from the stack, handling conversion if needed.
 2514:  * Check error with #xmlXPathCheckError.
 2515:  *
 2516:  * Returns the string
 2517:  */
 2518: xmlChar *
 2519: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
 2520:     xmlXPathObjectPtr obj;
 2521:     xmlChar * ret;
 2522: 
 2523:     obj = valuePop(ctxt);
 2524:     if (obj == NULL) {
 2525: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2526: 	return(NULL);
 2527:     }
 2528:     ret = xmlXPathCastToString(obj);	/* this does required strdup */
 2529:     /* TODO: needs refactoring somewhere else */
 2530:     if (obj->stringval == ret)
 2531: 	obj->stringval = NULL;
 2532:     xmlXPathReleaseObject(ctxt->context, obj);
 2533:     return(ret);
 2534: }
 2535: 
 2536: /**
 2537:  * xmlXPathPopNodeSet:
 2538:  * @ctxt:  an XPath parser context
 2539:  *
 2540:  * Pops a node-set from the stack, handling conversion if needed.
 2541:  * Check error with #xmlXPathCheckError.
 2542:  *
 2543:  * Returns the node-set
 2544:  */
 2545: xmlNodeSetPtr
 2546: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
 2547:     xmlXPathObjectPtr obj;
 2548:     xmlNodeSetPtr ret;
 2549: 
 2550:     if (ctxt == NULL) return(NULL);
 2551:     if (ctxt->value == NULL) {
 2552: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2553: 	return(NULL);
 2554:     }
 2555:     if (!xmlXPathStackIsNodeSet(ctxt)) {
 2556: 	xmlXPathSetTypeError(ctxt);
 2557: 	return(NULL);
 2558:     }
 2559:     obj = valuePop(ctxt);
 2560:     ret = obj->nodesetval;
 2561: #if 0
 2562:     /* to fix memory leak of not clearing obj->user */
 2563:     if (obj->boolval && obj->user != NULL)
 2564:         xmlFreeNodeList((xmlNodePtr) obj->user);
 2565: #endif
 2566:     obj->nodesetval = NULL;
 2567:     xmlXPathReleaseObject(ctxt->context, obj);
 2568:     return(ret);
 2569: }
 2570: 
 2571: /**
 2572:  * xmlXPathPopExternal:
 2573:  * @ctxt:  an XPath parser context
 2574:  *
 2575:  * Pops an external object from the stack, handling conversion if needed.
 2576:  * Check error with #xmlXPathCheckError.
 2577:  *
 2578:  * Returns the object
 2579:  */
 2580: void *
 2581: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
 2582:     xmlXPathObjectPtr obj;
 2583:     void * ret;
 2584: 
 2585:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
 2586: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2587: 	return(NULL);
 2588:     }
 2589:     if (ctxt->value->type != XPATH_USERS) {
 2590: 	xmlXPathSetTypeError(ctxt);
 2591: 	return(NULL);
 2592:     }
 2593:     obj = valuePop(ctxt);
 2594:     ret = obj->user;
 2595:     obj->user = NULL;
 2596:     xmlXPathReleaseObject(ctxt->context, obj);
 2597:     return(ret);
 2598: }
 2599: 
 2600: /*
 2601:  * Macros for accessing the content. Those should be used only by the parser,
 2602:  * and not exported.
 2603:  *
 2604:  * Dirty macros, i.e. one need to make assumption on the context to use them
 2605:  *
 2606:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
 2607:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
 2608:  *           in ISO-Latin or UTF-8.
 2609:  *           This should be used internally by the parser
 2610:  *           only to compare to ASCII values otherwise it would break when
 2611:  *           running with UTF-8 encoding.
 2612:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
 2613:  *           to compare on ASCII based substring.
 2614:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
 2615:  *           strings within the parser.
 2616:  *   CURRENT Returns the current char value, with the full decoding of
 2617:  *           UTF-8 if we are using this mode. It returns an int.
 2618:  *   NEXT    Skip to the next character, this does the proper decoding
 2619:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
 2620:  *           It returns the pointer to the current xmlChar.
 2621:  */
 2622: 
 2623: #define CUR (*ctxt->cur)
 2624: #define SKIP(val) ctxt->cur += (val)
 2625: #define NXT(val) ctxt->cur[(val)]
 2626: #define CUR_PTR ctxt->cur
 2627: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
 2628: 
 2629: #define COPY_BUF(l,b,i,v)                                              \
 2630:     if (l == 1) b[i++] = (xmlChar) v;                                  \
 2631:     else i += xmlCopyChar(l,&b[i],v)
 2632: 
 2633: #define NEXTL(l)  ctxt->cur += l
 2634: 
 2635: #define SKIP_BLANKS							\
 2636:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
 2637: 
 2638: #define CURRENT (*ctxt->cur)
 2639: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
 2640: 
 2641: 
 2642: #ifndef DBL_DIG
 2643: #define DBL_DIG 16
 2644: #endif
 2645: #ifndef DBL_EPSILON
 2646: #define DBL_EPSILON 1E-9
 2647: #endif
 2648: 
 2649: #define UPPER_DOUBLE 1E9
 2650: #define LOWER_DOUBLE 1E-5
 2651: #define	LOWER_DOUBLE_EXP 5
 2652: 
 2653: #define INTEGER_DIGITS DBL_DIG
 2654: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
 2655: #define EXPONENT_DIGITS (3 + 2)
 2656: 
 2657: /**
 2658:  * xmlXPathFormatNumber:
 2659:  * @number:     number to format
 2660:  * @buffer:     output buffer
 2661:  * @buffersize: size of output buffer
 2662:  *
 2663:  * Convert the number into a string representation.
 2664:  */
 2665: static void
 2666: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
 2667: {
 2668:     switch (xmlXPathIsInf(number)) {
 2669:     case 1:
 2670: 	if (buffersize > (int)sizeof("Infinity"))
 2671: 	    snprintf(buffer, buffersize, "Infinity");
 2672: 	break;
 2673:     case -1:
 2674: 	if (buffersize > (int)sizeof("-Infinity"))
 2675: 	    snprintf(buffer, buffersize, "-Infinity");
 2676: 	break;
 2677:     default:
 2678: 	if (xmlXPathIsNaN(number)) {
 2679: 	    if (buffersize > (int)sizeof("NaN"))
 2680: 		snprintf(buffer, buffersize, "NaN");
 2681: 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
 2682: 	    snprintf(buffer, buffersize, "0");
 2683: 	} else if (number == ((int) number)) {
 2684: 	    char work[30];
 2685: 	    char *ptr, *cur;
 2686: 	    int value = (int) number;
 2687: 
 2688:             ptr = &buffer[0];
 2689: 	    if (value == 0) {
 2690: 		*ptr++ = '0';
 2691: 	    } else {
 2692: 		snprintf(work, 29, "%d", value);
 2693: 		cur = &work[0];
 2694: 		while ((*cur) && (ptr - buffer < buffersize)) {
 2695: 		    *ptr++ = *cur++;
 2696: 		}
 2697: 	    }
 2698: 	    if (ptr - buffer < buffersize) {
 2699: 		*ptr = 0;
 2700: 	    } else if (buffersize > 0) {
 2701: 		ptr--;
 2702: 		*ptr = 0;
 2703: 	    }
 2704: 	} else {
 2705: 	    /*
 2706: 	      For the dimension of work,
 2707: 	          DBL_DIG is number of significant digits
 2708: 		  EXPONENT is only needed for "scientific notation"
 2709: 	          3 is sign, decimal point, and terminating zero
 2710: 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
 2711: 	      Note that this dimension is slightly (a few characters)
 2712: 	      larger than actually necessary.
 2713: 	    */
 2714: 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
 2715: 	    int integer_place, fraction_place;
 2716: 	    char *ptr;
 2717: 	    char *after_fraction;
 2718: 	    double absolute_value;
 2719: 	    int size;
 2720: 
 2721: 	    absolute_value = fabs(number);
 2722: 
 2723: 	    /*
 2724: 	     * First choose format - scientific or regular floating point.
 2725: 	     * In either case, result is in work, and after_fraction points
 2726: 	     * just past the fractional part.
 2727: 	    */
 2728: 	    if ( ((absolute_value > UPPER_DOUBLE) ||
 2729: 		  (absolute_value < LOWER_DOUBLE)) &&
 2730: 		 (absolute_value != 0.0) ) {
 2731: 		/* Use scientific notation */
 2732: 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
 2733: 		fraction_place = DBL_DIG - 1;
 2734: 		size = snprintf(work, sizeof(work),"%*.*e",
 2735: 			 integer_place, fraction_place, number);
 2736: 		while ((size > 0) && (work[size] != 'e')) size--;
 2737: 
 2738: 	    }
 2739: 	    else {
 2740: 		/* Use regular notation */
 2741: 		if (absolute_value > 0.0) {
 2742: 		    integer_place = (int)log10(absolute_value);
 2743: 		    if (integer_place > 0)
 2744: 		        fraction_place = DBL_DIG - integer_place - 1;
 2745: 		    else
 2746: 		        fraction_place = DBL_DIG - integer_place;
 2747: 		} else {
 2748: 		    fraction_place = 1;
 2749: 		}
 2750: 		size = snprintf(work, sizeof(work), "%0.*f",
 2751: 				fraction_place, number);
 2752: 	    }
 2753: 
 2754: 	    /* Remove fractional trailing zeroes */
 2755: 	    after_fraction = work + size;
 2756: 	    ptr = after_fraction;
 2757: 	    while (*(--ptr) == '0')
 2758: 		;
 2759: 	    if (*ptr != '.')
 2760: 	        ptr++;
 2761: 	    while ((*ptr++ = *after_fraction++) != 0);
 2762: 
 2763: 	    /* Finally copy result back to caller */
 2764: 	    size = strlen(work) + 1;
 2765: 	    if (size > buffersize) {
 2766: 		work[buffersize - 1] = 0;
 2767: 		size = buffersize;
 2768: 	    }
 2769: 	    memmove(buffer, work, size);
 2770: 	}
 2771: 	break;
 2772:     }
 2773: }
 2774: 
 2775: 
 2776: /************************************************************************
 2777:  *									*
 2778:  *			Routines to handle NodeSets			*
 2779:  *									*
 2780:  ************************************************************************/
 2781: 
 2782: /**
 2783:  * xmlXPathOrderDocElems:
 2784:  * @doc:  an input document
 2785:  *
 2786:  * Call this routine to speed up XPath computation on static documents.
 2787:  * This stamps all the element nodes with the document order
 2788:  * Like for line information, the order is kept in the element->content
 2789:  * field, the value stored is actually - the node number (starting at -1)
 2790:  * to be able to differentiate from line numbers.
 2791:  *
 2792:  * Returns the number of elements found in the document or -1 in case
 2793:  *    of error.
 2794:  */
 2795: long
 2796: xmlXPathOrderDocElems(xmlDocPtr doc) {
 2797:     long count = 0;
 2798:     xmlNodePtr cur;
 2799: 
 2800:     if (doc == NULL)
 2801: 	return(-1);
 2802:     cur = doc->children;
 2803:     while (cur != NULL) {
 2804: 	if (cur->type == XML_ELEMENT_NODE) {
 2805: 	    cur->content = (void *) (-(++count));
 2806: 	    if (cur->children != NULL) {
 2807: 		cur = cur->children;
 2808: 		continue;
 2809: 	    }
 2810: 	}
 2811: 	if (cur->next != NULL) {
 2812: 	    cur = cur->next;
 2813: 	    continue;
 2814: 	}
 2815: 	do {
 2816: 	    cur = cur->parent;
 2817: 	    if (cur == NULL)
 2818: 		break;
 2819: 	    if (cur == (xmlNodePtr) doc) {
 2820: 		cur = NULL;
 2821: 		break;
 2822: 	    }
 2823: 	    if (cur->next != NULL) {
 2824: 		cur = cur->next;
 2825: 		break;
 2826: 	    }
 2827: 	} while (cur != NULL);
 2828:     }
 2829:     return(count);
 2830: }
 2831: 
 2832: /**
 2833:  * xmlXPathCmpNodes:
 2834:  * @node1:  the first node
 2835:  * @node2:  the second node
 2836:  *
 2837:  * Compare two nodes w.r.t document order
 2838:  *
 2839:  * Returns -2 in case of error 1 if first point < second point, 0 if
 2840:  *         it's the same node, -1 otherwise
 2841:  */
 2842: int
 2843: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
 2844:     int depth1, depth2;
 2845:     int attr1 = 0, attr2 = 0;
 2846:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
 2847:     xmlNodePtr cur, root;
 2848: 
 2849:     if ((node1 == NULL) || (node2 == NULL))
 2850: 	return(-2);
 2851:     /*
 2852:      * a couple of optimizations which will avoid computations in most cases
 2853:      */
 2854:     if (node1 == node2)		/* trivial case */
 2855: 	return(0);
 2856:     if (node1->type == XML_ATTRIBUTE_NODE) {
 2857: 	attr1 = 1;
 2858: 	attrNode1 = node1;
 2859: 	node1 = node1->parent;
 2860:     }
 2861:     if (node2->type == XML_ATTRIBUTE_NODE) {
 2862: 	attr2 = 1;
 2863: 	attrNode2 = node2;
 2864: 	node2 = node2->parent;
 2865:     }
 2866:     if (node1 == node2) {
 2867: 	if (attr1 == attr2) {
 2868: 	    /* not required, but we keep attributes in order */
 2869: 	    if (attr1 != 0) {
 2870: 	        cur = attrNode2->prev;
 2871: 		while (cur != NULL) {
 2872: 		    if (cur == attrNode1)
 2873: 		        return (1);
 2874: 		    cur = cur->prev;
 2875: 		}
 2876: 		return (-1);
 2877: 	    }
 2878: 	    return(0);
 2879: 	}
 2880: 	if (attr2 == 1)
 2881: 	    return(1);
 2882: 	return(-1);
 2883:     }
 2884:     if ((node1->type == XML_NAMESPACE_DECL) ||
 2885:         (node2->type == XML_NAMESPACE_DECL))
 2886: 	return(1);
 2887:     if (node1 == node2->prev)
 2888: 	return(1);
 2889:     if (node1 == node2->next)
 2890: 	return(-1);
 2891: 
 2892:     /*
 2893:      * Speedup using document order if availble.
 2894:      */
 2895:     if ((node1->type == XML_ELEMENT_NODE) &&
 2896: 	(node2->type == XML_ELEMENT_NODE) &&
 2897: 	(0 > (long) node1->content) &&
 2898: 	(0 > (long) node2->content) &&
 2899: 	(node1->doc == node2->doc)) {
 2900: 	long l1, l2;
 2901: 
 2902: 	l1 = -((long) node1->content);
 2903: 	l2 = -((long) node2->content);
 2904: 	if (l1 < l2)
 2905: 	    return(1);
 2906: 	if (l1 > l2)
 2907: 	    return(-1);
 2908:     }
 2909: 
 2910:     /*
 2911:      * compute depth to root
 2912:      */
 2913:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 2914: 	if (cur == node1)
 2915: 	    return(1);
 2916: 	depth2++;
 2917:     }
 2918:     root = cur;
 2919:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 2920: 	if (cur == node2)
 2921: 	    return(-1);
 2922: 	depth1++;
 2923:     }
 2924:     /*
 2925:      * Distinct document (or distinct entities :-( ) case.
 2926:      */
 2927:     if (root != cur) {
 2928: 	return(-2);
 2929:     }
 2930:     /*
 2931:      * get the nearest common ancestor.
 2932:      */
 2933:     while (depth1 > depth2) {
 2934: 	depth1--;
 2935: 	node1 = node1->parent;
 2936:     }
 2937:     while (depth2 > depth1) {
 2938: 	depth2--;
 2939: 	node2 = node2->parent;
 2940:     }
 2941:     while (node1->parent != node2->parent) {
 2942: 	node1 = node1->parent;
 2943: 	node2 = node2->parent;
 2944: 	/* should not happen but just in case ... */
 2945: 	if ((node1 == NULL) || (node2 == NULL))
 2946: 	    return(-2);
 2947:     }
 2948:     /*
 2949:      * Find who's first.
 2950:      */
 2951:     if (node1 == node2->prev)
 2952: 	return(1);
 2953:     if (node1 == node2->next)
 2954: 	return(-1);
 2955:     /*
 2956:      * Speedup using document order if availble.
 2957:      */
 2958:     if ((node1->type == XML_ELEMENT_NODE) &&
 2959: 	(node2->type == XML_ELEMENT_NODE) &&
 2960: 	(0 > (long) node1->content) &&
 2961: 	(0 > (long) node2->content) &&
 2962: 	(node1->doc == node2->doc)) {
 2963: 	long l1, l2;
 2964: 
 2965: 	l1 = -((long) node1->content);
 2966: 	l2 = -((long) node2->content);
 2967: 	if (l1 < l2)
 2968: 	    return(1);
 2969: 	if (l1 > l2)
 2970: 	    return(-1);
 2971:     }
 2972: 
 2973:     for (cur = node1->next;cur != NULL;cur = cur->next)
 2974: 	if (cur == node2)
 2975: 	    return(1);
 2976:     return(-1); /* assume there is no sibling list corruption */
 2977: }
 2978: 
 2979: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 2980: /**
 2981:  * xmlXPathCmpNodesExt:
 2982:  * @node1:  the first node
 2983:  * @node2:  the second node
 2984:  *
 2985:  * Compare two nodes w.r.t document order.
 2986:  * This one is optimized for handling of non-element nodes.
 2987:  *
 2988:  * Returns -2 in case of error 1 if first point < second point, 0 if
 2989:  *         it's the same node, -1 otherwise
 2990:  */
 2991: static int
 2992: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 2993:     int depth1, depth2;
 2994:     int misc = 0, precedence1 = 0, precedence2 = 0;
 2995:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
 2996:     xmlNodePtr cur, root;
 2997:     long l1, l2;
 2998: 
 2999:     if ((node1 == NULL) || (node2 == NULL))
 3000: 	return(-2);
 3001: 
 3002:     if (node1 == node2)
 3003: 	return(0);
 3004: 
 3005:     /*
 3006:      * a couple of optimizations which will avoid computations in most cases
 3007:      */
 3008:     switch (node1->type) {
 3009: 	case XML_ELEMENT_NODE:
 3010: 	    if (node2->type == XML_ELEMENT_NODE) {
 3011: 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
 3012: 		    (0 > (long) node2->content) &&
 3013: 		    (node1->doc == node2->doc))
 3014: 		{
 3015: 		    l1 = -((long) node1->content);
 3016: 		    l2 = -((long) node2->content);
 3017: 		    if (l1 < l2)
 3018: 			return(1);
 3019: 		    if (l1 > l2)
 3020: 			return(-1);
 3021: 		} else
 3022: 		    goto turtle_comparison;
 3023: 	    }
 3024: 	    break;
 3025: 	case XML_ATTRIBUTE_NODE:
 3026: 	    precedence1 = 1; /* element is owner */
 3027: 	    miscNode1 = node1;
 3028: 	    node1 = node1->parent;
 3029: 	    misc = 1;
 3030: 	    break;
 3031: 	case XML_TEXT_NODE:
 3032: 	case XML_CDATA_SECTION_NODE:
 3033: 	case XML_COMMENT_NODE:
 3034: 	case XML_PI_NODE: {
 3035: 	    miscNode1 = node1;
 3036: 	    /*
 3037: 	    * Find nearest element node.
 3038: 	    */
 3039: 	    if (node1->prev != NULL) {
 3040: 		do {
 3041: 		    node1 = node1->prev;
 3042: 		    if (node1->type == XML_ELEMENT_NODE) {
 3043: 			precedence1 = 3; /* element in prev-sibl axis */
 3044: 			break;
 3045: 		    }
 3046: 		    if (node1->prev == NULL) {
 3047: 			precedence1 = 2; /* element is parent */
 3048: 			/*
 3049: 			* URGENT TODO: Are there any cases, where the
 3050: 			* parent of such a node is not an element node?
 3051: 			*/
 3052: 			node1 = node1->parent;
 3053: 			break;
 3054: 		    }
 3055: 		} while (1);
 3056: 	    } else {
 3057: 		precedence1 = 2; /* element is parent */
 3058: 		node1 = node1->parent;
 3059: 	    }
 3060: 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
 3061: 		(0 <= (long) node1->content)) {
 3062: 		/*
 3063: 		* Fallback for whatever case.
 3064: 		*/
 3065: 		node1 = miscNode1;
 3066: 		precedence1 = 0;
 3067: 	    } else
 3068: 		misc = 1;
 3069: 	}
 3070: 	    break;
 3071: 	case XML_NAMESPACE_DECL:
 3072: 	    /*
 3073: 	    * TODO: why do we return 1 for namespace nodes?
 3074: 	    */
 3075: 	    return(1);
 3076: 	default:
 3077: 	    break;
 3078:     }
 3079:     switch (node2->type) {
 3080: 	case XML_ELEMENT_NODE:
 3081: 	    break;
 3082: 	case XML_ATTRIBUTE_NODE:
 3083: 	    precedence2 = 1; /* element is owner */
 3084: 	    miscNode2 = node2;
 3085: 	    node2 = node2->parent;
 3086: 	    misc = 1;
 3087: 	    break;
 3088: 	case XML_TEXT_NODE:
 3089: 	case XML_CDATA_SECTION_NODE:
 3090: 	case XML_COMMENT_NODE:
 3091: 	case XML_PI_NODE: {
 3092: 	    miscNode2 = node2;
 3093: 	    if (node2->prev != NULL) {
 3094: 		do {
 3095: 		    node2 = node2->prev;
 3096: 		    if (node2->type == XML_ELEMENT_NODE) {
 3097: 			precedence2 = 3; /* element in prev-sibl axis */
 3098: 			break;
 3099: 		    }
 3100: 		    if (node2->prev == NULL) {
 3101: 			precedence2 = 2; /* element is parent */
 3102: 			node2 = node2->parent;
 3103: 			break;
 3104: 		    }
 3105: 		} while (1);
 3106: 	    } else {
 3107: 		precedence2 = 2; /* element is parent */
 3108: 		node2 = node2->parent;
 3109: 	    }
 3110: 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
 3111: 		(0 <= (long) node1->content))
 3112: 	    {
 3113: 		node2 = miscNode2;
 3114: 		precedence2 = 0;
 3115: 	    } else
 3116: 		misc = 1;
 3117: 	}
 3118: 	    break;
 3119: 	case XML_NAMESPACE_DECL:
 3120: 	    return(1);
 3121: 	default:
 3122: 	    break;
 3123:     }
 3124:     if (misc) {
 3125: 	if (node1 == node2) {
 3126: 	    if (precedence1 == precedence2) {
 3127: 		/*
 3128: 		* The ugly case; but normally there aren't many
 3129: 		* adjacent non-element nodes around.
 3130: 		*/
 3131: 		cur = miscNode2->prev;
 3132: 		while (cur != NULL) {
 3133: 		    if (cur == miscNode1)
 3134: 			return(1);
 3135: 		    if (cur->type == XML_ELEMENT_NODE)
 3136: 			return(-1);
 3137: 		    cur = cur->prev;
 3138: 		}
 3139: 		return (-1);
 3140: 	    } else {
 3141: 		/*
 3142: 		* Evaluate based on higher precedence wrt to the element.
 3143: 		* TODO: This assumes attributes are sorted before content.
 3144: 		*   Is this 100% correct?
 3145: 		*/
 3146: 		if (precedence1 < precedence2)
 3147: 		    return(1);
 3148: 		else
 3149: 		    return(-1);
 3150: 	    }
 3151: 	}
 3152: 	/*
 3153: 	* Special case: One of the helper-elements is contained by the other.
 3154: 	* <foo>
 3155: 	*   <node2>
 3156: 	*     <node1>Text-1(precedence1 == 2)</node1>
 3157: 	*   </node2>
 3158: 	*   Text-6(precedence2 == 3)
 3159: 	* </foo>
 3160: 	*/
 3161: 	if ((precedence2 == 3) && (precedence1 > 1)) {
 3162: 	    cur = node1->parent;
 3163: 	    while (cur) {
 3164: 		if (cur == node2)
 3165: 		    return(1);
 3166: 		cur = cur->parent;
 3167: 	    }
 3168: 	}
 3169: 	if ((precedence1 == 3) && (precedence2 > 1)) {
 3170: 	    cur = node2->parent;
 3171: 	    while (cur) {
 3172: 		if (cur == node1)
 3173: 		    return(-1);
 3174: 		cur = cur->parent;
 3175: 	    }
 3176: 	}
 3177:     }
 3178: 
 3179:     /*
 3180:      * Speedup using document order if availble.
 3181:      */
 3182:     if ((node1->type == XML_ELEMENT_NODE) &&
 3183: 	(node2->type == XML_ELEMENT_NODE) &&
 3184: 	(0 > (long) node1->content) &&
 3185: 	(0 > (long) node2->content) &&
 3186: 	(node1->doc == node2->doc)) {
 3187: 
 3188: 	l1 = -((long) node1->content);
 3189: 	l2 = -((long) node2->content);
 3190: 	if (l1 < l2)
 3191: 	    return(1);
 3192: 	if (l1 > l2)
 3193: 	    return(-1);
 3194:     }
 3195: 
 3196: turtle_comparison:
 3197: 
 3198:     if (node1 == node2->prev)
 3199: 	return(1);
 3200:     if (node1 == node2->next)
 3201: 	return(-1);
 3202:     /*
 3203:      * compute depth to root
 3204:      */
 3205:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 3206: 	if (cur == node1)
 3207: 	    return(1);
 3208: 	depth2++;
 3209:     }
 3210:     root = cur;
 3211:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 3212: 	if (cur == node2)
 3213: 	    return(-1);
 3214: 	depth1++;
 3215:     }
 3216:     /*
 3217:      * Distinct document (or distinct entities :-( ) case.
 3218:      */
 3219:     if (root != cur) {
 3220: 	return(-2);
 3221:     }
 3222:     /*
 3223:      * get the nearest common ancestor.
 3224:      */
 3225:     while (depth1 > depth2) {
 3226: 	depth1--;
 3227: 	node1 = node1->parent;
 3228:     }
 3229:     while (depth2 > depth1) {
 3230: 	depth2--;
 3231: 	node2 = node2->parent;
 3232:     }
 3233:     while (node1->parent != node2->parent) {
 3234: 	node1 = node1->parent;
 3235: 	node2 = node2->parent;
 3236: 	/* should not happen but just in case ... */
 3237: 	if ((node1 == NULL) || (node2 == NULL))
 3238: 	    return(-2);
 3239:     }
 3240:     /*
 3241:      * Find who's first.
 3242:      */
 3243:     if (node1 == node2->prev)
 3244: 	return(1);
 3245:     if (node1 == node2->next)
 3246: 	return(-1);
 3247:     /*
 3248:      * Speedup using document order if availble.
 3249:      */
 3250:     if ((node1->type == XML_ELEMENT_NODE) &&
 3251: 	(node2->type == XML_ELEMENT_NODE) &&
 3252: 	(0 > (long) node1->content) &&
 3253: 	(0 > (long) node2->content) &&
 3254: 	(node1->doc == node2->doc)) {
 3255: 
 3256: 	l1 = -((long) node1->content);
 3257: 	l2 = -((long) node2->content);
 3258: 	if (l1 < l2)
 3259: 	    return(1);
 3260: 	if (l1 > l2)
 3261: 	    return(-1);
 3262:     }
 3263: 
 3264:     for (cur = node1->next;cur != NULL;cur = cur->next)
 3265: 	if (cur == node2)
 3266: 	    return(1);
 3267:     return(-1); /* assume there is no sibling list corruption */
 3268: }
 3269: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
 3270: 
 3271: /**
 3272:  * xmlXPathNodeSetSort:
 3273:  * @set:  the node set
 3274:  *
 3275:  * Sort the node set in document order
 3276:  */
 3277: void
 3278: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
 3279:     int i, j, incr, len;
 3280:     xmlNodePtr tmp;
 3281: 
 3282:     if (set == NULL)
 3283: 	return;
 3284: 
 3285:     /* Use Shell's sort to sort the node-set */
 3286:     len = set->nodeNr;
 3287:     for (incr = len / 2; incr > 0; incr /= 2) {
 3288: 	for (i = incr; i < len; i++) {
 3289: 	    j = i - incr;
 3290: 	    while (j >= 0) {
 3291: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 3292: 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
 3293: 			set->nodeTab[j + incr]) == -1)
 3294: #else
 3295: 		if (xmlXPathCmpNodes(set->nodeTab[j],
 3296: 			set->nodeTab[j + incr]) == -1)
 3297: #endif
 3298: 		{
 3299: 		    tmp = set->nodeTab[j];
 3300: 		    set->nodeTab[j] = set->nodeTab[j + incr];
 3301: 		    set->nodeTab[j + incr] = tmp;
 3302: 		    j -= incr;
 3303: 		} else
 3304: 		    break;
 3305: 	    }
 3306: 	}
 3307:     }
 3308: }
 3309: 
 3310: #define XML_NODESET_DEFAULT	10
 3311: /**
 3312:  * xmlXPathNodeSetDupNs:
 3313:  * @node:  the parent node of the namespace XPath node
 3314:  * @ns:  the libxml namespace declaration node.
 3315:  *
 3316:  * Namespace node in libxml don't match the XPath semantic. In a node set
 3317:  * the namespace nodes are duplicated and the next pointer is set to the
 3318:  * parent node in the XPath semantic.
 3319:  *
 3320:  * Returns the newly created object.
 3321:  */
 3322: static xmlNodePtr
 3323: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
 3324:     xmlNsPtr cur;
 3325: 
 3326:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3327: 	return(NULL);
 3328:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
 3329: 	return((xmlNodePtr) ns);
 3330: 
 3331:     /*
 3332:      * Allocate a new Namespace and fill the fields.
 3333:      */
 3334:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
 3335:     if (cur == NULL) {
 3336:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
 3337: 	return(NULL);
 3338:     }
 3339:     memset(cur, 0, sizeof(xmlNs));
 3340:     cur->type = XML_NAMESPACE_DECL;
 3341:     if (ns->href != NULL)
 3342: 	cur->href = xmlStrdup(ns->href);
 3343:     if (ns->prefix != NULL)
 3344: 	cur->prefix = xmlStrdup(ns->prefix);
 3345:     cur->next = (xmlNsPtr) node;
 3346:     return((xmlNodePtr) cur);
 3347: }
 3348: 
 3349: /**
 3350:  * xmlXPathNodeSetFreeNs:
 3351:  * @ns:  the XPath namespace node found in a nodeset.
 3352:  *
 3353:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
 3354:  * the namespace nodes are duplicated and the next pointer is set to the
 3355:  * parent node in the XPath semantic. Check if such a node needs to be freed
 3356:  */
 3357: void
 3358: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
 3359:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3360: 	return;
 3361: 
 3362:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
 3363: 	if (ns->href != NULL)
 3364: 	    xmlFree((xmlChar *)ns->href);
 3365: 	if (ns->prefix != NULL)
 3366: 	    xmlFree((xmlChar *)ns->prefix);
 3367: 	xmlFree(ns);
 3368:     }
 3369: }
 3370: 
 3371: /**
 3372:  * xmlXPathNodeSetCreate:
 3373:  * @val:  an initial xmlNodePtr, or NULL
 3374:  *
 3375:  * Create a new xmlNodeSetPtr of type double and of value @val
 3376:  *
 3377:  * Returns the newly created object.
 3378:  */
 3379: xmlNodeSetPtr
 3380: xmlXPathNodeSetCreate(xmlNodePtr val) {
 3381:     xmlNodeSetPtr ret;
 3382: 
 3383:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3384:     if (ret == NULL) {
 3385:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3386: 	return(NULL);
 3387:     }
 3388:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3389:     if (val != NULL) {
 3390:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3391: 					     sizeof(xmlNodePtr));
 3392: 	if (ret->nodeTab == NULL) {
 3393: 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
 3394: 	    xmlFree(ret);
 3395: 	    return(NULL);
 3396: 	}
 3397: 	memset(ret->nodeTab, 0 ,
 3398: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3399:         ret->nodeMax = XML_NODESET_DEFAULT;
 3400: 	if (val->type == XML_NAMESPACE_DECL) {
 3401: 	    xmlNsPtr ns = (xmlNsPtr) val;
 3402: 
 3403: 	    ret->nodeTab[ret->nodeNr++] =
 3404: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3405: 	} else
 3406: 	    ret->nodeTab[ret->nodeNr++] = val;
 3407:     }
 3408:     return(ret);
 3409: }
 3410: 
 3411: /**
 3412:  * xmlXPathNodeSetCreateSize:
 3413:  * @size:  the initial size of the set
 3414:  *
 3415:  * Create a new xmlNodeSetPtr of type double and of value @val
 3416:  *
 3417:  * Returns the newly created object.
 3418:  */
 3419: static xmlNodeSetPtr
 3420: xmlXPathNodeSetCreateSize(int size) {
 3421:     xmlNodeSetPtr ret;
 3422: 
 3423:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3424:     if (ret == NULL) {
 3425:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3426: 	return(NULL);
 3427:     }
 3428:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3429:     if (size < XML_NODESET_DEFAULT)
 3430: 	size = XML_NODESET_DEFAULT;
 3431:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
 3432:     if (ret->nodeTab == NULL) {
 3433: 	xmlXPathErrMemory(NULL, "creating nodeset\n");
 3434: 	xmlFree(ret);
 3435: 	return(NULL);
 3436:     }
 3437:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
 3438:     ret->nodeMax = size;
 3439:     return(ret);
 3440: }
 3441: 
 3442: /**
 3443:  * xmlXPathNodeSetContains:
 3444:  * @cur:  the node-set
 3445:  * @val:  the node
 3446:  *
 3447:  * checks whether @cur contains @val
 3448:  *
 3449:  * Returns true (1) if @cur contains @val, false (0) otherwise
 3450:  */
 3451: int
 3452: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
 3453:     int i;
 3454: 
 3455:     if ((cur == NULL) || (val == NULL)) return(0);
 3456:     if (val->type == XML_NAMESPACE_DECL) {
 3457: 	for (i = 0; i < cur->nodeNr; i++) {
 3458: 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 3459: 		xmlNsPtr ns1, ns2;
 3460: 
 3461: 		ns1 = (xmlNsPtr) val;
 3462: 		ns2 = (xmlNsPtr) cur->nodeTab[i];
 3463: 		if (ns1 == ns2)
 3464: 		    return(1);
 3465: 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
 3466: 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
 3467: 		    return(1);
 3468: 	    }
 3469: 	}
 3470:     } else {
 3471: 	for (i = 0; i < cur->nodeNr; i++) {
 3472: 	    if (cur->nodeTab[i] == val)
 3473: 		return(1);
 3474: 	}
 3475:     }
 3476:     return(0);
 3477: }
 3478: 
 3479: /**
 3480:  * xmlXPathNodeSetAddNs:
 3481:  * @cur:  the initial node set
 3482:  * @node:  the hosting node
 3483:  * @ns:  a the namespace node
 3484:  *
 3485:  * add a new namespace node to an existing NodeSet
 3486:  */
 3487: void
 3488: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
 3489:     int i;
 3490: 
 3491: 
 3492:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
 3493:         (ns->type != XML_NAMESPACE_DECL) ||
 3494: 	(node->type != XML_ELEMENT_NODE))
 3495: 	return;
 3496: 
 3497:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3498:     /*
 3499:      * prevent duplicates
 3500:      */
 3501:     for (i = 0;i < cur->nodeNr;i++) {
 3502:         if ((cur->nodeTab[i] != NULL) &&
 3503: 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
 3504: 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
 3505: 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
 3506: 	    return;
 3507:     }
 3508: 
 3509:     /*
 3510:      * grow the nodeTab if needed
 3511:      */
 3512:     if (cur->nodeMax == 0) {
 3513:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3514: 					     sizeof(xmlNodePtr));
 3515: 	if (cur->nodeTab == NULL) {
 3516: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3517: 	    return;
 3518: 	}
 3519: 	memset(cur->nodeTab, 0 ,
 3520: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3521:         cur->nodeMax = XML_NODESET_DEFAULT;
 3522:     } else if (cur->nodeNr == cur->nodeMax) {
 3523:         xmlNodePtr *temp;
 3524: 
 3525:         cur->nodeMax *= 2;
 3526: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
 3527: 				      sizeof(xmlNodePtr));
 3528: 	if (temp == NULL) {
 3529: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3530: 	    return;
 3531: 	}
 3532: 	cur->nodeTab = temp;
 3533:     }
 3534:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
 3535: }
 3536: 
 3537: /**
 3538:  * xmlXPathNodeSetAdd:
 3539:  * @cur:  the initial node set
 3540:  * @val:  a new xmlNodePtr
 3541:  *
 3542:  * add a new xmlNodePtr to an existing NodeSet
 3543:  */
 3544: void
 3545: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
 3546:     int i;
 3547: 
 3548:     if ((cur == NULL) || (val == NULL)) return;
 3549: 
 3550: #if 0
 3551:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
 3552: 	return;	/* an XSLT fake node */
 3553: #endif
 3554: 
 3555:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3556:     /*
 3557:      * prevent duplcates
 3558:      */
 3559:     for (i = 0;i < cur->nodeNr;i++)
 3560:         if (cur->nodeTab[i] == val) return;
 3561: 
 3562:     /*
 3563:      * grow the nodeTab if needed
 3564:      */
 3565:     if (cur->nodeMax == 0) {
 3566:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3567: 					     sizeof(xmlNodePtr));
 3568: 	if (cur->nodeTab == NULL) {
 3569: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3570: 	    return;
 3571: 	}
 3572: 	memset(cur->nodeTab, 0 ,
 3573: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3574:         cur->nodeMax = XML_NODESET_DEFAULT;
 3575:     } else if (cur->nodeNr == cur->nodeMax) {
 3576:         xmlNodePtr *temp;
 3577: 
 3578:         cur->nodeMax *= 2;
 3579: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
 3580: 				      sizeof(xmlNodePtr));
 3581: 	if (temp == NULL) {
 3582: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3583: 	    return;
 3584: 	}
 3585: 	cur->nodeTab = temp;
 3586:     }
 3587:     if (val->type == XML_NAMESPACE_DECL) {
 3588: 	xmlNsPtr ns = (xmlNsPtr) val;
 3589: 
 3590: 	cur->nodeTab[cur->nodeNr++] =
 3591: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3592:     } else
 3593: 	cur->nodeTab[cur->nodeNr++] = val;
 3594: }
 3595: 
 3596: /**
 3597:  * xmlXPathNodeSetAddUnique:
 3598:  * @cur:  the initial node set
 3599:  * @val:  a new xmlNodePtr
 3600:  *
 3601:  * add a new xmlNodePtr to an existing NodeSet, optimized version
 3602:  * when we are sure the node is not already in the set.
 3603:  */
 3604: void
 3605: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
 3606:     if ((cur == NULL) || (val == NULL)) return;
 3607: 
 3608: #if 0
 3609:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
 3610: 	return;	/* an XSLT fake node */
 3611: #endif
 3612: 
 3613:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3614:     /*
 3615:      * grow the nodeTab if needed
 3616:      */
 3617:     if (cur->nodeMax == 0) {
 3618:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3619: 					     sizeof(xmlNodePtr));
 3620: 	if (cur->nodeTab == NULL) {
 3621: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3622: 	    return;
 3623: 	}
 3624: 	memset(cur->nodeTab, 0 ,
 3625: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3626:         cur->nodeMax = XML_NODESET_DEFAULT;
 3627:     } else if (cur->nodeNr == cur->nodeMax) {
 3628:         xmlNodePtr *temp;
 3629: 
 3630:         cur->nodeMax *= 2;
 3631: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
 3632: 				      sizeof(xmlNodePtr));
 3633: 	if (temp == NULL) {
 3634: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3635: 	    return;
 3636: 	}
 3637: 	cur->nodeTab = temp;
 3638:     }
 3639:     if (val->type == XML_NAMESPACE_DECL) {
 3640: 	xmlNsPtr ns = (xmlNsPtr) val;
 3641: 
 3642: 	cur->nodeTab[cur->nodeNr++] =
 3643: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3644:     } else
 3645: 	cur->nodeTab[cur->nodeNr++] = val;
 3646: }
 3647: 
 3648: /**
 3649:  * xmlXPathNodeSetMerge:
 3650:  * @val1:  the first NodeSet or NULL
 3651:  * @val2:  the second NodeSet
 3652:  *
 3653:  * Merges two nodesets, all nodes from @val2 are added to @val1
 3654:  * if @val1 is NULL, a new set is created and copied from @val2
 3655:  *
 3656:  * Returns @val1 once extended or NULL in case of error.
 3657:  */
 3658: xmlNodeSetPtr
 3659: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
 3660:     int i, j, initNr, skip;
 3661:     xmlNodePtr n1, n2;
 3662: 
 3663:     if (val2 == NULL) return(val1);
 3664:     if (val1 == NULL) {
 3665: 	val1 = xmlXPathNodeSetCreate(NULL);
 3666:     if (val1 == NULL)
 3667:         return (NULL);
 3668: #if 0
 3669: 	/*
 3670: 	* TODO: The optimization won't work in every case, since
 3671: 	*  those nasty namespace nodes need to be added with
 3672: 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
 3673: 	*  memcpy is not possible.
 3674: 	*  If there was a flag on the nodesetval, indicating that
 3675: 	*  some temporary nodes are in, that would be helpfull.
 3676: 	*/
 3677: 	/*
 3678: 	* Optimization: Create an equally sized node-set
 3679: 	* and memcpy the content.
 3680: 	*/
 3681: 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
 3682: 	if (val1 == NULL)
 3683: 	    return(NULL);
 3684: 	if (val2->nodeNr != 0) {
 3685: 	    if (val2->nodeNr == 1)
 3686: 		*(val1->nodeTab) = *(val2->nodeTab);
 3687: 	    else {
 3688: 		memcpy(val1->nodeTab, val2->nodeTab,
 3689: 		    val2->nodeNr * sizeof(xmlNodePtr));
 3690: 	    }
 3691: 	    val1->nodeNr = val2->nodeNr;
 3692: 	}
 3693: 	return(val1);
 3694: #endif
 3695:     }
 3696: 
 3697:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3698:     initNr = val1->nodeNr;
 3699: 
 3700:     for (i = 0;i < val2->nodeNr;i++) {
 3701: 	n2 = val2->nodeTab[i];
 3702: 	/*
 3703: 	 * check against duplicates
 3704: 	 */
 3705: 	skip = 0;
 3706: 	for (j = 0; j < initNr; j++) {
 3707: 	    n1 = val1->nodeTab[j];
 3708: 	    if (n1 == n2) {
 3709: 		skip = 1;
 3710: 		break;
 3711: 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
 3712: 		       (n2->type == XML_NAMESPACE_DECL)) {
 3713: 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3714: 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3715: 			((xmlNsPtr) n2)->prefix)))
 3716: 		{
 3717: 		    skip = 1;
 3718: 		    break;
 3719: 		}
 3720: 	    }
 3721: 	}
 3722: 	if (skip)
 3723: 	    continue;
 3724: 
 3725: 	/*
 3726: 	 * grow the nodeTab if needed
 3727: 	 */
 3728: 	if (val1->nodeMax == 0) {
 3729: 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3730: 						    sizeof(xmlNodePtr));
 3731: 	    if (val1->nodeTab == NULL) {
 3732: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3733: 		return(NULL);
 3734: 	    }
 3735: 	    memset(val1->nodeTab, 0 ,
 3736: 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3737: 	    val1->nodeMax = XML_NODESET_DEFAULT;
 3738: 	} else if (val1->nodeNr == val1->nodeMax) {
 3739: 	    xmlNodePtr *temp;
 3740: 
 3741: 	    val1->nodeMax *= 2;
 3742: 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
 3743: 					     sizeof(xmlNodePtr));
 3744: 	    if (temp == NULL) {
 3745: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3746: 		return(NULL);
 3747: 	    }
 3748: 	    val1->nodeTab = temp;
 3749: 	}
 3750: 	if (n2->type == XML_NAMESPACE_DECL) {
 3751: 	    xmlNsPtr ns = (xmlNsPtr) n2;
 3752: 
 3753: 	    val1->nodeTab[val1->nodeNr++] =
 3754: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3755: 	} else
 3756: 	    val1->nodeTab[val1->nodeNr++] = n2;
 3757:     }
 3758: 
 3759:     return(val1);
 3760: }
 3761: 
 3762: #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
 3763: /**
 3764:  * xmlXPathNodeSetMergeUnique:
 3765:  * @val1:  the first NodeSet or NULL
 3766:  * @val2:  the second NodeSet
 3767:  *
 3768:  * Merges two nodesets, all nodes from @val2 are added to @val1
 3769:  * if @val1 is NULL, a new set is created and copied from @val2
 3770:  *
 3771:  * Returns @val1 once extended or NULL in case of error.
 3772:  */
 3773: static xmlNodeSetPtr
 3774: xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
 3775:     int i;
 3776: 
 3777:     if (val2 == NULL) return(val1);
 3778:     if (val1 == NULL) {
 3779: 	val1 = xmlXPathNodeSetCreate(NULL);
 3780:     }
 3781:     if (val1 == NULL)
 3782:         return (NULL);
 3783: 
 3784:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3785: 
 3786:     for (i = 0;i < val2->nodeNr;i++) {
 3787: 	/*
 3788: 	 * grow the nodeTab if needed
 3789: 	 */
 3790: 	if (val1->nodeMax == 0) {
 3791: 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3792: 						    sizeof(xmlNodePtr));
 3793: 	    if (val1->nodeTab == NULL) {
 3794: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3795: 		return(NULL);
 3796: 	    }
 3797: 	    memset(val1->nodeTab, 0 ,
 3798: 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3799: 	    val1->nodeMax = XML_NODESET_DEFAULT;
 3800: 	} else if (val1->nodeNr == val1->nodeMax) {
 3801: 	    xmlNodePtr *temp;
 3802: 
 3803: 	    val1->nodeMax *= 2;
 3804: 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
 3805: 					     sizeof(xmlNodePtr));
 3806: 	    if (temp == NULL) {
 3807: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3808: 		return(NULL);
 3809: 	    }
 3810: 	    val1->nodeTab = temp;
 3811: 	}
 3812: 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 3813: 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
 3814: 
 3815: 	    val1->nodeTab[val1->nodeNr++] =
 3816: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3817: 	} else
 3818: 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
 3819:     }
 3820: 
 3821:     return(val1);
 3822: }
 3823: #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
 3824: 
 3825: /**
 3826:  * xmlXPathNodeSetMergeAndClear:
 3827:  * @set1:  the first NodeSet or NULL
 3828:  * @set2:  the second NodeSet
 3829:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 3830:  *
 3831:  * Merges two nodesets, all nodes from @set2 are added to @set1
 3832:  * if @set1 is NULL, a new set is created and copied from @set2.
 3833:  * Checks for duplicate nodes. Clears set2.
 3834:  *
 3835:  * Returns @set1 once extended or NULL in case of error.
 3836:  */
 3837: static xmlNodeSetPtr
 3838: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 3839: 			     int hasNullEntries)
 3840: {
 3841:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 3842: 	/*
 3843: 	* Note that doing a memcpy of the list, namespace nodes are
 3844: 	* just assigned to set1, since set2 is cleared anyway.
 3845: 	*/
 3846: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 3847: 	if (set1 == NULL)
 3848: 	    return(NULL);
 3849: 	if (set2->nodeNr != 0) {
 3850: 	    memcpy(set1->nodeTab, set2->nodeTab,
 3851: 		set2->nodeNr * sizeof(xmlNodePtr));
 3852: 	    set1->nodeNr = set2->nodeNr;
 3853: 	}
 3854:     } else {
 3855: 	int i, j, initNbSet1;
 3856: 	xmlNodePtr n1, n2;
 3857: 
 3858: 	if (set1 == NULL)
 3859:             set1 = xmlXPathNodeSetCreate(NULL);
 3860:         if (set1 == NULL)
 3861:             return (NULL);
 3862: 
 3863: 	initNbSet1 = set1->nodeNr;
 3864: 	for (i = 0;i < set2->nodeNr;i++) {
 3865: 	    n2 = set2->nodeTab[i];
 3866: 	    /*
 3867: 	    * Skip NULLed entries.
 3868: 	    */
 3869: 	    if (n2 == NULL)
 3870: 		continue;
 3871: 	    /*
 3872: 	    * Skip duplicates.
 3873: 	    */
 3874: 	    for (j = 0; j < initNbSet1; j++) {
 3875: 		n1 = set1->nodeTab[j];
 3876: 		if (n1 == n2) {
 3877: 		    goto skip_node;
 3878: 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
 3879: 		    (n2->type == XML_NAMESPACE_DECL))
 3880: 		{
 3881: 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3882: 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3883: 			((xmlNsPtr) n2)->prefix)))
 3884: 		    {
 3885: 			/*
 3886: 			* Free the namespace node.
 3887: 			*/
 3888: 			set2->nodeTab[i] = NULL;
 3889: 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
 3890: 			goto skip_node;
 3891: 		    }
 3892: 		}
 3893: 	    }
 3894: 	    /*
 3895: 	    * grow the nodeTab if needed
 3896: 	    */
 3897: 	    if (set1->nodeMax == 0) {
 3898: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 3899: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 3900: 		if (set1->nodeTab == NULL) {
 3901: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3902: 		    return(NULL);
 3903: 		}
 3904: 		memset(set1->nodeTab, 0,
 3905: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3906: 		set1->nodeMax = XML_NODESET_DEFAULT;
 3907: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 3908: 		xmlNodePtr *temp;
 3909: 
 3910: 		set1->nodeMax *= 2;
 3911: 		temp = (xmlNodePtr *) xmlRealloc(
 3912: 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
 3913: 		if (temp == NULL) {
 3914: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3915: 		    return(NULL);
 3916: 		}
 3917: 		set1->nodeTab = temp;
 3918: 	    }
 3919: 	    if (n2->type == XML_NAMESPACE_DECL) {
 3920: 		xmlNsPtr ns = (xmlNsPtr) n2;
 3921: 
 3922: 		set1->nodeTab[set1->nodeNr++] =
 3923: 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3924: 	    } else
 3925: 		set1->nodeTab[set1->nodeNr++] = n2;
 3926: skip_node:
 3927: 	    {}
 3928: 	}
 3929:     }
 3930:     set2->nodeNr = 0;
 3931:     return(set1);
 3932: }
 3933: 
 3934: /**
 3935:  * xmlXPathNodeSetMergeAndClearNoDupls:
 3936:  * @set1:  the first NodeSet or NULL
 3937:  * @set2:  the second NodeSet
 3938:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 3939:  *
 3940:  * Merges two nodesets, all nodes from @set2 are added to @set1
 3941:  * if @set1 is NULL, a new set is created and copied from @set2.
 3942:  * Doesn't chack for duplicate nodes. Clears set2.
 3943:  *
 3944:  * Returns @set1 once extended or NULL in case of error.
 3945:  */
 3946: static xmlNodeSetPtr
 3947: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 3948: 				    int hasNullEntries)
 3949: {
 3950:     if (set2 == NULL)
 3951: 	return(set1);
 3952:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 3953: 	/*
 3954: 	* Note that doing a memcpy of the list, namespace nodes are
 3955: 	* just assigned to set1, since set2 is cleared anyway.
 3956: 	*/
 3957: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 3958: 	if (set1 == NULL)
 3959: 	    return(NULL);
 3960: 	if (set2->nodeNr != 0) {
 3961: 	    memcpy(set1->nodeTab, set2->nodeTab,
 3962: 		set2->nodeNr * sizeof(xmlNodePtr));
 3963: 	    set1->nodeNr = set2->nodeNr;
 3964: 	}
 3965:     } else {
 3966: 	int i;
 3967: 	xmlNodePtr n2;
 3968: 
 3969: 	if (set1 == NULL)
 3970: 	    set1 = xmlXPathNodeSetCreate(NULL);
 3971:         if (set1 == NULL)
 3972:             return (NULL);
 3973: 
 3974: 	for (i = 0;i < set2->nodeNr;i++) {
 3975: 	    n2 = set2->nodeTab[i];
 3976: 	    /*
 3977: 	    * Skip NULLed entries.
 3978: 	    */
 3979: 	    if (n2 == NULL)
 3980: 		continue;
 3981: 	    if (set1->nodeMax == 0) {
 3982: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 3983: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 3984: 		if (set1->nodeTab == NULL) {
 3985: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3986: 		    return(NULL);
 3987: 		}
 3988: 		memset(set1->nodeTab, 0,
 3989: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3990: 		set1->nodeMax = XML_NODESET_DEFAULT;
 3991: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 3992: 		xmlNodePtr *temp;
 3993: 
 3994: 		set1->nodeMax *= 2;
 3995: 		temp = (xmlNodePtr *) xmlRealloc(
 3996: 		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
 3997: 		if (temp == NULL) {
 3998: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3999: 		    return(NULL);
 4000: 		}
 4001: 		set1->nodeTab = temp;
 4002: 	    }
 4003: 	    set1->nodeTab[set1->nodeNr++] = n2;
 4004: 	}
 4005:     }
 4006:     set2->nodeNr = 0;
 4007:     return(set1);
 4008: }
 4009: 
 4010: /**
 4011:  * xmlXPathNodeSetDel:
 4012:  * @cur:  the initial node set
 4013:  * @val:  an xmlNodePtr
 4014:  *
 4015:  * Removes an xmlNodePtr from an existing NodeSet
 4016:  */
 4017: void
 4018: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
 4019:     int i;
 4020: 
 4021:     if (cur == NULL) return;
 4022:     if (val == NULL) return;
 4023: 
 4024:     /*
 4025:      * find node in nodeTab
 4026:      */
 4027:     for (i = 0;i < cur->nodeNr;i++)
 4028:         if (cur->nodeTab[i] == val) break;
 4029: 
 4030:     if (i >= cur->nodeNr) {	/* not found */
 4031: #ifdef DEBUG
 4032:         xmlGenericError(xmlGenericErrorContext,
 4033: 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
 4034: 		val->name);
 4035: #endif
 4036:         return;
 4037:     }
 4038:     if ((cur->nodeTab[i] != NULL) &&
 4039: 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4040: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
 4041:     cur->nodeNr--;
 4042:     for (;i < cur->nodeNr;i++)
 4043:         cur->nodeTab[i] = cur->nodeTab[i + 1];
 4044:     cur->nodeTab[cur->nodeNr] = NULL;
 4045: }
 4046: 
 4047: /**
 4048:  * xmlXPathNodeSetRemove:
 4049:  * @cur:  the initial node set
 4050:  * @val:  the index to remove
 4051:  *
 4052:  * Removes an entry from an existing NodeSet list.
 4053:  */
 4054: void
 4055: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
 4056:     if (cur == NULL) return;
 4057:     if (val >= cur->nodeNr) return;
 4058:     if ((cur->nodeTab[val] != NULL) &&
 4059: 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
 4060: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
 4061:     cur->nodeNr--;
 4062:     for (;val < cur->nodeNr;val++)
 4063:         cur->nodeTab[val] = cur->nodeTab[val + 1];
 4064:     cur->nodeTab[cur->nodeNr] = NULL;
 4065: }
 4066: 
 4067: /**
 4068:  * xmlXPathFreeNodeSet:
 4069:  * @obj:  the xmlNodeSetPtr to free
 4070:  *
 4071:  * Free the NodeSet compound (not the actual nodes !).
 4072:  */
 4073: void
 4074: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
 4075:     if (obj == NULL) return;
 4076:     if (obj->nodeTab != NULL) {
 4077: 	int i;
 4078: 
 4079: 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4080: 	for (i = 0;i < obj->nodeNr;i++)
 4081: 	    if ((obj->nodeTab[i] != NULL) &&
 4082: 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4083: 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4084: 	xmlFree(obj->nodeTab);
 4085:     }
 4086:     xmlFree(obj);
 4087: }
 4088: 
 4089: /**
 4090:  * xmlXPathNodeSetClear:
 4091:  * @set:  the node set to clear
 4092:  *
 4093:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
 4094:  * are feed), but does *not* free the list itself. Sets the length of the
 4095:  * list to 0.
 4096:  */
 4097: static void
 4098: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
 4099: {
 4100:     if ((set == NULL) || (set->nodeNr <= 0))
 4101: 	return;
 4102:     else if (hasNsNodes) {
 4103: 	int i;
 4104: 	xmlNodePtr node;
 4105: 
 4106: 	for (i = 0; i < set->nodeNr; i++) {
 4107: 	    node = set->nodeTab[i];
 4108: 	    if ((node != NULL) &&
 4109: 		(node->type == XML_NAMESPACE_DECL))
 4110: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4111: 	}
 4112:     }
 4113:     set->nodeNr = 0;
 4114: }
 4115: 
 4116: /**
 4117:  * xmlXPathNodeSetClearFromPos:
 4118:  * @set: the node set to be cleared
 4119:  * @pos: the start position to clear from
 4120:  *
 4121:  * Clears the list from temporary XPath objects (e.g. namespace nodes
 4122:  * are feed) starting with the entry at @pos, but does *not* free the list
 4123:  * itself. Sets the length of the list to @pos.
 4124:  */
 4125: static void
 4126: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
 4127: {
 4128:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
 4129: 	return;
 4130:     else if ((hasNsNodes)) {
 4131: 	int i;
 4132: 	xmlNodePtr node;
 4133: 
 4134: 	for (i = pos; i < set->nodeNr; i++) {
 4135: 	    node = set->nodeTab[i];
 4136: 	    if ((node != NULL) &&
 4137: 		(node->type == XML_NAMESPACE_DECL))
 4138: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4139: 	}
 4140:     }
 4141:     set->nodeNr = pos;
 4142: }
 4143: 
 4144: /**
 4145:  * xmlXPathFreeValueTree:
 4146:  * @obj:  the xmlNodeSetPtr to free
 4147:  *
 4148:  * Free the NodeSet compound and the actual tree, this is different
 4149:  * from xmlXPathFreeNodeSet()
 4150:  */
 4151: static void
 4152: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
 4153:     int i;
 4154: 
 4155:     if (obj == NULL) return;
 4156: 
 4157:     if (obj->nodeTab != NULL) {
 4158: 	for (i = 0;i < obj->nodeNr;i++) {
 4159: 	    if (obj->nodeTab[i] != NULL) {
 4160: 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 4161: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4162: 		} else {
 4163: 		    xmlFreeNodeList(obj->nodeTab[i]);
 4164: 		}
 4165: 	    }
 4166: 	}
 4167: 	xmlFree(obj->nodeTab);
 4168:     }
 4169:     xmlFree(obj);
 4170: }
 4171: 
 4172: #if defined(DEBUG) || defined(DEBUG_STEP)
 4173: /**
 4174:  * xmlGenericErrorContextNodeSet:
 4175:  * @output:  a FILE * for the output
 4176:  * @obj:  the xmlNodeSetPtr to display
 4177:  *
 4178:  * Quick display of a NodeSet
 4179:  */
 4180: void
 4181: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
 4182:     int i;
 4183: 
 4184:     if (output == NULL) output = xmlGenericErrorContext;
 4185:     if (obj == NULL)  {
 4186:         fprintf(output, "NodeSet == NULL !\n");
 4187: 	return;
 4188:     }
 4189:     if (obj->nodeNr == 0) {
 4190:         fprintf(output, "NodeSet is empty\n");
 4191: 	return;
 4192:     }
 4193:     if (obj->nodeTab == NULL) {
 4194: 	fprintf(output, " nodeTab == NULL !\n");
 4195: 	return;
 4196:     }
 4197:     for (i = 0; i < obj->nodeNr; i++) {
 4198:         if (obj->nodeTab[i] == NULL) {
 4199: 	    fprintf(output, " NULL !\n");
 4200: 	    return;
 4201:         }
 4202: 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
 4203: 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
 4204: 	    fprintf(output, " /");
 4205: 	else if (obj->nodeTab[i]->name == NULL)
 4206: 	    fprintf(output, " noname!");
 4207: 	else fprintf(output, " %s", obj->nodeTab[i]->name);
 4208:     }
 4209:     fprintf(output, "\n");
 4210: }
 4211: #endif
 4212: 
 4213: /**
 4214:  * xmlXPathNewNodeSet:
 4215:  * @val:  the NodePtr value
 4216:  *
 4217:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4218:  * it with the single Node @val
 4219:  *
 4220:  * Returns the newly created object.
 4221:  */
 4222: xmlXPathObjectPtr
 4223: xmlXPathNewNodeSet(xmlNodePtr val) {
 4224:     xmlXPathObjectPtr ret;
 4225: 
 4226:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4227:     if (ret == NULL) {
 4228:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 4229: 	return(NULL);
 4230:     }
 4231:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4232:     ret->type = XPATH_NODESET;
 4233:     ret->boolval = 0;
 4234:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4235:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4236: #ifdef XP_DEBUG_OBJ_USAGE
 4237:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4238: #endif
 4239:     return(ret);
 4240: }
 4241: 
 4242: /**
 4243:  * xmlXPathNewValueTree:
 4244:  * @val:  the NodePtr value
 4245:  *
 4246:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
 4247:  * it with the tree root @val
 4248:  *
 4249:  * Returns the newly created object.
 4250:  */
 4251: xmlXPathObjectPtr
 4252: xmlXPathNewValueTree(xmlNodePtr val) {
 4253:     xmlXPathObjectPtr ret;
 4254: 
 4255:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4256:     if (ret == NULL) {
 4257:         xmlXPathErrMemory(NULL, "creating result value tree\n");
 4258: 	return(NULL);
 4259:     }
 4260:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4261:     ret->type = XPATH_XSLT_TREE;
 4262:     ret->boolval = 1;
 4263:     ret->user = (void *) val;
 4264:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4265: #ifdef XP_DEBUG_OBJ_USAGE
 4266:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
 4267: #endif
 4268:     return(ret);
 4269: }
 4270: 
 4271: /**
 4272:  * xmlXPathNewNodeSetList:
 4273:  * @val:  an existing NodeSet
 4274:  *
 4275:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4276:  * it with the Nodeset @val
 4277:  *
 4278:  * Returns the newly created object.
 4279:  */
 4280: xmlXPathObjectPtr
 4281: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
 4282: {
 4283:     xmlXPathObjectPtr ret;
 4284:     int i;
 4285: 
 4286:     if (val == NULL)
 4287:         ret = NULL;
 4288:     else if (val->nodeTab == NULL)
 4289:         ret = xmlXPathNewNodeSet(NULL);
 4290:     else {
 4291:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
 4292:         if (ret)
 4293:             for (i = 1; i < val->nodeNr; ++i)
 4294:                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
 4295:     }
 4296: 
 4297:     return (ret);
 4298: }
 4299: 
 4300: /**
 4301:  * xmlXPathWrapNodeSet:
 4302:  * @val:  the NodePtr value
 4303:  *
 4304:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 4305:  *
 4306:  * Returns the newly created object.
 4307:  */
 4308: xmlXPathObjectPtr
 4309: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
 4310:     xmlXPathObjectPtr ret;
 4311: 
 4312:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4313:     if (ret == NULL) {
 4314:         xmlXPathErrMemory(NULL, "creating node set object\n");
 4315: 	return(NULL);
 4316:     }
 4317:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4318:     ret->type = XPATH_NODESET;
 4319:     ret->nodesetval = val;
 4320: #ifdef XP_DEBUG_OBJ_USAGE
 4321:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4322: #endif
 4323:     return(ret);
 4324: }
 4325: 
 4326: /**
 4327:  * xmlXPathFreeNodeSetList:
 4328:  * @obj:  an existing NodeSetList object
 4329:  *
 4330:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
 4331:  * the list contrary to xmlXPathFreeObject().
 4332:  */
 4333: void
 4334: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
 4335:     if (obj == NULL) return;
 4336: #ifdef XP_DEBUG_OBJ_USAGE
 4337:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 4338: #endif
 4339:     xmlFree(obj);
 4340: }
 4341: 
 4342: /**
 4343:  * xmlXPathDifference:
 4344:  * @nodes1:  a node-set
 4345:  * @nodes2:  a node-set
 4346:  *
 4347:  * Implements the EXSLT - Sets difference() function:
 4348:  *    node-set set:difference (node-set, node-set)
 4349:  *
 4350:  * Returns the difference between the two node sets, or nodes1 if
 4351:  *         nodes2 is empty
 4352:  */
 4353: xmlNodeSetPtr
 4354: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4355:     xmlNodeSetPtr ret;
 4356:     int i, l1;
 4357:     xmlNodePtr cur;
 4358: 
 4359:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4360: 	return(nodes1);
 4361: 
 4362:     ret = xmlXPathNodeSetCreate(NULL);
 4363:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4364: 	return(ret);
 4365: 
 4366:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4367: 
 4368:     for (i = 0; i < l1; i++) {
 4369: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4370: 	if (!xmlXPathNodeSetContains(nodes2, cur))
 4371: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4372:     }
 4373:     return(ret);
 4374: }
 4375: 
 4376: /**
 4377:  * xmlXPathIntersection:
 4378:  * @nodes1:  a node-set
 4379:  * @nodes2:  a node-set
 4380:  *
 4381:  * Implements the EXSLT - Sets intersection() function:
 4382:  *    node-set set:intersection (node-set, node-set)
 4383:  *
 4384:  * Returns a node set comprising the nodes that are within both the
 4385:  *         node sets passed as arguments
 4386:  */
 4387: xmlNodeSetPtr
 4388: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4389:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
 4390:     int i, l1;
 4391:     xmlNodePtr cur;
 4392: 
 4393:     if (ret == NULL)
 4394:         return(ret);
 4395:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4396: 	return(ret);
 4397:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4398: 	return(ret);
 4399: 
 4400:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4401: 
 4402:     for (i = 0; i < l1; i++) {
 4403: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4404: 	if (xmlXPathNodeSetContains(nodes2, cur))
 4405: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4406:     }
 4407:     return(ret);
 4408: }
 4409: 
 4410: /**
 4411:  * xmlXPathDistinctSorted:
 4412:  * @nodes:  a node-set, sorted by document order
 4413:  *
 4414:  * Implements the EXSLT - Sets distinct() function:
 4415:  *    node-set set:distinct (node-set)
 4416:  *
 4417:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4418:  *         it is empty
 4419:  */
 4420: xmlNodeSetPtr
 4421: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
 4422:     xmlNodeSetPtr ret;
 4423:     xmlHashTablePtr hash;
 4424:     int i, l;
 4425:     xmlChar * strval;
 4426:     xmlNodePtr cur;
 4427: 
 4428:     if (xmlXPathNodeSetIsEmpty(nodes))
 4429: 	return(nodes);
 4430: 
 4431:     ret = xmlXPathNodeSetCreate(NULL);
 4432:     if (ret == NULL)
 4433:         return(ret);
 4434:     l = xmlXPathNodeSetGetLength(nodes);
 4435:     hash = xmlHashCreate (l);
 4436:     for (i = 0; i < l; i++) {
 4437: 	cur = xmlXPathNodeSetItem(nodes, i);
 4438: 	strval = xmlXPathCastNodeToString(cur);
 4439: 	if (xmlHashLookup(hash, strval) == NULL) {
 4440: 	    xmlHashAddEntry(hash, strval, strval);
 4441: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4442: 	} else {
 4443: 	    xmlFree(strval);
 4444: 	}
 4445:     }
 4446:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
 4447:     return(ret);
 4448: }
 4449: 
 4450: /**
 4451:  * xmlXPathDistinct:
 4452:  * @nodes:  a node-set
 4453:  *
 4454:  * Implements the EXSLT - Sets distinct() function:
 4455:  *    node-set set:distinct (node-set)
 4456:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
 4457:  * is called with the sorted node-set
 4458:  *
 4459:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4460:  *         it is empty
 4461:  */
 4462: xmlNodeSetPtr
 4463: xmlXPathDistinct (xmlNodeSetPtr nodes) {
 4464:     if (xmlXPathNodeSetIsEmpty(nodes))
 4465: 	return(nodes);
 4466: 
 4467:     xmlXPathNodeSetSort(nodes);
 4468:     return(xmlXPathDistinctSorted(nodes));
 4469: }
 4470: 
 4471: /**
 4472:  * xmlXPathHasSameNodes:
 4473:  * @nodes1:  a node-set
 4474:  * @nodes2:  a node-set
 4475:  *
 4476:  * Implements the EXSLT - Sets has-same-nodes function:
 4477:  *    boolean set:has-same-node(node-set, node-set)
 4478:  *
 4479:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
 4480:  *         otherwise
 4481:  */
 4482: int
 4483: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4484:     int i, l;
 4485:     xmlNodePtr cur;
 4486: 
 4487:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
 4488: 	xmlXPathNodeSetIsEmpty(nodes2))
 4489: 	return(0);
 4490: 
 4491:     l = xmlXPathNodeSetGetLength(nodes1);
 4492:     for (i = 0; i < l; i++) {
 4493: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4494: 	if (xmlXPathNodeSetContains(nodes2, cur))
 4495: 	    return(1);
 4496:     }
 4497:     return(0);
 4498: }
 4499: 
 4500: /**
 4501:  * xmlXPathNodeLeadingSorted:
 4502:  * @nodes: a node-set, sorted by document order
 4503:  * @node: a node
 4504:  *
 4505:  * Implements the EXSLT - Sets leading() function:
 4506:  *    node-set set:leading (node-set, node-set)
 4507:  *
 4508:  * Returns the nodes in @nodes that precede @node in document order,
 4509:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4510:  *         doesn't contain @node
 4511:  */
 4512: xmlNodeSetPtr
 4513: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4514:     int i, l;
 4515:     xmlNodePtr cur;
 4516:     xmlNodeSetPtr ret;
 4517: 
 4518:     if (node == NULL)
 4519: 	return(nodes);
 4520: 
 4521:     ret = xmlXPathNodeSetCreate(NULL);
 4522:     if (ret == NULL)
 4523:         return(ret);
 4524:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4525: 	(!xmlXPathNodeSetContains(nodes, node)))
 4526: 	return(ret);
 4527: 
 4528:     l = xmlXPathNodeSetGetLength(nodes);
 4529:     for (i = 0; i < l; i++) {
 4530: 	cur = xmlXPathNodeSetItem(nodes, i);
 4531: 	if (cur == node)
 4532: 	    break;
 4533: 	xmlXPathNodeSetAddUnique(ret, cur);
 4534:     }
 4535:     return(ret);
 4536: }
 4537: 
 4538: /**
 4539:  * xmlXPathNodeLeading:
 4540:  * @nodes:  a node-set
 4541:  * @node:  a node
 4542:  *
 4543:  * Implements the EXSLT - Sets leading() function:
 4544:  *    node-set set:leading (node-set, node-set)
 4545:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
 4546:  * is called.
 4547:  *
 4548:  * Returns the nodes in @nodes that precede @node in document order,
 4549:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4550:  *         doesn't contain @node
 4551:  */
 4552: xmlNodeSetPtr
 4553: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4554:     xmlXPathNodeSetSort(nodes);
 4555:     return(xmlXPathNodeLeadingSorted(nodes, node));
 4556: }
 4557: 
 4558: /**
 4559:  * xmlXPathLeadingSorted:
 4560:  * @nodes1:  a node-set, sorted by document order
 4561:  * @nodes2:  a node-set, sorted by document order
 4562:  *
 4563:  * Implements the EXSLT - Sets leading() function:
 4564:  *    node-set set:leading (node-set, node-set)
 4565:  *
 4566:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4567:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4568:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4569:  */
 4570: xmlNodeSetPtr
 4571: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4572:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4573: 	return(nodes1);
 4574:     return(xmlXPathNodeLeadingSorted(nodes1,
 4575: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4576: }
 4577: 
 4578: /**
 4579:  * xmlXPathLeading:
 4580:  * @nodes1:  a node-set
 4581:  * @nodes2:  a node-set
 4582:  *
 4583:  * Implements the EXSLT - Sets leading() function:
 4584:  *    node-set set:leading (node-set, node-set)
 4585:  * @nodes1 and @nodes2 are sorted by document order, then
 4586:  * #exslSetsLeadingSorted is called.
 4587:  *
 4588:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4589:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4590:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4591:  */
 4592: xmlNodeSetPtr
 4593: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4594:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4595: 	return(nodes1);
 4596:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4597: 	return(xmlXPathNodeSetCreate(NULL));
 4598:     xmlXPathNodeSetSort(nodes1);
 4599:     xmlXPathNodeSetSort(nodes2);
 4600:     return(xmlXPathNodeLeadingSorted(nodes1,
 4601: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4602: }
 4603: 
 4604: /**
 4605:  * xmlXPathNodeTrailingSorted:
 4606:  * @nodes: a node-set, sorted by document order
 4607:  * @node: a node
 4608:  *
 4609:  * Implements the EXSLT - Sets trailing() function:
 4610:  *    node-set set:trailing (node-set, node-set)
 4611:  *
 4612:  * Returns the nodes in @nodes that follow @node in document order,
 4613:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4614:  *         doesn't contain @node
 4615:  */
 4616: xmlNodeSetPtr
 4617: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4618:     int i, l;
 4619:     xmlNodePtr cur;
 4620:     xmlNodeSetPtr ret;
 4621: 
 4622:     if (node == NULL)
 4623: 	return(nodes);
 4624: 
 4625:     ret = xmlXPathNodeSetCreate(NULL);
 4626:     if (ret == NULL)
 4627:         return(ret);
 4628:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4629: 	(!xmlXPathNodeSetContains(nodes, node)))
 4630: 	return(ret);
 4631: 
 4632:     l = xmlXPathNodeSetGetLength(nodes);
 4633:     for (i = l - 1; i >= 0; i--) {
 4634: 	cur = xmlXPathNodeSetItem(nodes, i);
 4635: 	if (cur == node)
 4636: 	    break;
 4637: 	xmlXPathNodeSetAddUnique(ret, cur);
 4638:     }
 4639:     xmlXPathNodeSetSort(ret);	/* bug 413451 */
 4640:     return(ret);
 4641: }
 4642: 
 4643: /**
 4644:  * xmlXPathNodeTrailing:
 4645:  * @nodes:  a node-set
 4646:  * @node:  a node
 4647:  *
 4648:  * Implements the EXSLT - Sets trailing() function:
 4649:  *    node-set set:trailing (node-set, node-set)
 4650:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
 4651:  * is called.
 4652:  *
 4653:  * Returns the nodes in @nodes that follow @node in document order,
 4654:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4655:  *         doesn't contain @node
 4656:  */
 4657: xmlNodeSetPtr
 4658: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4659:     xmlXPathNodeSetSort(nodes);
 4660:     return(xmlXPathNodeTrailingSorted(nodes, node));
 4661: }
 4662: 
 4663: /**
 4664:  * xmlXPathTrailingSorted:
 4665:  * @nodes1:  a node-set, sorted by document order
 4666:  * @nodes2:  a node-set, sorted by document order
 4667:  *
 4668:  * Implements the EXSLT - Sets trailing() function:
 4669:  *    node-set set:trailing (node-set, node-set)
 4670:  *
 4671:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4672:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4673:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4674:  */
 4675: xmlNodeSetPtr
 4676: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4677:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4678: 	return(nodes1);
 4679:     return(xmlXPathNodeTrailingSorted(nodes1,
 4680: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4681: }
 4682: 
 4683: /**
 4684:  * xmlXPathTrailing:
 4685:  * @nodes1:  a node-set
 4686:  * @nodes2:  a node-set
 4687:  *
 4688:  * Implements the EXSLT - Sets trailing() function:
 4689:  *    node-set set:trailing (node-set, node-set)
 4690:  * @nodes1 and @nodes2 are sorted by document order, then
 4691:  * #xmlXPathTrailingSorted is called.
 4692:  *
 4693:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4694:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4695:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4696:  */
 4697: xmlNodeSetPtr
 4698: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4699:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4700: 	return(nodes1);
 4701:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4702: 	return(xmlXPathNodeSetCreate(NULL));
 4703:     xmlXPathNodeSetSort(nodes1);
 4704:     xmlXPathNodeSetSort(nodes2);
 4705:     return(xmlXPathNodeTrailingSorted(nodes1,
 4706: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4707: }
 4708: 
 4709: /************************************************************************
 4710:  *									*
 4711:  *		Routines to handle extra functions			*
 4712:  *									*
 4713:  ************************************************************************/
 4714: 
 4715: /**
 4716:  * xmlXPathRegisterFunc:
 4717:  * @ctxt:  the XPath context
 4718:  * @name:  the function name
 4719:  * @f:  the function implementation or NULL
 4720:  *
 4721:  * Register a new function. If @f is NULL it unregisters the function
 4722:  *
 4723:  * Returns 0 in case of success, -1 in case of error
 4724:  */
 4725: int
 4726: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
 4727: 		     xmlXPathFunction f) {
 4728:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
 4729: }
 4730: 
 4731: /**
 4732:  * xmlXPathRegisterFuncNS:
 4733:  * @ctxt:  the XPath context
 4734:  * @name:  the function name
 4735:  * @ns_uri:  the function namespace URI
 4736:  * @f:  the function implementation or NULL
 4737:  *
 4738:  * Register a new function. If @f is NULL it unregisters the function
 4739:  *
 4740:  * Returns 0 in case of success, -1 in case of error
 4741:  */
 4742: int
 4743: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4744: 		       const xmlChar *ns_uri, xmlXPathFunction f) {
 4745:     if (ctxt == NULL)
 4746: 	return(-1);
 4747:     if (name == NULL)
 4748: 	return(-1);
 4749: 
 4750:     if (ctxt->funcHash == NULL)
 4751: 	ctxt->funcHash = xmlHashCreate(0);
 4752:     if (ctxt->funcHash == NULL)
 4753: 	return(-1);
 4754:     if (f == NULL)
 4755:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
 4756:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
 4757: }
 4758: 
 4759: /**
 4760:  * xmlXPathRegisterFuncLookup:
 4761:  * @ctxt:  the XPath context
 4762:  * @f:  the lookup function
 4763:  * @funcCtxt:  the lookup data
 4764:  *
 4765:  * Registers an external mechanism to do function lookup.
 4766:  */
 4767: void
 4768: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
 4769: 			    xmlXPathFuncLookupFunc f,
 4770: 			    void *funcCtxt) {
 4771:     if (ctxt == NULL)
 4772: 	return;
 4773:     ctxt->funcLookupFunc = f;
 4774:     ctxt->funcLookupData = funcCtxt;
 4775: }
 4776: 
 4777: /**
 4778:  * xmlXPathFunctionLookup:
 4779:  * @ctxt:  the XPath context
 4780:  * @name:  the function name
 4781:  *
 4782:  * Search in the Function array of the context for the given
 4783:  * function.
 4784:  *
 4785:  * Returns the xmlXPathFunction or NULL if not found
 4786:  */
 4787: xmlXPathFunction
 4788: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 4789:     if (ctxt == NULL)
 4790: 	return (NULL);
 4791: 
 4792:     if (ctxt->funcLookupFunc != NULL) {
 4793: 	xmlXPathFunction ret;
 4794: 	xmlXPathFuncLookupFunc f;
 4795: 
 4796: 	f = ctxt->funcLookupFunc;
 4797: 	ret = f(ctxt->funcLookupData, name, NULL);
 4798: 	if (ret != NULL)
 4799: 	    return(ret);
 4800:     }
 4801:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
 4802: }
 4803: 
 4804: /**
 4805:  * xmlXPathFunctionLookupNS:
 4806:  * @ctxt:  the XPath context
 4807:  * @name:  the function name
 4808:  * @ns_uri:  the function namespace URI
 4809:  *
 4810:  * Search in the Function array of the context for the given
 4811:  * function.
 4812:  *
 4813:  * Returns the xmlXPathFunction or NULL if not found
 4814:  */
 4815: xmlXPathFunction
 4816: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4817: 			 const xmlChar *ns_uri) {
 4818:     xmlXPathFunction ret;
 4819: 
 4820:     if (ctxt == NULL)
 4821: 	return(NULL);
 4822:     if (name == NULL)
 4823: 	return(NULL);
 4824: 
 4825:     if (ctxt->funcLookupFunc != NULL) {
 4826: 	xmlXPathFuncLookupFunc f;
 4827: 
 4828: 	f = ctxt->funcLookupFunc;
 4829: 	ret = f(ctxt->funcLookupData, name, ns_uri);
 4830: 	if (ret != NULL)
 4831: 	    return(ret);
 4832:     }
 4833: 
 4834:     if (ctxt->funcHash == NULL)
 4835: 	return(NULL);
 4836: 
 4837:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
 4838:     return(ret);
 4839: }
 4840: 
 4841: /**
 4842:  * xmlXPathRegisteredFuncsCleanup:
 4843:  * @ctxt:  the XPath context
 4844:  *
 4845:  * Cleanup the XPath context data associated to registered functions
 4846:  */
 4847: void
 4848: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
 4849:     if (ctxt == NULL)
 4850: 	return;
 4851: 
 4852:     xmlHashFree(ctxt->funcHash, NULL);
 4853:     ctxt->funcHash = NULL;
 4854: }
 4855: 
 4856: /************************************************************************
 4857:  *									*
 4858:  *			Routines to handle Variables			*
 4859:  *									*
 4860:  ************************************************************************/
 4861: 
 4862: /**
 4863:  * xmlXPathRegisterVariable:
 4864:  * @ctxt:  the XPath context
 4865:  * @name:  the variable name
 4866:  * @value:  the variable value or NULL
 4867:  *
 4868:  * Register a new variable value. If @value is NULL it unregisters
 4869:  * the variable
 4870:  *
 4871:  * Returns 0 in case of success, -1 in case of error
 4872:  */
 4873: int
 4874: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
 4875: 			 xmlXPathObjectPtr value) {
 4876:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
 4877: }
 4878: 
 4879: /**
 4880:  * xmlXPathRegisterVariableNS:
 4881:  * @ctxt:  the XPath context
 4882:  * @name:  the variable name
 4883:  * @ns_uri:  the variable namespace URI
 4884:  * @value:  the variable value or NULL
 4885:  *
 4886:  * Register a new variable value. If @value is NULL it unregisters
 4887:  * the variable
 4888:  *
 4889:  * Returns 0 in case of success, -1 in case of error
 4890:  */
 4891: int
 4892: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4893: 			   const xmlChar *ns_uri,
 4894: 			   xmlXPathObjectPtr value) {
 4895:     if (ctxt == NULL)
 4896: 	return(-1);
 4897:     if (name == NULL)
 4898: 	return(-1);
 4899: 
 4900:     if (ctxt->varHash == NULL)
 4901: 	ctxt->varHash = xmlHashCreate(0);
 4902:     if (ctxt->varHash == NULL)
 4903: 	return(-1);
 4904:     if (value == NULL)
 4905:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
 4906: 	                           (xmlHashDeallocator)xmlXPathFreeObject));
 4907:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
 4908: 			       (void *) value,
 4909: 			       (xmlHashDeallocator)xmlXPathFreeObject));
 4910: }
 4911: 
 4912: /**
 4913:  * xmlXPathRegisterVariableLookup:
 4914:  * @ctxt:  the XPath context
 4915:  * @f:  the lookup function
 4916:  * @data:  the lookup data
 4917:  *
 4918:  * register an external mechanism to do variable lookup
 4919:  */
 4920: void
 4921: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
 4922: 	 xmlXPathVariableLookupFunc f, void *data) {
 4923:     if (ctxt == NULL)
 4924: 	return;
 4925:     ctxt->varLookupFunc = f;
 4926:     ctxt->varLookupData = data;
 4927: }
 4928: 
 4929: /**
 4930:  * xmlXPathVariableLookup:
 4931:  * @ctxt:  the XPath context
 4932:  * @name:  the variable name
 4933:  *
 4934:  * Search in the Variable array of the context for the given
 4935:  * variable value.
 4936:  *
 4937:  * Returns a copy of the value or NULL if not found
 4938:  */
 4939: xmlXPathObjectPtr
 4940: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 4941:     if (ctxt == NULL)
 4942: 	return(NULL);
 4943: 
 4944:     if (ctxt->varLookupFunc != NULL) {
 4945: 	xmlXPathObjectPtr ret;
 4946: 
 4947: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 4948: 	        (ctxt->varLookupData, name, NULL);
 4949: 	return(ret);
 4950:     }
 4951:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
 4952: }
 4953: 
 4954: /**
 4955:  * xmlXPathVariableLookupNS:
 4956:  * @ctxt:  the XPath context
 4957:  * @name:  the variable name
 4958:  * @ns_uri:  the variable namespace URI
 4959:  *
 4960:  * Search in the Variable array of the context for the given
 4961:  * variable value.
 4962:  *
 4963:  * Returns the a copy of the value or NULL if not found
 4964:  */
 4965: xmlXPathObjectPtr
 4966: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4967: 			 const xmlChar *ns_uri) {
 4968:     if (ctxt == NULL)
 4969: 	return(NULL);
 4970: 
 4971:     if (ctxt->varLookupFunc != NULL) {
 4972: 	xmlXPathObjectPtr ret;
 4973: 
 4974: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 4975: 	        (ctxt->varLookupData, name, ns_uri);
 4976: 	if (ret != NULL) return(ret);
 4977:     }
 4978: 
 4979:     if (ctxt->varHash == NULL)
 4980: 	return(NULL);
 4981:     if (name == NULL)
 4982: 	return(NULL);
 4983: 
 4984:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
 4985: 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
 4986: }
 4987: 
 4988: /**
 4989:  * xmlXPathRegisteredVariablesCleanup:
 4990:  * @ctxt:  the XPath context
 4991:  *
 4992:  * Cleanup the XPath context data associated to registered variables
 4993:  */
 4994: void
 4995: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
 4996:     if (ctxt == NULL)
 4997: 	return;
 4998: 
 4999:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
 5000:     ctxt->varHash = NULL;
 5001: }
 5002: 
 5003: /**
 5004:  * xmlXPathRegisterNs:
 5005:  * @ctxt:  the XPath context
 5006:  * @prefix:  the namespace prefix cannot be NULL or empty string
 5007:  * @ns_uri:  the namespace name
 5008:  *
 5009:  * Register a new namespace. If @ns_uri is NULL it unregisters
 5010:  * the namespace
 5011:  *
 5012:  * Returns 0 in case of success, -1 in case of error
 5013:  */
 5014: int
 5015: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
 5016: 			   const xmlChar *ns_uri) {
 5017:     if (ctxt == NULL)
 5018: 	return(-1);
 5019:     if (prefix == NULL)
 5020: 	return(-1);
 5021:     if (prefix[0] == 0)
 5022: 	return(-1);
 5023: 
 5024:     if (ctxt->nsHash == NULL)
 5025: 	ctxt->nsHash = xmlHashCreate(10);
 5026:     if (ctxt->nsHash == NULL)
 5027: 	return(-1);
 5028:     if (ns_uri == NULL)
 5029:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
 5030: 	                          (xmlHashDeallocator)xmlFree));
 5031:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
 5032: 			      (xmlHashDeallocator)xmlFree));
 5033: }
 5034: 
 5035: /**
 5036:  * xmlXPathNsLookup:
 5037:  * @ctxt:  the XPath context
 5038:  * @prefix:  the namespace prefix value
 5039:  *
 5040:  * Search in the namespace declaration array of the context for the given
 5041:  * namespace name associated to the given prefix
 5042:  *
 5043:  * Returns the value or NULL if not found
 5044:  */
 5045: const xmlChar *
 5046: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
 5047:     if (ctxt == NULL)
 5048: 	return(NULL);
 5049:     if (prefix == NULL)
 5050: 	return(NULL);
 5051: 
 5052: #ifdef XML_XML_NAMESPACE
 5053:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
 5054: 	return(XML_XML_NAMESPACE);
 5055: #endif
 5056: 
 5057:     if (ctxt->namespaces != NULL) {
 5058: 	int i;
 5059: 
 5060: 	for (i = 0;i < ctxt->nsNr;i++) {
 5061: 	    if ((ctxt->namespaces[i] != NULL) &&
 5062: 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
 5063: 		return(ctxt->namespaces[i]->href);
 5064: 	}
 5065:     }
 5066: 
 5067:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
 5068: }
 5069: 
 5070: /**
 5071:  * xmlXPathRegisteredNsCleanup:
 5072:  * @ctxt:  the XPath context
 5073:  *
 5074:  * Cleanup the XPath context data associated to registered variables
 5075:  */
 5076: void
 5077: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
 5078:     if (ctxt == NULL)
 5079: 	return;
 5080: 
 5081:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
 5082:     ctxt->nsHash = NULL;
 5083: }
 5084: 
 5085: /************************************************************************
 5086:  *									*
 5087:  *			Routines to handle Values			*
 5088:  *									*
 5089:  ************************************************************************/
 5090: 
 5091: /* Allocations are terrible, one needs to optimize all this !!! */
 5092: 
 5093: /**
 5094:  * xmlXPathNewFloat:
 5095:  * @val:  the double value
 5096:  *
 5097:  * Create a new xmlXPathObjectPtr of type double and of value @val
 5098:  *
 5099:  * Returns the newly created object.
 5100:  */
 5101: xmlXPathObjectPtr
 5102: xmlXPathNewFloat(double val) {
 5103:     xmlXPathObjectPtr ret;
 5104: 
 5105:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5106:     if (ret == NULL) {
 5107:         xmlXPathErrMemory(NULL, "creating float object\n");
 5108: 	return(NULL);
 5109:     }
 5110:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5111:     ret->type = XPATH_NUMBER;
 5112:     ret->floatval = val;
 5113: #ifdef XP_DEBUG_OBJ_USAGE
 5114:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
 5115: #endif
 5116:     return(ret);
 5117: }
 5118: 
 5119: /**
 5120:  * xmlXPathNewBoolean:
 5121:  * @val:  the boolean value
 5122:  *
 5123:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
 5124:  *
 5125:  * Returns the newly created object.
 5126:  */
 5127: xmlXPathObjectPtr
 5128: xmlXPathNewBoolean(int val) {
 5129:     xmlXPathObjectPtr ret;
 5130: 
 5131:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5132:     if (ret == NULL) {
 5133:         xmlXPathErrMemory(NULL, "creating boolean object\n");
 5134: 	return(NULL);
 5135:     }
 5136:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5137:     ret->type = XPATH_BOOLEAN;
 5138:     ret->boolval = (val != 0);
 5139: #ifdef XP_DEBUG_OBJ_USAGE
 5140:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
 5141: #endif
 5142:     return(ret);
 5143: }
 5144: 
 5145: /**
 5146:  * xmlXPathNewString:
 5147:  * @val:  the xmlChar * value
 5148:  *
 5149:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5150:  *
 5151:  * Returns the newly created object.
 5152:  */
 5153: xmlXPathObjectPtr
 5154: xmlXPathNewString(const xmlChar *val) {
 5155:     xmlXPathObjectPtr ret;
 5156: 
 5157:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5158:     if (ret == NULL) {
 5159:         xmlXPathErrMemory(NULL, "creating string object\n");
 5160: 	return(NULL);
 5161:     }
 5162:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5163:     ret->type = XPATH_STRING;
 5164:     if (val != NULL)
 5165: 	ret->stringval = xmlStrdup(val);
 5166:     else
 5167: 	ret->stringval = xmlStrdup((const xmlChar *)"");
 5168: #ifdef XP_DEBUG_OBJ_USAGE
 5169:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5170: #endif
 5171:     return(ret);
 5172: }
 5173: 
 5174: /**
 5175:  * xmlXPathWrapString:
 5176:  * @val:  the xmlChar * value
 5177:  *
 5178:  * Wraps the @val string into an XPath object.
 5179:  *
 5180:  * Returns the newly created object.
 5181:  */
 5182: xmlXPathObjectPtr
 5183: xmlXPathWrapString (xmlChar *val) {
 5184:     xmlXPathObjectPtr ret;
 5185: 
 5186:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5187:     if (ret == NULL) {
 5188:         xmlXPathErrMemory(NULL, "creating string object\n");
 5189: 	return(NULL);
 5190:     }
 5191:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5192:     ret->type = XPATH_STRING;
 5193:     ret->stringval = val;
 5194: #ifdef XP_DEBUG_OBJ_USAGE
 5195:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5196: #endif
 5197:     return(ret);
 5198: }
 5199: 
 5200: /**
 5201:  * xmlXPathNewCString:
 5202:  * @val:  the char * value
 5203:  *
 5204:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5205:  *
 5206:  * Returns the newly created object.
 5207:  */
 5208: xmlXPathObjectPtr
 5209: xmlXPathNewCString(const char *val) {
 5210:     xmlXPathObjectPtr ret;
 5211: 
 5212:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5213:     if (ret == NULL) {
 5214:         xmlXPathErrMemory(NULL, "creating string object\n");
 5215: 	return(NULL);
 5216:     }
 5217:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5218:     ret->type = XPATH_STRING;
 5219:     ret->stringval = xmlStrdup(BAD_CAST val);
 5220: #ifdef XP_DEBUG_OBJ_USAGE
 5221:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5222: #endif
 5223:     return(ret);
 5224: }
 5225: 
 5226: /**
 5227:  * xmlXPathWrapCString:
 5228:  * @val:  the char * value
 5229:  *
 5230:  * Wraps a string into an XPath object.
 5231:  *
 5232:  * Returns the newly created object.
 5233:  */
 5234: xmlXPathObjectPtr
 5235: xmlXPathWrapCString (char * val) {
 5236:     return(xmlXPathWrapString((xmlChar *)(val)));
 5237: }
 5238: 
 5239: /**
 5240:  * xmlXPathWrapExternal:
 5241:  * @val:  the user data
 5242:  *
 5243:  * Wraps the @val data into an XPath object.
 5244:  *
 5245:  * Returns the newly created object.
 5246:  */
 5247: xmlXPathObjectPtr
 5248: xmlXPathWrapExternal (void *val) {
 5249:     xmlXPathObjectPtr ret;
 5250: 
 5251:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5252:     if (ret == NULL) {
 5253:         xmlXPathErrMemory(NULL, "creating user object\n");
 5254: 	return(NULL);
 5255:     }
 5256:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5257:     ret->type = XPATH_USERS;
 5258:     ret->user = val;
 5259: #ifdef XP_DEBUG_OBJ_USAGE
 5260:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
 5261: #endif
 5262:     return(ret);
 5263: }
 5264: 
 5265: /**
 5266:  * xmlXPathObjectCopy:
 5267:  * @val:  the original object
 5268:  *
 5269:  * allocate a new copy of a given object
 5270:  *
 5271:  * Returns the newly created object.
 5272:  */
 5273: xmlXPathObjectPtr
 5274: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
 5275:     xmlXPathObjectPtr ret;
 5276: 
 5277:     if (val == NULL)
 5278: 	return(NULL);
 5279: 
 5280:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5281:     if (ret == NULL) {
 5282:         xmlXPathErrMemory(NULL, "copying object\n");
 5283: 	return(NULL);
 5284:     }
 5285:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
 5286: #ifdef XP_DEBUG_OBJ_USAGE
 5287:     xmlXPathDebugObjUsageRequested(NULL, val->type);
 5288: #endif
 5289:     switch (val->type) {
 5290: 	case XPATH_BOOLEAN:
 5291: 	case XPATH_NUMBER:
 5292: 	case XPATH_POINT:
 5293: 	case XPATH_RANGE:
 5294: 	    break;
 5295: 	case XPATH_STRING:
 5296: 	    ret->stringval = xmlStrdup(val->stringval);
 5297: 	    break;
 5298: 	case XPATH_XSLT_TREE:
 5299: #if 0
 5300: /*
 5301:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
 5302:   this previous handling is no longer correct, and can cause some serious
 5303:   problems (ref. bug 145547)
 5304: */
 5305: 	    if ((val->nodesetval != NULL) &&
 5306: 		(val->nodesetval->nodeTab != NULL)) {
 5307: 		xmlNodePtr cur, tmp;
 5308: 		xmlDocPtr top;
 5309: 
 5310: 		ret->boolval = 1;
 5311: 		top =  xmlNewDoc(NULL);
 5312: 		top->name = (char *)
 5313: 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
 5314: 		ret->user = top;
 5315: 		if (top != NULL) {
 5316: 		    top->doc = top;
 5317: 		    cur = val->nodesetval->nodeTab[0]->children;
 5318: 		    while (cur != NULL) {
 5319: 			tmp = xmlDocCopyNode(cur, top, 1);
 5320: 			xmlAddChild((xmlNodePtr) top, tmp);
 5321: 			cur = cur->next;
 5322: 		    }
 5323: 		}
 5324: 
 5325: 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
 5326: 	    } else
 5327: 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
 5328: 	    /* Deallocate the copied tree value */
 5329: 	    break;
 5330: #endif
 5331: 	case XPATH_NODESET:
 5332: 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
 5333: 	    /* Do not deallocate the copied tree value */
 5334: 	    ret->boolval = 0;
 5335: 	    break;
 5336: 	case XPATH_LOCATIONSET:
 5337: #ifdef LIBXML_XPTR_ENABLED
 5338: 	{
 5339: 	    xmlLocationSetPtr loc = val->user;
 5340: 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
 5341: 	    break;
 5342: 	}
 5343: #endif
 5344:         case XPATH_USERS:
 5345: 	    ret->user = val->user;
 5346: 	    break;
 5347:         case XPATH_UNDEFINED:
 5348: 	    xmlGenericError(xmlGenericErrorContext,
 5349: 		    "xmlXPathObjectCopy: unsupported type %d\n",
 5350: 		    val->type);
 5351: 	    break;
 5352:     }
 5353:     return(ret);
 5354: }
 5355: 
 5356: /**
 5357:  * xmlXPathFreeObject:
 5358:  * @obj:  the object to free
 5359:  *
 5360:  * Free up an xmlXPathObjectPtr object.
 5361:  */
 5362: void
 5363: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
 5364:     if (obj == NULL) return;
 5365:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 5366: 	if (obj->boolval) {
 5367: #if 0
 5368: 	    if (obj->user != NULL) {
 5369:                 xmlXPathFreeNodeSet(obj->nodesetval);
 5370: 		xmlFreeNodeList((xmlNodePtr) obj->user);
 5371: 	    } else
 5372: #endif
 5373: 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
 5374: 	    if (obj->nodesetval != NULL)
 5375: 		xmlXPathFreeValueTree(obj->nodesetval);
 5376: 	} else {
 5377: 	    if (obj->nodesetval != NULL)
 5378: 		xmlXPathFreeNodeSet(obj->nodesetval);
 5379: 	}
 5380: #ifdef LIBXML_XPTR_ENABLED
 5381:     } else if (obj->type == XPATH_LOCATIONSET) {
 5382: 	if (obj->user != NULL)
 5383: 	    xmlXPtrFreeLocationSet(obj->user);
 5384: #endif
 5385:     } else if (obj->type == XPATH_STRING) {
 5386: 	if (obj->stringval != NULL)
 5387: 	    xmlFree(obj->stringval);
 5388:     }
 5389: #ifdef XP_DEBUG_OBJ_USAGE
 5390:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5391: #endif
 5392:     xmlFree(obj);
 5393: }
 5394: 
 5395: /**
 5396:  * xmlXPathReleaseObject:
 5397:  * @obj:  the xmlXPathObjectPtr to free or to cache
 5398:  *
 5399:  * Depending on the state of the cache this frees the given
 5400:  * XPath object or stores it in the cache.
 5401:  */
 5402: static void
 5403: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
 5404: {
 5405: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
 5406: 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
 5407:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
 5408: 
 5409: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
 5410: 
 5411:     if (obj == NULL)
 5412: 	return;
 5413:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
 5414: 	 xmlXPathFreeObject(obj);
 5415:     } else {
 5416: 	xmlXPathContextCachePtr cache =
 5417: 	    (xmlXPathContextCachePtr) ctxt->cache;
 5418: 
 5419: 	switch (obj->type) {
 5420: 	    case XPATH_NODESET:
 5421: 	    case XPATH_XSLT_TREE:
 5422: 		if (obj->nodesetval != NULL) {
 5423: 		    if (obj->boolval) {
 5424: 			/*
 5425: 			* It looks like the @boolval is used for
 5426: 			* evaluation if this an XSLT Result Tree Fragment.
 5427: 			* TODO: Check if this assumption is correct.
 5428: 			*/
 5429: 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
 5430: 			xmlXPathFreeValueTree(obj->nodesetval);
 5431: 			obj->nodesetval = NULL;
 5432: 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
 5433: 			(XP_CACHE_WANTS(cache->nodesetObjs,
 5434: 					cache->maxNodeset)))
 5435: 		    {
 5436: 			XP_CACHE_ADD(cache->nodesetObjs, obj);
 5437: 			goto obj_cached;
 5438: 		    } else {
 5439: 			xmlXPathFreeNodeSet(obj->nodesetval);
 5440: 			obj->nodesetval = NULL;
 5441: 		    }
 5442: 		}
 5443: 		break;
 5444: 	    case XPATH_STRING:
 5445: 		if (obj->stringval != NULL)
 5446: 		    xmlFree(obj->stringval);
 5447: 
 5448: 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
 5449: 		    XP_CACHE_ADD(cache->stringObjs, obj);
 5450: 		    goto obj_cached;
 5451: 		}
 5452: 		break;
 5453: 	    case XPATH_BOOLEAN:
 5454: 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
 5455: 		    XP_CACHE_ADD(cache->booleanObjs, obj);
 5456: 		    goto obj_cached;
 5457: 		}
 5458: 		break;
 5459: 	    case XPATH_NUMBER:
 5460: 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
 5461: 		    XP_CACHE_ADD(cache->numberObjs, obj);
 5462: 		    goto obj_cached;
 5463: 		}
 5464: 		break;
 5465: #ifdef LIBXML_XPTR_ENABLED
 5466: 	    case XPATH_LOCATIONSET:
 5467: 		if (obj->user != NULL) {
 5468: 		    xmlXPtrFreeLocationSet(obj->user);
 5469: 		}
 5470: 		goto free_obj;
 5471: #endif
 5472: 	    default:
 5473: 		goto free_obj;
 5474: 	}
 5475: 
 5476: 	/*
 5477: 	* Fallback to adding to the misc-objects slot.
 5478: 	*/
 5479: 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
 5480: 	    XP_CACHE_ADD(cache->miscObjs, obj);
 5481: 	} else
 5482: 	    goto free_obj;
 5483: 
 5484: obj_cached:
 5485: 
 5486: #ifdef XP_DEBUG_OBJ_USAGE
 5487: 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
 5488: #endif
 5489: 
 5490: 	if (obj->nodesetval != NULL) {
 5491: 	    xmlNodeSetPtr tmpset = obj->nodesetval;
 5492: 
 5493: 	    /*
 5494: 	    * TODO: Due to those nasty ns-nodes, we need to traverse
 5495: 	    *  the list and free the ns-nodes.
 5496: 	    * URGENT TODO: Check if it's actually slowing things down.
 5497: 	    *  Maybe we shouldn't try to preserve the list.
 5498: 	    */
 5499: 	    if (tmpset->nodeNr > 1) {
 5500: 		int i;
 5501: 		xmlNodePtr node;
 5502: 
 5503: 		for (i = 0; i < tmpset->nodeNr; i++) {
 5504: 		    node = tmpset->nodeTab[i];
 5505: 		    if ((node != NULL) &&
 5506: 			(node->type == XML_NAMESPACE_DECL))
 5507: 		    {
 5508: 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 5509: 		    }
 5510: 		}
 5511: 	    } else if (tmpset->nodeNr == 1) {
 5512: 		if ((tmpset->nodeTab[0] != NULL) &&
 5513: 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
 5514: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
 5515: 	    }
 5516: 	    tmpset->nodeNr = 0;
 5517: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5518: 	    obj->nodesetval = tmpset;
 5519: 	} else
 5520: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5521: 
 5522: 	return;
 5523: 
 5524: free_obj:
 5525: 	/*
 5526: 	* Cache is full; free the object.
 5527: 	*/
 5528: 	if (obj->nodesetval != NULL)
 5529: 	    xmlXPathFreeNodeSet(obj->nodesetval);
 5530: #ifdef XP_DEBUG_OBJ_USAGE
 5531: 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5532: #endif
 5533: 	xmlFree(obj);
 5534:     }
 5535:     return;
 5536: }
 5537: 
 5538: 
 5539: /************************************************************************
 5540:  *									*
 5541:  *			Type Casting Routines				*
 5542:  *									*
 5543:  ************************************************************************/
 5544: 
 5545: /**
 5546:  * xmlXPathCastBooleanToString:
 5547:  * @val:  a boolean
 5548:  *
 5549:  * Converts a boolean to its string value.
 5550:  *
 5551:  * Returns a newly allocated string.
 5552:  */
 5553: xmlChar *
 5554: xmlXPathCastBooleanToString (int val) {
 5555:     xmlChar *ret;
 5556:     if (val)
 5557: 	ret = xmlStrdup((const xmlChar *) "true");
 5558:     else
 5559: 	ret = xmlStrdup((const xmlChar *) "false");
 5560:     return(ret);
 5561: }
 5562: 
 5563: /**
 5564:  * xmlXPathCastNumberToString:
 5565:  * @val:  a number
 5566:  *
 5567:  * Converts a number to its string value.
 5568:  *
 5569:  * Returns a newly allocated string.
 5570:  */
 5571: xmlChar *
 5572: xmlXPathCastNumberToString (double val) {
 5573:     xmlChar *ret;
 5574:     switch (xmlXPathIsInf(val)) {
 5575:     case 1:
 5576: 	ret = xmlStrdup((const xmlChar *) "Infinity");
 5577: 	break;
 5578:     case -1:
 5579: 	ret = xmlStrdup((const xmlChar *) "-Infinity");
 5580: 	break;
 5581:     default:
 5582: 	if (xmlXPathIsNaN(val)) {
 5583: 	    ret = xmlStrdup((const xmlChar *) "NaN");
 5584: 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
 5585: 	    ret = xmlStrdup((const xmlChar *) "0");
 5586: 	} else {
 5587: 	    /* could be improved */
 5588: 	    char buf[100];
 5589: 	    xmlXPathFormatNumber(val, buf, 99);
 5590: 	    buf[99] = 0;
 5591: 	    ret = xmlStrdup((const xmlChar *) buf);
 5592: 	}
 5593:     }
 5594:     return(ret);
 5595: }
 5596: 
 5597: /**
 5598:  * xmlXPathCastNodeToString:
 5599:  * @node:  a node
 5600:  *
 5601:  * Converts a node to its string value.
 5602:  *
 5603:  * Returns a newly allocated string.
 5604:  */
 5605: xmlChar *
 5606: xmlXPathCastNodeToString (xmlNodePtr node) {
 5607: xmlChar *ret;
 5608:     if ((ret = xmlNodeGetContent(node)) == NULL)
 5609: 	ret = xmlStrdup((const xmlChar *) "");
 5610:     return(ret);
 5611: }
 5612: 
 5613: /**
 5614:  * xmlXPathCastNodeSetToString:
 5615:  * @ns:  a node-set
 5616:  *
 5617:  * Converts a node-set to its string value.
 5618:  *
 5619:  * Returns a newly allocated string.
 5620:  */
 5621: xmlChar *
 5622: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
 5623:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
 5624: 	return(xmlStrdup((const xmlChar *) ""));
 5625: 
 5626:     if (ns->nodeNr > 1)
 5627: 	xmlXPathNodeSetSort(ns);
 5628:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
 5629: }
 5630: 
 5631: /**
 5632:  * xmlXPathCastToString:
 5633:  * @val:  an XPath object
 5634:  *
 5635:  * Converts an existing object to its string() equivalent
 5636:  *
 5637:  * Returns the allocated string value of the object, NULL in case of error.
 5638:  *         It's up to the caller to free the string memory with xmlFree().
 5639:  */
 5640: xmlChar *
 5641: xmlXPathCastToString(xmlXPathObjectPtr val) {
 5642:     xmlChar *ret = NULL;
 5643: 
 5644:     if (val == NULL)
 5645: 	return(xmlStrdup((const xmlChar *) ""));
 5646:     switch (val->type) {
 5647: 	case XPATH_UNDEFINED:
 5648: #ifdef DEBUG_EXPR
 5649: 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
 5650: #endif
 5651: 	    ret = xmlStrdup((const xmlChar *) "");
 5652: 	    break;
 5653:         case XPATH_NODESET:
 5654:         case XPATH_XSLT_TREE:
 5655: 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
 5656: 	    break;
 5657: 	case XPATH_STRING:
 5658: 	    return(xmlStrdup(val->stringval));
 5659:         case XPATH_BOOLEAN:
 5660: 	    ret = xmlXPathCastBooleanToString(val->boolval);
 5661: 	    break;
 5662: 	case XPATH_NUMBER: {
 5663: 	    ret = xmlXPathCastNumberToString(val->floatval);
 5664: 	    break;
 5665: 	}
 5666: 	case XPATH_USERS:
 5667: 	case XPATH_POINT:
 5668: 	case XPATH_RANGE:
 5669: 	case XPATH_LOCATIONSET:
 5670: 	    TODO
 5671: 	    ret = xmlStrdup((const xmlChar *) "");
 5672: 	    break;
 5673:     }
 5674:     return(ret);
 5675: }
 5676: 
 5677: /**
 5678:  * xmlXPathConvertString:
 5679:  * @val:  an XPath object
 5680:  *
 5681:  * Converts an existing object to its string() equivalent
 5682:  *
 5683:  * Returns the new object, the old one is freed (or the operation
 5684:  *         is done directly on @val)
 5685:  */
 5686: xmlXPathObjectPtr
 5687: xmlXPathConvertString(xmlXPathObjectPtr val) {
 5688:     xmlChar *res = NULL;
 5689: 
 5690:     if (val == NULL)
 5691: 	return(xmlXPathNewCString(""));
 5692: 
 5693:     switch (val->type) {
 5694:     case XPATH_UNDEFINED:
 5695: #ifdef DEBUG_EXPR
 5696: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 5697: #endif
 5698: 	break;
 5699:     case XPATH_NODESET:
 5700:     case XPATH_XSLT_TREE:
 5701: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 5702: 	break;
 5703:     case XPATH_STRING:
 5704: 	return(val);
 5705:     case XPATH_BOOLEAN:
 5706: 	res = xmlXPathCastBooleanToString(val->boolval);
 5707: 	break;
 5708:     case XPATH_NUMBER:
 5709: 	res = xmlXPathCastNumberToString(val->floatval);
 5710: 	break;
 5711:     case XPATH_USERS:
 5712:     case XPATH_POINT:
 5713:     case XPATH_RANGE:
 5714:     case XPATH_LOCATIONSET:
 5715: 	TODO;
 5716: 	break;
 5717:     }
 5718:     xmlXPathFreeObject(val);
 5719:     if (res == NULL)
 5720: 	return(xmlXPathNewCString(""));
 5721:     return(xmlXPathWrapString(res));
 5722: }
 5723: 
 5724: /**
 5725:  * xmlXPathCastBooleanToNumber:
 5726:  * @val:  a boolean
 5727:  *
 5728:  * Converts a boolean to its number value
 5729:  *
 5730:  * Returns the number value
 5731:  */
 5732: double
 5733: xmlXPathCastBooleanToNumber(int val) {
 5734:     if (val)
 5735: 	return(1.0);
 5736:     return(0.0);
 5737: }
 5738: 
 5739: /**
 5740:  * xmlXPathCastStringToNumber:
 5741:  * @val:  a string
 5742:  *
 5743:  * Converts a string to its number value
 5744:  *
 5745:  * Returns the number value
 5746:  */
 5747: double
 5748: xmlXPathCastStringToNumber(const xmlChar * val) {
 5749:     return(xmlXPathStringEvalNumber(val));
 5750: }
 5751: 
 5752: /**
 5753:  * xmlXPathCastNodeToNumber:
 5754:  * @node:  a node
 5755:  *
 5756:  * Converts a node to its number value
 5757:  *
 5758:  * Returns the number value
 5759:  */
 5760: double
 5761: xmlXPathCastNodeToNumber (xmlNodePtr node) {
 5762:     xmlChar *strval;
 5763:     double ret;
 5764: 
 5765:     if (node == NULL)
 5766: 	return(xmlXPathNAN);
 5767:     strval = xmlXPathCastNodeToString(node);
 5768:     if (strval == NULL)
 5769: 	return(xmlXPathNAN);
 5770:     ret = xmlXPathCastStringToNumber(strval);
 5771:     xmlFree(strval);
 5772: 
 5773:     return(ret);
 5774: }
 5775: 
 5776: /**
 5777:  * xmlXPathCastNodeSetToNumber:
 5778:  * @ns:  a node-set
 5779:  *
 5780:  * Converts a node-set to its number value
 5781:  *
 5782:  * Returns the number value
 5783:  */
 5784: double
 5785: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
 5786:     xmlChar *str;
 5787:     double ret;
 5788: 
 5789:     if (ns == NULL)
 5790: 	return(xmlXPathNAN);
 5791:     str = xmlXPathCastNodeSetToString(ns);
 5792:     ret = xmlXPathCastStringToNumber(str);
 5793:     xmlFree(str);
 5794:     return(ret);
 5795: }
 5796: 
 5797: /**
 5798:  * xmlXPathCastToNumber:
 5799:  * @val:  an XPath object
 5800:  *
 5801:  * Converts an XPath object to its number value
 5802:  *
 5803:  * Returns the number value
 5804:  */
 5805: double
 5806: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
 5807:     double ret = 0.0;
 5808: 
 5809:     if (val == NULL)
 5810: 	return(xmlXPathNAN);
 5811:     switch (val->type) {
 5812:     case XPATH_UNDEFINED:
 5813: #ifdef DEGUB_EXPR
 5814: 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
 5815: #endif
 5816: 	ret = xmlXPathNAN;
 5817: 	break;
 5818:     case XPATH_NODESET:
 5819:     case XPATH_XSLT_TREE:
 5820: 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
 5821: 	break;
 5822:     case XPATH_STRING:
 5823: 	ret = xmlXPathCastStringToNumber(val->stringval);
 5824: 	break;
 5825:     case XPATH_NUMBER:
 5826: 	ret = val->floatval;
 5827: 	break;
 5828:     case XPATH_BOOLEAN:
 5829: 	ret = xmlXPathCastBooleanToNumber(val->boolval);
 5830: 	break;
 5831:     case XPATH_USERS:
 5832:     case XPATH_POINT:
 5833:     case XPATH_RANGE:
 5834:     case XPATH_LOCATIONSET:
 5835: 	TODO;
 5836: 	ret = xmlXPathNAN;
 5837: 	break;
 5838:     }
 5839:     return(ret);
 5840: }
 5841: 
 5842: /**
 5843:  * xmlXPathConvertNumber:
 5844:  * @val:  an XPath object
 5845:  *
 5846:  * Converts an existing object to its number() equivalent
 5847:  *
 5848:  * Returns the new object, the old one is freed (or the operation
 5849:  *         is done directly on @val)
 5850:  */
 5851: xmlXPathObjectPtr
 5852: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
 5853:     xmlXPathObjectPtr ret;
 5854: 
 5855:     if (val == NULL)
 5856: 	return(xmlXPathNewFloat(0.0));
 5857:     if (val->type == XPATH_NUMBER)
 5858: 	return(val);
 5859:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
 5860:     xmlXPathFreeObject(val);
 5861:     return(ret);
 5862: }
 5863: 
 5864: /**
 5865:  * xmlXPathCastNumberToBoolean:
 5866:  * @val:  a number
 5867:  *
 5868:  * Converts a number to its boolean value
 5869:  *
 5870:  * Returns the boolean value
 5871:  */
 5872: int
 5873: xmlXPathCastNumberToBoolean (double val) {
 5874:      if (xmlXPathIsNaN(val) || (val == 0.0))
 5875: 	 return(0);
 5876:      return(1);
 5877: }
 5878: 
 5879: /**
 5880:  * xmlXPathCastStringToBoolean:
 5881:  * @val:  a string
 5882:  *
 5883:  * Converts a string to its boolean value
 5884:  *
 5885:  * Returns the boolean value
 5886:  */
 5887: int
 5888: xmlXPathCastStringToBoolean (const xmlChar *val) {
 5889:     if ((val == NULL) || (xmlStrlen(val) == 0))
 5890: 	return(0);
 5891:     return(1);
 5892: }
 5893: 
 5894: /**
 5895:  * xmlXPathCastNodeSetToBoolean:
 5896:  * @ns:  a node-set
 5897:  *
 5898:  * Converts a node-set to its boolean value
 5899:  *
 5900:  * Returns the boolean value
 5901:  */
 5902: int
 5903: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
 5904:     if ((ns == NULL) || (ns->nodeNr == 0))
 5905: 	return(0);
 5906:     return(1);
 5907: }
 5908: 
 5909: /**
 5910:  * xmlXPathCastToBoolean:
 5911:  * @val:  an XPath object
 5912:  *
 5913:  * Converts an XPath object to its boolean value
 5914:  *
 5915:  * Returns the boolean value
 5916:  */
 5917: int
 5918: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
 5919:     int ret = 0;
 5920: 
 5921:     if (val == NULL)
 5922: 	return(0);
 5923:     switch (val->type) {
 5924:     case XPATH_UNDEFINED:
 5925: #ifdef DEBUG_EXPR
 5926: 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
 5927: #endif
 5928: 	ret = 0;
 5929: 	break;
 5930:     case XPATH_NODESET:
 5931:     case XPATH_XSLT_TREE:
 5932: 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
 5933: 	break;
 5934:     case XPATH_STRING:
 5935: 	ret = xmlXPathCastStringToBoolean(val->stringval);
 5936: 	break;
 5937:     case XPATH_NUMBER:
 5938: 	ret = xmlXPathCastNumberToBoolean(val->floatval);
 5939: 	break;
 5940:     case XPATH_BOOLEAN:
 5941: 	ret = val->boolval;
 5942: 	break;
 5943:     case XPATH_USERS:
 5944:     case XPATH_POINT:
 5945:     case XPATH_RANGE:
 5946:     case XPATH_LOCATIONSET:
 5947: 	TODO;
 5948: 	ret = 0;
 5949: 	break;
 5950:     }
 5951:     return(ret);
 5952: }
 5953: 
 5954: 
 5955: /**
 5956:  * xmlXPathConvertBoolean:
 5957:  * @val:  an XPath object
 5958:  *
 5959:  * Converts an existing object to its boolean() equivalent
 5960:  *
 5961:  * Returns the new object, the old one is freed (or the operation
 5962:  *         is done directly on @val)
 5963:  */
 5964: xmlXPathObjectPtr
 5965: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
 5966:     xmlXPathObjectPtr ret;
 5967: 
 5968:     if (val == NULL)
 5969: 	return(xmlXPathNewBoolean(0));
 5970:     if (val->type == XPATH_BOOLEAN)
 5971: 	return(val);
 5972:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
 5973:     xmlXPathFreeObject(val);
 5974:     return(ret);
 5975: }
 5976: 
 5977: /************************************************************************
 5978:  *									*
 5979:  *		Routines to handle XPath contexts			*
 5980:  *									*
 5981:  ************************************************************************/
 5982: 
 5983: /**
 5984:  * xmlXPathNewContext:
 5985:  * @doc:  the XML document
 5986:  *
 5987:  * Create a new xmlXPathContext
 5988:  *
 5989:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
 5990:  */
 5991: xmlXPathContextPtr
 5992: xmlXPathNewContext(xmlDocPtr doc) {
 5993:     xmlXPathContextPtr ret;
 5994: 
 5995:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
 5996:     if (ret == NULL) {
 5997:         xmlXPathErrMemory(NULL, "creating context\n");
 5998: 	return(NULL);
 5999:     }
 6000:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
 6001:     ret->doc = doc;
 6002:     ret->node = NULL;
 6003: 
 6004:     ret->varHash = NULL;
 6005: 
 6006:     ret->nb_types = 0;
 6007:     ret->max_types = 0;
 6008:     ret->types = NULL;
 6009: 
 6010:     ret->funcHash = xmlHashCreate(0);
 6011: 
 6012:     ret->nb_axis = 0;
 6013:     ret->max_axis = 0;
 6014:     ret->axis = NULL;
 6015: 
 6016:     ret->nsHash = NULL;
 6017:     ret->user = NULL;
 6018: 
 6019:     ret->contextSize = -1;
 6020:     ret->proximityPosition = -1;
 6021: 
 6022: #ifdef XP_DEFAULT_CACHE_ON
 6023:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
 6024: 	xmlXPathFreeContext(ret);
 6025: 	return(NULL);
 6026:     }
 6027: #endif
 6028: 
 6029:     xmlXPathRegisterAllFunctions(ret);
 6030: 
 6031:     return(ret);
 6032: }
 6033: 
 6034: /**
 6035:  * xmlXPathFreeContext:
 6036:  * @ctxt:  the context to free
 6037:  *
 6038:  * Free up an xmlXPathContext
 6039:  */
 6040: void
 6041: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
 6042:     if (ctxt == NULL) return;
 6043: 
 6044:     if (ctxt->cache != NULL)
 6045: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 6046:     xmlXPathRegisteredNsCleanup(ctxt);
 6047:     xmlXPathRegisteredFuncsCleanup(ctxt);
 6048:     xmlXPathRegisteredVariablesCleanup(ctxt);
 6049:     xmlResetError(&ctxt->lastError);
 6050:     xmlFree(ctxt);
 6051: }
 6052: 
 6053: /************************************************************************
 6054:  *									*
 6055:  *		Routines to handle XPath parser contexts		*
 6056:  *									*
 6057:  ************************************************************************/
 6058: 
 6059: #define CHECK_CTXT(ctxt)						\
 6060:     if (ctxt == NULL) {						\
 6061: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6062: 		NULL, NULL, XML_FROM_XPATH,				\
 6063: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6064: 		__FILE__, __LINE__,					\
 6065: 		NULL, NULL, NULL, 0, 0,					\
 6066: 		"NULL context pointer\n");				\
 6067: 	return(NULL);							\
 6068:     }									\
 6069: 
 6070: #define CHECK_CTXT_NEG(ctxt)						\
 6071:     if (ctxt == NULL) {						\
 6072: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6073: 		NULL, NULL, XML_FROM_XPATH,				\
 6074: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6075: 		__FILE__, __LINE__,					\
 6076: 		NULL, NULL, NULL, 0, 0,					\
 6077: 		"NULL context pointer\n");				\
 6078: 	return(-1);							\
 6079:     }									\
 6080: 
 6081: 
 6082: #define CHECK_CONTEXT(ctxt)						\
 6083:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
 6084:         (ctxt->doc->children == NULL)) {				\
 6085: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
 6086: 	return(NULL);							\
 6087:     }
 6088: 
 6089: 
 6090: /**
 6091:  * xmlXPathNewParserContext:
 6092:  * @str:  the XPath expression
 6093:  * @ctxt:  the XPath context
 6094:  *
 6095:  * Create a new xmlXPathParserContext
 6096:  *
 6097:  * Returns the xmlXPathParserContext just allocated.
 6098:  */
 6099: xmlXPathParserContextPtr
 6100: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
 6101:     xmlXPathParserContextPtr ret;
 6102: 
 6103:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6104:     if (ret == NULL) {
 6105:         xmlXPathErrMemory(ctxt, "creating parser context\n");
 6106: 	return(NULL);
 6107:     }
 6108:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6109:     ret->cur = ret->base = str;
 6110:     ret->context = ctxt;
 6111: 
 6112:     ret->comp = xmlXPathNewCompExpr();
 6113:     if (ret->comp == NULL) {
 6114: 	xmlFree(ret->valueTab);
 6115: 	xmlFree(ret);
 6116: 	return(NULL);
 6117:     }
 6118:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
 6119:         ret->comp->dict = ctxt->dict;
 6120: 	xmlDictReference(ret->comp->dict);
 6121:     }
 6122: 
 6123:     return(ret);
 6124: }
 6125: 
 6126: /**
 6127:  * xmlXPathCompParserContext:
 6128:  * @comp:  the XPath compiled expression
 6129:  * @ctxt:  the XPath context
 6130:  *
 6131:  * Create a new xmlXPathParserContext when processing a compiled expression
 6132:  *
 6133:  * Returns the xmlXPathParserContext just allocated.
 6134:  */
 6135: static xmlXPathParserContextPtr
 6136: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
 6137:     xmlXPathParserContextPtr ret;
 6138: 
 6139:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6140:     if (ret == NULL) {
 6141:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6142: 	return(NULL);
 6143:     }
 6144:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6145: 
 6146:     /* Allocate the value stack */
 6147:     ret->valueTab = (xmlXPathObjectPtr *)
 6148:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
 6149:     if (ret->valueTab == NULL) {
 6150: 	xmlFree(ret);
 6151: 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6152: 	return(NULL);
 6153:     }
 6154:     ret->valueNr = 0;
 6155:     ret->valueMax = 10;
 6156:     ret->value = NULL;
 6157: 
 6158:     ret->context = ctxt;
 6159:     ret->comp = comp;
 6160: 
 6161:     return(ret);
 6162: }
 6163: 
 6164: /**
 6165:  * xmlXPathFreeParserContext:
 6166:  * @ctxt:  the context to free
 6167:  *
 6168:  * Free up an xmlXPathParserContext
 6169:  */
 6170: void
 6171: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
 6172:     if (ctxt->valueTab != NULL) {
 6173:         xmlFree(ctxt->valueTab);
 6174:     }
 6175:     if (ctxt->comp != NULL) {
 6176: #ifdef XPATH_STREAMING
 6177: 	if (ctxt->comp->stream != NULL) {
 6178: 	    xmlFreePatternList(ctxt->comp->stream);
 6179: 	    ctxt->comp->stream = NULL;
 6180: 	}
 6181: #endif
 6182: 	xmlXPathFreeCompExpr(ctxt->comp);
 6183:     }
 6184:     xmlFree(ctxt);
 6185: }
 6186: 
 6187: /************************************************************************
 6188:  *									*
 6189:  *		The implicit core function library			*
 6190:  *									*
 6191:  ************************************************************************/
 6192: 
 6193: /**
 6194:  * xmlXPathNodeValHash:
 6195:  * @node:  a node pointer
 6196:  *
 6197:  * Function computing the beginning of the string value of the node,
 6198:  * used to speed up comparisons
 6199:  *
 6200:  * Returns an int usable as a hash
 6201:  */
 6202: static unsigned int
 6203: xmlXPathNodeValHash(xmlNodePtr node) {
 6204:     int len = 2;
 6205:     const xmlChar * string = NULL;
 6206:     xmlNodePtr tmp = NULL;
 6207:     unsigned int ret = 0;
 6208: 
 6209:     if (node == NULL)
 6210: 	return(0);
 6211: 
 6212:     if (node->type == XML_DOCUMENT_NODE) {
 6213: 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
 6214: 	if (tmp == NULL)
 6215: 	    node = node->children;
 6216: 	else
 6217: 	    node = tmp;
 6218: 
 6219: 	if (node == NULL)
 6220: 	    return(0);
 6221:     }
 6222: 
 6223:     switch (node->type) {
 6224: 	case XML_COMMENT_NODE:
 6225: 	case XML_PI_NODE:
 6226: 	case XML_CDATA_SECTION_NODE:
 6227: 	case XML_TEXT_NODE:
 6228: 	    string = node->content;
 6229: 	    if (string == NULL)
 6230: 		return(0);
 6231: 	    if (string[0] == 0)
 6232: 		return(0);
 6233: 	    return(((unsigned int) string[0]) +
 6234: 		   (((unsigned int) string[1]) << 8));
 6235: 	case XML_NAMESPACE_DECL:
 6236: 	    string = ((xmlNsPtr)node)->href;
 6237: 	    if (string == NULL)
 6238: 		return(0);
 6239: 	    if (string[0] == 0)
 6240: 		return(0);
 6241: 	    return(((unsigned int) string[0]) +
 6242: 		   (((unsigned int) string[1]) << 8));
 6243: 	case XML_ATTRIBUTE_NODE:
 6244: 	    tmp = ((xmlAttrPtr) node)->children;
 6245: 	    break;
 6246: 	case XML_ELEMENT_NODE:
 6247: 	    tmp = node->children;
 6248: 	    break;
 6249: 	default:
 6250: 	    return(0);
 6251:     }
 6252:     while (tmp != NULL) {
 6253: 	switch (tmp->type) {
 6254: 	    case XML_COMMENT_NODE:
 6255: 	    case XML_PI_NODE:
 6256: 	    case XML_CDATA_SECTION_NODE:
 6257: 	    case XML_TEXT_NODE:
 6258: 		string = tmp->content;
 6259: 		break;
 6260: 	    case XML_NAMESPACE_DECL:
 6261: 		string = ((xmlNsPtr)tmp)->href;
 6262: 		break;
 6263: 	    default:
 6264: 		break;
 6265: 	}
 6266: 	if ((string != NULL) && (string[0] != 0)) {
 6267: 	    if (len == 1) {
 6268: 		return(ret + (((unsigned int) string[0]) << 8));
 6269: 	    }
 6270: 	    if (string[1] == 0) {
 6271: 		len = 1;
 6272: 		ret = (unsigned int) string[0];
 6273: 	    } else {
 6274: 		return(((unsigned int) string[0]) +
 6275: 		       (((unsigned int) string[1]) << 8));
 6276: 	    }
 6277: 	}
 6278: 	/*
 6279: 	 * Skip to next node
 6280: 	 */
 6281: 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
 6282: 	    if (tmp->children->type != XML_ENTITY_DECL) {
 6283: 		tmp = tmp->children;
 6284: 		continue;
 6285: 	    }
 6286: 	}
 6287: 	if (tmp == node)
 6288: 	    break;
 6289: 
 6290: 	if (tmp->next != NULL) {
 6291: 	    tmp = tmp->next;
 6292: 	    continue;
 6293: 	}
 6294: 
 6295: 	do {
 6296: 	    tmp = tmp->parent;
 6297: 	    if (tmp == NULL)
 6298: 		break;
 6299: 	    if (tmp == node) {
 6300: 		tmp = NULL;
 6301: 		break;
 6302: 	    }
 6303: 	    if (tmp->next != NULL) {
 6304: 		tmp = tmp->next;
 6305: 		break;
 6306: 	    }
 6307: 	} while (tmp != NULL);
 6308:     }
 6309:     return(ret);
 6310: }
 6311: 
 6312: /**
 6313:  * xmlXPathStringHash:
 6314:  * @string:  a string
 6315:  *
 6316:  * Function computing the beginning of the string value of the node,
 6317:  * used to speed up comparisons
 6318:  *
 6319:  * Returns an int usable as a hash
 6320:  */
 6321: static unsigned int
 6322: xmlXPathStringHash(const xmlChar * string) {
 6323:     if (string == NULL)
 6324: 	return((unsigned int) 0);
 6325:     if (string[0] == 0)
 6326: 	return(0);
 6327:     return(((unsigned int) string[0]) +
 6328: 	   (((unsigned int) string[1]) << 8));
 6329: }
 6330: 
 6331: /**
 6332:  * xmlXPathCompareNodeSetFloat:
 6333:  * @ctxt:  the XPath Parser context
 6334:  * @inf:  less than (1) or greater than (0)
 6335:  * @strict:  is the comparison strict
 6336:  * @arg:  the node set
 6337:  * @f:  the value
 6338:  *
 6339:  * Implement the compare operation between a nodeset and a number
 6340:  *     @ns < @val    (1, 1, ...
 6341:  *     @ns <= @val   (1, 0, ...
 6342:  *     @ns > @val    (0, 1, ...
 6343:  *     @ns >= @val   (0, 0, ...
 6344:  *
 6345:  * If one object to be compared is a node-set and the other is a number,
 6346:  * then the comparison will be true if and only if there is a node in the
 6347:  * node-set such that the result of performing the comparison on the number
 6348:  * to be compared and on the result of converting the string-value of that
 6349:  * node to a number using the number function is true.
 6350:  *
 6351:  * Returns 0 or 1 depending on the results of the test.
 6352:  */
 6353: static int
 6354: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6355: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
 6356:     int i, ret = 0;
 6357:     xmlNodeSetPtr ns;
 6358:     xmlChar *str2;
 6359: 
 6360:     if ((f == NULL) || (arg == NULL) ||
 6361: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6362: 	xmlXPathReleaseObject(ctxt->context, arg);
 6363: 	xmlXPathReleaseObject(ctxt->context, f);
 6364:         return(0);
 6365:     }
 6366:     ns = arg->nodesetval;
 6367:     if (ns != NULL) {
 6368: 	for (i = 0;i < ns->nodeNr;i++) {
 6369: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6370: 	     if (str2 != NULL) {
 6371: 		 valuePush(ctxt,
 6372: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6373: 		 xmlFree(str2);
 6374: 		 xmlXPathNumberFunction(ctxt, 1);
 6375: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
 6376: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6377: 		 if (ret)
 6378: 		     break;
 6379: 	     }
 6380: 	}
 6381:     }
 6382:     xmlXPathReleaseObject(ctxt->context, arg);
 6383:     xmlXPathReleaseObject(ctxt->context, f);
 6384:     return(ret);
 6385: }
 6386: 
 6387: /**
 6388:  * xmlXPathCompareNodeSetString:
 6389:  * @ctxt:  the XPath Parser context
 6390:  * @inf:  less than (1) or greater than (0)
 6391:  * @strict:  is the comparison strict
 6392:  * @arg:  the node set
 6393:  * @s:  the value
 6394:  *
 6395:  * Implement the compare operation between a nodeset and a string
 6396:  *     @ns < @val    (1, 1, ...
 6397:  *     @ns <= @val   (1, 0, ...
 6398:  *     @ns > @val    (0, 1, ...
 6399:  *     @ns >= @val   (0, 0, ...
 6400:  *
 6401:  * If one object to be compared is a node-set and the other is a string,
 6402:  * then the comparison will be true if and only if there is a node in
 6403:  * the node-set such that the result of performing the comparison on the
 6404:  * string-value of the node and the other string is true.
 6405:  *
 6406:  * Returns 0 or 1 depending on the results of the test.
 6407:  */
 6408: static int
 6409: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6410: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
 6411:     int i, ret = 0;
 6412:     xmlNodeSetPtr ns;
 6413:     xmlChar *str2;
 6414: 
 6415:     if ((s == NULL) || (arg == NULL) ||
 6416: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6417: 	xmlXPathReleaseObject(ctxt->context, arg);
 6418: 	xmlXPathReleaseObject(ctxt->context, s);
 6419:         return(0);
 6420:     }
 6421:     ns = arg->nodesetval;
 6422:     if (ns != NULL) {
 6423: 	for (i = 0;i < ns->nodeNr;i++) {
 6424: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6425: 	     if (str2 != NULL) {
 6426: 		 valuePush(ctxt,
 6427: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6428: 		 xmlFree(str2);
 6429: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
 6430: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6431: 		 if (ret)
 6432: 		     break;
 6433: 	     }
 6434: 	}
 6435:     }
 6436:     xmlXPathReleaseObject(ctxt->context, arg);
 6437:     xmlXPathReleaseObject(ctxt->context, s);
 6438:     return(ret);
 6439: }
 6440: 
 6441: /**
 6442:  * xmlXPathCompareNodeSets:
 6443:  * @inf:  less than (1) or greater than (0)
 6444:  * @strict:  is the comparison strict
 6445:  * @arg1:  the first node set object
 6446:  * @arg2:  the second node set object
 6447:  *
 6448:  * Implement the compare operation on nodesets:
 6449:  *
 6450:  * If both objects to be compared are node-sets, then the comparison
 6451:  * will be true if and only if there is a node in the first node-set
 6452:  * and a node in the second node-set such that the result of performing
 6453:  * the comparison on the string-values of the two nodes is true.
 6454:  * ....
 6455:  * When neither object to be compared is a node-set and the operator
 6456:  * is <=, <, >= or >, then the objects are compared by converting both
 6457:  * objects to numbers and comparing the numbers according to IEEE 754.
 6458:  * ....
 6459:  * The number function converts its argument to a number as follows:
 6460:  *  - a string that consists of optional whitespace followed by an
 6461:  *    optional minus sign followed by a Number followed by whitespace
 6462:  *    is converted to the IEEE 754 number that is nearest (according
 6463:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
 6464:  *    represented by the string; any other string is converted to NaN
 6465:  *
 6466:  * Conclusion all nodes need to be converted first to their string value
 6467:  * and then the comparison must be done when possible
 6468:  */
 6469: static int
 6470: xmlXPathCompareNodeSets(int inf, int strict,
 6471: 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6472:     int i, j, init = 0;
 6473:     double val1;
 6474:     double *values2;
 6475:     int ret = 0;
 6476:     xmlNodeSetPtr ns1;
 6477:     xmlNodeSetPtr ns2;
 6478: 
 6479:     if ((arg1 == NULL) ||
 6480: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
 6481: 	xmlXPathFreeObject(arg2);
 6482:         return(0);
 6483:     }
 6484:     if ((arg2 == NULL) ||
 6485: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
 6486: 	xmlXPathFreeObject(arg1);
 6487: 	xmlXPathFreeObject(arg2);
 6488:         return(0);
 6489:     }
 6490: 
 6491:     ns1 = arg1->nodesetval;
 6492:     ns2 = arg2->nodesetval;
 6493: 
 6494:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
 6495: 	xmlXPathFreeObject(arg1);
 6496: 	xmlXPathFreeObject(arg2);
 6497: 	return(0);
 6498:     }
 6499:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
 6500: 	xmlXPathFreeObject(arg1);
 6501: 	xmlXPathFreeObject(arg2);
 6502: 	return(0);
 6503:     }
 6504: 
 6505:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
 6506:     if (values2 == NULL) {
 6507:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6508: 	xmlXPathFreeObject(arg1);
 6509: 	xmlXPathFreeObject(arg2);
 6510: 	return(0);
 6511:     }
 6512:     for (i = 0;i < ns1->nodeNr;i++) {
 6513: 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
 6514: 	if (xmlXPathIsNaN(val1))
 6515: 	    continue;
 6516: 	for (j = 0;j < ns2->nodeNr;j++) {
 6517: 	    if (init == 0) {
 6518: 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
 6519: 	    }
 6520: 	    if (xmlXPathIsNaN(values2[j]))
 6521: 		continue;
 6522: 	    if (inf && strict)
 6523: 		ret = (val1 < values2[j]);
 6524: 	    else if (inf && !strict)
 6525: 		ret = (val1 <= values2[j]);
 6526: 	    else if (!inf && strict)
 6527: 		ret = (val1 > values2[j]);
 6528: 	    else if (!inf && !strict)
 6529: 		ret = (val1 >= values2[j]);
 6530: 	    if (ret)
 6531: 		break;
 6532: 	}
 6533: 	if (ret)
 6534: 	    break;
 6535: 	init = 1;
 6536:     }
 6537:     xmlFree(values2);
 6538:     xmlXPathFreeObject(arg1);
 6539:     xmlXPathFreeObject(arg2);
 6540:     return(ret);
 6541: }
 6542: 
 6543: /**
 6544:  * xmlXPathCompareNodeSetValue:
 6545:  * @ctxt:  the XPath Parser context
 6546:  * @inf:  less than (1) or greater than (0)
 6547:  * @strict:  is the comparison strict
 6548:  * @arg:  the node set
 6549:  * @val:  the value
 6550:  *
 6551:  * Implement the compare operation between a nodeset and a value
 6552:  *     @ns < @val    (1, 1, ...
 6553:  *     @ns <= @val   (1, 0, ...
 6554:  *     @ns > @val    (0, 1, ...
 6555:  *     @ns >= @val   (0, 0, ...
 6556:  *
 6557:  * If one object to be compared is a node-set and the other is a boolean,
 6558:  * then the comparison will be true if and only if the result of performing
 6559:  * the comparison on the boolean and on the result of converting
 6560:  * the node-set to a boolean using the boolean function is true.
 6561:  *
 6562:  * Returns 0 or 1 depending on the results of the test.
 6563:  */
 6564: static int
 6565: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6566: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
 6567:     if ((val == NULL) || (arg == NULL) ||
 6568: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6569:         return(0);
 6570: 
 6571:     switch(val->type) {
 6572:         case XPATH_NUMBER:
 6573: 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
 6574:         case XPATH_NODESET:
 6575:         case XPATH_XSLT_TREE:
 6576: 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
 6577:         case XPATH_STRING:
 6578: 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
 6579:         case XPATH_BOOLEAN:
 6580: 	    valuePush(ctxt, arg);
 6581: 	    xmlXPathBooleanFunction(ctxt, 1);
 6582: 	    valuePush(ctxt, val);
 6583: 	    return(xmlXPathCompareValues(ctxt, inf, strict));
 6584: 	default:
 6585: 	    TODO
 6586:     }
 6587:     return(0);
 6588: }
 6589: 
 6590: /**
 6591:  * xmlXPathEqualNodeSetString:
 6592:  * @arg:  the nodeset object argument
 6593:  * @str:  the string to compare to.
 6594:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
 6595:  *
 6596:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6597:  * If one object to be compared is a node-set and the other is a string,
 6598:  * then the comparison will be true if and only if there is a node in
 6599:  * the node-set such that the result of performing the comparison on the
 6600:  * string-value of the node and the other string is true.
 6601:  *
 6602:  * Returns 0 or 1 depending on the results of the test.
 6603:  */
 6604: static int
 6605: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
 6606: {
 6607:     int i;
 6608:     xmlNodeSetPtr ns;
 6609:     xmlChar *str2;
 6610:     unsigned int hash;
 6611: 
 6612:     if ((str == NULL) || (arg == NULL) ||
 6613:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6614:         return (0);
 6615:     ns = arg->nodesetval;
 6616:     /*
 6617:      * A NULL nodeset compared with a string is always false
 6618:      * (since there is no node equal, and no node not equal)
 6619:      */
 6620:     if ((ns == NULL) || (ns->nodeNr <= 0) )
 6621:         return (0);
 6622:     hash = xmlXPathStringHash(str);
 6623:     for (i = 0; i < ns->nodeNr; i++) {
 6624:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
 6625:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
 6626:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
 6627:                 xmlFree(str2);
 6628: 		if (neq)
 6629: 		    continue;
 6630:                 return (1);
 6631: 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
 6632: 		if (neq)
 6633: 		    continue;
 6634:                 return (1);
 6635:             } else if (neq) {
 6636: 		if (str2 != NULL)
 6637: 		    xmlFree(str2);
 6638: 		return (1);
 6639: 	    }
 6640:             if (str2 != NULL)
 6641:                 xmlFree(str2);
 6642:         } else if (neq)
 6643: 	    return (1);
 6644:     }
 6645:     return (0);
 6646: }
 6647: 
 6648: /**
 6649:  * xmlXPathEqualNodeSetFloat:
 6650:  * @arg:  the nodeset object argument
 6651:  * @f:  the float to compare to
 6652:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
 6653:  *
 6654:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6655:  * If one object to be compared is a node-set and the other is a number,
 6656:  * then the comparison will be true if and only if there is a node in
 6657:  * the node-set such that the result of performing the comparison on the
 6658:  * number to be compared and on the result of converting the string-value
 6659:  * of that node to a number using the number function is true.
 6660:  *
 6661:  * Returns 0 or 1 depending on the results of the test.
 6662:  */
 6663: static int
 6664: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
 6665:     xmlXPathObjectPtr arg, double f, int neq) {
 6666:   int i, ret=0;
 6667:   xmlNodeSetPtr ns;
 6668:   xmlChar *str2;
 6669:   xmlXPathObjectPtr val;
 6670:   double v;
 6671: 
 6672:     if ((arg == NULL) ||
 6673: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6674:         return(0);
 6675: 
 6676:     ns = arg->nodesetval;
 6677:     if (ns != NULL) {
 6678: 	for (i=0;i<ns->nodeNr;i++) {
 6679: 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6680: 	    if (str2 != NULL) {
 6681: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
 6682: 		xmlFree(str2);
 6683: 		xmlXPathNumberFunction(ctxt, 1);
 6684: 		val = valuePop(ctxt);
 6685: 		v = val->floatval;
 6686: 		xmlXPathReleaseObject(ctxt->context, val);
 6687: 		if (!xmlXPathIsNaN(v)) {
 6688: 		    if ((!neq) && (v==f)) {
 6689: 			ret = 1;
 6690: 			break;
 6691: 		    } else if ((neq) && (v!=f)) {
 6692: 			ret = 1;
 6693: 			break;
 6694: 		    }
 6695: 		} else {	/* NaN is unequal to any value */
 6696: 		    if (neq)
 6697: 			ret = 1;
 6698: 		}
 6699: 	    }
 6700: 	}
 6701:     }
 6702: 
 6703:     return(ret);
 6704: }
 6705: 
 6706: 
 6707: /**
 6708:  * xmlXPathEqualNodeSets:
 6709:  * @arg1:  first nodeset object argument
 6710:  * @arg2:  second nodeset object argument
 6711:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
 6712:  *
 6713:  * Implement the equal / not equal operation on XPath nodesets:
 6714:  * @arg1 == @arg2  or  @arg1 != @arg2
 6715:  * If both objects to be compared are node-sets, then the comparison
 6716:  * will be true if and only if there is a node in the first node-set and
 6717:  * a node in the second node-set such that the result of performing the
 6718:  * comparison on the string-values of the two nodes is true.
 6719:  *
 6720:  * (needless to say, this is a costly operation)
 6721:  *
 6722:  * Returns 0 or 1 depending on the results of the test.
 6723:  */
 6724: static int
 6725: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
 6726:     int i, j;
 6727:     unsigned int *hashs1;
 6728:     unsigned int *hashs2;
 6729:     xmlChar **values1;
 6730:     xmlChar **values2;
 6731:     int ret = 0;
 6732:     xmlNodeSetPtr ns1;
 6733:     xmlNodeSetPtr ns2;
 6734: 
 6735:     if ((arg1 == NULL) ||
 6736: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
 6737:         return(0);
 6738:     if ((arg2 == NULL) ||
 6739: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
 6740:         return(0);
 6741: 
 6742:     ns1 = arg1->nodesetval;
 6743:     ns2 = arg2->nodesetval;
 6744: 
 6745:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
 6746: 	return(0);
 6747:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
 6748: 	return(0);
 6749: 
 6750:     /*
 6751:      * for equal, check if there is a node pertaining to both sets
 6752:      */
 6753:     if (neq == 0)
 6754: 	for (i = 0;i < ns1->nodeNr;i++)
 6755: 	    for (j = 0;j < ns2->nodeNr;j++)
 6756: 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
 6757: 		    return(1);
 6758: 
 6759:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
 6760:     if (values1 == NULL) {
 6761:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6762: 	return(0);
 6763:     }
 6764:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
 6765:     if (hashs1 == NULL) {
 6766:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6767: 	xmlFree(values1);
 6768: 	return(0);
 6769:     }
 6770:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
 6771:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
 6772:     if (values2 == NULL) {
 6773:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6774: 	xmlFree(hashs1);
 6775: 	xmlFree(values1);
 6776: 	return(0);
 6777:     }
 6778:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
 6779:     if (hashs2 == NULL) {
 6780:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6781: 	xmlFree(hashs1);
 6782: 	xmlFree(values1);
 6783: 	xmlFree(values2);
 6784: 	return(0);
 6785:     }
 6786:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
 6787:     for (i = 0;i < ns1->nodeNr;i++) {
 6788: 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
 6789: 	for (j = 0;j < ns2->nodeNr;j++) {
 6790: 	    if (i == 0)
 6791: 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
 6792: 	    if (hashs1[i] != hashs2[j]) {
 6793: 		if (neq) {
 6794: 		    ret = 1;
 6795: 		    break;
 6796: 		}
 6797: 	    }
 6798: 	    else {
 6799: 		if (values1[i] == NULL)
 6800: 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
 6801: 		if (values2[j] == NULL)
 6802: 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
 6803: 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
 6804: 		if (ret)
 6805: 		    break;
 6806: 	    }
 6807: 	}
 6808: 	if (ret)
 6809: 	    break;
 6810:     }
 6811:     for (i = 0;i < ns1->nodeNr;i++)
 6812: 	if (values1[i] != NULL)
 6813: 	    xmlFree(values1[i]);
 6814:     for (j = 0;j < ns2->nodeNr;j++)
 6815: 	if (values2[j] != NULL)
 6816: 	    xmlFree(values2[j]);
 6817:     xmlFree(values1);
 6818:     xmlFree(values2);
 6819:     xmlFree(hashs1);
 6820:     xmlFree(hashs2);
 6821:     return(ret);
 6822: }
 6823: 
 6824: static int
 6825: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
 6826:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6827:     int ret = 0;
 6828:     /*
 6829:      *At this point we are assured neither arg1 nor arg2
 6830:      *is a nodeset, so we can just pick the appropriate routine.
 6831:      */
 6832:     switch (arg1->type) {
 6833:         case XPATH_UNDEFINED:
 6834: #ifdef DEBUG_EXPR
 6835: 	    xmlGenericError(xmlGenericErrorContext,
 6836: 		    "Equal: undefined\n");
 6837: #endif
 6838: 	    break;
 6839:         case XPATH_BOOLEAN:
 6840: 	    switch (arg2->type) {
 6841: 	        case XPATH_UNDEFINED:
 6842: #ifdef DEBUG_EXPR
 6843: 		    xmlGenericError(xmlGenericErrorContext,
 6844: 			    "Equal: undefined\n");
 6845: #endif
 6846: 		    break;
 6847: 		case XPATH_BOOLEAN:
 6848: #ifdef DEBUG_EXPR
 6849: 		    xmlGenericError(xmlGenericErrorContext,
 6850: 			    "Equal: %d boolean %d \n",
 6851: 			    arg1->boolval, arg2->boolval);
 6852: #endif
 6853: 		    ret = (arg1->boolval == arg2->boolval);
 6854: 		    break;
 6855: 		case XPATH_NUMBER:
 6856: 		    ret = (arg1->boolval ==
 6857: 			   xmlXPathCastNumberToBoolean(arg2->floatval));
 6858: 		    break;
 6859: 		case XPATH_STRING:
 6860: 		    if ((arg2->stringval == NULL) ||
 6861: 			(arg2->stringval[0] == 0)) ret = 0;
 6862: 		    else
 6863: 			ret = 1;
 6864: 		    ret = (arg1->boolval == ret);
 6865: 		    break;
 6866: 		case XPATH_USERS:
 6867: 		case XPATH_POINT:
 6868: 		case XPATH_RANGE:
 6869: 		case XPATH_LOCATIONSET:
 6870: 		    TODO
 6871: 		    break;
 6872: 		case XPATH_NODESET:
 6873: 		case XPATH_XSLT_TREE:
 6874: 		    break;
 6875: 	    }
 6876: 	    break;
 6877:         case XPATH_NUMBER:
 6878: 	    switch (arg2->type) {
 6879: 	        case XPATH_UNDEFINED:
 6880: #ifdef DEBUG_EXPR
 6881: 		    xmlGenericError(xmlGenericErrorContext,
 6882: 			    "Equal: undefined\n");
 6883: #endif
 6884: 		    break;
 6885: 		case XPATH_BOOLEAN:
 6886: 		    ret = (arg2->boolval==
 6887: 			   xmlXPathCastNumberToBoolean(arg1->floatval));
 6888: 		    break;
 6889: 		case XPATH_STRING:
 6890: 		    valuePush(ctxt, arg2);
 6891: 		    xmlXPathNumberFunction(ctxt, 1);
 6892: 		    arg2 = valuePop(ctxt);
 6893: 		    /* no break on purpose */
 6894: 		case XPATH_NUMBER:
 6895: 		    /* Hand check NaN and Infinity equalities */
 6896: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 6897: 			    xmlXPathIsNaN(arg2->floatval)) {
 6898: 		        ret = 0;
 6899: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 6900: 		        if (xmlXPathIsInf(arg2->floatval) == 1)
 6901: 			    ret = 1;
 6902: 			else
 6903: 			    ret = 0;
 6904: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 6905: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 6906: 			    ret = 1;
 6907: 			else
 6908: 			    ret = 0;
 6909: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 6910: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 6911: 			    ret = 1;
 6912: 			else
 6913: 			    ret = 0;
 6914: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 6915: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 6916: 			    ret = 1;
 6917: 			else
 6918: 			    ret = 0;
 6919: 		    } else {
 6920: 		        ret = (arg1->floatval == arg2->floatval);
 6921: 		    }
 6922: 		    break;
 6923: 		case XPATH_USERS:
 6924: 		case XPATH_POINT:
 6925: 		case XPATH_RANGE:
 6926: 		case XPATH_LOCATIONSET:
 6927: 		    TODO
 6928: 		    break;
 6929: 		case XPATH_NODESET:
 6930: 		case XPATH_XSLT_TREE:
 6931: 		    break;
 6932: 	    }
 6933: 	    break;
 6934:         case XPATH_STRING:
 6935: 	    switch (arg2->type) {
 6936: 	        case XPATH_UNDEFINED:
 6937: #ifdef DEBUG_EXPR
 6938: 		    xmlGenericError(xmlGenericErrorContext,
 6939: 			    "Equal: undefined\n");
 6940: #endif
 6941: 		    break;
 6942: 		case XPATH_BOOLEAN:
 6943: 		    if ((arg1->stringval == NULL) ||
 6944: 			(arg1->stringval[0] == 0)) ret = 0;
 6945: 		    else
 6946: 			ret = 1;
 6947: 		    ret = (arg2->boolval == ret);
 6948: 		    break;
 6949: 		case XPATH_STRING:
 6950: 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
 6951: 		    break;
 6952: 		case XPATH_NUMBER:
 6953: 		    valuePush(ctxt, arg1);
 6954: 		    xmlXPathNumberFunction(ctxt, 1);
 6955: 		    arg1 = valuePop(ctxt);
 6956: 		    /* Hand check NaN and Infinity equalities */
 6957: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 6958: 			    xmlXPathIsNaN(arg2->floatval)) {
 6959: 		        ret = 0;
 6960: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 6961: 			if (xmlXPathIsInf(arg2->floatval) == 1)
 6962: 			    ret = 1;
 6963: 			else
 6964: 			    ret = 0;
 6965: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 6966: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 6967: 			    ret = 1;
 6968: 			else
 6969: 			    ret = 0;
 6970: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 6971: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 6972: 			    ret = 1;
 6973: 			else
 6974: 			    ret = 0;
 6975: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 6976: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 6977: 			    ret = 1;
 6978: 			else
 6979: 			    ret = 0;
 6980: 		    } else {
 6981: 		        ret = (arg1->floatval == arg2->floatval);
 6982: 		    }
 6983: 		    break;
 6984: 		case XPATH_USERS:
 6985: 		case XPATH_POINT:
 6986: 		case XPATH_RANGE:
 6987: 		case XPATH_LOCATIONSET:
 6988: 		    TODO
 6989: 		    break;
 6990: 		case XPATH_NODESET:
 6991: 		case XPATH_XSLT_TREE:
 6992: 		    break;
 6993: 	    }
 6994: 	    break;
 6995:         case XPATH_USERS:
 6996: 	case XPATH_POINT:
 6997: 	case XPATH_RANGE:
 6998: 	case XPATH_LOCATIONSET:
 6999: 	    TODO
 7000: 	    break;
 7001: 	case XPATH_NODESET:
 7002: 	case XPATH_XSLT_TREE:
 7003: 	    break;
 7004:     }
 7005:     xmlXPathReleaseObject(ctxt->context, arg1);
 7006:     xmlXPathReleaseObject(ctxt->context, arg2);
 7007:     return(ret);
 7008: }
 7009: 
 7010: /**
 7011:  * xmlXPathEqualValues:
 7012:  * @ctxt:  the XPath Parser context
 7013:  *
 7014:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7015:  *
 7016:  * Returns 0 or 1 depending on the results of the test.
 7017:  */
 7018: int
 7019: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
 7020:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7021:     int ret = 0;
 7022: 
 7023:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7024:     arg2 = valuePop(ctxt);
 7025:     arg1 = valuePop(ctxt);
 7026:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7027: 	if (arg1 != NULL)
 7028: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7029: 	else
 7030: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7031: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7032:     }
 7033: 
 7034:     if (arg1 == arg2) {
 7035: #ifdef DEBUG_EXPR
 7036:         xmlGenericError(xmlGenericErrorContext,
 7037: 		"Equal: by pointer\n");
 7038: #endif
 7039: 	xmlXPathFreeObject(arg1);
 7040:         return(1);
 7041:     }
 7042: 
 7043:     /*
 7044:      *If either argument is a nodeset, it's a 'special case'
 7045:      */
 7046:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7047:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7048: 	/*
 7049: 	 *Hack it to assure arg1 is the nodeset
 7050: 	 */
 7051: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7052: 		argtmp = arg2;
 7053: 		arg2 = arg1;
 7054: 		arg1 = argtmp;
 7055: 	}
 7056: 	switch (arg2->type) {
 7057: 	    case XPATH_UNDEFINED:
 7058: #ifdef DEBUG_EXPR
 7059: 		xmlGenericError(xmlGenericErrorContext,
 7060: 			"Equal: undefined\n");
 7061: #endif
 7062: 		break;
 7063: 	    case XPATH_NODESET:
 7064: 	    case XPATH_XSLT_TREE:
 7065: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
 7066: 		break;
 7067: 	    case XPATH_BOOLEAN:
 7068: 		if ((arg1->nodesetval == NULL) ||
 7069: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7070: 		else
 7071: 		    ret = 1;
 7072: 		ret = (ret == arg2->boolval);
 7073: 		break;
 7074: 	    case XPATH_NUMBER:
 7075: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
 7076: 		break;
 7077: 	    case XPATH_STRING:
 7078: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
 7079: 		break;
 7080: 	    case XPATH_USERS:
 7081: 	    case XPATH_POINT:
 7082: 	    case XPATH_RANGE:
 7083: 	    case XPATH_LOCATIONSET:
 7084: 		TODO
 7085: 		break;
 7086: 	}
 7087: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7088: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7089: 	return(ret);
 7090:     }
 7091: 
 7092:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7093: }
 7094: 
 7095: /**
 7096:  * xmlXPathNotEqualValues:
 7097:  * @ctxt:  the XPath Parser context
 7098:  *
 7099:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7100:  *
 7101:  * Returns 0 or 1 depending on the results of the test.
 7102:  */
 7103: int
 7104: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
 7105:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7106:     int ret = 0;
 7107: 
 7108:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7109:     arg2 = valuePop(ctxt);
 7110:     arg1 = valuePop(ctxt);
 7111:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7112: 	if (arg1 != NULL)
 7113: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7114: 	else
 7115: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7116: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7117:     }
 7118: 
 7119:     if (arg1 == arg2) {
 7120: #ifdef DEBUG_EXPR
 7121:         xmlGenericError(xmlGenericErrorContext,
 7122: 		"NotEqual: by pointer\n");
 7123: #endif
 7124: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7125:         return(0);
 7126:     }
 7127: 
 7128:     /*
 7129:      *If either argument is a nodeset, it's a 'special case'
 7130:      */
 7131:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7132:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7133: 	/*
 7134: 	 *Hack it to assure arg1 is the nodeset
 7135: 	 */
 7136: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7137: 		argtmp = arg2;
 7138: 		arg2 = arg1;
 7139: 		arg1 = argtmp;
 7140: 	}
 7141: 	switch (arg2->type) {
 7142: 	    case XPATH_UNDEFINED:
 7143: #ifdef DEBUG_EXPR
 7144: 		xmlGenericError(xmlGenericErrorContext,
 7145: 			"NotEqual: undefined\n");
 7146: #endif
 7147: 		break;
 7148: 	    case XPATH_NODESET:
 7149: 	    case XPATH_XSLT_TREE:
 7150: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
 7151: 		break;
 7152: 	    case XPATH_BOOLEAN:
 7153: 		if ((arg1->nodesetval == NULL) ||
 7154: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7155: 		else
 7156: 		    ret = 1;
 7157: 		ret = (ret != arg2->boolval);
 7158: 		break;
 7159: 	    case XPATH_NUMBER:
 7160: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
 7161: 		break;
 7162: 	    case XPATH_STRING:
 7163: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
 7164: 		break;
 7165: 	    case XPATH_USERS:
 7166: 	    case XPATH_POINT:
 7167: 	    case XPATH_RANGE:
 7168: 	    case XPATH_LOCATIONSET:
 7169: 		TODO
 7170: 		break;
 7171: 	}
 7172: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7173: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7174: 	return(ret);
 7175:     }
 7176: 
 7177:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7178: }
 7179: 
 7180: /**
 7181:  * xmlXPathCompareValues:
 7182:  * @ctxt:  the XPath Parser context
 7183:  * @inf:  less than (1) or greater than (0)
 7184:  * @strict:  is the comparison strict
 7185:  *
 7186:  * Implement the compare operation on XPath objects:
 7187:  *     @arg1 < @arg2    (1, 1, ...
 7188:  *     @arg1 <= @arg2   (1, 0, ...
 7189:  *     @arg1 > @arg2    (0, 1, ...
 7190:  *     @arg1 >= @arg2   (0, 0, ...
 7191:  *
 7192:  * When neither object to be compared is a node-set and the operator is
 7193:  * <=, <, >=, >, then the objects are compared by converted both objects
 7194:  * to numbers and comparing the numbers according to IEEE 754. The <
 7195:  * comparison will be true if and only if the first number is less than the
 7196:  * second number. The <= comparison will be true if and only if the first
 7197:  * number is less than or equal to the second number. The > comparison
 7198:  * will be true if and only if the first number is greater than the second
 7199:  * number. The >= comparison will be true if and only if the first number
 7200:  * is greater than or equal to the second number.
 7201:  *
 7202:  * Returns 1 if the comparison succeeded, 0 if it failed
 7203:  */
 7204: int
 7205: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
 7206:     int ret = 0, arg1i = 0, arg2i = 0;
 7207:     xmlXPathObjectPtr arg1, arg2;
 7208: 
 7209:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7210:     arg2 = valuePop(ctxt);
 7211:     arg1 = valuePop(ctxt);
 7212:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7213: 	if (arg1 != NULL)
 7214: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7215: 	else
 7216: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7217: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7218:     }
 7219: 
 7220:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7221:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7222: 	/*
 7223: 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
 7224: 	 * are not freed from within this routine; they will be freed from the
 7225: 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
 7226: 	 */
 7227: 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
 7228: 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
 7229: 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
 7230: 	} else {
 7231: 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7232: 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
 7233: 			                          arg1, arg2);
 7234: 	    } else {
 7235: 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
 7236: 			                          arg2, arg1);
 7237: 	    }
 7238: 	}
 7239: 	return(ret);
 7240:     }
 7241: 
 7242:     if (arg1->type != XPATH_NUMBER) {
 7243: 	valuePush(ctxt, arg1);
 7244: 	xmlXPathNumberFunction(ctxt, 1);
 7245: 	arg1 = valuePop(ctxt);
 7246:     }
 7247:     if (arg1->type != XPATH_NUMBER) {
 7248: 	xmlXPathFreeObject(arg1);
 7249: 	xmlXPathFreeObject(arg2);
 7250: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7251:     }
 7252:     if (arg2->type != XPATH_NUMBER) {
 7253: 	valuePush(ctxt, arg2);
 7254: 	xmlXPathNumberFunction(ctxt, 1);
 7255: 	arg2 = valuePop(ctxt);
 7256:     }
 7257:     if (arg2->type != XPATH_NUMBER) {
 7258: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7259: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7260: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7261:     }
 7262:     /*
 7263:      * Add tests for infinity and nan
 7264:      * => feedback on 3.4 for Inf and NaN
 7265:      */
 7266:     /* Hand check NaN and Infinity comparisons */
 7267:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
 7268: 	ret=0;
 7269:     } else {
 7270: 	arg1i=xmlXPathIsInf(arg1->floatval);
 7271: 	arg2i=xmlXPathIsInf(arg2->floatval);
 7272: 	if (inf && strict) {
 7273: 	    if ((arg1i == -1 && arg2i != -1) ||
 7274: 		(arg2i == 1 && arg1i != 1)) {
 7275: 		ret = 1;
 7276: 	    } else if (arg1i == 0 && arg2i == 0) {
 7277: 		ret = (arg1->floatval < arg2->floatval);
 7278: 	    } else {
 7279: 		ret = 0;
 7280: 	    }
 7281: 	}
 7282: 	else if (inf && !strict) {
 7283: 	    if (arg1i == -1 || arg2i == 1) {
 7284: 		ret = 1;
 7285: 	    } else if (arg1i == 0 && arg2i == 0) {
 7286: 		ret = (arg1->floatval <= arg2->floatval);
 7287: 	    } else {
 7288: 		ret = 0;
 7289: 	    }
 7290: 	}
 7291: 	else if (!inf && strict) {
 7292: 	    if ((arg1i == 1 && arg2i != 1) ||
 7293: 		(arg2i == -1 && arg1i != -1)) {
 7294: 		ret = 1;
 7295: 	    } else if (arg1i == 0 && arg2i == 0) {
 7296: 		ret = (arg1->floatval > arg2->floatval);
 7297: 	    } else {
 7298: 		ret = 0;
 7299: 	    }
 7300: 	}
 7301: 	else if (!inf && !strict) {
 7302: 	    if (arg1i == 1 || arg2i == -1) {
 7303: 		ret = 1;
 7304: 	    } else if (arg1i == 0 && arg2i == 0) {
 7305: 		ret = (arg1->floatval >= arg2->floatval);
 7306: 	    } else {
 7307: 		ret = 0;
 7308: 	    }
 7309: 	}
 7310:     }
 7311:     xmlXPathReleaseObject(ctxt->context, arg1);
 7312:     xmlXPathReleaseObject(ctxt->context, arg2);
 7313:     return(ret);
 7314: }
 7315: 
 7316: /**
 7317:  * xmlXPathValueFlipSign:
 7318:  * @ctxt:  the XPath Parser context
 7319:  *
 7320:  * Implement the unary - operation on an XPath object
 7321:  * The numeric operators convert their operands to numbers as if
 7322:  * by calling the number function.
 7323:  */
 7324: void
 7325: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
 7326:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
 7327:     CAST_TO_NUMBER;
 7328:     CHECK_TYPE(XPATH_NUMBER);
 7329:     if (xmlXPathIsNaN(ctxt->value->floatval))
 7330:         ctxt->value->floatval=xmlXPathNAN;
 7331:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
 7332:         ctxt->value->floatval=xmlXPathNINF;
 7333:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
 7334:         ctxt->value->floatval=xmlXPathPINF;
 7335:     else if (ctxt->value->floatval == 0) {
 7336:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
 7337: 	    ctxt->value->floatval = xmlXPathNZERO;
 7338: 	else
 7339: 	    ctxt->value->floatval = 0;
 7340:     }
 7341:     else
 7342:         ctxt->value->floatval = - ctxt->value->floatval;
 7343: }
 7344: 
 7345: /**
 7346:  * xmlXPathAddValues:
 7347:  * @ctxt:  the XPath Parser context
 7348:  *
 7349:  * Implement the add operation on XPath objects:
 7350:  * The numeric operators convert their operands to numbers as if
 7351:  * by calling the number function.
 7352:  */
 7353: void
 7354: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
 7355:     xmlXPathObjectPtr arg;
 7356:     double val;
 7357: 
 7358:     arg = valuePop(ctxt);
 7359:     if (arg == NULL)
 7360: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7361:     val = xmlXPathCastToNumber(arg);
 7362:     xmlXPathReleaseObject(ctxt->context, arg);
 7363:     CAST_TO_NUMBER;
 7364:     CHECK_TYPE(XPATH_NUMBER);
 7365:     ctxt->value->floatval += val;
 7366: }
 7367: 
 7368: /**
 7369:  * xmlXPathSubValues:
 7370:  * @ctxt:  the XPath Parser context
 7371:  *
 7372:  * Implement the subtraction operation on XPath objects:
 7373:  * The numeric operators convert their operands to numbers as if
 7374:  * by calling the number function.
 7375:  */
 7376: void
 7377: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
 7378:     xmlXPathObjectPtr arg;
 7379:     double val;
 7380: 
 7381:     arg = valuePop(ctxt);
 7382:     if (arg == NULL)
 7383: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7384:     val = xmlXPathCastToNumber(arg);
 7385:     xmlXPathReleaseObject(ctxt->context, arg);
 7386:     CAST_TO_NUMBER;
 7387:     CHECK_TYPE(XPATH_NUMBER);
 7388:     ctxt->value->floatval -= val;
 7389: }
 7390: 
 7391: /**
 7392:  * xmlXPathMultValues:
 7393:  * @ctxt:  the XPath Parser context
 7394:  *
 7395:  * Implement the multiply operation on XPath objects:
 7396:  * The numeric operators convert their operands to numbers as if
 7397:  * by calling the number function.
 7398:  */
 7399: void
 7400: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
 7401:     xmlXPathObjectPtr arg;
 7402:     double val;
 7403: 
 7404:     arg = valuePop(ctxt);
 7405:     if (arg == NULL)
 7406: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7407:     val = xmlXPathCastToNumber(arg);
 7408:     xmlXPathReleaseObject(ctxt->context, arg);
 7409:     CAST_TO_NUMBER;
 7410:     CHECK_TYPE(XPATH_NUMBER);
 7411:     ctxt->value->floatval *= val;
 7412: }
 7413: 
 7414: /**
 7415:  * xmlXPathDivValues:
 7416:  * @ctxt:  the XPath Parser context
 7417:  *
 7418:  * Implement the div operation on XPath objects @arg1 / @arg2:
 7419:  * The numeric operators convert their operands to numbers as if
 7420:  * by calling the number function.
 7421:  */
 7422: void
 7423: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
 7424:     xmlXPathObjectPtr arg;
 7425:     double val;
 7426: 
 7427:     arg = valuePop(ctxt);
 7428:     if (arg == NULL)
 7429: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7430:     val = xmlXPathCastToNumber(arg);
 7431:     xmlXPathReleaseObject(ctxt->context, arg);
 7432:     CAST_TO_NUMBER;
 7433:     CHECK_TYPE(XPATH_NUMBER);
 7434:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
 7435: 	ctxt->value->floatval = xmlXPathNAN;
 7436:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
 7437: 	if (ctxt->value->floatval == 0)
 7438: 	    ctxt->value->floatval = xmlXPathNAN;
 7439: 	else if (ctxt->value->floatval > 0)
 7440: 	    ctxt->value->floatval = xmlXPathNINF;
 7441: 	else if (ctxt->value->floatval < 0)
 7442: 	    ctxt->value->floatval = xmlXPathPINF;
 7443:     }
 7444:     else if (val == 0) {
 7445: 	if (ctxt->value->floatval == 0)
 7446: 	    ctxt->value->floatval = xmlXPathNAN;
 7447: 	else if (ctxt->value->floatval > 0)
 7448: 	    ctxt->value->floatval = xmlXPathPINF;
 7449: 	else if (ctxt->value->floatval < 0)
 7450: 	    ctxt->value->floatval = xmlXPathNINF;
 7451:     } else
 7452: 	ctxt->value->floatval /= val;
 7453: }
 7454: 
 7455: /**
 7456:  * xmlXPathModValues:
 7457:  * @ctxt:  the XPath Parser context
 7458:  *
 7459:  * Implement the mod operation on XPath objects: @arg1 / @arg2
 7460:  * The numeric operators convert their operands to numbers as if
 7461:  * by calling the number function.
 7462:  */
 7463: void
 7464: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
 7465:     xmlXPathObjectPtr arg;
 7466:     double arg1, arg2;
 7467: 
 7468:     arg = valuePop(ctxt);
 7469:     if (arg == NULL)
 7470: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7471:     arg2 = xmlXPathCastToNumber(arg);
 7472:     xmlXPathReleaseObject(ctxt->context, arg);
 7473:     CAST_TO_NUMBER;
 7474:     CHECK_TYPE(XPATH_NUMBER);
 7475:     arg1 = ctxt->value->floatval;
 7476:     if (arg2 == 0)
 7477: 	ctxt->value->floatval = xmlXPathNAN;
 7478:     else {
 7479: 	ctxt->value->floatval = fmod(arg1, arg2);
 7480:     }
 7481: }
 7482: 
 7483: /************************************************************************
 7484:  *									*
 7485:  *		The traversal functions					*
 7486:  *									*
 7487:  ************************************************************************/
 7488: 
 7489: /*
 7490:  * A traversal function enumerates nodes along an axis.
 7491:  * Initially it must be called with NULL, and it indicates
 7492:  * termination on the axis by returning NULL.
 7493:  */
 7494: typedef xmlNodePtr (*xmlXPathTraversalFunction)
 7495:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
 7496: 
 7497: /*
 7498:  * xmlXPathTraversalFunctionExt:
 7499:  * A traversal function enumerates nodes along an axis.
 7500:  * Initially it must be called with NULL, and it indicates
 7501:  * termination on the axis by returning NULL.
 7502:  * The context node of the traversal is specified via @contextNode.
 7503:  */
 7504: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
 7505:                     (xmlNodePtr cur, xmlNodePtr contextNode);
 7506: 
 7507: /*
 7508:  * xmlXPathNodeSetMergeFunction:
 7509:  * Used for merging node sets in xmlXPathCollectAndTest().
 7510:  */
 7511: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
 7512: 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
 7513: 
 7514: 
 7515: /**
 7516:  * xmlXPathNextSelf:
 7517:  * @ctxt:  the XPath Parser context
 7518:  * @cur:  the current node in the traversal
 7519:  *
 7520:  * Traversal function for the "self" direction
 7521:  * The self axis contains just the context node itself
 7522:  *
 7523:  * Returns the next element following that axis
 7524:  */
 7525: xmlNodePtr
 7526: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7527:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7528:     if (cur == NULL)
 7529:         return(ctxt->context->node);
 7530:     return(NULL);
 7531: }
 7532: 
 7533: /**
 7534:  * xmlXPathNextChild:
 7535:  * @ctxt:  the XPath Parser context
 7536:  * @cur:  the current node in the traversal
 7537:  *
 7538:  * Traversal function for the "child" direction
 7539:  * The child axis contains the children of the context node in document order.
 7540:  *
 7541:  * Returns the next element following that axis
 7542:  */
 7543: xmlNodePtr
 7544: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7545:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7546:     if (cur == NULL) {
 7547: 	if (ctxt->context->node == NULL) return(NULL);
 7548: 	switch (ctxt->context->node->type) {
 7549:             case XML_ELEMENT_NODE:
 7550:             case XML_TEXT_NODE:
 7551:             case XML_CDATA_SECTION_NODE:
 7552:             case XML_ENTITY_REF_NODE:
 7553:             case XML_ENTITY_NODE:
 7554:             case XML_PI_NODE:
 7555:             case XML_COMMENT_NODE:
 7556:             case XML_NOTATION_NODE:
 7557:             case XML_DTD_NODE:
 7558: 		return(ctxt->context->node->children);
 7559:             case XML_DOCUMENT_NODE:
 7560:             case XML_DOCUMENT_TYPE_NODE:
 7561:             case XML_DOCUMENT_FRAG_NODE:
 7562:             case XML_HTML_DOCUMENT_NODE:
 7563: #ifdef LIBXML_DOCB_ENABLED
 7564: 	    case XML_DOCB_DOCUMENT_NODE:
 7565: #endif
 7566: 		return(((xmlDocPtr) ctxt->context->node)->children);
 7567: 	    case XML_ELEMENT_DECL:
 7568: 	    case XML_ATTRIBUTE_DECL:
 7569: 	    case XML_ENTITY_DECL:
 7570:             case XML_ATTRIBUTE_NODE:
 7571: 	    case XML_NAMESPACE_DECL:
 7572: 	    case XML_XINCLUDE_START:
 7573: 	    case XML_XINCLUDE_END:
 7574: 		return(NULL);
 7575: 	}
 7576: 	return(NULL);
 7577:     }
 7578:     if ((cur->type == XML_DOCUMENT_NODE) ||
 7579:         (cur->type == XML_HTML_DOCUMENT_NODE))
 7580: 	return(NULL);
 7581:     return(cur->next);
 7582: }
 7583: 
 7584: /**
 7585:  * xmlXPathNextChildElement:
 7586:  * @ctxt:  the XPath Parser context
 7587:  * @cur:  the current node in the traversal
 7588:  *
 7589:  * Traversal function for the "child" direction and nodes of type element.
 7590:  * The child axis contains the children of the context node in document order.
 7591:  *
 7592:  * Returns the next element following that axis
 7593:  */
 7594: static xmlNodePtr
 7595: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7596:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7597:     if (cur == NULL) {
 7598: 	cur = ctxt->context->node;
 7599: 	if (cur == NULL) return(NULL);
 7600: 	/*
 7601: 	* Get the first element child.
 7602: 	*/
 7603: 	switch (cur->type) {
 7604:             case XML_ELEMENT_NODE:
 7605: 	    case XML_DOCUMENT_FRAG_NODE:
 7606: 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
 7607:             case XML_ENTITY_NODE:
 7608: 		cur = cur->children;
 7609: 		if (cur != NULL) {
 7610: 		    if (cur->type == XML_ELEMENT_NODE)
 7611: 			return(cur);
 7612: 		    do {
 7613: 			cur = cur->next;
 7614: 		    } while ((cur != NULL) &&
 7615: 			(cur->type != XML_ELEMENT_NODE));
 7616: 		    return(cur);
 7617: 		}
 7618: 		return(NULL);
 7619:             case XML_DOCUMENT_NODE:
 7620:             case XML_HTML_DOCUMENT_NODE:
 7621: #ifdef LIBXML_DOCB_ENABLED
 7622: 	    case XML_DOCB_DOCUMENT_NODE:
 7623: #endif
 7624: 		return(xmlDocGetRootElement((xmlDocPtr) cur));
 7625: 	    default:
 7626: 		return(NULL);
 7627: 	}
 7628: 	return(NULL);
 7629:     }
 7630:     /*
 7631:     * Get the next sibling element node.
 7632:     */
 7633:     switch (cur->type) {
 7634: 	case XML_ELEMENT_NODE:
 7635: 	case XML_TEXT_NODE:
 7636: 	case XML_ENTITY_REF_NODE:
 7637: 	case XML_ENTITY_NODE:
 7638: 	case XML_CDATA_SECTION_NODE:
 7639: 	case XML_PI_NODE:
 7640: 	case XML_COMMENT_NODE:
 7641: 	case XML_XINCLUDE_END:
 7642: 	    break;
 7643: 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
 7644: 	default:
 7645: 	    return(NULL);
 7646:     }
 7647:     if (cur->next != NULL) {
 7648: 	if (cur->next->type == XML_ELEMENT_NODE)
 7649: 	    return(cur->next);
 7650: 	cur = cur->next;
 7651: 	do {
 7652: 	    cur = cur->next;
 7653: 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
 7654: 	return(cur);
 7655:     }
 7656:     return(NULL);
 7657: }
 7658: 
 7659: /**
 7660:  * xmlXPathNextDescendantOrSelfElemParent:
 7661:  * @ctxt:  the XPath Parser context
 7662:  * @cur:  the current node in the traversal
 7663:  *
 7664:  * Traversal function for the "descendant-or-self" axis.
 7665:  * Additionally it returns only nodes which can be parents of
 7666:  * element nodes.
 7667:  *
 7668:  *
 7669:  * Returns the next element following that axis
 7670:  */
 7671: static xmlNodePtr
 7672: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
 7673: 				       xmlNodePtr contextNode)
 7674: {
 7675:     if (cur == NULL) {
 7676: 	if (contextNode == NULL)
 7677: 	    return(NULL);
 7678: 	switch (contextNode->type) {
 7679: 	    case XML_ELEMENT_NODE:
 7680: 	    case XML_XINCLUDE_START:
 7681: 	    case XML_DOCUMENT_FRAG_NODE:
 7682: 	    case XML_DOCUMENT_NODE:
 7683: #ifdef LIBXML_DOCB_ENABLED
 7684: 	    case XML_DOCB_DOCUMENT_NODE:
 7685: #endif
 7686: 	    case XML_HTML_DOCUMENT_NODE:	    
 7687: 		return(contextNode);
 7688: 	    default:
 7689: 		return(NULL);
 7690: 	}
 7691: 	return(NULL);
 7692:     } else {
 7693: 	xmlNodePtr start = cur;
 7694: 
 7695: 	while (cur != NULL) {
 7696: 	    switch (cur->type) {
 7697: 		case XML_ELEMENT_NODE:
 7698: 		/* TODO: OK to have XInclude here? */
 7699: 		case XML_XINCLUDE_START:
 7700: 		case XML_DOCUMENT_FRAG_NODE:
 7701: 		    if (cur != start)
 7702: 			return(cur);
 7703: 		    if (cur->children != NULL) {
 7704: 			cur = cur->children;
 7705: 			continue;
 7706: 		    }
 7707: 		    break;
 7708: 		/* Not sure if we need those here. */
 7709: 		case XML_DOCUMENT_NODE:
 7710: #ifdef LIBXML_DOCB_ENABLED
 7711: 		case XML_DOCB_DOCUMENT_NODE:
 7712: #endif
 7713: 		case XML_HTML_DOCUMENT_NODE:
 7714: 		    if (cur != start)
 7715: 			return(cur);
 7716: 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
 7717: 		default:
 7718: 		    break;
 7719: 	    }
 7720: 
 7721: next_sibling:
 7722: 	    if ((cur == NULL) || (cur == contextNode))
 7723: 		return(NULL);
 7724: 	    if (cur->next != NULL) {
 7725: 		cur = cur->next;
 7726: 	    } else {
 7727: 		cur = cur->parent;
 7728: 		goto next_sibling;
 7729: 	    }
 7730: 	}
 7731:     }
 7732:     return(NULL);
 7733: }
 7734: 
 7735: /**
 7736:  * xmlXPathNextDescendant:
 7737:  * @ctxt:  the XPath Parser context
 7738:  * @cur:  the current node in the traversal
 7739:  *
 7740:  * Traversal function for the "descendant" direction
 7741:  * the descendant axis contains the descendants of the context node in document
 7742:  * order; a descendant is a child or a child of a child and so on.
 7743:  *
 7744:  * Returns the next element following that axis
 7745:  */
 7746: xmlNodePtr
 7747: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7748:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7749:     if (cur == NULL) {
 7750: 	if (ctxt->context->node == NULL)
 7751: 	    return(NULL);
 7752: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7753: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7754: 	    return(NULL);
 7755: 
 7756:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 7757: 	    return(ctxt->context->doc->children);
 7758:         return(ctxt->context->node->children);
 7759:     }
 7760: 
 7761:     if (cur->children != NULL) {
 7762: 	/*
 7763: 	 * Do not descend on entities declarations
 7764: 	 */
 7765: 	if (cur->children->type != XML_ENTITY_DECL) {
 7766: 	    cur = cur->children;
 7767: 	    /*
 7768: 	     * Skip DTDs
 7769: 	     */
 7770: 	    if (cur->type != XML_DTD_NODE)
 7771: 		return(cur);
 7772: 	}
 7773:     }
 7774: 
 7775:     if (cur == ctxt->context->node) return(NULL);
 7776: 
 7777:     while (cur->next != NULL) {
 7778: 	cur = cur->next;
 7779: 	if ((cur->type != XML_ENTITY_DECL) &&
 7780: 	    (cur->type != XML_DTD_NODE))
 7781: 	    return(cur);
 7782:     }
 7783: 
 7784:     do {
 7785:         cur = cur->parent;
 7786: 	if (cur == NULL) break;
 7787: 	if (cur == ctxt->context->node) return(NULL);
 7788: 	if (cur->next != NULL) {
 7789: 	    cur = cur->next;
 7790: 	    return(cur);
 7791: 	}
 7792:     } while (cur != NULL);
 7793:     return(cur);
 7794: }
 7795: 
 7796: /**
 7797:  * xmlXPathNextDescendantOrSelf:
 7798:  * @ctxt:  the XPath Parser context
 7799:  * @cur:  the current node in the traversal
 7800:  *
 7801:  * Traversal function for the "descendant-or-self" direction
 7802:  * the descendant-or-self axis contains the context node and the descendants
 7803:  * of the context node in document order; thus the context node is the first
 7804:  * node on the axis, and the first child of the context node is the second node
 7805:  * on the axis
 7806:  *
 7807:  * Returns the next element following that axis
 7808:  */
 7809: xmlNodePtr
 7810: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7811:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7812:     if (cur == NULL) {
 7813: 	if (ctxt->context->node == NULL)
 7814: 	    return(NULL);
 7815: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7816: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7817: 	    return(NULL);
 7818:         return(ctxt->context->node);
 7819:     }
 7820: 
 7821:     return(xmlXPathNextDescendant(ctxt, cur));
 7822: }
 7823: 
 7824: /**
 7825:  * xmlXPathNextParent:
 7826:  * @ctxt:  the XPath Parser context
 7827:  * @cur:  the current node in the traversal
 7828:  *
 7829:  * Traversal function for the "parent" direction
 7830:  * The parent axis contains the parent of the context node, if there is one.
 7831:  *
 7832:  * Returns the next element following that axis
 7833:  */
 7834: xmlNodePtr
 7835: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7836:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7837:     /*
 7838:      * the parent of an attribute or namespace node is the element
 7839:      * to which the attribute or namespace node is attached
 7840:      * Namespace handling !!!
 7841:      */
 7842:     if (cur == NULL) {
 7843: 	if (ctxt->context->node == NULL) return(NULL);
 7844: 	switch (ctxt->context->node->type) {
 7845:             case XML_ELEMENT_NODE:
 7846:             case XML_TEXT_NODE:
 7847:             case XML_CDATA_SECTION_NODE:
 7848:             case XML_ENTITY_REF_NODE:
 7849:             case XML_ENTITY_NODE:
 7850:             case XML_PI_NODE:
 7851:             case XML_COMMENT_NODE:
 7852:             case XML_NOTATION_NODE:
 7853:             case XML_DTD_NODE:
 7854: 	    case XML_ELEMENT_DECL:
 7855: 	    case XML_ATTRIBUTE_DECL:
 7856: 	    case XML_XINCLUDE_START:
 7857: 	    case XML_XINCLUDE_END:
 7858: 	    case XML_ENTITY_DECL:
 7859: 		if (ctxt->context->node->parent == NULL)
 7860: 		    return((xmlNodePtr) ctxt->context->doc);
 7861: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 7862: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 7863: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 7864: 				 BAD_CAST "fake node libxslt"))))
 7865: 		    return(NULL);
 7866: 		return(ctxt->context->node->parent);
 7867:             case XML_ATTRIBUTE_NODE: {
 7868: 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 7869: 
 7870: 		return(att->parent);
 7871: 	    }
 7872:             case XML_DOCUMENT_NODE:
 7873:             case XML_DOCUMENT_TYPE_NODE:
 7874:             case XML_DOCUMENT_FRAG_NODE:
 7875:             case XML_HTML_DOCUMENT_NODE:
 7876: #ifdef LIBXML_DOCB_ENABLED
 7877: 	    case XML_DOCB_DOCUMENT_NODE:
 7878: #endif
 7879:                 return(NULL);
 7880: 	    case XML_NAMESPACE_DECL: {
 7881: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 7882: 
 7883: 		if ((ns->next != NULL) &&
 7884: 		    (ns->next->type != XML_NAMESPACE_DECL))
 7885: 		    return((xmlNodePtr) ns->next);
 7886:                 return(NULL);
 7887: 	    }
 7888: 	}
 7889:     }
 7890:     return(NULL);
 7891: }
 7892: 
 7893: /**
 7894:  * xmlXPathNextAncestor:
 7895:  * @ctxt:  the XPath Parser context
 7896:  * @cur:  the current node in the traversal
 7897:  *
 7898:  * Traversal function for the "ancestor" direction
 7899:  * the ancestor axis contains the ancestors of the context node; the ancestors
 7900:  * of the context node consist of the parent of context node and the parent's
 7901:  * parent and so on; the nodes are ordered in reverse document order; thus the
 7902:  * parent is the first node on the axis, and the parent's parent is the second
 7903:  * node on the axis
 7904:  *
 7905:  * Returns the next element following that axis
 7906:  */
 7907: xmlNodePtr
 7908: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7909:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7910:     /*
 7911:      * the parent of an attribute or namespace node is the element
 7912:      * to which the attribute or namespace node is attached
 7913:      * !!!!!!!!!!!!!
 7914:      */
 7915:     if (cur == NULL) {
 7916: 	if (ctxt->context->node == NULL) return(NULL);
 7917: 	switch (ctxt->context->node->type) {
 7918:             case XML_ELEMENT_NODE:
 7919:             case XML_TEXT_NODE:
 7920:             case XML_CDATA_SECTION_NODE:
 7921:             case XML_ENTITY_REF_NODE:
 7922:             case XML_ENTITY_NODE:
 7923:             case XML_PI_NODE:
 7924:             case XML_COMMENT_NODE:
 7925: 	    case XML_DTD_NODE:
 7926: 	    case XML_ELEMENT_DECL:
 7927: 	    case XML_ATTRIBUTE_DECL:
 7928: 	    case XML_ENTITY_DECL:
 7929:             case XML_NOTATION_NODE:
 7930: 	    case XML_XINCLUDE_START:
 7931: 	    case XML_XINCLUDE_END:
 7932: 		if (ctxt->context->node->parent == NULL)
 7933: 		    return((xmlNodePtr) ctxt->context->doc);
 7934: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 7935: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 7936: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 7937: 				 BAD_CAST "fake node libxslt"))))
 7938: 		    return(NULL);
 7939: 		return(ctxt->context->node->parent);
 7940:             case XML_ATTRIBUTE_NODE: {
 7941: 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
 7942: 
 7943: 		return(tmp->parent);
 7944: 	    }
 7945:             case XML_DOCUMENT_NODE:
 7946:             case XML_DOCUMENT_TYPE_NODE:
 7947:             case XML_DOCUMENT_FRAG_NODE:
 7948:             case XML_HTML_DOCUMENT_NODE:
 7949: #ifdef LIBXML_DOCB_ENABLED
 7950: 	    case XML_DOCB_DOCUMENT_NODE:
 7951: #endif
 7952:                 return(NULL);
 7953: 	    case XML_NAMESPACE_DECL: {
 7954: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 7955: 
 7956: 		if ((ns->next != NULL) &&
 7957: 		    (ns->next->type != XML_NAMESPACE_DECL))
 7958: 		    return((xmlNodePtr) ns->next);
 7959: 		/* Bad, how did that namespace end up here ? */
 7960:                 return(NULL);
 7961: 	    }
 7962: 	}
 7963: 	return(NULL);
 7964:     }
 7965:     if (cur == ctxt->context->doc->children)
 7966: 	return((xmlNodePtr) ctxt->context->doc);
 7967:     if (cur == (xmlNodePtr) ctxt->context->doc)
 7968: 	return(NULL);
 7969:     switch (cur->type) {
 7970: 	case XML_ELEMENT_NODE:
 7971: 	case XML_TEXT_NODE:
 7972: 	case XML_CDATA_SECTION_NODE:
 7973: 	case XML_ENTITY_REF_NODE:
 7974: 	case XML_ENTITY_NODE:
 7975: 	case XML_PI_NODE:
 7976: 	case XML_COMMENT_NODE:
 7977: 	case XML_NOTATION_NODE:
 7978: 	case XML_DTD_NODE:
 7979:         case XML_ELEMENT_DECL:
 7980:         case XML_ATTRIBUTE_DECL:
 7981:         case XML_ENTITY_DECL:
 7982: 	case XML_XINCLUDE_START:
 7983: 	case XML_XINCLUDE_END:
 7984: 	    if (cur->parent == NULL)
 7985: 		return(NULL);
 7986: 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
 7987: 		((cur->parent->name[0] == ' ') ||
 7988: 		 (xmlStrEqual(cur->parent->name,
 7989: 			      BAD_CAST "fake node libxslt"))))
 7990: 		return(NULL);
 7991: 	    return(cur->parent);
 7992: 	case XML_ATTRIBUTE_NODE: {
 7993: 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 7994: 
 7995: 	    return(att->parent);
 7996: 	}
 7997: 	case XML_NAMESPACE_DECL: {
 7998: 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 7999: 
 8000: 	    if ((ns->next != NULL) &&
 8001: 	        (ns->next->type != XML_NAMESPACE_DECL))
 8002: 	        return((xmlNodePtr) ns->next);
 8003: 	    /* Bad, how did that namespace end up here ? */
 8004:             return(NULL);
 8005: 	}
 8006: 	case XML_DOCUMENT_NODE:
 8007: 	case XML_DOCUMENT_TYPE_NODE:
 8008: 	case XML_DOCUMENT_FRAG_NODE:
 8009: 	case XML_HTML_DOCUMENT_NODE:
 8010: #ifdef LIBXML_DOCB_ENABLED
 8011: 	case XML_DOCB_DOCUMENT_NODE:
 8012: #endif
 8013: 	    return(NULL);
 8014:     }
 8015:     return(NULL);
 8016: }
 8017: 
 8018: /**
 8019:  * xmlXPathNextAncestorOrSelf:
 8020:  * @ctxt:  the XPath Parser context
 8021:  * @cur:  the current node in the traversal
 8022:  *
 8023:  * Traversal function for the "ancestor-or-self" direction
 8024:  * he ancestor-or-self axis contains the context node and ancestors of
 8025:  * the context node in reverse document order; thus the context node is
 8026:  * the first node on the axis, and the context node's parent the second;
 8027:  * parent here is defined the same as with the parent axis.
 8028:  *
 8029:  * Returns the next element following that axis
 8030:  */
 8031: xmlNodePtr
 8032: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8033:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8034:     if (cur == NULL)
 8035:         return(ctxt->context->node);
 8036:     return(xmlXPathNextAncestor(ctxt, cur));
 8037: }
 8038: 
 8039: /**
 8040:  * xmlXPathNextFollowingSibling:
 8041:  * @ctxt:  the XPath Parser context
 8042:  * @cur:  the current node in the traversal
 8043:  *
 8044:  * Traversal function for the "following-sibling" direction
 8045:  * The following-sibling axis contains the following siblings of the context
 8046:  * node in document order.
 8047:  *
 8048:  * Returns the next element following that axis
 8049:  */
 8050: xmlNodePtr
 8051: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8052:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8053:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8054: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8055: 	return(NULL);
 8056:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8057:         return(NULL);
 8058:     if (cur == NULL)
 8059:         return(ctxt->context->node->next);
 8060:     return(cur->next);
 8061: }
 8062: 
 8063: /**
 8064:  * xmlXPathNextPrecedingSibling:
 8065:  * @ctxt:  the XPath Parser context
 8066:  * @cur:  the current node in the traversal
 8067:  *
 8068:  * Traversal function for the "preceding-sibling" direction
 8069:  * The preceding-sibling axis contains the preceding siblings of the context
 8070:  * node in reverse document order; the first preceding sibling is first on the
 8071:  * axis; the sibling preceding that node is the second on the axis and so on.
 8072:  *
 8073:  * Returns the next element following that axis
 8074:  */
 8075: xmlNodePtr
 8076: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8077:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8078:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8079: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8080: 	return(NULL);
 8081:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8082:         return(NULL);
 8083:     if (cur == NULL)
 8084:         return(ctxt->context->node->prev);
 8085:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
 8086: 	cur = cur->prev;
 8087: 	if (cur == NULL)
 8088: 	    return(ctxt->context->node->prev);
 8089:     }
 8090:     return(cur->prev);
 8091: }
 8092: 
 8093: /**
 8094:  * xmlXPathNextFollowing:
 8095:  * @ctxt:  the XPath Parser context
 8096:  * @cur:  the current node in the traversal
 8097:  *
 8098:  * Traversal function for the "following" direction
 8099:  * The following axis contains all nodes in the same document as the context
 8100:  * node that are after the context node in document order, excluding any
 8101:  * descendants and excluding attribute nodes and namespace nodes; the nodes
 8102:  * are ordered in document order
 8103:  *
 8104:  * Returns the next element following that axis
 8105:  */
 8106: xmlNodePtr
 8107: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8108:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8109:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
 8110:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
 8111:         return(cur->children);
 8112: 
 8113:     if (cur == NULL) {
 8114:         cur = ctxt->context->node;
 8115:         if (cur->type == XML_NAMESPACE_DECL)
 8116:             return(NULL);
 8117:         if (cur->type == XML_ATTRIBUTE_NODE)
 8118:             cur = cur->parent;
 8119:     }
 8120:     if (cur == NULL) return(NULL) ; /* ERROR */
 8121:     if (cur->next != NULL) return(cur->next) ;
 8122:     do {
 8123:         cur = cur->parent;
 8124:         if (cur == NULL) break;
 8125:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
 8126:         if (cur->next != NULL) return(cur->next);
 8127:     } while (cur != NULL);
 8128:     return(cur);
 8129: }
 8130: 
 8131: /*
 8132:  * xmlXPathIsAncestor:
 8133:  * @ancestor:  the ancestor node
 8134:  * @node:  the current node
 8135:  *
 8136:  * Check that @ancestor is a @node's ancestor
 8137:  *
 8138:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
 8139:  */
 8140: static int
 8141: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
 8142:     if ((ancestor == NULL) || (node == NULL)) return(0);
 8143:     /* nodes need to be in the same document */
 8144:     if (ancestor->doc != node->doc) return(0);
 8145:     /* avoid searching if ancestor or node is the root node */
 8146:     if (ancestor == (xmlNodePtr) node->doc) return(1);
 8147:     if (node == (xmlNodePtr) ancestor->doc) return(0);
 8148:     while (node->parent != NULL) {
 8149:         if (node->parent == ancestor)
 8150:             return(1);
 8151: 	node = node->parent;
 8152:     }
 8153:     return(0);
 8154: }
 8155: 
 8156: /**
 8157:  * xmlXPathNextPreceding:
 8158:  * @ctxt:  the XPath Parser context
 8159:  * @cur:  the current node in the traversal
 8160:  *
 8161:  * Traversal function for the "preceding" direction
 8162:  * the preceding axis contains all nodes in the same document as the context
 8163:  * node that are before the context node in document order, excluding any
 8164:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8165:  * ordered in reverse document order
 8166:  *
 8167:  * Returns the next element following that axis
 8168:  */
 8169: xmlNodePtr
 8170: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
 8171: {
 8172:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8173:     if (cur == NULL) {
 8174:         cur = ctxt->context->node;
 8175:         if (cur->type == XML_NAMESPACE_DECL)
 8176:             return(NULL);
 8177:         if (cur->type == XML_ATTRIBUTE_NODE)
 8178:             return(cur->parent);
 8179:     }
 8180:     if (cur == NULL)
 8181: 	return (NULL);
 8182:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8183: 	cur = cur->prev;
 8184:     do {
 8185:         if (cur->prev != NULL) {
 8186:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
 8187:             return (cur);
 8188:         }
 8189: 
 8190:         cur = cur->parent;
 8191:         if (cur == NULL)
 8192:             return (NULL);
 8193:         if (cur == ctxt->context->doc->children)
 8194:             return (NULL);
 8195:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
 8196:     return (cur);
 8197: }
 8198: 
 8199: /**
 8200:  * xmlXPathNextPrecedingInternal:
 8201:  * @ctxt:  the XPath Parser context
 8202:  * @cur:  the current node in the traversal
 8203:  *
 8204:  * Traversal function for the "preceding" direction
 8205:  * the preceding axis contains all nodes in the same document as the context
 8206:  * node that are before the context node in document order, excluding any
 8207:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8208:  * ordered in reverse document order
 8209:  * This is a faster implementation but internal only since it requires a
 8210:  * state kept in the parser context: ctxt->ancestor.
 8211:  *
 8212:  * Returns the next element following that axis
 8213:  */
 8214: static xmlNodePtr
 8215: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
 8216:                               xmlNodePtr cur)
 8217: {
 8218:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8219:     if (cur == NULL) {
 8220:         cur = ctxt->context->node;
 8221:         if (cur == NULL)
 8222:             return (NULL);
 8223:         if (cur->type == XML_NAMESPACE_DECL)
 8224:             return (NULL);
 8225:         ctxt->ancestor = cur->parent;
 8226:     }
 8227:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8228: 	cur = cur->prev;
 8229:     while (cur->prev == NULL) {
 8230:         cur = cur->parent;
 8231:         if (cur == NULL)
 8232:             return (NULL);
 8233:         if (cur == ctxt->context->doc->children)
 8234:             return (NULL);
 8235:         if (cur != ctxt->ancestor)
 8236:             return (cur);
 8237:         ctxt->ancestor = cur->parent;
 8238:     }
 8239:     cur = cur->prev;
 8240:     while (cur->last != NULL)
 8241:         cur = cur->last;
 8242:     return (cur);
 8243: }
 8244: 
 8245: /**
 8246:  * xmlXPathNextNamespace:
 8247:  * @ctxt:  the XPath Parser context
 8248:  * @cur:  the current attribute in the traversal
 8249:  *
 8250:  * Traversal function for the "namespace" direction
 8251:  * the namespace axis contains the namespace nodes of the context node;
 8252:  * the order of nodes on this axis is implementation-defined; the axis will
 8253:  * be empty unless the context node is an element
 8254:  *
 8255:  * We keep the XML namespace node at the end of the list.
 8256:  *
 8257:  * Returns the next element following that axis
 8258:  */
 8259: xmlNodePtr
 8260: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8261:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8262:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
 8263:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
 8264:         if (ctxt->context->tmpNsList != NULL)
 8265: 	    xmlFree(ctxt->context->tmpNsList);
 8266: 	ctxt->context->tmpNsList =
 8267: 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
 8268: 	ctxt->context->tmpNsNr = 0;
 8269: 	if (ctxt->context->tmpNsList != NULL) {
 8270: 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
 8271: 		ctxt->context->tmpNsNr++;
 8272: 	    }
 8273: 	}
 8274: 	return((xmlNodePtr) xmlXPathXMLNamespace);
 8275:     }
 8276:     if (ctxt->context->tmpNsNr > 0) {
 8277: 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
 8278:     } else {
 8279: 	if (ctxt->context->tmpNsList != NULL)
 8280: 	    xmlFree(ctxt->context->tmpNsList);
 8281: 	ctxt->context->tmpNsList = NULL;
 8282: 	return(NULL);
 8283:     }
 8284: }
 8285: 
 8286: /**
 8287:  * xmlXPathNextAttribute:
 8288:  * @ctxt:  the XPath Parser context
 8289:  * @cur:  the current attribute in the traversal
 8290:  *
 8291:  * Traversal function for the "attribute" direction
 8292:  * TODO: support DTD inherited default attributes
 8293:  *
 8294:  * Returns the next element following that axis
 8295:  */
 8296: xmlNodePtr
 8297: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8298:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8299:     if (ctxt->context->node == NULL)
 8300: 	return(NULL);
 8301:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
 8302: 	return(NULL);
 8303:     if (cur == NULL) {
 8304:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 8305: 	    return(NULL);
 8306:         return((xmlNodePtr)ctxt->context->node->properties);
 8307:     }
 8308:     return((xmlNodePtr)cur->next);
 8309: }
 8310: 
 8311: /************************************************************************
 8312:  *									*
 8313:  *		NodeTest Functions					*
 8314:  *									*
 8315:  ************************************************************************/
 8316: 
 8317: #define IS_FUNCTION			200
 8318: 
 8319: 
 8320: /************************************************************************
 8321:  *									*
 8322:  *		Implicit tree core function library			*
 8323:  *									*
 8324:  ************************************************************************/
 8325: 
 8326: /**
 8327:  * xmlXPathRoot:
 8328:  * @ctxt:  the XPath Parser context
 8329:  *
 8330:  * Initialize the context to the root of the document
 8331:  */
 8332: void
 8333: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
 8334:     if ((ctxt == NULL) || (ctxt->context == NULL))
 8335: 	return;
 8336:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
 8337:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8338: 	ctxt->context->node));
 8339: }
 8340: 
 8341: /************************************************************************
 8342:  *									*
 8343:  *		The explicit core function library			*
 8344:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
 8345:  *									*
 8346:  ************************************************************************/
 8347: 
 8348: 
 8349: /**
 8350:  * xmlXPathLastFunction:
 8351:  * @ctxt:  the XPath Parser context
 8352:  * @nargs:  the number of arguments
 8353:  *
 8354:  * Implement the last() XPath function
 8355:  *    number last()
 8356:  * The last function returns the number of nodes in the context node list.
 8357:  */
 8358: void
 8359: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8360:     CHECK_ARITY(0);
 8361:     if (ctxt->context->contextSize >= 0) {
 8362: 	valuePush(ctxt,
 8363: 	    xmlXPathCacheNewFloat(ctxt->context,
 8364: 		(double) ctxt->context->contextSize));
 8365: #ifdef DEBUG_EXPR
 8366: 	xmlGenericError(xmlGenericErrorContext,
 8367: 		"last() : %d\n", ctxt->context->contextSize);
 8368: #endif
 8369:     } else {
 8370: 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
 8371:     }
 8372: }
 8373: 
 8374: /**
 8375:  * xmlXPathPositionFunction:
 8376:  * @ctxt:  the XPath Parser context
 8377:  * @nargs:  the number of arguments
 8378:  *
 8379:  * Implement the position() XPath function
 8380:  *    number position()
 8381:  * The position function returns the position of the context node in the
 8382:  * context node list. The first position is 1, and so the last position
 8383:  * will be equal to last().
 8384:  */
 8385: void
 8386: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8387:     CHECK_ARITY(0);
 8388:     if (ctxt->context->proximityPosition >= 0) {
 8389: 	valuePush(ctxt,
 8390: 	      xmlXPathCacheNewFloat(ctxt->context,
 8391: 		(double) ctxt->context->proximityPosition));
 8392: #ifdef DEBUG_EXPR
 8393: 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
 8394: 		ctxt->context->proximityPosition);
 8395: #endif
 8396:     } else {
 8397: 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
 8398:     }
 8399: }
 8400: 
 8401: /**
 8402:  * xmlXPathCountFunction:
 8403:  * @ctxt:  the XPath Parser context
 8404:  * @nargs:  the number of arguments
 8405:  *
 8406:  * Implement the count() XPath function
 8407:  *    number count(node-set)
 8408:  */
 8409: void
 8410: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8411:     xmlXPathObjectPtr cur;
 8412: 
 8413:     CHECK_ARITY(1);
 8414:     if ((ctxt->value == NULL) ||
 8415: 	((ctxt->value->type != XPATH_NODESET) &&
 8416: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8417: 	XP_ERROR(XPATH_INVALID_TYPE);
 8418:     cur = valuePop(ctxt);
 8419: 
 8420:     if ((cur == NULL) || (cur->nodesetval == NULL))
 8421: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8422:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
 8423: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8424: 	    (double) cur->nodesetval->nodeNr));
 8425:     } else {
 8426: 	if ((cur->nodesetval->nodeNr != 1) ||
 8427: 	    (cur->nodesetval->nodeTab == NULL)) {
 8428: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8429: 	} else {
 8430: 	    xmlNodePtr tmp;
 8431: 	    int i = 0;
 8432: 
 8433: 	    tmp = cur->nodesetval->nodeTab[0];
 8434: 	    if (tmp != NULL) {
 8435: 		tmp = tmp->children;
 8436: 		while (tmp != NULL) {
 8437: 		    tmp = tmp->next;
 8438: 		    i++;
 8439: 		}
 8440: 	    }
 8441: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
 8442: 	}
 8443:     }
 8444:     xmlXPathReleaseObject(ctxt->context, cur);
 8445: }
 8446: 
 8447: /**
 8448:  * xmlXPathGetElementsByIds:
 8449:  * @doc:  the document
 8450:  * @ids:  a whitespace separated list of IDs
 8451:  *
 8452:  * Selects elements by their unique ID.
 8453:  *
 8454:  * Returns a node-set of selected elements.
 8455:  */
 8456: static xmlNodeSetPtr
 8457: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
 8458:     xmlNodeSetPtr ret;
 8459:     const xmlChar *cur = ids;
 8460:     xmlChar *ID;
 8461:     xmlAttrPtr attr;
 8462:     xmlNodePtr elem = NULL;
 8463: 
 8464:     if (ids == NULL) return(NULL);
 8465: 
 8466:     ret = xmlXPathNodeSetCreate(NULL);
 8467:     if (ret == NULL)
 8468:         return(ret);
 8469: 
 8470:     while (IS_BLANK_CH(*cur)) cur++;
 8471:     while (*cur != 0) {
 8472: 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
 8473: 	    cur++;
 8474: 
 8475:         ID = xmlStrndup(ids, cur - ids);
 8476: 	if (ID != NULL) {
 8477: 	    /*
 8478: 	     * We used to check the fact that the value passed
 8479: 	     * was an NCName, but this generated much troubles for
 8480: 	     * me and Aleksey Sanin, people blatantly violated that
 8481: 	     * constaint, like Visa3D spec.
 8482: 	     * if (xmlValidateNCName(ID, 1) == 0)
 8483: 	     */
 8484: 	    attr = xmlGetID(doc, ID);
 8485: 	    if (attr != NULL) {
 8486: 		if (attr->type == XML_ATTRIBUTE_NODE)
 8487: 		    elem = attr->parent;
 8488: 		else if (attr->type == XML_ELEMENT_NODE)
 8489: 		    elem = (xmlNodePtr) attr;
 8490: 		else
 8491: 		    elem = NULL;
 8492: 		if (elem != NULL)
 8493: 		    xmlXPathNodeSetAdd(ret, elem);
 8494: 	    }
 8495: 	    xmlFree(ID);
 8496: 	}
 8497: 
 8498: 	while (IS_BLANK_CH(*cur)) cur++;
 8499: 	ids = cur;
 8500:     }
 8501:     return(ret);
 8502: }
 8503: 
 8504: /**
 8505:  * xmlXPathIdFunction:
 8506:  * @ctxt:  the XPath Parser context
 8507:  * @nargs:  the number of arguments
 8508:  *
 8509:  * Implement the id() XPath function
 8510:  *    node-set id(object)
 8511:  * The id function selects elements by their unique ID
 8512:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
 8513:  * then the result is the union of the result of applying id to the
 8514:  * string value of each of the nodes in the argument node-set. When the
 8515:  * argument to id is of any other type, the argument is converted to a
 8516:  * string as if by a call to the string function; the string is split
 8517:  * into a whitespace-separated list of tokens (whitespace is any sequence
 8518:  * of characters matching the production S); the result is a node-set
 8519:  * containing the elements in the same document as the context node that
 8520:  * have a unique ID equal to any of the tokens in the list.
 8521:  */
 8522: void
 8523: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8524:     xmlChar *tokens;
 8525:     xmlNodeSetPtr ret;
 8526:     xmlXPathObjectPtr obj;
 8527: 
 8528:     CHECK_ARITY(1);
 8529:     obj = valuePop(ctxt);
 8530:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8531:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 8532: 	xmlNodeSetPtr ns;
 8533: 	int i;
 8534: 
 8535: 	ret = xmlXPathNodeSetCreate(NULL);
 8536:         /*
 8537:          * FIXME -- in an out-of-memory condition this will behave badly.
 8538:          * The solution is not clear -- we already popped an item from
 8539:          * ctxt, so the object is in a corrupt state.
 8540:          */
 8541: 
 8542: 	if (obj->nodesetval != NULL) {
 8543: 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 8544: 		tokens =
 8545: 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
 8546: 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
 8547: 		ret = xmlXPathNodeSetMerge(ret, ns);
 8548: 		xmlXPathFreeNodeSet(ns);
 8549: 		if (tokens != NULL)
 8550: 		    xmlFree(tokens);
 8551: 	    }
 8552: 	}
 8553: 	xmlXPathReleaseObject(ctxt->context, obj);
 8554: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8555: 	return;
 8556:     }
 8557:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
 8558:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
 8559:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8560:     xmlXPathReleaseObject(ctxt->context, obj);
 8561:     return;
 8562: }
 8563: 
 8564: /**
 8565:  * xmlXPathLocalNameFunction:
 8566:  * @ctxt:  the XPath Parser context
 8567:  * @nargs:  the number of arguments
 8568:  *
 8569:  * Implement the local-name() XPath function
 8570:  *    string local-name(node-set?)
 8571:  * The local-name function returns a string containing the local part
 8572:  * of the name of the node in the argument node-set that is first in
 8573:  * document order. If the node-set is empty or the first node has no
 8574:  * name, an empty string is returned. If the argument is omitted it
 8575:  * defaults to the context node.
 8576:  */
 8577: void
 8578: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8579:     xmlXPathObjectPtr cur;
 8580: 
 8581:     if (ctxt == NULL) return;
 8582: 
 8583:     if (nargs == 0) {
 8584: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8585: 	    ctxt->context->node));
 8586: 	nargs = 1;
 8587:     }
 8588: 
 8589:     CHECK_ARITY(1);
 8590:     if ((ctxt->value == NULL) ||
 8591: 	((ctxt->value->type != XPATH_NODESET) &&
 8592: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8593: 	XP_ERROR(XPATH_INVALID_TYPE);
 8594:     cur = valuePop(ctxt);
 8595: 
 8596:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8597: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8598:     } else {
 8599: 	int i = 0; /* Should be first in document order !!!!! */
 8600: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8601: 	case XML_ELEMENT_NODE:
 8602: 	case XML_ATTRIBUTE_NODE:
 8603: 	case XML_PI_NODE:
 8604: 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8605: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8606: 	    else
 8607: 		valuePush(ctxt,
 8608: 		      xmlXPathCacheNewString(ctxt->context,
 8609: 			cur->nodesetval->nodeTab[i]->name));
 8610: 	    break;
 8611: 	case XML_NAMESPACE_DECL:
 8612: 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8613: 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
 8614: 	    break;
 8615: 	default:
 8616: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8617: 	}
 8618:     }
 8619:     xmlXPathReleaseObject(ctxt->context, cur);
 8620: }
 8621: 
 8622: /**
 8623:  * xmlXPathNamespaceURIFunction:
 8624:  * @ctxt:  the XPath Parser context
 8625:  * @nargs:  the number of arguments
 8626:  *
 8627:  * Implement the namespace-uri() XPath function
 8628:  *    string namespace-uri(node-set?)
 8629:  * The namespace-uri function returns a string containing the
 8630:  * namespace URI of the expanded name of the node in the argument
 8631:  * node-set that is first in document order. If the node-set is empty,
 8632:  * the first node has no name, or the expanded name has no namespace
 8633:  * URI, an empty string is returned. If the argument is omitted it
 8634:  * defaults to the context node.
 8635:  */
 8636: void
 8637: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8638:     xmlXPathObjectPtr cur;
 8639: 
 8640:     if (ctxt == NULL) return;
 8641: 
 8642:     if (nargs == 0) {
 8643: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8644: 	    ctxt->context->node));
 8645: 	nargs = 1;
 8646:     }
 8647:     CHECK_ARITY(1);
 8648:     if ((ctxt->value == NULL) ||
 8649: 	((ctxt->value->type != XPATH_NODESET) &&
 8650: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8651: 	XP_ERROR(XPATH_INVALID_TYPE);
 8652:     cur = valuePop(ctxt);
 8653: 
 8654:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8655: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8656:     } else {
 8657: 	int i = 0; /* Should be first in document order !!!!! */
 8658: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8659: 	case XML_ELEMENT_NODE:
 8660: 	case XML_ATTRIBUTE_NODE:
 8661: 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
 8662: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8663: 	    else
 8664: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8665: 			  cur->nodesetval->nodeTab[i]->ns->href));
 8666: 	    break;
 8667: 	default:
 8668: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8669: 	}
 8670:     }
 8671:     xmlXPathReleaseObject(ctxt->context, cur);
 8672: }
 8673: 
 8674: /**
 8675:  * xmlXPathNameFunction:
 8676:  * @ctxt:  the XPath Parser context
 8677:  * @nargs:  the number of arguments
 8678:  *
 8679:  * Implement the name() XPath function
 8680:  *    string name(node-set?)
 8681:  * The name function returns a string containing a QName representing
 8682:  * the name of the node in the argument node-set that is first in document
 8683:  * order. The QName must represent the name with respect to the namespace
 8684:  * declarations in effect on the node whose name is being represented.
 8685:  * Typically, this will be the form in which the name occurred in the XML
 8686:  * source. This need not be the case if there are namespace declarations
 8687:  * in effect on the node that associate multiple prefixes with the same
 8688:  * namespace. However, an implementation may include information about
 8689:  * the original prefix in its representation of nodes; in this case, an
 8690:  * implementation can ensure that the returned string is always the same
 8691:  * as the QName used in the XML source. If the argument it omitted it
 8692:  * defaults to the context node.
 8693:  * Libxml keep the original prefix so the "real qualified name" used is
 8694:  * returned.
 8695:  */
 8696: static void
 8697: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
 8698: {
 8699:     xmlXPathObjectPtr cur;
 8700: 
 8701:     if (nargs == 0) {
 8702: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8703: 	    ctxt->context->node));
 8704:         nargs = 1;
 8705:     }
 8706: 
 8707:     CHECK_ARITY(1);
 8708:     if ((ctxt->value == NULL) ||
 8709:         ((ctxt->value->type != XPATH_NODESET) &&
 8710:          (ctxt->value->type != XPATH_XSLT_TREE)))
 8711:         XP_ERROR(XPATH_INVALID_TYPE);
 8712:     cur = valuePop(ctxt);
 8713: 
 8714:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8715:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8716:     } else {
 8717:         int i = 0;              /* Should be first in document order !!!!! */
 8718: 
 8719:         switch (cur->nodesetval->nodeTab[i]->type) {
 8720:             case XML_ELEMENT_NODE:
 8721:             case XML_ATTRIBUTE_NODE:
 8722: 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8723: 		    valuePush(ctxt,
 8724: 			xmlXPathCacheNewCString(ctxt->context, ""));
 8725: 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
 8726:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
 8727: 		    valuePush(ctxt,
 8728: 		        xmlXPathCacheNewString(ctxt->context,
 8729: 			    cur->nodesetval->nodeTab[i]->name));
 8730: 		} else {
 8731: 		    xmlChar *fullname;
 8732: 
 8733: 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
 8734: 				     cur->nodesetval->nodeTab[i]->ns->prefix,
 8735: 				     NULL, 0);
 8736: 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
 8737: 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
 8738: 		    if (fullname == NULL) {
 8739: 			XP_ERROR(XPATH_MEMORY_ERROR);
 8740: 		    }
 8741: 		    valuePush(ctxt, xmlXPathCacheWrapString(
 8742: 			ctxt->context, fullname));
 8743:                 }
 8744:                 break;
 8745:             default:
 8746: 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8747: 		    cur->nodesetval->nodeTab[i]));
 8748:                 xmlXPathLocalNameFunction(ctxt, 1);
 8749:         }
 8750:     }
 8751:     xmlXPathReleaseObject(ctxt->context, cur);
 8752: }
 8753: 
 8754: 
 8755: /**
 8756:  * xmlXPathStringFunction:
 8757:  * @ctxt:  the XPath Parser context
 8758:  * @nargs:  the number of arguments
 8759:  *
 8760:  * Implement the string() XPath function
 8761:  *    string string(object?)
 8762:  * The string function converts an object to a string as follows:
 8763:  *    - A node-set is converted to a string by returning the value of
 8764:  *      the node in the node-set that is first in document order.
 8765:  *      If the node-set is empty, an empty string is returned.
 8766:  *    - A number is converted to a string as follows
 8767:  *      + NaN is converted to the string NaN
 8768:  *      + positive zero is converted to the string 0
 8769:  *      + negative zero is converted to the string 0
 8770:  *      + positive infinity is converted to the string Infinity
 8771:  *      + negative infinity is converted to the string -Infinity
 8772:  *      + if the number is an integer, the number is represented in
 8773:  *        decimal form as a Number with no decimal point and no leading
 8774:  *        zeros, preceded by a minus sign (-) if the number is negative
 8775:  *      + otherwise, the number is represented in decimal form as a
 8776:  *        Number including a decimal point with at least one digit
 8777:  *        before the decimal point and at least one digit after the
 8778:  *        decimal point, preceded by a minus sign (-) if the number
 8779:  *        is negative; there must be no leading zeros before the decimal
 8780:  *        point apart possibly from the one required digit immediately
 8781:  *        before the decimal point; beyond the one required digit
 8782:  *        after the decimal point there must be as many, but only as
 8783:  *        many, more digits as are needed to uniquely distinguish the
 8784:  *        number from all other IEEE 754 numeric values.
 8785:  *    - The boolean false value is converted to the string false.
 8786:  *      The boolean true value is converted to the string true.
 8787:  *
 8788:  * If the argument is omitted, it defaults to a node-set with the
 8789:  * context node as its only member.
 8790:  */
 8791: void
 8792: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8793:     xmlXPathObjectPtr cur;
 8794: 
 8795:     if (ctxt == NULL) return;
 8796:     if (nargs == 0) {
 8797:     valuePush(ctxt,
 8798: 	xmlXPathCacheWrapString(ctxt->context,
 8799: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 8800: 	return;
 8801:     }
 8802: 
 8803:     CHECK_ARITY(1);
 8804:     cur = valuePop(ctxt);
 8805:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8806:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
 8807: }
 8808: 
 8809: /**
 8810:  * xmlXPathStringLengthFunction:
 8811:  * @ctxt:  the XPath Parser context
 8812:  * @nargs:  the number of arguments
 8813:  *
 8814:  * Implement the string-length() XPath function
 8815:  *    number string-length(string?)
 8816:  * The string-length returns the number of characters in the string
 8817:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
 8818:  * the context node converted to a string, in other words the value
 8819:  * of the context node.
 8820:  */
 8821: void
 8822: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8823:     xmlXPathObjectPtr cur;
 8824: 
 8825:     if (nargs == 0) {
 8826:         if ((ctxt == NULL) || (ctxt->context == NULL))
 8827: 	    return;
 8828: 	if (ctxt->context->node == NULL) {
 8829: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
 8830: 	} else {
 8831: 	    xmlChar *content;
 8832: 
 8833: 	    content = xmlXPathCastNodeToString(ctxt->context->node);
 8834: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8835: 		xmlUTF8Strlen(content)));
 8836: 	    xmlFree(content);
 8837: 	}
 8838: 	return;
 8839:     }
 8840:     CHECK_ARITY(1);
 8841:     CAST_TO_STRING;
 8842:     CHECK_TYPE(XPATH_STRING);
 8843:     cur = valuePop(ctxt);
 8844:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8845: 	xmlUTF8Strlen(cur->stringval)));
 8846:     xmlXPathReleaseObject(ctxt->context, cur);
 8847: }
 8848: 
 8849: /**
 8850:  * xmlXPathConcatFunction:
 8851:  * @ctxt:  the XPath Parser context
 8852:  * @nargs:  the number of arguments
 8853:  *
 8854:  * Implement the concat() XPath function
 8855:  *    string concat(string, string, string*)
 8856:  * The concat function returns the concatenation of its arguments.
 8857:  */
 8858: void
 8859: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8860:     xmlXPathObjectPtr cur, newobj;
 8861:     xmlChar *tmp;
 8862: 
 8863:     if (ctxt == NULL) return;
 8864:     if (nargs < 2) {
 8865: 	CHECK_ARITY(2);
 8866:     }
 8867: 
 8868:     CAST_TO_STRING;
 8869:     cur = valuePop(ctxt);
 8870:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
 8871: 	xmlXPathReleaseObject(ctxt->context, cur);
 8872: 	return;
 8873:     }
 8874:     nargs--;
 8875: 
 8876:     while (nargs > 0) {
 8877: 	CAST_TO_STRING;
 8878: 	newobj = valuePop(ctxt);
 8879: 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
 8880: 	    xmlXPathReleaseObject(ctxt->context, newobj);
 8881: 	    xmlXPathReleaseObject(ctxt->context, cur);
 8882: 	    XP_ERROR(XPATH_INVALID_TYPE);
 8883: 	}
 8884: 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
 8885: 	newobj->stringval = cur->stringval;
 8886: 	cur->stringval = tmp;
 8887: 	xmlXPathReleaseObject(ctxt->context, newobj);
 8888: 	nargs--;
 8889:     }
 8890:     valuePush(ctxt, cur);
 8891: }
 8892: 
 8893: /**
 8894:  * xmlXPathContainsFunction:
 8895:  * @ctxt:  the XPath Parser context
 8896:  * @nargs:  the number of arguments
 8897:  *
 8898:  * Implement the contains() XPath function
 8899:  *    boolean contains(string, string)
 8900:  * The contains function returns true if the first argument string
 8901:  * contains the second argument string, and otherwise returns false.
 8902:  */
 8903: void
 8904: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8905:     xmlXPathObjectPtr hay, needle;
 8906: 
 8907:     CHECK_ARITY(2);
 8908:     CAST_TO_STRING;
 8909:     CHECK_TYPE(XPATH_STRING);
 8910:     needle = valuePop(ctxt);
 8911:     CAST_TO_STRING;
 8912:     hay = valuePop(ctxt);
 8913: 
 8914:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 8915: 	xmlXPathReleaseObject(ctxt->context, hay);
 8916: 	xmlXPathReleaseObject(ctxt->context, needle);
 8917: 	XP_ERROR(XPATH_INVALID_TYPE);
 8918:     }
 8919:     if (xmlStrstr(hay->stringval, needle->stringval))
 8920: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 8921:     else
 8922: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 8923:     xmlXPathReleaseObject(ctxt->context, hay);
 8924:     xmlXPathReleaseObject(ctxt->context, needle);
 8925: }
 8926: 
 8927: /**
 8928:  * xmlXPathStartsWithFunction:
 8929:  * @ctxt:  the XPath Parser context
 8930:  * @nargs:  the number of arguments
 8931:  *
 8932:  * Implement the starts-with() XPath function
 8933:  *    boolean starts-with(string, string)
 8934:  * The starts-with function returns true if the first argument string
 8935:  * starts with the second argument string, and otherwise returns false.
 8936:  */
 8937: void
 8938: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8939:     xmlXPathObjectPtr hay, needle;
 8940:     int n;
 8941: 
 8942:     CHECK_ARITY(2);
 8943:     CAST_TO_STRING;
 8944:     CHECK_TYPE(XPATH_STRING);
 8945:     needle = valuePop(ctxt);
 8946:     CAST_TO_STRING;
 8947:     hay = valuePop(ctxt);
 8948: 
 8949:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 8950: 	xmlXPathReleaseObject(ctxt->context, hay);
 8951: 	xmlXPathReleaseObject(ctxt->context, needle);
 8952: 	XP_ERROR(XPATH_INVALID_TYPE);
 8953:     }
 8954:     n = xmlStrlen(needle->stringval);
 8955:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
 8956:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 8957:     else
 8958:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 8959:     xmlXPathReleaseObject(ctxt->context, hay);
 8960:     xmlXPathReleaseObject(ctxt->context, needle);
 8961: }
 8962: 
 8963: /**
 8964:  * xmlXPathSubstringFunction:
 8965:  * @ctxt:  the XPath Parser context
 8966:  * @nargs:  the number of arguments
 8967:  *
 8968:  * Implement the substring() XPath function
 8969:  *    string substring(string, number, number?)
 8970:  * The substring function returns the substring of the first argument
 8971:  * starting at the position specified in the second argument with
 8972:  * length specified in the third argument. For example,
 8973:  * substring("12345",2,3) returns "234". If the third argument is not
 8974:  * specified, it returns the substring starting at the position specified
 8975:  * in the second argument and continuing to the end of the string. For
 8976:  * example, substring("12345",2) returns "2345".  More precisely, each
 8977:  * character in the string (see [3.6 Strings]) is considered to have a
 8978:  * numeric position: the position of the first character is 1, the position
 8979:  * of the second character is 2 and so on. The returned substring contains
 8980:  * those characters for which the position of the character is greater than
 8981:  * or equal to the second argument and, if the third argument is specified,
 8982:  * less than the sum of the second and third arguments; the comparisons
 8983:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
 8984:  *  - substring("12345", 1.5, 2.6) returns "234"
 8985:  *  - substring("12345", 0, 3) returns "12"
 8986:  *  - substring("12345", 0 div 0, 3) returns ""
 8987:  *  - substring("12345", 1, 0 div 0) returns ""
 8988:  *  - substring("12345", -42, 1 div 0) returns "12345"
 8989:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
 8990:  */
 8991: void
 8992: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8993:     xmlXPathObjectPtr str, start, len;
 8994:     double le=0, in;
 8995:     int i, l, m;
 8996:     xmlChar *ret;
 8997: 
 8998:     if (nargs < 2) {
 8999: 	CHECK_ARITY(2);
 9000:     }
 9001:     if (nargs > 3) {
 9002: 	CHECK_ARITY(3);
 9003:     }
 9004:     /*
 9005:      * take care of possible last (position) argument
 9006:     */
 9007:     if (nargs == 3) {
 9008: 	CAST_TO_NUMBER;
 9009: 	CHECK_TYPE(XPATH_NUMBER);
 9010: 	len = valuePop(ctxt);
 9011: 	le = len->floatval;
 9012: 	xmlXPathReleaseObject(ctxt->context, len);
 9013:     }
 9014: 
 9015:     CAST_TO_NUMBER;
 9016:     CHECK_TYPE(XPATH_NUMBER);
 9017:     start = valuePop(ctxt);
 9018:     in = start->floatval;
 9019:     xmlXPathReleaseObject(ctxt->context, start);
 9020:     CAST_TO_STRING;
 9021:     CHECK_TYPE(XPATH_STRING);
 9022:     str = valuePop(ctxt);
 9023:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
 9024: 
 9025:     /*
 9026:      * If last pos not present, calculate last position
 9027:     */
 9028:     if (nargs != 3) {
 9029: 	le = (double)m;
 9030: 	if (in < 1.0)
 9031: 	    in = 1.0;
 9032:     }
 9033: 
 9034:     /* Need to check for the special cases where either
 9035:      * the index is NaN, the length is NaN, or both
 9036:      * arguments are infinity (relying on Inf + -Inf = NaN)
 9037:      */
 9038:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
 9039:         /*
 9040:          * To meet the requirements of the spec, the arguments
 9041: 	 * must be converted to integer format before
 9042: 	 * initial index calculations are done
 9043:          *
 9044:          * First we go to integer form, rounding up
 9045: 	 * and checking for special cases
 9046:          */
 9047:         i = (int) in;
 9048:         if (((double)i)+0.5 <= in) i++;
 9049: 
 9050: 	if (xmlXPathIsInf(le) == 1) {
 9051: 	    l = m;
 9052: 	    if (i < 1)
 9053: 		i = 1;
 9054: 	}
 9055: 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
 9056: 	    l = 0;
 9057: 	else {
 9058: 	    l = (int) le;
 9059: 	    if (((double)l)+0.5 <= le) l++;
 9060: 	}
 9061: 
 9062: 	/* Now we normalize inidices */
 9063:         i -= 1;
 9064:         l += i;
 9065:         if (i < 0)
 9066:             i = 0;
 9067:         if (l > m)
 9068:             l = m;
 9069: 
 9070:         /* number of chars to copy */
 9071:         l -= i;
 9072: 
 9073:         ret = xmlUTF8Strsub(str->stringval, i, l);
 9074:     }
 9075:     else {
 9076:         ret = NULL;
 9077:     }
 9078:     if (ret == NULL)
 9079: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 9080:     else {
 9081: 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
 9082: 	xmlFree(ret);
 9083:     }
 9084:     xmlXPathReleaseObject(ctxt->context, str);
 9085: }
 9086: 
 9087: /**
 9088:  * xmlXPathSubstringBeforeFunction:
 9089:  * @ctxt:  the XPath Parser context
 9090:  * @nargs:  the number of arguments
 9091:  *
 9092:  * Implement the substring-before() XPath function
 9093:  *    string substring-before(string, string)
 9094:  * The substring-before function returns the substring of the first
 9095:  * argument string that precedes the first occurrence of the second
 9096:  * argument string in the first argument string, or the empty string
 9097:  * if the first argument string does not contain the second argument
 9098:  * string. For example, substring-before("1999/04/01","/") returns 1999.
 9099:  */
 9100: void
 9101: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9102:   xmlXPathObjectPtr str;
 9103:   xmlXPathObjectPtr find;
 9104:   xmlBufferPtr target;
 9105:   const xmlChar *point;
 9106:   int offset;
 9107: 
 9108:   CHECK_ARITY(2);
 9109:   CAST_TO_STRING;
 9110:   find = valuePop(ctxt);
 9111:   CAST_TO_STRING;
 9112:   str = valuePop(ctxt);
 9113: 
 9114:   target = xmlBufferCreate();
 9115:   if (target) {
 9116:     point = xmlStrstr(str->stringval, find->stringval);
 9117:     if (point) {
 9118:       offset = (int)(point - str->stringval);
 9119:       xmlBufferAdd(target, str->stringval, offset);
 9120:     }
 9121:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9122: 	xmlBufferContent(target)));
 9123:     xmlBufferFree(target);
 9124:   }
 9125:   xmlXPathReleaseObject(ctxt->context, str);
 9126:   xmlXPathReleaseObject(ctxt->context, find);
 9127: }
 9128: 
 9129: /**
 9130:  * xmlXPathSubstringAfterFunction:
 9131:  * @ctxt:  the XPath Parser context
 9132:  * @nargs:  the number of arguments
 9133:  *
 9134:  * Implement the substring-after() XPath function
 9135:  *    string substring-after(string, string)
 9136:  * The substring-after function returns the substring of the first
 9137:  * argument string that follows the first occurrence of the second
 9138:  * argument string in the first argument string, or the empty stringi
 9139:  * if the first argument string does not contain the second argument
 9140:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
 9141:  * and substring-after("1999/04/01","19") returns 99/04/01.
 9142:  */
 9143: void
 9144: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9145:   xmlXPathObjectPtr str;
 9146:   xmlXPathObjectPtr find;
 9147:   xmlBufferPtr target;
 9148:   const xmlChar *point;
 9149:   int offset;
 9150: 
 9151:   CHECK_ARITY(2);
 9152:   CAST_TO_STRING;
 9153:   find = valuePop(ctxt);
 9154:   CAST_TO_STRING;
 9155:   str = valuePop(ctxt);
 9156: 
 9157:   target = xmlBufferCreate();
 9158:   if (target) {
 9159:     point = xmlStrstr(str->stringval, find->stringval);
 9160:     if (point) {
 9161:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
 9162:       xmlBufferAdd(target, &str->stringval[offset],
 9163: 		   xmlStrlen(str->stringval) - offset);
 9164:     }
 9165:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9166: 	xmlBufferContent(target)));
 9167:     xmlBufferFree(target);
 9168:   }
 9169:   xmlXPathReleaseObject(ctxt->context, str);
 9170:   xmlXPathReleaseObject(ctxt->context, find);
 9171: }
 9172: 
 9173: /**
 9174:  * xmlXPathNormalizeFunction:
 9175:  * @ctxt:  the XPath Parser context
 9176:  * @nargs:  the number of arguments
 9177:  *
 9178:  * Implement the normalize-space() XPath function
 9179:  *    string normalize-space(string?)
 9180:  * The normalize-space function returns the argument string with white
 9181:  * space normalized by stripping leading and trailing whitespace
 9182:  * and replacing sequences of whitespace characters by a single
 9183:  * space. Whitespace characters are the same allowed by the S production
 9184:  * in XML. If the argument is omitted, it defaults to the context
 9185:  * node converted to a string, in other words the value of the context node.
 9186:  */
 9187: void
 9188: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9189:   xmlXPathObjectPtr obj = NULL;
 9190:   xmlChar *source = NULL;
 9191:   xmlBufferPtr target;
 9192:   xmlChar blank;
 9193: 
 9194:   if (ctxt == NULL) return;
 9195:   if (nargs == 0) {
 9196:     /* Use current context node */
 9197:       valuePush(ctxt,
 9198: 	  xmlXPathCacheWrapString(ctxt->context,
 9199: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 9200:     nargs = 1;
 9201:   }
 9202: 
 9203:   CHECK_ARITY(1);
 9204:   CAST_TO_STRING;
 9205:   CHECK_TYPE(XPATH_STRING);
 9206:   obj = valuePop(ctxt);
 9207:   source = obj->stringval;
 9208: 
 9209:   target = xmlBufferCreate();
 9210:   if (target && source) {
 9211: 
 9212:     /* Skip leading whitespaces */
 9213:     while (IS_BLANK_CH(*source))
 9214:       source++;
 9215: 
 9216:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
 9217:     blank = 0;
 9218:     while (*source) {
 9219:       if (IS_BLANK_CH(*source)) {
 9220: 	blank = 0x20;
 9221:       } else {
 9222: 	if (blank) {
 9223: 	  xmlBufferAdd(target, &blank, 1);
 9224: 	  blank = 0;
 9225: 	}
 9226: 	xmlBufferAdd(target, source, 1);
 9227:       }
 9228:       source++;
 9229:     }
 9230:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9231: 	xmlBufferContent(target)));
 9232:     xmlBufferFree(target);
 9233:   }
 9234:   xmlXPathReleaseObject(ctxt->context, obj);
 9235: }
 9236: 
 9237: /**
 9238:  * xmlXPathTranslateFunction:
 9239:  * @ctxt:  the XPath Parser context
 9240:  * @nargs:  the number of arguments
 9241:  *
 9242:  * Implement the translate() XPath function
 9243:  *    string translate(string, string, string)
 9244:  * The translate function returns the first argument string with
 9245:  * occurrences of characters in the second argument string replaced
 9246:  * by the character at the corresponding position in the third argument
 9247:  * string. For example, translate("bar","abc","ABC") returns the string
 9248:  * BAr. If there is a character in the second argument string with no
 9249:  * character at a corresponding position in the third argument string
 9250:  * (because the second argument string is longer than the third argument
 9251:  * string), then occurrences of that character in the first argument
 9252:  * string are removed. For example, translate("--aaa--","abc-","ABC")
 9253:  * returns "AAA". If a character occurs more than once in second
 9254:  * argument string, then the first occurrence determines the replacement
 9255:  * character. If the third argument string is longer than the second
 9256:  * argument string, then excess characters are ignored.
 9257:  */
 9258: void
 9259: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9260:     xmlXPathObjectPtr str;
 9261:     xmlXPathObjectPtr from;
 9262:     xmlXPathObjectPtr to;
 9263:     xmlBufferPtr target;
 9264:     int offset, max;
 9265:     xmlChar ch;
 9266:     const xmlChar *point;
 9267:     xmlChar *cptr;
 9268: 
 9269:     CHECK_ARITY(3);
 9270: 
 9271:     CAST_TO_STRING;
 9272:     to = valuePop(ctxt);
 9273:     CAST_TO_STRING;
 9274:     from = valuePop(ctxt);
 9275:     CAST_TO_STRING;
 9276:     str = valuePop(ctxt);
 9277: 
 9278:     target = xmlBufferCreate();
 9279:     if (target) {
 9280: 	max = xmlUTF8Strlen(to->stringval);
 9281: 	for (cptr = str->stringval; (ch=*cptr); ) {
 9282: 	    offset = xmlUTF8Strloc(from->stringval, cptr);
 9283: 	    if (offset >= 0) {
 9284: 		if (offset < max) {
 9285: 		    point = xmlUTF8Strpos(to->stringval, offset);
 9286: 		    if (point)
 9287: 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
 9288: 		}
 9289: 	    } else
 9290: 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
 9291: 
 9292: 	    /* Step to next character in input */
 9293: 	    cptr++;
 9294: 	    if ( ch & 0x80 ) {
 9295: 		/* if not simple ascii, verify proper format */
 9296: 		if ( (ch & 0xc0) != 0xc0 ) {
 9297: 		    xmlGenericError(xmlGenericErrorContext,
 9298: 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9299: 		    break;
 9300: 		}
 9301: 		/* then skip over remaining bytes for this char */
 9302: 		while ( (ch <<= 1) & 0x80 )
 9303: 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
 9304: 			xmlGenericError(xmlGenericErrorContext,
 9305: 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9306: 			break;
 9307: 		    }
 9308: 		if (ch & 0x80) /* must have had error encountered */
 9309: 		    break;
 9310: 	    }
 9311: 	}
 9312:     }
 9313:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9314: 	xmlBufferContent(target)));
 9315:     xmlBufferFree(target);
 9316:     xmlXPathReleaseObject(ctxt->context, str);
 9317:     xmlXPathReleaseObject(ctxt->context, from);
 9318:     xmlXPathReleaseObject(ctxt->context, to);
 9319: }
 9320: 
 9321: /**
 9322:  * xmlXPathBooleanFunction:
 9323:  * @ctxt:  the XPath Parser context
 9324:  * @nargs:  the number of arguments
 9325:  *
 9326:  * Implement the boolean() XPath function
 9327:  *    boolean boolean(object)
 9328:  * The boolean function converts its argument to a boolean as follows:
 9329:  *    - a number is true if and only if it is neither positive or
 9330:  *      negative zero nor NaN
 9331:  *    - a node-set is true if and only if it is non-empty
 9332:  *    - a string is true if and only if its length is non-zero
 9333:  */
 9334: void
 9335: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9336:     xmlXPathObjectPtr cur;
 9337: 
 9338:     CHECK_ARITY(1);
 9339:     cur = valuePop(ctxt);
 9340:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 9341:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
 9342:     valuePush(ctxt, cur);
 9343: }
 9344: 
 9345: /**
 9346:  * xmlXPathNotFunction:
 9347:  * @ctxt:  the XPath Parser context
 9348:  * @nargs:  the number of arguments
 9349:  *
 9350:  * Implement the not() XPath function
 9351:  *    boolean not(boolean)
 9352:  * The not function returns true if its argument is false,
 9353:  * and false otherwise.
 9354:  */
 9355: void
 9356: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9357:     CHECK_ARITY(1);
 9358:     CAST_TO_BOOLEAN;
 9359:     CHECK_TYPE(XPATH_BOOLEAN);
 9360:     ctxt->value->boolval = ! ctxt->value->boolval;
 9361: }
 9362: 
 9363: /**
 9364:  * xmlXPathTrueFunction:
 9365:  * @ctxt:  the XPath Parser context
 9366:  * @nargs:  the number of arguments
 9367:  *
 9368:  * Implement the true() XPath function
 9369:  *    boolean true()
 9370:  */
 9371: void
 9372: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9373:     CHECK_ARITY(0);
 9374:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9375: }
 9376: 
 9377: /**
 9378:  * xmlXPathFalseFunction:
 9379:  * @ctxt:  the XPath Parser context
 9380:  * @nargs:  the number of arguments
 9381:  *
 9382:  * Implement the false() XPath function
 9383:  *    boolean false()
 9384:  */
 9385: void
 9386: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9387:     CHECK_ARITY(0);
 9388:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9389: }
 9390: 
 9391: /**
 9392:  * xmlXPathLangFunction:
 9393:  * @ctxt:  the XPath Parser context
 9394:  * @nargs:  the number of arguments
 9395:  *
 9396:  * Implement the lang() XPath function
 9397:  *    boolean lang(string)
 9398:  * The lang function returns true or false depending on whether the
 9399:  * language of the context node as specified by xml:lang attributes
 9400:  * is the same as or is a sublanguage of the language specified by
 9401:  * the argument string. The language of the context node is determined
 9402:  * by the value of the xml:lang attribute on the context node, or, if
 9403:  * the context node has no xml:lang attribute, by the value of the
 9404:  * xml:lang attribute on the nearest ancestor of the context node that
 9405:  * has an xml:lang attribute. If there is no such attribute, then lang
 9406:  * returns false. If there is such an attribute, then lang returns
 9407:  * true if the attribute value is equal to the argument ignoring case,
 9408:  * or if there is some suffix starting with - such that the attribute
 9409:  * value is equal to the argument ignoring that suffix of the attribute
 9410:  * value and ignoring case.
 9411:  */
 9412: void
 9413: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9414:     xmlXPathObjectPtr val = NULL;
 9415:     const xmlChar *theLang = NULL;
 9416:     const xmlChar *lang;
 9417:     int ret = 0;
 9418:     int i;
 9419: 
 9420:     CHECK_ARITY(1);
 9421:     CAST_TO_STRING;
 9422:     CHECK_TYPE(XPATH_STRING);
 9423:     val = valuePop(ctxt);
 9424:     lang = val->stringval;
 9425:     theLang = xmlNodeGetLang(ctxt->context->node);
 9426:     if ((theLang != NULL) && (lang != NULL)) {
 9427:         for (i = 0;lang[i] != 0;i++)
 9428: 	    if (toupper(lang[i]) != toupper(theLang[i]))
 9429: 	        goto not_equal;
 9430: 	if ((theLang[i] == 0) || (theLang[i] == '-'))
 9431: 	    ret = 1;
 9432:     }
 9433: not_equal:
 9434:     if (theLang != NULL)
 9435: 	xmlFree((void *)theLang);
 9436: 
 9437:     xmlXPathReleaseObject(ctxt->context, val);
 9438:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
 9439: }
 9440: 
 9441: /**
 9442:  * xmlXPathNumberFunction:
 9443:  * @ctxt:  the XPath Parser context
 9444:  * @nargs:  the number of arguments
 9445:  *
 9446:  * Implement the number() XPath function
 9447:  *    number number(object?)
 9448:  */
 9449: void
 9450: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9451:     xmlXPathObjectPtr cur;
 9452:     double res;
 9453: 
 9454:     if (ctxt == NULL) return;
 9455:     if (nargs == 0) {
 9456: 	if (ctxt->context->node == NULL) {
 9457: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
 9458: 	} else {
 9459: 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
 9460: 
 9461: 	    res = xmlXPathStringEvalNumber(content);
 9462: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9463: 	    xmlFree(content);
 9464: 	}
 9465: 	return;
 9466:     }
 9467: 
 9468:     CHECK_ARITY(1);
 9469:     cur = valuePop(ctxt);
 9470:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
 9471: }
 9472: 
 9473: /**
 9474:  * xmlXPathSumFunction:
 9475:  * @ctxt:  the XPath Parser context
 9476:  * @nargs:  the number of arguments
 9477:  *
 9478:  * Implement the sum() XPath function
 9479:  *    number sum(node-set)
 9480:  * The sum function returns the sum of the values of the nodes in
 9481:  * the argument node-set.
 9482:  */
 9483: void
 9484: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9485:     xmlXPathObjectPtr cur;
 9486:     int i;
 9487:     double res = 0.0;
 9488: 
 9489:     CHECK_ARITY(1);
 9490:     if ((ctxt->value == NULL) ||
 9491: 	((ctxt->value->type != XPATH_NODESET) &&
 9492: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 9493: 	XP_ERROR(XPATH_INVALID_TYPE);
 9494:     cur = valuePop(ctxt);
 9495: 
 9496:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
 9497: 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
 9498: 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
 9499: 	}
 9500:     }
 9501:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9502:     xmlXPathReleaseObject(ctxt->context, cur);
 9503: }
 9504: 
 9505: /*
 9506:  * To assure working code on multiple platforms, we want to only depend
 9507:  * upon the characteristic truncation of converting a floating point value
 9508:  * to an integer.  Unfortunately, because of the different storage sizes
 9509:  * of our internal floating point value (double) and integer (int), we
 9510:  * can't directly convert (see bug 301162).  This macro is a messy
 9511:  * 'workaround'
 9512:  */
 9513: #define XTRUNC(f, v)            \
 9514:     f = fmod((v), INT_MAX);     \
 9515:     f = (v) - (f) + (double)((int)(f));
 9516: 
 9517: /**
 9518:  * xmlXPathFloorFunction:
 9519:  * @ctxt:  the XPath Parser context
 9520:  * @nargs:  the number of arguments
 9521:  *
 9522:  * Implement the floor() XPath function
 9523:  *    number floor(number)
 9524:  * The floor function returns the largest (closest to positive infinity)
 9525:  * number that is not greater than the argument and that is an integer.
 9526:  */
 9527: void
 9528: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9529:     double f;
 9530: 
 9531:     CHECK_ARITY(1);
 9532:     CAST_TO_NUMBER;
 9533:     CHECK_TYPE(XPATH_NUMBER);
 9534: 
 9535:     XTRUNC(f, ctxt->value->floatval);
 9536:     if (f != ctxt->value->floatval) {
 9537: 	if (ctxt->value->floatval > 0)
 9538: 	    ctxt->value->floatval = f;
 9539: 	else
 9540: 	    ctxt->value->floatval = f - 1;
 9541:     }
 9542: }
 9543: 
 9544: /**
 9545:  * xmlXPathCeilingFunction:
 9546:  * @ctxt:  the XPath Parser context
 9547:  * @nargs:  the number of arguments
 9548:  *
 9549:  * Implement the ceiling() XPath function
 9550:  *    number ceiling(number)
 9551:  * The ceiling function returns the smallest (closest to negative infinity)
 9552:  * number that is not less than the argument and that is an integer.
 9553:  */
 9554: void
 9555: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9556:     double f;
 9557: 
 9558:     CHECK_ARITY(1);
 9559:     CAST_TO_NUMBER;
 9560:     CHECK_TYPE(XPATH_NUMBER);
 9561: 
 9562: #if 0
 9563:     ctxt->value->floatval = ceil(ctxt->value->floatval);
 9564: #else
 9565:     XTRUNC(f, ctxt->value->floatval);
 9566:     if (f != ctxt->value->floatval) {
 9567: 	if (ctxt->value->floatval > 0)
 9568: 	    ctxt->value->floatval = f + 1;
 9569: 	else {
 9570: 	    if (ctxt->value->floatval < 0 && f == 0)
 9571: 	        ctxt->value->floatval = xmlXPathNZERO;
 9572: 	    else
 9573: 	        ctxt->value->floatval = f;
 9574: 	}
 9575: 
 9576:     }
 9577: #endif
 9578: }
 9579: 
 9580: /**
 9581:  * xmlXPathRoundFunction:
 9582:  * @ctxt:  the XPath Parser context
 9583:  * @nargs:  the number of arguments
 9584:  *
 9585:  * Implement the round() XPath function
 9586:  *    number round(number)
 9587:  * The round function returns the number that is closest to the
 9588:  * argument and that is an integer. If there are two such numbers,
 9589:  * then the one that is even is returned.
 9590:  */
 9591: void
 9592: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9593:     double f;
 9594: 
 9595:     CHECK_ARITY(1);
 9596:     CAST_TO_NUMBER;
 9597:     CHECK_TYPE(XPATH_NUMBER);
 9598: 
 9599:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
 9600: 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
 9601: 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
 9602: 	(ctxt->value->floatval == 0.0))
 9603: 	return;
 9604: 
 9605:     XTRUNC(f, ctxt->value->floatval);
 9606:     if (ctxt->value->floatval < 0) {
 9607: 	if (ctxt->value->floatval < f - 0.5)
 9608: 	    ctxt->value->floatval = f - 1;
 9609: 	else
 9610: 	    ctxt->value->floatval = f;
 9611: 	if (ctxt->value->floatval == 0)
 9612: 	    ctxt->value->floatval = xmlXPathNZERO;
 9613:     } else {
 9614: 	if (ctxt->value->floatval < f + 0.5)
 9615: 	    ctxt->value->floatval = f;
 9616: 	else
 9617: 	    ctxt->value->floatval = f + 1;
 9618:     }
 9619: }
 9620: 
 9621: /************************************************************************
 9622:  *									*
 9623:  *			The Parser					*
 9624:  *									*
 9625:  ************************************************************************/
 9626: 
 9627: /*
 9628:  * a few forward declarations since we use a recursive call based
 9629:  * implementation.
 9630:  */
 9631: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
 9632: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
 9633: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
 9634: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
 9635: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
 9636: 	                                  int qualified);
 9637: 
 9638: /**
 9639:  * xmlXPathCurrentChar:
 9640:  * @ctxt:  the XPath parser context
 9641:  * @cur:  pointer to the beginning of the char
 9642:  * @len:  pointer to the length of the char read
 9643:  *
 9644:  * The current char value, if using UTF-8 this may actually span multiple
 9645:  * bytes in the input buffer.
 9646:  *
 9647:  * Returns the current char value and its length
 9648:  */
 9649: 
 9650: static int
 9651: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
 9652:     unsigned char c;
 9653:     unsigned int val;
 9654:     const xmlChar *cur;
 9655: 
 9656:     if (ctxt == NULL)
 9657: 	return(0);
 9658:     cur = ctxt->cur;
 9659: 
 9660:     /*
 9661:      * We are supposed to handle UTF8, check it's valid
 9662:      * From rfc2044: encoding of the Unicode values on UTF-8:
 9663:      *
 9664:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
 9665:      * 0000 0000-0000 007F   0xxxxxxx
 9666:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
 9667:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
 9668:      *
 9669:      * Check for the 0x110000 limit too
 9670:      */
 9671:     c = *cur;
 9672:     if (c & 0x80) {
 9673: 	if ((cur[1] & 0xc0) != 0x80)
 9674: 	    goto encoding_error;
 9675: 	if ((c & 0xe0) == 0xe0) {
 9676: 
 9677: 	    if ((cur[2] & 0xc0) != 0x80)
 9678: 		goto encoding_error;
 9679: 	    if ((c & 0xf0) == 0xf0) {
 9680: 		if (((c & 0xf8) != 0xf0) ||
 9681: 		    ((cur[3] & 0xc0) != 0x80))
 9682: 		    goto encoding_error;
 9683: 		/* 4-byte code */
 9684: 		*len = 4;
 9685: 		val = (cur[0] & 0x7) << 18;
 9686: 		val |= (cur[1] & 0x3f) << 12;
 9687: 		val |= (cur[2] & 0x3f) << 6;
 9688: 		val |= cur[3] & 0x3f;
 9689: 	    } else {
 9690: 	      /* 3-byte code */
 9691: 		*len = 3;
 9692: 		val = (cur[0] & 0xf) << 12;
 9693: 		val |= (cur[1] & 0x3f) << 6;
 9694: 		val |= cur[2] & 0x3f;
 9695: 	    }
 9696: 	} else {
 9697: 	  /* 2-byte code */
 9698: 	    *len = 2;
 9699: 	    val = (cur[0] & 0x1f) << 6;
 9700: 	    val |= cur[1] & 0x3f;
 9701: 	}
 9702: 	if (!IS_CHAR(val)) {
 9703: 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
 9704: 	}
 9705: 	return(val);
 9706:     } else {
 9707: 	/* 1-byte code */
 9708: 	*len = 1;
 9709: 	return((int) *cur);
 9710:     }
 9711: encoding_error:
 9712:     /*
 9713:      * If we detect an UTF8 error that probably means that the
 9714:      * input encoding didn't get properly advertised in the
 9715:      * declaration header. Report the error and switch the encoding
 9716:      * to ISO-Latin-1 (if you don't like this policy, just declare the
 9717:      * encoding !)
 9718:      */
 9719:     *len = 0;
 9720:     XP_ERROR0(XPATH_ENCODING_ERROR);
 9721: }
 9722: 
 9723: /**
 9724:  * xmlXPathParseNCName:
 9725:  * @ctxt:  the XPath Parser context
 9726:  *
 9727:  * parse an XML namespace non qualified name.
 9728:  *
 9729:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
 9730:  *
 9731:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
 9732:  *                       CombiningChar | Extender
 9733:  *
 9734:  * Returns the namespace name or NULL
 9735:  */
 9736: 
 9737: xmlChar *
 9738: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
 9739:     const xmlChar *in;
 9740:     xmlChar *ret;
 9741:     int count = 0;
 9742: 
 9743:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9744:     /*
 9745:      * Accelerator for simple ASCII names
 9746:      */
 9747:     in = ctxt->cur;
 9748:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9749: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9750: 	(*in == '_')) {
 9751: 	in++;
 9752: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9753: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9754: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9755: 	       (*in == '_') || (*in == '.') ||
 9756: 	       (*in == '-'))
 9757: 	    in++;
 9758: 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
 9759:             (*in == '[') || (*in == ']') || (*in == ':') ||
 9760:             (*in == '@') || (*in == '*')) {
 9761: 	    count = in - ctxt->cur;
 9762: 	    if (count == 0)
 9763: 		return(NULL);
 9764: 	    ret = xmlStrndup(ctxt->cur, count);
 9765: 	    ctxt->cur = in;
 9766: 	    return(ret);
 9767: 	}
 9768:     }
 9769:     return(xmlXPathParseNameComplex(ctxt, 0));
 9770: }
 9771: 
 9772: 
 9773: /**
 9774:  * xmlXPathParseQName:
 9775:  * @ctxt:  the XPath Parser context
 9776:  * @prefix:  a xmlChar **
 9777:  *
 9778:  * parse an XML qualified name
 9779:  *
 9780:  * [NS 5] QName ::= (Prefix ':')? LocalPart
 9781:  *
 9782:  * [NS 6] Prefix ::= NCName
 9783:  *
 9784:  * [NS 7] LocalPart ::= NCName
 9785:  *
 9786:  * Returns the function returns the local part, and prefix is updated
 9787:  *   to get the Prefix if any.
 9788:  */
 9789: 
 9790: static xmlChar *
 9791: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
 9792:     xmlChar *ret = NULL;
 9793: 
 9794:     *prefix = NULL;
 9795:     ret = xmlXPathParseNCName(ctxt);
 9796:     if (ret && CUR == ':') {
 9797:         *prefix = ret;
 9798: 	NEXT;
 9799: 	ret = xmlXPathParseNCName(ctxt);
 9800:     }
 9801:     return(ret);
 9802: }
 9803: 
 9804: /**
 9805:  * xmlXPathParseName:
 9806:  * @ctxt:  the XPath Parser context
 9807:  *
 9808:  * parse an XML name
 9809:  *
 9810:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
 9811:  *                  CombiningChar | Extender
 9812:  *
 9813:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
 9814:  *
 9815:  * Returns the namespace name or NULL
 9816:  */
 9817: 
 9818: xmlChar *
 9819: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
 9820:     const xmlChar *in;
 9821:     xmlChar *ret;
 9822:     int count = 0;
 9823: 
 9824:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9825:     /*
 9826:      * Accelerator for simple ASCII names
 9827:      */
 9828:     in = ctxt->cur;
 9829:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9830: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9831: 	(*in == '_') || (*in == ':')) {
 9832: 	in++;
 9833: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9834: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9835: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9836: 	       (*in == '_') || (*in == '-') ||
 9837: 	       (*in == ':') || (*in == '.'))
 9838: 	    in++;
 9839: 	if ((*in > 0) && (*in < 0x80)) {
 9840: 	    count = in - ctxt->cur;
 9841: 	    ret = xmlStrndup(ctxt->cur, count);
 9842: 	    ctxt->cur = in;
 9843: 	    return(ret);
 9844: 	}
 9845:     }
 9846:     return(xmlXPathParseNameComplex(ctxt, 1));
 9847: }
 9848: 
 9849: static xmlChar *
 9850: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
 9851:     xmlChar buf[XML_MAX_NAMELEN + 5];
 9852:     int len = 0, l;
 9853:     int c;
 9854: 
 9855:     /*
 9856:      * Handler for more complex cases
 9857:      */
 9858:     c = CUR_CHAR(l);
 9859:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
 9860:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
 9861:         (c == '*') || /* accelerators */
 9862: 	(!IS_LETTER(c) && (c != '_') &&
 9863:          ((qualified) && (c != ':')))) {
 9864: 	return(NULL);
 9865:     }
 9866: 
 9867:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
 9868: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
 9869:             (c == '.') || (c == '-') ||
 9870: 	    (c == '_') || ((qualified) && (c == ':')) ||
 9871: 	    (IS_COMBINING(c)) ||
 9872: 	    (IS_EXTENDER(c)))) {
 9873: 	COPY_BUF(l,buf,len,c);
 9874: 	NEXTL(l);
 9875: 	c = CUR_CHAR(l);
 9876: 	if (len >= XML_MAX_NAMELEN) {
 9877: 	    /*
 9878: 	     * Okay someone managed to make a huge name, so he's ready to pay
 9879: 	     * for the processing speed.
 9880: 	     */
 9881: 	    xmlChar *buffer;
 9882: 	    int max = len * 2;
 9883: 
 9884: 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
 9885: 	    if (buffer == NULL) {
 9886: 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
 9887: 	    }
 9888: 	    memcpy(buffer, buf, len);
 9889: 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
 9890: 		   (c == '.') || (c == '-') ||
 9891: 		   (c == '_') || ((qualified) && (c == ':')) ||
 9892: 		   (IS_COMBINING(c)) ||
 9893: 		   (IS_EXTENDER(c))) {
 9894: 		if (len + 10 > max) {
 9895: 		    max *= 2;
 9896: 		    buffer = (xmlChar *) xmlRealloc(buffer,
 9897: 			                            max * sizeof(xmlChar));
 9898: 		    if (buffer == NULL) {
 9899: 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
 9900: 		    }
 9901: 		}
 9902: 		COPY_BUF(l,buffer,len,c);
 9903: 		NEXTL(l);
 9904: 		c = CUR_CHAR(l);
 9905: 	    }
 9906: 	    buffer[len] = 0;
 9907: 	    return(buffer);
 9908: 	}
 9909:     }
 9910:     if (len == 0)
 9911: 	return(NULL);
 9912:     return(xmlStrndup(buf, len));
 9913: }
 9914: 
 9915: #define MAX_FRAC 20
 9916: 
 9917: /*
 9918:  * These are used as divisors for the fractional part of a number.
 9919:  * Since the table includes 1.0 (representing '0' fractional digits),
 9920:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
 9921:  */
 9922: static double my_pow10[MAX_FRAC+1] = {
 9923:     1.0, 10.0, 100.0, 1000.0, 10000.0,
 9924:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
 9925:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
 9926:     100000000000000.0,
 9927:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
 9928:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
 9929: };
 9930: 
 9931: /**
 9932:  * xmlXPathStringEvalNumber:
 9933:  * @str:  A string to scan
 9934:  *
 9935:  *  [30a]  Float  ::= Number ('e' Digits?)?
 9936:  *
 9937:  *  [30]   Number ::=   Digits ('.' Digits?)?
 9938:  *                    | '.' Digits
 9939:  *  [31]   Digits ::=   [0-9]+
 9940:  *
 9941:  * Compile a Number in the string
 9942:  * In complement of the Number expression, this function also handles
 9943:  * negative values : '-' Number.
 9944:  *
 9945:  * Returns the double value.
 9946:  */
 9947: double
 9948: xmlXPathStringEvalNumber(const xmlChar *str) {
 9949:     const xmlChar *cur = str;
 9950:     double ret;
 9951:     int ok = 0;
 9952:     int isneg = 0;
 9953:     int exponent = 0;
 9954:     int is_exponent_negative = 0;
 9955: #ifdef __GNUC__
 9956:     unsigned long tmp = 0;
 9957:     double temp;
 9958: #endif
 9959:     if (cur == NULL) return(0);
 9960:     while (IS_BLANK_CH(*cur)) cur++;
 9961:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
 9962:         return(xmlXPathNAN);
 9963:     }
 9964:     if (*cur == '-') {
 9965: 	isneg = 1;
 9966: 	cur++;
 9967:     }
 9968: 
 9969: #ifdef __GNUC__
 9970:     /*
 9971:      * tmp/temp is a workaround against a gcc compiler bug
 9972:      * http://veillard.com/gcc.bug
 9973:      */
 9974:     ret = 0;
 9975:     while ((*cur >= '0') && (*cur <= '9')) {
 9976: 	ret = ret * 10;
 9977: 	tmp = (*cur - '0');
 9978: 	ok = 1;
 9979: 	cur++;
 9980: 	temp = (double) tmp;
 9981: 	ret = ret + temp;
 9982:     }
 9983: #else
 9984:     ret = 0;
 9985:     while ((*cur >= '0') && (*cur <= '9')) {
 9986: 	ret = ret * 10 + (*cur - '0');
 9987: 	ok = 1;
 9988: 	cur++;
 9989:     }
 9990: #endif
 9991: 
 9992:     if (*cur == '.') {
 9993: 	int v, frac = 0;
 9994: 	double fraction = 0;
 9995: 
 9996:         cur++;
 9997: 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
 9998: 	    return(xmlXPathNAN);
 9999: 	}
10000: 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10001: 	    v = (*cur - '0');
10002: 	    fraction = fraction * 10 + v;
10003: 	    frac = frac + 1;
10004: 	    cur++;
10005: 	}
10006: 	fraction /= my_pow10[frac];
10007: 	ret = ret + fraction;
10008: 	while ((*cur >= '0') && (*cur <= '9'))
10009: 	    cur++;
10010:     }
10011:     if ((*cur == 'e') || (*cur == 'E')) {
10012:       cur++;
10013:       if (*cur == '-') {
10014: 	is_exponent_negative = 1;
10015: 	cur++;
10016:       } else if (*cur == '+') {
10017:         cur++;
10018:       }
10019:       while ((*cur >= '0') && (*cur <= '9')) {
10020: 	exponent = exponent * 10 + (*cur - '0');
10021: 	cur++;
10022:       }
10023:     }
10024:     while (IS_BLANK_CH(*cur)) cur++;
10025:     if (*cur != 0) return(xmlXPathNAN);
10026:     if (isneg) ret = -ret;
10027:     if (is_exponent_negative) exponent = -exponent;
10028:     ret *= pow(10.0, (double)exponent);
10029:     return(ret);
10030: }
10031: 
10032: /**
10033:  * xmlXPathCompNumber:
10034:  * @ctxt:  the XPath Parser context
10035:  *
10036:  *  [30]   Number ::=   Digits ('.' Digits?)?
10037:  *                    | '.' Digits
10038:  *  [31]   Digits ::=   [0-9]+
10039:  *
10040:  * Compile a Number, then push it on the stack
10041:  *
10042:  */
10043: static void
10044: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10045: {
10046:     double ret = 0.0;
10047:     double mult = 1;
10048:     int ok = 0;
10049:     int exponent = 0;
10050:     int is_exponent_negative = 0;
10051: #ifdef __GNUC__
10052:     unsigned long tmp = 0;
10053:     double temp;
10054: #endif
10055: 
10056:     CHECK_ERROR;
10057:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10058:         XP_ERROR(XPATH_NUMBER_ERROR);
10059:     }
10060: #ifdef __GNUC__
10061:     /*
10062:      * tmp/temp is a workaround against a gcc compiler bug
10063:      * http://veillard.com/gcc.bug
10064:      */
10065:     ret = 0;
10066:     while ((CUR >= '0') && (CUR <= '9')) {
10067: 	ret = ret * 10;
10068: 	tmp = (CUR - '0');
10069:         ok = 1;
10070:         NEXT;
10071: 	temp = (double) tmp;
10072: 	ret = ret + temp;
10073:     }
10074: #else
10075:     ret = 0;
10076:     while ((CUR >= '0') && (CUR <= '9')) {
10077: 	ret = ret * 10 + (CUR - '0');
10078: 	ok = 1;
10079: 	NEXT;
10080:     }
10081: #endif
10082:     if (CUR == '.') {
10083: 	int v, frac = 0;
10084: 	double fraction = 0;
10085: 
10086:         NEXT;
10087:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10088:             XP_ERROR(XPATH_NUMBER_ERROR);
10089:         }
10090:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10091: 	    v = (CUR - '0');
10092: 	    fraction = fraction * 10 + v;
10093: 	    frac = frac + 1;
10094:             NEXT;
10095:         }
10096:         fraction /= my_pow10[frac];
10097:         ret = ret + fraction;
10098:         while ((CUR >= '0') && (CUR <= '9'))
10099:             NEXT;
10100:     }
10101:     if ((CUR == 'e') || (CUR == 'E')) {
10102:         NEXT;
10103:         if (CUR == '-') {
10104:             is_exponent_negative = 1;
10105:             NEXT;
10106:         } else if (CUR == '+') {
10107: 	    NEXT;
10108: 	}
10109:         while ((CUR >= '0') && (CUR <= '9')) {
10110:             exponent = exponent * 10 + (CUR - '0');
10111:             NEXT;
10112:         }
10113:         if (is_exponent_negative)
10114:             exponent = -exponent;
10115:         ret *= pow(10.0, (double) exponent);
10116:     }
10117:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10118:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10119: }
10120: 
10121: /**
10122:  * xmlXPathParseLiteral:
10123:  * @ctxt:  the XPath Parser context
10124:  *
10125:  * Parse a Literal
10126:  *
10127:  *  [29]   Literal ::=   '"' [^"]* '"'
10128:  *                    | "'" [^']* "'"
10129:  *
10130:  * Returns the value found or NULL in case of error
10131:  */
10132: static xmlChar *
10133: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10134:     const xmlChar *q;
10135:     xmlChar *ret = NULL;
10136: 
10137:     if (CUR == '"') {
10138:         NEXT;
10139: 	q = CUR_PTR;
10140: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10141: 	    NEXT;
10142: 	if (!IS_CHAR_CH(CUR)) {
10143: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10144: 	} else {
10145: 	    ret = xmlStrndup(q, CUR_PTR - q);
10146: 	    NEXT;
10147:         }
10148:     } else if (CUR == '\'') {
10149:         NEXT;
10150: 	q = CUR_PTR;
10151: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10152: 	    NEXT;
10153: 	if (!IS_CHAR_CH(CUR)) {
10154: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10155: 	} else {
10156: 	    ret = xmlStrndup(q, CUR_PTR - q);
10157: 	    NEXT;
10158:         }
10159:     } else {
10160: 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10161:     }
10162:     return(ret);
10163: }
10164: 
10165: /**
10166:  * xmlXPathCompLiteral:
10167:  * @ctxt:  the XPath Parser context
10168:  *
10169:  * Parse a Literal and push it on the stack.
10170:  *
10171:  *  [29]   Literal ::=   '"' [^"]* '"'
10172:  *                    | "'" [^']* "'"
10173:  *
10174:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10175:  */
10176: static void
10177: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10178:     const xmlChar *q;
10179:     xmlChar *ret = NULL;
10180: 
10181:     if (CUR == '"') {
10182:         NEXT;
10183: 	q = CUR_PTR;
10184: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10185: 	    NEXT;
10186: 	if (!IS_CHAR_CH(CUR)) {
10187: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10188: 	} else {
10189: 	    ret = xmlStrndup(q, CUR_PTR - q);
10190: 	    NEXT;
10191:         }
10192:     } else if (CUR == '\'') {
10193:         NEXT;
10194: 	q = CUR_PTR;
10195: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10196: 	    NEXT;
10197: 	if (!IS_CHAR_CH(CUR)) {
10198: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10199: 	} else {
10200: 	    ret = xmlStrndup(q, CUR_PTR - q);
10201: 	    NEXT;
10202:         }
10203:     } else {
10204: 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10205:     }
10206:     if (ret == NULL) return;
10207:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10208: 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10209:     xmlFree(ret);
10210: }
10211: 
10212: /**
10213:  * xmlXPathCompVariableReference:
10214:  * @ctxt:  the XPath Parser context
10215:  *
10216:  * Parse a VariableReference, evaluate it and push it on the stack.
10217:  *
10218:  * The variable bindings consist of a mapping from variable names
10219:  * to variable values. The value of a variable is an object, which can be
10220:  * of any of the types that are possible for the value of an expression,
10221:  * and may also be of additional types not specified here.
10222:  *
10223:  * Early evaluation is possible since:
10224:  * The variable bindings [...] used to evaluate a subexpression are
10225:  * always the same as those used to evaluate the containing expression.
10226:  *
10227:  *  [36]   VariableReference ::=   '$' QName
10228:  */
10229: static void
10230: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10231:     xmlChar *name;
10232:     xmlChar *prefix;
10233: 
10234:     SKIP_BLANKS;
10235:     if (CUR != '$') {
10236: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10237:     }
10238:     NEXT;
10239:     name = xmlXPathParseQName(ctxt, &prefix);
10240:     if (name == NULL) {
10241: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10242:     }
10243:     ctxt->comp->last = -1;
10244:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10245: 	           name, prefix);
10246:     SKIP_BLANKS;
10247:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10248: 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10249:     }
10250: }
10251: 
10252: /**
10253:  * xmlXPathIsNodeType:
10254:  * @name:  a name string
10255:  *
10256:  * Is the name given a NodeType one.
10257:  *
10258:  *  [38]   NodeType ::=   'comment'
10259:  *                    | 'text'
10260:  *                    | 'processing-instruction'
10261:  *                    | 'node'
10262:  *
10263:  * Returns 1 if true 0 otherwise
10264:  */
10265: int
10266: xmlXPathIsNodeType(const xmlChar *name) {
10267:     if (name == NULL)
10268: 	return(0);
10269: 
10270:     if (xmlStrEqual(name, BAD_CAST "node"))
10271: 	return(1);
10272:     if (xmlStrEqual(name, BAD_CAST "text"))
10273: 	return(1);
10274:     if (xmlStrEqual(name, BAD_CAST "comment"))
10275: 	return(1);
10276:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10277: 	return(1);
10278:     return(0);
10279: }
10280: 
10281: /**
10282:  * xmlXPathCompFunctionCall:
10283:  * @ctxt:  the XPath Parser context
10284:  *
10285:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10286:  *  [17]   Argument ::=   Expr
10287:  *
10288:  * Compile a function call, the evaluation of all arguments are
10289:  * pushed on the stack
10290:  */
10291: static void
10292: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10293:     xmlChar *name;
10294:     xmlChar *prefix;
10295:     int nbargs = 0;
10296:     int sort = 1;
10297: 
10298:     name = xmlXPathParseQName(ctxt, &prefix);
10299:     if (name == NULL) {
10300: 	xmlFree(prefix);
10301: 	XP_ERROR(XPATH_EXPR_ERROR);
10302:     }
10303:     SKIP_BLANKS;
10304: #ifdef DEBUG_EXPR
10305:     if (prefix == NULL)
10306: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10307: 			name);
10308:     else
10309: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10310: 			prefix, name);
10311: #endif
10312: 
10313:     if (CUR != '(') {
10314: 	XP_ERROR(XPATH_EXPR_ERROR);
10315:     }
10316:     NEXT;
10317:     SKIP_BLANKS;
10318: 
10319:     /*
10320:     * Optimization for count(): we don't need the node-set to be sorted.
10321:     */
10322:     if ((prefix == NULL) && (name[0] == 'c') &&
10323: 	xmlStrEqual(name, BAD_CAST "count"))
10324:     {
10325: 	sort = 0;
10326:     }
10327:     ctxt->comp->last = -1;
10328:     if (CUR != ')') {
10329: 	while (CUR != 0) {
10330: 	    int op1 = ctxt->comp->last;
10331: 	    ctxt->comp->last = -1;
10332: 	    xmlXPathCompileExpr(ctxt, sort);
10333: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10334: 		xmlFree(name);
10335: 		xmlFree(prefix);
10336: 		return;
10337: 	    }
10338: 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10339: 	    nbargs++;
10340: 	    if (CUR == ')') break;
10341: 	    if (CUR != ',') {
10342: 		XP_ERROR(XPATH_EXPR_ERROR);
10343: 	    }
10344: 	    NEXT;
10345: 	    SKIP_BLANKS;
10346: 	}
10347:     }
10348:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10349: 	           name, prefix);
10350:     NEXT;
10351:     SKIP_BLANKS;
10352: }
10353: 
10354: /**
10355:  * xmlXPathCompPrimaryExpr:
10356:  * @ctxt:  the XPath Parser context
10357:  *
10358:  *  [15]   PrimaryExpr ::=   VariableReference
10359:  *                | '(' Expr ')'
10360:  *                | Literal
10361:  *                | Number
10362:  *                | FunctionCall
10363:  *
10364:  * Compile a primary expression.
10365:  */
10366: static void
10367: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10368:     SKIP_BLANKS;
10369:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10370:     else if (CUR == '(') {
10371: 	NEXT;
10372: 	SKIP_BLANKS;
10373: 	xmlXPathCompileExpr(ctxt, 1);
10374: 	CHECK_ERROR;
10375: 	if (CUR != ')') {
10376: 	    XP_ERROR(XPATH_EXPR_ERROR);
10377: 	}
10378: 	NEXT;
10379: 	SKIP_BLANKS;
10380:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10381: 	xmlXPathCompNumber(ctxt);
10382:     } else if ((CUR == '\'') || (CUR == '"')) {
10383: 	xmlXPathCompLiteral(ctxt);
10384:     } else {
10385: 	xmlXPathCompFunctionCall(ctxt);
10386:     }
10387:     SKIP_BLANKS;
10388: }
10389: 
10390: /**
10391:  * xmlXPathCompFilterExpr:
10392:  * @ctxt:  the XPath Parser context
10393:  *
10394:  *  [20]   FilterExpr ::=   PrimaryExpr
10395:  *               | FilterExpr Predicate
10396:  *
10397:  * Compile a filter expression.
10398:  * Square brackets are used to filter expressions in the same way that
10399:  * they are used in location paths. It is an error if the expression to
10400:  * be filtered does not evaluate to a node-set. The context node list
10401:  * used for evaluating the expression in square brackets is the node-set
10402:  * to be filtered listed in document order.
10403:  */
10404: 
10405: static void
10406: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10407:     xmlXPathCompPrimaryExpr(ctxt);
10408:     CHECK_ERROR;
10409:     SKIP_BLANKS;
10410: 
10411:     while (CUR == '[') {
10412: 	xmlXPathCompPredicate(ctxt, 1);
10413: 	SKIP_BLANKS;
10414:     }
10415: 
10416: 
10417: }
10418: 
10419: /**
10420:  * xmlXPathScanName:
10421:  * @ctxt:  the XPath Parser context
10422:  *
10423:  * Trickery: parse an XML name but without consuming the input flow
10424:  * Needed to avoid insanity in the parser state.
10425:  *
10426:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10427:  *                  CombiningChar | Extender
10428:  *
10429:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10430:  *
10431:  * [6] Names ::= Name (S Name)*
10432:  *
10433:  * Returns the Name parsed or NULL
10434:  */
10435: 
10436: static xmlChar *
10437: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10438:     int len = 0, l;
10439:     int c;
10440:     const xmlChar *cur;
10441:     xmlChar *ret;
10442: 
10443:     cur = ctxt->cur;
10444: 
10445:     c = CUR_CHAR(l);
10446:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10447: 	(!IS_LETTER(c) && (c != '_') &&
10448:          (c != ':'))) {
10449: 	return(NULL);
10450:     }
10451: 
10452:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10453: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10454:             (c == '.') || (c == '-') ||
10455: 	    (c == '_') || (c == ':') ||
10456: 	    (IS_COMBINING(c)) ||
10457: 	    (IS_EXTENDER(c)))) {
10458: 	len += l;
10459: 	NEXTL(l);
10460: 	c = CUR_CHAR(l);
10461:     }
10462:     ret = xmlStrndup(cur, ctxt->cur - cur);
10463:     ctxt->cur = cur;
10464:     return(ret);
10465: }
10466: 
10467: /**
10468:  * xmlXPathCompPathExpr:
10469:  * @ctxt:  the XPath Parser context
10470:  *
10471:  *  [19]   PathExpr ::=   LocationPath
10472:  *               | FilterExpr
10473:  *               | FilterExpr '/' RelativeLocationPath
10474:  *               | FilterExpr '//' RelativeLocationPath
10475:  *
10476:  * Compile a path expression.
10477:  * The / operator and // operators combine an arbitrary expression
10478:  * and a relative location path. It is an error if the expression
10479:  * does not evaluate to a node-set.
10480:  * The / operator does composition in the same way as when / is
10481:  * used in a location path. As in location paths, // is short for
10482:  * /descendant-or-self::node()/.
10483:  */
10484: 
10485: static void
10486: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10487:     int lc = 1;           /* Should we branch to LocationPath ?         */
10488:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10489: 
10490:     SKIP_BLANKS;
10491:     if ((CUR == '$') || (CUR == '(') ||
10492: 	(IS_ASCII_DIGIT(CUR)) ||
10493:         (CUR == '\'') || (CUR == '"') ||
10494: 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10495: 	lc = 0;
10496:     } else if (CUR == '*') {
10497: 	/* relative or absolute location path */
10498: 	lc = 1;
10499:     } else if (CUR == '/') {
10500: 	/* relative or absolute location path */
10501: 	lc = 1;
10502:     } else if (CUR == '@') {
10503: 	/* relative abbreviated attribute location path */
10504: 	lc = 1;
10505:     } else if (CUR == '.') {
10506: 	/* relative abbreviated attribute location path */
10507: 	lc = 1;
10508:     } else {
10509: 	/*
10510: 	 * Problem is finding if we have a name here whether it's:
10511: 	 *   - a nodetype
10512: 	 *   - a function call in which case it's followed by '('
10513: 	 *   - an axis in which case it's followed by ':'
10514: 	 *   - a element name
10515: 	 * We do an a priori analysis here rather than having to
10516: 	 * maintain parsed token content through the recursive function
10517: 	 * calls. This looks uglier but makes the code easier to
10518: 	 * read/write/debug.
10519: 	 */
10520: 	SKIP_BLANKS;
10521: 	name = xmlXPathScanName(ctxt);
10522: 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10523: #ifdef DEBUG_STEP
10524: 	    xmlGenericError(xmlGenericErrorContext,
10525: 		    "PathExpr: Axis\n");
10526: #endif
10527: 	    lc = 1;
10528: 	    xmlFree(name);
10529: 	} else if (name != NULL) {
10530: 	    int len =xmlStrlen(name);
10531: 
10532: 
10533: 	    while (NXT(len) != 0) {
10534: 		if (NXT(len) == '/') {
10535: 		    /* element name */
10536: #ifdef DEBUG_STEP
10537: 		    xmlGenericError(xmlGenericErrorContext,
10538: 			    "PathExpr: AbbrRelLocation\n");
10539: #endif
10540: 		    lc = 1;
10541: 		    break;
10542: 		} else if (IS_BLANK_CH(NXT(len))) {
10543: 		    /* ignore blanks */
10544: 		    ;
10545: 		} else if (NXT(len) == ':') {
10546: #ifdef DEBUG_STEP
10547: 		    xmlGenericError(xmlGenericErrorContext,
10548: 			    "PathExpr: AbbrRelLocation\n");
10549: #endif
10550: 		    lc = 1;
10551: 		    break;
10552: 		} else if ((NXT(len) == '(')) {
10553: 		    /* Note Type or Function */
10554: 		    if (xmlXPathIsNodeType(name)) {
10555: #ifdef DEBUG_STEP
10556: 		        xmlGenericError(xmlGenericErrorContext,
10557: 				"PathExpr: Type search\n");
10558: #endif
10559: 			lc = 1;
10560: 		    } else {
10561: #ifdef DEBUG_STEP
10562: 		        xmlGenericError(xmlGenericErrorContext,
10563: 				"PathExpr: function call\n");
10564: #endif
10565: 			lc = 0;
10566: 		    }
10567:                     break;
10568: 		} else if ((NXT(len) == '[')) {
10569: 		    /* element name */
10570: #ifdef DEBUG_STEP
10571: 		    xmlGenericError(xmlGenericErrorContext,
10572: 			    "PathExpr: AbbrRelLocation\n");
10573: #endif
10574: 		    lc = 1;
10575: 		    break;
10576: 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10577: 			   (NXT(len) == '=')) {
10578: 		    lc = 1;
10579: 		    break;
10580: 		} else {
10581: 		    lc = 1;
10582: 		    break;
10583: 		}
10584: 		len++;
10585: 	    }
10586: 	    if (NXT(len) == 0) {
10587: #ifdef DEBUG_STEP
10588: 		xmlGenericError(xmlGenericErrorContext,
10589: 			"PathExpr: AbbrRelLocation\n");
10590: #endif
10591: 		/* element name */
10592: 		lc = 1;
10593: 	    }
10594: 	    xmlFree(name);
10595: 	} else {
10596: 	    /* make sure all cases are covered explicitly */
10597: 	    XP_ERROR(XPATH_EXPR_ERROR);
10598: 	}
10599:     }
10600: 
10601:     if (lc) {
10602: 	if (CUR == '/') {
10603: 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10604: 	} else {
10605: 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10606: 	}
10607: 	xmlXPathCompLocationPath(ctxt);
10608:     } else {
10609: 	xmlXPathCompFilterExpr(ctxt);
10610: 	CHECK_ERROR;
10611: 	if ((CUR == '/') && (NXT(1) == '/')) {
10612: 	    SKIP(2);
10613: 	    SKIP_BLANKS;
10614: 
10615: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10616: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10617: 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10618: 
10619: 	    xmlXPathCompRelativeLocationPath(ctxt);
10620: 	} else if (CUR == '/') {
10621: 	    xmlXPathCompRelativeLocationPath(ctxt);
10622: 	}
10623:     }
10624:     SKIP_BLANKS;
10625: }
10626: 
10627: /**
10628:  * xmlXPathCompUnionExpr:
10629:  * @ctxt:  the XPath Parser context
10630:  *
10631:  *  [18]   UnionExpr ::=   PathExpr
10632:  *               | UnionExpr '|' PathExpr
10633:  *
10634:  * Compile an union expression.
10635:  */
10636: 
10637: static void
10638: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10639:     xmlXPathCompPathExpr(ctxt);
10640:     CHECK_ERROR;
10641:     SKIP_BLANKS;
10642:     while (CUR == '|') {
10643: 	int op1 = ctxt->comp->last;
10644: 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10645: 
10646: 	NEXT;
10647: 	SKIP_BLANKS;
10648: 	xmlXPathCompPathExpr(ctxt);
10649: 
10650: 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10651: 
10652: 	SKIP_BLANKS;
10653:     }
10654: }
10655: 
10656: /**
10657:  * xmlXPathCompUnaryExpr:
10658:  * @ctxt:  the XPath Parser context
10659:  *
10660:  *  [27]   UnaryExpr ::=   UnionExpr
10661:  *                   | '-' UnaryExpr
10662:  *
10663:  * Compile an unary expression.
10664:  */
10665: 
10666: static void
10667: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10668:     int minus = 0;
10669:     int found = 0;
10670: 
10671:     SKIP_BLANKS;
10672:     while (CUR == '-') {
10673:         minus = 1 - minus;
10674: 	found = 1;
10675: 	NEXT;
10676: 	SKIP_BLANKS;
10677:     }
10678: 
10679:     xmlXPathCompUnionExpr(ctxt);
10680:     CHECK_ERROR;
10681:     if (found) {
10682: 	if (minus)
10683: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10684: 	else
10685: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10686:     }
10687: }
10688: 
10689: /**
10690:  * xmlXPathCompMultiplicativeExpr:
10691:  * @ctxt:  the XPath Parser context
10692:  *
10693:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10694:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10695:  *                   | MultiplicativeExpr 'div' UnaryExpr
10696:  *                   | MultiplicativeExpr 'mod' UnaryExpr
10697:  *  [34]   MultiplyOperator ::=   '*'
10698:  *
10699:  * Compile an Additive expression.
10700:  */
10701: 
10702: static void
10703: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10704:     xmlXPathCompUnaryExpr(ctxt);
10705:     CHECK_ERROR;
10706:     SKIP_BLANKS;
10707:     while ((CUR == '*') ||
10708:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10709:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10710: 	int op = -1;
10711: 	int op1 = ctxt->comp->last;
10712: 
10713:         if (CUR == '*') {
10714: 	    op = 0;
10715: 	    NEXT;
10716: 	} else if (CUR == 'd') {
10717: 	    op = 1;
10718: 	    SKIP(3);
10719: 	} else if (CUR == 'm') {
10720: 	    op = 2;
10721: 	    SKIP(3);
10722: 	}
10723: 	SKIP_BLANKS;
10724:         xmlXPathCompUnaryExpr(ctxt);
10725: 	CHECK_ERROR;
10726: 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10727: 	SKIP_BLANKS;
10728:     }
10729: }
10730: 
10731: /**
10732:  * xmlXPathCompAdditiveExpr:
10733:  * @ctxt:  the XPath Parser context
10734:  *
10735:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10736:  *                   | AdditiveExpr '+' MultiplicativeExpr
10737:  *                   | AdditiveExpr '-' MultiplicativeExpr
10738:  *
10739:  * Compile an Additive expression.
10740:  */
10741: 
10742: static void
10743: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10744: 
10745:     xmlXPathCompMultiplicativeExpr(ctxt);
10746:     CHECK_ERROR;
10747:     SKIP_BLANKS;
10748:     while ((CUR == '+') || (CUR == '-')) {
10749: 	int plus;
10750: 	int op1 = ctxt->comp->last;
10751: 
10752:         if (CUR == '+') plus = 1;
10753: 	else plus = 0;
10754: 	NEXT;
10755: 	SKIP_BLANKS;
10756:         xmlXPathCompMultiplicativeExpr(ctxt);
10757: 	CHECK_ERROR;
10758: 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10759: 	SKIP_BLANKS;
10760:     }
10761: }
10762: 
10763: /**
10764:  * xmlXPathCompRelationalExpr:
10765:  * @ctxt:  the XPath Parser context
10766:  *
10767:  *  [24]   RelationalExpr ::=   AdditiveExpr
10768:  *                 | RelationalExpr '<' AdditiveExpr
10769:  *                 | RelationalExpr '>' AdditiveExpr
10770:  *                 | RelationalExpr '<=' AdditiveExpr
10771:  *                 | RelationalExpr '>=' AdditiveExpr
10772:  *
10773:  *  A <= B > C is allowed ? Answer from James, yes with
10774:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10775:  *  which is basically what got implemented.
10776:  *
10777:  * Compile a Relational expression, then push the result
10778:  * on the stack
10779:  */
10780: 
10781: static void
10782: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10783:     xmlXPathCompAdditiveExpr(ctxt);
10784:     CHECK_ERROR;
10785:     SKIP_BLANKS;
10786:     while ((CUR == '<') ||
10787:            (CUR == '>') ||
10788:            ((CUR == '<') && (NXT(1) == '=')) ||
10789:            ((CUR == '>') && (NXT(1) == '='))) {
10790: 	int inf, strict;
10791: 	int op1 = ctxt->comp->last;
10792: 
10793:         if (CUR == '<') inf = 1;
10794: 	else inf = 0;
10795: 	if (NXT(1) == '=') strict = 0;
10796: 	else strict = 1;
10797: 	NEXT;
10798: 	if (!strict) NEXT;
10799: 	SKIP_BLANKS;
10800:         xmlXPathCompAdditiveExpr(ctxt);
10801: 	CHECK_ERROR;
10802: 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10803: 	SKIP_BLANKS;
10804:     }
10805: }
10806: 
10807: /**
10808:  * xmlXPathCompEqualityExpr:
10809:  * @ctxt:  the XPath Parser context
10810:  *
10811:  *  [23]   EqualityExpr ::=   RelationalExpr
10812:  *                 | EqualityExpr '=' RelationalExpr
10813:  *                 | EqualityExpr '!=' RelationalExpr
10814:  *
10815:  *  A != B != C is allowed ? Answer from James, yes with
10816:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10817:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10818:  *  which is basically what got implemented.
10819:  *
10820:  * Compile an Equality expression.
10821:  *
10822:  */
10823: static void
10824: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10825:     xmlXPathCompRelationalExpr(ctxt);
10826:     CHECK_ERROR;
10827:     SKIP_BLANKS;
10828:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10829: 	int eq;
10830: 	int op1 = ctxt->comp->last;
10831: 
10832:         if (CUR == '=') eq = 1;
10833: 	else eq = 0;
10834: 	NEXT;
10835: 	if (!eq) NEXT;
10836: 	SKIP_BLANKS;
10837:         xmlXPathCompRelationalExpr(ctxt);
10838: 	CHECK_ERROR;
10839: 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10840: 	SKIP_BLANKS;
10841:     }
10842: }
10843: 
10844: /**
10845:  * xmlXPathCompAndExpr:
10846:  * @ctxt:  the XPath Parser context
10847:  *
10848:  *  [22]   AndExpr ::=   EqualityExpr
10849:  *                 | AndExpr 'and' EqualityExpr
10850:  *
10851:  * Compile an AND expression.
10852:  *
10853:  */
10854: static void
10855: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10856:     xmlXPathCompEqualityExpr(ctxt);
10857:     CHECK_ERROR;
10858:     SKIP_BLANKS;
10859:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10860: 	int op1 = ctxt->comp->last;
10861:         SKIP(3);
10862: 	SKIP_BLANKS;
10863:         xmlXPathCompEqualityExpr(ctxt);
10864: 	CHECK_ERROR;
10865: 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10866: 	SKIP_BLANKS;
10867:     }
10868: }
10869: 
10870: /**
10871:  * xmlXPathCompileExpr:
10872:  * @ctxt:  the XPath Parser context
10873:  *
10874:  *  [14]   Expr ::=   OrExpr
10875:  *  [21]   OrExpr ::=   AndExpr
10876:  *                 | OrExpr 'or' AndExpr
10877:  *
10878:  * Parse and compile an expression
10879:  */
10880: static void
10881: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10882:     xmlXPathCompAndExpr(ctxt);
10883:     CHECK_ERROR;
10884:     SKIP_BLANKS;
10885:     while ((CUR == 'o') && (NXT(1) == 'r')) {
10886: 	int op1 = ctxt->comp->last;
10887:         SKIP(2);
10888: 	SKIP_BLANKS;
10889:         xmlXPathCompAndExpr(ctxt);
10890: 	CHECK_ERROR;
10891: 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10892: 	SKIP_BLANKS;
10893:     }
10894:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10895: 	/* more ops could be optimized too */
10896: 	/*
10897: 	* This is the main place to eliminate sorting for
10898: 	* operations which don't require a sorted node-set.
10899: 	* E.g. count().
10900: 	*/
10901: 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10902:     }
10903: }
10904: 
10905: /**
10906:  * xmlXPathCompPredicate:
10907:  * @ctxt:  the XPath Parser context
10908:  * @filter:  act as a filter
10909:  *
10910:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10911:  *  [9]   PredicateExpr ::=   Expr
10912:  *
10913:  * Compile a predicate expression
10914:  */
10915: static void
10916: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10917:     int op1 = ctxt->comp->last;
10918: 
10919:     SKIP_BLANKS;
10920:     if (CUR != '[') {
10921: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922:     }
10923:     NEXT;
10924:     SKIP_BLANKS;
10925: 
10926:     ctxt->comp->last = -1;
10927:     /*
10928:     * This call to xmlXPathCompileExpr() will deactivate sorting
10929:     * of the predicate result.
10930:     * TODO: Sorting is still activated for filters, since I'm not
10931:     *  sure if needed. Normally sorting should not be needed, since
10932:     *  a filter can only diminish the number of items in a sequence,
10933:     *  but won't change its order; so if the initial sequence is sorted,
10934:     *  subsequent sorting is not needed.
10935:     */
10936:     if (! filter)
10937: 	xmlXPathCompileExpr(ctxt, 0);
10938:     else
10939: 	xmlXPathCompileExpr(ctxt, 1);
10940:     CHECK_ERROR;
10941: 
10942:     if (CUR != ']') {
10943: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10944:     }
10945: 
10946:     if (filter)
10947: 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10948:     else
10949: 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10950: 
10951:     NEXT;
10952:     SKIP_BLANKS;
10953: }
10954: 
10955: /**
10956:  * xmlXPathCompNodeTest:
10957:  * @ctxt:  the XPath Parser context
10958:  * @test:  pointer to a xmlXPathTestVal
10959:  * @type:  pointer to a xmlXPathTypeVal
10960:  * @prefix:  placeholder for a possible name prefix
10961:  *
10962:  * [7] NodeTest ::=   NameTest
10963:  *		    | NodeType '(' ')'
10964:  *		    | 'processing-instruction' '(' Literal ')'
10965:  *
10966:  * [37] NameTest ::=  '*'
10967:  *		    | NCName ':' '*'
10968:  *		    | QName
10969:  * [38] NodeType ::= 'comment'
10970:  *		   | 'text'
10971:  *		   | 'processing-instruction'
10972:  *		   | 'node'
10973:  *
10974:  * Returns the name found and updates @test, @type and @prefix appropriately
10975:  */
10976: static xmlChar *
10977: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10978: 	             xmlXPathTypeVal *type, const xmlChar **prefix,
10979: 		     xmlChar *name) {
10980:     int blanks;
10981: 
10982:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10983: 	STRANGE;
10984: 	return(NULL);
10985:     }
10986:     *type = (xmlXPathTypeVal) 0;
10987:     *test = (xmlXPathTestVal) 0;
10988:     *prefix = NULL;
10989:     SKIP_BLANKS;
10990: 
10991:     if ((name == NULL) && (CUR == '*')) {
10992: 	/*
10993: 	 * All elements
10994: 	 */
10995: 	NEXT;
10996: 	*test = NODE_TEST_ALL;
10997: 	return(NULL);
10998:     }
10999: 
11000:     if (name == NULL)
11001: 	name = xmlXPathParseNCName(ctxt);
11002:     if (name == NULL) {
11003: 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11004:     }
11005: 
11006:     blanks = IS_BLANK_CH(CUR);
11007:     SKIP_BLANKS;
11008:     if (CUR == '(') {
11009: 	NEXT;
11010: 	/*
11011: 	 * NodeType or PI search
11012: 	 */
11013: 	if (xmlStrEqual(name, BAD_CAST "comment"))
11014: 	    *type = NODE_TYPE_COMMENT;
11015: 	else if (xmlStrEqual(name, BAD_CAST "node"))
11016: 	    *type = NODE_TYPE_NODE;
11017: 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11018: 	    *type = NODE_TYPE_PI;
11019: 	else if (xmlStrEqual(name, BAD_CAST "text"))
11020: 	    *type = NODE_TYPE_TEXT;
11021: 	else {
11022: 	    if (name != NULL)
11023: 		xmlFree(name);
11024: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11025: 	}
11026: 
11027: 	*test = NODE_TEST_TYPE;
11028: 
11029: 	SKIP_BLANKS;
11030: 	if (*type == NODE_TYPE_PI) {
11031: 	    /*
11032: 	     * Specific case: search a PI by name.
11033: 	     */
11034: 	    if (name != NULL)
11035: 		xmlFree(name);
11036: 	    name = NULL;
11037: 	    if (CUR != ')') {
11038: 		name = xmlXPathParseLiteral(ctxt);
11039: 		CHECK_ERROR NULL;
11040: 		*test = NODE_TEST_PI;
11041: 		SKIP_BLANKS;
11042: 	    }
11043: 	}
11044: 	if (CUR != ')') {
11045: 	    if (name != NULL)
11046: 		xmlFree(name);
11047: 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11048: 	}
11049: 	NEXT;
11050: 	return(name);
11051:     }
11052:     *test = NODE_TEST_NAME;
11053:     if ((!blanks) && (CUR == ':')) {
11054: 	NEXT;
11055: 
11056: 	/*
11057: 	 * Since currently the parser context don't have a
11058: 	 * namespace list associated:
11059: 	 * The namespace name for this prefix can be computed
11060: 	 * only at evaluation time. The compilation is done
11061: 	 * outside of any context.
11062: 	 */
11063: #if 0
11064: 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11065: 	if (name != NULL)
11066: 	    xmlFree(name);
11067: 	if (*prefix == NULL) {
11068: 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11069: 	}
11070: #else
11071: 	*prefix = name;
11072: #endif
11073: 
11074: 	if (CUR == '*') {
11075: 	    /*
11076: 	     * All elements
11077: 	     */
11078: 	    NEXT;
11079: 	    *test = NODE_TEST_ALL;
11080: 	    return(NULL);
11081: 	}
11082: 
11083: 	name = xmlXPathParseNCName(ctxt);
11084: 	if (name == NULL) {
11085: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11086: 	}
11087:     }
11088:     return(name);
11089: }
11090: 
11091: /**
11092:  * xmlXPathIsAxisName:
11093:  * @name:  a preparsed name token
11094:  *
11095:  * [6] AxisName ::=   'ancestor'
11096:  *                  | 'ancestor-or-self'
11097:  *                  | 'attribute'
11098:  *                  | 'child'
11099:  *                  | 'descendant'
11100:  *                  | 'descendant-or-self'
11101:  *                  | 'following'
11102:  *                  | 'following-sibling'
11103:  *                  | 'namespace'
11104:  *                  | 'parent'
11105:  *                  | 'preceding'
11106:  *                  | 'preceding-sibling'
11107:  *                  | 'self'
11108:  *
11109:  * Returns the axis or 0
11110:  */
11111: static xmlXPathAxisVal
11112: xmlXPathIsAxisName(const xmlChar *name) {
11113:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11114:     switch (name[0]) {
11115: 	case 'a':
11116: 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11117: 		ret = AXIS_ANCESTOR;
11118: 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11119: 		ret = AXIS_ANCESTOR_OR_SELF;
11120: 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11121: 		ret = AXIS_ATTRIBUTE;
11122: 	    break;
11123: 	case 'c':
11124: 	    if (xmlStrEqual(name, BAD_CAST "child"))
11125: 		ret = AXIS_CHILD;
11126: 	    break;
11127: 	case 'd':
11128: 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11129: 		ret = AXIS_DESCENDANT;
11130: 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11131: 		ret = AXIS_DESCENDANT_OR_SELF;
11132: 	    break;
11133: 	case 'f':
11134: 	    if (xmlStrEqual(name, BAD_CAST "following"))
11135: 		ret = AXIS_FOLLOWING;
11136: 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11137: 		ret = AXIS_FOLLOWING_SIBLING;
11138: 	    break;
11139: 	case 'n':
11140: 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11141: 		ret = AXIS_NAMESPACE;
11142: 	    break;
11143: 	case 'p':
11144: 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11145: 		ret = AXIS_PARENT;
11146: 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11147: 		ret = AXIS_PRECEDING;
11148: 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11149: 		ret = AXIS_PRECEDING_SIBLING;
11150: 	    break;
11151: 	case 's':
11152: 	    if (xmlStrEqual(name, BAD_CAST "self"))
11153: 		ret = AXIS_SELF;
11154: 	    break;
11155:     }
11156:     return(ret);
11157: }
11158: 
11159: /**
11160:  * xmlXPathCompStep:
11161:  * @ctxt:  the XPath Parser context
11162:  *
11163:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11164:  *                  | AbbreviatedStep
11165:  *
11166:  * [12] AbbreviatedStep ::=   '.' | '..'
11167:  *
11168:  * [5] AxisSpecifier ::= AxisName '::'
11169:  *                  | AbbreviatedAxisSpecifier
11170:  *
11171:  * [13] AbbreviatedAxisSpecifier ::= '@'?
11172:  *
11173:  * Modified for XPtr range support as:
11174:  *
11175:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11176:  *                     | AbbreviatedStep
11177:  *                     | 'range-to' '(' Expr ')' Predicate*
11178:  *
11179:  * Compile one step in a Location Path
11180:  * A location step of . is short for self::node(). This is
11181:  * particularly useful in conjunction with //. For example, the
11182:  * location path .//para is short for
11183:  * self::node()/descendant-or-self::node()/child::para
11184:  * and so will select all para descendant elements of the context
11185:  * node.
11186:  * Similarly, a location step of .. is short for parent::node().
11187:  * For example, ../title is short for parent::node()/child::title
11188:  * and so will select the title children of the parent of the context
11189:  * node.
11190:  */
11191: static void
11192: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11193: #ifdef LIBXML_XPTR_ENABLED
11194:     int rangeto = 0;
11195:     int op2 = -1;
11196: #endif
11197: 
11198:     SKIP_BLANKS;
11199:     if ((CUR == '.') && (NXT(1) == '.')) {
11200: 	SKIP(2);
11201: 	SKIP_BLANKS;
11202: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11203: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11204:     } else if (CUR == '.') {
11205: 	NEXT;
11206: 	SKIP_BLANKS;
11207:     } else {
11208: 	xmlChar *name = NULL;
11209: 	const xmlChar *prefix = NULL;
11210: 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11211: 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11212: 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11213: 	int op1;
11214: 
11215: 	/*
11216: 	 * The modification needed for XPointer change to the production
11217: 	 */
11218: #ifdef LIBXML_XPTR_ENABLED
11219: 	if (ctxt->xptr) {
11220: 	    name = xmlXPathParseNCName(ctxt);
11221: 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11222:                 op2 = ctxt->comp->last;
11223: 		xmlFree(name);
11224: 		SKIP_BLANKS;
11225: 		if (CUR != '(') {
11226: 		    XP_ERROR(XPATH_EXPR_ERROR);
11227: 		}
11228: 		NEXT;
11229: 		SKIP_BLANKS;
11230: 
11231: 		xmlXPathCompileExpr(ctxt, 1);
11232: 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11233: 		CHECK_ERROR;
11234: 
11235: 		SKIP_BLANKS;
11236: 		if (CUR != ')') {
11237: 		    XP_ERROR(XPATH_EXPR_ERROR);
11238: 		}
11239: 		NEXT;
11240: 		rangeto = 1;
11241: 		goto eval_predicates;
11242: 	    }
11243: 	}
11244: #endif
11245: 	if (CUR == '*') {
11246: 	    axis = AXIS_CHILD;
11247: 	} else {
11248: 	    if (name == NULL)
11249: 		name = xmlXPathParseNCName(ctxt);
11250: 	    if (name != NULL) {
11251: 		axis = xmlXPathIsAxisName(name);
11252: 		if (axis != 0) {
11253: 		    SKIP_BLANKS;
11254: 		    if ((CUR == ':') && (NXT(1) == ':')) {
11255: 			SKIP(2);
11256: 			xmlFree(name);
11257: 			name = NULL;
11258: 		    } else {
11259: 			/* an element name can conflict with an axis one :-\ */
11260: 			axis = AXIS_CHILD;
11261: 		    }
11262: 		} else {
11263: 		    axis = AXIS_CHILD;
11264: 		}
11265: 	    } else if (CUR == '@') {
11266: 		NEXT;
11267: 		axis = AXIS_ATTRIBUTE;
11268: 	    } else {
11269: 		axis = AXIS_CHILD;
11270: 	    }
11271: 	}
11272: 
11273:         if (ctxt->error != XPATH_EXPRESSION_OK) {
11274:             xmlFree(name);
11275:             return;
11276:         }
11277: 
11278: 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11279: 	if (test == 0)
11280: 	    return;
11281: 
11282:         if ((prefix != NULL) && (ctxt->context != NULL) &&
11283: 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11284: 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11285: 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11286: 	    }
11287: 	}
11288: #ifdef DEBUG_STEP
11289: 	xmlGenericError(xmlGenericErrorContext,
11290: 		"Basis : computing new set\n");
11291: #endif
11292: 
11293: #ifdef DEBUG_STEP
11294: 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11295: 	if (ctxt->value == NULL)
11296: 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11297: 	else if (ctxt->value->nodesetval == NULL)
11298: 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11299: 	else
11300: 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11301: #endif
11302: 
11303: #ifdef LIBXML_XPTR_ENABLED
11304: eval_predicates:
11305: #endif
11306: 	op1 = ctxt->comp->last;
11307: 	ctxt->comp->last = -1;
11308: 
11309: 	SKIP_BLANKS;
11310: 	while (CUR == '[') {
11311: 	    xmlXPathCompPredicate(ctxt, 0);
11312: 	}
11313: 
11314: #ifdef LIBXML_XPTR_ENABLED
11315: 	if (rangeto) {
11316: 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11317: 	} else
11318: #endif
11319: 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11320: 			   test, type, (void *)prefix, (void *)name);
11321: 
11322:     }
11323: #ifdef DEBUG_STEP
11324:     xmlGenericError(xmlGenericErrorContext, "Step : ");
11325:     if (ctxt->value == NULL)
11326: 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11327:     else if (ctxt->value->nodesetval == NULL)
11328: 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11329:     else
11330: 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11331: 		ctxt->value->nodesetval);
11332: #endif
11333: }
11334: 
11335: /**
11336:  * xmlXPathCompRelativeLocationPath:
11337:  * @ctxt:  the XPath Parser context
11338:  *
11339:  *  [3]   RelativeLocationPath ::=   Step
11340:  *                     | RelativeLocationPath '/' Step
11341:  *                     | AbbreviatedRelativeLocationPath
11342:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11343:  *
11344:  * Compile a relative location path.
11345:  */
11346: static void
11347: xmlXPathCompRelativeLocationPath
11348: (xmlXPathParserContextPtr ctxt) {
11349:     SKIP_BLANKS;
11350:     if ((CUR == '/') && (NXT(1) == '/')) {
11351: 	SKIP(2);
11352: 	SKIP_BLANKS;
11353: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11354: 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11355:     } else if (CUR == '/') {
11356: 	    NEXT;
11357: 	SKIP_BLANKS;
11358:     }
11359:     xmlXPathCompStep(ctxt);
11360:     CHECK_ERROR;
11361:     SKIP_BLANKS;
11362:     while (CUR == '/') {
11363: 	if ((CUR == '/') && (NXT(1) == '/')) {
11364: 	    SKIP(2);
11365: 	    SKIP_BLANKS;
11366: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11367: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11368: 	    xmlXPathCompStep(ctxt);
11369: 	} else if (CUR == '/') {
11370: 	    NEXT;
11371: 	    SKIP_BLANKS;
11372: 	    xmlXPathCompStep(ctxt);
11373: 	}
11374: 	SKIP_BLANKS;
11375:     }
11376: }
11377: 
11378: /**
11379:  * xmlXPathCompLocationPath:
11380:  * @ctxt:  the XPath Parser context
11381:  *
11382:  *  [1]   LocationPath ::=   RelativeLocationPath
11383:  *                     | AbsoluteLocationPath
11384:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11385:  *                     | AbbreviatedAbsoluteLocationPath
11386:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11387:  *                           '//' RelativeLocationPath
11388:  *
11389:  * Compile a location path
11390:  *
11391:  * // is short for /descendant-or-self::node()/. For example,
11392:  * //para is short for /descendant-or-self::node()/child::para and
11393:  * so will select any para element in the document (even a para element
11394:  * that is a document element will be selected by //para since the
11395:  * document element node is a child of the root node); div//para is
11396:  * short for div/descendant-or-self::node()/child::para and so will
11397:  * select all para descendants of div children.
11398:  */
11399: static void
11400: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11401:     SKIP_BLANKS;
11402:     if (CUR != '/') {
11403:         xmlXPathCompRelativeLocationPath(ctxt);
11404:     } else {
11405: 	while (CUR == '/') {
11406: 	    if ((CUR == '/') && (NXT(1) == '/')) {
11407: 		SKIP(2);
11408: 		SKIP_BLANKS;
11409: 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11410: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11411: 		xmlXPathCompRelativeLocationPath(ctxt);
11412: 	    } else if (CUR == '/') {
11413: 		NEXT;
11414: 		SKIP_BLANKS;
11415: 		if ((CUR != 0 ) &&
11416: 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11417: 		     (CUR == '@') || (CUR == '*')))
11418: 		    xmlXPathCompRelativeLocationPath(ctxt);
11419: 	    }
11420: 	    CHECK_ERROR;
11421: 	}
11422:     }
11423: }
11424: 
11425: /************************************************************************
11426:  *									*
11427:  *		XPath precompiled expression evaluation			*
11428:  *									*
11429:  ************************************************************************/
11430: 
11431: static int
11432: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11433: 
11434: #ifdef DEBUG_STEP
11435: static void
11436: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11437: 			  int nbNodes)
11438: {
11439:     xmlGenericError(xmlGenericErrorContext, "new step : ");
11440:     switch (op->value) {
11441:         case AXIS_ANCESTOR:
11442:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11443:             break;
11444:         case AXIS_ANCESTOR_OR_SELF:
11445:             xmlGenericError(xmlGenericErrorContext,
11446:                             "axis 'ancestors-or-self' ");
11447:             break;
11448:         case AXIS_ATTRIBUTE:
11449:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11450:             break;
11451:         case AXIS_CHILD:
11452:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11453:             break;
11454:         case AXIS_DESCENDANT:
11455:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11456:             break;
11457:         case AXIS_DESCENDANT_OR_SELF:
11458:             xmlGenericError(xmlGenericErrorContext,
11459:                             "axis 'descendant-or-self' ");
11460:             break;
11461:         case AXIS_FOLLOWING:
11462:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11463:             break;
11464:         case AXIS_FOLLOWING_SIBLING:
11465:             xmlGenericError(xmlGenericErrorContext,
11466:                             "axis 'following-siblings' ");
11467:             break;
11468:         case AXIS_NAMESPACE:
11469:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11470:             break;
11471:         case AXIS_PARENT:
11472:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11473:             break;
11474:         case AXIS_PRECEDING:
11475:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11476:             break;
11477:         case AXIS_PRECEDING_SIBLING:
11478:             xmlGenericError(xmlGenericErrorContext,
11479:                             "axis 'preceding-sibling' ");
11480:             break;
11481:         case AXIS_SELF:
11482:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11483:             break;
11484:     }
11485:     xmlGenericError(xmlGenericErrorContext,
11486: 	" context contains %d nodes\n", nbNodes);
11487:     switch (op->value2) {
11488:         case NODE_TEST_NONE:
11489:             xmlGenericError(xmlGenericErrorContext,
11490:                             "           searching for none !!!\n");
11491:             break;
11492:         case NODE_TEST_TYPE:
11493:             xmlGenericError(xmlGenericErrorContext,
11494:                             "           searching for type %d\n", op->value3);
11495:             break;
11496:         case NODE_TEST_PI:
11497:             xmlGenericError(xmlGenericErrorContext,
11498:                             "           searching for PI !!!\n");
11499:             break;
11500:         case NODE_TEST_ALL:
11501:             xmlGenericError(xmlGenericErrorContext,
11502:                             "           searching for *\n");
11503:             break;
11504:         case NODE_TEST_NS:
11505:             xmlGenericError(xmlGenericErrorContext,
11506:                             "           searching for namespace %s\n",
11507:                             op->value5);
11508:             break;
11509:         case NODE_TEST_NAME:
11510:             xmlGenericError(xmlGenericErrorContext,
11511:                             "           searching for name %s\n", op->value5);
11512:             if (op->value4)
11513:                 xmlGenericError(xmlGenericErrorContext,
11514:                                 "           with namespace %s\n", op->value4);
11515:             break;
11516:     }
11517:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11518: }
11519: #endif /* DEBUG_STEP */
11520: 
11521: static int
11522: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11523: 			    xmlXPathStepOpPtr op,
11524: 			    xmlNodeSetPtr set,
11525: 			    int contextSize,
11526: 			    int hasNsNodes)
11527: {
11528:     if (op->ch1 != -1) {
11529: 	xmlXPathCompExprPtr comp = ctxt->comp;
11530: 	/*
11531: 	* Process inner predicates first.
11532: 	*/
11533: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11534: 	    /*
11535: 	    * TODO: raise an internal error.
11536: 	    */
11537: 	}
11538: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11539: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11540: 	CHECK_ERROR0;
11541: 	if (contextSize <= 0)
11542: 	    return(0);
11543:     }
11544:     if (op->ch2 != -1) {
11545: 	xmlXPathContextPtr xpctxt = ctxt->context;
11546: 	xmlNodePtr contextNode, oldContextNode;
11547: 	xmlDocPtr oldContextDoc;
11548: 	int i, res, contextPos = 0, newContextSize;
11549: 	xmlXPathStepOpPtr exprOp;
11550: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11551: 
11552: #ifdef LIBXML_XPTR_ENABLED
11553: 	/*
11554: 	* URGENT TODO: Check the following:
11555: 	*  We don't expect location sets if evaluating prediates, right?
11556: 	*  Only filters should expect location sets, right?
11557: 	*/
11558: #endif
11559: 	/*
11560: 	* SPEC XPath 1.0:
11561: 	*  "For each node in the node-set to be filtered, the
11562: 	*  PredicateExpr is evaluated with that node as the
11563: 	*  context node, with the number of nodes in the
11564: 	*  node-set as the context size, and with the proximity
11565: 	*  position of the node in the node-set with respect to
11566: 	*  the axis as the context position;"
11567: 	* @oldset is the node-set" to be filtered.
11568: 	*
11569: 	* SPEC XPath 1.0:
11570: 	*  "only predicates change the context position and
11571: 	*  context size (see [2.4 Predicates])."
11572: 	* Example:
11573: 	*   node-set  context pos
11574: 	*    nA         1
11575: 	*    nB         2
11576: 	*    nC         3
11577: 	*   After applying predicate [position() > 1] :
11578: 	*   node-set  context pos
11579: 	*    nB         1
11580: 	*    nC         2
11581: 	*/
11582: 	oldContextNode = xpctxt->node;
11583: 	oldContextDoc = xpctxt->doc;
11584: 	/*
11585: 	* Get the expression of this predicate.
11586: 	*/
11587: 	exprOp = &ctxt->comp->steps[op->ch2];
11588: 	newContextSize = 0;
11589: 	for (i = 0; i < set->nodeNr; i++) {
11590: 	    if (set->nodeTab[i] == NULL)
11591: 		continue;
11592: 
11593: 	    contextNode = set->nodeTab[i];
11594: 	    xpctxt->node = contextNode;
11595: 	    xpctxt->contextSize = contextSize;
11596: 	    xpctxt->proximityPosition = ++contextPos;
11597: 
11598: 	    /*
11599: 	    * Also set the xpath document in case things like
11600: 	    * key() are evaluated in the predicate.
11601: 	    */
11602: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11603: 		(contextNode->doc != NULL))
11604: 		xpctxt->doc = contextNode->doc;
11605: 	    /*
11606: 	    * Evaluate the predicate expression with 1 context node
11607: 	    * at a time; this node is packaged into a node set; this
11608: 	    * node set is handed over to the evaluation mechanism.
11609: 	    */
11610: 	    if (contextObj == NULL)
11611: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11612: 	    else
11613: 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11614: 		    contextNode);
11615: 
11616: 	    valuePush(ctxt, contextObj);
11617: 
11618: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11619: 
11620: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11621: 		xmlXPathNodeSetClear(set, hasNsNodes);
11622: 		newContextSize = 0;
11623: 		goto evaluation_exit;
11624: 	    }
11625: 
11626: 	    if (res != 0) {
11627: 		newContextSize++;
11628: 	    } else {
11629: 		/*
11630: 		* Remove the entry from the initial node set.
11631: 		*/
11632: 		set->nodeTab[i] = NULL;
11633: 		if (contextNode->type == XML_NAMESPACE_DECL)
11634: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11635: 	    }
11636: 	    if (ctxt->value == contextObj) {
11637: 		/*
11638: 		* Don't free the temporary XPath object holding the
11639: 		* context node, in order to avoid massive recreation
11640: 		* inside this loop.
11641: 		*/
11642: 		valuePop(ctxt);
11643: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11644: 	    } else {
11645: 		/*
11646: 		* TODO: The object was lost in the evaluation machinery.
11647: 		*  Can this happen? Maybe in internal-error cases.
11648: 		*/
11649: 		contextObj = NULL;
11650: 	    }
11651: 	}
11652: 
11653: 	if (contextObj != NULL) {
11654: 	    if (ctxt->value == contextObj)
11655: 		valuePop(ctxt);
11656: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11657: 	}
11658: evaluation_exit:
11659: 	if (exprRes != NULL)
11660: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11661: 	/*
11662: 	* Reset/invalidate the context.
11663: 	*/
11664: 	xpctxt->node = oldContextNode;
11665: 	xpctxt->doc = oldContextDoc;
11666: 	xpctxt->contextSize = -1;
11667: 	xpctxt->proximityPosition = -1;
11668: 	return(newContextSize);
11669:     }
11670:     return(contextSize);
11671: }
11672: 
11673: static int
11674: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11675: 				      xmlXPathStepOpPtr op,
11676: 				      xmlNodeSetPtr set,
11677: 				      int contextSize,
11678: 				      int minPos,
11679: 				      int maxPos,
11680: 				      int hasNsNodes)
11681: {
11682:     if (op->ch1 != -1) {
11683: 	xmlXPathCompExprPtr comp = ctxt->comp;
11684: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11685: 	    /*
11686: 	    * TODO: raise an internal error.
11687: 	    */
11688: 	}
11689: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11690: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11691: 	CHECK_ERROR0;
11692: 	if (contextSize <= 0)
11693: 	    return(0);
11694:     }
11695:     /*
11696:     * Check if the node set contains a sufficient number of nodes for
11697:     * the requested range.
11698:     */
11699:     if (contextSize < minPos) {
11700: 	xmlXPathNodeSetClear(set, hasNsNodes);
11701: 	return(0);
11702:     }
11703:     if (op->ch2 == -1) {
11704: 	/*
11705: 	* TODO: Can this ever happen?
11706: 	*/
11707: 	return (contextSize);
11708:     } else {
11709: 	xmlDocPtr oldContextDoc;
11710: 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11711: 	xmlXPathStepOpPtr exprOp;
11712: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11713: 	xmlNodePtr oldContextNode, contextNode = NULL;
11714: 	xmlXPathContextPtr xpctxt = ctxt->context;
11715: 
11716: #ifdef LIBXML_XPTR_ENABLED
11717: 	    /*
11718: 	    * URGENT TODO: Check the following:
11719: 	    *  We don't expect location sets if evaluating prediates, right?
11720: 	    *  Only filters should expect location sets, right?
11721: 	*/
11722: #endif /* LIBXML_XPTR_ENABLED */
11723: 
11724: 	/*
11725: 	* Save old context.
11726: 	*/
11727: 	oldContextNode = xpctxt->node;
11728: 	oldContextDoc = xpctxt->doc;
11729: 	/*
11730: 	* Get the expression of this predicate.
11731: 	*/
11732: 	exprOp = &ctxt->comp->steps[op->ch2];
11733: 	for (i = 0; i < set->nodeNr; i++) {
11734: 	    if (set->nodeTab[i] == NULL)
11735: 		continue;
11736: 
11737: 	    contextNode = set->nodeTab[i];
11738: 	    xpctxt->node = contextNode;
11739: 	    xpctxt->contextSize = contextSize;
11740: 	    xpctxt->proximityPosition = ++contextPos;
11741: 
11742: 	    /*
11743: 	    * Initialize the new set.
11744: 	    * Also set the xpath document in case things like
11745: 	    * key() evaluation are attempted on the predicate
11746: 	    */
11747: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11748: 		(contextNode->doc != NULL))
11749: 		xpctxt->doc = contextNode->doc;
11750: 	    /*
11751: 	    * Evaluate the predicate expression with 1 context node
11752: 	    * at a time; this node is packaged into a node set; this
11753: 	    * node set is handed over to the evaluation mechanism.
11754: 	    */
11755: 	    if (contextObj == NULL)
11756: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11757: 	    else
11758: 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11759: 		    contextNode);
11760: 
11761: 	    valuePush(ctxt, contextObj);
11762: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11763: 
11764: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11765: 	        xmlXPathObjectPtr tmp;
11766: 		/* pop the result */
11767: 		tmp = valuePop(ctxt);
11768: 		xmlXPathReleaseObject(xpctxt, tmp);
11769: 		/* then pop off contextObj, which will be freed later */
11770: 		valuePop(ctxt);
11771: 		goto evaluation_error;
11772: 	    }
11773: 
11774: 	    if (res)
11775: 		pos++;
11776: 
11777: 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11778: 		/*
11779: 		* Fits in the requested range.
11780: 		*/
11781: 		newContextSize++;
11782: 		if (minPos == maxPos) {
11783: 		    /*
11784: 		    * Only 1 node was requested.
11785: 		    */
11786: 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11787: 			/*
11788: 			* As always: take care of those nasty
11789: 			* namespace nodes.
11790: 			*/
11791: 			set->nodeTab[i] = NULL;
11792: 		    }
11793: 		    xmlXPathNodeSetClear(set, hasNsNodes);
11794: 		    set->nodeNr = 1;
11795: 		    set->nodeTab[0] = contextNode;
11796: 		    goto evaluation_exit;
11797: 		}
11798: 		if (pos == maxPos) {
11799: 		    /*
11800: 		    * We are done.
11801: 		    */
11802: 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11803: 		    goto evaluation_exit;
11804: 		}
11805: 	    } else {
11806: 		/*
11807: 		* Remove the entry from the initial node set.
11808: 		*/
11809: 		set->nodeTab[i] = NULL;
11810: 		if (contextNode->type == XML_NAMESPACE_DECL)
11811: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11812: 	    }
11813: 	    if (exprRes != NULL) {
11814: 		xmlXPathReleaseObject(ctxt->context, exprRes);
11815: 		exprRes = NULL;
11816: 	    }
11817: 	    if (ctxt->value == contextObj) {
11818: 		/*
11819: 		* Don't free the temporary XPath object holding the
11820: 		* context node, in order to avoid massive recreation
11821: 		* inside this loop.
11822: 		*/
11823: 		valuePop(ctxt);
11824: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11825: 	    } else {
11826: 		/*
11827: 		* The object was lost in the evaluation machinery.
11828: 		* Can this happen? Maybe in case of internal-errors.
11829: 		*/
11830: 		contextObj = NULL;
11831: 	    }
11832: 	}
11833: 	goto evaluation_exit;
11834: 
11835: evaluation_error:
11836: 	xmlXPathNodeSetClear(set, hasNsNodes);
11837: 	newContextSize = 0;
11838: 
11839: evaluation_exit:
11840: 	if (contextObj != NULL) {
11841: 	    if (ctxt->value == contextObj)
11842: 		valuePop(ctxt);
11843: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11844: 	}
11845: 	if (exprRes != NULL)
11846: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11847: 	/*
11848: 	* Reset/invalidate the context.
11849: 	*/
11850: 	xpctxt->node = oldContextNode;
11851: 	xpctxt->doc = oldContextDoc;
11852: 	xpctxt->contextSize = -1;
11853: 	xpctxt->proximityPosition = -1;
11854: 	return(newContextSize);
11855:     }
11856:     return(contextSize);
11857: }
11858: 
11859: static int
11860: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11861: 			    xmlXPathStepOpPtr op,
11862: 			    int *maxPos)
11863: {
11864: 
11865:     xmlXPathStepOpPtr exprOp;
11866: 
11867:     /*
11868:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11869:     */
11870: 
11871:     /*
11872:     * If not -1, then ch1 will point to:
11873:     * 1) For predicates (XPATH_OP_PREDICATE):
11874:     *    - an inner predicate operator
11875:     * 2) For filters (XPATH_OP_FILTER):
11876:     *    - an inner filter operater OR
11877:     *    - an expression selecting the node set.
11878:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11879:     */
11880:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11881: 	return(0);
11882: 
11883:     if (op->ch2 != -1) {
11884: 	exprOp = &ctxt->comp->steps[op->ch2];
11885:     } else
11886: 	return(0);
11887: 
11888:     if ((exprOp != NULL) &&
11889: 	(exprOp->op == XPATH_OP_VALUE) &&
11890: 	(exprOp->value4 != NULL) &&
11891: 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11892:     {
11893: 	/*
11894: 	* We have a "[n]" predicate here.
11895: 	* TODO: Unfortunately this simplistic test here is not
11896: 	* able to detect a position() predicate in compound
11897: 	* expressions like "[@attr = 'a" and position() = 1],
11898: 	* and even not the usage of position() in
11899: 	* "[position() = 1]"; thus - obviously - a position-range,
11900: 	* like it "[position() < 5]", is also not detected.
11901: 	* Maybe we could rewrite the AST to ease the optimization.
11902: 	*/
11903: 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11904: 
11905: 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11906: 	    (float) *maxPos)
11907: 	{
11908: 	    return(1);
11909: 	}
11910:     }
11911:     return(0);
11912: }
11913: 
11914: static int
11915: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11916:                            xmlXPathStepOpPtr op,
11917: 			   xmlNodePtr * first, xmlNodePtr * last,
11918: 			   int toBool)
11919: {
11920: 
11921: #define XP_TEST_HIT \
11922:     if (hasAxisRange != 0) { \
11923: 	if (++pos == maxPos) { \
11924: 	    addNode(seq, cur); \
11925: 	goto axis_range_end; } \
11926:     } else { \
11927: 	addNode(seq, cur); \
11928: 	if (breakOnFirstHit) goto first_hit; }
11929: 
11930: #define XP_TEST_HIT_NS \
11931:     if (hasAxisRange != 0) { \
11932: 	if (++pos == maxPos) { \
11933: 	    hasNsNodes = 1; \
11934: 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11935: 	goto axis_range_end; } \
11936:     } else { \
11937: 	hasNsNodes = 1; \
11938: 	xmlXPathNodeSetAddNs(seq, \
11939: 	xpctxt->node, (xmlNsPtr) cur); \
11940: 	if (breakOnFirstHit) goto first_hit; }
11941: 
11942:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11943:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11944:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11945:     const xmlChar *prefix = op->value4;
11946:     const xmlChar *name = op->value5;
11947:     const xmlChar *URI = NULL;
11948: 
11949: #ifdef DEBUG_STEP
11950:     int nbMatches = 0, prevMatches = 0;
11951: #endif
11952:     int total = 0, hasNsNodes = 0;
11953:     /* The popped object holding the context nodes */
11954:     xmlXPathObjectPtr obj;
11955:     /* The set of context nodes for the node tests */
11956:     xmlNodeSetPtr contextSeq;
11957:     int contextIdx;
11958:     xmlNodePtr contextNode;
11959:     /* The context node for a compound traversal */
11960:     xmlNodePtr outerContextNode;
11961:     /* The final resulting node set wrt to all context nodes */
11962:     xmlNodeSetPtr outSeq;
11963:     /*
11964:     * The temporary resulting node set wrt 1 context node.
11965:     * Used to feed predicate evaluation.
11966:     */
11967:     xmlNodeSetPtr seq;
11968:     xmlNodePtr cur;
11969:     /* First predicate operator */
11970:     xmlXPathStepOpPtr predOp;
11971:     int maxPos; /* The requested position() (when a "[n]" predicate) */
11972:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11973:     int breakOnFirstHit;
11974: 
11975:     xmlXPathTraversalFunction next = NULL;
11976:     /* compound axis traversal */
11977:     xmlXPathTraversalFunctionExt outerNext = NULL;
11978:     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11979:     xmlXPathNodeSetMergeFunction mergeAndClear;
11980:     xmlNodePtr oldContextNode;
11981:     xmlXPathContextPtr xpctxt = ctxt->context;
11982: 
11983: 
11984:     CHECK_TYPE0(XPATH_NODESET);
11985:     obj = valuePop(ctxt);
11986:     /*
11987:     * Setup namespaces.
11988:     */
11989:     if (prefix != NULL) {
11990:         URI = xmlXPathNsLookup(xpctxt, prefix);
11991:         if (URI == NULL) {
11992: 	    xmlXPathReleaseObject(xpctxt, obj);
11993:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11994: 	}
11995:     }
11996:     /*
11997:     * Setup axis.
11998:     *
11999:     * MAYBE FUTURE TODO: merging optimizations:
12000:     * - If the nodes to be traversed wrt to the initial nodes and
12001:     *   the current axis cannot overlap, then we could avoid searching
12002:     *   for duplicates during the merge.
12003:     *   But the question is how/when to evaluate if they cannot overlap.
12004:     *   Example: if we know that for two initial nodes, the one is
12005:     *   not in the ancestor-or-self axis of the other, then we could safely
12006:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12007:     *   the descendant-or-self axis.
12008:     */
12009:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12010:     switch (axis) {
12011:         case AXIS_ANCESTOR:
12012:             first = NULL;
12013:             next = xmlXPathNextAncestor;
12014:             break;
12015:         case AXIS_ANCESTOR_OR_SELF:
12016:             first = NULL;
12017:             next = xmlXPathNextAncestorOrSelf;
12018:             break;
12019:         case AXIS_ATTRIBUTE:
12020:             first = NULL;
12021: 	    last = NULL;
12022:             next = xmlXPathNextAttribute;
12023: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12024:             break;
12025:         case AXIS_CHILD:
12026: 	    last = NULL;
12027: 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12028: 		/*
12029: 		* This iterator will give us only nodes which can
12030: 		* hold element nodes.
12031: 		*/
12032: 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12033: 	    }
12034: 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12035: 		(type == NODE_TYPE_NODE))
12036: 	    {
12037: 		/*
12038: 		* Optimization if an element node type is 'element'.
12039: 		*/
12040: 		next = xmlXPathNextChildElement;
12041: 	    } else
12042: 		next = xmlXPathNextChild;
12043: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12044:             break;
12045:         case AXIS_DESCENDANT:
12046: 	    last = NULL;
12047:             next = xmlXPathNextDescendant;
12048:             break;
12049:         case AXIS_DESCENDANT_OR_SELF:
12050: 	    last = NULL;
12051:             next = xmlXPathNextDescendantOrSelf;
12052:             break;
12053:         case AXIS_FOLLOWING:
12054: 	    last = NULL;
12055:             next = xmlXPathNextFollowing;
12056:             break;
12057:         case AXIS_FOLLOWING_SIBLING:
12058: 	    last = NULL;
12059:             next = xmlXPathNextFollowingSibling;
12060:             break;
12061:         case AXIS_NAMESPACE:
12062:             first = NULL;
12063: 	    last = NULL;
12064:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12065: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12066:             break;
12067:         case AXIS_PARENT:
12068:             first = NULL;
12069:             next = xmlXPathNextParent;
12070:             break;
12071:         case AXIS_PRECEDING:
12072:             first = NULL;
12073:             next = xmlXPathNextPrecedingInternal;
12074:             break;
12075:         case AXIS_PRECEDING_SIBLING:
12076:             first = NULL;
12077:             next = xmlXPathNextPrecedingSibling;
12078:             break;
12079:         case AXIS_SELF:
12080:             first = NULL;
12081: 	    last = NULL;
12082:             next = xmlXPathNextSelf;
12083: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12084:             break;
12085:     }
12086: 
12087: #ifdef DEBUG_STEP
12088:     xmlXPathDebugDumpStepAxis(op,
12089: 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12090: #endif
12091: 
12092:     if (next == NULL) {
12093: 	xmlXPathReleaseObject(xpctxt, obj);
12094:         return(0);
12095:     }
12096:     contextSeq = obj->nodesetval;
12097:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12098: 	xmlXPathReleaseObject(xpctxt, obj);
12099:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12100:         return(0);
12101:     }
12102:     /*
12103:     * Predicate optimization ---------------------------------------------
12104:     * If this step has a last predicate, which contains a position(),
12105:     * then we'll optimize (although not exactly "position()", but only
12106:     * the  short-hand form, i.e., "[n]".
12107:     *
12108:     * Example - expression "/foo[parent::bar][1]":
12109:     *
12110:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12111:     *   ROOT                               -- op->ch1
12112:     *   PREDICATE                          -- op->ch2 (predOp)
12113:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12114:     *       SORT
12115:     *         COLLECT  'parent' 'name' 'node' bar
12116:     *           NODE
12117:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12118:     *
12119:     */
12120:     maxPos = 0;
12121:     predOp = NULL;
12122:     hasPredicateRange = 0;
12123:     hasAxisRange = 0;
12124:     if (op->ch2 != -1) {
12125: 	/*
12126: 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12127: 	*/
12128: 	predOp = &ctxt->comp->steps[op->ch2];
12129: 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12130: 	    if (predOp->ch1 != -1) {
12131: 		/*
12132: 		* Use the next inner predicate operator.
12133: 		*/
12134: 		predOp = &ctxt->comp->steps[predOp->ch1];
12135: 		hasPredicateRange = 1;
12136: 	    } else {
12137: 		/*
12138: 		* There's no other predicate than the [n] predicate.
12139: 		*/
12140: 		predOp = NULL;
12141: 		hasAxisRange = 1;
12142: 	    }
12143: 	}
12144:     }
12145:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12146:     /*
12147:     * Axis traversal -----------------------------------------------------
12148:     */
12149:     /*
12150:      * 2.3 Node Tests
12151:      *  - For the attribute axis, the principal node type is attribute.
12152:      *  - For the namespace axis, the principal node type is namespace.
12153:      *  - For other axes, the principal node type is element.
12154:      *
12155:      * A node test * is true for any node of the
12156:      * principal node type. For example, child::* will
12157:      * select all element children of the context node
12158:      */
12159:     oldContextNode = xpctxt->node;
12160:     addNode = xmlXPathNodeSetAddUnique;
12161:     outSeq = NULL;
12162:     seq = NULL;
12163:     outerContextNode = NULL;
12164:     contextNode = NULL;
12165:     contextIdx = 0;
12166: 
12167: 
12168:     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12169: 	if (outerNext != NULL) {
12170: 	    /*
12171: 	    * This is a compound traversal.
12172: 	    */
12173: 	    if (contextNode == NULL) {
12174: 		/*
12175: 		* Set the context for the outer traversal.
12176: 		*/
12177: 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12178: 		contextNode = outerNext(NULL, outerContextNode);
12179: 	    } else
12180: 		contextNode = outerNext(contextNode, outerContextNode);
12181: 	    if (contextNode == NULL)
12182: 		continue;
12183: 	    /*
12184: 	    * Set the context for the main traversal.
12185: 	    */
12186: 	    xpctxt->node = contextNode;
12187: 	} else
12188: 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12189: 
12190: 	if (seq == NULL) {
12191: 	    seq = xmlXPathNodeSetCreate(NULL);
12192: 	    if (seq == NULL) {
12193: 		total = 0;
12194: 		goto error;
12195: 	    }
12196: 	}
12197: 	/*
12198: 	* Traverse the axis and test the nodes.
12199: 	*/
12200: 	pos = 0;
12201: 	cur = NULL;
12202: 	hasNsNodes = 0;
12203:         do {
12204:             cur = next(ctxt, cur);
12205:             if (cur == NULL)
12206:                 break;
12207: 
12208: 	    /*
12209: 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12210: 	    */
12211:             if ((first != NULL) && (*first != NULL)) {
12212: 		if (*first == cur)
12213: 		    break;
12214: 		if (((total % 256) == 0) &&
12215: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216: 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217: #else
12218: 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12219: #endif
12220: 		{
12221: 		    break;
12222: 		}
12223: 	    }
12224: 	    if ((last != NULL) && (*last != NULL)) {
12225: 		if (*last == cur)
12226: 		    break;
12227: 		if (((total % 256) == 0) &&
12228: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229: 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230: #else
12231: 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12232: #endif
12233: 		{
12234: 		    break;
12235: 		}
12236: 	    }
12237: 
12238:             total++;
12239: 
12240: #ifdef DEBUG_STEP
12241:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242: #endif
12243: 
12244: 	    switch (test) {
12245:                 case NODE_TEST_NONE:
12246: 		    total = 0;
12247:                     STRANGE
12248: 		    goto error;
12249:                 case NODE_TEST_TYPE:
12250: 		    /*
12251: 		    * TODO: Don't we need to use
12252: 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12253: 		    *  Surprisingly, some c14n tests fail, if we do this.
12254: 		    */
12255: 		    if (type == NODE_TYPE_NODE) {
12256: 			switch (cur->type) {
12257: 			    case XML_DOCUMENT_NODE:
12258: 			    case XML_HTML_DOCUMENT_NODE:
12259: #ifdef LIBXML_DOCB_ENABLED
12260: 			    case XML_DOCB_DOCUMENT_NODE:
12261: #endif
12262: 			    case XML_ELEMENT_NODE:
12263: 			    case XML_ATTRIBUTE_NODE:
12264: 			    case XML_PI_NODE:
12265: 			    case XML_COMMENT_NODE:
12266: 			    case XML_CDATA_SECTION_NODE:
12267: 			    case XML_TEXT_NODE:
12268: 			    case XML_NAMESPACE_DECL:
12269: 				XP_TEST_HIT
12270: 				break;
12271: 			    default:
12272: 				break;
12273: 			}
12274: 		    } else if (cur->type == type) {
12275: 			if (type == XML_NAMESPACE_DECL)
12276: 			    XP_TEST_HIT_NS
12277: 			else
12278: 			    XP_TEST_HIT
12279: 		    } else if ((type == NODE_TYPE_TEXT) &&
12280: 			 (cur->type == XML_CDATA_SECTION_NODE))
12281: 		    {
12282: 			XP_TEST_HIT
12283: 		    }
12284: 		    break;
12285:                 case NODE_TEST_PI:
12286:                     if ((cur->type == XML_PI_NODE) &&
12287:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12288: 		    {
12289: 			XP_TEST_HIT
12290:                     }
12291:                     break;
12292:                 case NODE_TEST_ALL:
12293:                     if (axis == AXIS_ATTRIBUTE) {
12294:                         if (cur->type == XML_ATTRIBUTE_NODE)
12295: 			{
12296: 			    XP_TEST_HIT
12297:                         }
12298:                     } else if (axis == AXIS_NAMESPACE) {
12299:                         if (cur->type == XML_NAMESPACE_DECL)
12300: 			{
12301: 			    XP_TEST_HIT_NS
12302:                         }
12303:                     } else {
12304:                         if (cur->type == XML_ELEMENT_NODE) {
12305:                             if (prefix == NULL)
12306: 			    {
12307: 				XP_TEST_HIT
12308: 
12309:                             } else if ((cur->ns != NULL) &&
12310: 				(xmlStrEqual(URI, cur->ns->href)))
12311: 			    {
12312: 				XP_TEST_HIT
12313:                             }
12314:                         }
12315:                     }
12316:                     break;
12317:                 case NODE_TEST_NS:{
12318:                         TODO;
12319:                         break;
12320:                     }
12321:                 case NODE_TEST_NAME:
12322:                     if (axis == AXIS_ATTRIBUTE) {
12323:                         if (cur->type != XML_ATTRIBUTE_NODE)
12324: 			    break;
12325: 		    } else if (axis == AXIS_NAMESPACE) {
12326:                         if (cur->type != XML_NAMESPACE_DECL)
12327: 			    break;
12328: 		    } else {
12329: 		        if (cur->type != XML_ELEMENT_NODE)
12330: 			    break;
12331: 		    }
12332:                     switch (cur->type) {
12333:                         case XML_ELEMENT_NODE:
12334:                             if (xmlStrEqual(name, cur->name)) {
12335:                                 if (prefix == NULL) {
12336:                                     if (cur->ns == NULL)
12337: 				    {
12338: 					XP_TEST_HIT
12339:                                     }
12340:                                 } else {
12341:                                     if ((cur->ns != NULL) &&
12342:                                         (xmlStrEqual(URI, cur->ns->href)))
12343: 				    {
12344: 					XP_TEST_HIT
12345:                                     }
12346:                                 }
12347:                             }
12348:                             break;
12349:                         case XML_ATTRIBUTE_NODE:{
12350:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12351: 
12352:                                 if (xmlStrEqual(name, attr->name)) {
12353:                                     if (prefix == NULL) {
12354:                                         if ((attr->ns == NULL) ||
12355:                                             (attr->ns->prefix == NULL))
12356: 					{
12357: 					    XP_TEST_HIT
12358:                                         }
12359:                                     } else {
12360:                                         if ((attr->ns != NULL) &&
12361:                                             (xmlStrEqual(URI,
12362: 					      attr->ns->href)))
12363: 					{
12364: 					    XP_TEST_HIT
12365:                                         }
12366:                                     }
12367:                                 }
12368:                                 break;
12369:                             }
12370:                         case XML_NAMESPACE_DECL:
12371:                             if (cur->type == XML_NAMESPACE_DECL) {
12372:                                 xmlNsPtr ns = (xmlNsPtr) cur;
12373: 
12374:                                 if ((ns->prefix != NULL) && (name != NULL)
12375:                                     && (xmlStrEqual(ns->prefix, name)))
12376: 				{
12377: 				    XP_TEST_HIT_NS
12378:                                 }
12379:                             }
12380:                             break;
12381:                         default:
12382:                             break;
12383:                     }
12384:                     break;
12385: 	    } /* switch(test) */
12386:         } while (cur != NULL);
12387: 
12388: 	goto apply_predicates;
12389: 
12390: axis_range_end: /* ----------------------------------------------------- */
12391: 	/*
12392: 	* We have a "/foo[n]", and position() = n was reached.
12393: 	* Note that we can have as well "/foo/::parent::foo[1]", so
12394: 	* a duplicate-aware merge is still needed.
12395: 	* Merge with the result.
12396: 	*/
12397: 	if (outSeq == NULL) {
12398: 	    outSeq = seq;
12399: 	    seq = NULL;
12400: 	} else
12401: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12402: 	/*
12403: 	* Break if only a true/false result was requested.
12404: 	*/
12405: 	if (toBool)
12406: 	    break;
12407: 	continue;
12408: 
12409: first_hit: /* ---------------------------------------------------------- */
12410: 	/*
12411: 	* Break if only a true/false result was requested and
12412: 	* no predicates existed and a node test succeeded.
12413: 	*/
12414: 	if (outSeq == NULL) {
12415: 	    outSeq = seq;
12416: 	    seq = NULL;
12417: 	} else
12418: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12419: 	break;
12420: 
12421: #ifdef DEBUG_STEP
12422: 	if (seq != NULL)
12423: 	    nbMatches += seq->nodeNr;
12424: #endif
12425: 
12426: apply_predicates: /* --------------------------------------------------- */
12427:         /*
12428: 	* Apply predicates.
12429: 	*/
12430:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12431: 	    /*
12432: 	    * E.g. when we have a "/foo[some expression][n]".
12433: 	    */	    
12434: 	    /*
12435: 	    * QUESTION TODO: The old predicate evaluation took into
12436: 	    *  account location-sets.
12437: 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12438: 	    *  Do we expect such a set here?
12439: 	    *  All what I learned now from the evaluation semantics
12440: 	    *  does not indicate that a location-set will be processed
12441: 	    *  here, so this looks OK.
12442: 	    */	    
12443: 	    /*
12444: 	    * Iterate over all predicates, starting with the outermost
12445: 	    * predicate.
12446: 	    * TODO: Problem: we cannot execute the inner predicates first
12447: 	    *  since we cannot go back *up* the operator tree!
12448: 	    *  Options we have:
12449: 	    *  1) Use of recursive functions (like is it currently done
12450: 	    *     via xmlXPathCompOpEval())
12451: 	    *  2) Add a predicate evaluation information stack to the
12452: 	    *     context struct
12453: 	    *  3) Change the way the operators are linked; we need a
12454: 	    *     "parent" field on xmlXPathStepOp
12455: 	    *
12456: 	    * For the moment, I'll try to solve this with a recursive
12457: 	    * function: xmlXPathCompOpEvalPredicate().
12458: 	    */
12459: 	    size = seq->nodeNr;
12460: 	    if (hasPredicateRange != 0)
12461: 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12462: 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12463: 	    else
12464: 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12465: 		    predOp, seq, size, hasNsNodes);
12466: 
12467: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12468: 		total = 0;
12469: 		goto error;
12470: 	    }
12471: 	    /*
12472: 	    * Add the filtered set of nodes to the result node set.
12473: 	    */
12474: 	    if (newSize == 0) {
12475: 		/*
12476: 		* The predicates filtered all nodes out.
12477: 		*/
12478: 		xmlXPathNodeSetClear(seq, hasNsNodes);
12479: 	    } else if (seq->nodeNr > 0) {
12480: 		/*
12481: 		* Add to result set.
12482: 		*/
12483: 		if (outSeq == NULL) {
12484: 		    if (size != newSize) {
12485: 			/*
12486: 			* We need to merge and clear here, since
12487: 			* the sequence will contained NULLed entries.
12488: 			*/
12489: 			outSeq = mergeAndClear(NULL, seq, 1);
12490: 		    } else {
12491: 			outSeq = seq;
12492: 			seq = NULL;
12493: 		    }
12494: 		} else
12495: 		    outSeq = mergeAndClear(outSeq, seq,
12496: 			(size != newSize) ? 1: 0);
12497: 		/*
12498: 		* Break if only a true/false result was requested.
12499: 		*/
12500: 		if (toBool)
12501: 		    break;
12502: 	    }
12503:         } else if (seq->nodeNr > 0) {
12504: 	    /*
12505: 	    * Add to result set.
12506: 	    */
12507: 	    if (outSeq == NULL) {
12508: 		outSeq = seq;
12509: 		seq = NULL;
12510: 	    } else {
12511: 		outSeq = mergeAndClear(outSeq, seq, 0);
12512: 	    }
12513: 	}
12514:     }
12515: 
12516: error:
12517:     if ((obj->boolval) && (obj->user != NULL)) {
12518: 	/*
12519: 	* QUESTION TODO: What does this do and why?
12520: 	* TODO: Do we have to do this also for the "error"
12521: 	* cleanup further down?
12522: 	*/
12523: 	ctxt->value->boolval = 1;
12524: 	ctxt->value->user = obj->user;
12525: 	obj->user = NULL;
12526: 	obj->boolval = 0;
12527:     }
12528:     xmlXPathReleaseObject(xpctxt, obj);
12529: 
12530:     /*
12531:     * Ensure we return at least an emtpy set.
12532:     */
12533:     if (outSeq == NULL) {
12534: 	if ((seq != NULL) && (seq->nodeNr == 0))
12535: 	    outSeq = seq;
12536: 	else
12537: 	    outSeq = xmlXPathNodeSetCreate(NULL);
12538:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12539:     }
12540:     if ((seq != NULL) && (seq != outSeq)) {
12541: 	 xmlXPathFreeNodeSet(seq);
12542:     }
12543:     /*
12544:     * Hand over the result. Better to push the set also in
12545:     * case of errors.
12546:     */
12547:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12548:     /*
12549:     * Reset the context node.
12550:     */
12551:     xpctxt->node = oldContextNode;
12552: 
12553: #ifdef DEBUG_STEP
12554:     xmlGenericError(xmlGenericErrorContext,
12555: 	"\nExamined %d nodes, found %d nodes at that step\n",
12556: 	total, nbMatches);
12557: #endif
12558: 
12559:     return(total);
12560: }
12561: 
12562: static int
12563: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12564: 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12565: 
12566: /**
12567:  * xmlXPathCompOpEvalFirst:
12568:  * @ctxt:  the XPath parser context with the compiled expression
12569:  * @op:  an XPath compiled operation
12570:  * @first:  the first elem found so far
12571:  *
12572:  * Evaluate the Precompiled XPath operation searching only the first
12573:  * element in document order
12574:  *
12575:  * Returns the number of examined objects.
12576:  */
12577: static int
12578: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12579:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12580: {
12581:     int total = 0, cur;
12582:     xmlXPathCompExprPtr comp;
12583:     xmlXPathObjectPtr arg1, arg2;
12584: 
12585:     CHECK_ERROR0;
12586:     comp = ctxt->comp;
12587:     switch (op->op) {
12588:         case XPATH_OP_END:
12589:             return (0);
12590:         case XPATH_OP_UNION:
12591:             total =
12592:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12593:                                         first);
12594: 	    CHECK_ERROR0;
12595:             if ((ctxt->value != NULL)
12596:                 && (ctxt->value->type == XPATH_NODESET)
12597:                 && (ctxt->value->nodesetval != NULL)
12598:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12599:                 /*
12600:                  * limit tree traversing to first node in the result
12601:                  */
12602: 		/*
12603: 		* OPTIMIZE TODO: This implicitely sorts
12604: 		*  the result, even if not needed. E.g. if the argument
12605: 		*  of the count() function, no sorting is needed.
12606: 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12607: 		*  aready sorted?
12608: 		*/
12609: 		if (ctxt->value->nodesetval->nodeNr > 1)
12610: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611:                 *first = ctxt->value->nodesetval->nodeTab[0];
12612:             }
12613:             cur =
12614:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12615:                                         first);
12616: 	    CHECK_ERROR0;
12617:             CHECK_TYPE0(XPATH_NODESET);
12618:             arg2 = valuePop(ctxt);
12619: 
12620:             CHECK_TYPE0(XPATH_NODESET);
12621:             arg1 = valuePop(ctxt);
12622: 
12623:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12624:                                                     arg2->nodesetval);
12625:             valuePush(ctxt, arg1);
12626: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12627:             /* optimizer */
12628: 	    if (total > cur)
12629: 		xmlXPathCompSwap(op);
12630:             return (total + cur);
12631:         case XPATH_OP_ROOT:
12632:             xmlXPathRoot(ctxt);
12633:             return (0);
12634:         case XPATH_OP_NODE:
12635:             if (op->ch1 != -1)
12636:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12637: 	    CHECK_ERROR0;
12638:             if (op->ch2 != -1)
12639:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12640: 	    CHECK_ERROR0;
12641: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12642: 		ctxt->context->node));
12643:             return (total);
12644:         case XPATH_OP_RESET:
12645:             if (op->ch1 != -1)
12646:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12647: 	    CHECK_ERROR0;
12648:             if (op->ch2 != -1)
12649:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12650: 	    CHECK_ERROR0;
12651:             ctxt->context->node = NULL;
12652:             return (total);
12653:         case XPATH_OP_COLLECT:{
12654:                 if (op->ch1 == -1)
12655:                     return (total);
12656: 
12657:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12658: 		CHECK_ERROR0;
12659: 
12660:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12661:                 return (total);
12662:             }
12663:         case XPATH_OP_VALUE:
12664:             valuePush(ctxt,
12665:                       xmlXPathCacheObjectCopy(ctxt->context,
12666: 			(xmlXPathObjectPtr) op->value4));
12667:             return (0);
12668:         case XPATH_OP_SORT:
12669:             if (op->ch1 != -1)
12670:                 total +=
12671:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12672:                                             first);
12673: 	    CHECK_ERROR0;
12674:             if ((ctxt->value != NULL)
12675:                 && (ctxt->value->type == XPATH_NODESET)
12676:                 && (ctxt->value->nodesetval != NULL)
12677: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12678:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12679:             return (total);
12680: #ifdef XP_OPTIMIZED_FILTER_FIRST
12681: 	case XPATH_OP_FILTER:
12682:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12683:             return (total);
12684: #endif
12685:         default:
12686:             return (xmlXPathCompOpEval(ctxt, op));
12687:     }
12688: }
12689: 
12690: /**
12691:  * xmlXPathCompOpEvalLast:
12692:  * @ctxt:  the XPath parser context with the compiled expression
12693:  * @op:  an XPath compiled operation
12694:  * @last:  the last elem found so far
12695:  *
12696:  * Evaluate the Precompiled XPath operation searching only the last
12697:  * element in document order
12698:  *
12699:  * Returns the number of nodes traversed
12700:  */
12701: static int
12702: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12703:                        xmlNodePtr * last)
12704: {
12705:     int total = 0, cur;
12706:     xmlXPathCompExprPtr comp;
12707:     xmlXPathObjectPtr arg1, arg2;
12708:     xmlNodePtr bak;
12709:     xmlDocPtr bakd;
12710:     int pp;
12711:     int cs;
12712: 
12713:     CHECK_ERROR0;
12714:     comp = ctxt->comp;
12715:     switch (op->op) {
12716:         case XPATH_OP_END:
12717:             return (0);
12718:         case XPATH_OP_UNION:
12719: 	    bakd = ctxt->context->doc;
12720: 	    bak = ctxt->context->node;
12721: 	    pp = ctxt->context->proximityPosition;
12722: 	    cs = ctxt->context->contextSize;
12723:             total =
12724:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12725: 	    CHECK_ERROR0;
12726:             if ((ctxt->value != NULL)
12727:                 && (ctxt->value->type == XPATH_NODESET)
12728:                 && (ctxt->value->nodesetval != NULL)
12729:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12730:                 /*
12731:                  * limit tree traversing to first node in the result
12732:                  */
12733: 		if (ctxt->value->nodesetval->nodeNr > 1)
12734: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735:                 *last =
12736:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12737:                                                      nodesetval->nodeNr -
12738:                                                      1];
12739:             }
12740: 	    ctxt->context->doc = bakd;
12741: 	    ctxt->context->node = bak;
12742: 	    ctxt->context->proximityPosition = pp;
12743: 	    ctxt->context->contextSize = cs;
12744:             cur =
12745:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12746: 	    CHECK_ERROR0;
12747:             if ((ctxt->value != NULL)
12748:                 && (ctxt->value->type == XPATH_NODESET)
12749:                 && (ctxt->value->nodesetval != NULL)
12750:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12751:             }
12752:             CHECK_TYPE0(XPATH_NODESET);
12753:             arg2 = valuePop(ctxt);
12754: 
12755:             CHECK_TYPE0(XPATH_NODESET);
12756:             arg1 = valuePop(ctxt);
12757: 
12758:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12759:                                                     arg2->nodesetval);
12760:             valuePush(ctxt, arg1);
12761: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12762:             /* optimizer */
12763: 	    if (total > cur)
12764: 		xmlXPathCompSwap(op);
12765:             return (total + cur);
12766:         case XPATH_OP_ROOT:
12767:             xmlXPathRoot(ctxt);
12768:             return (0);
12769:         case XPATH_OP_NODE:
12770:             if (op->ch1 != -1)
12771:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12772: 	    CHECK_ERROR0;
12773:             if (op->ch2 != -1)
12774:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12775: 	    CHECK_ERROR0;
12776: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12777: 		ctxt->context->node));
12778:             return (total);
12779:         case XPATH_OP_RESET:
12780:             if (op->ch1 != -1)
12781:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12782: 	    CHECK_ERROR0;
12783:             if (op->ch2 != -1)
12784:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12785: 	    CHECK_ERROR0;
12786:             ctxt->context->node = NULL;
12787:             return (total);
12788:         case XPATH_OP_COLLECT:{
12789:                 if (op->ch1 == -1)
12790:                     return (0);
12791: 
12792:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793: 		CHECK_ERROR0;
12794: 
12795:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12796:                 return (total);
12797:             }
12798:         case XPATH_OP_VALUE:
12799:             valuePush(ctxt,
12800:                       xmlXPathCacheObjectCopy(ctxt->context,
12801: 			(xmlXPathObjectPtr) op->value4));
12802:             return (0);
12803:         case XPATH_OP_SORT:
12804:             if (op->ch1 != -1)
12805:                 total +=
12806:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12807:                                            last);
12808: 	    CHECK_ERROR0;
12809:             if ((ctxt->value != NULL)
12810:                 && (ctxt->value->type == XPATH_NODESET)
12811:                 && (ctxt->value->nodesetval != NULL)
12812: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12813:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12814:             return (total);
12815:         default:
12816:             return (xmlXPathCompOpEval(ctxt, op));
12817:     }
12818: }
12819: 
12820: #ifdef XP_OPTIMIZED_FILTER_FIRST
12821: static int
12822: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12823: 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12824: {
12825:     int total = 0;
12826:     xmlXPathCompExprPtr comp;
12827:     xmlXPathObjectPtr res;
12828:     xmlXPathObjectPtr obj;
12829:     xmlNodeSetPtr oldset;
12830:     xmlNodePtr oldnode;
12831:     xmlDocPtr oldDoc;
12832:     int i;
12833: 
12834:     CHECK_ERROR0;
12835:     comp = ctxt->comp;
12836:     /*
12837:     * Optimization for ()[last()] selection i.e. the last elem
12838:     */
12839:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12840: 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12841: 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12842: 	int f = comp->steps[op->ch2].ch1;
12843: 
12844: 	if ((f != -1) &&
12845: 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12846: 	    (comp->steps[f].value5 == NULL) &&
12847: 	    (comp->steps[f].value == 0) &&
12848: 	    (comp->steps[f].value4 != NULL) &&
12849: 	    (xmlStrEqual
12850: 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12851: 	    xmlNodePtr last = NULL;
12852: 
12853: 	    total +=
12854: 		xmlXPathCompOpEvalLast(ctxt,
12855: 		    &comp->steps[op->ch1],
12856: 		    &last);
12857: 	    CHECK_ERROR0;
12858: 	    /*
12859: 	    * The nodeset should be in document order,
12860: 	    * Keep only the last value
12861: 	    */
12862: 	    if ((ctxt->value != NULL) &&
12863: 		(ctxt->value->type == XPATH_NODESET) &&
12864: 		(ctxt->value->nodesetval != NULL) &&
12865: 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12866: 		(ctxt->value->nodesetval->nodeNr > 1)) {
12867: 		ctxt->value->nodesetval->nodeTab[0] =
12868: 		    ctxt->value->nodesetval->nodeTab[ctxt->
12869: 		    value->
12870: 		    nodesetval->
12871: 		    nodeNr -
12872: 		    1];
12873: 		ctxt->value->nodesetval->nodeNr = 1;
12874: 		*first = *(ctxt->value->nodesetval->nodeTab);
12875: 	    }
12876: 	    return (total);
12877: 	}
12878:     }
12879: 
12880:     if (op->ch1 != -1)
12881: 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12882:     CHECK_ERROR0;
12883:     if (op->ch2 == -1)
12884: 	return (total);
12885:     if (ctxt->value == NULL)
12886: 	return (total);
12887: 
12888: #ifdef LIBXML_XPTR_ENABLED
12889:     oldnode = ctxt->context->node;
12890:     /*
12891:     * Hum are we filtering the result of an XPointer expression
12892:     */
12893:     if (ctxt->value->type == XPATH_LOCATIONSET) {
12894: 	xmlXPathObjectPtr tmp = NULL;
12895: 	xmlLocationSetPtr newlocset = NULL;
12896: 	xmlLocationSetPtr oldlocset;
12897: 
12898: 	/*
12899: 	* Extract the old locset, and then evaluate the result of the
12900: 	* expression for all the element in the locset. use it to grow
12901: 	* up a new locset.
12902: 	*/
12903: 	CHECK_TYPE0(XPATH_LOCATIONSET);
12904: 	obj = valuePop(ctxt);
12905: 	oldlocset = obj->user;
12906: 	ctxt->context->node = NULL;
12907: 
12908: 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12909: 	    ctxt->context->contextSize = 0;
12910: 	    ctxt->context->proximityPosition = 0;
12911: 	    if (op->ch2 != -1)
12912: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12913: 	    res = valuePop(ctxt);
12914: 	    if (res != NULL) {
12915: 		xmlXPathReleaseObject(ctxt->context, res);
12916: 	    }
12917: 	    valuePush(ctxt, obj);
12918: 	    CHECK_ERROR0;
12919: 	    return (total);
12920: 	}
12921: 	newlocset = xmlXPtrLocationSetCreate(NULL);
12922: 
12923: 	for (i = 0; i < oldlocset->locNr; i++) {
12924: 	    /*
12925: 	    * Run the evaluation with a node list made of a
12926: 	    * single item in the nodelocset.
12927: 	    */
12928: 	    ctxt->context->node = oldlocset->locTab[i]->user;
12929: 	    ctxt->context->contextSize = oldlocset->locNr;
12930: 	    ctxt->context->proximityPosition = i + 1;
12931: 	    if (tmp == NULL) {
12932: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12933: 		    ctxt->context->node);
12934: 	    } else {
12935: 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12936: 		    ctxt->context->node);
12937: 	    }
12938: 	    valuePush(ctxt, tmp);
12939: 	    if (op->ch2 != -1)
12940: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12941: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12942: 		xmlXPathFreeObject(obj);
12943: 		return(0);
12944: 	    }
12945: 	    /*
12946: 	    * The result of the evaluation need to be tested to
12947: 	    * decided whether the filter succeeded or not
12948: 	    */
12949: 	    res = valuePop(ctxt);
12950: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12951: 		xmlXPtrLocationSetAdd(newlocset,
12952: 		    xmlXPathCacheObjectCopy(ctxt->context,
12953: 			oldlocset->locTab[i]));
12954: 	    }
12955: 	    /*
12956: 	    * Cleanup
12957: 	    */
12958: 	    if (res != NULL) {
12959: 		xmlXPathReleaseObject(ctxt->context, res);
12960: 	    }
12961: 	    if (ctxt->value == tmp) {
12962: 		valuePop(ctxt);
12963: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12964: 		/*
12965: 		* REVISIT TODO: Don't create a temporary nodeset
12966: 		* for everly iteration.
12967: 		*/
12968: 		/* OLD: xmlXPathFreeObject(res); */
12969: 	    } else
12970: 		tmp = NULL;
12971: 	    ctxt->context->node = NULL;
12972: 	    /*
12973: 	    * Only put the first node in the result, then leave.
12974: 	    */
12975: 	    if (newlocset->locNr > 0) {
12976: 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12977: 		break;
12978: 	    }
12979: 	}
12980: 	if (tmp != NULL) {
12981: 	    xmlXPathReleaseObject(ctxt->context, tmp);
12982: 	}
12983: 	/*
12984: 	* The result is used as the new evaluation locset.
12985: 	*/
12986: 	xmlXPathReleaseObject(ctxt->context, obj);
12987: 	ctxt->context->node = NULL;
12988: 	ctxt->context->contextSize = -1;
12989: 	ctxt->context->proximityPosition = -1;
12990: 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12991: 	ctxt->context->node = oldnode;
12992: 	return (total);
12993:     }
12994: #endif /* LIBXML_XPTR_ENABLED */
12995: 
12996:     /*
12997:     * Extract the old set, and then evaluate the result of the
12998:     * expression for all the element in the set. use it to grow
12999:     * up a new set.
13000:     */
13001:     CHECK_TYPE0(XPATH_NODESET);
13002:     obj = valuePop(ctxt);
13003:     oldset = obj->nodesetval;
13004: 
13005:     oldnode = ctxt->context->node;
13006:     oldDoc = ctxt->context->doc;
13007:     ctxt->context->node = NULL;
13008: 
13009:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13010: 	ctxt->context->contextSize = 0;
13011: 	ctxt->context->proximityPosition = 0;
13012: 	/* QUESTION TODO: Why was this code commented out?
13013: 	    if (op->ch2 != -1)
13014: 		total +=
13015: 		    xmlXPathCompOpEval(ctxt,
13016: 			&comp->steps[op->ch2]);
13017: 	    CHECK_ERROR0;
13018: 	    res = valuePop(ctxt);
13019: 	    if (res != NULL)
13020: 		xmlXPathFreeObject(res);
13021: 	*/
13022: 	valuePush(ctxt, obj);
13023: 	ctxt->context->node = oldnode;
13024: 	CHECK_ERROR0;
13025:     } else {
13026: 	xmlNodeSetPtr newset;
13027: 	xmlXPathObjectPtr tmp = NULL;
13028: 	/*
13029: 	* Initialize the new set.
13030: 	* Also set the xpath document in case things like
13031: 	* key() evaluation are attempted on the predicate
13032: 	*/
13033: 	newset = xmlXPathNodeSetCreate(NULL);
13034:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13035: 
13036: 	for (i = 0; i < oldset->nodeNr; i++) {
13037: 	    /*
13038: 	    * Run the evaluation with a node list made of
13039: 	    * a single item in the nodeset.
13040: 	    */
13041: 	    ctxt->context->node = oldset->nodeTab[i];
13042: 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13043: 		(oldset->nodeTab[i]->doc != NULL))
13044: 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13045: 	    if (tmp == NULL) {
13046: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13047: 		    ctxt->context->node);
13048: 	    } else {
13049: 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13050: 		    ctxt->context->node);
13051: 	    }
13052: 	    valuePush(ctxt, tmp);
13053: 	    ctxt->context->contextSize = oldset->nodeNr;
13054: 	    ctxt->context->proximityPosition = i + 1;
13055: 	    if (op->ch2 != -1)
13056: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13058: 		xmlXPathFreeNodeSet(newset);
13059: 		xmlXPathFreeObject(obj);
13060: 		return(0);
13061: 	    }
13062: 	    /*
13063: 	    * The result of the evaluation needs to be tested to
13064: 	    * decide whether the filter succeeded or not
13065: 	    */
13066: 	    res = valuePop(ctxt);
13067: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13068: 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13069: 	    }
13070: 	    /*
13071: 	    * Cleanup
13072: 	    */
13073: 	    if (res != NULL) {
13074: 		xmlXPathReleaseObject(ctxt->context, res);
13075: 	    }
13076: 	    if (ctxt->value == tmp) {
13077: 		valuePop(ctxt);
13078: 		/*
13079: 		* Don't free the temporary nodeset
13080: 		* in order to avoid massive recreation inside this
13081: 		* loop.
13082: 		*/
13083: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13084: 	    } else
13085: 		tmp = NULL;
13086: 	    ctxt->context->node = NULL;
13087: 	    /*
13088: 	    * Only put the first node in the result, then leave.
13089: 	    */
13090: 	    if (newset->nodeNr > 0) {
13091: 		*first = *(newset->nodeTab);
13092: 		break;
13093: 	    }
13094: 	}
13095: 	if (tmp != NULL) {
13096: 	    xmlXPathReleaseObject(ctxt->context, tmp);
13097: 	}
13098: 	/*
13099: 	* The result is used as the new evaluation set.
13100: 	*/
13101: 	xmlXPathReleaseObject(ctxt->context, obj);
13102: 	ctxt->context->node = NULL;
13103: 	ctxt->context->contextSize = -1;
13104: 	ctxt->context->proximityPosition = -1;
13105: 	/* may want to move this past the '}' later */
13106: 	ctxt->context->doc = oldDoc;
13107: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13108:     }
13109:     ctxt->context->node = oldnode;
13110:     return(total);
13111: }
13112: #endif /* XP_OPTIMIZED_FILTER_FIRST */
13113: 
13114: /**
13115:  * xmlXPathCompOpEval:
13116:  * @ctxt:  the XPath parser context with the compiled expression
13117:  * @op:  an XPath compiled operation
13118:  *
13119:  * Evaluate the Precompiled XPath operation
13120:  * Returns the number of nodes traversed
13121:  */
13122: static int
13123: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13124: {
13125:     int total = 0;
13126:     int equal, ret;
13127:     xmlXPathCompExprPtr comp;
13128:     xmlXPathObjectPtr arg1, arg2;
13129:     xmlNodePtr bak;
13130:     xmlDocPtr bakd;
13131:     int pp;
13132:     int cs;
13133: 
13134:     CHECK_ERROR0;
13135:     comp = ctxt->comp;
13136:     switch (op->op) {
13137:         case XPATH_OP_END:
13138:             return (0);
13139:         case XPATH_OP_AND:
13140: 	    bakd = ctxt->context->doc;
13141: 	    bak = ctxt->context->node;
13142: 	    pp = ctxt->context->proximityPosition;
13143: 	    cs = ctxt->context->contextSize;
13144:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145: 	    CHECK_ERROR0;
13146:             xmlXPathBooleanFunction(ctxt, 1);
13147:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13148:                 return (total);
13149:             arg2 = valuePop(ctxt);
13150: 	    ctxt->context->doc = bakd;
13151: 	    ctxt->context->node = bak;
13152: 	    ctxt->context->proximityPosition = pp;
13153: 	    ctxt->context->contextSize = cs;
13154:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155: 	    if (ctxt->error) {
13156: 		xmlXPathFreeObject(arg2);
13157: 		return(0);
13158: 	    }
13159:             xmlXPathBooleanFunction(ctxt, 1);
13160:             arg1 = valuePop(ctxt);
13161:             arg1->boolval &= arg2->boolval;
13162:             valuePush(ctxt, arg1);
13163: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13164:             return (total);
13165:         case XPATH_OP_OR:
13166: 	    bakd = ctxt->context->doc;
13167: 	    bak = ctxt->context->node;
13168: 	    pp = ctxt->context->proximityPosition;
13169: 	    cs = ctxt->context->contextSize;
13170:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171: 	    CHECK_ERROR0;
13172:             xmlXPathBooleanFunction(ctxt, 1);
13173:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13174:                 return (total);
13175:             arg2 = valuePop(ctxt);
13176: 	    ctxt->context->doc = bakd;
13177: 	    ctxt->context->node = bak;
13178: 	    ctxt->context->proximityPosition = pp;
13179: 	    ctxt->context->contextSize = cs;
13180:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13181: 	    if (ctxt->error) {
13182: 		xmlXPathFreeObject(arg2);
13183: 		return(0);
13184: 	    }
13185:             xmlXPathBooleanFunction(ctxt, 1);
13186:             arg1 = valuePop(ctxt);
13187:             arg1->boolval |= arg2->boolval;
13188:             valuePush(ctxt, arg1);
13189: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13190:             return (total);
13191:         case XPATH_OP_EQUAL:
13192: 	    bakd = ctxt->context->doc;
13193: 	    bak = ctxt->context->node;
13194: 	    pp = ctxt->context->proximityPosition;
13195: 	    cs = ctxt->context->contextSize;
13196:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13197: 	    CHECK_ERROR0;
13198: 	    ctxt->context->doc = bakd;
13199: 	    ctxt->context->node = bak;
13200: 	    ctxt->context->proximityPosition = pp;
13201: 	    ctxt->context->contextSize = cs;
13202:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13203: 	    CHECK_ERROR0;
13204: 	    if (op->value)
13205: 		equal = xmlXPathEqualValues(ctxt);
13206: 	    else
13207: 		equal = xmlXPathNotEqualValues(ctxt);
13208: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13209:             return (total);
13210:         case XPATH_OP_CMP:
13211: 	    bakd = ctxt->context->doc;
13212: 	    bak = ctxt->context->node;
13213: 	    pp = ctxt->context->proximityPosition;
13214: 	    cs = ctxt->context->contextSize;
13215:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13216: 	    CHECK_ERROR0;
13217: 	    ctxt->context->doc = bakd;
13218: 	    ctxt->context->node = bak;
13219: 	    ctxt->context->proximityPosition = pp;
13220: 	    ctxt->context->contextSize = cs;
13221:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13222: 	    CHECK_ERROR0;
13223:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13224: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13225:             return (total);
13226:         case XPATH_OP_PLUS:
13227: 	    bakd = ctxt->context->doc;
13228: 	    bak = ctxt->context->node;
13229: 	    pp = ctxt->context->proximityPosition;
13230: 	    cs = ctxt->context->contextSize;
13231:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232: 	    CHECK_ERROR0;
13233:             if (op->ch2 != -1) {
13234: 		ctxt->context->doc = bakd;
13235: 		ctxt->context->node = bak;
13236: 		ctxt->context->proximityPosition = pp;
13237: 		ctxt->context->contextSize = cs;
13238:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239: 	    }
13240: 	    CHECK_ERROR0;
13241:             if (op->value == 0)
13242:                 xmlXPathSubValues(ctxt);
13243:             else if (op->value == 1)
13244:                 xmlXPathAddValues(ctxt);
13245:             else if (op->value == 2)
13246:                 xmlXPathValueFlipSign(ctxt);
13247:             else if (op->value == 3) {
13248:                 CAST_TO_NUMBER;
13249:                 CHECK_TYPE0(XPATH_NUMBER);
13250:             }
13251:             return (total);
13252:         case XPATH_OP_MULT:
13253: 	    bakd = ctxt->context->doc;
13254: 	    bak = ctxt->context->node;
13255: 	    pp = ctxt->context->proximityPosition;
13256: 	    cs = ctxt->context->contextSize;
13257:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13258: 	    CHECK_ERROR0;
13259: 	    ctxt->context->doc = bakd;
13260: 	    ctxt->context->node = bak;
13261: 	    ctxt->context->proximityPosition = pp;
13262: 	    ctxt->context->contextSize = cs;
13263:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13264: 	    CHECK_ERROR0;
13265:             if (op->value == 0)
13266:                 xmlXPathMultValues(ctxt);
13267:             else if (op->value == 1)
13268:                 xmlXPathDivValues(ctxt);
13269:             else if (op->value == 2)
13270:                 xmlXPathModValues(ctxt);
13271:             return (total);
13272:         case XPATH_OP_UNION:
13273: 	    bakd = ctxt->context->doc;
13274: 	    bak = ctxt->context->node;
13275: 	    pp = ctxt->context->proximityPosition;
13276: 	    cs = ctxt->context->contextSize;
13277:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13278: 	    CHECK_ERROR0;
13279: 	    ctxt->context->doc = bakd;
13280: 	    ctxt->context->node = bak;
13281: 	    ctxt->context->proximityPosition = pp;
13282: 	    ctxt->context->contextSize = cs;
13283:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13284: 	    CHECK_ERROR0;
13285:             CHECK_TYPE0(XPATH_NODESET);
13286:             arg2 = valuePop(ctxt);
13287: 
13288:             CHECK_TYPE0(XPATH_NODESET);
13289:             arg1 = valuePop(ctxt);
13290: 
13291: 	    if ((arg1->nodesetval == NULL) ||
13292: 		((arg2->nodesetval != NULL) &&
13293: 		 (arg2->nodesetval->nodeNr != 0)))
13294: 	    {
13295: 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13296: 							arg2->nodesetval);
13297: 	    }
13298: 
13299:             valuePush(ctxt, arg1);
13300: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13301:             return (total);
13302:         case XPATH_OP_ROOT:
13303:             xmlXPathRoot(ctxt);
13304:             return (total);
13305:         case XPATH_OP_NODE:
13306:             if (op->ch1 != -1)
13307:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13308: 	    CHECK_ERROR0;
13309:             if (op->ch2 != -1)
13310:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13311: 	    CHECK_ERROR0;
13312: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13313: 		ctxt->context->node));
13314:             return (total);
13315:         case XPATH_OP_RESET:
13316:             if (op->ch1 != -1)
13317:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13318: 	    CHECK_ERROR0;
13319:             if (op->ch2 != -1)
13320:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321: 	    CHECK_ERROR0;
13322:             ctxt->context->node = NULL;
13323:             return (total);
13324:         case XPATH_OP_COLLECT:{
13325:                 if (op->ch1 == -1)
13326:                     return (total);
13327: 
13328:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329: 		CHECK_ERROR0;
13330: 
13331:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13332:                 return (total);
13333:             }
13334:         case XPATH_OP_VALUE:
13335:             valuePush(ctxt,
13336:                       xmlXPathCacheObjectCopy(ctxt->context,
13337: 			(xmlXPathObjectPtr) op->value4));
13338:             return (total);
13339:         case XPATH_OP_VARIABLE:{
13340: 		xmlXPathObjectPtr val;
13341: 
13342:                 if (op->ch1 != -1)
13343:                     total +=
13344:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13345:                 if (op->value5 == NULL) {
13346: 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13347: 		    if (val == NULL) {
13348: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13349: 			return(0);
13350: 		    }
13351:                     valuePush(ctxt, val);
13352: 		} else {
13353:                     const xmlChar *URI;
13354: 
13355:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13356:                     if (URI == NULL) {
13357:                         xmlGenericError(xmlGenericErrorContext,
13358:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13359:                                     (char *) op->value4, (char *)op->value5);
13360:                         return (total);
13361:                     }
13362: 		    val = xmlXPathVariableLookupNS(ctxt->context,
13363:                                                        op->value4, URI);
13364: 		    if (val == NULL) {
13365: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13366: 			return(0);
13367: 		    }
13368:                     valuePush(ctxt, val);
13369:                 }
13370:                 return (total);
13371:             }
13372:         case XPATH_OP_FUNCTION:{
13373:                 xmlXPathFunction func;
13374:                 const xmlChar *oldFunc, *oldFuncURI;
13375: 		int i;
13376: 
13377:                 if (op->ch1 != -1)
13378:                     total +=
13379:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380: 		if (ctxt->valueNr < op->value) {
13381: 		    xmlGenericError(xmlGenericErrorContext,
13382: 			    "xmlXPathCompOpEval: parameter error\n");
13383: 		    ctxt->error = XPATH_INVALID_OPERAND;
13384: 		    return (total);
13385: 		}
13386: 		for (i = 0; i < op->value; i++)
13387: 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13388: 			xmlGenericError(xmlGenericErrorContext,
13389: 				"xmlXPathCompOpEval: parameter error\n");
13390: 			ctxt->error = XPATH_INVALID_OPERAND;
13391: 			return (total);
13392: 		    }
13393:                 if (op->cache != NULL)
13394:                     XML_CAST_FPTR(func) = op->cache;
13395:                 else {
13396:                     const xmlChar *URI = NULL;
13397: 
13398:                     if (op->value5 == NULL)
13399:                         func =
13400:                             xmlXPathFunctionLookup(ctxt->context,
13401:                                                    op->value4);
13402:                     else {
13403:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13404:                         if (URI == NULL) {
13405:                             xmlGenericError(xmlGenericErrorContext,
13406:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13407:                                     (char *)op->value4, (char *)op->value5);
13408:                             return (total);
13409:                         }
13410:                         func = xmlXPathFunctionLookupNS(ctxt->context,
13411:                                                         op->value4, URI);
13412:                     }
13413:                     if (func == NULL) {
13414:                         xmlGenericError(xmlGenericErrorContext,
13415:                                 "xmlXPathCompOpEval: function %s not found\n",
13416:                                         (char *)op->value4);
13417:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13418:                     }
13419:                     op->cache = XML_CAST_FPTR(func);
13420:                     op->cacheURI = (void *) URI;
13421:                 }
13422:                 oldFunc = ctxt->context->function;
13423:                 oldFuncURI = ctxt->context->functionURI;
13424:                 ctxt->context->function = op->value4;
13425:                 ctxt->context->functionURI = op->cacheURI;
13426:                 func(ctxt, op->value);
13427:                 ctxt->context->function = oldFunc;
13428:                 ctxt->context->functionURI = oldFuncURI;
13429:                 return (total);
13430:             }
13431:         case XPATH_OP_ARG:
13432: 	    bakd = ctxt->context->doc;
13433: 	    bak = ctxt->context->node;
13434: 	    pp = ctxt->context->proximityPosition;
13435: 	    cs = ctxt->context->contextSize;
13436:             if (op->ch1 != -1)
13437:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438: 	    ctxt->context->contextSize = cs;
13439: 	    ctxt->context->proximityPosition = pp;
13440: 	    ctxt->context->node = bak;
13441: 	    ctxt->context->doc = bakd;
13442: 	    CHECK_ERROR0;
13443:             if (op->ch2 != -1) {
13444:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13445: 	        ctxt->context->doc = bakd;
13446: 	        ctxt->context->node = bak;
13447: 	        CHECK_ERROR0;
13448: 	    }
13449:             return (total);
13450:         case XPATH_OP_PREDICATE:
13451:         case XPATH_OP_FILTER:{
13452:                 xmlXPathObjectPtr res;
13453:                 xmlXPathObjectPtr obj, tmp;
13454:                 xmlNodeSetPtr newset = NULL;
13455:                 xmlNodeSetPtr oldset;
13456:                 xmlNodePtr oldnode;
13457: 		xmlDocPtr oldDoc;
13458:                 int i;
13459: 
13460:                 /*
13461:                  * Optimization for ()[1] selection i.e. the first elem
13462:                  */
13463:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13464: #ifdef XP_OPTIMIZED_FILTER_FIRST
13465: 		    /*
13466: 		    * FILTER TODO: Can we assume that the inner processing
13467: 		    *  will result in an ordered list if we have an
13468: 		    *  XPATH_OP_FILTER?
13469: 		    *  What about an additional field or flag on
13470: 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13471: 		    *  to assume anything, so it would be more robust and
13472: 		    *  easier to optimize.
13473: 		    */
13474:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13475: 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13476: #else
13477: 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13478: #endif
13479:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13480:                     xmlXPathObjectPtr val;
13481: 
13482:                     val = comp->steps[op->ch2].value4;
13483:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13484:                         (val->floatval == 1.0)) {
13485:                         xmlNodePtr first = NULL;
13486: 
13487:                         total +=
13488:                             xmlXPathCompOpEvalFirst(ctxt,
13489:                                                     &comp->steps[op->ch1],
13490:                                                     &first);
13491: 			CHECK_ERROR0;
13492:                         /*
13493:                          * The nodeset should be in document order,
13494:                          * Keep only the first value
13495:                          */
13496:                         if ((ctxt->value != NULL) &&
13497:                             (ctxt->value->type == XPATH_NODESET) &&
13498:                             (ctxt->value->nodesetval != NULL) &&
13499:                             (ctxt->value->nodesetval->nodeNr > 1))
13500:                             ctxt->value->nodesetval->nodeNr = 1;
13501:                         return (total);
13502:                     }
13503:                 }
13504:                 /*
13505:                  * Optimization for ()[last()] selection i.e. the last elem
13506:                  */
13507:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13508:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13509:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13510:                     int f = comp->steps[op->ch2].ch1;
13511: 
13512:                     if ((f != -1) &&
13513:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13514:                         (comp->steps[f].value5 == NULL) &&
13515:                         (comp->steps[f].value == 0) &&
13516:                         (comp->steps[f].value4 != NULL) &&
13517:                         (xmlStrEqual
13518:                          (comp->steps[f].value4, BAD_CAST "last"))) {
13519:                         xmlNodePtr last = NULL;
13520: 
13521:                         total +=
13522:                             xmlXPathCompOpEvalLast(ctxt,
13523:                                                    &comp->steps[op->ch1],
13524:                                                    &last);
13525: 			CHECK_ERROR0;
13526:                         /*
13527:                          * The nodeset should be in document order,
13528:                          * Keep only the last value
13529:                          */
13530:                         if ((ctxt->value != NULL) &&
13531:                             (ctxt->value->type == XPATH_NODESET) &&
13532:                             (ctxt->value->nodesetval != NULL) &&
13533:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13534:                             (ctxt->value->nodesetval->nodeNr > 1)) {
13535:                             ctxt->value->nodesetval->nodeTab[0] =
13536:                                 ctxt->value->nodesetval->nodeTab[ctxt->
13537:                                                                  value->
13538:                                                                  nodesetval->
13539:                                                                  nodeNr -
13540:                                                                  1];
13541:                             ctxt->value->nodesetval->nodeNr = 1;
13542:                         }
13543:                         return (total);
13544:                     }
13545:                 }
13546: 		/*
13547: 		* Process inner predicates first.
13548: 		* Example "index[parent::book][1]":
13549: 		* ...
13550: 		*   PREDICATE   <-- we are here "[1]"
13551: 		*     PREDICATE <-- process "[parent::book]" first
13552: 		*       SORT
13553: 		*         COLLECT  'parent' 'name' 'node' book
13554: 		*           NODE
13555: 		*     ELEM Object is a number : 1
13556: 		*/
13557:                 if (op->ch1 != -1)
13558:                     total +=
13559:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13560: 		CHECK_ERROR0;
13561:                 if (op->ch2 == -1)
13562:                     return (total);
13563:                 if (ctxt->value == NULL)
13564:                     return (total);
13565: 
13566:                 oldnode = ctxt->context->node;
13567: 
13568: #ifdef LIBXML_XPTR_ENABLED
13569:                 /*
13570:                  * Hum are we filtering the result of an XPointer expression
13571:                  */
13572:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13573:                     xmlLocationSetPtr newlocset = NULL;
13574:                     xmlLocationSetPtr oldlocset;
13575: 
13576:                     /*
13577:                      * Extract the old locset, and then evaluate the result of the
13578:                      * expression for all the element in the locset. use it to grow
13579:                      * up a new locset.
13580:                      */
13581:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13582:                     obj = valuePop(ctxt);
13583:                     oldlocset = obj->user;
13584:                     ctxt->context->node = NULL;
13585: 
13586:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13587:                         ctxt->context->contextSize = 0;
13588:                         ctxt->context->proximityPosition = 0;
13589:                         if (op->ch2 != -1)
13590:                             total +=
13591:                                 xmlXPathCompOpEval(ctxt,
13592:                                                    &comp->steps[op->ch2]);
13593:                         res = valuePop(ctxt);
13594:                         if (res != NULL) {
13595: 			    xmlXPathReleaseObject(ctxt->context, res);
13596: 			}
13597:                         valuePush(ctxt, obj);
13598:                         CHECK_ERROR0;
13599:                         return (total);
13600:                     }
13601:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13602: 
13603:                     for (i = 0; i < oldlocset->locNr; i++) {
13604:                         /*
13605:                          * Run the evaluation with a node list made of a
13606:                          * single item in the nodelocset.
13607:                          */
13608:                         ctxt->context->node = oldlocset->locTab[i]->user;
13609:                         ctxt->context->contextSize = oldlocset->locNr;
13610:                         ctxt->context->proximityPosition = i + 1;
13611: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13612: 			    ctxt->context->node);
13613:                         valuePush(ctxt, tmp);
13614: 
13615:                         if (op->ch2 != -1)
13616:                             total +=
13617:                                 xmlXPathCompOpEval(ctxt,
13618:                                                    &comp->steps[op->ch2]);
13619: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13620: 			    xmlXPathFreeObject(obj);
13621: 			    return(0);
13622: 			}
13623: 
13624:                         /*
13625:                          * The result of the evaluation need to be tested to
13626:                          * decided whether the filter succeeded or not
13627:                          */
13628:                         res = valuePop(ctxt);
13629:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13630:                             xmlXPtrLocationSetAdd(newlocset,
13631:                                                   xmlXPathObjectCopy
13632:                                                   (oldlocset->locTab[i]));
13633:                         }
13634: 
13635:                         /*
13636:                          * Cleanup
13637:                          */
13638:                         if (res != NULL) {
13639: 			    xmlXPathReleaseObject(ctxt->context, res);
13640: 			}
13641:                         if (ctxt->value == tmp) {
13642:                             res = valuePop(ctxt);
13643: 			    xmlXPathReleaseObject(ctxt->context, res);
13644:                         }
13645: 
13646:                         ctxt->context->node = NULL;
13647:                     }
13648: 
13649:                     /*
13650:                      * The result is used as the new evaluation locset.
13651:                      */
13652: 		    xmlXPathReleaseObject(ctxt->context, obj);
13653:                     ctxt->context->node = NULL;
13654:                     ctxt->context->contextSize = -1;
13655:                     ctxt->context->proximityPosition = -1;
13656:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13657:                     ctxt->context->node = oldnode;
13658:                     return (total);
13659:                 }
13660: #endif /* LIBXML_XPTR_ENABLED */
13661: 
13662:                 /*
13663:                  * Extract the old set, and then evaluate the result of the
13664:                  * expression for all the element in the set. use it to grow
13665:                  * up a new set.
13666:                  */
13667:                 CHECK_TYPE0(XPATH_NODESET);
13668:                 obj = valuePop(ctxt);
13669:                 oldset = obj->nodesetval;
13670: 
13671:                 oldnode = ctxt->context->node;
13672: 		oldDoc = ctxt->context->doc;
13673:                 ctxt->context->node = NULL;
13674: 
13675:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13676:                     ctxt->context->contextSize = 0;
13677:                     ctxt->context->proximityPosition = 0;
13678: /*
13679:                     if (op->ch2 != -1)
13680:                         total +=
13681:                             xmlXPathCompOpEval(ctxt,
13682:                                                &comp->steps[op->ch2]);
13683: 		    CHECK_ERROR0;
13684:                     res = valuePop(ctxt);
13685:                     if (res != NULL)
13686:                         xmlXPathFreeObject(res);
13687: */
13688:                     valuePush(ctxt, obj);
13689:                     ctxt->context->node = oldnode;
13690:                     CHECK_ERROR0;
13691:                 } else {
13692: 		    tmp = NULL;
13693:                     /*
13694:                      * Initialize the new set.
13695: 		     * Also set the xpath document in case things like
13696: 		     * key() evaluation are attempted on the predicate
13697:                      */
13698:                     newset = xmlXPathNodeSetCreate(NULL);
13699: 		    /*
13700: 		    * SPEC XPath 1.0:
13701: 		    *  "For each node in the node-set to be filtered, the
13702: 		    *  PredicateExpr is evaluated with that node as the
13703: 		    *  context node, with the number of nodes in the
13704: 		    *  node-set as the context size, and with the proximity
13705: 		    *  position of the node in the node-set with respect to
13706: 		    *  the axis as the context position;"
13707: 		    * @oldset is the node-set" to be filtered.
13708: 		    *
13709: 		    * SPEC XPath 1.0:
13710: 		    *  "only predicates change the context position and
13711: 		    *  context size (see [2.4 Predicates])."
13712: 		    * Example:
13713: 		    *   node-set  context pos
13714: 		    *    nA         1
13715: 		    *    nB         2
13716: 		    *    nC         3
13717: 		    *   After applying predicate [position() > 1] :
13718: 		    *   node-set  context pos
13719: 		    *    nB         1
13720: 		    *    nC         2
13721: 		    *
13722: 		    * removed the first node in the node-set, then
13723: 		    * the context position of the
13724: 		    */
13725:                     for (i = 0; i < oldset->nodeNr; i++) {
13726:                         /*
13727:                          * Run the evaluation with a node list made of
13728:                          * a single item in the nodeset.
13729:                          */
13730:                         ctxt->context->node = oldset->nodeTab[i];
13731: 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13732: 			    (oldset->nodeTab[i]->doc != NULL))
13733: 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13734: 			if (tmp == NULL) {
13735: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13736: 				ctxt->context->node);
13737: 			} else {
13738: 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13739: 				ctxt->context->node);
13740: 			}
13741:                         valuePush(ctxt, tmp);
13742:                         ctxt->context->contextSize = oldset->nodeNr;
13743:                         ctxt->context->proximityPosition = i + 1;
13744: 			/*
13745: 			* Evaluate the predicate against the context node.
13746: 			* Can/should we optimize position() predicates
13747: 			* here (e.g. "[1]")?
13748: 			*/
13749:                         if (op->ch2 != -1)
13750:                             total +=
13751:                                 xmlXPathCompOpEval(ctxt,
13752:                                                    &comp->steps[op->ch2]);
13753: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13754: 			    xmlXPathFreeNodeSet(newset);
13755: 			    xmlXPathFreeObject(obj);
13756: 			    return(0);
13757: 			}
13758: 
13759:                         /*
13760:                          * The result of the evaluation needs to be tested to
13761:                          * decide whether the filter succeeded or not
13762:                          */
13763: 			/*
13764: 			* OPTIMIZE TODO: Can we use
13765: 			* xmlXPathNodeSetAdd*Unique()* instead?
13766: 			*/
13767:                         res = valuePop(ctxt);
13768:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13769:                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13770:                         }
13771: 
13772:                         /*
13773:                          * Cleanup
13774:                          */
13775:                         if (res != NULL) {
13776: 			    xmlXPathReleaseObject(ctxt->context, res);
13777: 			}
13778:                         if (ctxt->value == tmp) {
13779:                             valuePop(ctxt);
13780: 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13781: 			    /*
13782: 			    * Don't free the temporary nodeset
13783: 			    * in order to avoid massive recreation inside this
13784: 			    * loop.
13785: 			    */
13786:                         } else
13787: 			    tmp = NULL;
13788:                         ctxt->context->node = NULL;
13789:                     }
13790: 		    if (tmp != NULL)
13791: 			xmlXPathReleaseObject(ctxt->context, tmp);
13792:                     /*
13793:                      * The result is used as the new evaluation set.
13794:                      */
13795: 		    xmlXPathReleaseObject(ctxt->context, obj);
13796:                     ctxt->context->node = NULL;
13797:                     ctxt->context->contextSize = -1;
13798:                     ctxt->context->proximityPosition = -1;
13799: 		    /* may want to move this past the '}' later */
13800: 		    ctxt->context->doc = oldDoc;
13801: 		    valuePush(ctxt,
13802: 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13803:                 }
13804:                 ctxt->context->node = oldnode;
13805:                 return (total);
13806:             }
13807:         case XPATH_OP_SORT:
13808:             if (op->ch1 != -1)
13809:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13810: 	    CHECK_ERROR0;
13811:             if ((ctxt->value != NULL) &&
13812:                 (ctxt->value->type == XPATH_NODESET) &&
13813:                 (ctxt->value->nodesetval != NULL) &&
13814: 		(ctxt->value->nodesetval->nodeNr > 1))
13815: 	    {
13816:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13817: 	    }
13818:             return (total);
13819: #ifdef LIBXML_XPTR_ENABLED
13820:         case XPATH_OP_RANGETO:{
13821:                 xmlXPathObjectPtr range;
13822:                 xmlXPathObjectPtr res, obj;
13823:                 xmlXPathObjectPtr tmp;
13824:                 xmlLocationSetPtr newlocset = NULL;
13825: 		    xmlLocationSetPtr oldlocset;
13826:                 xmlNodeSetPtr oldset;
13827:                 int i, j;
13828: 
13829:                 if (op->ch1 != -1)
13830:                     total +=
13831:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13832:                 if (op->ch2 == -1)
13833:                     return (total);
13834: 
13835:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836:                     /*
13837:                      * Extract the old locset, and then evaluate the result of the
13838:                      * expression for all the element in the locset. use it to grow
13839:                      * up a new locset.
13840:                      */
13841:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13842:                     obj = valuePop(ctxt);
13843:                     oldlocset = obj->user;
13844: 
13845:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13846: 		        ctxt->context->node = NULL;
13847:                         ctxt->context->contextSize = 0;
13848:                         ctxt->context->proximityPosition = 0;
13849:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13850:                         res = valuePop(ctxt);
13851:                         if (res != NULL) {
13852: 			    xmlXPathReleaseObject(ctxt->context, res);
13853: 			}
13854:                         valuePush(ctxt, obj);
13855:                         CHECK_ERROR0;
13856:                         return (total);
13857:                     }
13858:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13859: 
13860:                     for (i = 0; i < oldlocset->locNr; i++) {
13861:                         /*
13862:                          * Run the evaluation with a node list made of a
13863:                          * single item in the nodelocset.
13864:                          */
13865:                         ctxt->context->node = oldlocset->locTab[i]->user;
13866:                         ctxt->context->contextSize = oldlocset->locNr;
13867:                         ctxt->context->proximityPosition = i + 1;
13868: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13869: 			    ctxt->context->node);
13870:                         valuePush(ctxt, tmp);
13871: 
13872:                         if (op->ch2 != -1)
13873:                             total +=
13874:                                 xmlXPathCompOpEval(ctxt,
13875:                                                    &comp->steps[op->ch2]);
13876: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13877: 			    xmlXPathFreeObject(obj);
13878: 			    return(0);
13879: 			}
13880: 
13881:                         res = valuePop(ctxt);
13882: 			if (res->type == XPATH_LOCATIONSET) {
13883: 			    xmlLocationSetPtr rloc =
13884: 			        (xmlLocationSetPtr)res->user;
13885: 			    for (j=0; j<rloc->locNr; j++) {
13886: 			        range = xmlXPtrNewRange(
13887: 				  oldlocset->locTab[i]->user,
13888: 				  oldlocset->locTab[i]->index,
13889: 				  rloc->locTab[j]->user2,
13890: 				  rloc->locTab[j]->index2);
13891: 				if (range != NULL) {
13892: 				    xmlXPtrLocationSetAdd(newlocset, range);
13893: 				}
13894: 			    }
13895: 			} else {
13896: 			    range = xmlXPtrNewRangeNodeObject(
13897: 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13898:                             if (range != NULL) {
13899:                                 xmlXPtrLocationSetAdd(newlocset,range);
13900: 			    }
13901:                         }
13902: 
13903:                         /*
13904:                          * Cleanup
13905:                          */
13906:                         if (res != NULL) {
13907: 			    xmlXPathReleaseObject(ctxt->context, res);
13908: 			}
13909:                         if (ctxt->value == tmp) {
13910:                             res = valuePop(ctxt);
13911: 			    xmlXPathReleaseObject(ctxt->context, res);
13912:                         }
13913: 
13914:                         ctxt->context->node = NULL;
13915:                     }
13916: 		} else {	/* Not a location set */
13917:                     CHECK_TYPE0(XPATH_NODESET);
13918:                     obj = valuePop(ctxt);
13919:                     oldset = obj->nodesetval;
13920:                     ctxt->context->node = NULL;
13921: 
13922:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13923: 
13924:                     if (oldset != NULL) {
13925:                         for (i = 0; i < oldset->nodeNr; i++) {
13926:                             /*
13927:                              * Run the evaluation with a node list made of a single item
13928:                              * in the nodeset.
13929:                              */
13930:                             ctxt->context->node = oldset->nodeTab[i];
13931: 			    /*
13932: 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13933: 			    */
13934: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13935: 				ctxt->context->node);
13936:                             valuePush(ctxt, tmp);
13937: 
13938:                             if (op->ch2 != -1)
13939:                                 total +=
13940:                                     xmlXPathCompOpEval(ctxt,
13941:                                                    &comp->steps[op->ch2]);
13942: 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13943: 				xmlXPathFreeObject(obj);
13944: 				return(0);
13945: 			    }
13946: 
13947:                             res = valuePop(ctxt);
13948:                             range =
13949:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13950:                                                       res);
13951:                             if (range != NULL) {
13952:                                 xmlXPtrLocationSetAdd(newlocset, range);
13953:                             }
13954: 
13955:                             /*
13956:                              * Cleanup
13957:                              */
13958:                             if (res != NULL) {
13959: 				xmlXPathReleaseObject(ctxt->context, res);
13960: 			    }
13961:                             if (ctxt->value == tmp) {
13962:                                 res = valuePop(ctxt);
13963: 				xmlXPathReleaseObject(ctxt->context, res);
13964:                             }
13965: 
13966:                             ctxt->context->node = NULL;
13967:                         }
13968:                     }
13969:                 }
13970: 
13971:                 /*
13972:                  * The result is used as the new evaluation set.
13973:                  */
13974: 		xmlXPathReleaseObject(ctxt->context, obj);
13975:                 ctxt->context->node = NULL;
13976:                 ctxt->context->contextSize = -1;
13977:                 ctxt->context->proximityPosition = -1;
13978:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13979:                 return (total);
13980:             }
13981: #endif /* LIBXML_XPTR_ENABLED */
13982:     }
13983:     xmlGenericError(xmlGenericErrorContext,
13984:                     "XPath: unknown precompiled operation %d\n", op->op);
13985:     return (total);
13986: }
13987: 
13988: /**
13989:  * xmlXPathCompOpEvalToBoolean:
13990:  * @ctxt:  the XPath parser context
13991:  *
13992:  * Evaluates if the expression evaluates to true.
13993:  *
13994:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13995:  */
13996: static int
13997: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13998: 			    xmlXPathStepOpPtr op,
13999: 			    int isPredicate)
14000: {
14001:     xmlXPathObjectPtr resObj = NULL;
14002: 
14003: start:
14004:     /* comp = ctxt->comp; */
14005:     switch (op->op) {
14006:         case XPATH_OP_END:
14007:             return (0);
14008: 	case XPATH_OP_VALUE:
14009: 	    resObj = (xmlXPathObjectPtr) op->value4;
14010: 	    if (isPredicate)
14011: 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14012: 	    return(xmlXPathCastToBoolean(resObj));
14013: 	case XPATH_OP_SORT:
14014: 	    /*
14015: 	    * We don't need sorting for boolean results. Skip this one.
14016: 	    */
14017:             if (op->ch1 != -1) {
14018: 		op = &ctxt->comp->steps[op->ch1];
14019: 		goto start;
14020: 	    }
14021: 	    return(0);
14022: 	case XPATH_OP_COLLECT:
14023: 	    if (op->ch1 == -1)
14024: 		return(0);
14025: 
14026:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14027: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14028: 		return(-1);
14029: 
14030:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14031: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14032: 		return(-1);
14033: 
14034: 	    resObj = valuePop(ctxt);
14035: 	    if (resObj == NULL)
14036: 		return(-1);
14037: 	    break;
14038: 	default:
14039: 	    /*
14040: 	    * Fallback to call xmlXPathCompOpEval().
14041: 	    */
14042: 	    xmlXPathCompOpEval(ctxt, op);
14043: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14044: 		return(-1);
14045: 
14046: 	    resObj = valuePop(ctxt);
14047: 	    if (resObj == NULL)
14048: 		return(-1);
14049: 	    break;
14050:     }
14051: 
14052:     if (resObj) {
14053: 	int res;
14054: 
14055: 	if (resObj->type == XPATH_BOOLEAN) {
14056: 	    res = resObj->boolval;
14057: 	} else if (isPredicate) {
14058: 	    /*
14059: 	    * For predicates a result of type "number" is handled
14060: 	    * differently:
14061: 	    * SPEC XPath 1.0:
14062: 	    * "If the result is a number, the result will be converted
14063: 	    *  to true if the number is equal to the context position
14064: 	    *  and will be converted to false otherwise;"
14065: 	    */
14066: 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14067: 	} else {
14068: 	    res = xmlXPathCastToBoolean(resObj);
14069: 	}
14070: 	xmlXPathReleaseObject(ctxt->context, resObj);
14071: 	return(res);
14072:     }
14073: 
14074:     return(0);
14075: }
14076: 
14077: #ifdef XPATH_STREAMING
14078: /**
14079:  * xmlXPathRunStreamEval:
14080:  * @ctxt:  the XPath parser context with the compiled expression
14081:  *
14082:  * Evaluate the Precompiled Streamable XPath expression in the given context.
14083:  */
14084: static int
14085: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14086: 		      xmlXPathObjectPtr *resultSeq, int toBool)
14087: {
14088:     int max_depth, min_depth;
14089:     int from_root;
14090:     int ret, depth;
14091:     int eval_all_nodes;
14092:     xmlNodePtr cur = NULL, limit = NULL;
14093:     xmlStreamCtxtPtr patstream = NULL;
14094: 
14095:     int nb_nodes = 0;
14096: 
14097:     if ((ctxt == NULL) || (comp == NULL))
14098:         return(-1);
14099:     max_depth = xmlPatternMaxDepth(comp);
14100:     if (max_depth == -1)
14101:         return(-1);
14102:     if (max_depth == -2)
14103:         max_depth = 10000;
14104:     min_depth = xmlPatternMinDepth(comp);
14105:     if (min_depth == -1)
14106:         return(-1);
14107:     from_root = xmlPatternFromRoot(comp);
14108:     if (from_root < 0)
14109:         return(-1);
14110: #if 0
14111:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14112: #endif
14113: 
14114:     if (! toBool) {
14115: 	if (resultSeq == NULL)
14116: 	    return(-1);
14117: 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14118: 	if (*resultSeq == NULL)
14119: 	    return(-1);
14120:     }
14121: 
14122:     /*
14123:      * handle the special cases of "/" amd "." being matched
14124:      */
14125:     if (min_depth == 0) {
14126: 	if (from_root) {
14127: 	    /* Select "/" */
14128: 	    if (toBool)
14129: 		return(1);
14130: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14131: 		(xmlNodePtr) ctxt->doc);
14132: 	} else {
14133: 	    /* Select "self::node()" */
14134: 	    if (toBool)
14135: 		return(1);
14136: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14137: 	}
14138:     }
14139:     if (max_depth == 0) {
14140: 	return(0);
14141:     }
14142: 
14143:     if (from_root) {
14144:         cur = (xmlNodePtr)ctxt->doc;
14145:     } else if (ctxt->node != NULL) {
14146:         switch (ctxt->node->type) {
14147:             case XML_ELEMENT_NODE:
14148:             case XML_DOCUMENT_NODE:
14149:             case XML_DOCUMENT_FRAG_NODE:
14150:             case XML_HTML_DOCUMENT_NODE:
14151: #ifdef LIBXML_DOCB_ENABLED
14152:             case XML_DOCB_DOCUMENT_NODE:
14153: #endif
14154: 	        cur = ctxt->node;
14155: 		break;
14156:             case XML_ATTRIBUTE_NODE:
14157:             case XML_TEXT_NODE:
14158:             case XML_CDATA_SECTION_NODE:
14159:             case XML_ENTITY_REF_NODE:
14160:             case XML_ENTITY_NODE:
14161:             case XML_PI_NODE:
14162:             case XML_COMMENT_NODE:
14163:             case XML_NOTATION_NODE:
14164:             case XML_DTD_NODE:
14165:             case XML_DOCUMENT_TYPE_NODE:
14166:             case XML_ELEMENT_DECL:
14167:             case XML_ATTRIBUTE_DECL:
14168:             case XML_ENTITY_DECL:
14169:             case XML_NAMESPACE_DECL:
14170:             case XML_XINCLUDE_START:
14171:             case XML_XINCLUDE_END:
14172: 		break;
14173: 	}
14174: 	limit = cur;
14175:     }
14176:     if (cur == NULL) {
14177:         return(0);
14178:     }
14179: 
14180:     patstream = xmlPatternGetStreamCtxt(comp);
14181:     if (patstream == NULL) {
14182: 	/*
14183: 	* QUESTION TODO: Is this an error?
14184: 	*/
14185: 	return(0);
14186:     }
14187: 
14188:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14189: 
14190:     if (from_root) {
14191: 	ret = xmlStreamPush(patstream, NULL, NULL);
14192: 	if (ret < 0) {
14193: 	} else if (ret == 1) {
14194: 	    if (toBool)
14195: 		goto return_1;
14196: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14197: 	}
14198:     }
14199:     depth = 0;
14200:     goto scan_children;
14201: next_node:
14202:     do {
14203:         nb_nodes++;
14204: 
14205: 	switch (cur->type) {
14206: 	    case XML_ELEMENT_NODE:
14207: 	    case XML_TEXT_NODE:
14208: 	    case XML_CDATA_SECTION_NODE:
14209: 	    case XML_COMMENT_NODE:
14210: 	    case XML_PI_NODE:
14211: 		if (cur->type == XML_ELEMENT_NODE) {
14212: 		    ret = xmlStreamPush(patstream, cur->name,
14213: 				(cur->ns ? cur->ns->href : NULL));
14214: 		} else if (eval_all_nodes)
14215: 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14216: 		else
14217: 		    break;
14218: 
14219: 		if (ret < 0) {
14220: 		    /* NOP. */
14221: 		} else if (ret == 1) {
14222: 		    if (toBool)
14223: 			goto return_1;
14224: 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14225: 		}
14226: 		if ((cur->children == NULL) || (depth >= max_depth)) {
14227: 		    ret = xmlStreamPop(patstream);
14228: 		    while (cur->next != NULL) {
14229: 			cur = cur->next;
14230: 			if ((cur->type != XML_ENTITY_DECL) &&
14231: 			    (cur->type != XML_DTD_NODE))
14232: 			    goto next_node;
14233: 		    }
14234: 		}
14235: 	    default:
14236: 		break;
14237: 	}
14238: 
14239: scan_children:
14240: 	if ((cur->children != NULL) && (depth < max_depth)) {
14241: 	    /*
14242: 	     * Do not descend on entities declarations
14243: 	     */
14244: 	    if (cur->children->type != XML_ENTITY_DECL) {
14245: 		cur = cur->children;
14246: 		depth++;
14247: 		/*
14248: 		 * Skip DTDs
14249: 		 */
14250: 		if (cur->type != XML_DTD_NODE)
14251: 		    continue;
14252: 	    }
14253: 	}
14254: 
14255: 	if (cur == limit)
14256: 	    break;
14257: 
14258: 	while (cur->next != NULL) {
14259: 	    cur = cur->next;
14260: 	    if ((cur->type != XML_ENTITY_DECL) &&
14261: 		(cur->type != XML_DTD_NODE))
14262: 		goto next_node;
14263: 	}
14264: 
14265: 	do {
14266: 	    cur = cur->parent;
14267: 	    depth--;
14268: 	    if ((cur == NULL) || (cur == limit))
14269: 	        goto done;
14270: 	    if (cur->type == XML_ELEMENT_NODE) {
14271: 		ret = xmlStreamPop(patstream);
14272: 	    } else if ((eval_all_nodes) &&
14273: 		((cur->type == XML_TEXT_NODE) ||
14274: 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14275: 		 (cur->type == XML_COMMENT_NODE) ||
14276: 		 (cur->type == XML_PI_NODE)))
14277: 	    {
14278: 		ret = xmlStreamPop(patstream);
14279: 	    }
14280: 	    if (cur->next != NULL) {
14281: 		cur = cur->next;
14282: 		break;
14283: 	    }
14284: 	} while (cur != NULL);
14285: 
14286:     } while ((cur != NULL) && (depth >= 0));
14287: 
14288: done:
14289: 
14290: #if 0
14291:     printf("stream eval: checked %d nodes selected %d\n",
14292:            nb_nodes, retObj->nodesetval->nodeNr);
14293: #endif
14294: 
14295:     if (patstream)
14296: 	xmlFreeStreamCtxt(patstream);
14297:     return(0);
14298: 
14299: return_1:
14300:     if (patstream)
14301: 	xmlFreeStreamCtxt(patstream);
14302:     return(1);
14303: }
14304: #endif /* XPATH_STREAMING */
14305: 
14306: /**
14307:  * xmlXPathRunEval:
14308:  * @ctxt:  the XPath parser context with the compiled expression
14309:  * @toBool:  evaluate to a boolean result
14310:  *
14311:  * Evaluate the Precompiled XPath expression in the given context.
14312:  */
14313: static int
14314: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14315: {
14316:     xmlXPathCompExprPtr comp;
14317: 
14318:     if ((ctxt == NULL) || (ctxt->comp == NULL))
14319: 	return(-1);
14320: 
14321:     if (ctxt->valueTab == NULL) {
14322: 	/* Allocate the value stack */
14323: 	ctxt->valueTab = (xmlXPathObjectPtr *)
14324: 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14325: 	if (ctxt->valueTab == NULL) {
14326: 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14327: 	    xmlFree(ctxt);
14328: 	}
14329: 	ctxt->valueNr = 0;
14330: 	ctxt->valueMax = 10;
14331: 	ctxt->value = NULL;
14332:     }
14333: #ifdef XPATH_STREAMING
14334:     if (ctxt->comp->stream) {
14335: 	int res;
14336: 
14337: 	if (toBool) {
14338: 	    /*
14339: 	    * Evaluation to boolean result.
14340: 	    */
14341: 	    res = xmlXPathRunStreamEval(ctxt->context,
14342: 		ctxt->comp->stream, NULL, 1);
14343: 	    if (res != -1)
14344: 		return(res);
14345: 	} else {
14346: 	    xmlXPathObjectPtr resObj = NULL;
14347: 
14348: 	    /*
14349: 	    * Evaluation to a sequence.
14350: 	    */
14351: 	    res = xmlXPathRunStreamEval(ctxt->context,
14352: 		ctxt->comp->stream, &resObj, 0);
14353: 
14354: 	    if ((res != -1) && (resObj != NULL)) {
14355: 		valuePush(ctxt, resObj);
14356: 		return(0);
14357: 	    }
14358: 	    if (resObj != NULL)
14359: 		xmlXPathReleaseObject(ctxt->context, resObj);
14360: 	}
14361: 	/*
14362: 	* QUESTION TODO: This falls back to normal XPath evaluation
14363: 	* if res == -1. Is this intended?
14364: 	*/
14365:     }
14366: #endif
14367:     comp = ctxt->comp;
14368:     if (comp->last < 0) {
14369: 	xmlGenericError(xmlGenericErrorContext,
14370: 	    "xmlXPathRunEval: last is less than zero\n");
14371: 	return(-1);
14372:     }
14373:     if (toBool)
14374: 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14375: 	    &comp->steps[comp->last], 0));
14376:     else
14377: 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14378: 
14379:     return(0);
14380: }
14381: 
14382: /************************************************************************
14383:  *									*
14384:  *			Public interfaces				*
14385:  *									*
14386:  ************************************************************************/
14387: 
14388: /**
14389:  * xmlXPathEvalPredicate:
14390:  * @ctxt:  the XPath context
14391:  * @res:  the Predicate Expression evaluation result
14392:  *
14393:  * Evaluate a predicate result for the current node.
14394:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14395:  * the result to a boolean. If the result is a number, the result will
14396:  * be converted to true if the number is equal to the position of the
14397:  * context node in the context node list (as returned by the position
14398:  * function) and will be converted to false otherwise; if the result
14399:  * is not a number, then the result will be converted as if by a call
14400:  * to the boolean function.
14401:  *
14402:  * Returns 1 if predicate is true, 0 otherwise
14403:  */
14404: int
14405: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14406:     if ((ctxt == NULL) || (res == NULL)) return(0);
14407:     switch (res->type) {
14408:         case XPATH_BOOLEAN:
14409: 	    return(res->boolval);
14410:         case XPATH_NUMBER:
14411: 	    return(res->floatval == ctxt->proximityPosition);
14412:         case XPATH_NODESET:
14413:         case XPATH_XSLT_TREE:
14414: 	    if (res->nodesetval == NULL)
14415: 		return(0);
14416: 	    return(res->nodesetval->nodeNr != 0);
14417:         case XPATH_STRING:
14418: 	    return((res->stringval != NULL) &&
14419: 	           (xmlStrlen(res->stringval) != 0));
14420:         default:
14421: 	    STRANGE
14422:     }
14423:     return(0);
14424: }
14425: 
14426: /**
14427:  * xmlXPathEvaluatePredicateResult:
14428:  * @ctxt:  the XPath Parser context
14429:  * @res:  the Predicate Expression evaluation result
14430:  *
14431:  * Evaluate a predicate result for the current node.
14432:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14433:  * the result to a boolean. If the result is a number, the result will
14434:  * be converted to true if the number is equal to the position of the
14435:  * context node in the context node list (as returned by the position
14436:  * function) and will be converted to false otherwise; if the result
14437:  * is not a number, then the result will be converted as if by a call
14438:  * to the boolean function.
14439:  *
14440:  * Returns 1 if predicate is true, 0 otherwise
14441:  */
14442: int
14443: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14444:                                 xmlXPathObjectPtr res) {
14445:     if ((ctxt == NULL) || (res == NULL)) return(0);
14446:     switch (res->type) {
14447:         case XPATH_BOOLEAN:
14448: 	    return(res->boolval);
14449:         case XPATH_NUMBER:
14450: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14451: 	    return((res->floatval == ctxt->context->proximityPosition) &&
14452: 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14453: #else
14454: 	    return(res->floatval == ctxt->context->proximityPosition);
14455: #endif
14456:         case XPATH_NODESET:
14457:         case XPATH_XSLT_TREE:
14458: 	    if (res->nodesetval == NULL)
14459: 		return(0);
14460: 	    return(res->nodesetval->nodeNr != 0);
14461:         case XPATH_STRING:
14462: 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14463: #ifdef LIBXML_XPTR_ENABLED
14464: 	case XPATH_LOCATIONSET:{
14465: 	    xmlLocationSetPtr ptr = res->user;
14466: 	    if (ptr == NULL)
14467: 	        return(0);
14468: 	    return (ptr->locNr != 0);
14469: 	    }
14470: #endif
14471:         default:
14472: 	    STRANGE
14473:     }
14474:     return(0);
14475: }
14476: 
14477: #ifdef XPATH_STREAMING
14478: /**
14479:  * xmlXPathTryStreamCompile:
14480:  * @ctxt: an XPath context
14481:  * @str:  the XPath expression
14482:  *
14483:  * Try to compile the XPath expression as a streamable subset.
14484:  *
14485:  * Returns the compiled expression or NULL if failed to compile.
14486:  */
14487: static xmlXPathCompExprPtr
14488: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14489:     /*
14490:      * Optimization: use streaming patterns when the XPath expression can
14491:      * be compiled to a stream lookup
14492:      */
14493:     xmlPatternPtr stream;
14494:     xmlXPathCompExprPtr comp;
14495:     xmlDictPtr dict = NULL;
14496:     const xmlChar **namespaces = NULL;
14497:     xmlNsPtr ns;
14498:     int i, j;
14499: 
14500:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14501:         (!xmlStrchr(str, '@'))) {
14502: 	const xmlChar *tmp;
14503: 
14504: 	/*
14505: 	 * We don't try to handle expressions using the verbose axis
14506: 	 * specifiers ("::"), just the simplied form at this point.
14507: 	 * Additionally, if there is no list of namespaces available and
14508: 	 *  there's a ":" in the expression, indicating a prefixed QName,
14509: 	 *  then we won't try to compile either. xmlPatterncompile() needs
14510: 	 *  to have a list of namespaces at compilation time in order to
14511: 	 *  compile prefixed name tests.
14512: 	 */
14513: 	tmp = xmlStrchr(str, ':');
14514: 	if ((tmp != NULL) &&
14515: 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14516: 	    return(NULL);
14517: 
14518: 	if (ctxt != NULL) {
14519: 	    dict = ctxt->dict;
14520: 	    if (ctxt->nsNr > 0) {
14521: 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14522: 		if (namespaces == NULL) {
14523: 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14524: 		    return(NULL);
14525: 		}
14526: 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14527: 		    ns = ctxt->namespaces[j];
14528: 		    namespaces[i++] = ns->href;
14529: 		    namespaces[i++] = ns->prefix;
14530: 		}
14531: 		namespaces[i++] = NULL;
14532: 		namespaces[i] = NULL;
14533: 	    }
14534: 	}
14535: 
14536: 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14537: 			&namespaces[0]);
14538: 	if (namespaces != NULL) {
14539: 	    xmlFree((xmlChar **)namespaces);
14540: 	}
14541: 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14542: 	    comp = xmlXPathNewCompExpr();
14543: 	    if (comp == NULL) {
14544: 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14545: 		return(NULL);
14546: 	    }
14547: 	    comp->stream = stream;
14548: 	    comp->dict = dict;
14549: 	    if (comp->dict)
14550: 		xmlDictReference(comp->dict);
14551: 	    return(comp);
14552: 	}
14553: 	xmlFreePattern(stream);
14554:     }
14555:     return(NULL);
14556: }
14557: #endif /* XPATH_STREAMING */
14558: 
14559: static int
14560: xmlXPathCanRewriteDosExpression(xmlChar *expr)
14561: {
14562:     if (expr == NULL)
14563: 	return(0);
14564:     do {
14565:         if ((*expr == '/') && (*(++expr) == '/'))
14566: 	    return(1);
14567:     } while (*expr++);
14568:     return(0);
14569: }
14570: static void
14571: xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14572: {
14573:     /*
14574:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14575:     * internal representation.
14576:     */
14577:     if (op->ch1 != -1) {
14578: 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14579: 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14580: 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14581: 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14582: 	{
14583: 	    /*
14584: 	    * This is a "child::foo"
14585: 	    */
14586: 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14587: 
14588: 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14589: 		(prevop->ch1 != -1) &&
14590: 		((xmlXPathAxisVal) prevop->value ==
14591: 		    AXIS_DESCENDANT_OR_SELF) &&
14592: 		(prevop->ch2 == -1) &&
14593: 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14594: 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14595: 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14596: 	    {
14597: 		/*
14598: 		* This is a "/descendant-or-self::node()" without predicates.
14599: 		* Eliminate it.
14600: 		*/
14601: 		op->ch1 = prevop->ch1;
14602: 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14603: 	    }
14604: 	}
14605: 	if (op->ch1 != -1)
14606: 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14607:     }
14608:     if (op->ch2 != -1)
14609: 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14610: }
14611: 
14612: /**
14613:  * xmlXPathCtxtCompile:
14614:  * @ctxt: an XPath context
14615:  * @str:  the XPath expression
14616:  *
14617:  * Compile an XPath expression
14618:  *
14619:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14620:  *         the caller has to free the object.
14621:  */
14622: xmlXPathCompExprPtr
14623: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14624:     xmlXPathParserContextPtr pctxt;
14625:     xmlXPathCompExprPtr comp;
14626: 
14627: #ifdef XPATH_STREAMING
14628:     comp = xmlXPathTryStreamCompile(ctxt, str);
14629:     if (comp != NULL)
14630:         return(comp);
14631: #endif
14632: 
14633:     xmlXPathInit();
14634: 
14635:     pctxt = xmlXPathNewParserContext(str, ctxt);
14636:     if (pctxt == NULL)
14637:         return NULL;
14638:     xmlXPathCompileExpr(pctxt, 1);
14639: 
14640:     if( pctxt->error != XPATH_EXPRESSION_OK )
14641:     {
14642:         xmlXPathFreeParserContext(pctxt);
14643:         return(NULL);
14644:     }
14645: 
14646:     if (*pctxt->cur != 0) {
14647: 	/*
14648: 	 * aleksey: in some cases this line prints *second* error message
14649: 	 * (see bug #78858) and probably this should be fixed.
14650: 	 * However, we are not sure that all error messages are printed
14651: 	 * out in other places. It's not critical so we leave it as-is for now
14652: 	 */
14653: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14654: 	comp = NULL;
14655:     } else {
14656: 	comp = pctxt->comp;
14657: 	pctxt->comp = NULL;
14658:     }
14659:     xmlXPathFreeParserContext(pctxt);
14660: 
14661:     if (comp != NULL) {
14662: 	comp->expr = xmlStrdup(str);
14663: #ifdef DEBUG_EVAL_COUNTS
14664: 	comp->string = xmlStrdup(str);
14665: 	comp->nb = 0;
14666: #endif
14667: 	if ((comp->expr != NULL) &&
14668: 	    (comp->nbStep > 2) &&
14669: 	    (comp->last >= 0) &&
14670: 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14671: 	{
14672: 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14673: 	}
14674:     }
14675:     return(comp);
14676: }
14677: 
14678: /**
14679:  * xmlXPathCompile:
14680:  * @str:  the XPath expression
14681:  *
14682:  * Compile an XPath expression
14683:  *
14684:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14685:  *         the caller has to free the object.
14686:  */
14687: xmlXPathCompExprPtr
14688: xmlXPathCompile(const xmlChar *str) {
14689:     return(xmlXPathCtxtCompile(NULL, str));
14690: }
14691: 
14692: /**
14693:  * xmlXPathCompiledEvalInternal:
14694:  * @comp:  the compiled XPath expression
14695:  * @ctxt:  the XPath context
14696:  * @resObj: the resulting XPath object or NULL
14697:  * @toBool: 1 if only a boolean result is requested
14698:  *
14699:  * Evaluate the Precompiled XPath expression in the given context.
14700:  * The caller has to free @resObj.
14701:  *
14702:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14703:  *         the caller has to free the object.
14704:  */
14705: static int
14706: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14707: 			     xmlXPathContextPtr ctxt,
14708: 			     xmlXPathObjectPtr *resObj,
14709: 			     int toBool)
14710: {
14711:     xmlXPathParserContextPtr pctxt;
14712: #ifndef LIBXML_THREAD_ENABLED
14713:     static int reentance = 0;
14714: #endif
14715:     int res;
14716: 
14717:     CHECK_CTXT_NEG(ctxt)
14718: 
14719:     if (comp == NULL)
14720: 	return(-1);
14721:     xmlXPathInit();
14722: 
14723: #ifndef LIBXML_THREAD_ENABLED
14724:     reentance++;
14725:     if (reentance > 1)
14726: 	xmlXPathDisableOptimizer = 1;
14727: #endif
14728: 
14729: #ifdef DEBUG_EVAL_COUNTS
14730:     comp->nb++;
14731:     if ((comp->string != NULL) && (comp->nb > 100)) {
14732: 	fprintf(stderr, "100 x %s\n", comp->string);
14733: 	comp->nb = 0;
14734:     }
14735: #endif
14736:     pctxt = xmlXPathCompParserContext(comp, ctxt);
14737:     res = xmlXPathRunEval(pctxt, toBool);
14738: 
14739:     if (resObj) {
14740: 	if (pctxt->value == NULL) {
14741: 	    xmlGenericError(xmlGenericErrorContext,
14742: 		"xmlXPathCompiledEval: evaluation failed\n");
14743: 	    *resObj = NULL;
14744: 	} else {
14745: 	    *resObj = valuePop(pctxt);
14746: 	}
14747:     }
14748: 
14749:     /*
14750:     * Pop all remaining objects from the stack.
14751:     */
14752:     if (pctxt->valueNr > 0) {
14753: 	xmlXPathObjectPtr tmp;
14754: 	int stack = 0;
14755: 
14756: 	do {
14757: 	    tmp = valuePop(pctxt);
14758: 	    if (tmp != NULL) {
14759: 		stack++;
14760: 		xmlXPathReleaseObject(ctxt, tmp);
14761: 	    }
14762: 	} while (tmp != NULL);
14763: 	if ((stack != 0) &&
14764: 	    ((toBool) || ((resObj) && (*resObj))))
14765: 	{
14766: 	    xmlGenericError(xmlGenericErrorContext,
14767: 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14768: 		stack);
14769: 	}
14770:     }
14771: 
14772:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14773: 	xmlXPathFreeObject(*resObj);
14774: 	*resObj = NULL;
14775:     }
14776:     pctxt->comp = NULL;
14777:     xmlXPathFreeParserContext(pctxt);
14778: #ifndef LIBXML_THREAD_ENABLED
14779:     reentance--;
14780: #endif
14781: 
14782:     return(res);
14783: }
14784: 
14785: /**
14786:  * xmlXPathCompiledEval:
14787:  * @comp:  the compiled XPath expression
14788:  * @ctx:  the XPath context
14789:  *
14790:  * Evaluate the Precompiled XPath expression in the given context.
14791:  *
14792:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14793:  *         the caller has to free the object.
14794:  */
14795: xmlXPathObjectPtr
14796: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14797: {
14798:     xmlXPathObjectPtr res = NULL;
14799: 
14800:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14801:     return(res);
14802: }
14803: 
14804: /**
14805:  * xmlXPathCompiledEvalToBoolean:
14806:  * @comp:  the compiled XPath expression
14807:  * @ctxt:  the XPath context
14808:  *
14809:  * Applies the XPath boolean() function on the result of the given
14810:  * compiled expression.
14811:  *
14812:  * Returns 1 if the expression evaluated to true, 0 if to false and
14813:  *         -1 in API and internal errors.
14814:  */
14815: int
14816: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14817: 			      xmlXPathContextPtr ctxt)
14818: {
14819:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14820: }
14821: 
14822: /**
14823:  * xmlXPathEvalExpr:
14824:  * @ctxt:  the XPath Parser context
14825:  *
14826:  * Parse and evaluate an XPath expression in the given context,
14827:  * then push the result on the context stack
14828:  */
14829: void
14830: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14831: #ifdef XPATH_STREAMING
14832:     xmlXPathCompExprPtr comp;
14833: #endif
14834: 
14835:     if (ctxt == NULL) return;
14836: 
14837: #ifdef XPATH_STREAMING
14838:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14839:     if (comp != NULL) {
14840:         if (ctxt->comp != NULL)
14841: 	    xmlXPathFreeCompExpr(ctxt->comp);
14842:         ctxt->comp = comp;
14843: 	if (ctxt->cur != NULL)
14844: 	    while (*ctxt->cur != 0) ctxt->cur++;
14845:     } else
14846: #endif
14847:     {
14848: 	xmlXPathCompileExpr(ctxt, 1);
14849: 	/*
14850: 	* In this scenario the expression string will sit in ctxt->base.
14851: 	*/
14852: 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14853: 	    (ctxt->comp != NULL) &&
14854: 	    (ctxt->base != NULL) &&
14855: 	    (ctxt->comp->nbStep > 2) &&
14856: 	    (ctxt->comp->last >= 0) &&
14857: 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14858: 	{
14859: 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14860: 		&ctxt->comp->steps[ctxt->comp->last]);
14861: 	}
14862:     }
14863:     CHECK_ERROR;
14864:     xmlXPathRunEval(ctxt, 0);
14865: }
14866: 
14867: /**
14868:  * xmlXPathEval:
14869:  * @str:  the XPath expression
14870:  * @ctx:  the XPath context
14871:  *
14872:  * Evaluate the XPath Location Path in the given context.
14873:  *
14874:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14875:  *         the caller has to free the object.
14876:  */
14877: xmlXPathObjectPtr
14878: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14879:     xmlXPathParserContextPtr ctxt;
14880:     xmlXPathObjectPtr res, tmp, init = NULL;
14881:     int stack = 0;
14882: 
14883:     CHECK_CTXT(ctx)
14884: 
14885:     xmlXPathInit();
14886: 
14887:     ctxt = xmlXPathNewParserContext(str, ctx);
14888:     if (ctxt == NULL)
14889:         return NULL;
14890:     xmlXPathEvalExpr(ctxt);
14891: 
14892:     if (ctxt->value == NULL) {
14893: 	xmlGenericError(xmlGenericErrorContext,
14894: 		"xmlXPathEval: evaluation failed\n");
14895: 	res = NULL;
14896:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14897: #ifdef XPATH_STREAMING
14898:             && (ctxt->comp->stream == NULL)
14899: #endif
14900: 	      ) {
14901: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14902: 	res = NULL;
14903:     } else {
14904: 	res = valuePop(ctxt);
14905:     }
14906: 
14907:     do {
14908:         tmp = valuePop(ctxt);
14909: 	if (tmp != NULL) {
14910: 	    if (tmp != init)
14911: 		stack++;
14912: 	    xmlXPathReleaseObject(ctx, tmp);
14913:         }
14914:     } while (tmp != NULL);
14915:     if ((stack != 0) && (res != NULL)) {
14916: 	xmlGenericError(xmlGenericErrorContext,
14917: 		"xmlXPathEval: %d object left on the stack\n",
14918: 	        stack);
14919:     }
14920:     if (ctxt->error != XPATH_EXPRESSION_OK) {
14921: 	xmlXPathFreeObject(res);
14922: 	res = NULL;
14923:     }
14924: 
14925:     xmlXPathFreeParserContext(ctxt);
14926:     return(res);
14927: }
14928: 
14929: /**
14930:  * xmlXPathEvalExpression:
14931:  * @str:  the XPath expression
14932:  * @ctxt:  the XPath context
14933:  *
14934:  * Evaluate the XPath expression in the given context.
14935:  *
14936:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14937:  *         the caller has to free the object.
14938:  */
14939: xmlXPathObjectPtr
14940: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14941:     xmlXPathParserContextPtr pctxt;
14942:     xmlXPathObjectPtr res, tmp;
14943:     int stack = 0;
14944: 
14945:     CHECK_CTXT(ctxt)
14946: 
14947:     xmlXPathInit();
14948: 
14949:     pctxt = xmlXPathNewParserContext(str, ctxt);
14950:     if (pctxt == NULL)
14951:         return NULL;
14952:     xmlXPathEvalExpr(pctxt);
14953: 
14954:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14955: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14956: 	res = NULL;
14957:     } else {
14958: 	res = valuePop(pctxt);
14959:     }
14960:     do {
14961:         tmp = valuePop(pctxt);
14962: 	if (tmp != NULL) {
14963: 	    xmlXPathReleaseObject(ctxt, tmp);
14964: 	    stack++;
14965: 	}
14966:     } while (tmp != NULL);
14967:     if ((stack != 0) && (res != NULL)) {
14968: 	xmlGenericError(xmlGenericErrorContext,
14969: 		"xmlXPathEvalExpression: %d object left on the stack\n",
14970: 	        stack);
14971:     }
14972:     xmlXPathFreeParserContext(pctxt);
14973:     return(res);
14974: }
14975: 
14976: /************************************************************************
14977:  *									*
14978:  *	Extra functions not pertaining to the XPath spec		*
14979:  *									*
14980:  ************************************************************************/
14981: /**
14982:  * xmlXPathEscapeUriFunction:
14983:  * @ctxt:  the XPath Parser context
14984:  * @nargs:  the number of arguments
14985:  *
14986:  * Implement the escape-uri() XPath function
14987:  *    string escape-uri(string $str, bool $escape-reserved)
14988:  *
14989:  * This function applies the URI escaping rules defined in section 2 of [RFC
14990:  * 2396] to the string supplied as $uri-part, which typically represents all
14991:  * or part of a URI. The effect of the function is to replace any special
14992:  * character in the string by an escape sequence of the form %xx%yy...,
14993:  * where xxyy... is the hexadecimal representation of the octets used to
14994:  * represent the character in UTF-8.
14995:  *
14996:  * The set of characters that are escaped depends on the setting of the
14997:  * boolean argument $escape-reserved.
14998:  *
14999:  * If $escape-reserved is true, all characters are escaped other than lower
15000:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15001:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15002:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15003:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15004:  * A-F).
15005:  *
15006:  * If $escape-reserved is false, the behavior differs in that characters
15007:  * referred to in [RFC 2396] as reserved characters are not escaped. These
15008:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15009:  *
15010:  * [RFC 2396] does not define whether escaped URIs should use lower case or
15011:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15012:  * compared using string comparison functions, this function must always use
15013:  * the upper-case letters A-F.
15014:  *
15015:  * Generally, $escape-reserved should be set to true when escaping a string
15016:  * that is to form a single part of a URI, and to false when escaping an
15017:  * entire URI or URI reference.
15018:  *
15019:  * In the case of non-ascii characters, the string is encoded according to
15020:  * utf-8 and then converted according to RFC 2396.
15021:  *
15022:  * Examples
15023:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15024:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15025:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15026:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15027:  *
15028:  */
15029: static void
15030: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15031:     xmlXPathObjectPtr str;
15032:     int escape_reserved;
15033:     xmlBufferPtr target;
15034:     xmlChar *cptr;
15035:     xmlChar escape[4];
15036: 
15037:     CHECK_ARITY(2);
15038: 
15039:     escape_reserved = xmlXPathPopBoolean(ctxt);
15040: 
15041:     CAST_TO_STRING;
15042:     str = valuePop(ctxt);
15043: 
15044:     target = xmlBufferCreate();
15045: 
15046:     escape[0] = '%';
15047:     escape[3] = 0;
15048: 
15049:     if (target) {
15050: 	for (cptr = str->stringval; *cptr; cptr++) {
15051: 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15052: 		(*cptr >= 'a' && *cptr <= 'z') ||
15053: 		(*cptr >= '0' && *cptr <= '9') ||
15054: 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15055: 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15056: 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15057: 		(*cptr == '%' &&
15058: 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15059: 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15060: 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15061: 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15062: 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15063: 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15064: 		(!escape_reserved &&
15065: 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15066: 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15067: 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15068: 		  *cptr == ','))) {
15069: 		xmlBufferAdd(target, cptr, 1);
15070: 	    } else {
15071: 		if ((*cptr >> 4) < 10)
15072: 		    escape[1] = '0' + (*cptr >> 4);
15073: 		else
15074: 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15075: 		if ((*cptr & 0xF) < 10)
15076: 		    escape[2] = '0' + (*cptr & 0xF);
15077: 		else
15078: 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15079: 
15080: 		xmlBufferAdd(target, &escape[0], 3);
15081: 	    }
15082: 	}
15083:     }
15084:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15085: 	xmlBufferContent(target)));
15086:     xmlBufferFree(target);
15087:     xmlXPathReleaseObject(ctxt->context, str);
15088: }
15089: 
15090: /**
15091:  * xmlXPathRegisterAllFunctions:
15092:  * @ctxt:  the XPath context
15093:  *
15094:  * Registers all default XPath functions in this context
15095:  */
15096: void
15097: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15098: {
15099:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15100:                          xmlXPathBooleanFunction);
15101:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15102:                          xmlXPathCeilingFunction);
15103:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15104:                          xmlXPathCountFunction);
15105:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15106:                          xmlXPathConcatFunction);
15107:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15108:                          xmlXPathContainsFunction);
15109:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15110:                          xmlXPathIdFunction);
15111:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15112:                          xmlXPathFalseFunction);
15113:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15114:                          xmlXPathFloorFunction);
15115:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15116:                          xmlXPathLastFunction);
15117:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15118:                          xmlXPathLangFunction);
15119:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15120:                          xmlXPathLocalNameFunction);
15121:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15122:                          xmlXPathNotFunction);
15123:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15124:                          xmlXPathNameFunction);
15125:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15126:                          xmlXPathNamespaceURIFunction);
15127:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15128:                          xmlXPathNormalizeFunction);
15129:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15130:                          xmlXPathNumberFunction);
15131:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15132:                          xmlXPathPositionFunction);
15133:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15134:                          xmlXPathRoundFunction);
15135:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15136:                          xmlXPathStringFunction);
15137:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15138:                          xmlXPathStringLengthFunction);
15139:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15140:                          xmlXPathStartsWithFunction);
15141:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15142:                          xmlXPathSubstringFunction);
15143:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15144:                          xmlXPathSubstringBeforeFunction);
15145:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15146:                          xmlXPathSubstringAfterFunction);
15147:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15148:                          xmlXPathSumFunction);
15149:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15150:                          xmlXPathTrueFunction);
15151:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15152:                          xmlXPathTranslateFunction);
15153: 
15154:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15155: 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15156:                          xmlXPathEscapeUriFunction);
15157: }
15158: 
15159: #endif /* LIBXML_XPATH_ENABLED */
15160: #define bottom_xpath
15161: #include "elfgcchack.h"

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