File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xpath.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:22 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

    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:     "Stack usage errror\n",
  256:     "?? Unknown error ??\n"	/* Must be last in the list! */
  257: };
  258: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
  259: 		   sizeof(xmlXPathErrorMessages[0])) - 1)
  260: /**
  261:  * xmlXPathErrMemory:
  262:  * @ctxt:  an XPath context
  263:  * @extra:  extra informations
  264:  *
  265:  * Handle a redefinition of attribute error
  266:  */
  267: static void
  268: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  269: {
  270:     if (ctxt != NULL) {
  271:         if (extra) {
  272:             xmlChar buf[200];
  273: 
  274:             xmlStrPrintf(buf, 200,
  275:                          BAD_CAST "Memory allocation failed : %s\n",
  276:                          extra);
  277:             ctxt->lastError.message = (char *) xmlStrdup(buf);
  278:         } else {
  279:             ctxt->lastError.message = (char *)
  280: 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
  281:         }
  282:         ctxt->lastError.domain = XML_FROM_XPATH;
  283:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
  284: 	if (ctxt->error != NULL)
  285: 	    ctxt->error(ctxt->userData, &ctxt->lastError);
  286:     } else {
  287:         if (extra)
  288:             __xmlRaiseError(NULL, NULL, NULL,
  289:                             NULL, NULL, XML_FROM_XPATH,
  290:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  291:                             extra, NULL, NULL, 0, 0,
  292:                             "Memory allocation failed : %s\n", extra);
  293:         else
  294:             __xmlRaiseError(NULL, NULL, NULL,
  295:                             NULL, NULL, XML_FROM_XPATH,
  296:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  297:                             NULL, NULL, NULL, 0, 0,
  298:                             "Memory allocation failed\n");
  299:     }
  300: }
  301: 
  302: /**
  303:  * xmlXPathPErrMemory:
  304:  * @ctxt:  an XPath parser context
  305:  * @extra:  extra informations
  306:  *
  307:  * Handle a redefinition of attribute error
  308:  */
  309: static void
  310: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  311: {
  312:     if (ctxt == NULL)
  313: 	xmlXPathErrMemory(NULL, extra);
  314:     else {
  315: 	ctxt->error = XPATH_MEMORY_ERROR;
  316: 	xmlXPathErrMemory(ctxt->context, extra);
  317:     }
  318: }
  319: 
  320: /**
  321:  * xmlXPathErr:
  322:  * @ctxt:  a XPath parser context
  323:  * @error:  the error code
  324:  *
  325:  * Handle an XPath error
  326:  */
  327: void
  328: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  329: {
  330:     if ((error < 0) || (error > MAXERRNO))
  331: 	error = MAXERRNO;
  332:     if (ctxt == NULL) {
  333: 	__xmlRaiseError(NULL, NULL, NULL,
  334: 			NULL, NULL, XML_FROM_XPATH,
  335: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  336: 			XML_ERR_ERROR, NULL, 0,
  337: 			NULL, NULL, NULL, 0, 0,
  338: 			"%s", xmlXPathErrorMessages[error]);
  339: 	return;
  340:     }
  341:     ctxt->error = error;
  342:     if (ctxt->context == NULL) {
  343: 	__xmlRaiseError(NULL, NULL, NULL,
  344: 			NULL, NULL, XML_FROM_XPATH,
  345: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  346: 			XML_ERR_ERROR, NULL, 0,
  347: 			(const char *) ctxt->base, NULL, NULL,
  348: 			ctxt->cur - ctxt->base, 0,
  349: 			"%s", xmlXPathErrorMessages[error]);
  350: 	return;
  351:     }
  352: 
  353:     /* cleanup current last error */
  354:     xmlResetError(&ctxt->context->lastError);
  355: 
  356:     ctxt->context->lastError.domain = XML_FROM_XPATH;
  357:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  358:                            XPATH_EXPRESSION_OK;
  359:     ctxt->context->lastError.level = XML_ERR_ERROR;
  360:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  361:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  362:     ctxt->context->lastError.node = ctxt->context->debugNode;
  363:     if (ctxt->context->error != NULL) {
  364: 	ctxt->context->error(ctxt->context->userData,
  365: 	                     &ctxt->context->lastError);
  366:     } else {
  367: 	__xmlRaiseError(NULL, NULL, NULL,
  368: 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  369: 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  370: 			XML_ERR_ERROR, NULL, 0,
  371: 			(const char *) ctxt->base, NULL, NULL,
  372: 			ctxt->cur - ctxt->base, 0,
  373: 			"%s", xmlXPathErrorMessages[error]);
  374:     }
  375: 
  376: }
  377: 
  378: /**
  379:  * xmlXPatherror:
  380:  * @ctxt:  the XPath Parser context
  381:  * @file:  the file name
  382:  * @line:  the line number
  383:  * @no:  the error number
  384:  *
  385:  * Formats an error message.
  386:  */
  387: void
  388: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  389:               int line ATTRIBUTE_UNUSED, int no) {
  390:     xmlXPathErr(ctxt, no);
  391: }
  392: 
  393: /************************************************************************
  394:  *									*
  395:  *			Utilities					*
  396:  *									*
  397:  ************************************************************************/
  398: 
  399: /**
  400:  * xsltPointerList:
  401:  *
  402:  * Pointer-list for various purposes.
  403:  */
  404: typedef struct _xmlPointerList xmlPointerList;
  405: typedef xmlPointerList *xmlPointerListPtr;
  406: struct _xmlPointerList {
  407:     void **items;
  408:     int number;
  409:     int size;
  410: };
  411: /*
  412: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  413: * and here, we should make the functions public.
  414: */
  415: static int
  416: xmlPointerListAddSize(xmlPointerListPtr list,
  417: 		       void *item,
  418: 		       int initialSize)
  419: {
  420:     if (list->items == NULL) {
  421: 	if (initialSize <= 0)
  422: 	    initialSize = 1;
  423: 	list->items = (void **) xmlMalloc(
  424: 	    initialSize * sizeof(void *));
  425: 	if (list->items == NULL) {
  426: 	    xmlXPathErrMemory(NULL,
  427: 		"xmlPointerListCreate: allocating item\n");
  428: 	    return(-1);
  429: 	}
  430: 	list->number = 0;
  431: 	list->size = initialSize;
  432:     } else if (list->size <= list->number) {
  433: 	list->size *= 2;
  434: 	list->items = (void **) xmlRealloc(list->items,
  435: 	    list->size * sizeof(void *));
  436: 	if (list->items == NULL) {
  437: 	    xmlXPathErrMemory(NULL,
  438: 		"xmlPointerListCreate: re-allocating item\n");
  439: 	    list->size = 0;
  440: 	    return(-1);
  441: 	}
  442:     }
  443:     list->items[list->number++] = item;
  444:     return(0);
  445: }
  446: 
  447: /**
  448:  * xsltPointerListCreate:
  449:  *
  450:  * Creates an xsltPointerList structure.
  451:  *
  452:  * Returns a xsltPointerList structure or NULL in case of an error.
  453:  */
  454: static xmlPointerListPtr
  455: xmlPointerListCreate(int initialSize)
  456: {
  457:     xmlPointerListPtr ret;
  458: 
  459:     ret = xmlMalloc(sizeof(xmlPointerList));
  460:     if (ret == NULL) {
  461: 	xmlXPathErrMemory(NULL,
  462: 	    "xmlPointerListCreate: allocating item\n");
  463: 	return (NULL);
  464:     }
  465:     memset(ret, 0, sizeof(xmlPointerList));
  466:     if (initialSize > 0) {
  467: 	xmlPointerListAddSize(ret, NULL, initialSize);
  468: 	ret->number = 0;
  469:     }
  470:     return (ret);
  471: }
  472: 
  473: /**
  474:  * xsltPointerListFree:
  475:  *
  476:  * Frees the xsltPointerList structure. This does not free
  477:  * the content of the list.
  478:  */
  479: static void
  480: xmlPointerListFree(xmlPointerListPtr list)
  481: {
  482:     if (list == NULL)
  483: 	return;
  484:     if (list->items != NULL)
  485: 	xmlFree(list->items);
  486:     xmlFree(list);
  487: }
  488: 
  489: /************************************************************************
  490:  *									*
  491:  *			Parser Types					*
  492:  *									*
  493:  ************************************************************************/
  494: 
  495: /*
  496:  * Types are private:
  497:  */
  498: 
  499: typedef enum {
  500:     XPATH_OP_END=0,
  501:     XPATH_OP_AND,
  502:     XPATH_OP_OR,
  503:     XPATH_OP_EQUAL,
  504:     XPATH_OP_CMP,
  505:     XPATH_OP_PLUS,
  506:     XPATH_OP_MULT,
  507:     XPATH_OP_UNION,
  508:     XPATH_OP_ROOT,
  509:     XPATH_OP_NODE,
  510:     XPATH_OP_RESET, /* 10 */
  511:     XPATH_OP_COLLECT,
  512:     XPATH_OP_VALUE, /* 12 */
  513:     XPATH_OP_VARIABLE,
  514:     XPATH_OP_FUNCTION,
  515:     XPATH_OP_ARG,
  516:     XPATH_OP_PREDICATE,
  517:     XPATH_OP_FILTER, /* 17 */
  518:     XPATH_OP_SORT /* 18 */
  519: #ifdef LIBXML_XPTR_ENABLED
  520:     ,XPATH_OP_RANGETO
  521: #endif
  522: } xmlXPathOp;
  523: 
  524: typedef enum {
  525:     AXIS_ANCESTOR = 1,
  526:     AXIS_ANCESTOR_OR_SELF,
  527:     AXIS_ATTRIBUTE,
  528:     AXIS_CHILD,
  529:     AXIS_DESCENDANT,
  530:     AXIS_DESCENDANT_OR_SELF,
  531:     AXIS_FOLLOWING,
  532:     AXIS_FOLLOWING_SIBLING,
  533:     AXIS_NAMESPACE,
  534:     AXIS_PARENT,
  535:     AXIS_PRECEDING,
  536:     AXIS_PRECEDING_SIBLING,
  537:     AXIS_SELF
  538: } xmlXPathAxisVal;
  539: 
  540: typedef enum {
  541:     NODE_TEST_NONE = 0,
  542:     NODE_TEST_TYPE = 1,
  543:     NODE_TEST_PI = 2,
  544:     NODE_TEST_ALL = 3,
  545:     NODE_TEST_NS = 4,
  546:     NODE_TEST_NAME = 5
  547: } xmlXPathTestVal;
  548: 
  549: typedef enum {
  550:     NODE_TYPE_NODE = 0,
  551:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  552:     NODE_TYPE_TEXT = XML_TEXT_NODE,
  553:     NODE_TYPE_PI = XML_PI_NODE
  554: } xmlXPathTypeVal;
  555: 
  556: #define XP_REWRITE_DOS_CHILD_ELEM 1
  557: 
  558: typedef struct _xmlXPathStepOp xmlXPathStepOp;
  559: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  560: struct _xmlXPathStepOp {
  561:     xmlXPathOp op;		/* The identifier of the operation */
  562:     int ch1;			/* First child */
  563:     int ch2;			/* Second child */
  564:     int value;
  565:     int value2;
  566:     int value3;
  567:     void *value4;
  568:     void *value5;
  569:     void *cache;
  570:     void *cacheURI;
  571:     int rewriteType;
  572: };
  573: 
  574: struct _xmlXPathCompExpr {
  575:     int nbStep;			/* Number of steps in this expression */
  576:     int maxStep;		/* Maximum number of steps allocated */
  577:     xmlXPathStepOp *steps;	/* ops for computation of this expression */
  578:     int last;			/* index of last step in expression */
  579:     xmlChar *expr;		/* the expression being computed */
  580:     xmlDictPtr dict;		/* the dictionnary to use if any */
  581: #ifdef DEBUG_EVAL_COUNTS
  582:     int nb;
  583:     xmlChar *string;
  584: #endif
  585: #ifdef XPATH_STREAMING
  586:     xmlPatternPtr stream;
  587: #endif
  588: };
  589: 
  590: /************************************************************************
  591:  *									*
  592:  *			Forward declarations				*
  593:  *									*
  594:  ************************************************************************/
  595: static void
  596: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  597: static void
  598: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  599: static int
  600: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  601:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
  602: static int
  603: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  604: 			    xmlXPathStepOpPtr op,
  605: 			    int isPredicate);
  606: 
  607: /************************************************************************
  608:  *									*
  609:  *			Parser Type functions				*
  610:  *									*
  611:  ************************************************************************/
  612: 
  613: /**
  614:  * xmlXPathNewCompExpr:
  615:  *
  616:  * Create a new Xpath component
  617:  *
  618:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  619:  */
  620: static xmlXPathCompExprPtr
  621: xmlXPathNewCompExpr(void) {
  622:     xmlXPathCompExprPtr cur;
  623: 
  624:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  625:     if (cur == NULL) {
  626:         xmlXPathErrMemory(NULL, "allocating component\n");
  627: 	return(NULL);
  628:     }
  629:     memset(cur, 0, sizeof(xmlXPathCompExpr));
  630:     cur->maxStep = 10;
  631:     cur->nbStep = 0;
  632:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  633: 	                                   sizeof(xmlXPathStepOp));
  634:     if (cur->steps == NULL) {
  635:         xmlXPathErrMemory(NULL, "allocating steps\n");
  636: 	xmlFree(cur);
  637: 	return(NULL);
  638:     }
  639:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  640:     cur->last = -1;
  641: #ifdef DEBUG_EVAL_COUNTS
  642:     cur->nb = 0;
  643: #endif
  644:     return(cur);
  645: }
  646: 
  647: /**
  648:  * xmlXPathFreeCompExpr:
  649:  * @comp:  an XPATH comp
  650:  *
  651:  * Free up the memory allocated by @comp
  652:  */
  653: void
  654: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  655: {
  656:     xmlXPathStepOpPtr op;
  657:     int i;
  658: 
  659:     if (comp == NULL)
  660:         return;
  661:     if (comp->dict == NULL) {
  662: 	for (i = 0; i < comp->nbStep; i++) {
  663: 	    op = &comp->steps[i];
  664: 	    if (op->value4 != NULL) {
  665: 		if (op->op == XPATH_OP_VALUE)
  666: 		    xmlXPathFreeObject(op->value4);
  667: 		else
  668: 		    xmlFree(op->value4);
  669: 	    }
  670: 	    if (op->value5 != NULL)
  671: 		xmlFree(op->value5);
  672: 	}
  673:     } else {
  674: 	for (i = 0; i < comp->nbStep; i++) {
  675: 	    op = &comp->steps[i];
  676: 	    if (op->value4 != NULL) {
  677: 		if (op->op == XPATH_OP_VALUE)
  678: 		    xmlXPathFreeObject(op->value4);
  679: 	    }
  680: 	}
  681:         xmlDictFree(comp->dict);
  682:     }
  683:     if (comp->steps != NULL) {
  684:         xmlFree(comp->steps);
  685:     }
  686: #ifdef DEBUG_EVAL_COUNTS
  687:     if (comp->string != NULL) {
  688:         xmlFree(comp->string);
  689:     }
  690: #endif
  691: #ifdef XPATH_STREAMING
  692:     if (comp->stream != NULL) {
  693:         xmlFreePatternList(comp->stream);
  694:     }
  695: #endif
  696:     if (comp->expr != NULL) {
  697:         xmlFree(comp->expr);
  698:     }
  699: 
  700:     xmlFree(comp);
  701: }
  702: 
  703: /**
  704:  * xmlXPathCompExprAdd:
  705:  * @comp:  the compiled expression
  706:  * @ch1: first child index
  707:  * @ch2: second child index
  708:  * @op:  an op
  709:  * @value:  the first int value
  710:  * @value2:  the second int value
  711:  * @value3:  the third int value
  712:  * @value4:  the first string value
  713:  * @value5:  the second string value
  714:  *
  715:  * Add a step to an XPath Compiled Expression
  716:  *
  717:  * Returns -1 in case of failure, the index otherwise
  718:  */
  719: static int
  720: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
  721:    xmlXPathOp op, int value,
  722:    int value2, int value3, void *value4, void *value5) {
  723:     if (comp->nbStep >= comp->maxStep) {
  724: 	xmlXPathStepOp *real;
  725: 
  726: 	comp->maxStep *= 2;
  727: 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  728: 		                      comp->maxStep * sizeof(xmlXPathStepOp));
  729: 	if (real == NULL) {
  730: 	    comp->maxStep /= 2;
  731: 	    xmlXPathErrMemory(NULL, "adding step\n");
  732: 	    return(-1);
  733: 	}
  734: 	comp->steps = real;
  735:     }
  736:     comp->last = comp->nbStep;
  737:     comp->steps[comp->nbStep].rewriteType = 0;
  738:     comp->steps[comp->nbStep].ch1 = ch1;
  739:     comp->steps[comp->nbStep].ch2 = ch2;
  740:     comp->steps[comp->nbStep].op = op;
  741:     comp->steps[comp->nbStep].value = value;
  742:     comp->steps[comp->nbStep].value2 = value2;
  743:     comp->steps[comp->nbStep].value3 = value3;
  744:     if ((comp->dict != NULL) &&
  745:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  746: 	 (op == XPATH_OP_COLLECT))) {
  747:         if (value4 != NULL) {
  748: 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
  749: 	        (void *)xmlDictLookup(comp->dict, value4, -1);
  750: 	    xmlFree(value4);
  751: 	} else
  752: 	    comp->steps[comp->nbStep].value4 = NULL;
  753:         if (value5 != NULL) {
  754: 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
  755: 	        (void *)xmlDictLookup(comp->dict, value5, -1);
  756: 	    xmlFree(value5);
  757: 	} else
  758: 	    comp->steps[comp->nbStep].value5 = NULL;
  759:     } else {
  760: 	comp->steps[comp->nbStep].value4 = value4;
  761: 	comp->steps[comp->nbStep].value5 = value5;
  762:     }
  763:     comp->steps[comp->nbStep].cache = NULL;
  764:     return(comp->nbStep++);
  765: }
  766: 
  767: /**
  768:  * xmlXPathCompSwap:
  769:  * @comp:  the compiled expression
  770:  * @op: operation index
  771:  *
  772:  * Swaps 2 operations in the compiled expression
  773:  */
  774: static void
  775: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  776:     int tmp;
  777: 
  778: #ifndef LIBXML_THREAD_ENABLED
  779:     /*
  780:      * Since this manipulates possibly shared variables, this is
  781:      * disabled if one detects that the library is used in a multithreaded
  782:      * application
  783:      */
  784:     if (xmlXPathDisableOptimizer)
  785: 	return;
  786: #endif
  787: 
  788:     tmp = op->ch1;
  789:     op->ch1 = op->ch2;
  790:     op->ch2 = tmp;
  791: }
  792: 
  793: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
  794:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
  795: 	                (op), (val), (val2), (val3), (val4), (val5))
  796: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
  797:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
  798: 	                (op), (val), (val2), (val3), (val4), (val5))
  799: 
  800: #define PUSH_LEAVE_EXPR(op, val, val2)					\
  801: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  802: 
  803: #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
  804: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  805: 
  806: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
  807: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
  808: 			(val), (val2), 0 ,NULL ,NULL)
  809: 
  810: /************************************************************************
  811:  *									*
  812:  *		XPath object cache structures				*
  813:  *									*
  814:  ************************************************************************/
  815: 
  816: /* #define XP_DEFAULT_CACHE_ON */
  817: 
  818: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  819: 
  820: typedef struct _xmlXPathContextCache xmlXPathContextCache;
  821: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  822: struct _xmlXPathContextCache {
  823:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
  824:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
  825:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
  826:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
  827:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
  828:     int maxNodeset;
  829:     int maxString;
  830:     int maxBoolean;
  831:     int maxNumber;
  832:     int maxMisc;
  833: #ifdef XP_DEBUG_OBJ_USAGE
  834:     int dbgCachedAll;
  835:     int dbgCachedNodeset;
  836:     int dbgCachedString;
  837:     int dbgCachedBool;
  838:     int dbgCachedNumber;
  839:     int dbgCachedPoint;
  840:     int dbgCachedRange;
  841:     int dbgCachedLocset;
  842:     int dbgCachedUsers;
  843:     int dbgCachedXSLTTree;
  844:     int dbgCachedUndefined;
  845: 
  846: 
  847:     int dbgReusedAll;
  848:     int dbgReusedNodeset;
  849:     int dbgReusedString;
  850:     int dbgReusedBool;
  851:     int dbgReusedNumber;
  852:     int dbgReusedPoint;
  853:     int dbgReusedRange;
  854:     int dbgReusedLocset;
  855:     int dbgReusedUsers;
  856:     int dbgReusedXSLTTree;
  857:     int dbgReusedUndefined;
  858: 
  859: #endif
  860: };
  861: 
  862: /************************************************************************
  863:  *									*
  864:  *		Debugging related functions				*
  865:  *									*
  866:  ************************************************************************/
  867: 
  868: #define STRANGE							\
  869:     xmlGenericError(xmlGenericErrorContext,				\
  870: 	    "Internal error at %s:%d\n",				\
  871:             __FILE__, __LINE__);
  872: 
  873: #ifdef LIBXML_DEBUG_ENABLED
  874: static void
  875: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  876:     int i;
  877:     char shift[100];
  878: 
  879:     for (i = 0;((i < depth) && (i < 25));i++)
  880:         shift[2 * i] = shift[2 * i + 1] = ' ';
  881:     shift[2 * i] = shift[2 * i + 1] = 0;
  882:     if (cur == NULL) {
  883: 	fprintf(output, "%s", shift);
  884: 	fprintf(output, "Node is NULL !\n");
  885: 	return;
  886: 
  887:     }
  888: 
  889:     if ((cur->type == XML_DOCUMENT_NODE) ||
  890: 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
  891: 	fprintf(output, "%s", shift);
  892: 	fprintf(output, " /\n");
  893:     } else if (cur->type == XML_ATTRIBUTE_NODE)
  894: 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  895:     else
  896: 	xmlDebugDumpOneNode(output, cur, depth);
  897: }
  898: static void
  899: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  900:     xmlNodePtr tmp;
  901:     int i;
  902:     char shift[100];
  903: 
  904:     for (i = 0;((i < depth) && (i < 25));i++)
  905:         shift[2 * i] = shift[2 * i + 1] = ' ';
  906:     shift[2 * i] = shift[2 * i + 1] = 0;
  907:     if (cur == NULL) {
  908: 	fprintf(output, "%s", shift);
  909: 	fprintf(output, "Node is NULL !\n");
  910: 	return;
  911: 
  912:     }
  913: 
  914:     while (cur != NULL) {
  915: 	tmp = cur;
  916: 	cur = cur->next;
  917: 	xmlDebugDumpOneNode(output, tmp, depth);
  918:     }
  919: }
  920: 
  921: static void
  922: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  923:     int i;
  924:     char shift[100];
  925: 
  926:     for (i = 0;((i < depth) && (i < 25));i++)
  927:         shift[2 * i] = shift[2 * i + 1] = ' ';
  928:     shift[2 * i] = shift[2 * i + 1] = 0;
  929: 
  930:     if (cur == NULL) {
  931: 	fprintf(output, "%s", shift);
  932: 	fprintf(output, "NodeSet is NULL !\n");
  933: 	return;
  934: 
  935:     }
  936: 
  937:     if (cur != NULL) {
  938: 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  939: 	for (i = 0;i < cur->nodeNr;i++) {
  940: 	    fprintf(output, "%s", shift);
  941: 	    fprintf(output, "%d", i + 1);
  942: 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  943: 	}
  944:     }
  945: }
  946: 
  947: static void
  948: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  949:     int i;
  950:     char shift[100];
  951: 
  952:     for (i = 0;((i < depth) && (i < 25));i++)
  953:         shift[2 * i] = shift[2 * i + 1] = ' ';
  954:     shift[2 * i] = shift[2 * i + 1] = 0;
  955: 
  956:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  957: 	fprintf(output, "%s", shift);
  958: 	fprintf(output, "Value Tree is NULL !\n");
  959: 	return;
  960: 
  961:     }
  962: 
  963:     fprintf(output, "%s", shift);
  964:     fprintf(output, "%d", i + 1);
  965:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  966: }
  967: #if defined(LIBXML_XPTR_ENABLED)
  968: static void
  969: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  970:     int i;
  971:     char shift[100];
  972: 
  973:     for (i = 0;((i < depth) && (i < 25));i++)
  974:         shift[2 * i] = shift[2 * i + 1] = ' ';
  975:     shift[2 * i] = shift[2 * i + 1] = 0;
  976: 
  977:     if (cur == NULL) {
  978: 	fprintf(output, "%s", shift);
  979: 	fprintf(output, "LocationSet is NULL !\n");
  980: 	return;
  981: 
  982:     }
  983: 
  984:     for (i = 0;i < cur->locNr;i++) {
  985: 	fprintf(output, "%s", shift);
  986:         fprintf(output, "%d : ", i + 1);
  987: 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  988:     }
  989: }
  990: #endif /* LIBXML_XPTR_ENABLED */
  991: 
  992: /**
  993:  * xmlXPathDebugDumpObject:
  994:  * @output:  the FILE * to dump the output
  995:  * @cur:  the object to inspect
  996:  * @depth:  indentation level
  997:  *
  998:  * Dump the content of the object for debugging purposes
  999:  */
 1000: void
 1001: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
 1002:     int i;
 1003:     char shift[100];
 1004: 
 1005:     if (output == NULL) return;
 1006: 
 1007:     for (i = 0;((i < depth) && (i < 25));i++)
 1008:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1009:     shift[2 * i] = shift[2 * i + 1] = 0;
 1010: 
 1011: 
 1012:     fprintf(output, "%s", shift);
 1013: 
 1014:     if (cur == NULL) {
 1015:         fprintf(output, "Object is empty (NULL)\n");
 1016: 	return;
 1017:     }
 1018:     switch(cur->type) {
 1019:         case XPATH_UNDEFINED:
 1020: 	    fprintf(output, "Object is uninitialized\n");
 1021: 	    break;
 1022:         case XPATH_NODESET:
 1023: 	    fprintf(output, "Object is a Node Set :\n");
 1024: 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
 1025: 	    break;
 1026: 	case XPATH_XSLT_TREE:
 1027: 	    fprintf(output, "Object is an XSLT value tree :\n");
 1028: 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
 1029: 	    break;
 1030:         case XPATH_BOOLEAN:
 1031: 	    fprintf(output, "Object is a Boolean : ");
 1032: 	    if (cur->boolval) fprintf(output, "true\n");
 1033: 	    else fprintf(output, "false\n");
 1034: 	    break;
 1035:         case XPATH_NUMBER:
 1036: 	    switch (xmlXPathIsInf(cur->floatval)) {
 1037: 	    case 1:
 1038: 		fprintf(output, "Object is a number : Infinity\n");
 1039: 		break;
 1040: 	    case -1:
 1041: 		fprintf(output, "Object is a number : -Infinity\n");
 1042: 		break;
 1043: 	    default:
 1044: 		if (xmlXPathIsNaN(cur->floatval)) {
 1045: 		    fprintf(output, "Object is a number : NaN\n");
 1046: 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
 1047: 		    fprintf(output, "Object is a number : 0\n");
 1048: 		} else {
 1049: 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
 1050: 		}
 1051: 	    }
 1052: 	    break;
 1053:         case XPATH_STRING:
 1054: 	    fprintf(output, "Object is a string : ");
 1055: 	    xmlDebugDumpString(output, cur->stringval);
 1056: 	    fprintf(output, "\n");
 1057: 	    break;
 1058: 	case XPATH_POINT:
 1059: 	    fprintf(output, "Object is a point : index %d in node", cur->index);
 1060: 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
 1061: 	    fprintf(output, "\n");
 1062: 	    break;
 1063: 	case XPATH_RANGE:
 1064: 	    if ((cur->user2 == NULL) ||
 1065: 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
 1066: 		fprintf(output, "Object is a collapsed range :\n");
 1067: 		fprintf(output, "%s", shift);
 1068: 		if (cur->index >= 0)
 1069: 		    fprintf(output, "index %d in ", cur->index);
 1070: 		fprintf(output, "node\n");
 1071: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1072: 			              depth + 1);
 1073: 	    } else  {
 1074: 		fprintf(output, "Object is a range :\n");
 1075: 		fprintf(output, "%s", shift);
 1076: 		fprintf(output, "From ");
 1077: 		if (cur->index >= 0)
 1078: 		    fprintf(output, "index %d in ", cur->index);
 1079: 		fprintf(output, "node\n");
 1080: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
 1081: 			              depth + 1);
 1082: 		fprintf(output, "%s", shift);
 1083: 		fprintf(output, "To ");
 1084: 		if (cur->index2 >= 0)
 1085: 		    fprintf(output, "index %d in ", cur->index2);
 1086: 		fprintf(output, "node\n");
 1087: 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
 1088: 			              depth + 1);
 1089: 		fprintf(output, "\n");
 1090: 	    }
 1091: 	    break;
 1092: 	case XPATH_LOCATIONSET:
 1093: #if defined(LIBXML_XPTR_ENABLED)
 1094: 	    fprintf(output, "Object is a Location Set:\n");
 1095: 	    xmlXPathDebugDumpLocationSet(output,
 1096: 		    (xmlLocationSetPtr) cur->user, depth);
 1097: #endif
 1098: 	    break;
 1099: 	case XPATH_USERS:
 1100: 	    fprintf(output, "Object is user defined\n");
 1101: 	    break;
 1102:     }
 1103: }
 1104: 
 1105: static void
 1106: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
 1107: 	                     xmlXPathStepOpPtr op, int depth) {
 1108:     int i;
 1109:     char shift[100];
 1110: 
 1111:     for (i = 0;((i < depth) && (i < 25));i++)
 1112:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1113:     shift[2 * i] = shift[2 * i + 1] = 0;
 1114: 
 1115:     fprintf(output, "%s", shift);
 1116:     if (op == NULL) {
 1117: 	fprintf(output, "Step is NULL\n");
 1118: 	return;
 1119:     }
 1120:     switch (op->op) {
 1121:         case XPATH_OP_END:
 1122: 	    fprintf(output, "END"); break;
 1123:         case XPATH_OP_AND:
 1124: 	    fprintf(output, "AND"); break;
 1125:         case XPATH_OP_OR:
 1126: 	    fprintf(output, "OR"); break;
 1127:         case XPATH_OP_EQUAL:
 1128: 	     if (op->value)
 1129: 		 fprintf(output, "EQUAL =");
 1130: 	     else
 1131: 		 fprintf(output, "EQUAL !=");
 1132: 	     break;
 1133:         case XPATH_OP_CMP:
 1134: 	     if (op->value)
 1135: 		 fprintf(output, "CMP <");
 1136: 	     else
 1137: 		 fprintf(output, "CMP >");
 1138: 	     if (!op->value2)
 1139: 		 fprintf(output, "=");
 1140: 	     break;
 1141:         case XPATH_OP_PLUS:
 1142: 	     if (op->value == 0)
 1143: 		 fprintf(output, "PLUS -");
 1144: 	     else if (op->value == 1)
 1145: 		 fprintf(output, "PLUS +");
 1146: 	     else if (op->value == 2)
 1147: 		 fprintf(output, "PLUS unary -");
 1148: 	     else if (op->value == 3)
 1149: 		 fprintf(output, "PLUS unary - -");
 1150: 	     break;
 1151:         case XPATH_OP_MULT:
 1152: 	     if (op->value == 0)
 1153: 		 fprintf(output, "MULT *");
 1154: 	     else if (op->value == 1)
 1155: 		 fprintf(output, "MULT div");
 1156: 	     else
 1157: 		 fprintf(output, "MULT mod");
 1158: 	     break;
 1159:         case XPATH_OP_UNION:
 1160: 	     fprintf(output, "UNION"); break;
 1161:         case XPATH_OP_ROOT:
 1162: 	     fprintf(output, "ROOT"); break;
 1163:         case XPATH_OP_NODE:
 1164: 	     fprintf(output, "NODE"); break;
 1165:         case XPATH_OP_RESET:
 1166: 	     fprintf(output, "RESET"); break;
 1167:         case XPATH_OP_SORT:
 1168: 	     fprintf(output, "SORT"); break;
 1169:         case XPATH_OP_COLLECT: {
 1170: 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
 1171: 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
 1172: 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
 1173: 	    const xmlChar *prefix = op->value4;
 1174: 	    const xmlChar *name = op->value5;
 1175: 
 1176: 	    fprintf(output, "COLLECT ");
 1177: 	    switch (axis) {
 1178: 		case AXIS_ANCESTOR:
 1179: 		    fprintf(output, " 'ancestors' "); break;
 1180: 		case AXIS_ANCESTOR_OR_SELF:
 1181: 		    fprintf(output, " 'ancestors-or-self' "); break;
 1182: 		case AXIS_ATTRIBUTE:
 1183: 		    fprintf(output, " 'attributes' "); break;
 1184: 		case AXIS_CHILD:
 1185: 		    fprintf(output, " 'child' "); break;
 1186: 		case AXIS_DESCENDANT:
 1187: 		    fprintf(output, " 'descendant' "); break;
 1188: 		case AXIS_DESCENDANT_OR_SELF:
 1189: 		    fprintf(output, " 'descendant-or-self' "); break;
 1190: 		case AXIS_FOLLOWING:
 1191: 		    fprintf(output, " 'following' "); break;
 1192: 		case AXIS_FOLLOWING_SIBLING:
 1193: 		    fprintf(output, " 'following-siblings' "); break;
 1194: 		case AXIS_NAMESPACE:
 1195: 		    fprintf(output, " 'namespace' "); break;
 1196: 		case AXIS_PARENT:
 1197: 		    fprintf(output, " 'parent' "); break;
 1198: 		case AXIS_PRECEDING:
 1199: 		    fprintf(output, " 'preceding' "); break;
 1200: 		case AXIS_PRECEDING_SIBLING:
 1201: 		    fprintf(output, " 'preceding-sibling' "); break;
 1202: 		case AXIS_SELF:
 1203: 		    fprintf(output, " 'self' "); break;
 1204: 	    }
 1205: 	    switch (test) {
 1206:                 case NODE_TEST_NONE:
 1207: 		    fprintf(output, "'none' "); break;
 1208:                 case NODE_TEST_TYPE:
 1209: 		    fprintf(output, "'type' "); break;
 1210:                 case NODE_TEST_PI:
 1211: 		    fprintf(output, "'PI' "); break;
 1212:                 case NODE_TEST_ALL:
 1213: 		    fprintf(output, "'all' "); break;
 1214:                 case NODE_TEST_NS:
 1215: 		    fprintf(output, "'namespace' "); break;
 1216:                 case NODE_TEST_NAME:
 1217: 		    fprintf(output, "'name' "); break;
 1218: 	    }
 1219: 	    switch (type) {
 1220:                 case NODE_TYPE_NODE:
 1221: 		    fprintf(output, "'node' "); break;
 1222:                 case NODE_TYPE_COMMENT:
 1223: 		    fprintf(output, "'comment' "); break;
 1224:                 case NODE_TYPE_TEXT:
 1225: 		    fprintf(output, "'text' "); break;
 1226:                 case NODE_TYPE_PI:
 1227: 		    fprintf(output, "'PI' "); break;
 1228: 	    }
 1229: 	    if (prefix != NULL)
 1230: 		fprintf(output, "%s:", prefix);
 1231: 	    if (name != NULL)
 1232: 		fprintf(output, "%s", (const char *) name);
 1233: 	    break;
 1234: 
 1235:         }
 1236: 	case XPATH_OP_VALUE: {
 1237: 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
 1238: 
 1239: 	    fprintf(output, "ELEM ");
 1240: 	    xmlXPathDebugDumpObject(output, object, 0);
 1241: 	    goto finish;
 1242: 	}
 1243: 	case XPATH_OP_VARIABLE: {
 1244: 	    const xmlChar *prefix = op->value5;
 1245: 	    const xmlChar *name = op->value4;
 1246: 
 1247: 	    if (prefix != NULL)
 1248: 		fprintf(output, "VARIABLE %s:%s", prefix, name);
 1249: 	    else
 1250: 		fprintf(output, "VARIABLE %s", name);
 1251: 	    break;
 1252: 	}
 1253: 	case XPATH_OP_FUNCTION: {
 1254: 	    int nbargs = op->value;
 1255: 	    const xmlChar *prefix = op->value5;
 1256: 	    const xmlChar *name = op->value4;
 1257: 
 1258: 	    if (prefix != NULL)
 1259: 		fprintf(output, "FUNCTION %s:%s(%d args)",
 1260: 			prefix, name, nbargs);
 1261: 	    else
 1262: 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
 1263: 	    break;
 1264: 	}
 1265:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
 1266:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
 1267:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
 1268: #ifdef LIBXML_XPTR_ENABLED
 1269:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
 1270: #endif
 1271: 	default:
 1272:         fprintf(output, "UNKNOWN %d\n", op->op); return;
 1273:     }
 1274:     fprintf(output, "\n");
 1275: finish:
 1276:     if (op->ch1 >= 0)
 1277: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
 1278:     if (op->ch2 >= 0)
 1279: 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
 1280: }
 1281: 
 1282: /**
 1283:  * xmlXPathDebugDumpCompExpr:
 1284:  * @output:  the FILE * for the output
 1285:  * @comp:  the precompiled XPath expression
 1286:  * @depth:  the indentation level.
 1287:  *
 1288:  * Dumps the tree of the compiled XPath expression.
 1289:  */
 1290: void
 1291: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
 1292: 	                  int depth) {
 1293:     int i;
 1294:     char shift[100];
 1295: 
 1296:     if ((output == NULL) || (comp == NULL)) return;
 1297: 
 1298:     for (i = 0;((i < depth) && (i < 25));i++)
 1299:         shift[2 * i] = shift[2 * i + 1] = ' ';
 1300:     shift[2 * i] = shift[2 * i + 1] = 0;
 1301: 
 1302:     fprintf(output, "%s", shift);
 1303: 
 1304:     fprintf(output, "Compiled Expression : %d elements\n",
 1305: 	    comp->nbStep);
 1306:     i = comp->last;
 1307:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
 1308: }
 1309: 
 1310: #ifdef XP_DEBUG_OBJ_USAGE
 1311: 
 1312: /*
 1313: * XPath object usage related debugging variables.
 1314: */
 1315: static int xmlXPathDebugObjCounterUndefined = 0;
 1316: static int xmlXPathDebugObjCounterNodeset = 0;
 1317: static int xmlXPathDebugObjCounterBool = 0;
 1318: static int xmlXPathDebugObjCounterNumber = 0;
 1319: static int xmlXPathDebugObjCounterString = 0;
 1320: static int xmlXPathDebugObjCounterPoint = 0;
 1321: static int xmlXPathDebugObjCounterRange = 0;
 1322: static int xmlXPathDebugObjCounterLocset = 0;
 1323: static int xmlXPathDebugObjCounterUsers = 0;
 1324: static int xmlXPathDebugObjCounterXSLTTree = 0;
 1325: static int xmlXPathDebugObjCounterAll = 0;
 1326: 
 1327: static int xmlXPathDebugObjTotalUndefined = 0;
 1328: static int xmlXPathDebugObjTotalNodeset = 0;
 1329: static int xmlXPathDebugObjTotalBool = 0;
 1330: static int xmlXPathDebugObjTotalNumber = 0;
 1331: static int xmlXPathDebugObjTotalString = 0;
 1332: static int xmlXPathDebugObjTotalPoint = 0;
 1333: static int xmlXPathDebugObjTotalRange = 0;
 1334: static int xmlXPathDebugObjTotalLocset = 0;
 1335: static int xmlXPathDebugObjTotalUsers = 0;
 1336: static int xmlXPathDebugObjTotalXSLTTree = 0;
 1337: static int xmlXPathDebugObjTotalAll = 0;
 1338: 
 1339: static int xmlXPathDebugObjMaxUndefined = 0;
 1340: static int xmlXPathDebugObjMaxNodeset = 0;
 1341: static int xmlXPathDebugObjMaxBool = 0;
 1342: static int xmlXPathDebugObjMaxNumber = 0;
 1343: static int xmlXPathDebugObjMaxString = 0;
 1344: static int xmlXPathDebugObjMaxPoint = 0;
 1345: static int xmlXPathDebugObjMaxRange = 0;
 1346: static int xmlXPathDebugObjMaxLocset = 0;
 1347: static int xmlXPathDebugObjMaxUsers = 0;
 1348: static int xmlXPathDebugObjMaxXSLTTree = 0;
 1349: static int xmlXPathDebugObjMaxAll = 0;
 1350: 
 1351: /* REVISIT TODO: Make this static when committing */
 1352: static void
 1353: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
 1354: {
 1355:     if (ctxt != NULL) {
 1356: 	if (ctxt->cache != NULL) {
 1357: 	    xmlXPathContextCachePtr cache =
 1358: 		(xmlXPathContextCachePtr) ctxt->cache;
 1359: 
 1360: 	    cache->dbgCachedAll = 0;
 1361: 	    cache->dbgCachedNodeset = 0;
 1362: 	    cache->dbgCachedString = 0;
 1363: 	    cache->dbgCachedBool = 0;
 1364: 	    cache->dbgCachedNumber = 0;
 1365: 	    cache->dbgCachedPoint = 0;
 1366: 	    cache->dbgCachedRange = 0;
 1367: 	    cache->dbgCachedLocset = 0;
 1368: 	    cache->dbgCachedUsers = 0;
 1369: 	    cache->dbgCachedXSLTTree = 0;
 1370: 	    cache->dbgCachedUndefined = 0;
 1371: 
 1372: 	    cache->dbgReusedAll = 0;
 1373: 	    cache->dbgReusedNodeset = 0;
 1374: 	    cache->dbgReusedString = 0;
 1375: 	    cache->dbgReusedBool = 0;
 1376: 	    cache->dbgReusedNumber = 0;
 1377: 	    cache->dbgReusedPoint = 0;
 1378: 	    cache->dbgReusedRange = 0;
 1379: 	    cache->dbgReusedLocset = 0;
 1380: 	    cache->dbgReusedUsers = 0;
 1381: 	    cache->dbgReusedXSLTTree = 0;
 1382: 	    cache->dbgReusedUndefined = 0;
 1383: 	}
 1384:     }
 1385: 
 1386:     xmlXPathDebugObjCounterUndefined = 0;
 1387:     xmlXPathDebugObjCounterNodeset = 0;
 1388:     xmlXPathDebugObjCounterBool = 0;
 1389:     xmlXPathDebugObjCounterNumber = 0;
 1390:     xmlXPathDebugObjCounterString = 0;
 1391:     xmlXPathDebugObjCounterPoint = 0;
 1392:     xmlXPathDebugObjCounterRange = 0;
 1393:     xmlXPathDebugObjCounterLocset = 0;
 1394:     xmlXPathDebugObjCounterUsers = 0;
 1395:     xmlXPathDebugObjCounterXSLTTree = 0;
 1396:     xmlXPathDebugObjCounterAll = 0;
 1397: 
 1398:     xmlXPathDebugObjTotalUndefined = 0;
 1399:     xmlXPathDebugObjTotalNodeset = 0;
 1400:     xmlXPathDebugObjTotalBool = 0;
 1401:     xmlXPathDebugObjTotalNumber = 0;
 1402:     xmlXPathDebugObjTotalString = 0;
 1403:     xmlXPathDebugObjTotalPoint = 0;
 1404:     xmlXPathDebugObjTotalRange = 0;
 1405:     xmlXPathDebugObjTotalLocset = 0;
 1406:     xmlXPathDebugObjTotalUsers = 0;
 1407:     xmlXPathDebugObjTotalXSLTTree = 0;
 1408:     xmlXPathDebugObjTotalAll = 0;
 1409: 
 1410:     xmlXPathDebugObjMaxUndefined = 0;
 1411:     xmlXPathDebugObjMaxNodeset = 0;
 1412:     xmlXPathDebugObjMaxBool = 0;
 1413:     xmlXPathDebugObjMaxNumber = 0;
 1414:     xmlXPathDebugObjMaxString = 0;
 1415:     xmlXPathDebugObjMaxPoint = 0;
 1416:     xmlXPathDebugObjMaxRange = 0;
 1417:     xmlXPathDebugObjMaxLocset = 0;
 1418:     xmlXPathDebugObjMaxUsers = 0;
 1419:     xmlXPathDebugObjMaxXSLTTree = 0;
 1420:     xmlXPathDebugObjMaxAll = 0;
 1421: 
 1422: }
 1423: 
 1424: static void
 1425: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
 1426: 			      xmlXPathObjectType objType)
 1427: {
 1428:     int isCached = 0;
 1429: 
 1430:     if (ctxt != NULL) {
 1431: 	if (ctxt->cache != NULL) {
 1432: 	    xmlXPathContextCachePtr cache =
 1433: 		(xmlXPathContextCachePtr) ctxt->cache;
 1434: 
 1435: 	    isCached = 1;
 1436: 
 1437: 	    cache->dbgReusedAll++;
 1438: 	    switch (objType) {
 1439: 		case XPATH_UNDEFINED:
 1440: 		    cache->dbgReusedUndefined++;
 1441: 		    break;
 1442: 		case XPATH_NODESET:
 1443: 		    cache->dbgReusedNodeset++;
 1444: 		    break;
 1445: 		case XPATH_BOOLEAN:
 1446: 		    cache->dbgReusedBool++;
 1447: 		    break;
 1448: 		case XPATH_NUMBER:
 1449: 		    cache->dbgReusedNumber++;
 1450: 		    break;
 1451: 		case XPATH_STRING:
 1452: 		    cache->dbgReusedString++;
 1453: 		    break;
 1454: 		case XPATH_POINT:
 1455: 		    cache->dbgReusedPoint++;
 1456: 		    break;
 1457: 		case XPATH_RANGE:
 1458: 		    cache->dbgReusedRange++;
 1459: 		    break;
 1460: 		case XPATH_LOCATIONSET:
 1461: 		    cache->dbgReusedLocset++;
 1462: 		    break;
 1463: 		case XPATH_USERS:
 1464: 		    cache->dbgReusedUsers++;
 1465: 		    break;
 1466: 		case XPATH_XSLT_TREE:
 1467: 		    cache->dbgReusedXSLTTree++;
 1468: 		    break;
 1469: 		default:
 1470: 		    break;
 1471: 	    }
 1472: 	}
 1473:     }
 1474: 
 1475:     switch (objType) {
 1476: 	case XPATH_UNDEFINED:
 1477: 	    if (! isCached)
 1478: 		xmlXPathDebugObjTotalUndefined++;
 1479: 	    xmlXPathDebugObjCounterUndefined++;
 1480: 	    if (xmlXPathDebugObjCounterUndefined >
 1481: 		xmlXPathDebugObjMaxUndefined)
 1482: 		xmlXPathDebugObjMaxUndefined =
 1483: 		    xmlXPathDebugObjCounterUndefined;
 1484: 	    break;
 1485: 	case XPATH_NODESET:
 1486: 	    if (! isCached)
 1487: 		xmlXPathDebugObjTotalNodeset++;
 1488: 	    xmlXPathDebugObjCounterNodeset++;
 1489: 	    if (xmlXPathDebugObjCounterNodeset >
 1490: 		xmlXPathDebugObjMaxNodeset)
 1491: 		xmlXPathDebugObjMaxNodeset =
 1492: 		    xmlXPathDebugObjCounterNodeset;
 1493: 	    break;
 1494: 	case XPATH_BOOLEAN:
 1495: 	    if (! isCached)
 1496: 		xmlXPathDebugObjTotalBool++;
 1497: 	    xmlXPathDebugObjCounterBool++;
 1498: 	    if (xmlXPathDebugObjCounterBool >
 1499: 		xmlXPathDebugObjMaxBool)
 1500: 		xmlXPathDebugObjMaxBool =
 1501: 		    xmlXPathDebugObjCounterBool;
 1502: 	    break;
 1503: 	case XPATH_NUMBER:
 1504: 	    if (! isCached)
 1505: 		xmlXPathDebugObjTotalNumber++;
 1506: 	    xmlXPathDebugObjCounterNumber++;
 1507: 	    if (xmlXPathDebugObjCounterNumber >
 1508: 		xmlXPathDebugObjMaxNumber)
 1509: 		xmlXPathDebugObjMaxNumber =
 1510: 		    xmlXPathDebugObjCounterNumber;
 1511: 	    break;
 1512: 	case XPATH_STRING:
 1513: 	    if (! isCached)
 1514: 		xmlXPathDebugObjTotalString++;
 1515: 	    xmlXPathDebugObjCounterString++;
 1516: 	    if (xmlXPathDebugObjCounterString >
 1517: 		xmlXPathDebugObjMaxString)
 1518: 		xmlXPathDebugObjMaxString =
 1519: 		    xmlXPathDebugObjCounterString;
 1520: 	    break;
 1521: 	case XPATH_POINT:
 1522: 	    if (! isCached)
 1523: 		xmlXPathDebugObjTotalPoint++;
 1524: 	    xmlXPathDebugObjCounterPoint++;
 1525: 	    if (xmlXPathDebugObjCounterPoint >
 1526: 		xmlXPathDebugObjMaxPoint)
 1527: 		xmlXPathDebugObjMaxPoint =
 1528: 		    xmlXPathDebugObjCounterPoint;
 1529: 	    break;
 1530: 	case XPATH_RANGE:
 1531: 	    if (! isCached)
 1532: 		xmlXPathDebugObjTotalRange++;
 1533: 	    xmlXPathDebugObjCounterRange++;
 1534: 	    if (xmlXPathDebugObjCounterRange >
 1535: 		xmlXPathDebugObjMaxRange)
 1536: 		xmlXPathDebugObjMaxRange =
 1537: 		    xmlXPathDebugObjCounterRange;
 1538: 	    break;
 1539: 	case XPATH_LOCATIONSET:
 1540: 	    if (! isCached)
 1541: 		xmlXPathDebugObjTotalLocset++;
 1542: 	    xmlXPathDebugObjCounterLocset++;
 1543: 	    if (xmlXPathDebugObjCounterLocset >
 1544: 		xmlXPathDebugObjMaxLocset)
 1545: 		xmlXPathDebugObjMaxLocset =
 1546: 		    xmlXPathDebugObjCounterLocset;
 1547: 	    break;
 1548: 	case XPATH_USERS:
 1549: 	    if (! isCached)
 1550: 		xmlXPathDebugObjTotalUsers++;
 1551: 	    xmlXPathDebugObjCounterUsers++;
 1552: 	    if (xmlXPathDebugObjCounterUsers >
 1553: 		xmlXPathDebugObjMaxUsers)
 1554: 		xmlXPathDebugObjMaxUsers =
 1555: 		    xmlXPathDebugObjCounterUsers;
 1556: 	    break;
 1557: 	case XPATH_XSLT_TREE:
 1558: 	    if (! isCached)
 1559: 		xmlXPathDebugObjTotalXSLTTree++;
 1560: 	    xmlXPathDebugObjCounterXSLTTree++;
 1561: 	    if (xmlXPathDebugObjCounterXSLTTree >
 1562: 		xmlXPathDebugObjMaxXSLTTree)
 1563: 		xmlXPathDebugObjMaxXSLTTree =
 1564: 		    xmlXPathDebugObjCounterXSLTTree;
 1565: 	    break;
 1566: 	default:
 1567: 	    break;
 1568:     }
 1569:     if (! isCached)
 1570: 	xmlXPathDebugObjTotalAll++;
 1571:     xmlXPathDebugObjCounterAll++;
 1572:     if (xmlXPathDebugObjCounterAll >
 1573: 	xmlXPathDebugObjMaxAll)
 1574: 	xmlXPathDebugObjMaxAll =
 1575: 	    xmlXPathDebugObjCounterAll;
 1576: }
 1577: 
 1578: static void
 1579: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
 1580: 			      xmlXPathObjectType objType)
 1581: {
 1582:     int isCached = 0;
 1583: 
 1584:     if (ctxt != NULL) {
 1585: 	if (ctxt->cache != NULL) {
 1586: 	    xmlXPathContextCachePtr cache =
 1587: 		(xmlXPathContextCachePtr) ctxt->cache;
 1588: 
 1589: 	    isCached = 1;
 1590: 
 1591: 	    cache->dbgCachedAll++;
 1592: 	    switch (objType) {
 1593: 		case XPATH_UNDEFINED:
 1594: 		    cache->dbgCachedUndefined++;
 1595: 		    break;
 1596: 		case XPATH_NODESET:
 1597: 		    cache->dbgCachedNodeset++;
 1598: 		    break;
 1599: 		case XPATH_BOOLEAN:
 1600: 		    cache->dbgCachedBool++;
 1601: 		    break;
 1602: 		case XPATH_NUMBER:
 1603: 		    cache->dbgCachedNumber++;
 1604: 		    break;
 1605: 		case XPATH_STRING:
 1606: 		    cache->dbgCachedString++;
 1607: 		    break;
 1608: 		case XPATH_POINT:
 1609: 		    cache->dbgCachedPoint++;
 1610: 		    break;
 1611: 		case XPATH_RANGE:
 1612: 		    cache->dbgCachedRange++;
 1613: 		    break;
 1614: 		case XPATH_LOCATIONSET:
 1615: 		    cache->dbgCachedLocset++;
 1616: 		    break;
 1617: 		case XPATH_USERS:
 1618: 		    cache->dbgCachedUsers++;
 1619: 		    break;
 1620: 		case XPATH_XSLT_TREE:
 1621: 		    cache->dbgCachedXSLTTree++;
 1622: 		    break;
 1623: 		default:
 1624: 		    break;
 1625: 	    }
 1626: 
 1627: 	}
 1628:     }
 1629:     switch (objType) {
 1630: 	case XPATH_UNDEFINED:
 1631: 	    xmlXPathDebugObjCounterUndefined--;
 1632: 	    break;
 1633: 	case XPATH_NODESET:
 1634: 	    xmlXPathDebugObjCounterNodeset--;
 1635: 	    break;
 1636: 	case XPATH_BOOLEAN:
 1637: 	    xmlXPathDebugObjCounterBool--;
 1638: 	    break;
 1639: 	case XPATH_NUMBER:
 1640: 	    xmlXPathDebugObjCounterNumber--;
 1641: 	    break;
 1642: 	case XPATH_STRING:
 1643: 	    xmlXPathDebugObjCounterString--;
 1644: 	    break;
 1645: 	case XPATH_POINT:
 1646: 	    xmlXPathDebugObjCounterPoint--;
 1647: 	    break;
 1648: 	case XPATH_RANGE:
 1649: 	    xmlXPathDebugObjCounterRange--;
 1650: 	    break;
 1651: 	case XPATH_LOCATIONSET:
 1652: 	    xmlXPathDebugObjCounterLocset--;
 1653: 	    break;
 1654: 	case XPATH_USERS:
 1655: 	    xmlXPathDebugObjCounterUsers--;
 1656: 	    break;
 1657: 	case XPATH_XSLT_TREE:
 1658: 	    xmlXPathDebugObjCounterXSLTTree--;
 1659: 	    break;
 1660: 	default:
 1661: 	    break;
 1662:     }
 1663:     xmlXPathDebugObjCounterAll--;
 1664: }
 1665: 
 1666: /* REVISIT TODO: Make this static when committing */
 1667: static void
 1668: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
 1669: {
 1670:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
 1671: 	reqXSLTTree, reqUndefined;
 1672:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
 1673: 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
 1674:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
 1675: 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
 1676:     int leftObjs = xmlXPathDebugObjCounterAll;
 1677: 
 1678:     reqAll = xmlXPathDebugObjTotalAll;
 1679:     reqNodeset = xmlXPathDebugObjTotalNodeset;
 1680:     reqString = xmlXPathDebugObjTotalString;
 1681:     reqBool = xmlXPathDebugObjTotalBool;
 1682:     reqNumber = xmlXPathDebugObjTotalNumber;
 1683:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
 1684:     reqUndefined = xmlXPathDebugObjTotalUndefined;
 1685: 
 1686:     printf("# XPath object usage:\n");
 1687: 
 1688:     if (ctxt != NULL) {
 1689: 	if (ctxt->cache != NULL) {
 1690: 	    xmlXPathContextCachePtr cache =
 1691: 		(xmlXPathContextCachePtr) ctxt->cache;
 1692: 
 1693: 	    reAll = cache->dbgReusedAll;
 1694: 	    reqAll += reAll;
 1695: 	    reNodeset = cache->dbgReusedNodeset;
 1696: 	    reqNodeset += reNodeset;
 1697: 	    reString = cache->dbgReusedString;
 1698: 	    reqString += reString;
 1699: 	    reBool = cache->dbgReusedBool;
 1700: 	    reqBool += reBool;
 1701: 	    reNumber = cache->dbgReusedNumber;
 1702: 	    reqNumber += reNumber;
 1703: 	    reXSLTTree = cache->dbgReusedXSLTTree;
 1704: 	    reqXSLTTree += reXSLTTree;
 1705: 	    reUndefined = cache->dbgReusedUndefined;
 1706: 	    reqUndefined += reUndefined;
 1707: 
 1708: 	    caAll = cache->dbgCachedAll;
 1709: 	    caBool = cache->dbgCachedBool;
 1710: 	    caNodeset = cache->dbgCachedNodeset;
 1711: 	    caString = cache->dbgCachedString;
 1712: 	    caNumber = cache->dbgCachedNumber;
 1713: 	    caXSLTTree = cache->dbgCachedXSLTTree;
 1714: 	    caUndefined = cache->dbgCachedUndefined;
 1715: 
 1716: 	    if (cache->nodesetObjs)
 1717: 		leftObjs -= cache->nodesetObjs->number;
 1718: 	    if (cache->stringObjs)
 1719: 		leftObjs -= cache->stringObjs->number;
 1720: 	    if (cache->booleanObjs)
 1721: 		leftObjs -= cache->booleanObjs->number;
 1722: 	    if (cache->numberObjs)
 1723: 		leftObjs -= cache->numberObjs->number;
 1724: 	    if (cache->miscObjs)
 1725: 		leftObjs -= cache->miscObjs->number;
 1726: 	}
 1727:     }
 1728: 
 1729:     printf("# all\n");
 1730:     printf("#   total  : %d\n", reqAll);
 1731:     printf("#   left  : %d\n", leftObjs);
 1732:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
 1733:     printf("#   reused : %d\n", reAll);
 1734:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
 1735: 
 1736:     printf("# node-sets\n");
 1737:     printf("#   total  : %d\n", reqNodeset);
 1738:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
 1739:     printf("#   reused : %d\n", reNodeset);
 1740:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
 1741: 
 1742:     printf("# strings\n");
 1743:     printf("#   total  : %d\n", reqString);
 1744:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
 1745:     printf("#   reused : %d\n", reString);
 1746:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
 1747: 
 1748:     printf("# booleans\n");
 1749:     printf("#   total  : %d\n", reqBool);
 1750:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
 1751:     printf("#   reused : %d\n", reBool);
 1752:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
 1753: 
 1754:     printf("# numbers\n");
 1755:     printf("#   total  : %d\n", reqNumber);
 1756:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
 1757:     printf("#   reused : %d\n", reNumber);
 1758:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
 1759: 
 1760:     printf("# XSLT result tree fragments\n");
 1761:     printf("#   total  : %d\n", reqXSLTTree);
 1762:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
 1763:     printf("#   reused : %d\n", reXSLTTree);
 1764:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
 1765: 
 1766:     printf("# undefined\n");
 1767:     printf("#   total  : %d\n", reqUndefined);
 1768:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
 1769:     printf("#   reused : %d\n", reUndefined);
 1770:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
 1771: 
 1772: }
 1773: 
 1774: #endif /* XP_DEBUG_OBJ_USAGE */
 1775: 
 1776: #endif /* LIBXML_DEBUG_ENABLED */
 1777: 
 1778: /************************************************************************
 1779:  *									*
 1780:  *			XPath object caching				*
 1781:  *									*
 1782:  ************************************************************************/
 1783: 
 1784: /**
 1785:  * xmlXPathNewCache:
 1786:  *
 1787:  * Create a new object cache
 1788:  *
 1789:  * Returns the xmlXPathCache just allocated.
 1790:  */
 1791: static xmlXPathContextCachePtr
 1792: xmlXPathNewCache(void)
 1793: {
 1794:     xmlXPathContextCachePtr ret;
 1795: 
 1796:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
 1797:     if (ret == NULL) {
 1798:         xmlXPathErrMemory(NULL, "creating object cache\n");
 1799: 	return(NULL);
 1800:     }
 1801:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
 1802:     ret->maxNodeset = 100;
 1803:     ret->maxString = 100;
 1804:     ret->maxBoolean = 100;
 1805:     ret->maxNumber = 100;
 1806:     ret->maxMisc = 100;
 1807:     return(ret);
 1808: }
 1809: 
 1810: static void
 1811: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
 1812: {
 1813:     int i;
 1814:     xmlXPathObjectPtr obj;
 1815: 
 1816:     if (list == NULL)
 1817: 	return;
 1818: 
 1819:     for (i = 0; i < list->number; i++) {
 1820: 	obj = list->items[i];
 1821: 	/*
 1822: 	* Note that it is already assured that we don't need to
 1823: 	* look out for namespace nodes in the node-set.
 1824: 	*/
 1825: 	if (obj->nodesetval != NULL) {
 1826: 	    if (obj->nodesetval->nodeTab != NULL)
 1827: 		xmlFree(obj->nodesetval->nodeTab);
 1828: 	    xmlFree(obj->nodesetval);
 1829: 	}
 1830: 	xmlFree(obj);
 1831: #ifdef XP_DEBUG_OBJ_USAGE
 1832: 	xmlXPathDebugObjCounterAll--;
 1833: #endif
 1834:     }
 1835:     xmlPointerListFree(list);
 1836: }
 1837: 
 1838: static void
 1839: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
 1840: {
 1841:     if (cache == NULL)
 1842: 	return;
 1843:     if (cache->nodesetObjs)
 1844: 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
 1845:     if (cache->stringObjs)
 1846: 	xmlXPathCacheFreeObjectList(cache->stringObjs);
 1847:     if (cache->booleanObjs)
 1848: 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
 1849:     if (cache->numberObjs)
 1850: 	xmlXPathCacheFreeObjectList(cache->numberObjs);
 1851:     if (cache->miscObjs)
 1852: 	xmlXPathCacheFreeObjectList(cache->miscObjs);
 1853:     xmlFree(cache);
 1854: }
 1855: 
 1856: /**
 1857:  * xmlXPathContextSetCache:
 1858:  *
 1859:  * @ctxt:  the XPath context
 1860:  * @active: enables/disables (creates/frees) the cache
 1861:  * @value: a value with semantics dependant on @options
 1862:  * @options: options (currently only the value 0 is used)
 1863:  *
 1864:  * Creates/frees an object cache on the XPath context.
 1865:  * If activates XPath objects (xmlXPathObject) will be cached internally
 1866:  * to be reused.
 1867:  * @options:
 1868:  *   0: This will set the XPath object caching:
 1869:  *      @value:
 1870:  *        This will set the maximum number of XPath objects
 1871:  *        to be cached per slot
 1872:  *        There are 5 slots for: node-set, string, number, boolean, and
 1873:  *        misc objects. Use <0 for the default number (100).
 1874:  *   Other values for @options have currently no effect.
 1875:  *
 1876:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
 1877:  */
 1878: int
 1879: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
 1880: 			int active,
 1881: 			int value,
 1882: 			int options)
 1883: {
 1884:     if (ctxt == NULL)
 1885: 	return(-1);
 1886:     if (active) {
 1887: 	xmlXPathContextCachePtr cache;
 1888: 
 1889: 	if (ctxt->cache == NULL) {
 1890: 	    ctxt->cache = xmlXPathNewCache();
 1891: 	    if (ctxt->cache == NULL)
 1892: 		return(-1);
 1893: 	}
 1894: 	cache = (xmlXPathContextCachePtr) ctxt->cache;
 1895: 	if (options == 0) {
 1896: 	    if (value < 0)
 1897: 		value = 100;
 1898: 	    cache->maxNodeset = value;
 1899: 	    cache->maxString = value;
 1900: 	    cache->maxNumber = value;
 1901: 	    cache->maxBoolean = value;
 1902: 	    cache->maxMisc = value;
 1903: 	}
 1904:     } else if (ctxt->cache != NULL) {
 1905: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 1906: 	ctxt->cache = NULL;
 1907:     }
 1908:     return(0);
 1909: }
 1910: 
 1911: /**
 1912:  * xmlXPathCacheWrapNodeSet:
 1913:  * @ctxt: the XPath context
 1914:  * @val:  the NodePtr value
 1915:  *
 1916:  * This is the cached version of xmlXPathWrapNodeSet().
 1917:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 1918:  *
 1919:  * Returns the created or reused object.
 1920:  */
 1921: static xmlXPathObjectPtr
 1922: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
 1923: {
 1924:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 1925: 	xmlXPathContextCachePtr cache =
 1926: 	    (xmlXPathContextCachePtr) ctxt->cache;
 1927: 
 1928: 	if ((cache->miscObjs != NULL) &&
 1929: 	    (cache->miscObjs->number != 0))
 1930: 	{
 1931: 	    xmlXPathObjectPtr ret;
 1932: 
 1933: 	    ret = (xmlXPathObjectPtr)
 1934: 		cache->miscObjs->items[--cache->miscObjs->number];
 1935: 	    ret->type = XPATH_NODESET;
 1936: 	    ret->nodesetval = val;
 1937: #ifdef XP_DEBUG_OBJ_USAGE
 1938: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 1939: #endif
 1940: 	    return(ret);
 1941: 	}
 1942:     }
 1943: 
 1944:     return(xmlXPathWrapNodeSet(val));
 1945: 
 1946: }
 1947: 
 1948: /**
 1949:  * xmlXPathCacheWrapString:
 1950:  * @ctxt: the XPath context
 1951:  * @val:  the xmlChar * value
 1952:  *
 1953:  * This is the cached version of xmlXPathWrapString().
 1954:  * Wraps the @val string into an XPath object.
 1955:  *
 1956:  * Returns the created or reused object.
 1957:  */
 1958: static xmlXPathObjectPtr
 1959: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
 1960: {
 1961:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
 1962: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 1963: 
 1964: 	if ((cache->stringObjs != NULL) &&
 1965: 	    (cache->stringObjs->number != 0))
 1966: 	{
 1967: 
 1968: 	    xmlXPathObjectPtr ret;
 1969: 
 1970: 	    ret = (xmlXPathObjectPtr)
 1971: 		cache->stringObjs->items[--cache->stringObjs->number];
 1972: 	    ret->type = XPATH_STRING;
 1973: 	    ret->stringval = val;
 1974: #ifdef XP_DEBUG_OBJ_USAGE
 1975: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 1976: #endif
 1977: 	    return(ret);
 1978: 	} else if ((cache->miscObjs != NULL) &&
 1979: 	    (cache->miscObjs->number != 0))
 1980: 	{
 1981: 	    xmlXPathObjectPtr ret;
 1982: 	    /*
 1983: 	    * Fallback to misc-cache.
 1984: 	    */
 1985: 	    ret = (xmlXPathObjectPtr)
 1986: 		cache->miscObjs->items[--cache->miscObjs->number];
 1987: 
 1988: 	    ret->type = XPATH_STRING;
 1989: 	    ret->stringval = val;
 1990: #ifdef XP_DEBUG_OBJ_USAGE
 1991: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 1992: #endif
 1993: 	    return(ret);
 1994: 	}
 1995:     }
 1996:     return(xmlXPathWrapString(val));
 1997: }
 1998: 
 1999: /**
 2000:  * xmlXPathCacheNewNodeSet:
 2001:  * @ctxt: the XPath context
 2002:  * @val:  the NodePtr value
 2003:  *
 2004:  * This is the cached version of xmlXPathNewNodeSet().
 2005:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
 2006:  * it with the single Node @val
 2007:  *
 2008:  * Returns the created or reused object.
 2009:  */
 2010: static xmlXPathObjectPtr
 2011: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
 2012: {
 2013:     if ((ctxt != NULL) && (ctxt->cache)) {
 2014: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2015: 
 2016: 	if ((cache->nodesetObjs != NULL) &&
 2017: 	    (cache->nodesetObjs->number != 0))
 2018: 	{
 2019: 	    xmlXPathObjectPtr ret;
 2020: 	    /*
 2021: 	    * Use the nodset-cache.
 2022: 	    */
 2023: 	    ret = (xmlXPathObjectPtr)
 2024: 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
 2025: 	    ret->type = XPATH_NODESET;
 2026: 	    ret->boolval = 0;
 2027: 	    if (val) {
 2028: 		if ((ret->nodesetval->nodeMax == 0) ||
 2029: 		    (val->type == XML_NAMESPACE_DECL))
 2030: 		{
 2031: 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
 2032: 		} else {
 2033: 		    ret->nodesetval->nodeTab[0] = val;
 2034: 		    ret->nodesetval->nodeNr = 1;
 2035: 		}
 2036: 	    }
 2037: #ifdef XP_DEBUG_OBJ_USAGE
 2038: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2039: #endif
 2040: 	    return(ret);
 2041: 	} else if ((cache->miscObjs != NULL) &&
 2042: 	    (cache->miscObjs->number != 0))
 2043: 	{
 2044: 	    xmlXPathObjectPtr ret;
 2045: 	    /*
 2046: 	    * Fallback to misc-cache.
 2047: 	    */
 2048: 
 2049: 	    ret = (xmlXPathObjectPtr)
 2050: 		cache->miscObjs->items[--cache->miscObjs->number];
 2051: 
 2052: 	    ret->type = XPATH_NODESET;
 2053: 	    ret->boolval = 0;
 2054: 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
 2055: #ifdef XP_DEBUG_OBJ_USAGE
 2056: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
 2057: #endif
 2058: 	    return(ret);
 2059: 	}
 2060:     }
 2061:     return(xmlXPathNewNodeSet(val));
 2062: }
 2063: 
 2064: /**
 2065:  * xmlXPathCacheNewCString:
 2066:  * @ctxt: the XPath context
 2067:  * @val:  the char * value
 2068:  *
 2069:  * This is the cached version of xmlXPathNewCString().
 2070:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2071:  *
 2072:  * Returns the created or reused object.
 2073:  */
 2074: static xmlXPathObjectPtr
 2075: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
 2076: {
 2077:     if ((ctxt != NULL) && (ctxt->cache)) {
 2078: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2079: 
 2080: 	if ((cache->stringObjs != NULL) &&
 2081: 	    (cache->stringObjs->number != 0))
 2082: 	{
 2083: 	    xmlXPathObjectPtr ret;
 2084: 
 2085: 	    ret = (xmlXPathObjectPtr)
 2086: 		cache->stringObjs->items[--cache->stringObjs->number];
 2087: 
 2088: 	    ret->type = XPATH_STRING;
 2089: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2090: #ifdef XP_DEBUG_OBJ_USAGE
 2091: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2092: #endif
 2093: 	    return(ret);
 2094: 	} else if ((cache->miscObjs != NULL) &&
 2095: 	    (cache->miscObjs->number != 0))
 2096: 	{
 2097: 	    xmlXPathObjectPtr ret;
 2098: 
 2099: 	    ret = (xmlXPathObjectPtr)
 2100: 		cache->miscObjs->items[--cache->miscObjs->number];
 2101: 
 2102: 	    ret->type = XPATH_STRING;
 2103: 	    ret->stringval = xmlStrdup(BAD_CAST val);
 2104: #ifdef XP_DEBUG_OBJ_USAGE
 2105: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2106: #endif
 2107: 	    return(ret);
 2108: 	}
 2109:     }
 2110:     return(xmlXPathNewCString(val));
 2111: }
 2112: 
 2113: /**
 2114:  * xmlXPathCacheNewString:
 2115:  * @ctxt: the XPath context
 2116:  * @val:  the xmlChar * value
 2117:  *
 2118:  * This is the cached version of xmlXPathNewString().
 2119:  * Acquire an xmlXPathObjectPtr of type string and of value @val
 2120:  *
 2121:  * Returns the created or reused object.
 2122:  */
 2123: static xmlXPathObjectPtr
 2124: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
 2125: {
 2126:     if ((ctxt != NULL) && (ctxt->cache)) {
 2127: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2128: 
 2129: 	if ((cache->stringObjs != NULL) &&
 2130: 	    (cache->stringObjs->number != 0))
 2131: 	{
 2132: 	    xmlXPathObjectPtr ret;
 2133: 
 2134: 	    ret = (xmlXPathObjectPtr)
 2135: 		cache->stringObjs->items[--cache->stringObjs->number];
 2136: 	    ret->type = XPATH_STRING;
 2137: 	    if (val != NULL)
 2138: 		ret->stringval = xmlStrdup(val);
 2139: 	    else
 2140: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2141: #ifdef XP_DEBUG_OBJ_USAGE
 2142: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2143: #endif
 2144: 	    return(ret);
 2145: 	} else if ((cache->miscObjs != NULL) &&
 2146: 	    (cache->miscObjs->number != 0))
 2147: 	{
 2148: 	    xmlXPathObjectPtr ret;
 2149: 
 2150: 	    ret = (xmlXPathObjectPtr)
 2151: 		cache->miscObjs->items[--cache->miscObjs->number];
 2152: 
 2153: 	    ret->type = XPATH_STRING;
 2154: 	    if (val != NULL)
 2155: 		ret->stringval = xmlStrdup(val);
 2156: 	    else
 2157: 		ret->stringval = xmlStrdup((const xmlChar *)"");
 2158: #ifdef XP_DEBUG_OBJ_USAGE
 2159: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
 2160: #endif
 2161: 	    return(ret);
 2162: 	}
 2163:     }
 2164:     return(xmlXPathNewString(val));
 2165: }
 2166: 
 2167: /**
 2168:  * xmlXPathCacheNewBoolean:
 2169:  * @ctxt: the XPath context
 2170:  * @val:  the boolean value
 2171:  *
 2172:  * This is the cached version of xmlXPathNewBoolean().
 2173:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
 2174:  *
 2175:  * Returns the created or reused object.
 2176:  */
 2177: static xmlXPathObjectPtr
 2178: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
 2179: {
 2180:     if ((ctxt != NULL) && (ctxt->cache)) {
 2181: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2182: 
 2183: 	if ((cache->booleanObjs != NULL) &&
 2184: 	    (cache->booleanObjs->number != 0))
 2185: 	{
 2186: 	    xmlXPathObjectPtr ret;
 2187: 
 2188: 	    ret = (xmlXPathObjectPtr)
 2189: 		cache->booleanObjs->items[--cache->booleanObjs->number];
 2190: 	    ret->type = XPATH_BOOLEAN;
 2191: 	    ret->boolval = (val != 0);
 2192: #ifdef XP_DEBUG_OBJ_USAGE
 2193: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2194: #endif
 2195: 	    return(ret);
 2196: 	} else if ((cache->miscObjs != NULL) &&
 2197: 	    (cache->miscObjs->number != 0))
 2198: 	{
 2199: 	    xmlXPathObjectPtr ret;
 2200: 
 2201: 	    ret = (xmlXPathObjectPtr)
 2202: 		cache->miscObjs->items[--cache->miscObjs->number];
 2203: 
 2204: 	    ret->type = XPATH_BOOLEAN;
 2205: 	    ret->boolval = (val != 0);
 2206: #ifdef XP_DEBUG_OBJ_USAGE
 2207: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
 2208: #endif
 2209: 	    return(ret);
 2210: 	}
 2211:     }
 2212:     return(xmlXPathNewBoolean(val));
 2213: }
 2214: 
 2215: /**
 2216:  * xmlXPathCacheNewFloat:
 2217:  * @ctxt: the XPath context
 2218:  * @val:  the double value
 2219:  *
 2220:  * This is the cached version of xmlXPathNewFloat().
 2221:  * Acquires an xmlXPathObjectPtr of type double and of value @val
 2222:  *
 2223:  * Returns the created or reused object.
 2224:  */
 2225: static xmlXPathObjectPtr
 2226: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
 2227: {
 2228:      if ((ctxt != NULL) && (ctxt->cache)) {
 2229: 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
 2230: 
 2231: 	if ((cache->numberObjs != NULL) &&
 2232: 	    (cache->numberObjs->number != 0))
 2233: 	{
 2234: 	    xmlXPathObjectPtr ret;
 2235: 
 2236: 	    ret = (xmlXPathObjectPtr)
 2237: 		cache->numberObjs->items[--cache->numberObjs->number];
 2238: 	    ret->type = XPATH_NUMBER;
 2239: 	    ret->floatval = val;
 2240: #ifdef XP_DEBUG_OBJ_USAGE
 2241: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2242: #endif
 2243: 	    return(ret);
 2244: 	} else if ((cache->miscObjs != NULL) &&
 2245: 	    (cache->miscObjs->number != 0))
 2246: 	{
 2247: 	    xmlXPathObjectPtr ret;
 2248: 
 2249: 	    ret = (xmlXPathObjectPtr)
 2250: 		cache->miscObjs->items[--cache->miscObjs->number];
 2251: 
 2252: 	    ret->type = XPATH_NUMBER;
 2253: 	    ret->floatval = val;
 2254: #ifdef XP_DEBUG_OBJ_USAGE
 2255: 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
 2256: #endif
 2257: 	    return(ret);
 2258: 	}
 2259:     }
 2260:     return(xmlXPathNewFloat(val));
 2261: }
 2262: 
 2263: /**
 2264:  * xmlXPathCacheConvertString:
 2265:  * @ctxt: the XPath context
 2266:  * @val:  an XPath object
 2267:  *
 2268:  * This is the cached version of xmlXPathConvertString().
 2269:  * Converts an existing object to its string() equivalent
 2270:  *
 2271:  * Returns a created or reused object, the old one is freed (cached)
 2272:  *         (or the operation is done directly on @val)
 2273:  */
 2274: 
 2275: static xmlXPathObjectPtr
 2276: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2277:     xmlChar *res = NULL;
 2278: 
 2279:     if (val == NULL)
 2280: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2281: 
 2282:     switch (val->type) {
 2283:     case XPATH_UNDEFINED:
 2284: #ifdef DEBUG_EXPR
 2285: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 2286: #endif
 2287: 	break;
 2288:     case XPATH_NODESET:
 2289:     case XPATH_XSLT_TREE:
 2290: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 2291: 	break;
 2292:     case XPATH_STRING:
 2293: 	return(val);
 2294:     case XPATH_BOOLEAN:
 2295: 	res = xmlXPathCastBooleanToString(val->boolval);
 2296: 	break;
 2297:     case XPATH_NUMBER:
 2298: 	res = xmlXPathCastNumberToString(val->floatval);
 2299: 	break;
 2300:     case XPATH_USERS:
 2301:     case XPATH_POINT:
 2302:     case XPATH_RANGE:
 2303:     case XPATH_LOCATIONSET:
 2304: 	TODO;
 2305: 	break;
 2306:     }
 2307:     xmlXPathReleaseObject(ctxt, val);
 2308:     if (res == NULL)
 2309: 	return(xmlXPathCacheNewCString(ctxt, ""));
 2310:     return(xmlXPathCacheWrapString(ctxt, res));
 2311: }
 2312: 
 2313: /**
 2314:  * xmlXPathCacheObjectCopy:
 2315:  * @ctxt: the XPath context
 2316:  * @val:  the original object
 2317:  *
 2318:  * This is the cached version of xmlXPathObjectCopy().
 2319:  * Acquire a copy of a given object
 2320:  *
 2321:  * Returns a created or reused created object.
 2322:  */
 2323: static xmlXPathObjectPtr
 2324: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
 2325: {
 2326:     if (val == NULL)
 2327: 	return(NULL);
 2328: 
 2329:     if (XP_HAS_CACHE(ctxt)) {
 2330: 	switch (val->type) {
 2331: 	    case XPATH_NODESET:
 2332: 		return(xmlXPathCacheWrapNodeSet(ctxt,
 2333: 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
 2334: 	    case XPATH_STRING:
 2335: 		return(xmlXPathCacheNewString(ctxt, val->stringval));
 2336: 	    case XPATH_BOOLEAN:
 2337: 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
 2338: 	    case XPATH_NUMBER:
 2339: 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
 2340: 	    default:
 2341: 		break;
 2342: 	}
 2343:     }
 2344:     return(xmlXPathObjectCopy(val));
 2345: }
 2346: 
 2347: /**
 2348:  * xmlXPathCacheConvertBoolean:
 2349:  * @ctxt: the XPath context
 2350:  * @val:  an XPath object
 2351:  *
 2352:  * This is the cached version of xmlXPathConvertBoolean().
 2353:  * Converts an existing object to its boolean() equivalent
 2354:  *
 2355:  * Returns a created or reused object, the old one is freed (or the operation
 2356:  *         is done directly on @val)
 2357:  */
 2358: static xmlXPathObjectPtr
 2359: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2360:     xmlXPathObjectPtr ret;
 2361: 
 2362:     if (val == NULL)
 2363: 	return(xmlXPathCacheNewBoolean(ctxt, 0));
 2364:     if (val->type == XPATH_BOOLEAN)
 2365: 	return(val);
 2366:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
 2367:     xmlXPathReleaseObject(ctxt, val);
 2368:     return(ret);
 2369: }
 2370: 
 2371: /**
 2372:  * xmlXPathCacheConvertNumber:
 2373:  * @ctxt: the XPath context
 2374:  * @val:  an XPath object
 2375:  *
 2376:  * This is the cached version of xmlXPathConvertNumber().
 2377:  * Converts an existing object to its number() equivalent
 2378:  *
 2379:  * Returns a created or reused object, the old one is freed (or the operation
 2380:  *         is done directly on @val)
 2381:  */
 2382: static xmlXPathObjectPtr
 2383: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
 2384:     xmlXPathObjectPtr ret;
 2385: 
 2386:     if (val == NULL)
 2387: 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
 2388:     if (val->type == XPATH_NUMBER)
 2389: 	return(val);
 2390:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
 2391:     xmlXPathReleaseObject(ctxt, val);
 2392:     return(ret);
 2393: }
 2394: 
 2395: /************************************************************************
 2396:  *									*
 2397:  *		Parser stacks related functions and macros		*
 2398:  *									*
 2399:  ************************************************************************/
 2400: 
 2401: /**
 2402:  * xmlXPathSetFrame:
 2403:  * @ctxt: an XPath parser context
 2404:  *
 2405:  * Set the callee evaluation frame
 2406:  *
 2407:  * Returns the previous frame value to be restored once done
 2408:  */
 2409: static int
 2410: xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
 2411:     int ret;
 2412: 
 2413:     if (ctxt == NULL)
 2414:         return(0);
 2415:     ret = ctxt->valueFrame;
 2416:     ctxt->valueFrame = ctxt->valueNr;
 2417:     return(ret);
 2418: }
 2419: 
 2420: /**
 2421:  * xmlXPathPopFrame:
 2422:  * @ctxt: an XPath parser context
 2423:  * @frame: the previous frame value
 2424:  *
 2425:  * Remove the callee evaluation frame
 2426:  */
 2427: static void
 2428: xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
 2429:     if (ctxt == NULL)
 2430:         return;
 2431:     if (ctxt->valueNr < ctxt->valueFrame) {
 2432:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
 2433:     }
 2434:     ctxt->valueFrame = frame;
 2435: }
 2436: 
 2437: /**
 2438:  * valuePop:
 2439:  * @ctxt: an XPath evaluation context
 2440:  *
 2441:  * Pops the top XPath object from the value stack
 2442:  *
 2443:  * Returns the XPath object just removed
 2444:  */
 2445: xmlXPathObjectPtr
 2446: valuePop(xmlXPathParserContextPtr ctxt)
 2447: {
 2448:     xmlXPathObjectPtr ret;
 2449: 
 2450:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
 2451:         return (NULL);
 2452: 
 2453:     if (ctxt->valueNr <= ctxt->valueFrame) {
 2454:         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
 2455:         return (NULL);
 2456:     }
 2457: 
 2458:     ctxt->valueNr--;
 2459:     if (ctxt->valueNr > 0)
 2460:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
 2461:     else
 2462:         ctxt->value = NULL;
 2463:     ret = ctxt->valueTab[ctxt->valueNr];
 2464:     ctxt->valueTab[ctxt->valueNr] = NULL;
 2465:     return (ret);
 2466: }
 2467: /**
 2468:  * valuePush:
 2469:  * @ctxt:  an XPath evaluation context
 2470:  * @value:  the XPath object
 2471:  *
 2472:  * Pushes a new XPath object on top of the value stack
 2473:  *
 2474:  * returns the number of items on the value stack
 2475:  */
 2476: int
 2477: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
 2478: {
 2479:     if ((ctxt == NULL) || (value == NULL)) return(-1);
 2480:     if (ctxt->valueNr >= ctxt->valueMax) {
 2481:         xmlXPathObjectPtr *tmp;
 2482: 
 2483:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
 2484:                                              2 * ctxt->valueMax *
 2485:                                              sizeof(ctxt->valueTab[0]));
 2486:         if (tmp == NULL) {
 2487:             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
 2488:             ctxt->error = XPATH_MEMORY_ERROR;
 2489:             return (0);
 2490:         }
 2491:         ctxt->valueMax *= 2;
 2492: 	ctxt->valueTab = tmp;
 2493:     }
 2494:     ctxt->valueTab[ctxt->valueNr] = value;
 2495:     ctxt->value = value;
 2496:     return (ctxt->valueNr++);
 2497: }
 2498: 
 2499: /**
 2500:  * xmlXPathPopBoolean:
 2501:  * @ctxt:  an XPath parser context
 2502:  *
 2503:  * Pops a boolean from the stack, handling conversion if needed.
 2504:  * Check error with #xmlXPathCheckError.
 2505:  *
 2506:  * Returns the boolean
 2507:  */
 2508: int
 2509: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
 2510:     xmlXPathObjectPtr obj;
 2511:     int ret;
 2512: 
 2513:     obj = valuePop(ctxt);
 2514:     if (obj == NULL) {
 2515: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2516: 	return(0);
 2517:     }
 2518:     if (obj->type != XPATH_BOOLEAN)
 2519: 	ret = xmlXPathCastToBoolean(obj);
 2520:     else
 2521:         ret = obj->boolval;
 2522:     xmlXPathReleaseObject(ctxt->context, obj);
 2523:     return(ret);
 2524: }
 2525: 
 2526: /**
 2527:  * xmlXPathPopNumber:
 2528:  * @ctxt:  an XPath parser context
 2529:  *
 2530:  * Pops a number from the stack, handling conversion if needed.
 2531:  * Check error with #xmlXPathCheckError.
 2532:  *
 2533:  * Returns the number
 2534:  */
 2535: double
 2536: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
 2537:     xmlXPathObjectPtr obj;
 2538:     double ret;
 2539: 
 2540:     obj = valuePop(ctxt);
 2541:     if (obj == NULL) {
 2542: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2543: 	return(0);
 2544:     }
 2545:     if (obj->type != XPATH_NUMBER)
 2546: 	ret = xmlXPathCastToNumber(obj);
 2547:     else
 2548:         ret = obj->floatval;
 2549:     xmlXPathReleaseObject(ctxt->context, obj);
 2550:     return(ret);
 2551: }
 2552: 
 2553: /**
 2554:  * xmlXPathPopString:
 2555:  * @ctxt:  an XPath parser context
 2556:  *
 2557:  * Pops a string from the stack, handling conversion if needed.
 2558:  * Check error with #xmlXPathCheckError.
 2559:  *
 2560:  * Returns the string
 2561:  */
 2562: xmlChar *
 2563: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
 2564:     xmlXPathObjectPtr obj;
 2565:     xmlChar * ret;
 2566: 
 2567:     obj = valuePop(ctxt);
 2568:     if (obj == NULL) {
 2569: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2570: 	return(NULL);
 2571:     }
 2572:     ret = xmlXPathCastToString(obj);	/* this does required strdup */
 2573:     /* TODO: needs refactoring somewhere else */
 2574:     if (obj->stringval == ret)
 2575: 	obj->stringval = NULL;
 2576:     xmlXPathReleaseObject(ctxt->context, obj);
 2577:     return(ret);
 2578: }
 2579: 
 2580: /**
 2581:  * xmlXPathPopNodeSet:
 2582:  * @ctxt:  an XPath parser context
 2583:  *
 2584:  * Pops a node-set from the stack, handling conversion if needed.
 2585:  * Check error with #xmlXPathCheckError.
 2586:  *
 2587:  * Returns the node-set
 2588:  */
 2589: xmlNodeSetPtr
 2590: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
 2591:     xmlXPathObjectPtr obj;
 2592:     xmlNodeSetPtr ret;
 2593: 
 2594:     if (ctxt == NULL) return(NULL);
 2595:     if (ctxt->value == NULL) {
 2596: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2597: 	return(NULL);
 2598:     }
 2599:     if (!xmlXPathStackIsNodeSet(ctxt)) {
 2600: 	xmlXPathSetTypeError(ctxt);
 2601: 	return(NULL);
 2602:     }
 2603:     obj = valuePop(ctxt);
 2604:     ret = obj->nodesetval;
 2605: #if 0
 2606:     /* to fix memory leak of not clearing obj->user */
 2607:     if (obj->boolval && obj->user != NULL)
 2608:         xmlFreeNodeList((xmlNodePtr) obj->user);
 2609: #endif
 2610:     obj->nodesetval = NULL;
 2611:     xmlXPathReleaseObject(ctxt->context, obj);
 2612:     return(ret);
 2613: }
 2614: 
 2615: /**
 2616:  * xmlXPathPopExternal:
 2617:  * @ctxt:  an XPath parser context
 2618:  *
 2619:  * Pops an external object from the stack, handling conversion if needed.
 2620:  * Check error with #xmlXPathCheckError.
 2621:  *
 2622:  * Returns the object
 2623:  */
 2624: void *
 2625: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
 2626:     xmlXPathObjectPtr obj;
 2627:     void * ret;
 2628: 
 2629:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
 2630: 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
 2631: 	return(NULL);
 2632:     }
 2633:     if (ctxt->value->type != XPATH_USERS) {
 2634: 	xmlXPathSetTypeError(ctxt);
 2635: 	return(NULL);
 2636:     }
 2637:     obj = valuePop(ctxt);
 2638:     ret = obj->user;
 2639:     obj->user = NULL;
 2640:     xmlXPathReleaseObject(ctxt->context, obj);
 2641:     return(ret);
 2642: }
 2643: 
 2644: /*
 2645:  * Macros for accessing the content. Those should be used only by the parser,
 2646:  * and not exported.
 2647:  *
 2648:  * Dirty macros, i.e. one need to make assumption on the context to use them
 2649:  *
 2650:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
 2651:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
 2652:  *           in ISO-Latin or UTF-8.
 2653:  *           This should be used internally by the parser
 2654:  *           only to compare to ASCII values otherwise it would break when
 2655:  *           running with UTF-8 encoding.
 2656:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
 2657:  *           to compare on ASCII based substring.
 2658:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
 2659:  *           strings within the parser.
 2660:  *   CURRENT Returns the current char value, with the full decoding of
 2661:  *           UTF-8 if we are using this mode. It returns an int.
 2662:  *   NEXT    Skip to the next character, this does the proper decoding
 2663:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
 2664:  *           It returns the pointer to the current xmlChar.
 2665:  */
 2666: 
 2667: #define CUR (*ctxt->cur)
 2668: #define SKIP(val) ctxt->cur += (val)
 2669: #define NXT(val) ctxt->cur[(val)]
 2670: #define CUR_PTR ctxt->cur
 2671: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
 2672: 
 2673: #define COPY_BUF(l,b,i,v)                                              \
 2674:     if (l == 1) b[i++] = (xmlChar) v;                                  \
 2675:     else i += xmlCopyChar(l,&b[i],v)
 2676: 
 2677: #define NEXTL(l)  ctxt->cur += l
 2678: 
 2679: #define SKIP_BLANKS							\
 2680:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
 2681: 
 2682: #define CURRENT (*ctxt->cur)
 2683: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
 2684: 
 2685: 
 2686: #ifndef DBL_DIG
 2687: #define DBL_DIG 16
 2688: #endif
 2689: #ifndef DBL_EPSILON
 2690: #define DBL_EPSILON 1E-9
 2691: #endif
 2692: 
 2693: #define UPPER_DOUBLE 1E9
 2694: #define LOWER_DOUBLE 1E-5
 2695: #define	LOWER_DOUBLE_EXP 5
 2696: 
 2697: #define INTEGER_DIGITS DBL_DIG
 2698: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
 2699: #define EXPONENT_DIGITS (3 + 2)
 2700: 
 2701: /**
 2702:  * xmlXPathFormatNumber:
 2703:  * @number:     number to format
 2704:  * @buffer:     output buffer
 2705:  * @buffersize: size of output buffer
 2706:  *
 2707:  * Convert the number into a string representation.
 2708:  */
 2709: static void
 2710: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
 2711: {
 2712:     switch (xmlXPathIsInf(number)) {
 2713:     case 1:
 2714: 	if (buffersize > (int)sizeof("Infinity"))
 2715: 	    snprintf(buffer, buffersize, "Infinity");
 2716: 	break;
 2717:     case -1:
 2718: 	if (buffersize > (int)sizeof("-Infinity"))
 2719: 	    snprintf(buffer, buffersize, "-Infinity");
 2720: 	break;
 2721:     default:
 2722: 	if (xmlXPathIsNaN(number)) {
 2723: 	    if (buffersize > (int)sizeof("NaN"))
 2724: 		snprintf(buffer, buffersize, "NaN");
 2725: 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
 2726: 	    snprintf(buffer, buffersize, "0");
 2727: 	} else if (number == ((int) number)) {
 2728: 	    char work[30];
 2729: 	    char *ptr, *cur;
 2730: 	    int value = (int) number;
 2731: 
 2732:             ptr = &buffer[0];
 2733: 	    if (value == 0) {
 2734: 		*ptr++ = '0';
 2735: 	    } else {
 2736: 		snprintf(work, 29, "%d", value);
 2737: 		cur = &work[0];
 2738: 		while ((*cur) && (ptr - buffer < buffersize)) {
 2739: 		    *ptr++ = *cur++;
 2740: 		}
 2741: 	    }
 2742: 	    if (ptr - buffer < buffersize) {
 2743: 		*ptr = 0;
 2744: 	    } else if (buffersize > 0) {
 2745: 		ptr--;
 2746: 		*ptr = 0;
 2747: 	    }
 2748: 	} else {
 2749: 	    /*
 2750: 	      For the dimension of work,
 2751: 	          DBL_DIG is number of significant digits
 2752: 		  EXPONENT is only needed for "scientific notation"
 2753: 	          3 is sign, decimal point, and terminating zero
 2754: 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
 2755: 	      Note that this dimension is slightly (a few characters)
 2756: 	      larger than actually necessary.
 2757: 	    */
 2758: 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
 2759: 	    int integer_place, fraction_place;
 2760: 	    char *ptr;
 2761: 	    char *after_fraction;
 2762: 	    double absolute_value;
 2763: 	    int size;
 2764: 
 2765: 	    absolute_value = fabs(number);
 2766: 
 2767: 	    /*
 2768: 	     * First choose format - scientific or regular floating point.
 2769: 	     * In either case, result is in work, and after_fraction points
 2770: 	     * just past the fractional part.
 2771: 	    */
 2772: 	    if ( ((absolute_value > UPPER_DOUBLE) ||
 2773: 		  (absolute_value < LOWER_DOUBLE)) &&
 2774: 		 (absolute_value != 0.0) ) {
 2775: 		/* Use scientific notation */
 2776: 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
 2777: 		fraction_place = DBL_DIG - 1;
 2778: 		size = snprintf(work, sizeof(work),"%*.*e",
 2779: 			 integer_place, fraction_place, number);
 2780: 		while ((size > 0) && (work[size] != 'e')) size--;
 2781: 
 2782: 	    }
 2783: 	    else {
 2784: 		/* Use regular notation */
 2785: 		if (absolute_value > 0.0) {
 2786: 		    integer_place = (int)log10(absolute_value);
 2787: 		    if (integer_place > 0)
 2788: 		        fraction_place = DBL_DIG - integer_place - 1;
 2789: 		    else
 2790: 		        fraction_place = DBL_DIG - integer_place;
 2791: 		} else {
 2792: 		    fraction_place = 1;
 2793: 		}
 2794: 		size = snprintf(work, sizeof(work), "%0.*f",
 2795: 				fraction_place, number);
 2796: 	    }
 2797: 
 2798: 	    /* Remove fractional trailing zeroes */
 2799: 	    after_fraction = work + size;
 2800: 	    ptr = after_fraction;
 2801: 	    while (*(--ptr) == '0')
 2802: 		;
 2803: 	    if (*ptr != '.')
 2804: 	        ptr++;
 2805: 	    while ((*ptr++ = *after_fraction++) != 0);
 2806: 
 2807: 	    /* Finally copy result back to caller */
 2808: 	    size = strlen(work) + 1;
 2809: 	    if (size > buffersize) {
 2810: 		work[buffersize - 1] = 0;
 2811: 		size = buffersize;
 2812: 	    }
 2813: 	    memmove(buffer, work, size);
 2814: 	}
 2815: 	break;
 2816:     }
 2817: }
 2818: 
 2819: 
 2820: /************************************************************************
 2821:  *									*
 2822:  *			Routines to handle NodeSets			*
 2823:  *									*
 2824:  ************************************************************************/
 2825: 
 2826: /**
 2827:  * xmlXPathOrderDocElems:
 2828:  * @doc:  an input document
 2829:  *
 2830:  * Call this routine to speed up XPath computation on static documents.
 2831:  * This stamps all the element nodes with the document order
 2832:  * Like for line information, the order is kept in the element->content
 2833:  * field, the value stored is actually - the node number (starting at -1)
 2834:  * to be able to differentiate from line numbers.
 2835:  *
 2836:  * Returns the number of elements found in the document or -1 in case
 2837:  *    of error.
 2838:  */
 2839: long
 2840: xmlXPathOrderDocElems(xmlDocPtr doc) {
 2841:     long count = 0;
 2842:     xmlNodePtr cur;
 2843: 
 2844:     if (doc == NULL)
 2845: 	return(-1);
 2846:     cur = doc->children;
 2847:     while (cur != NULL) {
 2848: 	if (cur->type == XML_ELEMENT_NODE) {
 2849: 	    cur->content = (void *) (-(++count));
 2850: 	    if (cur->children != NULL) {
 2851: 		cur = cur->children;
 2852: 		continue;
 2853: 	    }
 2854: 	}
 2855: 	if (cur->next != NULL) {
 2856: 	    cur = cur->next;
 2857: 	    continue;
 2858: 	}
 2859: 	do {
 2860: 	    cur = cur->parent;
 2861: 	    if (cur == NULL)
 2862: 		break;
 2863: 	    if (cur == (xmlNodePtr) doc) {
 2864: 		cur = NULL;
 2865: 		break;
 2866: 	    }
 2867: 	    if (cur->next != NULL) {
 2868: 		cur = cur->next;
 2869: 		break;
 2870: 	    }
 2871: 	} while (cur != NULL);
 2872:     }
 2873:     return(count);
 2874: }
 2875: 
 2876: /**
 2877:  * xmlXPathCmpNodes:
 2878:  * @node1:  the first node
 2879:  * @node2:  the second node
 2880:  *
 2881:  * Compare two nodes w.r.t document order
 2882:  *
 2883:  * Returns -2 in case of error 1 if first point < second point, 0 if
 2884:  *         it's the same node, -1 otherwise
 2885:  */
 2886: int
 2887: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
 2888:     int depth1, depth2;
 2889:     int attr1 = 0, attr2 = 0;
 2890:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
 2891:     xmlNodePtr cur, root;
 2892: 
 2893:     if ((node1 == NULL) || (node2 == NULL))
 2894: 	return(-2);
 2895:     /*
 2896:      * a couple of optimizations which will avoid computations in most cases
 2897:      */
 2898:     if (node1 == node2)		/* trivial case */
 2899: 	return(0);
 2900:     if (node1->type == XML_ATTRIBUTE_NODE) {
 2901: 	attr1 = 1;
 2902: 	attrNode1 = node1;
 2903: 	node1 = node1->parent;
 2904:     }
 2905:     if (node2->type == XML_ATTRIBUTE_NODE) {
 2906: 	attr2 = 1;
 2907: 	attrNode2 = node2;
 2908: 	node2 = node2->parent;
 2909:     }
 2910:     if (node1 == node2) {
 2911: 	if (attr1 == attr2) {
 2912: 	    /* not required, but we keep attributes in order */
 2913: 	    if (attr1 != 0) {
 2914: 	        cur = attrNode2->prev;
 2915: 		while (cur != NULL) {
 2916: 		    if (cur == attrNode1)
 2917: 		        return (1);
 2918: 		    cur = cur->prev;
 2919: 		}
 2920: 		return (-1);
 2921: 	    }
 2922: 	    return(0);
 2923: 	}
 2924: 	if (attr2 == 1)
 2925: 	    return(1);
 2926: 	return(-1);
 2927:     }
 2928:     if ((node1->type == XML_NAMESPACE_DECL) ||
 2929:         (node2->type == XML_NAMESPACE_DECL))
 2930: 	return(1);
 2931:     if (node1 == node2->prev)
 2932: 	return(1);
 2933:     if (node1 == node2->next)
 2934: 	return(-1);
 2935: 
 2936:     /*
 2937:      * Speedup using document order if availble.
 2938:      */
 2939:     if ((node1->type == XML_ELEMENT_NODE) &&
 2940: 	(node2->type == XML_ELEMENT_NODE) &&
 2941: 	(0 > (long) node1->content) &&
 2942: 	(0 > (long) node2->content) &&
 2943: 	(node1->doc == node2->doc)) {
 2944: 	long l1, l2;
 2945: 
 2946: 	l1 = -((long) node1->content);
 2947: 	l2 = -((long) node2->content);
 2948: 	if (l1 < l2)
 2949: 	    return(1);
 2950: 	if (l1 > l2)
 2951: 	    return(-1);
 2952:     }
 2953: 
 2954:     /*
 2955:      * compute depth to root
 2956:      */
 2957:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 2958: 	if (cur == node1)
 2959: 	    return(1);
 2960: 	depth2++;
 2961:     }
 2962:     root = cur;
 2963:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 2964: 	if (cur == node2)
 2965: 	    return(-1);
 2966: 	depth1++;
 2967:     }
 2968:     /*
 2969:      * Distinct document (or distinct entities :-( ) case.
 2970:      */
 2971:     if (root != cur) {
 2972: 	return(-2);
 2973:     }
 2974:     /*
 2975:      * get the nearest common ancestor.
 2976:      */
 2977:     while (depth1 > depth2) {
 2978: 	depth1--;
 2979: 	node1 = node1->parent;
 2980:     }
 2981:     while (depth2 > depth1) {
 2982: 	depth2--;
 2983: 	node2 = node2->parent;
 2984:     }
 2985:     while (node1->parent != node2->parent) {
 2986: 	node1 = node1->parent;
 2987: 	node2 = node2->parent;
 2988: 	/* should not happen but just in case ... */
 2989: 	if ((node1 == NULL) || (node2 == NULL))
 2990: 	    return(-2);
 2991:     }
 2992:     /*
 2993:      * Find who's first.
 2994:      */
 2995:     if (node1 == node2->prev)
 2996: 	return(1);
 2997:     if (node1 == node2->next)
 2998: 	return(-1);
 2999:     /*
 3000:      * Speedup using document order if availble.
 3001:      */
 3002:     if ((node1->type == XML_ELEMENT_NODE) &&
 3003: 	(node2->type == XML_ELEMENT_NODE) &&
 3004: 	(0 > (long) node1->content) &&
 3005: 	(0 > (long) node2->content) &&
 3006: 	(node1->doc == node2->doc)) {
 3007: 	long l1, l2;
 3008: 
 3009: 	l1 = -((long) node1->content);
 3010: 	l2 = -((long) node2->content);
 3011: 	if (l1 < l2)
 3012: 	    return(1);
 3013: 	if (l1 > l2)
 3014: 	    return(-1);
 3015:     }
 3016: 
 3017:     for (cur = node1->next;cur != NULL;cur = cur->next)
 3018: 	if (cur == node2)
 3019: 	    return(1);
 3020:     return(-1); /* assume there is no sibling list corruption */
 3021: }
 3022: 
 3023: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 3024: /**
 3025:  * xmlXPathCmpNodesExt:
 3026:  * @node1:  the first node
 3027:  * @node2:  the second node
 3028:  *
 3029:  * Compare two nodes w.r.t document order.
 3030:  * This one is optimized for handling of non-element nodes.
 3031:  *
 3032:  * Returns -2 in case of error 1 if first point < second point, 0 if
 3033:  *         it's the same node, -1 otherwise
 3034:  */
 3035: static int
 3036: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 3037:     int depth1, depth2;
 3038:     int misc = 0, precedence1 = 0, precedence2 = 0;
 3039:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
 3040:     xmlNodePtr cur, root;
 3041:     long l1, l2;
 3042: 
 3043:     if ((node1 == NULL) || (node2 == NULL))
 3044: 	return(-2);
 3045: 
 3046:     if (node1 == node2)
 3047: 	return(0);
 3048: 
 3049:     /*
 3050:      * a couple of optimizations which will avoid computations in most cases
 3051:      */
 3052:     switch (node1->type) {
 3053: 	case XML_ELEMENT_NODE:
 3054: 	    if (node2->type == XML_ELEMENT_NODE) {
 3055: 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
 3056: 		    (0 > (long) node2->content) &&
 3057: 		    (node1->doc == node2->doc))
 3058: 		{
 3059: 		    l1 = -((long) node1->content);
 3060: 		    l2 = -((long) node2->content);
 3061: 		    if (l1 < l2)
 3062: 			return(1);
 3063: 		    if (l1 > l2)
 3064: 			return(-1);
 3065: 		} else
 3066: 		    goto turtle_comparison;
 3067: 	    }
 3068: 	    break;
 3069: 	case XML_ATTRIBUTE_NODE:
 3070: 	    precedence1 = 1; /* element is owner */
 3071: 	    miscNode1 = node1;
 3072: 	    node1 = node1->parent;
 3073: 	    misc = 1;
 3074: 	    break;
 3075: 	case XML_TEXT_NODE:
 3076: 	case XML_CDATA_SECTION_NODE:
 3077: 	case XML_COMMENT_NODE:
 3078: 	case XML_PI_NODE: {
 3079: 	    miscNode1 = node1;
 3080: 	    /*
 3081: 	    * Find nearest element node.
 3082: 	    */
 3083: 	    if (node1->prev != NULL) {
 3084: 		do {
 3085: 		    node1 = node1->prev;
 3086: 		    if (node1->type == XML_ELEMENT_NODE) {
 3087: 			precedence1 = 3; /* element in prev-sibl axis */
 3088: 			break;
 3089: 		    }
 3090: 		    if (node1->prev == NULL) {
 3091: 			precedence1 = 2; /* element is parent */
 3092: 			/*
 3093: 			* URGENT TODO: Are there any cases, where the
 3094: 			* parent of such a node is not an element node?
 3095: 			*/
 3096: 			node1 = node1->parent;
 3097: 			break;
 3098: 		    }
 3099: 		} while (1);
 3100: 	    } else {
 3101: 		precedence1 = 2; /* element is parent */
 3102: 		node1 = node1->parent;
 3103: 	    }
 3104: 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
 3105: 		(0 <= (long) node1->content)) {
 3106: 		/*
 3107: 		* Fallback for whatever case.
 3108: 		*/
 3109: 		node1 = miscNode1;
 3110: 		precedence1 = 0;
 3111: 	    } else
 3112: 		misc = 1;
 3113: 	}
 3114: 	    break;
 3115: 	case XML_NAMESPACE_DECL:
 3116: 	    /*
 3117: 	    * TODO: why do we return 1 for namespace nodes?
 3118: 	    */
 3119: 	    return(1);
 3120: 	default:
 3121: 	    break;
 3122:     }
 3123:     switch (node2->type) {
 3124: 	case XML_ELEMENT_NODE:
 3125: 	    break;
 3126: 	case XML_ATTRIBUTE_NODE:
 3127: 	    precedence2 = 1; /* element is owner */
 3128: 	    miscNode2 = node2;
 3129: 	    node2 = node2->parent;
 3130: 	    misc = 1;
 3131: 	    break;
 3132: 	case XML_TEXT_NODE:
 3133: 	case XML_CDATA_SECTION_NODE:
 3134: 	case XML_COMMENT_NODE:
 3135: 	case XML_PI_NODE: {
 3136: 	    miscNode2 = node2;
 3137: 	    if (node2->prev != NULL) {
 3138: 		do {
 3139: 		    node2 = node2->prev;
 3140: 		    if (node2->type == XML_ELEMENT_NODE) {
 3141: 			precedence2 = 3; /* element in prev-sibl axis */
 3142: 			break;
 3143: 		    }
 3144: 		    if (node2->prev == NULL) {
 3145: 			precedence2 = 2; /* element is parent */
 3146: 			node2 = node2->parent;
 3147: 			break;
 3148: 		    }
 3149: 		} while (1);
 3150: 	    } else {
 3151: 		precedence2 = 2; /* element is parent */
 3152: 		node2 = node2->parent;
 3153: 	    }
 3154: 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
 3155: 		(0 <= (long) node1->content))
 3156: 	    {
 3157: 		node2 = miscNode2;
 3158: 		precedence2 = 0;
 3159: 	    } else
 3160: 		misc = 1;
 3161: 	}
 3162: 	    break;
 3163: 	case XML_NAMESPACE_DECL:
 3164: 	    return(1);
 3165: 	default:
 3166: 	    break;
 3167:     }
 3168:     if (misc) {
 3169: 	if (node1 == node2) {
 3170: 	    if (precedence1 == precedence2) {
 3171: 		/*
 3172: 		* The ugly case; but normally there aren't many
 3173: 		* adjacent non-element nodes around.
 3174: 		*/
 3175: 		cur = miscNode2->prev;
 3176: 		while (cur != NULL) {
 3177: 		    if (cur == miscNode1)
 3178: 			return(1);
 3179: 		    if (cur->type == XML_ELEMENT_NODE)
 3180: 			return(-1);
 3181: 		    cur = cur->prev;
 3182: 		}
 3183: 		return (-1);
 3184: 	    } else {
 3185: 		/*
 3186: 		* Evaluate based on higher precedence wrt to the element.
 3187: 		* TODO: This assumes attributes are sorted before content.
 3188: 		*   Is this 100% correct?
 3189: 		*/
 3190: 		if (precedence1 < precedence2)
 3191: 		    return(1);
 3192: 		else
 3193: 		    return(-1);
 3194: 	    }
 3195: 	}
 3196: 	/*
 3197: 	* Special case: One of the helper-elements is contained by the other.
 3198: 	* <foo>
 3199: 	*   <node2>
 3200: 	*     <node1>Text-1(precedence1 == 2)</node1>
 3201: 	*   </node2>
 3202: 	*   Text-6(precedence2 == 3)
 3203: 	* </foo>
 3204: 	*/
 3205: 	if ((precedence2 == 3) && (precedence1 > 1)) {
 3206: 	    cur = node1->parent;
 3207: 	    while (cur) {
 3208: 		if (cur == node2)
 3209: 		    return(1);
 3210: 		cur = cur->parent;
 3211: 	    }
 3212: 	}
 3213: 	if ((precedence1 == 3) && (precedence2 > 1)) {
 3214: 	    cur = node2->parent;
 3215: 	    while (cur) {
 3216: 		if (cur == node1)
 3217: 		    return(-1);
 3218: 		cur = cur->parent;
 3219: 	    }
 3220: 	}
 3221:     }
 3222: 
 3223:     /*
 3224:      * Speedup using document order if availble.
 3225:      */
 3226:     if ((node1->type == XML_ELEMENT_NODE) &&
 3227: 	(node2->type == XML_ELEMENT_NODE) &&
 3228: 	(0 > (long) node1->content) &&
 3229: 	(0 > (long) node2->content) &&
 3230: 	(node1->doc == node2->doc)) {
 3231: 
 3232: 	l1 = -((long) node1->content);
 3233: 	l2 = -((long) node2->content);
 3234: 	if (l1 < l2)
 3235: 	    return(1);
 3236: 	if (l1 > l2)
 3237: 	    return(-1);
 3238:     }
 3239: 
 3240: turtle_comparison:
 3241: 
 3242:     if (node1 == node2->prev)
 3243: 	return(1);
 3244:     if (node1 == node2->next)
 3245: 	return(-1);
 3246:     /*
 3247:      * compute depth to root
 3248:      */
 3249:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
 3250: 	if (cur == node1)
 3251: 	    return(1);
 3252: 	depth2++;
 3253:     }
 3254:     root = cur;
 3255:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
 3256: 	if (cur == node2)
 3257: 	    return(-1);
 3258: 	depth1++;
 3259:     }
 3260:     /*
 3261:      * Distinct document (or distinct entities :-( ) case.
 3262:      */
 3263:     if (root != cur) {
 3264: 	return(-2);
 3265:     }
 3266:     /*
 3267:      * get the nearest common ancestor.
 3268:      */
 3269:     while (depth1 > depth2) {
 3270: 	depth1--;
 3271: 	node1 = node1->parent;
 3272:     }
 3273:     while (depth2 > depth1) {
 3274: 	depth2--;
 3275: 	node2 = node2->parent;
 3276:     }
 3277:     while (node1->parent != node2->parent) {
 3278: 	node1 = node1->parent;
 3279: 	node2 = node2->parent;
 3280: 	/* should not happen but just in case ... */
 3281: 	if ((node1 == NULL) || (node2 == NULL))
 3282: 	    return(-2);
 3283:     }
 3284:     /*
 3285:      * Find who's first.
 3286:      */
 3287:     if (node1 == node2->prev)
 3288: 	return(1);
 3289:     if (node1 == node2->next)
 3290: 	return(-1);
 3291:     /*
 3292:      * Speedup using document order if availble.
 3293:      */
 3294:     if ((node1->type == XML_ELEMENT_NODE) &&
 3295: 	(node2->type == XML_ELEMENT_NODE) &&
 3296: 	(0 > (long) node1->content) &&
 3297: 	(0 > (long) node2->content) &&
 3298: 	(node1->doc == node2->doc)) {
 3299: 
 3300: 	l1 = -((long) node1->content);
 3301: 	l2 = -((long) node2->content);
 3302: 	if (l1 < l2)
 3303: 	    return(1);
 3304: 	if (l1 > l2)
 3305: 	    return(-1);
 3306:     }
 3307: 
 3308:     for (cur = node1->next;cur != NULL;cur = cur->next)
 3309: 	if (cur == node2)
 3310: 	    return(1);
 3311:     return(-1); /* assume there is no sibling list corruption */
 3312: }
 3313: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
 3314: 
 3315: /**
 3316:  * xmlXPathNodeSetSort:
 3317:  * @set:  the node set
 3318:  *
 3319:  * Sort the node set in document order
 3320:  */
 3321: void
 3322: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
 3323:     int i, j, incr, len;
 3324:     xmlNodePtr tmp;
 3325: 
 3326:     if (set == NULL)
 3327: 	return;
 3328: 
 3329:     /* Use Shell's sort to sort the node-set */
 3330:     len = set->nodeNr;
 3331:     for (incr = len / 2; incr > 0; incr /= 2) {
 3332: 	for (i = incr; i < len; i++) {
 3333: 	    j = i - incr;
 3334: 	    while (j >= 0) {
 3335: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 3336: 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
 3337: 			set->nodeTab[j + incr]) == -1)
 3338: #else
 3339: 		if (xmlXPathCmpNodes(set->nodeTab[j],
 3340: 			set->nodeTab[j + incr]) == -1)
 3341: #endif
 3342: 		{
 3343: 		    tmp = set->nodeTab[j];
 3344: 		    set->nodeTab[j] = set->nodeTab[j + incr];
 3345: 		    set->nodeTab[j + incr] = tmp;
 3346: 		    j -= incr;
 3347: 		} else
 3348: 		    break;
 3349: 	    }
 3350: 	}
 3351:     }
 3352: }
 3353: 
 3354: #define XML_NODESET_DEFAULT	10
 3355: /**
 3356:  * xmlXPathNodeSetDupNs:
 3357:  * @node:  the parent node of the namespace XPath node
 3358:  * @ns:  the libxml namespace declaration node.
 3359:  *
 3360:  * Namespace node in libxml don't match the XPath semantic. In a node set
 3361:  * the namespace nodes are duplicated and the next pointer is set to the
 3362:  * parent node in the XPath semantic.
 3363:  *
 3364:  * Returns the newly created object.
 3365:  */
 3366: static xmlNodePtr
 3367: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
 3368:     xmlNsPtr cur;
 3369: 
 3370:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3371: 	return(NULL);
 3372:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
 3373: 	return((xmlNodePtr) ns);
 3374: 
 3375:     /*
 3376:      * Allocate a new Namespace and fill the fields.
 3377:      */
 3378:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
 3379:     if (cur == NULL) {
 3380:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
 3381: 	return(NULL);
 3382:     }
 3383:     memset(cur, 0, sizeof(xmlNs));
 3384:     cur->type = XML_NAMESPACE_DECL;
 3385:     if (ns->href != NULL)
 3386: 	cur->href = xmlStrdup(ns->href);
 3387:     if (ns->prefix != NULL)
 3388: 	cur->prefix = xmlStrdup(ns->prefix);
 3389:     cur->next = (xmlNsPtr) node;
 3390:     return((xmlNodePtr) cur);
 3391: }
 3392: 
 3393: /**
 3394:  * xmlXPathNodeSetFreeNs:
 3395:  * @ns:  the XPath namespace node found in a nodeset.
 3396:  *
 3397:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
 3398:  * the namespace nodes are duplicated and the next pointer is set to the
 3399:  * parent node in the XPath semantic. Check if such a node needs to be freed
 3400:  */
 3401: void
 3402: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
 3403:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
 3404: 	return;
 3405: 
 3406:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
 3407: 	if (ns->href != NULL)
 3408: 	    xmlFree((xmlChar *)ns->href);
 3409: 	if (ns->prefix != NULL)
 3410: 	    xmlFree((xmlChar *)ns->prefix);
 3411: 	xmlFree(ns);
 3412:     }
 3413: }
 3414: 
 3415: /**
 3416:  * xmlXPathNodeSetCreate:
 3417:  * @val:  an initial xmlNodePtr, or NULL
 3418:  *
 3419:  * Create a new xmlNodeSetPtr of type double and of value @val
 3420:  *
 3421:  * Returns the newly created object.
 3422:  */
 3423: xmlNodeSetPtr
 3424: xmlXPathNodeSetCreate(xmlNodePtr val) {
 3425:     xmlNodeSetPtr ret;
 3426: 
 3427:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3428:     if (ret == NULL) {
 3429:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3430: 	return(NULL);
 3431:     }
 3432:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3433:     if (val != NULL) {
 3434:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3435: 					     sizeof(xmlNodePtr));
 3436: 	if (ret->nodeTab == NULL) {
 3437: 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
 3438: 	    xmlFree(ret);
 3439: 	    return(NULL);
 3440: 	}
 3441: 	memset(ret->nodeTab, 0 ,
 3442: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3443:         ret->nodeMax = XML_NODESET_DEFAULT;
 3444: 	if (val->type == XML_NAMESPACE_DECL) {
 3445: 	    xmlNsPtr ns = (xmlNsPtr) val;
 3446: 
 3447: 	    ret->nodeTab[ret->nodeNr++] =
 3448: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3449: 	} else
 3450: 	    ret->nodeTab[ret->nodeNr++] = val;
 3451:     }
 3452:     return(ret);
 3453: }
 3454: 
 3455: /**
 3456:  * xmlXPathNodeSetCreateSize:
 3457:  * @size:  the initial size of the set
 3458:  *
 3459:  * Create a new xmlNodeSetPtr of type double and of value @val
 3460:  *
 3461:  * Returns the newly created object.
 3462:  */
 3463: static xmlNodeSetPtr
 3464: xmlXPathNodeSetCreateSize(int size) {
 3465:     xmlNodeSetPtr ret;
 3466: 
 3467:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
 3468:     if (ret == NULL) {
 3469:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 3470: 	return(NULL);
 3471:     }
 3472:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
 3473:     if (size < XML_NODESET_DEFAULT)
 3474: 	size = XML_NODESET_DEFAULT;
 3475:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
 3476:     if (ret->nodeTab == NULL) {
 3477: 	xmlXPathErrMemory(NULL, "creating nodeset\n");
 3478: 	xmlFree(ret);
 3479: 	return(NULL);
 3480:     }
 3481:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
 3482:     ret->nodeMax = size;
 3483:     return(ret);
 3484: }
 3485: 
 3486: /**
 3487:  * xmlXPathNodeSetContains:
 3488:  * @cur:  the node-set
 3489:  * @val:  the node
 3490:  *
 3491:  * checks whether @cur contains @val
 3492:  *
 3493:  * Returns true (1) if @cur contains @val, false (0) otherwise
 3494:  */
 3495: int
 3496: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
 3497:     int i;
 3498: 
 3499:     if ((cur == NULL) || (val == NULL)) return(0);
 3500:     if (val->type == XML_NAMESPACE_DECL) {
 3501: 	for (i = 0; i < cur->nodeNr; i++) {
 3502: 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 3503: 		xmlNsPtr ns1, ns2;
 3504: 
 3505: 		ns1 = (xmlNsPtr) val;
 3506: 		ns2 = (xmlNsPtr) cur->nodeTab[i];
 3507: 		if (ns1 == ns2)
 3508: 		    return(1);
 3509: 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
 3510: 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
 3511: 		    return(1);
 3512: 	    }
 3513: 	}
 3514:     } else {
 3515: 	for (i = 0; i < cur->nodeNr; i++) {
 3516: 	    if (cur->nodeTab[i] == val)
 3517: 		return(1);
 3518: 	}
 3519:     }
 3520:     return(0);
 3521: }
 3522: 
 3523: /**
 3524:  * xmlXPathNodeSetAddNs:
 3525:  * @cur:  the initial node set
 3526:  * @node:  the hosting node
 3527:  * @ns:  a the namespace node
 3528:  *
 3529:  * add a new namespace node to an existing NodeSet
 3530:  */
 3531: void
 3532: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
 3533:     int i;
 3534: 
 3535: 
 3536:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
 3537:         (ns->type != XML_NAMESPACE_DECL) ||
 3538: 	(node->type != XML_ELEMENT_NODE))
 3539: 	return;
 3540: 
 3541:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3542:     /*
 3543:      * prevent duplicates
 3544:      */
 3545:     for (i = 0;i < cur->nodeNr;i++) {
 3546:         if ((cur->nodeTab[i] != NULL) &&
 3547: 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
 3548: 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
 3549: 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
 3550: 	    return;
 3551:     }
 3552: 
 3553:     /*
 3554:      * grow the nodeTab if needed
 3555:      */
 3556:     if (cur->nodeMax == 0) {
 3557:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3558: 					     sizeof(xmlNodePtr));
 3559: 	if (cur->nodeTab == NULL) {
 3560: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3561: 	    return;
 3562: 	}
 3563: 	memset(cur->nodeTab, 0 ,
 3564: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3565:         cur->nodeMax = XML_NODESET_DEFAULT;
 3566:     } else if (cur->nodeNr == cur->nodeMax) {
 3567:         xmlNodePtr *temp;
 3568: 
 3569: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3570: 				      sizeof(xmlNodePtr));
 3571: 	if (temp == NULL) {
 3572: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3573: 	    return;
 3574: 	}
 3575:         cur->nodeMax *= 2;
 3576: 	cur->nodeTab = temp;
 3577:     }
 3578:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
 3579: }
 3580: 
 3581: /**
 3582:  * xmlXPathNodeSetAdd:
 3583:  * @cur:  the initial node set
 3584:  * @val:  a new xmlNodePtr
 3585:  *
 3586:  * add a new xmlNodePtr to an existing NodeSet
 3587:  */
 3588: void
 3589: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
 3590:     int i;
 3591: 
 3592:     if ((cur == NULL) || (val == NULL)) return;
 3593: 
 3594: #if 0
 3595:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
 3596: 	return;	/* an XSLT fake node */
 3597: #endif
 3598: 
 3599:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3600:     /*
 3601:      * prevent duplcates
 3602:      */
 3603:     for (i = 0;i < cur->nodeNr;i++)
 3604:         if (cur->nodeTab[i] == val) return;
 3605: 
 3606:     /*
 3607:      * grow the nodeTab if needed
 3608:      */
 3609:     if (cur->nodeMax == 0) {
 3610:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3611: 					     sizeof(xmlNodePtr));
 3612: 	if (cur->nodeTab == NULL) {
 3613: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3614: 	    return;
 3615: 	}
 3616: 	memset(cur->nodeTab, 0 ,
 3617: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3618:         cur->nodeMax = XML_NODESET_DEFAULT;
 3619:     } else if (cur->nodeNr == cur->nodeMax) {
 3620:         xmlNodePtr *temp;
 3621: 
 3622: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3623: 				      sizeof(xmlNodePtr));
 3624: 	if (temp == NULL) {
 3625: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3626: 	    return;
 3627: 	}
 3628:         cur->nodeMax *= 2;
 3629: 	cur->nodeTab = temp;
 3630:     }
 3631:     if (val->type == XML_NAMESPACE_DECL) {
 3632: 	xmlNsPtr ns = (xmlNsPtr) val;
 3633: 
 3634: 	cur->nodeTab[cur->nodeNr++] =
 3635: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3636:     } else
 3637: 	cur->nodeTab[cur->nodeNr++] = val;
 3638: }
 3639: 
 3640: /**
 3641:  * xmlXPathNodeSetAddUnique:
 3642:  * @cur:  the initial node set
 3643:  * @val:  a new xmlNodePtr
 3644:  *
 3645:  * add a new xmlNodePtr to an existing NodeSet, optimized version
 3646:  * when we are sure the node is not already in the set.
 3647:  */
 3648: void
 3649: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
 3650:     if ((cur == NULL) || (val == NULL)) return;
 3651: 
 3652: #if 0
 3653:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
 3654: 	return;	/* an XSLT fake node */
 3655: #endif
 3656: 
 3657:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3658:     /*
 3659:      * grow the nodeTab if needed
 3660:      */
 3661:     if (cur->nodeMax == 0) {
 3662:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3663: 					     sizeof(xmlNodePtr));
 3664: 	if (cur->nodeTab == NULL) {
 3665: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3666: 	    return;
 3667: 	}
 3668: 	memset(cur->nodeTab, 0 ,
 3669: 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3670:         cur->nodeMax = XML_NODESET_DEFAULT;
 3671:     } else if (cur->nodeNr == cur->nodeMax) {
 3672:         xmlNodePtr *temp;
 3673: 
 3674: 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
 3675: 				      sizeof(xmlNodePtr));
 3676: 	if (temp == NULL) {
 3677: 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
 3678: 	    return;
 3679: 	}
 3680: 	cur->nodeTab = temp;
 3681:         cur->nodeMax *= 2;
 3682:     }
 3683:     if (val->type == XML_NAMESPACE_DECL) {
 3684: 	xmlNsPtr ns = (xmlNsPtr) val;
 3685: 
 3686: 	cur->nodeTab[cur->nodeNr++] =
 3687: 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3688:     } else
 3689: 	cur->nodeTab[cur->nodeNr++] = val;
 3690: }
 3691: 
 3692: /**
 3693:  * xmlXPathNodeSetMerge:
 3694:  * @val1:  the first NodeSet or NULL
 3695:  * @val2:  the second NodeSet
 3696:  *
 3697:  * Merges two nodesets, all nodes from @val2 are added to @val1
 3698:  * if @val1 is NULL, a new set is created and copied from @val2
 3699:  *
 3700:  * Returns @val1 once extended or NULL in case of error.
 3701:  */
 3702: xmlNodeSetPtr
 3703: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
 3704:     int i, j, initNr, skip;
 3705:     xmlNodePtr n1, n2;
 3706: 
 3707:     if (val2 == NULL) return(val1);
 3708:     if (val1 == NULL) {
 3709: 	val1 = xmlXPathNodeSetCreate(NULL);
 3710:     if (val1 == NULL)
 3711:         return (NULL);
 3712: #if 0
 3713: 	/*
 3714: 	* TODO: The optimization won't work in every case, since
 3715: 	*  those nasty namespace nodes need to be added with
 3716: 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
 3717: 	*  memcpy is not possible.
 3718: 	*  If there was a flag on the nodesetval, indicating that
 3719: 	*  some temporary nodes are in, that would be helpfull.
 3720: 	*/
 3721: 	/*
 3722: 	* Optimization: Create an equally sized node-set
 3723: 	* and memcpy the content.
 3724: 	*/
 3725: 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
 3726: 	if (val1 == NULL)
 3727: 	    return(NULL);
 3728: 	if (val2->nodeNr != 0) {
 3729: 	    if (val2->nodeNr == 1)
 3730: 		*(val1->nodeTab) = *(val2->nodeTab);
 3731: 	    else {
 3732: 		memcpy(val1->nodeTab, val2->nodeTab,
 3733: 		    val2->nodeNr * sizeof(xmlNodePtr));
 3734: 	    }
 3735: 	    val1->nodeNr = val2->nodeNr;
 3736: 	}
 3737: 	return(val1);
 3738: #endif
 3739:     }
 3740: 
 3741:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3742:     initNr = val1->nodeNr;
 3743: 
 3744:     for (i = 0;i < val2->nodeNr;i++) {
 3745: 	n2 = val2->nodeTab[i];
 3746: 	/*
 3747: 	 * check against duplicates
 3748: 	 */
 3749: 	skip = 0;
 3750: 	for (j = 0; j < initNr; j++) {
 3751: 	    n1 = val1->nodeTab[j];
 3752: 	    if (n1 == n2) {
 3753: 		skip = 1;
 3754: 		break;
 3755: 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
 3756: 		       (n2->type == XML_NAMESPACE_DECL)) {
 3757: 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3758: 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3759: 			((xmlNsPtr) n2)->prefix)))
 3760: 		{
 3761: 		    skip = 1;
 3762: 		    break;
 3763: 		}
 3764: 	    }
 3765: 	}
 3766: 	if (skip)
 3767: 	    continue;
 3768: 
 3769: 	/*
 3770: 	 * grow the nodeTab if needed
 3771: 	 */
 3772: 	if (val1->nodeMax == 0) {
 3773: 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3774: 						    sizeof(xmlNodePtr));
 3775: 	    if (val1->nodeTab == NULL) {
 3776: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3777: 		return(NULL);
 3778: 	    }
 3779: 	    memset(val1->nodeTab, 0 ,
 3780: 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3781: 	    val1->nodeMax = XML_NODESET_DEFAULT;
 3782: 	} else if (val1->nodeNr == val1->nodeMax) {
 3783: 	    xmlNodePtr *temp;
 3784: 
 3785: 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
 3786: 					     sizeof(xmlNodePtr));
 3787: 	    if (temp == NULL) {
 3788: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3789: 		return(NULL);
 3790: 	    }
 3791: 	    val1->nodeTab = temp;
 3792: 	    val1->nodeMax *= 2;
 3793: 	}
 3794: 	if (n2->type == XML_NAMESPACE_DECL) {
 3795: 	    xmlNsPtr ns = (xmlNsPtr) n2;
 3796: 
 3797: 	    val1->nodeTab[val1->nodeNr++] =
 3798: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3799: 	} else
 3800: 	    val1->nodeTab[val1->nodeNr++] = n2;
 3801:     }
 3802: 
 3803:     return(val1);
 3804: }
 3805: 
 3806: #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
 3807: /**
 3808:  * xmlXPathNodeSetMergeUnique:
 3809:  * @val1:  the first NodeSet or NULL
 3810:  * @val2:  the second NodeSet
 3811:  *
 3812:  * Merges two nodesets, all nodes from @val2 are added to @val1
 3813:  * if @val1 is NULL, a new set is created and copied from @val2
 3814:  *
 3815:  * Returns @val1 once extended or NULL in case of error.
 3816:  */
 3817: static xmlNodeSetPtr
 3818: xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
 3819:     int i;
 3820: 
 3821:     if (val2 == NULL) return(val1);
 3822:     if (val1 == NULL) {
 3823: 	val1 = xmlXPathNodeSetCreate(NULL);
 3824:     }
 3825:     if (val1 == NULL)
 3826:         return (NULL);
 3827: 
 3828:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 3829: 
 3830:     for (i = 0;i < val2->nodeNr;i++) {
 3831: 	/*
 3832: 	 * grow the nodeTab if needed
 3833: 	 */
 3834: 	if (val1->nodeMax == 0) {
 3835: 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
 3836: 						    sizeof(xmlNodePtr));
 3837: 	    if (val1->nodeTab == NULL) {
 3838: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3839: 		return(NULL);
 3840: 	    }
 3841: 	    memset(val1->nodeTab, 0 ,
 3842: 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3843: 	    val1->nodeMax = XML_NODESET_DEFAULT;
 3844: 	} else if (val1->nodeNr == val1->nodeMax) {
 3845: 	    xmlNodePtr *temp;
 3846: 
 3847: 	    val1->nodeMax *= 2;
 3848: 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
 3849: 					     sizeof(xmlNodePtr));
 3850: 	    if (temp == NULL) {
 3851: 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
 3852: 		return(NULL);
 3853: 	    }
 3854: 	    val1->nodeTab = temp;
 3855: 	}
 3856: 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 3857: 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
 3858: 
 3859: 	    val1->nodeTab[val1->nodeNr++] =
 3860: 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3861: 	} else
 3862: 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
 3863:     }
 3864: 
 3865:     return(val1);
 3866: }
 3867: #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
 3868: 
 3869: /**
 3870:  * xmlXPathNodeSetMergeAndClear:
 3871:  * @set1:  the first NodeSet or NULL
 3872:  * @set2:  the second NodeSet
 3873:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 3874:  *
 3875:  * Merges two nodesets, all nodes from @set2 are added to @set1
 3876:  * if @set1 is NULL, a new set is created and copied from @set2.
 3877:  * Checks for duplicate nodes. Clears set2.
 3878:  *
 3879:  * Returns @set1 once extended or NULL in case of error.
 3880:  */
 3881: static xmlNodeSetPtr
 3882: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 3883: 			     int hasNullEntries)
 3884: {
 3885:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 3886: 	/*
 3887: 	* Note that doing a memcpy of the list, namespace nodes are
 3888: 	* just assigned to set1, since set2 is cleared anyway.
 3889: 	*/
 3890: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 3891: 	if (set1 == NULL)
 3892: 	    return(NULL);
 3893: 	if (set2->nodeNr != 0) {
 3894: 	    memcpy(set1->nodeTab, set2->nodeTab,
 3895: 		set2->nodeNr * sizeof(xmlNodePtr));
 3896: 	    set1->nodeNr = set2->nodeNr;
 3897: 	}
 3898:     } else {
 3899: 	int i, j, initNbSet1;
 3900: 	xmlNodePtr n1, n2;
 3901: 
 3902: 	if (set1 == NULL)
 3903:             set1 = xmlXPathNodeSetCreate(NULL);
 3904:         if (set1 == NULL)
 3905:             return (NULL);
 3906: 
 3907: 	initNbSet1 = set1->nodeNr;
 3908: 	for (i = 0;i < set2->nodeNr;i++) {
 3909: 	    n2 = set2->nodeTab[i];
 3910: 	    /*
 3911: 	    * Skip NULLed entries.
 3912: 	    */
 3913: 	    if (n2 == NULL)
 3914: 		continue;
 3915: 	    /*
 3916: 	    * Skip duplicates.
 3917: 	    */
 3918: 	    for (j = 0; j < initNbSet1; j++) {
 3919: 		n1 = set1->nodeTab[j];
 3920: 		if (n1 == n2) {
 3921: 		    goto skip_node;
 3922: 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
 3923: 		    (n2->type == XML_NAMESPACE_DECL))
 3924: 		{
 3925: 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
 3926: 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
 3927: 			((xmlNsPtr) n2)->prefix)))
 3928: 		    {
 3929: 			/*
 3930: 			* Free the namespace node.
 3931: 			*/
 3932: 			set2->nodeTab[i] = NULL;
 3933: 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
 3934: 			goto skip_node;
 3935: 		    }
 3936: 		}
 3937: 	    }
 3938: 	    /*
 3939: 	    * grow the nodeTab if needed
 3940: 	    */
 3941: 	    if (set1->nodeMax == 0) {
 3942: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 3943: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 3944: 		if (set1->nodeTab == NULL) {
 3945: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3946: 		    return(NULL);
 3947: 		}
 3948: 		memset(set1->nodeTab, 0,
 3949: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 3950: 		set1->nodeMax = XML_NODESET_DEFAULT;
 3951: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 3952: 		xmlNodePtr *temp;
 3953: 
 3954: 		temp = (xmlNodePtr *) xmlRealloc(
 3955: 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
 3956: 		if (temp == NULL) {
 3957: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 3958: 		    return(NULL);
 3959: 		}
 3960: 		set1->nodeTab = temp;
 3961: 		set1->nodeMax *= 2;
 3962: 	    }
 3963: 	    if (n2->type == XML_NAMESPACE_DECL) {
 3964: 		xmlNsPtr ns = (xmlNsPtr) n2;
 3965: 
 3966: 		set1->nodeTab[set1->nodeNr++] =
 3967: 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
 3968: 	    } else
 3969: 		set1->nodeTab[set1->nodeNr++] = n2;
 3970: skip_node:
 3971: 	    {}
 3972: 	}
 3973:     }
 3974:     set2->nodeNr = 0;
 3975:     return(set1);
 3976: }
 3977: 
 3978: /**
 3979:  * xmlXPathNodeSetMergeAndClearNoDupls:
 3980:  * @set1:  the first NodeSet or NULL
 3981:  * @set2:  the second NodeSet
 3982:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
 3983:  *
 3984:  * Merges two nodesets, all nodes from @set2 are added to @set1
 3985:  * if @set1 is NULL, a new set is created and copied from @set2.
 3986:  * Doesn't chack for duplicate nodes. Clears set2.
 3987:  *
 3988:  * Returns @set1 once extended or NULL in case of error.
 3989:  */
 3990: static xmlNodeSetPtr
 3991: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
 3992: 				    int hasNullEntries)
 3993: {
 3994:     if (set2 == NULL)
 3995: 	return(set1);
 3996:     if ((set1 == NULL) && (hasNullEntries == 0)) {
 3997: 	/*
 3998: 	* Note that doing a memcpy of the list, namespace nodes are
 3999: 	* just assigned to set1, since set2 is cleared anyway.
 4000: 	*/
 4001: 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
 4002: 	if (set1 == NULL)
 4003: 	    return(NULL);
 4004: 	if (set2->nodeNr != 0) {
 4005: 	    memcpy(set1->nodeTab, set2->nodeTab,
 4006: 		set2->nodeNr * sizeof(xmlNodePtr));
 4007: 	    set1->nodeNr = set2->nodeNr;
 4008: 	}
 4009:     } else {
 4010: 	int i;
 4011: 	xmlNodePtr n2;
 4012: 
 4013: 	if (set1 == NULL)
 4014: 	    set1 = xmlXPathNodeSetCreate(NULL);
 4015:         if (set1 == NULL)
 4016:             return (NULL);
 4017: 
 4018: 	for (i = 0;i < set2->nodeNr;i++) {
 4019: 	    n2 = set2->nodeTab[i];
 4020: 	    /*
 4021: 	    * Skip NULLed entries.
 4022: 	    */
 4023: 	    if (n2 == NULL)
 4024: 		continue;
 4025: 	    if (set1->nodeMax == 0) {
 4026: 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
 4027: 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
 4028: 		if (set1->nodeTab == NULL) {
 4029: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 4030: 		    return(NULL);
 4031: 		}
 4032: 		memset(set1->nodeTab, 0,
 4033: 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
 4034: 		set1->nodeMax = XML_NODESET_DEFAULT;
 4035: 	    } else if (set1->nodeNr >= set1->nodeMax) {
 4036: 		xmlNodePtr *temp;
 4037: 
 4038: 		temp = (xmlNodePtr *) xmlRealloc(
 4039: 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
 4040: 		if (temp == NULL) {
 4041: 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
 4042: 		    return(NULL);
 4043: 		}
 4044: 		set1->nodeTab = temp;
 4045: 		set1->nodeMax *= 2;
 4046: 	    }
 4047: 	    set1->nodeTab[set1->nodeNr++] = n2;
 4048: 	}
 4049:     }
 4050:     set2->nodeNr = 0;
 4051:     return(set1);
 4052: }
 4053: 
 4054: /**
 4055:  * xmlXPathNodeSetDel:
 4056:  * @cur:  the initial node set
 4057:  * @val:  an xmlNodePtr
 4058:  *
 4059:  * Removes an xmlNodePtr from an existing NodeSet
 4060:  */
 4061: void
 4062: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
 4063:     int i;
 4064: 
 4065:     if (cur == NULL) return;
 4066:     if (val == NULL) return;
 4067: 
 4068:     /*
 4069:      * find node in nodeTab
 4070:      */
 4071:     for (i = 0;i < cur->nodeNr;i++)
 4072:         if (cur->nodeTab[i] == val) break;
 4073: 
 4074:     if (i >= cur->nodeNr) {	/* not found */
 4075: #ifdef DEBUG
 4076:         xmlGenericError(xmlGenericErrorContext,
 4077: 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
 4078: 		val->name);
 4079: #endif
 4080:         return;
 4081:     }
 4082:     if ((cur->nodeTab[i] != NULL) &&
 4083: 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4084: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
 4085:     cur->nodeNr--;
 4086:     for (;i < cur->nodeNr;i++)
 4087:         cur->nodeTab[i] = cur->nodeTab[i + 1];
 4088:     cur->nodeTab[cur->nodeNr] = NULL;
 4089: }
 4090: 
 4091: /**
 4092:  * xmlXPathNodeSetRemove:
 4093:  * @cur:  the initial node set
 4094:  * @val:  the index to remove
 4095:  *
 4096:  * Removes an entry from an existing NodeSet list.
 4097:  */
 4098: void
 4099: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
 4100:     if (cur == NULL) return;
 4101:     if (val >= cur->nodeNr) return;
 4102:     if ((cur->nodeTab[val] != NULL) &&
 4103: 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
 4104: 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
 4105:     cur->nodeNr--;
 4106:     for (;val < cur->nodeNr;val++)
 4107:         cur->nodeTab[val] = cur->nodeTab[val + 1];
 4108:     cur->nodeTab[cur->nodeNr] = NULL;
 4109: }
 4110: 
 4111: /**
 4112:  * xmlXPathFreeNodeSet:
 4113:  * @obj:  the xmlNodeSetPtr to free
 4114:  *
 4115:  * Free the NodeSet compound (not the actual nodes !).
 4116:  */
 4117: void
 4118: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
 4119:     if (obj == NULL) return;
 4120:     if (obj->nodeTab != NULL) {
 4121: 	int i;
 4122: 
 4123: 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4124: 	for (i = 0;i < obj->nodeNr;i++)
 4125: 	    if ((obj->nodeTab[i] != NULL) &&
 4126: 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
 4127: 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4128: 	xmlFree(obj->nodeTab);
 4129:     }
 4130:     xmlFree(obj);
 4131: }
 4132: 
 4133: /**
 4134:  * xmlXPathNodeSetClear:
 4135:  * @set:  the node set to clear
 4136:  *
 4137:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
 4138:  * are feed), but does *not* free the list itself. Sets the length of the
 4139:  * list to 0.
 4140:  */
 4141: static void
 4142: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
 4143: {
 4144:     if ((set == NULL) || (set->nodeNr <= 0))
 4145: 	return;
 4146:     else if (hasNsNodes) {
 4147: 	int i;
 4148: 	xmlNodePtr node;
 4149: 
 4150: 	for (i = 0; i < set->nodeNr; i++) {
 4151: 	    node = set->nodeTab[i];
 4152: 	    if ((node != NULL) &&
 4153: 		(node->type == XML_NAMESPACE_DECL))
 4154: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4155: 	}
 4156:     }
 4157:     set->nodeNr = 0;
 4158: }
 4159: 
 4160: /**
 4161:  * xmlXPathNodeSetClearFromPos:
 4162:  * @set: the node set to be cleared
 4163:  * @pos: the start position to clear from
 4164:  *
 4165:  * Clears the list from temporary XPath objects (e.g. namespace nodes
 4166:  * are feed) starting with the entry at @pos, but does *not* free the list
 4167:  * itself. Sets the length of the list to @pos.
 4168:  */
 4169: static void
 4170: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
 4171: {
 4172:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
 4173: 	return;
 4174:     else if ((hasNsNodes)) {
 4175: 	int i;
 4176: 	xmlNodePtr node;
 4177: 
 4178: 	for (i = pos; i < set->nodeNr; i++) {
 4179: 	    node = set->nodeTab[i];
 4180: 	    if ((node != NULL) &&
 4181: 		(node->type == XML_NAMESPACE_DECL))
 4182: 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 4183: 	}
 4184:     }
 4185:     set->nodeNr = pos;
 4186: }
 4187: 
 4188: /**
 4189:  * xmlXPathFreeValueTree:
 4190:  * @obj:  the xmlNodeSetPtr to free
 4191:  *
 4192:  * Free the NodeSet compound and the actual tree, this is different
 4193:  * from xmlXPathFreeNodeSet()
 4194:  */
 4195: static void
 4196: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
 4197:     int i;
 4198: 
 4199:     if (obj == NULL) return;
 4200: 
 4201:     if (obj->nodeTab != NULL) {
 4202: 	for (i = 0;i < obj->nodeNr;i++) {
 4203: 	    if (obj->nodeTab[i] != NULL) {
 4204: 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
 4205: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
 4206: 		} else {
 4207: 		    xmlFreeNodeList(obj->nodeTab[i]);
 4208: 		}
 4209: 	    }
 4210: 	}
 4211: 	xmlFree(obj->nodeTab);
 4212:     }
 4213:     xmlFree(obj);
 4214: }
 4215: 
 4216: #if defined(DEBUG) || defined(DEBUG_STEP)
 4217: /**
 4218:  * xmlGenericErrorContextNodeSet:
 4219:  * @output:  a FILE * for the output
 4220:  * @obj:  the xmlNodeSetPtr to display
 4221:  *
 4222:  * Quick display of a NodeSet
 4223:  */
 4224: void
 4225: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
 4226:     int i;
 4227: 
 4228:     if (output == NULL) output = xmlGenericErrorContext;
 4229:     if (obj == NULL)  {
 4230:         fprintf(output, "NodeSet == NULL !\n");
 4231: 	return;
 4232:     }
 4233:     if (obj->nodeNr == 0) {
 4234:         fprintf(output, "NodeSet is empty\n");
 4235: 	return;
 4236:     }
 4237:     if (obj->nodeTab == NULL) {
 4238: 	fprintf(output, " nodeTab == NULL !\n");
 4239: 	return;
 4240:     }
 4241:     for (i = 0; i < obj->nodeNr; i++) {
 4242:         if (obj->nodeTab[i] == NULL) {
 4243: 	    fprintf(output, " NULL !\n");
 4244: 	    return;
 4245:         }
 4246: 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
 4247: 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
 4248: 	    fprintf(output, " /");
 4249: 	else if (obj->nodeTab[i]->name == NULL)
 4250: 	    fprintf(output, " noname!");
 4251: 	else fprintf(output, " %s", obj->nodeTab[i]->name);
 4252:     }
 4253:     fprintf(output, "\n");
 4254: }
 4255: #endif
 4256: 
 4257: /**
 4258:  * xmlXPathNewNodeSet:
 4259:  * @val:  the NodePtr value
 4260:  *
 4261:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4262:  * it with the single Node @val
 4263:  *
 4264:  * Returns the newly created object.
 4265:  */
 4266: xmlXPathObjectPtr
 4267: xmlXPathNewNodeSet(xmlNodePtr val) {
 4268:     xmlXPathObjectPtr ret;
 4269: 
 4270:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4271:     if (ret == NULL) {
 4272:         xmlXPathErrMemory(NULL, "creating nodeset\n");
 4273: 	return(NULL);
 4274:     }
 4275:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4276:     ret->type = XPATH_NODESET;
 4277:     ret->boolval = 0;
 4278:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4279:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
 4280: #ifdef XP_DEBUG_OBJ_USAGE
 4281:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4282: #endif
 4283:     return(ret);
 4284: }
 4285: 
 4286: /**
 4287:  * xmlXPathNewValueTree:
 4288:  * @val:  the NodePtr value
 4289:  *
 4290:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
 4291:  * it with the tree root @val
 4292:  *
 4293:  * Returns the newly created object.
 4294:  */
 4295: xmlXPathObjectPtr
 4296: xmlXPathNewValueTree(xmlNodePtr val) {
 4297:     xmlXPathObjectPtr ret;
 4298: 
 4299:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4300:     if (ret == NULL) {
 4301:         xmlXPathErrMemory(NULL, "creating result value tree\n");
 4302: 	return(NULL);
 4303:     }
 4304:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4305:     ret->type = XPATH_XSLT_TREE;
 4306:     ret->boolval = 1;
 4307:     ret->user = (void *) val;
 4308:     ret->nodesetval = xmlXPathNodeSetCreate(val);
 4309: #ifdef XP_DEBUG_OBJ_USAGE
 4310:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
 4311: #endif
 4312:     return(ret);
 4313: }
 4314: 
 4315: /**
 4316:  * xmlXPathNewNodeSetList:
 4317:  * @val:  an existing NodeSet
 4318:  *
 4319:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
 4320:  * it with the Nodeset @val
 4321:  *
 4322:  * Returns the newly created object.
 4323:  */
 4324: xmlXPathObjectPtr
 4325: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
 4326: {
 4327:     xmlXPathObjectPtr ret;
 4328:     int i;
 4329: 
 4330:     if (val == NULL)
 4331:         ret = NULL;
 4332:     else if (val->nodeTab == NULL)
 4333:         ret = xmlXPathNewNodeSet(NULL);
 4334:     else {
 4335:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
 4336:         if (ret)
 4337:             for (i = 1; i < val->nodeNr; ++i)
 4338:                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
 4339:     }
 4340: 
 4341:     return (ret);
 4342: }
 4343: 
 4344: /**
 4345:  * xmlXPathWrapNodeSet:
 4346:  * @val:  the NodePtr value
 4347:  *
 4348:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
 4349:  *
 4350:  * Returns the newly created object.
 4351:  */
 4352: xmlXPathObjectPtr
 4353: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
 4354:     xmlXPathObjectPtr ret;
 4355: 
 4356:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 4357:     if (ret == NULL) {
 4358:         xmlXPathErrMemory(NULL, "creating node set object\n");
 4359: 	return(NULL);
 4360:     }
 4361:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 4362:     ret->type = XPATH_NODESET;
 4363:     ret->nodesetval = val;
 4364: #ifdef XP_DEBUG_OBJ_USAGE
 4365:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
 4366: #endif
 4367:     return(ret);
 4368: }
 4369: 
 4370: /**
 4371:  * xmlXPathFreeNodeSetList:
 4372:  * @obj:  an existing NodeSetList object
 4373:  *
 4374:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
 4375:  * the list contrary to xmlXPathFreeObject().
 4376:  */
 4377: void
 4378: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
 4379:     if (obj == NULL) return;
 4380: #ifdef XP_DEBUG_OBJ_USAGE
 4381:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 4382: #endif
 4383:     xmlFree(obj);
 4384: }
 4385: 
 4386: /**
 4387:  * xmlXPathDifference:
 4388:  * @nodes1:  a node-set
 4389:  * @nodes2:  a node-set
 4390:  *
 4391:  * Implements the EXSLT - Sets difference() function:
 4392:  *    node-set set:difference (node-set, node-set)
 4393:  *
 4394:  * Returns the difference between the two node sets, or nodes1 if
 4395:  *         nodes2 is empty
 4396:  */
 4397: xmlNodeSetPtr
 4398: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4399:     xmlNodeSetPtr ret;
 4400:     int i, l1;
 4401:     xmlNodePtr cur;
 4402: 
 4403:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4404: 	return(nodes1);
 4405: 
 4406:     ret = xmlXPathNodeSetCreate(NULL);
 4407:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4408: 	return(ret);
 4409: 
 4410:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4411: 
 4412:     for (i = 0; i < l1; i++) {
 4413: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4414: 	if (!xmlXPathNodeSetContains(nodes2, cur))
 4415: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4416:     }
 4417:     return(ret);
 4418: }
 4419: 
 4420: /**
 4421:  * xmlXPathIntersection:
 4422:  * @nodes1:  a node-set
 4423:  * @nodes2:  a node-set
 4424:  *
 4425:  * Implements the EXSLT - Sets intersection() function:
 4426:  *    node-set set:intersection (node-set, node-set)
 4427:  *
 4428:  * Returns a node set comprising the nodes that are within both the
 4429:  *         node sets passed as arguments
 4430:  */
 4431: xmlNodeSetPtr
 4432: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4433:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
 4434:     int i, l1;
 4435:     xmlNodePtr cur;
 4436: 
 4437:     if (ret == NULL)
 4438:         return(ret);
 4439:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4440: 	return(ret);
 4441:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4442: 	return(ret);
 4443: 
 4444:     l1 = xmlXPathNodeSetGetLength(nodes1);
 4445: 
 4446:     for (i = 0; i < l1; i++) {
 4447: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4448: 	if (xmlXPathNodeSetContains(nodes2, cur))
 4449: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4450:     }
 4451:     return(ret);
 4452: }
 4453: 
 4454: /**
 4455:  * xmlXPathDistinctSorted:
 4456:  * @nodes:  a node-set, sorted by document order
 4457:  *
 4458:  * Implements the EXSLT - Sets distinct() function:
 4459:  *    node-set set:distinct (node-set)
 4460:  *
 4461:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4462:  *         it is empty
 4463:  */
 4464: xmlNodeSetPtr
 4465: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
 4466:     xmlNodeSetPtr ret;
 4467:     xmlHashTablePtr hash;
 4468:     int i, l;
 4469:     xmlChar * strval;
 4470:     xmlNodePtr cur;
 4471: 
 4472:     if (xmlXPathNodeSetIsEmpty(nodes))
 4473: 	return(nodes);
 4474: 
 4475:     ret = xmlXPathNodeSetCreate(NULL);
 4476:     if (ret == NULL)
 4477:         return(ret);
 4478:     l = xmlXPathNodeSetGetLength(nodes);
 4479:     hash = xmlHashCreate (l);
 4480:     for (i = 0; i < l; i++) {
 4481: 	cur = xmlXPathNodeSetItem(nodes, i);
 4482: 	strval = xmlXPathCastNodeToString(cur);
 4483: 	if (xmlHashLookup(hash, strval) == NULL) {
 4484: 	    xmlHashAddEntry(hash, strval, strval);
 4485: 	    xmlXPathNodeSetAddUnique(ret, cur);
 4486: 	} else {
 4487: 	    xmlFree(strval);
 4488: 	}
 4489:     }
 4490:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
 4491:     return(ret);
 4492: }
 4493: 
 4494: /**
 4495:  * xmlXPathDistinct:
 4496:  * @nodes:  a node-set
 4497:  *
 4498:  * Implements the EXSLT - Sets distinct() function:
 4499:  *    node-set set:distinct (node-set)
 4500:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
 4501:  * is called with the sorted node-set
 4502:  *
 4503:  * Returns a subset of the nodes contained in @nodes, or @nodes if
 4504:  *         it is empty
 4505:  */
 4506: xmlNodeSetPtr
 4507: xmlXPathDistinct (xmlNodeSetPtr nodes) {
 4508:     if (xmlXPathNodeSetIsEmpty(nodes))
 4509: 	return(nodes);
 4510: 
 4511:     xmlXPathNodeSetSort(nodes);
 4512:     return(xmlXPathDistinctSorted(nodes));
 4513: }
 4514: 
 4515: /**
 4516:  * xmlXPathHasSameNodes:
 4517:  * @nodes1:  a node-set
 4518:  * @nodes2:  a node-set
 4519:  *
 4520:  * Implements the EXSLT - Sets has-same-nodes function:
 4521:  *    boolean set:has-same-node(node-set, node-set)
 4522:  *
 4523:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
 4524:  *         otherwise
 4525:  */
 4526: int
 4527: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4528:     int i, l;
 4529:     xmlNodePtr cur;
 4530: 
 4531:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
 4532: 	xmlXPathNodeSetIsEmpty(nodes2))
 4533: 	return(0);
 4534: 
 4535:     l = xmlXPathNodeSetGetLength(nodes1);
 4536:     for (i = 0; i < l; i++) {
 4537: 	cur = xmlXPathNodeSetItem(nodes1, i);
 4538: 	if (xmlXPathNodeSetContains(nodes2, cur))
 4539: 	    return(1);
 4540:     }
 4541:     return(0);
 4542: }
 4543: 
 4544: /**
 4545:  * xmlXPathNodeLeadingSorted:
 4546:  * @nodes: a node-set, sorted by document order
 4547:  * @node: a node
 4548:  *
 4549:  * Implements the EXSLT - Sets leading() function:
 4550:  *    node-set set:leading (node-set, node-set)
 4551:  *
 4552:  * Returns the nodes in @nodes that precede @node in document order,
 4553:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4554:  *         doesn't contain @node
 4555:  */
 4556: xmlNodeSetPtr
 4557: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4558:     int i, l;
 4559:     xmlNodePtr cur;
 4560:     xmlNodeSetPtr ret;
 4561: 
 4562:     if (node == NULL)
 4563: 	return(nodes);
 4564: 
 4565:     ret = xmlXPathNodeSetCreate(NULL);
 4566:     if (ret == NULL)
 4567:         return(ret);
 4568:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4569: 	(!xmlXPathNodeSetContains(nodes, node)))
 4570: 	return(ret);
 4571: 
 4572:     l = xmlXPathNodeSetGetLength(nodes);
 4573:     for (i = 0; i < l; i++) {
 4574: 	cur = xmlXPathNodeSetItem(nodes, i);
 4575: 	if (cur == node)
 4576: 	    break;
 4577: 	xmlXPathNodeSetAddUnique(ret, cur);
 4578:     }
 4579:     return(ret);
 4580: }
 4581: 
 4582: /**
 4583:  * xmlXPathNodeLeading:
 4584:  * @nodes:  a node-set
 4585:  * @node:  a node
 4586:  *
 4587:  * Implements the EXSLT - Sets leading() function:
 4588:  *    node-set set:leading (node-set, node-set)
 4589:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
 4590:  * is called.
 4591:  *
 4592:  * Returns the nodes in @nodes that precede @node in document order,
 4593:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4594:  *         doesn't contain @node
 4595:  */
 4596: xmlNodeSetPtr
 4597: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4598:     xmlXPathNodeSetSort(nodes);
 4599:     return(xmlXPathNodeLeadingSorted(nodes, node));
 4600: }
 4601: 
 4602: /**
 4603:  * xmlXPathLeadingSorted:
 4604:  * @nodes1:  a node-set, sorted by document order
 4605:  * @nodes2:  a node-set, sorted by document order
 4606:  *
 4607:  * Implements the EXSLT - Sets leading() function:
 4608:  *    node-set set:leading (node-set, node-set)
 4609:  *
 4610:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4611:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4612:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4613:  */
 4614: xmlNodeSetPtr
 4615: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4616:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4617: 	return(nodes1);
 4618:     return(xmlXPathNodeLeadingSorted(nodes1,
 4619: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4620: }
 4621: 
 4622: /**
 4623:  * xmlXPathLeading:
 4624:  * @nodes1:  a node-set
 4625:  * @nodes2:  a node-set
 4626:  *
 4627:  * Implements the EXSLT - Sets leading() function:
 4628:  *    node-set set:leading (node-set, node-set)
 4629:  * @nodes1 and @nodes2 are sorted by document order, then
 4630:  * #exslSetsLeadingSorted is called.
 4631:  *
 4632:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
 4633:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4634:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4635:  */
 4636: xmlNodeSetPtr
 4637: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4638:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4639: 	return(nodes1);
 4640:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4641: 	return(xmlXPathNodeSetCreate(NULL));
 4642:     xmlXPathNodeSetSort(nodes1);
 4643:     xmlXPathNodeSetSort(nodes2);
 4644:     return(xmlXPathNodeLeadingSorted(nodes1,
 4645: 				     xmlXPathNodeSetItem(nodes2, 1)));
 4646: }
 4647: 
 4648: /**
 4649:  * xmlXPathNodeTrailingSorted:
 4650:  * @nodes: a node-set, sorted by document order
 4651:  * @node: a node
 4652:  *
 4653:  * Implements the EXSLT - Sets trailing() function:
 4654:  *    node-set set:trailing (node-set, node-set)
 4655:  *
 4656:  * Returns the nodes in @nodes that follow @node in document order,
 4657:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4658:  *         doesn't contain @node
 4659:  */
 4660: xmlNodeSetPtr
 4661: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4662:     int i, l;
 4663:     xmlNodePtr cur;
 4664:     xmlNodeSetPtr ret;
 4665: 
 4666:     if (node == NULL)
 4667: 	return(nodes);
 4668: 
 4669:     ret = xmlXPathNodeSetCreate(NULL);
 4670:     if (ret == NULL)
 4671:         return(ret);
 4672:     if (xmlXPathNodeSetIsEmpty(nodes) ||
 4673: 	(!xmlXPathNodeSetContains(nodes, node)))
 4674: 	return(ret);
 4675: 
 4676:     l = xmlXPathNodeSetGetLength(nodes);
 4677:     for (i = l - 1; i >= 0; i--) {
 4678: 	cur = xmlXPathNodeSetItem(nodes, i);
 4679: 	if (cur == node)
 4680: 	    break;
 4681: 	xmlXPathNodeSetAddUnique(ret, cur);
 4682:     }
 4683:     xmlXPathNodeSetSort(ret);	/* bug 413451 */
 4684:     return(ret);
 4685: }
 4686: 
 4687: /**
 4688:  * xmlXPathNodeTrailing:
 4689:  * @nodes:  a node-set
 4690:  * @node:  a node
 4691:  *
 4692:  * Implements the EXSLT - Sets trailing() function:
 4693:  *    node-set set:trailing (node-set, node-set)
 4694:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
 4695:  * is called.
 4696:  *
 4697:  * Returns the nodes in @nodes that follow @node in document order,
 4698:  *         @nodes if @node is NULL or an empty node-set if @nodes
 4699:  *         doesn't contain @node
 4700:  */
 4701: xmlNodeSetPtr
 4702: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
 4703:     xmlXPathNodeSetSort(nodes);
 4704:     return(xmlXPathNodeTrailingSorted(nodes, node));
 4705: }
 4706: 
 4707: /**
 4708:  * xmlXPathTrailingSorted:
 4709:  * @nodes1:  a node-set, sorted by document order
 4710:  * @nodes2:  a node-set, sorted by document order
 4711:  *
 4712:  * Implements the EXSLT - Sets trailing() function:
 4713:  *    node-set set:trailing (node-set, node-set)
 4714:  *
 4715:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4716:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4717:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4718:  */
 4719: xmlNodeSetPtr
 4720: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4721:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4722: 	return(nodes1);
 4723:     return(xmlXPathNodeTrailingSorted(nodes1,
 4724: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4725: }
 4726: 
 4727: /**
 4728:  * xmlXPathTrailing:
 4729:  * @nodes1:  a node-set
 4730:  * @nodes2:  a node-set
 4731:  *
 4732:  * Implements the EXSLT - Sets trailing() function:
 4733:  *    node-set set:trailing (node-set, node-set)
 4734:  * @nodes1 and @nodes2 are sorted by document order, then
 4735:  * #xmlXPathTrailingSorted is called.
 4736:  *
 4737:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
 4738:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
 4739:  *         an empty node-set if @nodes1 doesn't contain @nodes2
 4740:  */
 4741: xmlNodeSetPtr
 4742: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
 4743:     if (xmlXPathNodeSetIsEmpty(nodes2))
 4744: 	return(nodes1);
 4745:     if (xmlXPathNodeSetIsEmpty(nodes1))
 4746: 	return(xmlXPathNodeSetCreate(NULL));
 4747:     xmlXPathNodeSetSort(nodes1);
 4748:     xmlXPathNodeSetSort(nodes2);
 4749:     return(xmlXPathNodeTrailingSorted(nodes1,
 4750: 				      xmlXPathNodeSetItem(nodes2, 0)));
 4751: }
 4752: 
 4753: /************************************************************************
 4754:  *									*
 4755:  *		Routines to handle extra functions			*
 4756:  *									*
 4757:  ************************************************************************/
 4758: 
 4759: /**
 4760:  * xmlXPathRegisterFunc:
 4761:  * @ctxt:  the XPath context
 4762:  * @name:  the function name
 4763:  * @f:  the function implementation or NULL
 4764:  *
 4765:  * Register a new function. If @f is NULL it unregisters the function
 4766:  *
 4767:  * Returns 0 in case of success, -1 in case of error
 4768:  */
 4769: int
 4770: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
 4771: 		     xmlXPathFunction f) {
 4772:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
 4773: }
 4774: 
 4775: /**
 4776:  * xmlXPathRegisterFuncNS:
 4777:  * @ctxt:  the XPath context
 4778:  * @name:  the function name
 4779:  * @ns_uri:  the function namespace URI
 4780:  * @f:  the function implementation or NULL
 4781:  *
 4782:  * Register a new function. If @f is NULL it unregisters the function
 4783:  *
 4784:  * Returns 0 in case of success, -1 in case of error
 4785:  */
 4786: int
 4787: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4788: 		       const xmlChar *ns_uri, xmlXPathFunction f) {
 4789:     if (ctxt == NULL)
 4790: 	return(-1);
 4791:     if (name == NULL)
 4792: 	return(-1);
 4793: 
 4794:     if (ctxt->funcHash == NULL)
 4795: 	ctxt->funcHash = xmlHashCreate(0);
 4796:     if (ctxt->funcHash == NULL)
 4797: 	return(-1);
 4798:     if (f == NULL)
 4799:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
 4800:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
 4801: }
 4802: 
 4803: /**
 4804:  * xmlXPathRegisterFuncLookup:
 4805:  * @ctxt:  the XPath context
 4806:  * @f:  the lookup function
 4807:  * @funcCtxt:  the lookup data
 4808:  *
 4809:  * Registers an external mechanism to do function lookup.
 4810:  */
 4811: void
 4812: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
 4813: 			    xmlXPathFuncLookupFunc f,
 4814: 			    void *funcCtxt) {
 4815:     if (ctxt == NULL)
 4816: 	return;
 4817:     ctxt->funcLookupFunc = f;
 4818:     ctxt->funcLookupData = funcCtxt;
 4819: }
 4820: 
 4821: /**
 4822:  * xmlXPathFunctionLookup:
 4823:  * @ctxt:  the XPath context
 4824:  * @name:  the function name
 4825:  *
 4826:  * Search in the Function array of the context for the given
 4827:  * function.
 4828:  *
 4829:  * Returns the xmlXPathFunction or NULL if not found
 4830:  */
 4831: xmlXPathFunction
 4832: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 4833:     if (ctxt == NULL)
 4834: 	return (NULL);
 4835: 
 4836:     if (ctxt->funcLookupFunc != NULL) {
 4837: 	xmlXPathFunction ret;
 4838: 	xmlXPathFuncLookupFunc f;
 4839: 
 4840: 	f = ctxt->funcLookupFunc;
 4841: 	ret = f(ctxt->funcLookupData, name, NULL);
 4842: 	if (ret != NULL)
 4843: 	    return(ret);
 4844:     }
 4845:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
 4846: }
 4847: 
 4848: /**
 4849:  * xmlXPathFunctionLookupNS:
 4850:  * @ctxt:  the XPath context
 4851:  * @name:  the function name
 4852:  * @ns_uri:  the function namespace URI
 4853:  *
 4854:  * Search in the Function array of the context for the given
 4855:  * function.
 4856:  *
 4857:  * Returns the xmlXPathFunction or NULL if not found
 4858:  */
 4859: xmlXPathFunction
 4860: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4861: 			 const xmlChar *ns_uri) {
 4862:     xmlXPathFunction ret;
 4863: 
 4864:     if (ctxt == NULL)
 4865: 	return(NULL);
 4866:     if (name == NULL)
 4867: 	return(NULL);
 4868: 
 4869:     if (ctxt->funcLookupFunc != NULL) {
 4870: 	xmlXPathFuncLookupFunc f;
 4871: 
 4872: 	f = ctxt->funcLookupFunc;
 4873: 	ret = f(ctxt->funcLookupData, name, ns_uri);
 4874: 	if (ret != NULL)
 4875: 	    return(ret);
 4876:     }
 4877: 
 4878:     if (ctxt->funcHash == NULL)
 4879: 	return(NULL);
 4880: 
 4881:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
 4882:     return(ret);
 4883: }
 4884: 
 4885: /**
 4886:  * xmlXPathRegisteredFuncsCleanup:
 4887:  * @ctxt:  the XPath context
 4888:  *
 4889:  * Cleanup the XPath context data associated to registered functions
 4890:  */
 4891: void
 4892: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
 4893:     if (ctxt == NULL)
 4894: 	return;
 4895: 
 4896:     xmlHashFree(ctxt->funcHash, NULL);
 4897:     ctxt->funcHash = NULL;
 4898: }
 4899: 
 4900: /************************************************************************
 4901:  *									*
 4902:  *			Routines to handle Variables			*
 4903:  *									*
 4904:  ************************************************************************/
 4905: 
 4906: /**
 4907:  * xmlXPathRegisterVariable:
 4908:  * @ctxt:  the XPath context
 4909:  * @name:  the variable name
 4910:  * @value:  the variable value or NULL
 4911:  *
 4912:  * Register a new variable value. If @value is NULL it unregisters
 4913:  * the variable
 4914:  *
 4915:  * Returns 0 in case of success, -1 in case of error
 4916:  */
 4917: int
 4918: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
 4919: 			 xmlXPathObjectPtr value) {
 4920:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
 4921: }
 4922: 
 4923: /**
 4924:  * xmlXPathRegisterVariableNS:
 4925:  * @ctxt:  the XPath context
 4926:  * @name:  the variable name
 4927:  * @ns_uri:  the variable namespace URI
 4928:  * @value:  the variable value or NULL
 4929:  *
 4930:  * Register a new variable value. If @value is NULL it unregisters
 4931:  * the variable
 4932:  *
 4933:  * Returns 0 in case of success, -1 in case of error
 4934:  */
 4935: int
 4936: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 4937: 			   const xmlChar *ns_uri,
 4938: 			   xmlXPathObjectPtr value) {
 4939:     if (ctxt == NULL)
 4940: 	return(-1);
 4941:     if (name == NULL)
 4942: 	return(-1);
 4943: 
 4944:     if (ctxt->varHash == NULL)
 4945: 	ctxt->varHash = xmlHashCreate(0);
 4946:     if (ctxt->varHash == NULL)
 4947: 	return(-1);
 4948:     if (value == NULL)
 4949:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
 4950: 	                           (xmlHashDeallocator)xmlXPathFreeObject));
 4951:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
 4952: 			       (void *) value,
 4953: 			       (xmlHashDeallocator)xmlXPathFreeObject));
 4954: }
 4955: 
 4956: /**
 4957:  * xmlXPathRegisterVariableLookup:
 4958:  * @ctxt:  the XPath context
 4959:  * @f:  the lookup function
 4960:  * @data:  the lookup data
 4961:  *
 4962:  * register an external mechanism to do variable lookup
 4963:  */
 4964: void
 4965: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
 4966: 	 xmlXPathVariableLookupFunc f, void *data) {
 4967:     if (ctxt == NULL)
 4968: 	return;
 4969:     ctxt->varLookupFunc = f;
 4970:     ctxt->varLookupData = data;
 4971: }
 4972: 
 4973: /**
 4974:  * xmlXPathVariableLookup:
 4975:  * @ctxt:  the XPath context
 4976:  * @name:  the variable name
 4977:  *
 4978:  * Search in the Variable array of the context for the given
 4979:  * variable value.
 4980:  *
 4981:  * Returns a copy of the value or NULL if not found
 4982:  */
 4983: xmlXPathObjectPtr
 4984: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
 4985:     if (ctxt == NULL)
 4986: 	return(NULL);
 4987: 
 4988:     if (ctxt->varLookupFunc != NULL) {
 4989: 	xmlXPathObjectPtr ret;
 4990: 
 4991: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 4992: 	        (ctxt->varLookupData, name, NULL);
 4993: 	return(ret);
 4994:     }
 4995:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
 4996: }
 4997: 
 4998: /**
 4999:  * xmlXPathVariableLookupNS:
 5000:  * @ctxt:  the XPath context
 5001:  * @name:  the variable name
 5002:  * @ns_uri:  the variable namespace URI
 5003:  *
 5004:  * Search in the Variable array of the context for the given
 5005:  * variable value.
 5006:  *
 5007:  * Returns the a copy of the value or NULL if not found
 5008:  */
 5009: xmlXPathObjectPtr
 5010: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
 5011: 			 const xmlChar *ns_uri) {
 5012:     if (ctxt == NULL)
 5013: 	return(NULL);
 5014: 
 5015:     if (ctxt->varLookupFunc != NULL) {
 5016: 	xmlXPathObjectPtr ret;
 5017: 
 5018: 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
 5019: 	        (ctxt->varLookupData, name, ns_uri);
 5020: 	if (ret != NULL) return(ret);
 5021:     }
 5022: 
 5023:     if (ctxt->varHash == NULL)
 5024: 	return(NULL);
 5025:     if (name == NULL)
 5026: 	return(NULL);
 5027: 
 5028:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
 5029: 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
 5030: }
 5031: 
 5032: /**
 5033:  * xmlXPathRegisteredVariablesCleanup:
 5034:  * @ctxt:  the XPath context
 5035:  *
 5036:  * Cleanup the XPath context data associated to registered variables
 5037:  */
 5038: void
 5039: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
 5040:     if (ctxt == NULL)
 5041: 	return;
 5042: 
 5043:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
 5044:     ctxt->varHash = NULL;
 5045: }
 5046: 
 5047: /**
 5048:  * xmlXPathRegisterNs:
 5049:  * @ctxt:  the XPath context
 5050:  * @prefix:  the namespace prefix cannot be NULL or empty string
 5051:  * @ns_uri:  the namespace name
 5052:  *
 5053:  * Register a new namespace. If @ns_uri is NULL it unregisters
 5054:  * the namespace
 5055:  *
 5056:  * Returns 0 in case of success, -1 in case of error
 5057:  */
 5058: int
 5059: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
 5060: 			   const xmlChar *ns_uri) {
 5061:     if (ctxt == NULL)
 5062: 	return(-1);
 5063:     if (prefix == NULL)
 5064: 	return(-1);
 5065:     if (prefix[0] == 0)
 5066: 	return(-1);
 5067: 
 5068:     if (ctxt->nsHash == NULL)
 5069: 	ctxt->nsHash = xmlHashCreate(10);
 5070:     if (ctxt->nsHash == NULL)
 5071: 	return(-1);
 5072:     if (ns_uri == NULL)
 5073:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
 5074: 	                          (xmlHashDeallocator)xmlFree));
 5075:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
 5076: 			      (xmlHashDeallocator)xmlFree));
 5077: }
 5078: 
 5079: /**
 5080:  * xmlXPathNsLookup:
 5081:  * @ctxt:  the XPath context
 5082:  * @prefix:  the namespace prefix value
 5083:  *
 5084:  * Search in the namespace declaration array of the context for the given
 5085:  * namespace name associated to the given prefix
 5086:  *
 5087:  * Returns the value or NULL if not found
 5088:  */
 5089: const xmlChar *
 5090: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
 5091:     if (ctxt == NULL)
 5092: 	return(NULL);
 5093:     if (prefix == NULL)
 5094: 	return(NULL);
 5095: 
 5096: #ifdef XML_XML_NAMESPACE
 5097:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
 5098: 	return(XML_XML_NAMESPACE);
 5099: #endif
 5100: 
 5101:     if (ctxt->namespaces != NULL) {
 5102: 	int i;
 5103: 
 5104: 	for (i = 0;i < ctxt->nsNr;i++) {
 5105: 	    if ((ctxt->namespaces[i] != NULL) &&
 5106: 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
 5107: 		return(ctxt->namespaces[i]->href);
 5108: 	}
 5109:     }
 5110: 
 5111:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
 5112: }
 5113: 
 5114: /**
 5115:  * xmlXPathRegisteredNsCleanup:
 5116:  * @ctxt:  the XPath context
 5117:  *
 5118:  * Cleanup the XPath context data associated to registered variables
 5119:  */
 5120: void
 5121: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
 5122:     if (ctxt == NULL)
 5123: 	return;
 5124: 
 5125:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
 5126:     ctxt->nsHash = NULL;
 5127: }
 5128: 
 5129: /************************************************************************
 5130:  *									*
 5131:  *			Routines to handle Values			*
 5132:  *									*
 5133:  ************************************************************************/
 5134: 
 5135: /* Allocations are terrible, one needs to optimize all this !!! */
 5136: 
 5137: /**
 5138:  * xmlXPathNewFloat:
 5139:  * @val:  the double value
 5140:  *
 5141:  * Create a new xmlXPathObjectPtr of type double and of value @val
 5142:  *
 5143:  * Returns the newly created object.
 5144:  */
 5145: xmlXPathObjectPtr
 5146: xmlXPathNewFloat(double val) {
 5147:     xmlXPathObjectPtr ret;
 5148: 
 5149:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5150:     if (ret == NULL) {
 5151:         xmlXPathErrMemory(NULL, "creating float object\n");
 5152: 	return(NULL);
 5153:     }
 5154:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5155:     ret->type = XPATH_NUMBER;
 5156:     ret->floatval = val;
 5157: #ifdef XP_DEBUG_OBJ_USAGE
 5158:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
 5159: #endif
 5160:     return(ret);
 5161: }
 5162: 
 5163: /**
 5164:  * xmlXPathNewBoolean:
 5165:  * @val:  the boolean value
 5166:  *
 5167:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
 5168:  *
 5169:  * Returns the newly created object.
 5170:  */
 5171: xmlXPathObjectPtr
 5172: xmlXPathNewBoolean(int val) {
 5173:     xmlXPathObjectPtr ret;
 5174: 
 5175:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5176:     if (ret == NULL) {
 5177:         xmlXPathErrMemory(NULL, "creating boolean object\n");
 5178: 	return(NULL);
 5179:     }
 5180:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5181:     ret->type = XPATH_BOOLEAN;
 5182:     ret->boolval = (val != 0);
 5183: #ifdef XP_DEBUG_OBJ_USAGE
 5184:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
 5185: #endif
 5186:     return(ret);
 5187: }
 5188: 
 5189: /**
 5190:  * xmlXPathNewString:
 5191:  * @val:  the xmlChar * value
 5192:  *
 5193:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5194:  *
 5195:  * Returns the newly created object.
 5196:  */
 5197: xmlXPathObjectPtr
 5198: xmlXPathNewString(const xmlChar *val) {
 5199:     xmlXPathObjectPtr ret;
 5200: 
 5201:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5202:     if (ret == NULL) {
 5203:         xmlXPathErrMemory(NULL, "creating string object\n");
 5204: 	return(NULL);
 5205:     }
 5206:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5207:     ret->type = XPATH_STRING;
 5208:     if (val != NULL)
 5209: 	ret->stringval = xmlStrdup(val);
 5210:     else
 5211: 	ret->stringval = xmlStrdup((const xmlChar *)"");
 5212: #ifdef XP_DEBUG_OBJ_USAGE
 5213:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5214: #endif
 5215:     return(ret);
 5216: }
 5217: 
 5218: /**
 5219:  * xmlXPathWrapString:
 5220:  * @val:  the xmlChar * value
 5221:  *
 5222:  * Wraps the @val string into an XPath object.
 5223:  *
 5224:  * Returns the newly created object.
 5225:  */
 5226: xmlXPathObjectPtr
 5227: xmlXPathWrapString (xmlChar *val) {
 5228:     xmlXPathObjectPtr ret;
 5229: 
 5230:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5231:     if (ret == NULL) {
 5232:         xmlXPathErrMemory(NULL, "creating string object\n");
 5233: 	return(NULL);
 5234:     }
 5235:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5236:     ret->type = XPATH_STRING;
 5237:     ret->stringval = val;
 5238: #ifdef XP_DEBUG_OBJ_USAGE
 5239:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5240: #endif
 5241:     return(ret);
 5242: }
 5243: 
 5244: /**
 5245:  * xmlXPathNewCString:
 5246:  * @val:  the char * value
 5247:  *
 5248:  * Create a new xmlXPathObjectPtr of type string and of value @val
 5249:  *
 5250:  * Returns the newly created object.
 5251:  */
 5252: xmlXPathObjectPtr
 5253: xmlXPathNewCString(const char *val) {
 5254:     xmlXPathObjectPtr ret;
 5255: 
 5256:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5257:     if (ret == NULL) {
 5258:         xmlXPathErrMemory(NULL, "creating string object\n");
 5259: 	return(NULL);
 5260:     }
 5261:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5262:     ret->type = XPATH_STRING;
 5263:     ret->stringval = xmlStrdup(BAD_CAST val);
 5264: #ifdef XP_DEBUG_OBJ_USAGE
 5265:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
 5266: #endif
 5267:     return(ret);
 5268: }
 5269: 
 5270: /**
 5271:  * xmlXPathWrapCString:
 5272:  * @val:  the char * value
 5273:  *
 5274:  * Wraps a string into an XPath object.
 5275:  *
 5276:  * Returns the newly created object.
 5277:  */
 5278: xmlXPathObjectPtr
 5279: xmlXPathWrapCString (char * val) {
 5280:     return(xmlXPathWrapString((xmlChar *)(val)));
 5281: }
 5282: 
 5283: /**
 5284:  * xmlXPathWrapExternal:
 5285:  * @val:  the user data
 5286:  *
 5287:  * Wraps the @val data into an XPath object.
 5288:  *
 5289:  * Returns the newly created object.
 5290:  */
 5291: xmlXPathObjectPtr
 5292: xmlXPathWrapExternal (void *val) {
 5293:     xmlXPathObjectPtr ret;
 5294: 
 5295:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5296:     if (ret == NULL) {
 5297:         xmlXPathErrMemory(NULL, "creating user object\n");
 5298: 	return(NULL);
 5299:     }
 5300:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
 5301:     ret->type = XPATH_USERS;
 5302:     ret->user = val;
 5303: #ifdef XP_DEBUG_OBJ_USAGE
 5304:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
 5305: #endif
 5306:     return(ret);
 5307: }
 5308: 
 5309: /**
 5310:  * xmlXPathObjectCopy:
 5311:  * @val:  the original object
 5312:  *
 5313:  * allocate a new copy of a given object
 5314:  *
 5315:  * Returns the newly created object.
 5316:  */
 5317: xmlXPathObjectPtr
 5318: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
 5319:     xmlXPathObjectPtr ret;
 5320: 
 5321:     if (val == NULL)
 5322: 	return(NULL);
 5323: 
 5324:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
 5325:     if (ret == NULL) {
 5326:         xmlXPathErrMemory(NULL, "copying object\n");
 5327: 	return(NULL);
 5328:     }
 5329:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
 5330: #ifdef XP_DEBUG_OBJ_USAGE
 5331:     xmlXPathDebugObjUsageRequested(NULL, val->type);
 5332: #endif
 5333:     switch (val->type) {
 5334: 	case XPATH_BOOLEAN:
 5335: 	case XPATH_NUMBER:
 5336: 	case XPATH_POINT:
 5337: 	case XPATH_RANGE:
 5338: 	    break;
 5339: 	case XPATH_STRING:
 5340: 	    ret->stringval = xmlStrdup(val->stringval);
 5341: 	    break;
 5342: 	case XPATH_XSLT_TREE:
 5343: #if 0
 5344: /*
 5345:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
 5346:   this previous handling is no longer correct, and can cause some serious
 5347:   problems (ref. bug 145547)
 5348: */
 5349: 	    if ((val->nodesetval != NULL) &&
 5350: 		(val->nodesetval->nodeTab != NULL)) {
 5351: 		xmlNodePtr cur, tmp;
 5352: 		xmlDocPtr top;
 5353: 
 5354: 		ret->boolval = 1;
 5355: 		top =  xmlNewDoc(NULL);
 5356: 		top->name = (char *)
 5357: 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
 5358: 		ret->user = top;
 5359: 		if (top != NULL) {
 5360: 		    top->doc = top;
 5361: 		    cur = val->nodesetval->nodeTab[0]->children;
 5362: 		    while (cur != NULL) {
 5363: 			tmp = xmlDocCopyNode(cur, top, 1);
 5364: 			xmlAddChild((xmlNodePtr) top, tmp);
 5365: 			cur = cur->next;
 5366: 		    }
 5367: 		}
 5368: 
 5369: 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
 5370: 	    } else
 5371: 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
 5372: 	    /* Deallocate the copied tree value */
 5373: 	    break;
 5374: #endif
 5375: 	case XPATH_NODESET:
 5376: 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
 5377: 	    /* Do not deallocate the copied tree value */
 5378: 	    ret->boolval = 0;
 5379: 	    break;
 5380: 	case XPATH_LOCATIONSET:
 5381: #ifdef LIBXML_XPTR_ENABLED
 5382: 	{
 5383: 	    xmlLocationSetPtr loc = val->user;
 5384: 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
 5385: 	    break;
 5386: 	}
 5387: #endif
 5388:         case XPATH_USERS:
 5389: 	    ret->user = val->user;
 5390: 	    break;
 5391:         case XPATH_UNDEFINED:
 5392: 	    xmlGenericError(xmlGenericErrorContext,
 5393: 		    "xmlXPathObjectCopy: unsupported type %d\n",
 5394: 		    val->type);
 5395: 	    break;
 5396:     }
 5397:     return(ret);
 5398: }
 5399: 
 5400: /**
 5401:  * xmlXPathFreeObject:
 5402:  * @obj:  the object to free
 5403:  *
 5404:  * Free up an xmlXPathObjectPtr object.
 5405:  */
 5406: void
 5407: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
 5408:     if (obj == NULL) return;
 5409:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 5410: 	if (obj->boolval) {
 5411: #if 0
 5412: 	    if (obj->user != NULL) {
 5413:                 xmlXPathFreeNodeSet(obj->nodesetval);
 5414: 		xmlFreeNodeList((xmlNodePtr) obj->user);
 5415: 	    } else
 5416: #endif
 5417: 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
 5418: 	    if (obj->nodesetval != NULL)
 5419: 		xmlXPathFreeValueTree(obj->nodesetval);
 5420: 	} else {
 5421: 	    if (obj->nodesetval != NULL)
 5422: 		xmlXPathFreeNodeSet(obj->nodesetval);
 5423: 	}
 5424: #ifdef LIBXML_XPTR_ENABLED
 5425:     } else if (obj->type == XPATH_LOCATIONSET) {
 5426: 	if (obj->user != NULL)
 5427: 	    xmlXPtrFreeLocationSet(obj->user);
 5428: #endif
 5429:     } else if (obj->type == XPATH_STRING) {
 5430: 	if (obj->stringval != NULL)
 5431: 	    xmlFree(obj->stringval);
 5432:     }
 5433: #ifdef XP_DEBUG_OBJ_USAGE
 5434:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5435: #endif
 5436:     xmlFree(obj);
 5437: }
 5438: 
 5439: /**
 5440:  * xmlXPathReleaseObject:
 5441:  * @obj:  the xmlXPathObjectPtr to free or to cache
 5442:  *
 5443:  * Depending on the state of the cache this frees the given
 5444:  * XPath object or stores it in the cache.
 5445:  */
 5446: static void
 5447: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
 5448: {
 5449: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
 5450: 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
 5451:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
 5452: 
 5453: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
 5454: 
 5455:     if (obj == NULL)
 5456: 	return;
 5457:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
 5458: 	 xmlXPathFreeObject(obj);
 5459:     } else {
 5460: 	xmlXPathContextCachePtr cache =
 5461: 	    (xmlXPathContextCachePtr) ctxt->cache;
 5462: 
 5463: 	switch (obj->type) {
 5464: 	    case XPATH_NODESET:
 5465: 	    case XPATH_XSLT_TREE:
 5466: 		if (obj->nodesetval != NULL) {
 5467: 		    if (obj->boolval) {
 5468: 			/*
 5469: 			* It looks like the @boolval is used for
 5470: 			* evaluation if this an XSLT Result Tree Fragment.
 5471: 			* TODO: Check if this assumption is correct.
 5472: 			*/
 5473: 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
 5474: 			xmlXPathFreeValueTree(obj->nodesetval);
 5475: 			obj->nodesetval = NULL;
 5476: 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
 5477: 			(XP_CACHE_WANTS(cache->nodesetObjs,
 5478: 					cache->maxNodeset)))
 5479: 		    {
 5480: 			XP_CACHE_ADD(cache->nodesetObjs, obj);
 5481: 			goto obj_cached;
 5482: 		    } else {
 5483: 			xmlXPathFreeNodeSet(obj->nodesetval);
 5484: 			obj->nodesetval = NULL;
 5485: 		    }
 5486: 		}
 5487: 		break;
 5488: 	    case XPATH_STRING:
 5489: 		if (obj->stringval != NULL)
 5490: 		    xmlFree(obj->stringval);
 5491: 
 5492: 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
 5493: 		    XP_CACHE_ADD(cache->stringObjs, obj);
 5494: 		    goto obj_cached;
 5495: 		}
 5496: 		break;
 5497: 	    case XPATH_BOOLEAN:
 5498: 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
 5499: 		    XP_CACHE_ADD(cache->booleanObjs, obj);
 5500: 		    goto obj_cached;
 5501: 		}
 5502: 		break;
 5503: 	    case XPATH_NUMBER:
 5504: 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
 5505: 		    XP_CACHE_ADD(cache->numberObjs, obj);
 5506: 		    goto obj_cached;
 5507: 		}
 5508: 		break;
 5509: #ifdef LIBXML_XPTR_ENABLED
 5510: 	    case XPATH_LOCATIONSET:
 5511: 		if (obj->user != NULL) {
 5512: 		    xmlXPtrFreeLocationSet(obj->user);
 5513: 		}
 5514: 		goto free_obj;
 5515: #endif
 5516: 	    default:
 5517: 		goto free_obj;
 5518: 	}
 5519: 
 5520: 	/*
 5521: 	* Fallback to adding to the misc-objects slot.
 5522: 	*/
 5523: 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
 5524: 	    XP_CACHE_ADD(cache->miscObjs, obj);
 5525: 	} else
 5526: 	    goto free_obj;
 5527: 
 5528: obj_cached:
 5529: 
 5530: #ifdef XP_DEBUG_OBJ_USAGE
 5531: 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
 5532: #endif
 5533: 
 5534: 	if (obj->nodesetval != NULL) {
 5535: 	    xmlNodeSetPtr tmpset = obj->nodesetval;
 5536: 
 5537: 	    /*
 5538: 	    * TODO: Due to those nasty ns-nodes, we need to traverse
 5539: 	    *  the list and free the ns-nodes.
 5540: 	    * URGENT TODO: Check if it's actually slowing things down.
 5541: 	    *  Maybe we shouldn't try to preserve the list.
 5542: 	    */
 5543: 	    if (tmpset->nodeNr > 1) {
 5544: 		int i;
 5545: 		xmlNodePtr node;
 5546: 
 5547: 		for (i = 0; i < tmpset->nodeNr; i++) {
 5548: 		    node = tmpset->nodeTab[i];
 5549: 		    if ((node != NULL) &&
 5550: 			(node->type == XML_NAMESPACE_DECL))
 5551: 		    {
 5552: 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
 5553: 		    }
 5554: 		}
 5555: 	    } else if (tmpset->nodeNr == 1) {
 5556: 		if ((tmpset->nodeTab[0] != NULL) &&
 5557: 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
 5558: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
 5559: 	    }
 5560: 	    tmpset->nodeNr = 0;
 5561: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5562: 	    obj->nodesetval = tmpset;
 5563: 	} else
 5564: 	    memset(obj, 0, sizeof(xmlXPathObject));
 5565: 
 5566: 	return;
 5567: 
 5568: free_obj:
 5569: 	/*
 5570: 	* Cache is full; free the object.
 5571: 	*/
 5572: 	if (obj->nodesetval != NULL)
 5573: 	    xmlXPathFreeNodeSet(obj->nodesetval);
 5574: #ifdef XP_DEBUG_OBJ_USAGE
 5575: 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
 5576: #endif
 5577: 	xmlFree(obj);
 5578:     }
 5579:     return;
 5580: }
 5581: 
 5582: 
 5583: /************************************************************************
 5584:  *									*
 5585:  *			Type Casting Routines				*
 5586:  *									*
 5587:  ************************************************************************/
 5588: 
 5589: /**
 5590:  * xmlXPathCastBooleanToString:
 5591:  * @val:  a boolean
 5592:  *
 5593:  * Converts a boolean to its string value.
 5594:  *
 5595:  * Returns a newly allocated string.
 5596:  */
 5597: xmlChar *
 5598: xmlXPathCastBooleanToString (int val) {
 5599:     xmlChar *ret;
 5600:     if (val)
 5601: 	ret = xmlStrdup((const xmlChar *) "true");
 5602:     else
 5603: 	ret = xmlStrdup((const xmlChar *) "false");
 5604:     return(ret);
 5605: }
 5606: 
 5607: /**
 5608:  * xmlXPathCastNumberToString:
 5609:  * @val:  a number
 5610:  *
 5611:  * Converts a number to its string value.
 5612:  *
 5613:  * Returns a newly allocated string.
 5614:  */
 5615: xmlChar *
 5616: xmlXPathCastNumberToString (double val) {
 5617:     xmlChar *ret;
 5618:     switch (xmlXPathIsInf(val)) {
 5619:     case 1:
 5620: 	ret = xmlStrdup((const xmlChar *) "Infinity");
 5621: 	break;
 5622:     case -1:
 5623: 	ret = xmlStrdup((const xmlChar *) "-Infinity");
 5624: 	break;
 5625:     default:
 5626: 	if (xmlXPathIsNaN(val)) {
 5627: 	    ret = xmlStrdup((const xmlChar *) "NaN");
 5628: 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
 5629: 	    ret = xmlStrdup((const xmlChar *) "0");
 5630: 	} else {
 5631: 	    /* could be improved */
 5632: 	    char buf[100];
 5633: 	    xmlXPathFormatNumber(val, buf, 99);
 5634: 	    buf[99] = 0;
 5635: 	    ret = xmlStrdup((const xmlChar *) buf);
 5636: 	}
 5637:     }
 5638:     return(ret);
 5639: }
 5640: 
 5641: /**
 5642:  * xmlXPathCastNodeToString:
 5643:  * @node:  a node
 5644:  *
 5645:  * Converts a node to its string value.
 5646:  *
 5647:  * Returns a newly allocated string.
 5648:  */
 5649: xmlChar *
 5650: xmlXPathCastNodeToString (xmlNodePtr node) {
 5651: xmlChar *ret;
 5652:     if ((ret = xmlNodeGetContent(node)) == NULL)
 5653: 	ret = xmlStrdup((const xmlChar *) "");
 5654:     return(ret);
 5655: }
 5656: 
 5657: /**
 5658:  * xmlXPathCastNodeSetToString:
 5659:  * @ns:  a node-set
 5660:  *
 5661:  * Converts a node-set to its string value.
 5662:  *
 5663:  * Returns a newly allocated string.
 5664:  */
 5665: xmlChar *
 5666: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
 5667:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
 5668: 	return(xmlStrdup((const xmlChar *) ""));
 5669: 
 5670:     if (ns->nodeNr > 1)
 5671: 	xmlXPathNodeSetSort(ns);
 5672:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
 5673: }
 5674: 
 5675: /**
 5676:  * xmlXPathCastToString:
 5677:  * @val:  an XPath object
 5678:  *
 5679:  * Converts an existing object to its string() equivalent
 5680:  *
 5681:  * Returns the allocated string value of the object, NULL in case of error.
 5682:  *         It's up to the caller to free the string memory with xmlFree().
 5683:  */
 5684: xmlChar *
 5685: xmlXPathCastToString(xmlXPathObjectPtr val) {
 5686:     xmlChar *ret = NULL;
 5687: 
 5688:     if (val == NULL)
 5689: 	return(xmlStrdup((const xmlChar *) ""));
 5690:     switch (val->type) {
 5691: 	case XPATH_UNDEFINED:
 5692: #ifdef DEBUG_EXPR
 5693: 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
 5694: #endif
 5695: 	    ret = xmlStrdup((const xmlChar *) "");
 5696: 	    break;
 5697:         case XPATH_NODESET:
 5698:         case XPATH_XSLT_TREE:
 5699: 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
 5700: 	    break;
 5701: 	case XPATH_STRING:
 5702: 	    return(xmlStrdup(val->stringval));
 5703:         case XPATH_BOOLEAN:
 5704: 	    ret = xmlXPathCastBooleanToString(val->boolval);
 5705: 	    break;
 5706: 	case XPATH_NUMBER: {
 5707: 	    ret = xmlXPathCastNumberToString(val->floatval);
 5708: 	    break;
 5709: 	}
 5710: 	case XPATH_USERS:
 5711: 	case XPATH_POINT:
 5712: 	case XPATH_RANGE:
 5713: 	case XPATH_LOCATIONSET:
 5714: 	    TODO
 5715: 	    ret = xmlStrdup((const xmlChar *) "");
 5716: 	    break;
 5717:     }
 5718:     return(ret);
 5719: }
 5720: 
 5721: /**
 5722:  * xmlXPathConvertString:
 5723:  * @val:  an XPath object
 5724:  *
 5725:  * Converts an existing object to its string() equivalent
 5726:  *
 5727:  * Returns the new object, the old one is freed (or the operation
 5728:  *         is done directly on @val)
 5729:  */
 5730: xmlXPathObjectPtr
 5731: xmlXPathConvertString(xmlXPathObjectPtr val) {
 5732:     xmlChar *res = NULL;
 5733: 
 5734:     if (val == NULL)
 5735: 	return(xmlXPathNewCString(""));
 5736: 
 5737:     switch (val->type) {
 5738:     case XPATH_UNDEFINED:
 5739: #ifdef DEBUG_EXPR
 5740: 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
 5741: #endif
 5742: 	break;
 5743:     case XPATH_NODESET:
 5744:     case XPATH_XSLT_TREE:
 5745: 	res = xmlXPathCastNodeSetToString(val->nodesetval);
 5746: 	break;
 5747:     case XPATH_STRING:
 5748: 	return(val);
 5749:     case XPATH_BOOLEAN:
 5750: 	res = xmlXPathCastBooleanToString(val->boolval);
 5751: 	break;
 5752:     case XPATH_NUMBER:
 5753: 	res = xmlXPathCastNumberToString(val->floatval);
 5754: 	break;
 5755:     case XPATH_USERS:
 5756:     case XPATH_POINT:
 5757:     case XPATH_RANGE:
 5758:     case XPATH_LOCATIONSET:
 5759: 	TODO;
 5760: 	break;
 5761:     }
 5762:     xmlXPathFreeObject(val);
 5763:     if (res == NULL)
 5764: 	return(xmlXPathNewCString(""));
 5765:     return(xmlXPathWrapString(res));
 5766: }
 5767: 
 5768: /**
 5769:  * xmlXPathCastBooleanToNumber:
 5770:  * @val:  a boolean
 5771:  *
 5772:  * Converts a boolean to its number value
 5773:  *
 5774:  * Returns the number value
 5775:  */
 5776: double
 5777: xmlXPathCastBooleanToNumber(int val) {
 5778:     if (val)
 5779: 	return(1.0);
 5780:     return(0.0);
 5781: }
 5782: 
 5783: /**
 5784:  * xmlXPathCastStringToNumber:
 5785:  * @val:  a string
 5786:  *
 5787:  * Converts a string to its number value
 5788:  *
 5789:  * Returns the number value
 5790:  */
 5791: double
 5792: xmlXPathCastStringToNumber(const xmlChar * val) {
 5793:     return(xmlXPathStringEvalNumber(val));
 5794: }
 5795: 
 5796: /**
 5797:  * xmlXPathCastNodeToNumber:
 5798:  * @node:  a node
 5799:  *
 5800:  * Converts a node to its number value
 5801:  *
 5802:  * Returns the number value
 5803:  */
 5804: double
 5805: xmlXPathCastNodeToNumber (xmlNodePtr node) {
 5806:     xmlChar *strval;
 5807:     double ret;
 5808: 
 5809:     if (node == NULL)
 5810: 	return(xmlXPathNAN);
 5811:     strval = xmlXPathCastNodeToString(node);
 5812:     if (strval == NULL)
 5813: 	return(xmlXPathNAN);
 5814:     ret = xmlXPathCastStringToNumber(strval);
 5815:     xmlFree(strval);
 5816: 
 5817:     return(ret);
 5818: }
 5819: 
 5820: /**
 5821:  * xmlXPathCastNodeSetToNumber:
 5822:  * @ns:  a node-set
 5823:  *
 5824:  * Converts a node-set to its number value
 5825:  *
 5826:  * Returns the number value
 5827:  */
 5828: double
 5829: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
 5830:     xmlChar *str;
 5831:     double ret;
 5832: 
 5833:     if (ns == NULL)
 5834: 	return(xmlXPathNAN);
 5835:     str = xmlXPathCastNodeSetToString(ns);
 5836:     ret = xmlXPathCastStringToNumber(str);
 5837:     xmlFree(str);
 5838:     return(ret);
 5839: }
 5840: 
 5841: /**
 5842:  * xmlXPathCastToNumber:
 5843:  * @val:  an XPath object
 5844:  *
 5845:  * Converts an XPath object to its number value
 5846:  *
 5847:  * Returns the number value
 5848:  */
 5849: double
 5850: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
 5851:     double ret = 0.0;
 5852: 
 5853:     if (val == NULL)
 5854: 	return(xmlXPathNAN);
 5855:     switch (val->type) {
 5856:     case XPATH_UNDEFINED:
 5857: #ifdef DEGUB_EXPR
 5858: 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
 5859: #endif
 5860: 	ret = xmlXPathNAN;
 5861: 	break;
 5862:     case XPATH_NODESET:
 5863:     case XPATH_XSLT_TREE:
 5864: 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
 5865: 	break;
 5866:     case XPATH_STRING:
 5867: 	ret = xmlXPathCastStringToNumber(val->stringval);
 5868: 	break;
 5869:     case XPATH_NUMBER:
 5870: 	ret = val->floatval;
 5871: 	break;
 5872:     case XPATH_BOOLEAN:
 5873: 	ret = xmlXPathCastBooleanToNumber(val->boolval);
 5874: 	break;
 5875:     case XPATH_USERS:
 5876:     case XPATH_POINT:
 5877:     case XPATH_RANGE:
 5878:     case XPATH_LOCATIONSET:
 5879: 	TODO;
 5880: 	ret = xmlXPathNAN;
 5881: 	break;
 5882:     }
 5883:     return(ret);
 5884: }
 5885: 
 5886: /**
 5887:  * xmlXPathConvertNumber:
 5888:  * @val:  an XPath object
 5889:  *
 5890:  * Converts an existing object to its number() equivalent
 5891:  *
 5892:  * Returns the new object, the old one is freed (or the operation
 5893:  *         is done directly on @val)
 5894:  */
 5895: xmlXPathObjectPtr
 5896: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
 5897:     xmlXPathObjectPtr ret;
 5898: 
 5899:     if (val == NULL)
 5900: 	return(xmlXPathNewFloat(0.0));
 5901:     if (val->type == XPATH_NUMBER)
 5902: 	return(val);
 5903:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
 5904:     xmlXPathFreeObject(val);
 5905:     return(ret);
 5906: }
 5907: 
 5908: /**
 5909:  * xmlXPathCastNumberToBoolean:
 5910:  * @val:  a number
 5911:  *
 5912:  * Converts a number to its boolean value
 5913:  *
 5914:  * Returns the boolean value
 5915:  */
 5916: int
 5917: xmlXPathCastNumberToBoolean (double val) {
 5918:      if (xmlXPathIsNaN(val) || (val == 0.0))
 5919: 	 return(0);
 5920:      return(1);
 5921: }
 5922: 
 5923: /**
 5924:  * xmlXPathCastStringToBoolean:
 5925:  * @val:  a string
 5926:  *
 5927:  * Converts a string to its boolean value
 5928:  *
 5929:  * Returns the boolean value
 5930:  */
 5931: int
 5932: xmlXPathCastStringToBoolean (const xmlChar *val) {
 5933:     if ((val == NULL) || (xmlStrlen(val) == 0))
 5934: 	return(0);
 5935:     return(1);
 5936: }
 5937: 
 5938: /**
 5939:  * xmlXPathCastNodeSetToBoolean:
 5940:  * @ns:  a node-set
 5941:  *
 5942:  * Converts a node-set to its boolean value
 5943:  *
 5944:  * Returns the boolean value
 5945:  */
 5946: int
 5947: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
 5948:     if ((ns == NULL) || (ns->nodeNr == 0))
 5949: 	return(0);
 5950:     return(1);
 5951: }
 5952: 
 5953: /**
 5954:  * xmlXPathCastToBoolean:
 5955:  * @val:  an XPath object
 5956:  *
 5957:  * Converts an XPath object to its boolean value
 5958:  *
 5959:  * Returns the boolean value
 5960:  */
 5961: int
 5962: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
 5963:     int ret = 0;
 5964: 
 5965:     if (val == NULL)
 5966: 	return(0);
 5967:     switch (val->type) {
 5968:     case XPATH_UNDEFINED:
 5969: #ifdef DEBUG_EXPR
 5970: 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
 5971: #endif
 5972: 	ret = 0;
 5973: 	break;
 5974:     case XPATH_NODESET:
 5975:     case XPATH_XSLT_TREE:
 5976: 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
 5977: 	break;
 5978:     case XPATH_STRING:
 5979: 	ret = xmlXPathCastStringToBoolean(val->stringval);
 5980: 	break;
 5981:     case XPATH_NUMBER:
 5982: 	ret = xmlXPathCastNumberToBoolean(val->floatval);
 5983: 	break;
 5984:     case XPATH_BOOLEAN:
 5985: 	ret = val->boolval;
 5986: 	break;
 5987:     case XPATH_USERS:
 5988:     case XPATH_POINT:
 5989:     case XPATH_RANGE:
 5990:     case XPATH_LOCATIONSET:
 5991: 	TODO;
 5992: 	ret = 0;
 5993: 	break;
 5994:     }
 5995:     return(ret);
 5996: }
 5997: 
 5998: 
 5999: /**
 6000:  * xmlXPathConvertBoolean:
 6001:  * @val:  an XPath object
 6002:  *
 6003:  * Converts an existing object to its boolean() equivalent
 6004:  *
 6005:  * Returns the new object, the old one is freed (or the operation
 6006:  *         is done directly on @val)
 6007:  */
 6008: xmlXPathObjectPtr
 6009: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
 6010:     xmlXPathObjectPtr ret;
 6011: 
 6012:     if (val == NULL)
 6013: 	return(xmlXPathNewBoolean(0));
 6014:     if (val->type == XPATH_BOOLEAN)
 6015: 	return(val);
 6016:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
 6017:     xmlXPathFreeObject(val);
 6018:     return(ret);
 6019: }
 6020: 
 6021: /************************************************************************
 6022:  *									*
 6023:  *		Routines to handle XPath contexts			*
 6024:  *									*
 6025:  ************************************************************************/
 6026: 
 6027: /**
 6028:  * xmlXPathNewContext:
 6029:  * @doc:  the XML document
 6030:  *
 6031:  * Create a new xmlXPathContext
 6032:  *
 6033:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
 6034:  */
 6035: xmlXPathContextPtr
 6036: xmlXPathNewContext(xmlDocPtr doc) {
 6037:     xmlXPathContextPtr ret;
 6038: 
 6039:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
 6040:     if (ret == NULL) {
 6041:         xmlXPathErrMemory(NULL, "creating context\n");
 6042: 	return(NULL);
 6043:     }
 6044:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
 6045:     ret->doc = doc;
 6046:     ret->node = NULL;
 6047: 
 6048:     ret->varHash = NULL;
 6049: 
 6050:     ret->nb_types = 0;
 6051:     ret->max_types = 0;
 6052:     ret->types = NULL;
 6053: 
 6054:     ret->funcHash = xmlHashCreate(0);
 6055: 
 6056:     ret->nb_axis = 0;
 6057:     ret->max_axis = 0;
 6058:     ret->axis = NULL;
 6059: 
 6060:     ret->nsHash = NULL;
 6061:     ret->user = NULL;
 6062: 
 6063:     ret->contextSize = -1;
 6064:     ret->proximityPosition = -1;
 6065: 
 6066: #ifdef XP_DEFAULT_CACHE_ON
 6067:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
 6068: 	xmlXPathFreeContext(ret);
 6069: 	return(NULL);
 6070:     }
 6071: #endif
 6072: 
 6073:     xmlXPathRegisterAllFunctions(ret);
 6074: 
 6075:     return(ret);
 6076: }
 6077: 
 6078: /**
 6079:  * xmlXPathFreeContext:
 6080:  * @ctxt:  the context to free
 6081:  *
 6082:  * Free up an xmlXPathContext
 6083:  */
 6084: void
 6085: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
 6086:     if (ctxt == NULL) return;
 6087: 
 6088:     if (ctxt->cache != NULL)
 6089: 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
 6090:     xmlXPathRegisteredNsCleanup(ctxt);
 6091:     xmlXPathRegisteredFuncsCleanup(ctxt);
 6092:     xmlXPathRegisteredVariablesCleanup(ctxt);
 6093:     xmlResetError(&ctxt->lastError);
 6094:     xmlFree(ctxt);
 6095: }
 6096: 
 6097: /************************************************************************
 6098:  *									*
 6099:  *		Routines to handle XPath parser contexts		*
 6100:  *									*
 6101:  ************************************************************************/
 6102: 
 6103: #define CHECK_CTXT(ctxt)						\
 6104:     if (ctxt == NULL) {						\
 6105: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6106: 		NULL, NULL, XML_FROM_XPATH,				\
 6107: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6108: 		__FILE__, __LINE__,					\
 6109: 		NULL, NULL, NULL, 0, 0,					\
 6110: 		"NULL context pointer\n");				\
 6111: 	return(NULL);							\
 6112:     }									\
 6113: 
 6114: #define CHECK_CTXT_NEG(ctxt)						\
 6115:     if (ctxt == NULL) {						\
 6116: 	__xmlRaiseError(NULL, NULL, NULL,				\
 6117: 		NULL, NULL, XML_FROM_XPATH,				\
 6118: 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
 6119: 		__FILE__, __LINE__,					\
 6120: 		NULL, NULL, NULL, 0, 0,					\
 6121: 		"NULL context pointer\n");				\
 6122: 	return(-1);							\
 6123:     }									\
 6124: 
 6125: 
 6126: #define CHECK_CONTEXT(ctxt)						\
 6127:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
 6128:         (ctxt->doc->children == NULL)) {				\
 6129: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
 6130: 	return(NULL);							\
 6131:     }
 6132: 
 6133: 
 6134: /**
 6135:  * xmlXPathNewParserContext:
 6136:  * @str:  the XPath expression
 6137:  * @ctxt:  the XPath context
 6138:  *
 6139:  * Create a new xmlXPathParserContext
 6140:  *
 6141:  * Returns the xmlXPathParserContext just allocated.
 6142:  */
 6143: xmlXPathParserContextPtr
 6144: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
 6145:     xmlXPathParserContextPtr ret;
 6146: 
 6147:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6148:     if (ret == NULL) {
 6149:         xmlXPathErrMemory(ctxt, "creating parser context\n");
 6150: 	return(NULL);
 6151:     }
 6152:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6153:     ret->cur = ret->base = str;
 6154:     ret->context = ctxt;
 6155: 
 6156:     ret->comp = xmlXPathNewCompExpr();
 6157:     if (ret->comp == NULL) {
 6158: 	xmlFree(ret->valueTab);
 6159: 	xmlFree(ret);
 6160: 	return(NULL);
 6161:     }
 6162:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
 6163:         ret->comp->dict = ctxt->dict;
 6164: 	xmlDictReference(ret->comp->dict);
 6165:     }
 6166: 
 6167:     return(ret);
 6168: }
 6169: 
 6170: /**
 6171:  * xmlXPathCompParserContext:
 6172:  * @comp:  the XPath compiled expression
 6173:  * @ctxt:  the XPath context
 6174:  *
 6175:  * Create a new xmlXPathParserContext when processing a compiled expression
 6176:  *
 6177:  * Returns the xmlXPathParserContext just allocated.
 6178:  */
 6179: static xmlXPathParserContextPtr
 6180: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
 6181:     xmlXPathParserContextPtr ret;
 6182: 
 6183:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
 6184:     if (ret == NULL) {
 6185:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6186: 	return(NULL);
 6187:     }
 6188:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
 6189: 
 6190:     /* Allocate the value stack */
 6191:     ret->valueTab = (xmlXPathObjectPtr *)
 6192:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
 6193:     if (ret->valueTab == NULL) {
 6194: 	xmlFree(ret);
 6195: 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
 6196: 	return(NULL);
 6197:     }
 6198:     ret->valueNr = 0;
 6199:     ret->valueMax = 10;
 6200:     ret->value = NULL;
 6201:     ret->valueFrame = 0;
 6202: 
 6203:     ret->context = ctxt;
 6204:     ret->comp = comp;
 6205: 
 6206:     return(ret);
 6207: }
 6208: 
 6209: /**
 6210:  * xmlXPathFreeParserContext:
 6211:  * @ctxt:  the context to free
 6212:  *
 6213:  * Free up an xmlXPathParserContext
 6214:  */
 6215: void
 6216: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
 6217:     if (ctxt->valueTab != NULL) {
 6218:         xmlFree(ctxt->valueTab);
 6219:     }
 6220:     if (ctxt->comp != NULL) {
 6221: #ifdef XPATH_STREAMING
 6222: 	if (ctxt->comp->stream != NULL) {
 6223: 	    xmlFreePatternList(ctxt->comp->stream);
 6224: 	    ctxt->comp->stream = NULL;
 6225: 	}
 6226: #endif
 6227: 	xmlXPathFreeCompExpr(ctxt->comp);
 6228:     }
 6229:     xmlFree(ctxt);
 6230: }
 6231: 
 6232: /************************************************************************
 6233:  *									*
 6234:  *		The implicit core function library			*
 6235:  *									*
 6236:  ************************************************************************/
 6237: 
 6238: /**
 6239:  * xmlXPathNodeValHash:
 6240:  * @node:  a node pointer
 6241:  *
 6242:  * Function computing the beginning of the string value of the node,
 6243:  * used to speed up comparisons
 6244:  *
 6245:  * Returns an int usable as a hash
 6246:  */
 6247: static unsigned int
 6248: xmlXPathNodeValHash(xmlNodePtr node) {
 6249:     int len = 2;
 6250:     const xmlChar * string = NULL;
 6251:     xmlNodePtr tmp = NULL;
 6252:     unsigned int ret = 0;
 6253: 
 6254:     if (node == NULL)
 6255: 	return(0);
 6256: 
 6257:     if (node->type == XML_DOCUMENT_NODE) {
 6258: 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
 6259: 	if (tmp == NULL)
 6260: 	    node = node->children;
 6261: 	else
 6262: 	    node = tmp;
 6263: 
 6264: 	if (node == NULL)
 6265: 	    return(0);
 6266:     }
 6267: 
 6268:     switch (node->type) {
 6269: 	case XML_COMMENT_NODE:
 6270: 	case XML_PI_NODE:
 6271: 	case XML_CDATA_SECTION_NODE:
 6272: 	case XML_TEXT_NODE:
 6273: 	    string = node->content;
 6274: 	    if (string == NULL)
 6275: 		return(0);
 6276: 	    if (string[0] == 0)
 6277: 		return(0);
 6278: 	    return(((unsigned int) string[0]) +
 6279: 		   (((unsigned int) string[1]) << 8));
 6280: 	case XML_NAMESPACE_DECL:
 6281: 	    string = ((xmlNsPtr)node)->href;
 6282: 	    if (string == NULL)
 6283: 		return(0);
 6284: 	    if (string[0] == 0)
 6285: 		return(0);
 6286: 	    return(((unsigned int) string[0]) +
 6287: 		   (((unsigned int) string[1]) << 8));
 6288: 	case XML_ATTRIBUTE_NODE:
 6289: 	    tmp = ((xmlAttrPtr) node)->children;
 6290: 	    break;
 6291: 	case XML_ELEMENT_NODE:
 6292: 	    tmp = node->children;
 6293: 	    break;
 6294: 	default:
 6295: 	    return(0);
 6296:     }
 6297:     while (tmp != NULL) {
 6298: 	switch (tmp->type) {
 6299: 	    case XML_COMMENT_NODE:
 6300: 	    case XML_PI_NODE:
 6301: 	    case XML_CDATA_SECTION_NODE:
 6302: 	    case XML_TEXT_NODE:
 6303: 		string = tmp->content;
 6304: 		break;
 6305: 	    case XML_NAMESPACE_DECL:
 6306: 		string = ((xmlNsPtr)tmp)->href;
 6307: 		break;
 6308: 	    default:
 6309: 		break;
 6310: 	}
 6311: 	if ((string != NULL) && (string[0] != 0)) {
 6312: 	    if (len == 1) {
 6313: 		return(ret + (((unsigned int) string[0]) << 8));
 6314: 	    }
 6315: 	    if (string[1] == 0) {
 6316: 		len = 1;
 6317: 		ret = (unsigned int) string[0];
 6318: 	    } else {
 6319: 		return(((unsigned int) string[0]) +
 6320: 		       (((unsigned int) string[1]) << 8));
 6321: 	    }
 6322: 	}
 6323: 	/*
 6324: 	 * Skip to next node
 6325: 	 */
 6326: 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
 6327: 	    if (tmp->children->type != XML_ENTITY_DECL) {
 6328: 		tmp = tmp->children;
 6329: 		continue;
 6330: 	    }
 6331: 	}
 6332: 	if (tmp == node)
 6333: 	    break;
 6334: 
 6335: 	if (tmp->next != NULL) {
 6336: 	    tmp = tmp->next;
 6337: 	    continue;
 6338: 	}
 6339: 
 6340: 	do {
 6341: 	    tmp = tmp->parent;
 6342: 	    if (tmp == NULL)
 6343: 		break;
 6344: 	    if (tmp == node) {
 6345: 		tmp = NULL;
 6346: 		break;
 6347: 	    }
 6348: 	    if (tmp->next != NULL) {
 6349: 		tmp = tmp->next;
 6350: 		break;
 6351: 	    }
 6352: 	} while (tmp != NULL);
 6353:     }
 6354:     return(ret);
 6355: }
 6356: 
 6357: /**
 6358:  * xmlXPathStringHash:
 6359:  * @string:  a string
 6360:  *
 6361:  * Function computing the beginning of the string value of the node,
 6362:  * used to speed up comparisons
 6363:  *
 6364:  * Returns an int usable as a hash
 6365:  */
 6366: static unsigned int
 6367: xmlXPathStringHash(const xmlChar * string) {
 6368:     if (string == NULL)
 6369: 	return((unsigned int) 0);
 6370:     if (string[0] == 0)
 6371: 	return(0);
 6372:     return(((unsigned int) string[0]) +
 6373: 	   (((unsigned int) string[1]) << 8));
 6374: }
 6375: 
 6376: /**
 6377:  * xmlXPathCompareNodeSetFloat:
 6378:  * @ctxt:  the XPath Parser context
 6379:  * @inf:  less than (1) or greater than (0)
 6380:  * @strict:  is the comparison strict
 6381:  * @arg:  the node set
 6382:  * @f:  the value
 6383:  *
 6384:  * Implement the compare operation between a nodeset and a number
 6385:  *     @ns < @val    (1, 1, ...
 6386:  *     @ns <= @val   (1, 0, ...
 6387:  *     @ns > @val    (0, 1, ...
 6388:  *     @ns >= @val   (0, 0, ...
 6389:  *
 6390:  * If one object to be compared is a node-set and the other is a number,
 6391:  * then the comparison will be true if and only if there is a node in the
 6392:  * node-set such that the result of performing the comparison on the number
 6393:  * to be compared and on the result of converting the string-value of that
 6394:  * node to a number using the number function is true.
 6395:  *
 6396:  * Returns 0 or 1 depending on the results of the test.
 6397:  */
 6398: static int
 6399: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6400: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
 6401:     int i, ret = 0;
 6402:     xmlNodeSetPtr ns;
 6403:     xmlChar *str2;
 6404: 
 6405:     if ((f == NULL) || (arg == NULL) ||
 6406: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6407: 	xmlXPathReleaseObject(ctxt->context, arg);
 6408: 	xmlXPathReleaseObject(ctxt->context, f);
 6409:         return(0);
 6410:     }
 6411:     ns = arg->nodesetval;
 6412:     if (ns != NULL) {
 6413: 	for (i = 0;i < ns->nodeNr;i++) {
 6414: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6415: 	     if (str2 != NULL) {
 6416: 		 valuePush(ctxt,
 6417: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6418: 		 xmlFree(str2);
 6419: 		 xmlXPathNumberFunction(ctxt, 1);
 6420: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
 6421: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6422: 		 if (ret)
 6423: 		     break;
 6424: 	     }
 6425: 	}
 6426:     }
 6427:     xmlXPathReleaseObject(ctxt->context, arg);
 6428:     xmlXPathReleaseObject(ctxt->context, f);
 6429:     return(ret);
 6430: }
 6431: 
 6432: /**
 6433:  * xmlXPathCompareNodeSetString:
 6434:  * @ctxt:  the XPath Parser context
 6435:  * @inf:  less than (1) or greater than (0)
 6436:  * @strict:  is the comparison strict
 6437:  * @arg:  the node set
 6438:  * @s:  the value
 6439:  *
 6440:  * Implement the compare operation between a nodeset and a string
 6441:  *     @ns < @val    (1, 1, ...
 6442:  *     @ns <= @val   (1, 0, ...
 6443:  *     @ns > @val    (0, 1, ...
 6444:  *     @ns >= @val   (0, 0, ...
 6445:  *
 6446:  * If one object to be compared is a node-set and the other is a string,
 6447:  * then the comparison will be true if and only if there is a node in
 6448:  * the node-set such that the result of performing the comparison on the
 6449:  * string-value of the node and the other string is true.
 6450:  *
 6451:  * Returns 0 or 1 depending on the results of the test.
 6452:  */
 6453: static int
 6454: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6455: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
 6456:     int i, ret = 0;
 6457:     xmlNodeSetPtr ns;
 6458:     xmlChar *str2;
 6459: 
 6460:     if ((s == NULL) || (arg == NULL) ||
 6461: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
 6462: 	xmlXPathReleaseObject(ctxt->context, arg);
 6463: 	xmlXPathReleaseObject(ctxt->context, s);
 6464:         return(0);
 6465:     }
 6466:     ns = arg->nodesetval;
 6467:     if (ns != NULL) {
 6468: 	for (i = 0;i < ns->nodeNr;i++) {
 6469: 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6470: 	     if (str2 != NULL) {
 6471: 		 valuePush(ctxt,
 6472: 			   xmlXPathCacheNewString(ctxt->context, str2));
 6473: 		 xmlFree(str2);
 6474: 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
 6475: 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
 6476: 		 if (ret)
 6477: 		     break;
 6478: 	     }
 6479: 	}
 6480:     }
 6481:     xmlXPathReleaseObject(ctxt->context, arg);
 6482:     xmlXPathReleaseObject(ctxt->context, s);
 6483:     return(ret);
 6484: }
 6485: 
 6486: /**
 6487:  * xmlXPathCompareNodeSets:
 6488:  * @inf:  less than (1) or greater than (0)
 6489:  * @strict:  is the comparison strict
 6490:  * @arg1:  the first node set object
 6491:  * @arg2:  the second node set object
 6492:  *
 6493:  * Implement the compare operation on nodesets:
 6494:  *
 6495:  * If both objects to be compared are node-sets, then the comparison
 6496:  * will be true if and only if there is a node in the first node-set
 6497:  * and a node in the second node-set such that the result of performing
 6498:  * the comparison on the string-values of the two nodes is true.
 6499:  * ....
 6500:  * When neither object to be compared is a node-set and the operator
 6501:  * is <=, <, >= or >, then the objects are compared by converting both
 6502:  * objects to numbers and comparing the numbers according to IEEE 754.
 6503:  * ....
 6504:  * The number function converts its argument to a number as follows:
 6505:  *  - a string that consists of optional whitespace followed by an
 6506:  *    optional minus sign followed by a Number followed by whitespace
 6507:  *    is converted to the IEEE 754 number that is nearest (according
 6508:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
 6509:  *    represented by the string; any other string is converted to NaN
 6510:  *
 6511:  * Conclusion all nodes need to be converted first to their string value
 6512:  * and then the comparison must be done when possible
 6513:  */
 6514: static int
 6515: xmlXPathCompareNodeSets(int inf, int strict,
 6516: 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6517:     int i, j, init = 0;
 6518:     double val1;
 6519:     double *values2;
 6520:     int ret = 0;
 6521:     xmlNodeSetPtr ns1;
 6522:     xmlNodeSetPtr ns2;
 6523: 
 6524:     if ((arg1 == NULL) ||
 6525: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
 6526: 	xmlXPathFreeObject(arg2);
 6527:         return(0);
 6528:     }
 6529:     if ((arg2 == NULL) ||
 6530: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
 6531: 	xmlXPathFreeObject(arg1);
 6532: 	xmlXPathFreeObject(arg2);
 6533:         return(0);
 6534:     }
 6535: 
 6536:     ns1 = arg1->nodesetval;
 6537:     ns2 = arg2->nodesetval;
 6538: 
 6539:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
 6540: 	xmlXPathFreeObject(arg1);
 6541: 	xmlXPathFreeObject(arg2);
 6542: 	return(0);
 6543:     }
 6544:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
 6545: 	xmlXPathFreeObject(arg1);
 6546: 	xmlXPathFreeObject(arg2);
 6547: 	return(0);
 6548:     }
 6549: 
 6550:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
 6551:     if (values2 == NULL) {
 6552:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6553: 	xmlXPathFreeObject(arg1);
 6554: 	xmlXPathFreeObject(arg2);
 6555: 	return(0);
 6556:     }
 6557:     for (i = 0;i < ns1->nodeNr;i++) {
 6558: 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
 6559: 	if (xmlXPathIsNaN(val1))
 6560: 	    continue;
 6561: 	for (j = 0;j < ns2->nodeNr;j++) {
 6562: 	    if (init == 0) {
 6563: 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
 6564: 	    }
 6565: 	    if (xmlXPathIsNaN(values2[j]))
 6566: 		continue;
 6567: 	    if (inf && strict)
 6568: 		ret = (val1 < values2[j]);
 6569: 	    else if (inf && !strict)
 6570: 		ret = (val1 <= values2[j]);
 6571: 	    else if (!inf && strict)
 6572: 		ret = (val1 > values2[j]);
 6573: 	    else if (!inf && !strict)
 6574: 		ret = (val1 >= values2[j]);
 6575: 	    if (ret)
 6576: 		break;
 6577: 	}
 6578: 	if (ret)
 6579: 	    break;
 6580: 	init = 1;
 6581:     }
 6582:     xmlFree(values2);
 6583:     xmlXPathFreeObject(arg1);
 6584:     xmlXPathFreeObject(arg2);
 6585:     return(ret);
 6586: }
 6587: 
 6588: /**
 6589:  * xmlXPathCompareNodeSetValue:
 6590:  * @ctxt:  the XPath Parser context
 6591:  * @inf:  less than (1) or greater than (0)
 6592:  * @strict:  is the comparison strict
 6593:  * @arg:  the node set
 6594:  * @val:  the value
 6595:  *
 6596:  * Implement the compare operation between a nodeset and a value
 6597:  *     @ns < @val    (1, 1, ...
 6598:  *     @ns <= @val   (1, 0, ...
 6599:  *     @ns > @val    (0, 1, ...
 6600:  *     @ns >= @val   (0, 0, ...
 6601:  *
 6602:  * If one object to be compared is a node-set and the other is a boolean,
 6603:  * then the comparison will be true if and only if the result of performing
 6604:  * the comparison on the boolean and on the result of converting
 6605:  * the node-set to a boolean using the boolean function is true.
 6606:  *
 6607:  * Returns 0 or 1 depending on the results of the test.
 6608:  */
 6609: static int
 6610: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
 6611: 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
 6612:     if ((val == NULL) || (arg == NULL) ||
 6613: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6614:         return(0);
 6615: 
 6616:     switch(val->type) {
 6617:         case XPATH_NUMBER:
 6618: 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
 6619:         case XPATH_NODESET:
 6620:         case XPATH_XSLT_TREE:
 6621: 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
 6622:         case XPATH_STRING:
 6623: 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
 6624:         case XPATH_BOOLEAN:
 6625: 	    valuePush(ctxt, arg);
 6626: 	    xmlXPathBooleanFunction(ctxt, 1);
 6627: 	    valuePush(ctxt, val);
 6628: 	    return(xmlXPathCompareValues(ctxt, inf, strict));
 6629: 	default:
 6630: 	    TODO
 6631:     }
 6632:     return(0);
 6633: }
 6634: 
 6635: /**
 6636:  * xmlXPathEqualNodeSetString:
 6637:  * @arg:  the nodeset object argument
 6638:  * @str:  the string to compare to.
 6639:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
 6640:  *
 6641:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6642:  * If one object to be compared is a node-set and the other is a string,
 6643:  * then the comparison will be true if and only if there is a node in
 6644:  * the node-set such that the result of performing the comparison on the
 6645:  * string-value of the node and the other string is true.
 6646:  *
 6647:  * Returns 0 or 1 depending on the results of the test.
 6648:  */
 6649: static int
 6650: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
 6651: {
 6652:     int i;
 6653:     xmlNodeSetPtr ns;
 6654:     xmlChar *str2;
 6655:     unsigned int hash;
 6656: 
 6657:     if ((str == NULL) || (arg == NULL) ||
 6658:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6659:         return (0);
 6660:     ns = arg->nodesetval;
 6661:     /*
 6662:      * A NULL nodeset compared with a string is always false
 6663:      * (since there is no node equal, and no node not equal)
 6664:      */
 6665:     if ((ns == NULL) || (ns->nodeNr <= 0) )
 6666:         return (0);
 6667:     hash = xmlXPathStringHash(str);
 6668:     for (i = 0; i < ns->nodeNr; i++) {
 6669:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
 6670:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
 6671:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
 6672:                 xmlFree(str2);
 6673: 		if (neq)
 6674: 		    continue;
 6675:                 return (1);
 6676: 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
 6677: 		if (neq)
 6678: 		    continue;
 6679:                 return (1);
 6680:             } else if (neq) {
 6681: 		if (str2 != NULL)
 6682: 		    xmlFree(str2);
 6683: 		return (1);
 6684: 	    }
 6685:             if (str2 != NULL)
 6686:                 xmlFree(str2);
 6687:         } else if (neq)
 6688: 	    return (1);
 6689:     }
 6690:     return (0);
 6691: }
 6692: 
 6693: /**
 6694:  * xmlXPathEqualNodeSetFloat:
 6695:  * @arg:  the nodeset object argument
 6696:  * @f:  the float to compare to
 6697:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
 6698:  *
 6699:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 6700:  * If one object to be compared is a node-set and the other is a number,
 6701:  * then the comparison will be true if and only if there is a node in
 6702:  * the node-set such that the result of performing the comparison on the
 6703:  * number to be compared and on the result of converting the string-value
 6704:  * of that node to a number using the number function is true.
 6705:  *
 6706:  * Returns 0 or 1 depending on the results of the test.
 6707:  */
 6708: static int
 6709: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
 6710:     xmlXPathObjectPtr arg, double f, int neq) {
 6711:   int i, ret=0;
 6712:   xmlNodeSetPtr ns;
 6713:   xmlChar *str2;
 6714:   xmlXPathObjectPtr val;
 6715:   double v;
 6716: 
 6717:     if ((arg == NULL) ||
 6718: 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
 6719:         return(0);
 6720: 
 6721:     ns = arg->nodesetval;
 6722:     if (ns != NULL) {
 6723: 	for (i=0;i<ns->nodeNr;i++) {
 6724: 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 6725: 	    if (str2 != NULL) {
 6726: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
 6727: 		xmlFree(str2);
 6728: 		xmlXPathNumberFunction(ctxt, 1);
 6729: 		val = valuePop(ctxt);
 6730: 		v = val->floatval;
 6731: 		xmlXPathReleaseObject(ctxt->context, val);
 6732: 		if (!xmlXPathIsNaN(v)) {
 6733: 		    if ((!neq) && (v==f)) {
 6734: 			ret = 1;
 6735: 			break;
 6736: 		    } else if ((neq) && (v!=f)) {
 6737: 			ret = 1;
 6738: 			break;
 6739: 		    }
 6740: 		} else {	/* NaN is unequal to any value */
 6741: 		    if (neq)
 6742: 			ret = 1;
 6743: 		}
 6744: 	    }
 6745: 	}
 6746:     }
 6747: 
 6748:     return(ret);
 6749: }
 6750: 
 6751: 
 6752: /**
 6753:  * xmlXPathEqualNodeSets:
 6754:  * @arg1:  first nodeset object argument
 6755:  * @arg2:  second nodeset object argument
 6756:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
 6757:  *
 6758:  * Implement the equal / not equal operation on XPath nodesets:
 6759:  * @arg1 == @arg2  or  @arg1 != @arg2
 6760:  * If both objects to be compared are node-sets, then the comparison
 6761:  * will be true if and only if there is a node in the first node-set and
 6762:  * a node in the second node-set such that the result of performing the
 6763:  * comparison on the string-values of the two nodes is true.
 6764:  *
 6765:  * (needless to say, this is a costly operation)
 6766:  *
 6767:  * Returns 0 or 1 depending on the results of the test.
 6768:  */
 6769: static int
 6770: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
 6771:     int i, j;
 6772:     unsigned int *hashs1;
 6773:     unsigned int *hashs2;
 6774:     xmlChar **values1;
 6775:     xmlChar **values2;
 6776:     int ret = 0;
 6777:     xmlNodeSetPtr ns1;
 6778:     xmlNodeSetPtr ns2;
 6779: 
 6780:     if ((arg1 == NULL) ||
 6781: 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
 6782:         return(0);
 6783:     if ((arg2 == NULL) ||
 6784: 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
 6785:         return(0);
 6786: 
 6787:     ns1 = arg1->nodesetval;
 6788:     ns2 = arg2->nodesetval;
 6789: 
 6790:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
 6791: 	return(0);
 6792:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
 6793: 	return(0);
 6794: 
 6795:     /*
 6796:      * for equal, check if there is a node pertaining to both sets
 6797:      */
 6798:     if (neq == 0)
 6799: 	for (i = 0;i < ns1->nodeNr;i++)
 6800: 	    for (j = 0;j < ns2->nodeNr;j++)
 6801: 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
 6802: 		    return(1);
 6803: 
 6804:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
 6805:     if (values1 == NULL) {
 6806:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6807: 	return(0);
 6808:     }
 6809:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
 6810:     if (hashs1 == NULL) {
 6811:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6812: 	xmlFree(values1);
 6813: 	return(0);
 6814:     }
 6815:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
 6816:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
 6817:     if (values2 == NULL) {
 6818:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6819: 	xmlFree(hashs1);
 6820: 	xmlFree(values1);
 6821: 	return(0);
 6822:     }
 6823:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
 6824:     if (hashs2 == NULL) {
 6825:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
 6826: 	xmlFree(hashs1);
 6827: 	xmlFree(values1);
 6828: 	xmlFree(values2);
 6829: 	return(0);
 6830:     }
 6831:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
 6832:     for (i = 0;i < ns1->nodeNr;i++) {
 6833: 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
 6834: 	for (j = 0;j < ns2->nodeNr;j++) {
 6835: 	    if (i == 0)
 6836: 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
 6837: 	    if (hashs1[i] != hashs2[j]) {
 6838: 		if (neq) {
 6839: 		    ret = 1;
 6840: 		    break;
 6841: 		}
 6842: 	    }
 6843: 	    else {
 6844: 		if (values1[i] == NULL)
 6845: 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
 6846: 		if (values2[j] == NULL)
 6847: 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
 6848: 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
 6849: 		if (ret)
 6850: 		    break;
 6851: 	    }
 6852: 	}
 6853: 	if (ret)
 6854: 	    break;
 6855:     }
 6856:     for (i = 0;i < ns1->nodeNr;i++)
 6857: 	if (values1[i] != NULL)
 6858: 	    xmlFree(values1[i]);
 6859:     for (j = 0;j < ns2->nodeNr;j++)
 6860: 	if (values2[j] != NULL)
 6861: 	    xmlFree(values2[j]);
 6862:     xmlFree(values1);
 6863:     xmlFree(values2);
 6864:     xmlFree(hashs1);
 6865:     xmlFree(hashs2);
 6866:     return(ret);
 6867: }
 6868: 
 6869: static int
 6870: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
 6871:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
 6872:     int ret = 0;
 6873:     /*
 6874:      *At this point we are assured neither arg1 nor arg2
 6875:      *is a nodeset, so we can just pick the appropriate routine.
 6876:      */
 6877:     switch (arg1->type) {
 6878:         case XPATH_UNDEFINED:
 6879: #ifdef DEBUG_EXPR
 6880: 	    xmlGenericError(xmlGenericErrorContext,
 6881: 		    "Equal: undefined\n");
 6882: #endif
 6883: 	    break;
 6884:         case XPATH_BOOLEAN:
 6885: 	    switch (arg2->type) {
 6886: 	        case XPATH_UNDEFINED:
 6887: #ifdef DEBUG_EXPR
 6888: 		    xmlGenericError(xmlGenericErrorContext,
 6889: 			    "Equal: undefined\n");
 6890: #endif
 6891: 		    break;
 6892: 		case XPATH_BOOLEAN:
 6893: #ifdef DEBUG_EXPR
 6894: 		    xmlGenericError(xmlGenericErrorContext,
 6895: 			    "Equal: %d boolean %d \n",
 6896: 			    arg1->boolval, arg2->boolval);
 6897: #endif
 6898: 		    ret = (arg1->boolval == arg2->boolval);
 6899: 		    break;
 6900: 		case XPATH_NUMBER:
 6901: 		    ret = (arg1->boolval ==
 6902: 			   xmlXPathCastNumberToBoolean(arg2->floatval));
 6903: 		    break;
 6904: 		case XPATH_STRING:
 6905: 		    if ((arg2->stringval == NULL) ||
 6906: 			(arg2->stringval[0] == 0)) ret = 0;
 6907: 		    else
 6908: 			ret = 1;
 6909: 		    ret = (arg1->boolval == ret);
 6910: 		    break;
 6911: 		case XPATH_USERS:
 6912: 		case XPATH_POINT:
 6913: 		case XPATH_RANGE:
 6914: 		case XPATH_LOCATIONSET:
 6915: 		    TODO
 6916: 		    break;
 6917: 		case XPATH_NODESET:
 6918: 		case XPATH_XSLT_TREE:
 6919: 		    break;
 6920: 	    }
 6921: 	    break;
 6922:         case XPATH_NUMBER:
 6923: 	    switch (arg2->type) {
 6924: 	        case XPATH_UNDEFINED:
 6925: #ifdef DEBUG_EXPR
 6926: 		    xmlGenericError(xmlGenericErrorContext,
 6927: 			    "Equal: undefined\n");
 6928: #endif
 6929: 		    break;
 6930: 		case XPATH_BOOLEAN:
 6931: 		    ret = (arg2->boolval==
 6932: 			   xmlXPathCastNumberToBoolean(arg1->floatval));
 6933: 		    break;
 6934: 		case XPATH_STRING:
 6935: 		    valuePush(ctxt, arg2);
 6936: 		    xmlXPathNumberFunction(ctxt, 1);
 6937: 		    arg2 = valuePop(ctxt);
 6938: 		    /* no break on purpose */
 6939: 		case XPATH_NUMBER:
 6940: 		    /* Hand check NaN and Infinity equalities */
 6941: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 6942: 			    xmlXPathIsNaN(arg2->floatval)) {
 6943: 		        ret = 0;
 6944: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 6945: 		        if (xmlXPathIsInf(arg2->floatval) == 1)
 6946: 			    ret = 1;
 6947: 			else
 6948: 			    ret = 0;
 6949: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 6950: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 6951: 			    ret = 1;
 6952: 			else
 6953: 			    ret = 0;
 6954: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 6955: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 6956: 			    ret = 1;
 6957: 			else
 6958: 			    ret = 0;
 6959: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 6960: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 6961: 			    ret = 1;
 6962: 			else
 6963: 			    ret = 0;
 6964: 		    } else {
 6965: 		        ret = (arg1->floatval == arg2->floatval);
 6966: 		    }
 6967: 		    break;
 6968: 		case XPATH_USERS:
 6969: 		case XPATH_POINT:
 6970: 		case XPATH_RANGE:
 6971: 		case XPATH_LOCATIONSET:
 6972: 		    TODO
 6973: 		    break;
 6974: 		case XPATH_NODESET:
 6975: 		case XPATH_XSLT_TREE:
 6976: 		    break;
 6977: 	    }
 6978: 	    break;
 6979:         case XPATH_STRING:
 6980: 	    switch (arg2->type) {
 6981: 	        case XPATH_UNDEFINED:
 6982: #ifdef DEBUG_EXPR
 6983: 		    xmlGenericError(xmlGenericErrorContext,
 6984: 			    "Equal: undefined\n");
 6985: #endif
 6986: 		    break;
 6987: 		case XPATH_BOOLEAN:
 6988: 		    if ((arg1->stringval == NULL) ||
 6989: 			(arg1->stringval[0] == 0)) ret = 0;
 6990: 		    else
 6991: 			ret = 1;
 6992: 		    ret = (arg2->boolval == ret);
 6993: 		    break;
 6994: 		case XPATH_STRING:
 6995: 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
 6996: 		    break;
 6997: 		case XPATH_NUMBER:
 6998: 		    valuePush(ctxt, arg1);
 6999: 		    xmlXPathNumberFunction(ctxt, 1);
 7000: 		    arg1 = valuePop(ctxt);
 7001: 		    /* Hand check NaN and Infinity equalities */
 7002: 		    if (xmlXPathIsNaN(arg1->floatval) ||
 7003: 			    xmlXPathIsNaN(arg2->floatval)) {
 7004: 		        ret = 0;
 7005: 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
 7006: 			if (xmlXPathIsInf(arg2->floatval) == 1)
 7007: 			    ret = 1;
 7008: 			else
 7009: 			    ret = 0;
 7010: 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
 7011: 			if (xmlXPathIsInf(arg2->floatval) == -1)
 7012: 			    ret = 1;
 7013: 			else
 7014: 			    ret = 0;
 7015: 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
 7016: 			if (xmlXPathIsInf(arg1->floatval) == 1)
 7017: 			    ret = 1;
 7018: 			else
 7019: 			    ret = 0;
 7020: 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
 7021: 			if (xmlXPathIsInf(arg1->floatval) == -1)
 7022: 			    ret = 1;
 7023: 			else
 7024: 			    ret = 0;
 7025: 		    } else {
 7026: 		        ret = (arg1->floatval == arg2->floatval);
 7027: 		    }
 7028: 		    break;
 7029: 		case XPATH_USERS:
 7030: 		case XPATH_POINT:
 7031: 		case XPATH_RANGE:
 7032: 		case XPATH_LOCATIONSET:
 7033: 		    TODO
 7034: 		    break;
 7035: 		case XPATH_NODESET:
 7036: 		case XPATH_XSLT_TREE:
 7037: 		    break;
 7038: 	    }
 7039: 	    break;
 7040:         case XPATH_USERS:
 7041: 	case XPATH_POINT:
 7042: 	case XPATH_RANGE:
 7043: 	case XPATH_LOCATIONSET:
 7044: 	    TODO
 7045: 	    break;
 7046: 	case XPATH_NODESET:
 7047: 	case XPATH_XSLT_TREE:
 7048: 	    break;
 7049:     }
 7050:     xmlXPathReleaseObject(ctxt->context, arg1);
 7051:     xmlXPathReleaseObject(ctxt->context, arg2);
 7052:     return(ret);
 7053: }
 7054: 
 7055: /**
 7056:  * xmlXPathEqualValues:
 7057:  * @ctxt:  the XPath Parser context
 7058:  *
 7059:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7060:  *
 7061:  * Returns 0 or 1 depending on the results of the test.
 7062:  */
 7063: int
 7064: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
 7065:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7066:     int ret = 0;
 7067: 
 7068:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7069:     arg2 = valuePop(ctxt);
 7070:     arg1 = valuePop(ctxt);
 7071:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7072: 	if (arg1 != NULL)
 7073: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7074: 	else
 7075: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7076: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7077:     }
 7078: 
 7079:     if (arg1 == arg2) {
 7080: #ifdef DEBUG_EXPR
 7081:         xmlGenericError(xmlGenericErrorContext,
 7082: 		"Equal: by pointer\n");
 7083: #endif
 7084: 	xmlXPathFreeObject(arg1);
 7085:         return(1);
 7086:     }
 7087: 
 7088:     /*
 7089:      *If either argument is a nodeset, it's a 'special case'
 7090:      */
 7091:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7092:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7093: 	/*
 7094: 	 *Hack it to assure arg1 is the nodeset
 7095: 	 */
 7096: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7097: 		argtmp = arg2;
 7098: 		arg2 = arg1;
 7099: 		arg1 = argtmp;
 7100: 	}
 7101: 	switch (arg2->type) {
 7102: 	    case XPATH_UNDEFINED:
 7103: #ifdef DEBUG_EXPR
 7104: 		xmlGenericError(xmlGenericErrorContext,
 7105: 			"Equal: undefined\n");
 7106: #endif
 7107: 		break;
 7108: 	    case XPATH_NODESET:
 7109: 	    case XPATH_XSLT_TREE:
 7110: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
 7111: 		break;
 7112: 	    case XPATH_BOOLEAN:
 7113: 		if ((arg1->nodesetval == NULL) ||
 7114: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7115: 		else
 7116: 		    ret = 1;
 7117: 		ret = (ret == arg2->boolval);
 7118: 		break;
 7119: 	    case XPATH_NUMBER:
 7120: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
 7121: 		break;
 7122: 	    case XPATH_STRING:
 7123: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
 7124: 		break;
 7125: 	    case XPATH_USERS:
 7126: 	    case XPATH_POINT:
 7127: 	    case XPATH_RANGE:
 7128: 	    case XPATH_LOCATIONSET:
 7129: 		TODO
 7130: 		break;
 7131: 	}
 7132: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7133: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7134: 	return(ret);
 7135:     }
 7136: 
 7137:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7138: }
 7139: 
 7140: /**
 7141:  * xmlXPathNotEqualValues:
 7142:  * @ctxt:  the XPath Parser context
 7143:  *
 7144:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
 7145:  *
 7146:  * Returns 0 or 1 depending on the results of the test.
 7147:  */
 7148: int
 7149: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
 7150:     xmlXPathObjectPtr arg1, arg2, argtmp;
 7151:     int ret = 0;
 7152: 
 7153:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7154:     arg2 = valuePop(ctxt);
 7155:     arg1 = valuePop(ctxt);
 7156:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7157: 	if (arg1 != NULL)
 7158: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7159: 	else
 7160: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7161: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7162:     }
 7163: 
 7164:     if (arg1 == arg2) {
 7165: #ifdef DEBUG_EXPR
 7166:         xmlGenericError(xmlGenericErrorContext,
 7167: 		"NotEqual: by pointer\n");
 7168: #endif
 7169: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7170:         return(0);
 7171:     }
 7172: 
 7173:     /*
 7174:      *If either argument is a nodeset, it's a 'special case'
 7175:      */
 7176:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7177:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7178: 	/*
 7179: 	 *Hack it to assure arg1 is the nodeset
 7180: 	 */
 7181: 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
 7182: 		argtmp = arg2;
 7183: 		arg2 = arg1;
 7184: 		arg1 = argtmp;
 7185: 	}
 7186: 	switch (arg2->type) {
 7187: 	    case XPATH_UNDEFINED:
 7188: #ifdef DEBUG_EXPR
 7189: 		xmlGenericError(xmlGenericErrorContext,
 7190: 			"NotEqual: undefined\n");
 7191: #endif
 7192: 		break;
 7193: 	    case XPATH_NODESET:
 7194: 	    case XPATH_XSLT_TREE:
 7195: 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
 7196: 		break;
 7197: 	    case XPATH_BOOLEAN:
 7198: 		if ((arg1->nodesetval == NULL) ||
 7199: 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
 7200: 		else
 7201: 		    ret = 1;
 7202: 		ret = (ret != arg2->boolval);
 7203: 		break;
 7204: 	    case XPATH_NUMBER:
 7205: 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
 7206: 		break;
 7207: 	    case XPATH_STRING:
 7208: 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
 7209: 		break;
 7210: 	    case XPATH_USERS:
 7211: 	    case XPATH_POINT:
 7212: 	    case XPATH_RANGE:
 7213: 	    case XPATH_LOCATIONSET:
 7214: 		TODO
 7215: 		break;
 7216: 	}
 7217: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7218: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7219: 	return(ret);
 7220:     }
 7221: 
 7222:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
 7223: }
 7224: 
 7225: /**
 7226:  * xmlXPathCompareValues:
 7227:  * @ctxt:  the XPath Parser context
 7228:  * @inf:  less than (1) or greater than (0)
 7229:  * @strict:  is the comparison strict
 7230:  *
 7231:  * Implement the compare operation on XPath objects:
 7232:  *     @arg1 < @arg2    (1, 1, ...
 7233:  *     @arg1 <= @arg2   (1, 0, ...
 7234:  *     @arg1 > @arg2    (0, 1, ...
 7235:  *     @arg1 >= @arg2   (0, 0, ...
 7236:  *
 7237:  * When neither object to be compared is a node-set and the operator is
 7238:  * <=, <, >=, >, then the objects are compared by converted both objects
 7239:  * to numbers and comparing the numbers according to IEEE 754. The <
 7240:  * comparison will be true if and only if the first number is less than the
 7241:  * second number. The <= comparison will be true if and only if the first
 7242:  * number is less than or equal to the second number. The > comparison
 7243:  * will be true if and only if the first number is greater than the second
 7244:  * number. The >= comparison will be true if and only if the first number
 7245:  * is greater than or equal to the second number.
 7246:  *
 7247:  * Returns 1 if the comparison succeeded, 0 if it failed
 7248:  */
 7249: int
 7250: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
 7251:     int ret = 0, arg1i = 0, arg2i = 0;
 7252:     xmlXPathObjectPtr arg1, arg2;
 7253: 
 7254:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
 7255:     arg2 = valuePop(ctxt);
 7256:     arg1 = valuePop(ctxt);
 7257:     if ((arg1 == NULL) || (arg2 == NULL)) {
 7258: 	if (arg1 != NULL)
 7259: 	    xmlXPathReleaseObject(ctxt->context, arg1);
 7260: 	else
 7261: 	    xmlXPathReleaseObject(ctxt->context, arg2);
 7262: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7263:     }
 7264: 
 7265:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
 7266:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7267: 	/*
 7268: 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
 7269: 	 * are not freed from within this routine; they will be freed from the
 7270: 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
 7271: 	 */
 7272: 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
 7273: 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
 7274: 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
 7275: 	} else {
 7276: 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
 7277: 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
 7278: 			                          arg1, arg2);
 7279: 	    } else {
 7280: 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
 7281: 			                          arg2, arg1);
 7282: 	    }
 7283: 	}
 7284: 	return(ret);
 7285:     }
 7286: 
 7287:     if (arg1->type != XPATH_NUMBER) {
 7288: 	valuePush(ctxt, arg1);
 7289: 	xmlXPathNumberFunction(ctxt, 1);
 7290: 	arg1 = valuePop(ctxt);
 7291:     }
 7292:     if (arg1->type != XPATH_NUMBER) {
 7293: 	xmlXPathFreeObject(arg1);
 7294: 	xmlXPathFreeObject(arg2);
 7295: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7296:     }
 7297:     if (arg2->type != XPATH_NUMBER) {
 7298: 	valuePush(ctxt, arg2);
 7299: 	xmlXPathNumberFunction(ctxt, 1);
 7300: 	arg2 = valuePop(ctxt);
 7301:     }
 7302:     if (arg2->type != XPATH_NUMBER) {
 7303: 	xmlXPathReleaseObject(ctxt->context, arg1);
 7304: 	xmlXPathReleaseObject(ctxt->context, arg2);
 7305: 	XP_ERROR0(XPATH_INVALID_OPERAND);
 7306:     }
 7307:     /*
 7308:      * Add tests for infinity and nan
 7309:      * => feedback on 3.4 for Inf and NaN
 7310:      */
 7311:     /* Hand check NaN and Infinity comparisons */
 7312:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
 7313: 	ret=0;
 7314:     } else {
 7315: 	arg1i=xmlXPathIsInf(arg1->floatval);
 7316: 	arg2i=xmlXPathIsInf(arg2->floatval);
 7317: 	if (inf && strict) {
 7318: 	    if ((arg1i == -1 && arg2i != -1) ||
 7319: 		(arg2i == 1 && arg1i != 1)) {
 7320: 		ret = 1;
 7321: 	    } else if (arg1i == 0 && arg2i == 0) {
 7322: 		ret = (arg1->floatval < arg2->floatval);
 7323: 	    } else {
 7324: 		ret = 0;
 7325: 	    }
 7326: 	}
 7327: 	else if (inf && !strict) {
 7328: 	    if (arg1i == -1 || arg2i == 1) {
 7329: 		ret = 1;
 7330: 	    } else if (arg1i == 0 && arg2i == 0) {
 7331: 		ret = (arg1->floatval <= arg2->floatval);
 7332: 	    } else {
 7333: 		ret = 0;
 7334: 	    }
 7335: 	}
 7336: 	else if (!inf && strict) {
 7337: 	    if ((arg1i == 1 && arg2i != 1) ||
 7338: 		(arg2i == -1 && arg1i != -1)) {
 7339: 		ret = 1;
 7340: 	    } else if (arg1i == 0 && arg2i == 0) {
 7341: 		ret = (arg1->floatval > arg2->floatval);
 7342: 	    } else {
 7343: 		ret = 0;
 7344: 	    }
 7345: 	}
 7346: 	else if (!inf && !strict) {
 7347: 	    if (arg1i == 1 || arg2i == -1) {
 7348: 		ret = 1;
 7349: 	    } else if (arg1i == 0 && arg2i == 0) {
 7350: 		ret = (arg1->floatval >= arg2->floatval);
 7351: 	    } else {
 7352: 		ret = 0;
 7353: 	    }
 7354: 	}
 7355:     }
 7356:     xmlXPathReleaseObject(ctxt->context, arg1);
 7357:     xmlXPathReleaseObject(ctxt->context, arg2);
 7358:     return(ret);
 7359: }
 7360: 
 7361: /**
 7362:  * xmlXPathValueFlipSign:
 7363:  * @ctxt:  the XPath Parser context
 7364:  *
 7365:  * Implement the unary - operation on an XPath object
 7366:  * The numeric operators convert their operands to numbers as if
 7367:  * by calling the number function.
 7368:  */
 7369: void
 7370: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
 7371:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
 7372:     CAST_TO_NUMBER;
 7373:     CHECK_TYPE(XPATH_NUMBER);
 7374:     if (xmlXPathIsNaN(ctxt->value->floatval))
 7375:         ctxt->value->floatval=xmlXPathNAN;
 7376:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
 7377:         ctxt->value->floatval=xmlXPathNINF;
 7378:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
 7379:         ctxt->value->floatval=xmlXPathPINF;
 7380:     else if (ctxt->value->floatval == 0) {
 7381:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
 7382: 	    ctxt->value->floatval = xmlXPathNZERO;
 7383: 	else
 7384: 	    ctxt->value->floatval = 0;
 7385:     }
 7386:     else
 7387:         ctxt->value->floatval = - ctxt->value->floatval;
 7388: }
 7389: 
 7390: /**
 7391:  * xmlXPathAddValues:
 7392:  * @ctxt:  the XPath Parser context
 7393:  *
 7394:  * Implement the add operation on XPath objects:
 7395:  * The numeric operators convert their operands to numbers as if
 7396:  * by calling the number function.
 7397:  */
 7398: void
 7399: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
 7400:     xmlXPathObjectPtr arg;
 7401:     double val;
 7402: 
 7403:     arg = valuePop(ctxt);
 7404:     if (arg == NULL)
 7405: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7406:     val = xmlXPathCastToNumber(arg);
 7407:     xmlXPathReleaseObject(ctxt->context, arg);
 7408:     CAST_TO_NUMBER;
 7409:     CHECK_TYPE(XPATH_NUMBER);
 7410:     ctxt->value->floatval += val;
 7411: }
 7412: 
 7413: /**
 7414:  * xmlXPathSubValues:
 7415:  * @ctxt:  the XPath Parser context
 7416:  *
 7417:  * Implement the subtraction operation on XPath objects:
 7418:  * The numeric operators convert their operands to numbers as if
 7419:  * by calling the number function.
 7420:  */
 7421: void
 7422: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
 7423:     xmlXPathObjectPtr arg;
 7424:     double val;
 7425: 
 7426:     arg = valuePop(ctxt);
 7427:     if (arg == NULL)
 7428: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7429:     val = xmlXPathCastToNumber(arg);
 7430:     xmlXPathReleaseObject(ctxt->context, arg);
 7431:     CAST_TO_NUMBER;
 7432:     CHECK_TYPE(XPATH_NUMBER);
 7433:     ctxt->value->floatval -= val;
 7434: }
 7435: 
 7436: /**
 7437:  * xmlXPathMultValues:
 7438:  * @ctxt:  the XPath Parser context
 7439:  *
 7440:  * Implement the multiply operation on XPath objects:
 7441:  * The numeric operators convert their operands to numbers as if
 7442:  * by calling the number function.
 7443:  */
 7444: void
 7445: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
 7446:     xmlXPathObjectPtr arg;
 7447:     double val;
 7448: 
 7449:     arg = valuePop(ctxt);
 7450:     if (arg == NULL)
 7451: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7452:     val = xmlXPathCastToNumber(arg);
 7453:     xmlXPathReleaseObject(ctxt->context, arg);
 7454:     CAST_TO_NUMBER;
 7455:     CHECK_TYPE(XPATH_NUMBER);
 7456:     ctxt->value->floatval *= val;
 7457: }
 7458: 
 7459: /**
 7460:  * xmlXPathDivValues:
 7461:  * @ctxt:  the XPath Parser context
 7462:  *
 7463:  * Implement the div operation on XPath objects @arg1 / @arg2:
 7464:  * The numeric operators convert their operands to numbers as if
 7465:  * by calling the number function.
 7466:  */
 7467: void
 7468: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
 7469:     xmlXPathObjectPtr arg;
 7470:     double val;
 7471: 
 7472:     arg = valuePop(ctxt);
 7473:     if (arg == NULL)
 7474: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7475:     val = xmlXPathCastToNumber(arg);
 7476:     xmlXPathReleaseObject(ctxt->context, arg);
 7477:     CAST_TO_NUMBER;
 7478:     CHECK_TYPE(XPATH_NUMBER);
 7479:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
 7480: 	ctxt->value->floatval = xmlXPathNAN;
 7481:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
 7482: 	if (ctxt->value->floatval == 0)
 7483: 	    ctxt->value->floatval = xmlXPathNAN;
 7484: 	else if (ctxt->value->floatval > 0)
 7485: 	    ctxt->value->floatval = xmlXPathNINF;
 7486: 	else if (ctxt->value->floatval < 0)
 7487: 	    ctxt->value->floatval = xmlXPathPINF;
 7488:     }
 7489:     else if (val == 0) {
 7490: 	if (ctxt->value->floatval == 0)
 7491: 	    ctxt->value->floatval = xmlXPathNAN;
 7492: 	else if (ctxt->value->floatval > 0)
 7493: 	    ctxt->value->floatval = xmlXPathPINF;
 7494: 	else if (ctxt->value->floatval < 0)
 7495: 	    ctxt->value->floatval = xmlXPathNINF;
 7496:     } else
 7497: 	ctxt->value->floatval /= val;
 7498: }
 7499: 
 7500: /**
 7501:  * xmlXPathModValues:
 7502:  * @ctxt:  the XPath Parser context
 7503:  *
 7504:  * Implement the mod operation on XPath objects: @arg1 / @arg2
 7505:  * The numeric operators convert their operands to numbers as if
 7506:  * by calling the number function.
 7507:  */
 7508: void
 7509: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
 7510:     xmlXPathObjectPtr arg;
 7511:     double arg1, arg2;
 7512: 
 7513:     arg = valuePop(ctxt);
 7514:     if (arg == NULL)
 7515: 	XP_ERROR(XPATH_INVALID_OPERAND);
 7516:     arg2 = xmlXPathCastToNumber(arg);
 7517:     xmlXPathReleaseObject(ctxt->context, arg);
 7518:     CAST_TO_NUMBER;
 7519:     CHECK_TYPE(XPATH_NUMBER);
 7520:     arg1 = ctxt->value->floatval;
 7521:     if (arg2 == 0)
 7522: 	ctxt->value->floatval = xmlXPathNAN;
 7523:     else {
 7524: 	ctxt->value->floatval = fmod(arg1, arg2);
 7525:     }
 7526: }
 7527: 
 7528: /************************************************************************
 7529:  *									*
 7530:  *		The traversal functions					*
 7531:  *									*
 7532:  ************************************************************************/
 7533: 
 7534: /*
 7535:  * A traversal function enumerates nodes along an axis.
 7536:  * Initially it must be called with NULL, and it indicates
 7537:  * termination on the axis by returning NULL.
 7538:  */
 7539: typedef xmlNodePtr (*xmlXPathTraversalFunction)
 7540:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
 7541: 
 7542: /*
 7543:  * xmlXPathTraversalFunctionExt:
 7544:  * A traversal function enumerates nodes along an axis.
 7545:  * Initially it must be called with NULL, and it indicates
 7546:  * termination on the axis by returning NULL.
 7547:  * The context node of the traversal is specified via @contextNode.
 7548:  */
 7549: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
 7550:                     (xmlNodePtr cur, xmlNodePtr contextNode);
 7551: 
 7552: /*
 7553:  * xmlXPathNodeSetMergeFunction:
 7554:  * Used for merging node sets in xmlXPathCollectAndTest().
 7555:  */
 7556: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
 7557: 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
 7558: 
 7559: 
 7560: /**
 7561:  * xmlXPathNextSelf:
 7562:  * @ctxt:  the XPath Parser context
 7563:  * @cur:  the current node in the traversal
 7564:  *
 7565:  * Traversal function for the "self" direction
 7566:  * The self axis contains just the context node itself
 7567:  *
 7568:  * Returns the next element following that axis
 7569:  */
 7570: xmlNodePtr
 7571: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7572:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7573:     if (cur == NULL)
 7574:         return(ctxt->context->node);
 7575:     return(NULL);
 7576: }
 7577: 
 7578: /**
 7579:  * xmlXPathNextChild:
 7580:  * @ctxt:  the XPath Parser context
 7581:  * @cur:  the current node in the traversal
 7582:  *
 7583:  * Traversal function for the "child" direction
 7584:  * The child axis contains the children of the context node in document order.
 7585:  *
 7586:  * Returns the next element following that axis
 7587:  */
 7588: xmlNodePtr
 7589: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7590:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7591:     if (cur == NULL) {
 7592: 	if (ctxt->context->node == NULL) return(NULL);
 7593: 	switch (ctxt->context->node->type) {
 7594:             case XML_ELEMENT_NODE:
 7595:             case XML_TEXT_NODE:
 7596:             case XML_CDATA_SECTION_NODE:
 7597:             case XML_ENTITY_REF_NODE:
 7598:             case XML_ENTITY_NODE:
 7599:             case XML_PI_NODE:
 7600:             case XML_COMMENT_NODE:
 7601:             case XML_NOTATION_NODE:
 7602:             case XML_DTD_NODE:
 7603: 		return(ctxt->context->node->children);
 7604:             case XML_DOCUMENT_NODE:
 7605:             case XML_DOCUMENT_TYPE_NODE:
 7606:             case XML_DOCUMENT_FRAG_NODE:
 7607:             case XML_HTML_DOCUMENT_NODE:
 7608: #ifdef LIBXML_DOCB_ENABLED
 7609: 	    case XML_DOCB_DOCUMENT_NODE:
 7610: #endif
 7611: 		return(((xmlDocPtr) ctxt->context->node)->children);
 7612: 	    case XML_ELEMENT_DECL:
 7613: 	    case XML_ATTRIBUTE_DECL:
 7614: 	    case XML_ENTITY_DECL:
 7615:             case XML_ATTRIBUTE_NODE:
 7616: 	    case XML_NAMESPACE_DECL:
 7617: 	    case XML_XINCLUDE_START:
 7618: 	    case XML_XINCLUDE_END:
 7619: 		return(NULL);
 7620: 	}
 7621: 	return(NULL);
 7622:     }
 7623:     if ((cur->type == XML_DOCUMENT_NODE) ||
 7624:         (cur->type == XML_HTML_DOCUMENT_NODE))
 7625: 	return(NULL);
 7626:     return(cur->next);
 7627: }
 7628: 
 7629: /**
 7630:  * xmlXPathNextChildElement:
 7631:  * @ctxt:  the XPath Parser context
 7632:  * @cur:  the current node in the traversal
 7633:  *
 7634:  * Traversal function for the "child" direction and nodes of type element.
 7635:  * The child axis contains the children of the context node in document order.
 7636:  *
 7637:  * Returns the next element following that axis
 7638:  */
 7639: static xmlNodePtr
 7640: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7641:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7642:     if (cur == NULL) {
 7643: 	cur = ctxt->context->node;
 7644: 	if (cur == NULL) return(NULL);
 7645: 	/*
 7646: 	* Get the first element child.
 7647: 	*/
 7648: 	switch (cur->type) {
 7649:             case XML_ELEMENT_NODE:
 7650: 	    case XML_DOCUMENT_FRAG_NODE:
 7651: 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
 7652:             case XML_ENTITY_NODE:
 7653: 		cur = cur->children;
 7654: 		if (cur != NULL) {
 7655: 		    if (cur->type == XML_ELEMENT_NODE)
 7656: 			return(cur);
 7657: 		    do {
 7658: 			cur = cur->next;
 7659: 		    } while ((cur != NULL) &&
 7660: 			(cur->type != XML_ELEMENT_NODE));
 7661: 		    return(cur);
 7662: 		}
 7663: 		return(NULL);
 7664:             case XML_DOCUMENT_NODE:
 7665:             case XML_HTML_DOCUMENT_NODE:
 7666: #ifdef LIBXML_DOCB_ENABLED
 7667: 	    case XML_DOCB_DOCUMENT_NODE:
 7668: #endif
 7669: 		return(xmlDocGetRootElement((xmlDocPtr) cur));
 7670: 	    default:
 7671: 		return(NULL);
 7672: 	}
 7673: 	return(NULL);
 7674:     }
 7675:     /*
 7676:     * Get the next sibling element node.
 7677:     */
 7678:     switch (cur->type) {
 7679: 	case XML_ELEMENT_NODE:
 7680: 	case XML_TEXT_NODE:
 7681: 	case XML_ENTITY_REF_NODE:
 7682: 	case XML_ENTITY_NODE:
 7683: 	case XML_CDATA_SECTION_NODE:
 7684: 	case XML_PI_NODE:
 7685: 	case XML_COMMENT_NODE:
 7686: 	case XML_XINCLUDE_END:
 7687: 	    break;
 7688: 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
 7689: 	default:
 7690: 	    return(NULL);
 7691:     }
 7692:     if (cur->next != NULL) {
 7693: 	if (cur->next->type == XML_ELEMENT_NODE)
 7694: 	    return(cur->next);
 7695: 	cur = cur->next;
 7696: 	do {
 7697: 	    cur = cur->next;
 7698: 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
 7699: 	return(cur);
 7700:     }
 7701:     return(NULL);
 7702: }
 7703: 
 7704: /**
 7705:  * xmlXPathNextDescendantOrSelfElemParent:
 7706:  * @ctxt:  the XPath Parser context
 7707:  * @cur:  the current node in the traversal
 7708:  *
 7709:  * Traversal function for the "descendant-or-self" axis.
 7710:  * Additionally it returns only nodes which can be parents of
 7711:  * element nodes.
 7712:  *
 7713:  *
 7714:  * Returns the next element following that axis
 7715:  */
 7716: static xmlNodePtr
 7717: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
 7718: 				       xmlNodePtr contextNode)
 7719: {
 7720:     if (cur == NULL) {
 7721: 	if (contextNode == NULL)
 7722: 	    return(NULL);
 7723: 	switch (contextNode->type) {
 7724: 	    case XML_ELEMENT_NODE:
 7725: 	    case XML_XINCLUDE_START:
 7726: 	    case XML_DOCUMENT_FRAG_NODE:
 7727: 	    case XML_DOCUMENT_NODE:
 7728: #ifdef LIBXML_DOCB_ENABLED
 7729: 	    case XML_DOCB_DOCUMENT_NODE:
 7730: #endif
 7731: 	    case XML_HTML_DOCUMENT_NODE:	    
 7732: 		return(contextNode);
 7733: 	    default:
 7734: 		return(NULL);
 7735: 	}
 7736: 	return(NULL);
 7737:     } else {
 7738: 	xmlNodePtr start = cur;
 7739: 
 7740: 	while (cur != NULL) {
 7741: 	    switch (cur->type) {
 7742: 		case XML_ELEMENT_NODE:
 7743: 		/* TODO: OK to have XInclude here? */
 7744: 		case XML_XINCLUDE_START:
 7745: 		case XML_DOCUMENT_FRAG_NODE:
 7746: 		    if (cur != start)
 7747: 			return(cur);
 7748: 		    if (cur->children != NULL) {
 7749: 			cur = cur->children;
 7750: 			continue;
 7751: 		    }
 7752: 		    break;
 7753: 		/* Not sure if we need those here. */
 7754: 		case XML_DOCUMENT_NODE:
 7755: #ifdef LIBXML_DOCB_ENABLED
 7756: 		case XML_DOCB_DOCUMENT_NODE:
 7757: #endif
 7758: 		case XML_HTML_DOCUMENT_NODE:
 7759: 		    if (cur != start)
 7760: 			return(cur);
 7761: 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
 7762: 		default:
 7763: 		    break;
 7764: 	    }
 7765: 
 7766: next_sibling:
 7767: 	    if ((cur == NULL) || (cur == contextNode))
 7768: 		return(NULL);
 7769: 	    if (cur->next != NULL) {
 7770: 		cur = cur->next;
 7771: 	    } else {
 7772: 		cur = cur->parent;
 7773: 		goto next_sibling;
 7774: 	    }
 7775: 	}
 7776:     }
 7777:     return(NULL);
 7778: }
 7779: 
 7780: /**
 7781:  * xmlXPathNextDescendant:
 7782:  * @ctxt:  the XPath Parser context
 7783:  * @cur:  the current node in the traversal
 7784:  *
 7785:  * Traversal function for the "descendant" direction
 7786:  * the descendant axis contains the descendants of the context node in document
 7787:  * order; a descendant is a child or a child of a child and so on.
 7788:  *
 7789:  * Returns the next element following that axis
 7790:  */
 7791: xmlNodePtr
 7792: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7793:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7794:     if (cur == NULL) {
 7795: 	if (ctxt->context->node == NULL)
 7796: 	    return(NULL);
 7797: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7798: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7799: 	    return(NULL);
 7800: 
 7801:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 7802: 	    return(ctxt->context->doc->children);
 7803:         return(ctxt->context->node->children);
 7804:     }
 7805: 
 7806:     if (cur->children != NULL) {
 7807: 	/*
 7808: 	 * Do not descend on entities declarations
 7809: 	 */
 7810: 	if (cur->children->type != XML_ENTITY_DECL) {
 7811: 	    cur = cur->children;
 7812: 	    /*
 7813: 	     * Skip DTDs
 7814: 	     */
 7815: 	    if (cur->type != XML_DTD_NODE)
 7816: 		return(cur);
 7817: 	}
 7818:     }
 7819: 
 7820:     if (cur == ctxt->context->node) return(NULL);
 7821: 
 7822:     while (cur->next != NULL) {
 7823: 	cur = cur->next;
 7824: 	if ((cur->type != XML_ENTITY_DECL) &&
 7825: 	    (cur->type != XML_DTD_NODE))
 7826: 	    return(cur);
 7827:     }
 7828: 
 7829:     do {
 7830:         cur = cur->parent;
 7831: 	if (cur == NULL) break;
 7832: 	if (cur == ctxt->context->node) return(NULL);
 7833: 	if (cur->next != NULL) {
 7834: 	    cur = cur->next;
 7835: 	    return(cur);
 7836: 	}
 7837:     } while (cur != NULL);
 7838:     return(cur);
 7839: }
 7840: 
 7841: /**
 7842:  * xmlXPathNextDescendantOrSelf:
 7843:  * @ctxt:  the XPath Parser context
 7844:  * @cur:  the current node in the traversal
 7845:  *
 7846:  * Traversal function for the "descendant-or-self" direction
 7847:  * the descendant-or-self axis contains the context node and the descendants
 7848:  * of the context node in document order; thus the context node is the first
 7849:  * node on the axis, and the first child of the context node is the second node
 7850:  * on the axis
 7851:  *
 7852:  * Returns the next element following that axis
 7853:  */
 7854: xmlNodePtr
 7855: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7856:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7857:     if (cur == NULL) {
 7858: 	if (ctxt->context->node == NULL)
 7859: 	    return(NULL);
 7860: 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 7861: 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 7862: 	    return(NULL);
 7863:         return(ctxt->context->node);
 7864:     }
 7865: 
 7866:     return(xmlXPathNextDescendant(ctxt, cur));
 7867: }
 7868: 
 7869: /**
 7870:  * xmlXPathNextParent:
 7871:  * @ctxt:  the XPath Parser context
 7872:  * @cur:  the current node in the traversal
 7873:  *
 7874:  * Traversal function for the "parent" direction
 7875:  * The parent axis contains the parent of the context node, if there is one.
 7876:  *
 7877:  * Returns the next element following that axis
 7878:  */
 7879: xmlNodePtr
 7880: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7881:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7882:     /*
 7883:      * the parent of an attribute or namespace node is the element
 7884:      * to which the attribute or namespace node is attached
 7885:      * Namespace handling !!!
 7886:      */
 7887:     if (cur == NULL) {
 7888: 	if (ctxt->context->node == NULL) return(NULL);
 7889: 	switch (ctxt->context->node->type) {
 7890:             case XML_ELEMENT_NODE:
 7891:             case XML_TEXT_NODE:
 7892:             case XML_CDATA_SECTION_NODE:
 7893:             case XML_ENTITY_REF_NODE:
 7894:             case XML_ENTITY_NODE:
 7895:             case XML_PI_NODE:
 7896:             case XML_COMMENT_NODE:
 7897:             case XML_NOTATION_NODE:
 7898:             case XML_DTD_NODE:
 7899: 	    case XML_ELEMENT_DECL:
 7900: 	    case XML_ATTRIBUTE_DECL:
 7901: 	    case XML_XINCLUDE_START:
 7902: 	    case XML_XINCLUDE_END:
 7903: 	    case XML_ENTITY_DECL:
 7904: 		if (ctxt->context->node->parent == NULL)
 7905: 		    return((xmlNodePtr) ctxt->context->doc);
 7906: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 7907: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 7908: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 7909: 				 BAD_CAST "fake node libxslt"))))
 7910: 		    return(NULL);
 7911: 		return(ctxt->context->node->parent);
 7912:             case XML_ATTRIBUTE_NODE: {
 7913: 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 7914: 
 7915: 		return(att->parent);
 7916: 	    }
 7917:             case XML_DOCUMENT_NODE:
 7918:             case XML_DOCUMENT_TYPE_NODE:
 7919:             case XML_DOCUMENT_FRAG_NODE:
 7920:             case XML_HTML_DOCUMENT_NODE:
 7921: #ifdef LIBXML_DOCB_ENABLED
 7922: 	    case XML_DOCB_DOCUMENT_NODE:
 7923: #endif
 7924:                 return(NULL);
 7925: 	    case XML_NAMESPACE_DECL: {
 7926: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 7927: 
 7928: 		if ((ns->next != NULL) &&
 7929: 		    (ns->next->type != XML_NAMESPACE_DECL))
 7930: 		    return((xmlNodePtr) ns->next);
 7931:                 return(NULL);
 7932: 	    }
 7933: 	}
 7934:     }
 7935:     return(NULL);
 7936: }
 7937: 
 7938: /**
 7939:  * xmlXPathNextAncestor:
 7940:  * @ctxt:  the XPath Parser context
 7941:  * @cur:  the current node in the traversal
 7942:  *
 7943:  * Traversal function for the "ancestor" direction
 7944:  * the ancestor axis contains the ancestors of the context node; the ancestors
 7945:  * of the context node consist of the parent of context node and the parent's
 7946:  * parent and so on; the nodes are ordered in reverse document order; thus the
 7947:  * parent is the first node on the axis, and the parent's parent is the second
 7948:  * node on the axis
 7949:  *
 7950:  * Returns the next element following that axis
 7951:  */
 7952: xmlNodePtr
 7953: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 7954:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 7955:     /*
 7956:      * the parent of an attribute or namespace node is the element
 7957:      * to which the attribute or namespace node is attached
 7958:      * !!!!!!!!!!!!!
 7959:      */
 7960:     if (cur == NULL) {
 7961: 	if (ctxt->context->node == NULL) return(NULL);
 7962: 	switch (ctxt->context->node->type) {
 7963:             case XML_ELEMENT_NODE:
 7964:             case XML_TEXT_NODE:
 7965:             case XML_CDATA_SECTION_NODE:
 7966:             case XML_ENTITY_REF_NODE:
 7967:             case XML_ENTITY_NODE:
 7968:             case XML_PI_NODE:
 7969:             case XML_COMMENT_NODE:
 7970: 	    case XML_DTD_NODE:
 7971: 	    case XML_ELEMENT_DECL:
 7972: 	    case XML_ATTRIBUTE_DECL:
 7973: 	    case XML_ENTITY_DECL:
 7974:             case XML_NOTATION_NODE:
 7975: 	    case XML_XINCLUDE_START:
 7976: 	    case XML_XINCLUDE_END:
 7977: 		if (ctxt->context->node->parent == NULL)
 7978: 		    return((xmlNodePtr) ctxt->context->doc);
 7979: 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
 7980: 		    ((ctxt->context->node->parent->name[0] == ' ') ||
 7981: 		     (xmlStrEqual(ctxt->context->node->parent->name,
 7982: 				 BAD_CAST "fake node libxslt"))))
 7983: 		    return(NULL);
 7984: 		return(ctxt->context->node->parent);
 7985:             case XML_ATTRIBUTE_NODE: {
 7986: 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
 7987: 
 7988: 		return(tmp->parent);
 7989: 	    }
 7990:             case XML_DOCUMENT_NODE:
 7991:             case XML_DOCUMENT_TYPE_NODE:
 7992:             case XML_DOCUMENT_FRAG_NODE:
 7993:             case XML_HTML_DOCUMENT_NODE:
 7994: #ifdef LIBXML_DOCB_ENABLED
 7995: 	    case XML_DOCB_DOCUMENT_NODE:
 7996: #endif
 7997:                 return(NULL);
 7998: 	    case XML_NAMESPACE_DECL: {
 7999: 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 8000: 
 8001: 		if ((ns->next != NULL) &&
 8002: 		    (ns->next->type != XML_NAMESPACE_DECL))
 8003: 		    return((xmlNodePtr) ns->next);
 8004: 		/* Bad, how did that namespace end up here ? */
 8005:                 return(NULL);
 8006: 	    }
 8007: 	}
 8008: 	return(NULL);
 8009:     }
 8010:     if (cur == ctxt->context->doc->children)
 8011: 	return((xmlNodePtr) ctxt->context->doc);
 8012:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8013: 	return(NULL);
 8014:     switch (cur->type) {
 8015: 	case XML_ELEMENT_NODE:
 8016: 	case XML_TEXT_NODE:
 8017: 	case XML_CDATA_SECTION_NODE:
 8018: 	case XML_ENTITY_REF_NODE:
 8019: 	case XML_ENTITY_NODE:
 8020: 	case XML_PI_NODE:
 8021: 	case XML_COMMENT_NODE:
 8022: 	case XML_NOTATION_NODE:
 8023: 	case XML_DTD_NODE:
 8024:         case XML_ELEMENT_DECL:
 8025:         case XML_ATTRIBUTE_DECL:
 8026:         case XML_ENTITY_DECL:
 8027: 	case XML_XINCLUDE_START:
 8028: 	case XML_XINCLUDE_END:
 8029: 	    if (cur->parent == NULL)
 8030: 		return(NULL);
 8031: 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
 8032: 		((cur->parent->name[0] == ' ') ||
 8033: 		 (xmlStrEqual(cur->parent->name,
 8034: 			      BAD_CAST "fake node libxslt"))))
 8035: 		return(NULL);
 8036: 	    return(cur->parent);
 8037: 	case XML_ATTRIBUTE_NODE: {
 8038: 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
 8039: 
 8040: 	    return(att->parent);
 8041: 	}
 8042: 	case XML_NAMESPACE_DECL: {
 8043: 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
 8044: 
 8045: 	    if ((ns->next != NULL) &&
 8046: 	        (ns->next->type != XML_NAMESPACE_DECL))
 8047: 	        return((xmlNodePtr) ns->next);
 8048: 	    /* Bad, how did that namespace end up here ? */
 8049:             return(NULL);
 8050: 	}
 8051: 	case XML_DOCUMENT_NODE:
 8052: 	case XML_DOCUMENT_TYPE_NODE:
 8053: 	case XML_DOCUMENT_FRAG_NODE:
 8054: 	case XML_HTML_DOCUMENT_NODE:
 8055: #ifdef LIBXML_DOCB_ENABLED
 8056: 	case XML_DOCB_DOCUMENT_NODE:
 8057: #endif
 8058: 	    return(NULL);
 8059:     }
 8060:     return(NULL);
 8061: }
 8062: 
 8063: /**
 8064:  * xmlXPathNextAncestorOrSelf:
 8065:  * @ctxt:  the XPath Parser context
 8066:  * @cur:  the current node in the traversal
 8067:  *
 8068:  * Traversal function for the "ancestor-or-self" direction
 8069:  * he ancestor-or-self axis contains the context node and ancestors of
 8070:  * the context node in reverse document order; thus the context node is
 8071:  * the first node on the axis, and the context node's parent the second;
 8072:  * parent here is defined the same as with the parent axis.
 8073:  *
 8074:  * Returns the next element following that axis
 8075:  */
 8076: xmlNodePtr
 8077: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8078:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8079:     if (cur == NULL)
 8080:         return(ctxt->context->node);
 8081:     return(xmlXPathNextAncestor(ctxt, cur));
 8082: }
 8083: 
 8084: /**
 8085:  * xmlXPathNextFollowingSibling:
 8086:  * @ctxt:  the XPath Parser context
 8087:  * @cur:  the current node in the traversal
 8088:  *
 8089:  * Traversal function for the "following-sibling" direction
 8090:  * The following-sibling axis contains the following siblings of the context
 8091:  * node in document order.
 8092:  *
 8093:  * Returns the next element following that axis
 8094:  */
 8095: xmlNodePtr
 8096: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8097:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8098:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8099: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8100: 	return(NULL);
 8101:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8102:         return(NULL);
 8103:     if (cur == NULL)
 8104:         return(ctxt->context->node->next);
 8105:     return(cur->next);
 8106: }
 8107: 
 8108: /**
 8109:  * xmlXPathNextPrecedingSibling:
 8110:  * @ctxt:  the XPath Parser context
 8111:  * @cur:  the current node in the traversal
 8112:  *
 8113:  * Traversal function for the "preceding-sibling" direction
 8114:  * The preceding-sibling axis contains the preceding siblings of the context
 8115:  * node in reverse document order; the first preceding sibling is first on the
 8116:  * axis; the sibling preceding that node is the second on the axis and so on.
 8117:  *
 8118:  * Returns the next element following that axis
 8119:  */
 8120: xmlNodePtr
 8121: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8122:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8123:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 8124: 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 8125: 	return(NULL);
 8126:     if (cur == (xmlNodePtr) ctxt->context->doc)
 8127:         return(NULL);
 8128:     if (cur == NULL)
 8129:         return(ctxt->context->node->prev);
 8130:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
 8131: 	cur = cur->prev;
 8132: 	if (cur == NULL)
 8133: 	    return(ctxt->context->node->prev);
 8134:     }
 8135:     return(cur->prev);
 8136: }
 8137: 
 8138: /**
 8139:  * xmlXPathNextFollowing:
 8140:  * @ctxt:  the XPath Parser context
 8141:  * @cur:  the current node in the traversal
 8142:  *
 8143:  * Traversal function for the "following" direction
 8144:  * The following axis contains all nodes in the same document as the context
 8145:  * node that are after the context node in document order, excluding any
 8146:  * descendants and excluding attribute nodes and namespace nodes; the nodes
 8147:  * are ordered in document order
 8148:  *
 8149:  * Returns the next element following that axis
 8150:  */
 8151: xmlNodePtr
 8152: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8153:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8154:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
 8155:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
 8156:         return(cur->children);
 8157: 
 8158:     if (cur == NULL) {
 8159:         cur = ctxt->context->node;
 8160:         if (cur->type == XML_NAMESPACE_DECL)
 8161:             return(NULL);
 8162:         if (cur->type == XML_ATTRIBUTE_NODE)
 8163:             cur = cur->parent;
 8164:     }
 8165:     if (cur == NULL) return(NULL) ; /* ERROR */
 8166:     if (cur->next != NULL) return(cur->next) ;
 8167:     do {
 8168:         cur = cur->parent;
 8169:         if (cur == NULL) break;
 8170:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
 8171:         if (cur->next != NULL) return(cur->next);
 8172:     } while (cur != NULL);
 8173:     return(cur);
 8174: }
 8175: 
 8176: /*
 8177:  * xmlXPathIsAncestor:
 8178:  * @ancestor:  the ancestor node
 8179:  * @node:  the current node
 8180:  *
 8181:  * Check that @ancestor is a @node's ancestor
 8182:  *
 8183:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
 8184:  */
 8185: static int
 8186: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
 8187:     if ((ancestor == NULL) || (node == NULL)) return(0);
 8188:     /* nodes need to be in the same document */
 8189:     if (ancestor->doc != node->doc) return(0);
 8190:     /* avoid searching if ancestor or node is the root node */
 8191:     if (ancestor == (xmlNodePtr) node->doc) return(1);
 8192:     if (node == (xmlNodePtr) ancestor->doc) return(0);
 8193:     while (node->parent != NULL) {
 8194:         if (node->parent == ancestor)
 8195:             return(1);
 8196: 	node = node->parent;
 8197:     }
 8198:     return(0);
 8199: }
 8200: 
 8201: /**
 8202:  * xmlXPathNextPreceding:
 8203:  * @ctxt:  the XPath Parser context
 8204:  * @cur:  the current node in the traversal
 8205:  *
 8206:  * Traversal function for the "preceding" direction
 8207:  * the preceding axis contains all nodes in the same document as the context
 8208:  * node that are before the context node in document order, excluding any
 8209:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8210:  * ordered in reverse document order
 8211:  *
 8212:  * Returns the next element following that axis
 8213:  */
 8214: xmlNodePtr
 8215: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
 8216: {
 8217:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8218:     if (cur == NULL) {
 8219:         cur = ctxt->context->node;
 8220:         if (cur->type == XML_NAMESPACE_DECL)
 8221:             return(NULL);
 8222:         if (cur->type == XML_ATTRIBUTE_NODE)
 8223:             return(cur->parent);
 8224:     }
 8225:     if (cur == NULL)
 8226: 	return (NULL);
 8227:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8228: 	cur = cur->prev;
 8229:     do {
 8230:         if (cur->prev != NULL) {
 8231:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
 8232:             return (cur);
 8233:         }
 8234: 
 8235:         cur = cur->parent;
 8236:         if (cur == NULL)
 8237:             return (NULL);
 8238:         if (cur == ctxt->context->doc->children)
 8239:             return (NULL);
 8240:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
 8241:     return (cur);
 8242: }
 8243: 
 8244: /**
 8245:  * xmlXPathNextPrecedingInternal:
 8246:  * @ctxt:  the XPath Parser context
 8247:  * @cur:  the current node in the traversal
 8248:  *
 8249:  * Traversal function for the "preceding" direction
 8250:  * the preceding axis contains all nodes in the same document as the context
 8251:  * node that are before the context node in document order, excluding any
 8252:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
 8253:  * ordered in reverse document order
 8254:  * This is a faster implementation but internal only since it requires a
 8255:  * state kept in the parser context: ctxt->ancestor.
 8256:  *
 8257:  * Returns the next element following that axis
 8258:  */
 8259: static xmlNodePtr
 8260: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
 8261:                               xmlNodePtr cur)
 8262: {
 8263:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8264:     if (cur == NULL) {
 8265:         cur = ctxt->context->node;
 8266:         if (cur == NULL)
 8267:             return (NULL);
 8268:         if (cur->type == XML_NAMESPACE_DECL)
 8269:             return (NULL);
 8270:         ctxt->ancestor = cur->parent;
 8271:     }
 8272:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
 8273: 	cur = cur->prev;
 8274:     while (cur->prev == NULL) {
 8275:         cur = cur->parent;
 8276:         if (cur == NULL)
 8277:             return (NULL);
 8278:         if (cur == ctxt->context->doc->children)
 8279:             return (NULL);
 8280:         if (cur != ctxt->ancestor)
 8281:             return (cur);
 8282:         ctxt->ancestor = cur->parent;
 8283:     }
 8284:     cur = cur->prev;
 8285:     while (cur->last != NULL)
 8286:         cur = cur->last;
 8287:     return (cur);
 8288: }
 8289: 
 8290: /**
 8291:  * xmlXPathNextNamespace:
 8292:  * @ctxt:  the XPath Parser context
 8293:  * @cur:  the current attribute in the traversal
 8294:  *
 8295:  * Traversal function for the "namespace" direction
 8296:  * the namespace axis contains the namespace nodes of the context node;
 8297:  * the order of nodes on this axis is implementation-defined; the axis will
 8298:  * be empty unless the context node is an element
 8299:  *
 8300:  * We keep the XML namespace node at the end of the list.
 8301:  *
 8302:  * Returns the next element following that axis
 8303:  */
 8304: xmlNodePtr
 8305: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8306:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8307:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
 8308:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
 8309:         if (ctxt->context->tmpNsList != NULL)
 8310: 	    xmlFree(ctxt->context->tmpNsList);
 8311: 	ctxt->context->tmpNsList =
 8312: 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
 8313: 	ctxt->context->tmpNsNr = 0;
 8314: 	if (ctxt->context->tmpNsList != NULL) {
 8315: 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
 8316: 		ctxt->context->tmpNsNr++;
 8317: 	    }
 8318: 	}
 8319: 	return((xmlNodePtr) xmlXPathXMLNamespace);
 8320:     }
 8321:     if (ctxt->context->tmpNsNr > 0) {
 8322: 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
 8323:     } else {
 8324: 	if (ctxt->context->tmpNsList != NULL)
 8325: 	    xmlFree(ctxt->context->tmpNsList);
 8326: 	ctxt->context->tmpNsList = NULL;
 8327: 	return(NULL);
 8328:     }
 8329: }
 8330: 
 8331: /**
 8332:  * xmlXPathNextAttribute:
 8333:  * @ctxt:  the XPath Parser context
 8334:  * @cur:  the current attribute in the traversal
 8335:  *
 8336:  * Traversal function for the "attribute" direction
 8337:  * TODO: support DTD inherited default attributes
 8338:  *
 8339:  * Returns the next element following that axis
 8340:  */
 8341: xmlNodePtr
 8342: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 8343:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
 8344:     if (ctxt->context->node == NULL)
 8345: 	return(NULL);
 8346:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
 8347: 	return(NULL);
 8348:     if (cur == NULL) {
 8349:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 8350: 	    return(NULL);
 8351:         return((xmlNodePtr)ctxt->context->node->properties);
 8352:     }
 8353:     return((xmlNodePtr)cur->next);
 8354: }
 8355: 
 8356: /************************************************************************
 8357:  *									*
 8358:  *		NodeTest Functions					*
 8359:  *									*
 8360:  ************************************************************************/
 8361: 
 8362: #define IS_FUNCTION			200
 8363: 
 8364: 
 8365: /************************************************************************
 8366:  *									*
 8367:  *		Implicit tree core function library			*
 8368:  *									*
 8369:  ************************************************************************/
 8370: 
 8371: /**
 8372:  * xmlXPathRoot:
 8373:  * @ctxt:  the XPath Parser context
 8374:  *
 8375:  * Initialize the context to the root of the document
 8376:  */
 8377: void
 8378: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
 8379:     if ((ctxt == NULL) || (ctxt->context == NULL))
 8380: 	return;
 8381:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
 8382:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8383: 	ctxt->context->node));
 8384: }
 8385: 
 8386: /************************************************************************
 8387:  *									*
 8388:  *		The explicit core function library			*
 8389:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
 8390:  *									*
 8391:  ************************************************************************/
 8392: 
 8393: 
 8394: /**
 8395:  * xmlXPathLastFunction:
 8396:  * @ctxt:  the XPath Parser context
 8397:  * @nargs:  the number of arguments
 8398:  *
 8399:  * Implement the last() XPath function
 8400:  *    number last()
 8401:  * The last function returns the number of nodes in the context node list.
 8402:  */
 8403: void
 8404: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8405:     CHECK_ARITY(0);
 8406:     if (ctxt->context->contextSize >= 0) {
 8407: 	valuePush(ctxt,
 8408: 	    xmlXPathCacheNewFloat(ctxt->context,
 8409: 		(double) ctxt->context->contextSize));
 8410: #ifdef DEBUG_EXPR
 8411: 	xmlGenericError(xmlGenericErrorContext,
 8412: 		"last() : %d\n", ctxt->context->contextSize);
 8413: #endif
 8414:     } else {
 8415: 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
 8416:     }
 8417: }
 8418: 
 8419: /**
 8420:  * xmlXPathPositionFunction:
 8421:  * @ctxt:  the XPath Parser context
 8422:  * @nargs:  the number of arguments
 8423:  *
 8424:  * Implement the position() XPath function
 8425:  *    number position()
 8426:  * The position function returns the position of the context node in the
 8427:  * context node list. The first position is 1, and so the last position
 8428:  * will be equal to last().
 8429:  */
 8430: void
 8431: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8432:     CHECK_ARITY(0);
 8433:     if (ctxt->context->proximityPosition >= 0) {
 8434: 	valuePush(ctxt,
 8435: 	      xmlXPathCacheNewFloat(ctxt->context,
 8436: 		(double) ctxt->context->proximityPosition));
 8437: #ifdef DEBUG_EXPR
 8438: 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
 8439: 		ctxt->context->proximityPosition);
 8440: #endif
 8441:     } else {
 8442: 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
 8443:     }
 8444: }
 8445: 
 8446: /**
 8447:  * xmlXPathCountFunction:
 8448:  * @ctxt:  the XPath Parser context
 8449:  * @nargs:  the number of arguments
 8450:  *
 8451:  * Implement the count() XPath function
 8452:  *    number count(node-set)
 8453:  */
 8454: void
 8455: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8456:     xmlXPathObjectPtr cur;
 8457: 
 8458:     CHECK_ARITY(1);
 8459:     if ((ctxt->value == NULL) ||
 8460: 	((ctxt->value->type != XPATH_NODESET) &&
 8461: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8462: 	XP_ERROR(XPATH_INVALID_TYPE);
 8463:     cur = valuePop(ctxt);
 8464: 
 8465:     if ((cur == NULL) || (cur->nodesetval == NULL))
 8466: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8467:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
 8468: 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8469: 	    (double) cur->nodesetval->nodeNr));
 8470:     } else {
 8471: 	if ((cur->nodesetval->nodeNr != 1) ||
 8472: 	    (cur->nodesetval->nodeTab == NULL)) {
 8473: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
 8474: 	} else {
 8475: 	    xmlNodePtr tmp;
 8476: 	    int i = 0;
 8477: 
 8478: 	    tmp = cur->nodesetval->nodeTab[0];
 8479: 	    if (tmp != NULL) {
 8480: 		tmp = tmp->children;
 8481: 		while (tmp != NULL) {
 8482: 		    tmp = tmp->next;
 8483: 		    i++;
 8484: 		}
 8485: 	    }
 8486: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
 8487: 	}
 8488:     }
 8489:     xmlXPathReleaseObject(ctxt->context, cur);
 8490: }
 8491: 
 8492: /**
 8493:  * xmlXPathGetElementsByIds:
 8494:  * @doc:  the document
 8495:  * @ids:  a whitespace separated list of IDs
 8496:  *
 8497:  * Selects elements by their unique ID.
 8498:  *
 8499:  * Returns a node-set of selected elements.
 8500:  */
 8501: static xmlNodeSetPtr
 8502: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
 8503:     xmlNodeSetPtr ret;
 8504:     const xmlChar *cur = ids;
 8505:     xmlChar *ID;
 8506:     xmlAttrPtr attr;
 8507:     xmlNodePtr elem = NULL;
 8508: 
 8509:     if (ids == NULL) return(NULL);
 8510: 
 8511:     ret = xmlXPathNodeSetCreate(NULL);
 8512:     if (ret == NULL)
 8513:         return(ret);
 8514: 
 8515:     while (IS_BLANK_CH(*cur)) cur++;
 8516:     while (*cur != 0) {
 8517: 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
 8518: 	    cur++;
 8519: 
 8520:         ID = xmlStrndup(ids, cur - ids);
 8521: 	if (ID != NULL) {
 8522: 	    /*
 8523: 	     * We used to check the fact that the value passed
 8524: 	     * was an NCName, but this generated much troubles for
 8525: 	     * me and Aleksey Sanin, people blatantly violated that
 8526: 	     * constaint, like Visa3D spec.
 8527: 	     * if (xmlValidateNCName(ID, 1) == 0)
 8528: 	     */
 8529: 	    attr = xmlGetID(doc, ID);
 8530: 	    if (attr != NULL) {
 8531: 		if (attr->type == XML_ATTRIBUTE_NODE)
 8532: 		    elem = attr->parent;
 8533: 		else if (attr->type == XML_ELEMENT_NODE)
 8534: 		    elem = (xmlNodePtr) attr;
 8535: 		else
 8536: 		    elem = NULL;
 8537: 		if (elem != NULL)
 8538: 		    xmlXPathNodeSetAdd(ret, elem);
 8539: 	    }
 8540: 	    xmlFree(ID);
 8541: 	}
 8542: 
 8543: 	while (IS_BLANK_CH(*cur)) cur++;
 8544: 	ids = cur;
 8545:     }
 8546:     return(ret);
 8547: }
 8548: 
 8549: /**
 8550:  * xmlXPathIdFunction:
 8551:  * @ctxt:  the XPath Parser context
 8552:  * @nargs:  the number of arguments
 8553:  *
 8554:  * Implement the id() XPath function
 8555:  *    node-set id(object)
 8556:  * The id function selects elements by their unique ID
 8557:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
 8558:  * then the result is the union of the result of applying id to the
 8559:  * string value of each of the nodes in the argument node-set. When the
 8560:  * argument to id is of any other type, the argument is converted to a
 8561:  * string as if by a call to the string function; the string is split
 8562:  * into a whitespace-separated list of tokens (whitespace is any sequence
 8563:  * of characters matching the production S); the result is a node-set
 8564:  * containing the elements in the same document as the context node that
 8565:  * have a unique ID equal to any of the tokens in the list.
 8566:  */
 8567: void
 8568: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8569:     xmlChar *tokens;
 8570:     xmlNodeSetPtr ret;
 8571:     xmlXPathObjectPtr obj;
 8572: 
 8573:     CHECK_ARITY(1);
 8574:     obj = valuePop(ctxt);
 8575:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8576:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
 8577: 	xmlNodeSetPtr ns;
 8578: 	int i;
 8579: 
 8580: 	ret = xmlXPathNodeSetCreate(NULL);
 8581:         /*
 8582:          * FIXME -- in an out-of-memory condition this will behave badly.
 8583:          * The solution is not clear -- we already popped an item from
 8584:          * ctxt, so the object is in a corrupt state.
 8585:          */
 8586: 
 8587: 	if (obj->nodesetval != NULL) {
 8588: 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 8589: 		tokens =
 8590: 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
 8591: 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
 8592: 		ret = xmlXPathNodeSetMerge(ret, ns);
 8593: 		xmlXPathFreeNodeSet(ns);
 8594: 		if (tokens != NULL)
 8595: 		    xmlFree(tokens);
 8596: 	    }
 8597: 	}
 8598: 	xmlXPathReleaseObject(ctxt->context, obj);
 8599: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8600: 	return;
 8601:     }
 8602:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
 8603:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
 8604:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
 8605:     xmlXPathReleaseObject(ctxt->context, obj);
 8606:     return;
 8607: }
 8608: 
 8609: /**
 8610:  * xmlXPathLocalNameFunction:
 8611:  * @ctxt:  the XPath Parser context
 8612:  * @nargs:  the number of arguments
 8613:  *
 8614:  * Implement the local-name() XPath function
 8615:  *    string local-name(node-set?)
 8616:  * The local-name function returns a string containing the local part
 8617:  * of the name of the node in the argument node-set that is first in
 8618:  * document order. If the node-set is empty or the first node has no
 8619:  * name, an empty string is returned. If the argument is omitted it
 8620:  * defaults to the context node.
 8621:  */
 8622: void
 8623: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8624:     xmlXPathObjectPtr cur;
 8625: 
 8626:     if (ctxt == NULL) return;
 8627: 
 8628:     if (nargs == 0) {
 8629: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8630: 	    ctxt->context->node));
 8631: 	nargs = 1;
 8632:     }
 8633: 
 8634:     CHECK_ARITY(1);
 8635:     if ((ctxt->value == NULL) ||
 8636: 	((ctxt->value->type != XPATH_NODESET) &&
 8637: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8638: 	XP_ERROR(XPATH_INVALID_TYPE);
 8639:     cur = valuePop(ctxt);
 8640: 
 8641:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8642: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8643:     } else {
 8644: 	int i = 0; /* Should be first in document order !!!!! */
 8645: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8646: 	case XML_ELEMENT_NODE:
 8647: 	case XML_ATTRIBUTE_NODE:
 8648: 	case XML_PI_NODE:
 8649: 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8650: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8651: 	    else
 8652: 		valuePush(ctxt,
 8653: 		      xmlXPathCacheNewString(ctxt->context,
 8654: 			cur->nodesetval->nodeTab[i]->name));
 8655: 	    break;
 8656: 	case XML_NAMESPACE_DECL:
 8657: 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8658: 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
 8659: 	    break;
 8660: 	default:
 8661: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8662: 	}
 8663:     }
 8664:     xmlXPathReleaseObject(ctxt->context, cur);
 8665: }
 8666: 
 8667: /**
 8668:  * xmlXPathNamespaceURIFunction:
 8669:  * @ctxt:  the XPath Parser context
 8670:  * @nargs:  the number of arguments
 8671:  *
 8672:  * Implement the namespace-uri() XPath function
 8673:  *    string namespace-uri(node-set?)
 8674:  * The namespace-uri function returns a string containing the
 8675:  * namespace URI of the expanded name of the node in the argument
 8676:  * node-set that is first in document order. If the node-set is empty,
 8677:  * the first node has no name, or the expanded name has no namespace
 8678:  * URI, an empty string is returned. If the argument is omitted it
 8679:  * defaults to the context node.
 8680:  */
 8681: void
 8682: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8683:     xmlXPathObjectPtr cur;
 8684: 
 8685:     if (ctxt == NULL) return;
 8686: 
 8687:     if (nargs == 0) {
 8688: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8689: 	    ctxt->context->node));
 8690: 	nargs = 1;
 8691:     }
 8692:     CHECK_ARITY(1);
 8693:     if ((ctxt->value == NULL) ||
 8694: 	((ctxt->value->type != XPATH_NODESET) &&
 8695: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 8696: 	XP_ERROR(XPATH_INVALID_TYPE);
 8697:     cur = valuePop(ctxt);
 8698: 
 8699:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8700: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8701:     } else {
 8702: 	int i = 0; /* Should be first in document order !!!!! */
 8703: 	switch (cur->nodesetval->nodeTab[i]->type) {
 8704: 	case XML_ELEMENT_NODE:
 8705: 	case XML_ATTRIBUTE_NODE:
 8706: 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
 8707: 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8708: 	    else
 8709: 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 8710: 			  cur->nodesetval->nodeTab[i]->ns->href));
 8711: 	    break;
 8712: 	default:
 8713: 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8714: 	}
 8715:     }
 8716:     xmlXPathReleaseObject(ctxt->context, cur);
 8717: }
 8718: 
 8719: /**
 8720:  * xmlXPathNameFunction:
 8721:  * @ctxt:  the XPath Parser context
 8722:  * @nargs:  the number of arguments
 8723:  *
 8724:  * Implement the name() XPath function
 8725:  *    string name(node-set?)
 8726:  * The name function returns a string containing a QName representing
 8727:  * the name of the node in the argument node-set that is first in document
 8728:  * order. The QName must represent the name with respect to the namespace
 8729:  * declarations in effect on the node whose name is being represented.
 8730:  * Typically, this will be the form in which the name occurred in the XML
 8731:  * source. This need not be the case if there are namespace declarations
 8732:  * in effect on the node that associate multiple prefixes with the same
 8733:  * namespace. However, an implementation may include information about
 8734:  * the original prefix in its representation of nodes; in this case, an
 8735:  * implementation can ensure that the returned string is always the same
 8736:  * as the QName used in the XML source. If the argument it omitted it
 8737:  * defaults to the context node.
 8738:  * Libxml keep the original prefix so the "real qualified name" used is
 8739:  * returned.
 8740:  */
 8741: static void
 8742: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
 8743: {
 8744:     xmlXPathObjectPtr cur;
 8745: 
 8746:     if (nargs == 0) {
 8747: 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8748: 	    ctxt->context->node));
 8749:         nargs = 1;
 8750:     }
 8751: 
 8752:     CHECK_ARITY(1);
 8753:     if ((ctxt->value == NULL) ||
 8754:         ((ctxt->value->type != XPATH_NODESET) &&
 8755:          (ctxt->value->type != XPATH_XSLT_TREE)))
 8756:         XP_ERROR(XPATH_INVALID_TYPE);
 8757:     cur = valuePop(ctxt);
 8758: 
 8759:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 8760:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 8761:     } else {
 8762:         int i = 0;              /* Should be first in document order !!!!! */
 8763: 
 8764:         switch (cur->nodesetval->nodeTab[i]->type) {
 8765:             case XML_ELEMENT_NODE:
 8766:             case XML_ATTRIBUTE_NODE:
 8767: 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
 8768: 		    valuePush(ctxt,
 8769: 			xmlXPathCacheNewCString(ctxt->context, ""));
 8770: 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
 8771:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
 8772: 		    valuePush(ctxt,
 8773: 		        xmlXPathCacheNewString(ctxt->context,
 8774: 			    cur->nodesetval->nodeTab[i]->name));
 8775: 		} else {
 8776: 		    xmlChar *fullname;
 8777: 
 8778: 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
 8779: 				     cur->nodesetval->nodeTab[i]->ns->prefix,
 8780: 				     NULL, 0);
 8781: 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
 8782: 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
 8783: 		    if (fullname == NULL) {
 8784: 			XP_ERROR(XPATH_MEMORY_ERROR);
 8785: 		    }
 8786: 		    valuePush(ctxt, xmlXPathCacheWrapString(
 8787: 			ctxt->context, fullname));
 8788:                 }
 8789:                 break;
 8790:             default:
 8791: 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
 8792: 		    cur->nodesetval->nodeTab[i]));
 8793:                 xmlXPathLocalNameFunction(ctxt, 1);
 8794:         }
 8795:     }
 8796:     xmlXPathReleaseObject(ctxt->context, cur);
 8797: }
 8798: 
 8799: 
 8800: /**
 8801:  * xmlXPathStringFunction:
 8802:  * @ctxt:  the XPath Parser context
 8803:  * @nargs:  the number of arguments
 8804:  *
 8805:  * Implement the string() XPath function
 8806:  *    string string(object?)
 8807:  * The string function converts an object to a string as follows:
 8808:  *    - A node-set is converted to a string by returning the value of
 8809:  *      the node in the node-set that is first in document order.
 8810:  *      If the node-set is empty, an empty string is returned.
 8811:  *    - A number is converted to a string as follows
 8812:  *      + NaN is converted to the string NaN
 8813:  *      + positive zero is converted to the string 0
 8814:  *      + negative zero is converted to the string 0
 8815:  *      + positive infinity is converted to the string Infinity
 8816:  *      + negative infinity is converted to the string -Infinity
 8817:  *      + if the number is an integer, the number is represented in
 8818:  *        decimal form as a Number with no decimal point and no leading
 8819:  *        zeros, preceded by a minus sign (-) if the number is negative
 8820:  *      + otherwise, the number is represented in decimal form as a
 8821:  *        Number including a decimal point with at least one digit
 8822:  *        before the decimal point and at least one digit after the
 8823:  *        decimal point, preceded by a minus sign (-) if the number
 8824:  *        is negative; there must be no leading zeros before the decimal
 8825:  *        point apart possibly from the one required digit immediately
 8826:  *        before the decimal point; beyond the one required digit
 8827:  *        after the decimal point there must be as many, but only as
 8828:  *        many, more digits as are needed to uniquely distinguish the
 8829:  *        number from all other IEEE 754 numeric values.
 8830:  *    - The boolean false value is converted to the string false.
 8831:  *      The boolean true value is converted to the string true.
 8832:  *
 8833:  * If the argument is omitted, it defaults to a node-set with the
 8834:  * context node as its only member.
 8835:  */
 8836: void
 8837: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8838:     xmlXPathObjectPtr cur;
 8839: 
 8840:     if (ctxt == NULL) return;
 8841:     if (nargs == 0) {
 8842:     valuePush(ctxt,
 8843: 	xmlXPathCacheWrapString(ctxt->context,
 8844: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 8845: 	return;
 8846:     }
 8847: 
 8848:     CHECK_ARITY(1);
 8849:     cur = valuePop(ctxt);
 8850:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 8851:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
 8852: }
 8853: 
 8854: /**
 8855:  * xmlXPathStringLengthFunction:
 8856:  * @ctxt:  the XPath Parser context
 8857:  * @nargs:  the number of arguments
 8858:  *
 8859:  * Implement the string-length() XPath function
 8860:  *    number string-length(string?)
 8861:  * The string-length returns the number of characters in the string
 8862:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
 8863:  * the context node converted to a string, in other words the value
 8864:  * of the context node.
 8865:  */
 8866: void
 8867: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8868:     xmlXPathObjectPtr cur;
 8869: 
 8870:     if (nargs == 0) {
 8871:         if ((ctxt == NULL) || (ctxt->context == NULL))
 8872: 	    return;
 8873: 	if (ctxt->context->node == NULL) {
 8874: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
 8875: 	} else {
 8876: 	    xmlChar *content;
 8877: 
 8878: 	    content = xmlXPathCastNodeToString(ctxt->context->node);
 8879: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8880: 		xmlUTF8Strlen(content)));
 8881: 	    xmlFree(content);
 8882: 	}
 8883: 	return;
 8884:     }
 8885:     CHECK_ARITY(1);
 8886:     CAST_TO_STRING;
 8887:     CHECK_TYPE(XPATH_STRING);
 8888:     cur = valuePop(ctxt);
 8889:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
 8890: 	xmlUTF8Strlen(cur->stringval)));
 8891:     xmlXPathReleaseObject(ctxt->context, cur);
 8892: }
 8893: 
 8894: /**
 8895:  * xmlXPathConcatFunction:
 8896:  * @ctxt:  the XPath Parser context
 8897:  * @nargs:  the number of arguments
 8898:  *
 8899:  * Implement the concat() XPath function
 8900:  *    string concat(string, string, string*)
 8901:  * The concat function returns the concatenation of its arguments.
 8902:  */
 8903: void
 8904: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8905:     xmlXPathObjectPtr cur, newobj;
 8906:     xmlChar *tmp;
 8907: 
 8908:     if (ctxt == NULL) return;
 8909:     if (nargs < 2) {
 8910: 	CHECK_ARITY(2);
 8911:     }
 8912: 
 8913:     CAST_TO_STRING;
 8914:     cur = valuePop(ctxt);
 8915:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
 8916: 	xmlXPathReleaseObject(ctxt->context, cur);
 8917: 	return;
 8918:     }
 8919:     nargs--;
 8920: 
 8921:     while (nargs > 0) {
 8922: 	CAST_TO_STRING;
 8923: 	newobj = valuePop(ctxt);
 8924: 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
 8925: 	    xmlXPathReleaseObject(ctxt->context, newobj);
 8926: 	    xmlXPathReleaseObject(ctxt->context, cur);
 8927: 	    XP_ERROR(XPATH_INVALID_TYPE);
 8928: 	}
 8929: 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
 8930: 	newobj->stringval = cur->stringval;
 8931: 	cur->stringval = tmp;
 8932: 	xmlXPathReleaseObject(ctxt->context, newobj);
 8933: 	nargs--;
 8934:     }
 8935:     valuePush(ctxt, cur);
 8936: }
 8937: 
 8938: /**
 8939:  * xmlXPathContainsFunction:
 8940:  * @ctxt:  the XPath Parser context
 8941:  * @nargs:  the number of arguments
 8942:  *
 8943:  * Implement the contains() XPath function
 8944:  *    boolean contains(string, string)
 8945:  * The contains function returns true if the first argument string
 8946:  * contains the second argument string, and otherwise returns false.
 8947:  */
 8948: void
 8949: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8950:     xmlXPathObjectPtr hay, needle;
 8951: 
 8952:     CHECK_ARITY(2);
 8953:     CAST_TO_STRING;
 8954:     CHECK_TYPE(XPATH_STRING);
 8955:     needle = valuePop(ctxt);
 8956:     CAST_TO_STRING;
 8957:     hay = valuePop(ctxt);
 8958: 
 8959:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 8960: 	xmlXPathReleaseObject(ctxt->context, hay);
 8961: 	xmlXPathReleaseObject(ctxt->context, needle);
 8962: 	XP_ERROR(XPATH_INVALID_TYPE);
 8963:     }
 8964:     if (xmlStrstr(hay->stringval, needle->stringval))
 8965: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 8966:     else
 8967: 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 8968:     xmlXPathReleaseObject(ctxt->context, hay);
 8969:     xmlXPathReleaseObject(ctxt->context, needle);
 8970: }
 8971: 
 8972: /**
 8973:  * xmlXPathStartsWithFunction:
 8974:  * @ctxt:  the XPath Parser context
 8975:  * @nargs:  the number of arguments
 8976:  *
 8977:  * Implement the starts-with() XPath function
 8978:  *    boolean starts-with(string, string)
 8979:  * The starts-with function returns true if the first argument string
 8980:  * starts with the second argument string, and otherwise returns false.
 8981:  */
 8982: void
 8983: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 8984:     xmlXPathObjectPtr hay, needle;
 8985:     int n;
 8986: 
 8987:     CHECK_ARITY(2);
 8988:     CAST_TO_STRING;
 8989:     CHECK_TYPE(XPATH_STRING);
 8990:     needle = valuePop(ctxt);
 8991:     CAST_TO_STRING;
 8992:     hay = valuePop(ctxt);
 8993: 
 8994:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
 8995: 	xmlXPathReleaseObject(ctxt->context, hay);
 8996: 	xmlXPathReleaseObject(ctxt->context, needle);
 8997: 	XP_ERROR(XPATH_INVALID_TYPE);
 8998:     }
 8999:     n = xmlStrlen(needle->stringval);
 9000:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
 9001:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9002:     else
 9003:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9004:     xmlXPathReleaseObject(ctxt->context, hay);
 9005:     xmlXPathReleaseObject(ctxt->context, needle);
 9006: }
 9007: 
 9008: /**
 9009:  * xmlXPathSubstringFunction:
 9010:  * @ctxt:  the XPath Parser context
 9011:  * @nargs:  the number of arguments
 9012:  *
 9013:  * Implement the substring() XPath function
 9014:  *    string substring(string, number, number?)
 9015:  * The substring function returns the substring of the first argument
 9016:  * starting at the position specified in the second argument with
 9017:  * length specified in the third argument. For example,
 9018:  * substring("12345",2,3) returns "234". If the third argument is not
 9019:  * specified, it returns the substring starting at the position specified
 9020:  * in the second argument and continuing to the end of the string. For
 9021:  * example, substring("12345",2) returns "2345".  More precisely, each
 9022:  * character in the string (see [3.6 Strings]) is considered to have a
 9023:  * numeric position: the position of the first character is 1, the position
 9024:  * of the second character is 2 and so on. The returned substring contains
 9025:  * those characters for which the position of the character is greater than
 9026:  * or equal to the second argument and, if the third argument is specified,
 9027:  * less than the sum of the second and third arguments; the comparisons
 9028:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
 9029:  *  - substring("12345", 1.5, 2.6) returns "234"
 9030:  *  - substring("12345", 0, 3) returns "12"
 9031:  *  - substring("12345", 0 div 0, 3) returns ""
 9032:  *  - substring("12345", 1, 0 div 0) returns ""
 9033:  *  - substring("12345", -42, 1 div 0) returns "12345"
 9034:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
 9035:  */
 9036: void
 9037: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9038:     xmlXPathObjectPtr str, start, len;
 9039:     double le=0, in;
 9040:     int i, l, m;
 9041:     xmlChar *ret;
 9042: 
 9043:     if (nargs < 2) {
 9044: 	CHECK_ARITY(2);
 9045:     }
 9046:     if (nargs > 3) {
 9047: 	CHECK_ARITY(3);
 9048:     }
 9049:     /*
 9050:      * take care of possible last (position) argument
 9051:     */
 9052:     if (nargs == 3) {
 9053: 	CAST_TO_NUMBER;
 9054: 	CHECK_TYPE(XPATH_NUMBER);
 9055: 	len = valuePop(ctxt);
 9056: 	le = len->floatval;
 9057: 	xmlXPathReleaseObject(ctxt->context, len);
 9058:     }
 9059: 
 9060:     CAST_TO_NUMBER;
 9061:     CHECK_TYPE(XPATH_NUMBER);
 9062:     start = valuePop(ctxt);
 9063:     in = start->floatval;
 9064:     xmlXPathReleaseObject(ctxt->context, start);
 9065:     CAST_TO_STRING;
 9066:     CHECK_TYPE(XPATH_STRING);
 9067:     str = valuePop(ctxt);
 9068:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
 9069: 
 9070:     /*
 9071:      * If last pos not present, calculate last position
 9072:     */
 9073:     if (nargs != 3) {
 9074: 	le = (double)m;
 9075: 	if (in < 1.0)
 9076: 	    in = 1.0;
 9077:     }
 9078: 
 9079:     /* Need to check for the special cases where either
 9080:      * the index is NaN, the length is NaN, or both
 9081:      * arguments are infinity (relying on Inf + -Inf = NaN)
 9082:      */
 9083:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
 9084:         /*
 9085:          * To meet the requirements of the spec, the arguments
 9086: 	 * must be converted to integer format before
 9087: 	 * initial index calculations are done
 9088:          *
 9089:          * First we go to integer form, rounding up
 9090: 	 * and checking for special cases
 9091:          */
 9092:         i = (int) in;
 9093:         if (((double)i)+0.5 <= in) i++;
 9094: 
 9095: 	if (xmlXPathIsInf(le) == 1) {
 9096: 	    l = m;
 9097: 	    if (i < 1)
 9098: 		i = 1;
 9099: 	}
 9100: 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
 9101: 	    l = 0;
 9102: 	else {
 9103: 	    l = (int) le;
 9104: 	    if (((double)l)+0.5 <= le) l++;
 9105: 	}
 9106: 
 9107: 	/* Now we normalize inidices */
 9108:         i -= 1;
 9109:         l += i;
 9110:         if (i < 0)
 9111:             i = 0;
 9112:         if (l > m)
 9113:             l = m;
 9114: 
 9115:         /* number of chars to copy */
 9116:         l -= i;
 9117: 
 9118:         ret = xmlUTF8Strsub(str->stringval, i, l);
 9119:     }
 9120:     else {
 9121:         ret = NULL;
 9122:     }
 9123:     if (ret == NULL)
 9124: 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
 9125:     else {
 9126: 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
 9127: 	xmlFree(ret);
 9128:     }
 9129:     xmlXPathReleaseObject(ctxt->context, str);
 9130: }
 9131: 
 9132: /**
 9133:  * xmlXPathSubstringBeforeFunction:
 9134:  * @ctxt:  the XPath Parser context
 9135:  * @nargs:  the number of arguments
 9136:  *
 9137:  * Implement the substring-before() XPath function
 9138:  *    string substring-before(string, string)
 9139:  * The substring-before function returns the substring of the first
 9140:  * argument string that precedes the first occurrence of the second
 9141:  * argument string in the first argument string, or the empty string
 9142:  * if the first argument string does not contain the second argument
 9143:  * string. For example, substring-before("1999/04/01","/") returns 1999.
 9144:  */
 9145: void
 9146: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9147:   xmlXPathObjectPtr str;
 9148:   xmlXPathObjectPtr find;
 9149:   xmlBufferPtr target;
 9150:   const xmlChar *point;
 9151:   int offset;
 9152: 
 9153:   CHECK_ARITY(2);
 9154:   CAST_TO_STRING;
 9155:   find = valuePop(ctxt);
 9156:   CAST_TO_STRING;
 9157:   str = valuePop(ctxt);
 9158: 
 9159:   target = xmlBufferCreate();
 9160:   if (target) {
 9161:     point = xmlStrstr(str->stringval, find->stringval);
 9162:     if (point) {
 9163:       offset = (int)(point - str->stringval);
 9164:       xmlBufferAdd(target, str->stringval, offset);
 9165:     }
 9166:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9167: 	xmlBufferContent(target)));
 9168:     xmlBufferFree(target);
 9169:   }
 9170:   xmlXPathReleaseObject(ctxt->context, str);
 9171:   xmlXPathReleaseObject(ctxt->context, find);
 9172: }
 9173: 
 9174: /**
 9175:  * xmlXPathSubstringAfterFunction:
 9176:  * @ctxt:  the XPath Parser context
 9177:  * @nargs:  the number of arguments
 9178:  *
 9179:  * Implement the substring-after() XPath function
 9180:  *    string substring-after(string, string)
 9181:  * The substring-after function returns the substring of the first
 9182:  * argument string that follows the first occurrence of the second
 9183:  * argument string in the first argument string, or the empty stringi
 9184:  * if the first argument string does not contain the second argument
 9185:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
 9186:  * and substring-after("1999/04/01","19") returns 99/04/01.
 9187:  */
 9188: void
 9189: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9190:   xmlXPathObjectPtr str;
 9191:   xmlXPathObjectPtr find;
 9192:   xmlBufferPtr target;
 9193:   const xmlChar *point;
 9194:   int offset;
 9195: 
 9196:   CHECK_ARITY(2);
 9197:   CAST_TO_STRING;
 9198:   find = valuePop(ctxt);
 9199:   CAST_TO_STRING;
 9200:   str = valuePop(ctxt);
 9201: 
 9202:   target = xmlBufferCreate();
 9203:   if (target) {
 9204:     point = xmlStrstr(str->stringval, find->stringval);
 9205:     if (point) {
 9206:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
 9207:       xmlBufferAdd(target, &str->stringval[offset],
 9208: 		   xmlStrlen(str->stringval) - offset);
 9209:     }
 9210:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9211: 	xmlBufferContent(target)));
 9212:     xmlBufferFree(target);
 9213:   }
 9214:   xmlXPathReleaseObject(ctxt->context, str);
 9215:   xmlXPathReleaseObject(ctxt->context, find);
 9216: }
 9217: 
 9218: /**
 9219:  * xmlXPathNormalizeFunction:
 9220:  * @ctxt:  the XPath Parser context
 9221:  * @nargs:  the number of arguments
 9222:  *
 9223:  * Implement the normalize-space() XPath function
 9224:  *    string normalize-space(string?)
 9225:  * The normalize-space function returns the argument string with white
 9226:  * space normalized by stripping leading and trailing whitespace
 9227:  * and replacing sequences of whitespace characters by a single
 9228:  * space. Whitespace characters are the same allowed by the S production
 9229:  * in XML. If the argument is omitted, it defaults to the context
 9230:  * node converted to a string, in other words the value of the context node.
 9231:  */
 9232: void
 9233: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9234:   xmlXPathObjectPtr obj = NULL;
 9235:   xmlChar *source = NULL;
 9236:   xmlBufferPtr target;
 9237:   xmlChar blank;
 9238: 
 9239:   if (ctxt == NULL) return;
 9240:   if (nargs == 0) {
 9241:     /* Use current context node */
 9242:       valuePush(ctxt,
 9243: 	  xmlXPathCacheWrapString(ctxt->context,
 9244: 	    xmlXPathCastNodeToString(ctxt->context->node)));
 9245:     nargs = 1;
 9246:   }
 9247: 
 9248:   CHECK_ARITY(1);
 9249:   CAST_TO_STRING;
 9250:   CHECK_TYPE(XPATH_STRING);
 9251:   obj = valuePop(ctxt);
 9252:   source = obj->stringval;
 9253: 
 9254:   target = xmlBufferCreate();
 9255:   if (target && source) {
 9256: 
 9257:     /* Skip leading whitespaces */
 9258:     while (IS_BLANK_CH(*source))
 9259:       source++;
 9260: 
 9261:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
 9262:     blank = 0;
 9263:     while (*source) {
 9264:       if (IS_BLANK_CH(*source)) {
 9265: 	blank = 0x20;
 9266:       } else {
 9267: 	if (blank) {
 9268: 	  xmlBufferAdd(target, &blank, 1);
 9269: 	  blank = 0;
 9270: 	}
 9271: 	xmlBufferAdd(target, source, 1);
 9272:       }
 9273:       source++;
 9274:     }
 9275:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9276: 	xmlBufferContent(target)));
 9277:     xmlBufferFree(target);
 9278:   }
 9279:   xmlXPathReleaseObject(ctxt->context, obj);
 9280: }
 9281: 
 9282: /**
 9283:  * xmlXPathTranslateFunction:
 9284:  * @ctxt:  the XPath Parser context
 9285:  * @nargs:  the number of arguments
 9286:  *
 9287:  * Implement the translate() XPath function
 9288:  *    string translate(string, string, string)
 9289:  * The translate function returns the first argument string with
 9290:  * occurrences of characters in the second argument string replaced
 9291:  * by the character at the corresponding position in the third argument
 9292:  * string. For example, translate("bar","abc","ABC") returns the string
 9293:  * BAr. If there is a character in the second argument string with no
 9294:  * character at a corresponding position in the third argument string
 9295:  * (because the second argument string is longer than the third argument
 9296:  * string), then occurrences of that character in the first argument
 9297:  * string are removed. For example, translate("--aaa--","abc-","ABC")
 9298:  * returns "AAA". If a character occurs more than once in second
 9299:  * argument string, then the first occurrence determines the replacement
 9300:  * character. If the third argument string is longer than the second
 9301:  * argument string, then excess characters are ignored.
 9302:  */
 9303: void
 9304: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9305:     xmlXPathObjectPtr str;
 9306:     xmlXPathObjectPtr from;
 9307:     xmlXPathObjectPtr to;
 9308:     xmlBufferPtr target;
 9309:     int offset, max;
 9310:     xmlChar ch;
 9311:     const xmlChar *point;
 9312:     xmlChar *cptr;
 9313: 
 9314:     CHECK_ARITY(3);
 9315: 
 9316:     CAST_TO_STRING;
 9317:     to = valuePop(ctxt);
 9318:     CAST_TO_STRING;
 9319:     from = valuePop(ctxt);
 9320:     CAST_TO_STRING;
 9321:     str = valuePop(ctxt);
 9322: 
 9323:     target = xmlBufferCreate();
 9324:     if (target) {
 9325: 	max = xmlUTF8Strlen(to->stringval);
 9326: 	for (cptr = str->stringval; (ch=*cptr); ) {
 9327: 	    offset = xmlUTF8Strloc(from->stringval, cptr);
 9328: 	    if (offset >= 0) {
 9329: 		if (offset < max) {
 9330: 		    point = xmlUTF8Strpos(to->stringval, offset);
 9331: 		    if (point)
 9332: 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
 9333: 		}
 9334: 	    } else
 9335: 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
 9336: 
 9337: 	    /* Step to next character in input */
 9338: 	    cptr++;
 9339: 	    if ( ch & 0x80 ) {
 9340: 		/* if not simple ascii, verify proper format */
 9341: 		if ( (ch & 0xc0) != 0xc0 ) {
 9342: 		    xmlGenericError(xmlGenericErrorContext,
 9343: 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9344:                     /* not asserting an XPath error is probably better */
 9345: 		    break;
 9346: 		}
 9347: 		/* then skip over remaining bytes for this char */
 9348: 		while ( (ch <<= 1) & 0x80 )
 9349: 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
 9350: 			xmlGenericError(xmlGenericErrorContext,
 9351: 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
 9352:                         /* not asserting an XPath error is probably better */
 9353: 			break;
 9354: 		    }
 9355: 		if (ch & 0x80) /* must have had error encountered */
 9356: 		    break;
 9357: 	    }
 9358: 	}
 9359:     }
 9360:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
 9361: 	xmlBufferContent(target)));
 9362:     xmlBufferFree(target);
 9363:     xmlXPathReleaseObject(ctxt->context, str);
 9364:     xmlXPathReleaseObject(ctxt->context, from);
 9365:     xmlXPathReleaseObject(ctxt->context, to);
 9366: }
 9367: 
 9368: /**
 9369:  * xmlXPathBooleanFunction:
 9370:  * @ctxt:  the XPath Parser context
 9371:  * @nargs:  the number of arguments
 9372:  *
 9373:  * Implement the boolean() XPath function
 9374:  *    boolean boolean(object)
 9375:  * The boolean function converts its argument to a boolean as follows:
 9376:  *    - a number is true if and only if it is neither positive or
 9377:  *      negative zero nor NaN
 9378:  *    - a node-set is true if and only if it is non-empty
 9379:  *    - a string is true if and only if its length is non-zero
 9380:  */
 9381: void
 9382: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9383:     xmlXPathObjectPtr cur;
 9384: 
 9385:     CHECK_ARITY(1);
 9386:     cur = valuePop(ctxt);
 9387:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
 9388:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
 9389:     valuePush(ctxt, cur);
 9390: }
 9391: 
 9392: /**
 9393:  * xmlXPathNotFunction:
 9394:  * @ctxt:  the XPath Parser context
 9395:  * @nargs:  the number of arguments
 9396:  *
 9397:  * Implement the not() XPath function
 9398:  *    boolean not(boolean)
 9399:  * The not function returns true if its argument is false,
 9400:  * and false otherwise.
 9401:  */
 9402: void
 9403: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9404:     CHECK_ARITY(1);
 9405:     CAST_TO_BOOLEAN;
 9406:     CHECK_TYPE(XPATH_BOOLEAN);
 9407:     ctxt->value->boolval = ! ctxt->value->boolval;
 9408: }
 9409: 
 9410: /**
 9411:  * xmlXPathTrueFunction:
 9412:  * @ctxt:  the XPath Parser context
 9413:  * @nargs:  the number of arguments
 9414:  *
 9415:  * Implement the true() XPath function
 9416:  *    boolean true()
 9417:  */
 9418: void
 9419: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9420:     CHECK_ARITY(0);
 9421:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
 9422: }
 9423: 
 9424: /**
 9425:  * xmlXPathFalseFunction:
 9426:  * @ctxt:  the XPath Parser context
 9427:  * @nargs:  the number of arguments
 9428:  *
 9429:  * Implement the false() XPath function
 9430:  *    boolean false()
 9431:  */
 9432: void
 9433: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9434:     CHECK_ARITY(0);
 9435:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
 9436: }
 9437: 
 9438: /**
 9439:  * xmlXPathLangFunction:
 9440:  * @ctxt:  the XPath Parser context
 9441:  * @nargs:  the number of arguments
 9442:  *
 9443:  * Implement the lang() XPath function
 9444:  *    boolean lang(string)
 9445:  * The lang function returns true or false depending on whether the
 9446:  * language of the context node as specified by xml:lang attributes
 9447:  * is the same as or is a sublanguage of the language specified by
 9448:  * the argument string. The language of the context node is determined
 9449:  * by the value of the xml:lang attribute on the context node, or, if
 9450:  * the context node has no xml:lang attribute, by the value of the
 9451:  * xml:lang attribute on the nearest ancestor of the context node that
 9452:  * has an xml:lang attribute. If there is no such attribute, then lang
 9453:  * returns false. If there is such an attribute, then lang returns
 9454:  * true if the attribute value is equal to the argument ignoring case,
 9455:  * or if there is some suffix starting with - such that the attribute
 9456:  * value is equal to the argument ignoring that suffix of the attribute
 9457:  * value and ignoring case.
 9458:  */
 9459: void
 9460: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9461:     xmlXPathObjectPtr val = NULL;
 9462:     const xmlChar *theLang = NULL;
 9463:     const xmlChar *lang;
 9464:     int ret = 0;
 9465:     int i;
 9466: 
 9467:     CHECK_ARITY(1);
 9468:     CAST_TO_STRING;
 9469:     CHECK_TYPE(XPATH_STRING);
 9470:     val = valuePop(ctxt);
 9471:     lang = val->stringval;
 9472:     theLang = xmlNodeGetLang(ctxt->context->node);
 9473:     if ((theLang != NULL) && (lang != NULL)) {
 9474:         for (i = 0;lang[i] != 0;i++)
 9475: 	    if (toupper(lang[i]) != toupper(theLang[i]))
 9476: 	        goto not_equal;
 9477: 	if ((theLang[i] == 0) || (theLang[i] == '-'))
 9478: 	    ret = 1;
 9479:     }
 9480: not_equal:
 9481:     if (theLang != NULL)
 9482: 	xmlFree((void *)theLang);
 9483: 
 9484:     xmlXPathReleaseObject(ctxt->context, val);
 9485:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
 9486: }
 9487: 
 9488: /**
 9489:  * xmlXPathNumberFunction:
 9490:  * @ctxt:  the XPath Parser context
 9491:  * @nargs:  the number of arguments
 9492:  *
 9493:  * Implement the number() XPath function
 9494:  *    number number(object?)
 9495:  */
 9496: void
 9497: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9498:     xmlXPathObjectPtr cur;
 9499:     double res;
 9500: 
 9501:     if (ctxt == NULL) return;
 9502:     if (nargs == 0) {
 9503: 	if (ctxt->context->node == NULL) {
 9504: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
 9505: 	} else {
 9506: 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
 9507: 
 9508: 	    res = xmlXPathStringEvalNumber(content);
 9509: 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9510: 	    xmlFree(content);
 9511: 	}
 9512: 	return;
 9513:     }
 9514: 
 9515:     CHECK_ARITY(1);
 9516:     cur = valuePop(ctxt);
 9517:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
 9518: }
 9519: 
 9520: /**
 9521:  * xmlXPathSumFunction:
 9522:  * @ctxt:  the XPath Parser context
 9523:  * @nargs:  the number of arguments
 9524:  *
 9525:  * Implement the sum() XPath function
 9526:  *    number sum(node-set)
 9527:  * The sum function returns the sum of the values of the nodes in
 9528:  * the argument node-set.
 9529:  */
 9530: void
 9531: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9532:     xmlXPathObjectPtr cur;
 9533:     int i;
 9534:     double res = 0.0;
 9535: 
 9536:     CHECK_ARITY(1);
 9537:     if ((ctxt->value == NULL) ||
 9538: 	((ctxt->value->type != XPATH_NODESET) &&
 9539: 	 (ctxt->value->type != XPATH_XSLT_TREE)))
 9540: 	XP_ERROR(XPATH_INVALID_TYPE);
 9541:     cur = valuePop(ctxt);
 9542: 
 9543:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
 9544: 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
 9545: 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
 9546: 	}
 9547:     }
 9548:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
 9549:     xmlXPathReleaseObject(ctxt->context, cur);
 9550: }
 9551: 
 9552: /*
 9553:  * To assure working code on multiple platforms, we want to only depend
 9554:  * upon the characteristic truncation of converting a floating point value
 9555:  * to an integer.  Unfortunately, because of the different storage sizes
 9556:  * of our internal floating point value (double) and integer (int), we
 9557:  * can't directly convert (see bug 301162).  This macro is a messy
 9558:  * 'workaround'
 9559:  */
 9560: #define XTRUNC(f, v)            \
 9561:     f = fmod((v), INT_MAX);     \
 9562:     f = (v) - (f) + (double)((int)(f));
 9563: 
 9564: /**
 9565:  * xmlXPathFloorFunction:
 9566:  * @ctxt:  the XPath Parser context
 9567:  * @nargs:  the number of arguments
 9568:  *
 9569:  * Implement the floor() XPath function
 9570:  *    number floor(number)
 9571:  * The floor function returns the largest (closest to positive infinity)
 9572:  * number that is not greater than the argument and that is an integer.
 9573:  */
 9574: void
 9575: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9576:     double f;
 9577: 
 9578:     CHECK_ARITY(1);
 9579:     CAST_TO_NUMBER;
 9580:     CHECK_TYPE(XPATH_NUMBER);
 9581: 
 9582:     XTRUNC(f, ctxt->value->floatval);
 9583:     if (f != ctxt->value->floatval) {
 9584: 	if (ctxt->value->floatval > 0)
 9585: 	    ctxt->value->floatval = f;
 9586: 	else
 9587: 	    ctxt->value->floatval = f - 1;
 9588:     }
 9589: }
 9590: 
 9591: /**
 9592:  * xmlXPathCeilingFunction:
 9593:  * @ctxt:  the XPath Parser context
 9594:  * @nargs:  the number of arguments
 9595:  *
 9596:  * Implement the ceiling() XPath function
 9597:  *    number ceiling(number)
 9598:  * The ceiling function returns the smallest (closest to negative infinity)
 9599:  * number that is not less than the argument and that is an integer.
 9600:  */
 9601: void
 9602: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9603:     double f;
 9604: 
 9605:     CHECK_ARITY(1);
 9606:     CAST_TO_NUMBER;
 9607:     CHECK_TYPE(XPATH_NUMBER);
 9608: 
 9609: #if 0
 9610:     ctxt->value->floatval = ceil(ctxt->value->floatval);
 9611: #else
 9612:     XTRUNC(f, ctxt->value->floatval);
 9613:     if (f != ctxt->value->floatval) {
 9614: 	if (ctxt->value->floatval > 0)
 9615: 	    ctxt->value->floatval = f + 1;
 9616: 	else {
 9617: 	    if (ctxt->value->floatval < 0 && f == 0)
 9618: 	        ctxt->value->floatval = xmlXPathNZERO;
 9619: 	    else
 9620: 	        ctxt->value->floatval = f;
 9621: 	}
 9622: 
 9623:     }
 9624: #endif
 9625: }
 9626: 
 9627: /**
 9628:  * xmlXPathRoundFunction:
 9629:  * @ctxt:  the XPath Parser context
 9630:  * @nargs:  the number of arguments
 9631:  *
 9632:  * Implement the round() XPath function
 9633:  *    number round(number)
 9634:  * The round function returns the number that is closest to the
 9635:  * argument and that is an integer. If there are two such numbers,
 9636:  * then the one that is even is returned.
 9637:  */
 9638: void
 9639: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 9640:     double f;
 9641: 
 9642:     CHECK_ARITY(1);
 9643:     CAST_TO_NUMBER;
 9644:     CHECK_TYPE(XPATH_NUMBER);
 9645: 
 9646:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
 9647: 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
 9648: 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
 9649: 	(ctxt->value->floatval == 0.0))
 9650: 	return;
 9651: 
 9652:     XTRUNC(f, ctxt->value->floatval);
 9653:     if (ctxt->value->floatval < 0) {
 9654: 	if (ctxt->value->floatval < f - 0.5)
 9655: 	    ctxt->value->floatval = f - 1;
 9656: 	else
 9657: 	    ctxt->value->floatval = f;
 9658: 	if (ctxt->value->floatval == 0)
 9659: 	    ctxt->value->floatval = xmlXPathNZERO;
 9660:     } else {
 9661: 	if (ctxt->value->floatval < f + 0.5)
 9662: 	    ctxt->value->floatval = f;
 9663: 	else
 9664: 	    ctxt->value->floatval = f + 1;
 9665:     }
 9666: }
 9667: 
 9668: /************************************************************************
 9669:  *									*
 9670:  *			The Parser					*
 9671:  *									*
 9672:  ************************************************************************/
 9673: 
 9674: /*
 9675:  * a few forward declarations since we use a recursive call based
 9676:  * implementation.
 9677:  */
 9678: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
 9679: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
 9680: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
 9681: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
 9682: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
 9683: 	                                  int qualified);
 9684: 
 9685: /**
 9686:  * xmlXPathCurrentChar:
 9687:  * @ctxt:  the XPath parser context
 9688:  * @cur:  pointer to the beginning of the char
 9689:  * @len:  pointer to the length of the char read
 9690:  *
 9691:  * The current char value, if using UTF-8 this may actually span multiple
 9692:  * bytes in the input buffer.
 9693:  *
 9694:  * Returns the current char value and its length
 9695:  */
 9696: 
 9697: static int
 9698: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
 9699:     unsigned char c;
 9700:     unsigned int val;
 9701:     const xmlChar *cur;
 9702: 
 9703:     if (ctxt == NULL)
 9704: 	return(0);
 9705:     cur = ctxt->cur;
 9706: 
 9707:     /*
 9708:      * We are supposed to handle UTF8, check it's valid
 9709:      * From rfc2044: encoding of the Unicode values on UTF-8:
 9710:      *
 9711:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
 9712:      * 0000 0000-0000 007F   0xxxxxxx
 9713:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
 9714:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
 9715:      *
 9716:      * Check for the 0x110000 limit too
 9717:      */
 9718:     c = *cur;
 9719:     if (c & 0x80) {
 9720: 	if ((cur[1] & 0xc0) != 0x80)
 9721: 	    goto encoding_error;
 9722: 	if ((c & 0xe0) == 0xe0) {
 9723: 
 9724: 	    if ((cur[2] & 0xc0) != 0x80)
 9725: 		goto encoding_error;
 9726: 	    if ((c & 0xf0) == 0xf0) {
 9727: 		if (((c & 0xf8) != 0xf0) ||
 9728: 		    ((cur[3] & 0xc0) != 0x80))
 9729: 		    goto encoding_error;
 9730: 		/* 4-byte code */
 9731: 		*len = 4;
 9732: 		val = (cur[0] & 0x7) << 18;
 9733: 		val |= (cur[1] & 0x3f) << 12;
 9734: 		val |= (cur[2] & 0x3f) << 6;
 9735: 		val |= cur[3] & 0x3f;
 9736: 	    } else {
 9737: 	      /* 3-byte code */
 9738: 		*len = 3;
 9739: 		val = (cur[0] & 0xf) << 12;
 9740: 		val |= (cur[1] & 0x3f) << 6;
 9741: 		val |= cur[2] & 0x3f;
 9742: 	    }
 9743: 	} else {
 9744: 	  /* 2-byte code */
 9745: 	    *len = 2;
 9746: 	    val = (cur[0] & 0x1f) << 6;
 9747: 	    val |= cur[1] & 0x3f;
 9748: 	}
 9749: 	if (!IS_CHAR(val)) {
 9750: 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
 9751: 	}
 9752: 	return(val);
 9753:     } else {
 9754: 	/* 1-byte code */
 9755: 	*len = 1;
 9756: 	return((int) *cur);
 9757:     }
 9758: encoding_error:
 9759:     /*
 9760:      * If we detect an UTF8 error that probably means that the
 9761:      * input encoding didn't get properly advertised in the
 9762:      * declaration header. Report the error and switch the encoding
 9763:      * to ISO-Latin-1 (if you don't like this policy, just declare the
 9764:      * encoding !)
 9765:      */
 9766:     *len = 0;
 9767:     XP_ERROR0(XPATH_ENCODING_ERROR);
 9768: }
 9769: 
 9770: /**
 9771:  * xmlXPathParseNCName:
 9772:  * @ctxt:  the XPath Parser context
 9773:  *
 9774:  * parse an XML namespace non qualified name.
 9775:  *
 9776:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
 9777:  *
 9778:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
 9779:  *                       CombiningChar | Extender
 9780:  *
 9781:  * Returns the namespace name or NULL
 9782:  */
 9783: 
 9784: xmlChar *
 9785: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
 9786:     const xmlChar *in;
 9787:     xmlChar *ret;
 9788:     int count = 0;
 9789: 
 9790:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9791:     /*
 9792:      * Accelerator for simple ASCII names
 9793:      */
 9794:     in = ctxt->cur;
 9795:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9796: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9797: 	(*in == '_')) {
 9798: 	in++;
 9799: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9800: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9801: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9802: 	       (*in == '_') || (*in == '.') ||
 9803: 	       (*in == '-'))
 9804: 	    in++;
 9805: 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
 9806:             (*in == '[') || (*in == ']') || (*in == ':') ||
 9807:             (*in == '@') || (*in == '*')) {
 9808: 	    count = in - ctxt->cur;
 9809: 	    if (count == 0)
 9810: 		return(NULL);
 9811: 	    ret = xmlStrndup(ctxt->cur, count);
 9812: 	    ctxt->cur = in;
 9813: 	    return(ret);
 9814: 	}
 9815:     }
 9816:     return(xmlXPathParseNameComplex(ctxt, 0));
 9817: }
 9818: 
 9819: 
 9820: /**
 9821:  * xmlXPathParseQName:
 9822:  * @ctxt:  the XPath Parser context
 9823:  * @prefix:  a xmlChar **
 9824:  *
 9825:  * parse an XML qualified name
 9826:  *
 9827:  * [NS 5] QName ::= (Prefix ':')? LocalPart
 9828:  *
 9829:  * [NS 6] Prefix ::= NCName
 9830:  *
 9831:  * [NS 7] LocalPart ::= NCName
 9832:  *
 9833:  * Returns the function returns the local part, and prefix is updated
 9834:  *   to get the Prefix if any.
 9835:  */
 9836: 
 9837: static xmlChar *
 9838: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
 9839:     xmlChar *ret = NULL;
 9840: 
 9841:     *prefix = NULL;
 9842:     ret = xmlXPathParseNCName(ctxt);
 9843:     if (ret && CUR == ':') {
 9844:         *prefix = ret;
 9845: 	NEXT;
 9846: 	ret = xmlXPathParseNCName(ctxt);
 9847:     }
 9848:     return(ret);
 9849: }
 9850: 
 9851: /**
 9852:  * xmlXPathParseName:
 9853:  * @ctxt:  the XPath Parser context
 9854:  *
 9855:  * parse an XML name
 9856:  *
 9857:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
 9858:  *                  CombiningChar | Extender
 9859:  *
 9860:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
 9861:  *
 9862:  * Returns the namespace name or NULL
 9863:  */
 9864: 
 9865: xmlChar *
 9866: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
 9867:     const xmlChar *in;
 9868:     xmlChar *ret;
 9869:     int count = 0;
 9870: 
 9871:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
 9872:     /*
 9873:      * Accelerator for simple ASCII names
 9874:      */
 9875:     in = ctxt->cur;
 9876:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
 9877: 	((*in >= 0x41) && (*in <= 0x5A)) ||
 9878: 	(*in == '_') || (*in == ':')) {
 9879: 	in++;
 9880: 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
 9881: 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
 9882: 	       ((*in >= 0x30) && (*in <= 0x39)) ||
 9883: 	       (*in == '_') || (*in == '-') ||
 9884: 	       (*in == ':') || (*in == '.'))
 9885: 	    in++;
 9886: 	if ((*in > 0) && (*in < 0x80)) {
 9887: 	    count = in - ctxt->cur;
 9888: 	    ret = xmlStrndup(ctxt->cur, count);
 9889: 	    ctxt->cur = in;
 9890: 	    return(ret);
 9891: 	}
 9892:     }
 9893:     return(xmlXPathParseNameComplex(ctxt, 1));
 9894: }
 9895: 
 9896: static xmlChar *
 9897: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
 9898:     xmlChar buf[XML_MAX_NAMELEN + 5];
 9899:     int len = 0, l;
 9900:     int c;
 9901: 
 9902:     /*
 9903:      * Handler for more complex cases
 9904:      */
 9905:     c = CUR_CHAR(l);
 9906:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
 9907:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
 9908:         (c == '*') || /* accelerators */
 9909: 	(!IS_LETTER(c) && (c != '_') &&
 9910:          ((qualified) && (c != ':')))) {
 9911: 	return(NULL);
 9912:     }
 9913: 
 9914:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
 9915: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
 9916:             (c == '.') || (c == '-') ||
 9917: 	    (c == '_') || ((qualified) && (c == ':')) ||
 9918: 	    (IS_COMBINING(c)) ||
 9919: 	    (IS_EXTENDER(c)))) {
 9920: 	COPY_BUF(l,buf,len,c);
 9921: 	NEXTL(l);
 9922: 	c = CUR_CHAR(l);
 9923: 	if (len >= XML_MAX_NAMELEN) {
 9924: 	    /*
 9925: 	     * Okay someone managed to make a huge name, so he's ready to pay
 9926: 	     * for the processing speed.
 9927: 	     */
 9928: 	    xmlChar *buffer;
 9929: 	    int max = len * 2;
 9930: 
 9931: 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
 9932: 	    if (buffer == NULL) {
 9933: 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
 9934: 	    }
 9935: 	    memcpy(buffer, buf, len);
 9936: 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
 9937: 		   (c == '.') || (c == '-') ||
 9938: 		   (c == '_') || ((qualified) && (c == ':')) ||
 9939: 		   (IS_COMBINING(c)) ||
 9940: 		   (IS_EXTENDER(c))) {
 9941: 		if (len + 10 > max) {
 9942: 		    max *= 2;
 9943: 		    buffer = (xmlChar *) xmlRealloc(buffer,
 9944: 			                            max * sizeof(xmlChar));
 9945: 		    if (buffer == NULL) {
 9946: 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
 9947: 		    }
 9948: 		}
 9949: 		COPY_BUF(l,buffer,len,c);
 9950: 		NEXTL(l);
 9951: 		c = CUR_CHAR(l);
 9952: 	    }
 9953: 	    buffer[len] = 0;
 9954: 	    return(buffer);
 9955: 	}
 9956:     }
 9957:     if (len == 0)
 9958: 	return(NULL);
 9959:     return(xmlStrndup(buf, len));
 9960: }
 9961: 
 9962: #define MAX_FRAC 20
 9963: 
 9964: /*
 9965:  * These are used as divisors for the fractional part of a number.
 9966:  * Since the table includes 1.0 (representing '0' fractional digits),
 9967:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
 9968:  */
 9969: static double my_pow10[MAX_FRAC+1] = {
 9970:     1.0, 10.0, 100.0, 1000.0, 10000.0,
 9971:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
 9972:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
 9973:     100000000000000.0,
 9974:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
 9975:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
 9976: };
 9977: 
 9978: /**
 9979:  * xmlXPathStringEvalNumber:
 9980:  * @str:  A string to scan
 9981:  *
 9982:  *  [30a]  Float  ::= Number ('e' Digits?)?
 9983:  *
 9984:  *  [30]   Number ::=   Digits ('.' Digits?)?
 9985:  *                    | '.' Digits
 9986:  *  [31]   Digits ::=   [0-9]+
 9987:  *
 9988:  * Compile a Number in the string
 9989:  * In complement of the Number expression, this function also handles
 9990:  * negative values : '-' Number.
 9991:  *
 9992:  * Returns the double value.
 9993:  */
 9994: double
 9995: xmlXPathStringEvalNumber(const xmlChar *str) {
 9996:     const xmlChar *cur = str;
 9997:     double ret;
 9998:     int ok = 0;
 9999:     int isneg = 0;
10000:     int exponent = 0;
10001:     int is_exponent_negative = 0;
10002: #ifdef __GNUC__
10003:     unsigned long tmp = 0;
10004:     double temp;
10005: #endif
10006:     if (cur == NULL) return(0);
10007:     while (IS_BLANK_CH(*cur)) cur++;
10008:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009:         return(xmlXPathNAN);
10010:     }
10011:     if (*cur == '-') {
10012: 	isneg = 1;
10013: 	cur++;
10014:     }
10015: 
10016: #ifdef __GNUC__
10017:     /*
10018:      * tmp/temp is a workaround against a gcc compiler bug
10019:      * http://veillard.com/gcc.bug
10020:      */
10021:     ret = 0;
10022:     while ((*cur >= '0') && (*cur <= '9')) {
10023: 	ret = ret * 10;
10024: 	tmp = (*cur - '0');
10025: 	ok = 1;
10026: 	cur++;
10027: 	temp = (double) tmp;
10028: 	ret = ret + temp;
10029:     }
10030: #else
10031:     ret = 0;
10032:     while ((*cur >= '0') && (*cur <= '9')) {
10033: 	ret = ret * 10 + (*cur - '0');
10034: 	ok = 1;
10035: 	cur++;
10036:     }
10037: #endif
10038: 
10039:     if (*cur == '.') {
10040: 	int v, frac = 0;
10041: 	double fraction = 0;
10042: 
10043:         cur++;
10044: 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045: 	    return(xmlXPathNAN);
10046: 	}
10047: 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048: 	    v = (*cur - '0');
10049: 	    fraction = fraction * 10 + v;
10050: 	    frac = frac + 1;
10051: 	    cur++;
10052: 	}
10053: 	fraction /= my_pow10[frac];
10054: 	ret = ret + fraction;
10055: 	while ((*cur >= '0') && (*cur <= '9'))
10056: 	    cur++;
10057:     }
10058:     if ((*cur == 'e') || (*cur == 'E')) {
10059:       cur++;
10060:       if (*cur == '-') {
10061: 	is_exponent_negative = 1;
10062: 	cur++;
10063:       } else if (*cur == '+') {
10064:         cur++;
10065:       }
10066:       while ((*cur >= '0') && (*cur <= '9')) {
10067: 	exponent = exponent * 10 + (*cur - '0');
10068: 	cur++;
10069:       }
10070:     }
10071:     while (IS_BLANK_CH(*cur)) cur++;
10072:     if (*cur != 0) return(xmlXPathNAN);
10073:     if (isneg) ret = -ret;
10074:     if (is_exponent_negative) exponent = -exponent;
10075:     ret *= pow(10.0, (double)exponent);
10076:     return(ret);
10077: }
10078: 
10079: /**
10080:  * xmlXPathCompNumber:
10081:  * @ctxt:  the XPath Parser context
10082:  *
10083:  *  [30]   Number ::=   Digits ('.' Digits?)?
10084:  *                    | '.' Digits
10085:  *  [31]   Digits ::=   [0-9]+
10086:  *
10087:  * Compile a Number, then push it on the stack
10088:  *
10089:  */
10090: static void
10091: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092: {
10093:     double ret = 0.0;
10094:     int ok = 0;
10095:     int exponent = 0;
10096:     int is_exponent_negative = 0;
10097: #ifdef __GNUC__
10098:     unsigned long tmp = 0;
10099:     double temp;
10100: #endif
10101: 
10102:     CHECK_ERROR;
10103:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104:         XP_ERROR(XPATH_NUMBER_ERROR);
10105:     }
10106: #ifdef __GNUC__
10107:     /*
10108:      * tmp/temp is a workaround against a gcc compiler bug
10109:      * http://veillard.com/gcc.bug
10110:      */
10111:     ret = 0;
10112:     while ((CUR >= '0') && (CUR <= '9')) {
10113: 	ret = ret * 10;
10114: 	tmp = (CUR - '0');
10115:         ok = 1;
10116:         NEXT;
10117: 	temp = (double) tmp;
10118: 	ret = ret + temp;
10119:     }
10120: #else
10121:     ret = 0;
10122:     while ((CUR >= '0') && (CUR <= '9')) {
10123: 	ret = ret * 10 + (CUR - '0');
10124: 	ok = 1;
10125: 	NEXT;
10126:     }
10127: #endif
10128:     if (CUR == '.') {
10129: 	int v, frac = 0;
10130: 	double fraction = 0;
10131: 
10132:         NEXT;
10133:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134:             XP_ERROR(XPATH_NUMBER_ERROR);
10135:         }
10136:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137: 	    v = (CUR - '0');
10138: 	    fraction = fraction * 10 + v;
10139: 	    frac = frac + 1;
10140:             NEXT;
10141:         }
10142:         fraction /= my_pow10[frac];
10143:         ret = ret + fraction;
10144:         while ((CUR >= '0') && (CUR <= '9'))
10145:             NEXT;
10146:     }
10147:     if ((CUR == 'e') || (CUR == 'E')) {
10148:         NEXT;
10149:         if (CUR == '-') {
10150:             is_exponent_negative = 1;
10151:             NEXT;
10152:         } else if (CUR == '+') {
10153: 	    NEXT;
10154: 	}
10155:         while ((CUR >= '0') && (CUR <= '9')) {
10156:             exponent = exponent * 10 + (CUR - '0');
10157:             NEXT;
10158:         }
10159:         if (is_exponent_negative)
10160:             exponent = -exponent;
10161:         ret *= pow(10.0, (double) exponent);
10162:     }
10163:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165: }
10166: 
10167: /**
10168:  * xmlXPathParseLiteral:
10169:  * @ctxt:  the XPath Parser context
10170:  *
10171:  * Parse a Literal
10172:  *
10173:  *  [29]   Literal ::=   '"' [^"]* '"'
10174:  *                    | "'" [^']* "'"
10175:  *
10176:  * Returns the value found or NULL in case of error
10177:  */
10178: static xmlChar *
10179: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180:     const xmlChar *q;
10181:     xmlChar *ret = NULL;
10182: 
10183:     if (CUR == '"') {
10184:         NEXT;
10185: 	q = CUR_PTR;
10186: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187: 	    NEXT;
10188: 	if (!IS_CHAR_CH(CUR)) {
10189: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190: 	} else {
10191: 	    ret = xmlStrndup(q, CUR_PTR - q);
10192: 	    NEXT;
10193:         }
10194:     } else if (CUR == '\'') {
10195:         NEXT;
10196: 	q = CUR_PTR;
10197: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198: 	    NEXT;
10199: 	if (!IS_CHAR_CH(CUR)) {
10200: 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201: 	} else {
10202: 	    ret = xmlStrndup(q, CUR_PTR - q);
10203: 	    NEXT;
10204:         }
10205:     } else {
10206: 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207:     }
10208:     return(ret);
10209: }
10210: 
10211: /**
10212:  * xmlXPathCompLiteral:
10213:  * @ctxt:  the XPath Parser context
10214:  *
10215:  * Parse a Literal and push it on the stack.
10216:  *
10217:  *  [29]   Literal ::=   '"' [^"]* '"'
10218:  *                    | "'" [^']* "'"
10219:  *
10220:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221:  */
10222: static void
10223: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224:     const xmlChar *q;
10225:     xmlChar *ret = NULL;
10226: 
10227:     if (CUR == '"') {
10228:         NEXT;
10229: 	q = CUR_PTR;
10230: 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231: 	    NEXT;
10232: 	if (!IS_CHAR_CH(CUR)) {
10233: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234: 	} else {
10235: 	    ret = xmlStrndup(q, CUR_PTR - q);
10236: 	    NEXT;
10237:         }
10238:     } else if (CUR == '\'') {
10239:         NEXT;
10240: 	q = CUR_PTR;
10241: 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242: 	    NEXT;
10243: 	if (!IS_CHAR_CH(CUR)) {
10244: 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245: 	} else {
10246: 	    ret = xmlStrndup(q, CUR_PTR - q);
10247: 	    NEXT;
10248:         }
10249:     } else {
10250: 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10251:     }
10252:     if (ret == NULL) return;
10253:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254: 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255:     xmlFree(ret);
10256: }
10257: 
10258: /**
10259:  * xmlXPathCompVariableReference:
10260:  * @ctxt:  the XPath Parser context
10261:  *
10262:  * Parse a VariableReference, evaluate it and push it on the stack.
10263:  *
10264:  * The variable bindings consist of a mapping from variable names
10265:  * to variable values. The value of a variable is an object, which can be
10266:  * of any of the types that are possible for the value of an expression,
10267:  * and may also be of additional types not specified here.
10268:  *
10269:  * Early evaluation is possible since:
10270:  * The variable bindings [...] used to evaluate a subexpression are
10271:  * always the same as those used to evaluate the containing expression.
10272:  *
10273:  *  [36]   VariableReference ::=   '$' QName
10274:  */
10275: static void
10276: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277:     xmlChar *name;
10278:     xmlChar *prefix;
10279: 
10280:     SKIP_BLANKS;
10281:     if (CUR != '$') {
10282: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283:     }
10284:     NEXT;
10285:     name = xmlXPathParseQName(ctxt, &prefix);
10286:     if (name == NULL) {
10287: 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288:     }
10289:     ctxt->comp->last = -1;
10290:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291: 	           name, prefix);
10292:     SKIP_BLANKS;
10293:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294: 	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295:     }
10296: }
10297: 
10298: /**
10299:  * xmlXPathIsNodeType:
10300:  * @name:  a name string
10301:  *
10302:  * Is the name given a NodeType one.
10303:  *
10304:  *  [38]   NodeType ::=   'comment'
10305:  *                    | 'text'
10306:  *                    | 'processing-instruction'
10307:  *                    | 'node'
10308:  *
10309:  * Returns 1 if true 0 otherwise
10310:  */
10311: int
10312: xmlXPathIsNodeType(const xmlChar *name) {
10313:     if (name == NULL)
10314: 	return(0);
10315: 
10316:     if (xmlStrEqual(name, BAD_CAST "node"))
10317: 	return(1);
10318:     if (xmlStrEqual(name, BAD_CAST "text"))
10319: 	return(1);
10320:     if (xmlStrEqual(name, BAD_CAST "comment"))
10321: 	return(1);
10322:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10323: 	return(1);
10324:     return(0);
10325: }
10326: 
10327: /**
10328:  * xmlXPathCompFunctionCall:
10329:  * @ctxt:  the XPath Parser context
10330:  *
10331:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332:  *  [17]   Argument ::=   Expr
10333:  *
10334:  * Compile a function call, the evaluation of all arguments are
10335:  * pushed on the stack
10336:  */
10337: static void
10338: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10339:     xmlChar *name;
10340:     xmlChar *prefix;
10341:     int nbargs = 0;
10342:     int sort = 1;
10343: 
10344:     name = xmlXPathParseQName(ctxt, &prefix);
10345:     if (name == NULL) {
10346: 	xmlFree(prefix);
10347: 	XP_ERROR(XPATH_EXPR_ERROR);
10348:     }
10349:     SKIP_BLANKS;
10350: #ifdef DEBUG_EXPR
10351:     if (prefix == NULL)
10352: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353: 			name);
10354:     else
10355: 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356: 			prefix, name);
10357: #endif
10358: 
10359:     if (CUR != '(') {
10360: 	XP_ERROR(XPATH_EXPR_ERROR);
10361:     }
10362:     NEXT;
10363:     SKIP_BLANKS;
10364: 
10365:     /*
10366:     * Optimization for count(): we don't need the node-set to be sorted.
10367:     */
10368:     if ((prefix == NULL) && (name[0] == 'c') &&
10369: 	xmlStrEqual(name, BAD_CAST "count"))
10370:     {
10371: 	sort = 0;
10372:     }
10373:     ctxt->comp->last = -1;
10374:     if (CUR != ')') {
10375: 	while (CUR != 0) {
10376: 	    int op1 = ctxt->comp->last;
10377: 	    ctxt->comp->last = -1;
10378: 	    xmlXPathCompileExpr(ctxt, sort);
10379: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10380: 		xmlFree(name);
10381: 		xmlFree(prefix);
10382: 		return;
10383: 	    }
10384: 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385: 	    nbargs++;
10386: 	    if (CUR == ')') break;
10387: 	    if (CUR != ',') {
10388: 		XP_ERROR(XPATH_EXPR_ERROR);
10389: 	    }
10390: 	    NEXT;
10391: 	    SKIP_BLANKS;
10392: 	}
10393:     }
10394:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395: 	           name, prefix);
10396:     NEXT;
10397:     SKIP_BLANKS;
10398: }
10399: 
10400: /**
10401:  * xmlXPathCompPrimaryExpr:
10402:  * @ctxt:  the XPath Parser context
10403:  *
10404:  *  [15]   PrimaryExpr ::=   VariableReference
10405:  *                | '(' Expr ')'
10406:  *                | Literal
10407:  *                | Number
10408:  *                | FunctionCall
10409:  *
10410:  * Compile a primary expression.
10411:  */
10412: static void
10413: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10414:     SKIP_BLANKS;
10415:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416:     else if (CUR == '(') {
10417: 	NEXT;
10418: 	SKIP_BLANKS;
10419: 	xmlXPathCompileExpr(ctxt, 1);
10420: 	CHECK_ERROR;
10421: 	if (CUR != ')') {
10422: 	    XP_ERROR(XPATH_EXPR_ERROR);
10423: 	}
10424: 	NEXT;
10425: 	SKIP_BLANKS;
10426:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427: 	xmlXPathCompNumber(ctxt);
10428:     } else if ((CUR == '\'') || (CUR == '"')) {
10429: 	xmlXPathCompLiteral(ctxt);
10430:     } else {
10431: 	xmlXPathCompFunctionCall(ctxt);
10432:     }
10433:     SKIP_BLANKS;
10434: }
10435: 
10436: /**
10437:  * xmlXPathCompFilterExpr:
10438:  * @ctxt:  the XPath Parser context
10439:  *
10440:  *  [20]   FilterExpr ::=   PrimaryExpr
10441:  *               | FilterExpr Predicate
10442:  *
10443:  * Compile a filter expression.
10444:  * Square brackets are used to filter expressions in the same way that
10445:  * they are used in location paths. It is an error if the expression to
10446:  * be filtered does not evaluate to a node-set. The context node list
10447:  * used for evaluating the expression in square brackets is the node-set
10448:  * to be filtered listed in document order.
10449:  */
10450: 
10451: static void
10452: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453:     xmlXPathCompPrimaryExpr(ctxt);
10454:     CHECK_ERROR;
10455:     SKIP_BLANKS;
10456: 
10457:     while (CUR == '[') {
10458: 	xmlXPathCompPredicate(ctxt, 1);
10459: 	SKIP_BLANKS;
10460:     }
10461: 
10462: 
10463: }
10464: 
10465: /**
10466:  * xmlXPathScanName:
10467:  * @ctxt:  the XPath Parser context
10468:  *
10469:  * Trickery: parse an XML name but without consuming the input flow
10470:  * Needed to avoid insanity in the parser state.
10471:  *
10472:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473:  *                  CombiningChar | Extender
10474:  *
10475:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476:  *
10477:  * [6] Names ::= Name (S Name)*
10478:  *
10479:  * Returns the Name parsed or NULL
10480:  */
10481: 
10482: static xmlChar *
10483: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10484:     int len = 0, l;
10485:     int c;
10486:     const xmlChar *cur;
10487:     xmlChar *ret;
10488: 
10489:     cur = ctxt->cur;
10490: 
10491:     c = CUR_CHAR(l);
10492:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493: 	(!IS_LETTER(c) && (c != '_') &&
10494:          (c != ':'))) {
10495: 	return(NULL);
10496:     }
10497: 
10498:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499: 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500:             (c == '.') || (c == '-') ||
10501: 	    (c == '_') || (c == ':') ||
10502: 	    (IS_COMBINING(c)) ||
10503: 	    (IS_EXTENDER(c)))) {
10504: 	len += l;
10505: 	NEXTL(l);
10506: 	c = CUR_CHAR(l);
10507:     }
10508:     ret = xmlStrndup(cur, ctxt->cur - cur);
10509:     ctxt->cur = cur;
10510:     return(ret);
10511: }
10512: 
10513: /**
10514:  * xmlXPathCompPathExpr:
10515:  * @ctxt:  the XPath Parser context
10516:  *
10517:  *  [19]   PathExpr ::=   LocationPath
10518:  *               | FilterExpr
10519:  *               | FilterExpr '/' RelativeLocationPath
10520:  *               | FilterExpr '//' RelativeLocationPath
10521:  *
10522:  * Compile a path expression.
10523:  * The / operator and // operators combine an arbitrary expression
10524:  * and a relative location path. It is an error if the expression
10525:  * does not evaluate to a node-set.
10526:  * The / operator does composition in the same way as when / is
10527:  * used in a location path. As in location paths, // is short for
10528:  * /descendant-or-self::node()/.
10529:  */
10530: 
10531: static void
10532: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533:     int lc = 1;           /* Should we branch to LocationPath ?         */
10534:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535: 
10536:     SKIP_BLANKS;
10537:     if ((CUR == '$') || (CUR == '(') ||
10538: 	(IS_ASCII_DIGIT(CUR)) ||
10539:         (CUR == '\'') || (CUR == '"') ||
10540: 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10541: 	lc = 0;
10542:     } else if (CUR == '*') {
10543: 	/* relative or absolute location path */
10544: 	lc = 1;
10545:     } else if (CUR == '/') {
10546: 	/* relative or absolute location path */
10547: 	lc = 1;
10548:     } else if (CUR == '@') {
10549: 	/* relative abbreviated attribute location path */
10550: 	lc = 1;
10551:     } else if (CUR == '.') {
10552: 	/* relative abbreviated attribute location path */
10553: 	lc = 1;
10554:     } else {
10555: 	/*
10556: 	 * Problem is finding if we have a name here whether it's:
10557: 	 *   - a nodetype
10558: 	 *   - a function call in which case it's followed by '('
10559: 	 *   - an axis in which case it's followed by ':'
10560: 	 *   - a element name
10561: 	 * We do an a priori analysis here rather than having to
10562: 	 * maintain parsed token content through the recursive function
10563: 	 * calls. This looks uglier but makes the code easier to
10564: 	 * read/write/debug.
10565: 	 */
10566: 	SKIP_BLANKS;
10567: 	name = xmlXPathScanName(ctxt);
10568: 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569: #ifdef DEBUG_STEP
10570: 	    xmlGenericError(xmlGenericErrorContext,
10571: 		    "PathExpr: Axis\n");
10572: #endif
10573: 	    lc = 1;
10574: 	    xmlFree(name);
10575: 	} else if (name != NULL) {
10576: 	    int len =xmlStrlen(name);
10577: 
10578: 
10579: 	    while (NXT(len) != 0) {
10580: 		if (NXT(len) == '/') {
10581: 		    /* element name */
10582: #ifdef DEBUG_STEP
10583: 		    xmlGenericError(xmlGenericErrorContext,
10584: 			    "PathExpr: AbbrRelLocation\n");
10585: #endif
10586: 		    lc = 1;
10587: 		    break;
10588: 		} else if (IS_BLANK_CH(NXT(len))) {
10589: 		    /* ignore blanks */
10590: 		    ;
10591: 		} else if (NXT(len) == ':') {
10592: #ifdef DEBUG_STEP
10593: 		    xmlGenericError(xmlGenericErrorContext,
10594: 			    "PathExpr: AbbrRelLocation\n");
10595: #endif
10596: 		    lc = 1;
10597: 		    break;
10598: 		} else if ((NXT(len) == '(')) {
10599: 		    /* Note Type or Function */
10600: 		    if (xmlXPathIsNodeType(name)) {
10601: #ifdef DEBUG_STEP
10602: 		        xmlGenericError(xmlGenericErrorContext,
10603: 				"PathExpr: Type search\n");
10604: #endif
10605: 			lc = 1;
10606: 		    } else {
10607: #ifdef DEBUG_STEP
10608: 		        xmlGenericError(xmlGenericErrorContext,
10609: 				"PathExpr: function call\n");
10610: #endif
10611: 			lc = 0;
10612: 		    }
10613:                     break;
10614: 		} else if ((NXT(len) == '[')) {
10615: 		    /* element name */
10616: #ifdef DEBUG_STEP
10617: 		    xmlGenericError(xmlGenericErrorContext,
10618: 			    "PathExpr: AbbrRelLocation\n");
10619: #endif
10620: 		    lc = 1;
10621: 		    break;
10622: 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623: 			   (NXT(len) == '=')) {
10624: 		    lc = 1;
10625: 		    break;
10626: 		} else {
10627: 		    lc = 1;
10628: 		    break;
10629: 		}
10630: 		len++;
10631: 	    }
10632: 	    if (NXT(len) == 0) {
10633: #ifdef DEBUG_STEP
10634: 		xmlGenericError(xmlGenericErrorContext,
10635: 			"PathExpr: AbbrRelLocation\n");
10636: #endif
10637: 		/* element name */
10638: 		lc = 1;
10639: 	    }
10640: 	    xmlFree(name);
10641: 	} else {
10642: 	    /* make sure all cases are covered explicitly */
10643: 	    XP_ERROR(XPATH_EXPR_ERROR);
10644: 	}
10645:     }
10646: 
10647:     if (lc) {
10648: 	if (CUR == '/') {
10649: 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650: 	} else {
10651: 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10652: 	}
10653: 	xmlXPathCompLocationPath(ctxt);
10654:     } else {
10655: 	xmlXPathCompFilterExpr(ctxt);
10656: 	CHECK_ERROR;
10657: 	if ((CUR == '/') && (NXT(1) == '/')) {
10658: 	    SKIP(2);
10659: 	    SKIP_BLANKS;
10660: 
10661: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663: 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664: 
10665: 	    xmlXPathCompRelativeLocationPath(ctxt);
10666: 	} else if (CUR == '/') {
10667: 	    xmlXPathCompRelativeLocationPath(ctxt);
10668: 	}
10669:     }
10670:     SKIP_BLANKS;
10671: }
10672: 
10673: /**
10674:  * xmlXPathCompUnionExpr:
10675:  * @ctxt:  the XPath Parser context
10676:  *
10677:  *  [18]   UnionExpr ::=   PathExpr
10678:  *               | UnionExpr '|' PathExpr
10679:  *
10680:  * Compile an union expression.
10681:  */
10682: 
10683: static void
10684: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685:     xmlXPathCompPathExpr(ctxt);
10686:     CHECK_ERROR;
10687:     SKIP_BLANKS;
10688:     while (CUR == '|') {
10689: 	int op1 = ctxt->comp->last;
10690: 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10691: 
10692: 	NEXT;
10693: 	SKIP_BLANKS;
10694: 	xmlXPathCompPathExpr(ctxt);
10695: 
10696: 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697: 
10698: 	SKIP_BLANKS;
10699:     }
10700: }
10701: 
10702: /**
10703:  * xmlXPathCompUnaryExpr:
10704:  * @ctxt:  the XPath Parser context
10705:  *
10706:  *  [27]   UnaryExpr ::=   UnionExpr
10707:  *                   | '-' UnaryExpr
10708:  *
10709:  * Compile an unary expression.
10710:  */
10711: 
10712: static void
10713: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10714:     int minus = 0;
10715:     int found = 0;
10716: 
10717:     SKIP_BLANKS;
10718:     while (CUR == '-') {
10719:         minus = 1 - minus;
10720: 	found = 1;
10721: 	NEXT;
10722: 	SKIP_BLANKS;
10723:     }
10724: 
10725:     xmlXPathCompUnionExpr(ctxt);
10726:     CHECK_ERROR;
10727:     if (found) {
10728: 	if (minus)
10729: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730: 	else
10731: 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10732:     }
10733: }
10734: 
10735: /**
10736:  * xmlXPathCompMultiplicativeExpr:
10737:  * @ctxt:  the XPath Parser context
10738:  *
10739:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10740:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10741:  *                   | MultiplicativeExpr 'div' UnaryExpr
10742:  *                   | MultiplicativeExpr 'mod' UnaryExpr
10743:  *  [34]   MultiplyOperator ::=   '*'
10744:  *
10745:  * Compile an Additive expression.
10746:  */
10747: 
10748: static void
10749: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750:     xmlXPathCompUnaryExpr(ctxt);
10751:     CHECK_ERROR;
10752:     SKIP_BLANKS;
10753:     while ((CUR == '*') ||
10754:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756: 	int op = -1;
10757: 	int op1 = ctxt->comp->last;
10758: 
10759:         if (CUR == '*') {
10760: 	    op = 0;
10761: 	    NEXT;
10762: 	} else if (CUR == 'd') {
10763: 	    op = 1;
10764: 	    SKIP(3);
10765: 	} else if (CUR == 'm') {
10766: 	    op = 2;
10767: 	    SKIP(3);
10768: 	}
10769: 	SKIP_BLANKS;
10770:         xmlXPathCompUnaryExpr(ctxt);
10771: 	CHECK_ERROR;
10772: 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10773: 	SKIP_BLANKS;
10774:     }
10775: }
10776: 
10777: /**
10778:  * xmlXPathCompAdditiveExpr:
10779:  * @ctxt:  the XPath Parser context
10780:  *
10781:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10782:  *                   | AdditiveExpr '+' MultiplicativeExpr
10783:  *                   | AdditiveExpr '-' MultiplicativeExpr
10784:  *
10785:  * Compile an Additive expression.
10786:  */
10787: 
10788: static void
10789: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10790: 
10791:     xmlXPathCompMultiplicativeExpr(ctxt);
10792:     CHECK_ERROR;
10793:     SKIP_BLANKS;
10794:     while ((CUR == '+') || (CUR == '-')) {
10795: 	int plus;
10796: 	int op1 = ctxt->comp->last;
10797: 
10798:         if (CUR == '+') plus = 1;
10799: 	else plus = 0;
10800: 	NEXT;
10801: 	SKIP_BLANKS;
10802:         xmlXPathCompMultiplicativeExpr(ctxt);
10803: 	CHECK_ERROR;
10804: 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10805: 	SKIP_BLANKS;
10806:     }
10807: }
10808: 
10809: /**
10810:  * xmlXPathCompRelationalExpr:
10811:  * @ctxt:  the XPath Parser context
10812:  *
10813:  *  [24]   RelationalExpr ::=   AdditiveExpr
10814:  *                 | RelationalExpr '<' AdditiveExpr
10815:  *                 | RelationalExpr '>' AdditiveExpr
10816:  *                 | RelationalExpr '<=' AdditiveExpr
10817:  *                 | RelationalExpr '>=' AdditiveExpr
10818:  *
10819:  *  A <= B > C is allowed ? Answer from James, yes with
10820:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821:  *  which is basically what got implemented.
10822:  *
10823:  * Compile a Relational expression, then push the result
10824:  * on the stack
10825:  */
10826: 
10827: static void
10828: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829:     xmlXPathCompAdditiveExpr(ctxt);
10830:     CHECK_ERROR;
10831:     SKIP_BLANKS;
10832:     while ((CUR == '<') ||
10833:            (CUR == '>') ||
10834:            ((CUR == '<') && (NXT(1) == '=')) ||
10835:            ((CUR == '>') && (NXT(1) == '='))) {
10836: 	int inf, strict;
10837: 	int op1 = ctxt->comp->last;
10838: 
10839:         if (CUR == '<') inf = 1;
10840: 	else inf = 0;
10841: 	if (NXT(1) == '=') strict = 0;
10842: 	else strict = 1;
10843: 	NEXT;
10844: 	if (!strict) NEXT;
10845: 	SKIP_BLANKS;
10846:         xmlXPathCompAdditiveExpr(ctxt);
10847: 	CHECK_ERROR;
10848: 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10849: 	SKIP_BLANKS;
10850:     }
10851: }
10852: 
10853: /**
10854:  * xmlXPathCompEqualityExpr:
10855:  * @ctxt:  the XPath Parser context
10856:  *
10857:  *  [23]   EqualityExpr ::=   RelationalExpr
10858:  *                 | EqualityExpr '=' RelationalExpr
10859:  *                 | EqualityExpr '!=' RelationalExpr
10860:  *
10861:  *  A != B != C is allowed ? Answer from James, yes with
10862:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10863:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10864:  *  which is basically what got implemented.
10865:  *
10866:  * Compile an Equality expression.
10867:  *
10868:  */
10869: static void
10870: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871:     xmlXPathCompRelationalExpr(ctxt);
10872:     CHECK_ERROR;
10873:     SKIP_BLANKS;
10874:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10875: 	int eq;
10876: 	int op1 = ctxt->comp->last;
10877: 
10878:         if (CUR == '=') eq = 1;
10879: 	else eq = 0;
10880: 	NEXT;
10881: 	if (!eq) NEXT;
10882: 	SKIP_BLANKS;
10883:         xmlXPathCompRelationalExpr(ctxt);
10884: 	CHECK_ERROR;
10885: 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10886: 	SKIP_BLANKS;
10887:     }
10888: }
10889: 
10890: /**
10891:  * xmlXPathCompAndExpr:
10892:  * @ctxt:  the XPath Parser context
10893:  *
10894:  *  [22]   AndExpr ::=   EqualityExpr
10895:  *                 | AndExpr 'and' EqualityExpr
10896:  *
10897:  * Compile an AND expression.
10898:  *
10899:  */
10900: static void
10901: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902:     xmlXPathCompEqualityExpr(ctxt);
10903:     CHECK_ERROR;
10904:     SKIP_BLANKS;
10905:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906: 	int op1 = ctxt->comp->last;
10907:         SKIP(3);
10908: 	SKIP_BLANKS;
10909:         xmlXPathCompEqualityExpr(ctxt);
10910: 	CHECK_ERROR;
10911: 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10912: 	SKIP_BLANKS;
10913:     }
10914: }
10915: 
10916: /**
10917:  * xmlXPathCompileExpr:
10918:  * @ctxt:  the XPath Parser context
10919:  *
10920:  *  [14]   Expr ::=   OrExpr
10921:  *  [21]   OrExpr ::=   AndExpr
10922:  *                 | OrExpr 'or' AndExpr
10923:  *
10924:  * Parse and compile an expression
10925:  */
10926: static void
10927: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928:     xmlXPathCompAndExpr(ctxt);
10929:     CHECK_ERROR;
10930:     SKIP_BLANKS;
10931:     while ((CUR == 'o') && (NXT(1) == 'r')) {
10932: 	int op1 = ctxt->comp->last;
10933:         SKIP(2);
10934: 	SKIP_BLANKS;
10935:         xmlXPathCompAndExpr(ctxt);
10936: 	CHECK_ERROR;
10937: 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10938: 	SKIP_BLANKS;
10939:     }
10940:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941: 	/* more ops could be optimized too */
10942: 	/*
10943: 	* This is the main place to eliminate sorting for
10944: 	* operations which don't require a sorted node-set.
10945: 	* E.g. count().
10946: 	*/
10947: 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948:     }
10949: }
10950: 
10951: /**
10952:  * xmlXPathCompPredicate:
10953:  * @ctxt:  the XPath Parser context
10954:  * @filter:  act as a filter
10955:  *
10956:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10957:  *  [9]   PredicateExpr ::=   Expr
10958:  *
10959:  * Compile a predicate expression
10960:  */
10961: static void
10962: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963:     int op1 = ctxt->comp->last;
10964: 
10965:     SKIP_BLANKS;
10966:     if (CUR != '[') {
10967: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968:     }
10969:     NEXT;
10970:     SKIP_BLANKS;
10971: 
10972:     ctxt->comp->last = -1;
10973:     /*
10974:     * This call to xmlXPathCompileExpr() will deactivate sorting
10975:     * of the predicate result.
10976:     * TODO: Sorting is still activated for filters, since I'm not
10977:     *  sure if needed. Normally sorting should not be needed, since
10978:     *  a filter can only diminish the number of items in a sequence,
10979:     *  but won't change its order; so if the initial sequence is sorted,
10980:     *  subsequent sorting is not needed.
10981:     */
10982:     if (! filter)
10983: 	xmlXPathCompileExpr(ctxt, 0);
10984:     else
10985: 	xmlXPathCompileExpr(ctxt, 1);
10986:     CHECK_ERROR;
10987: 
10988:     if (CUR != ']') {
10989: 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990:     }
10991: 
10992:     if (filter)
10993: 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994:     else
10995: 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10996: 
10997:     NEXT;
10998:     SKIP_BLANKS;
10999: }
11000: 
11001: /**
11002:  * xmlXPathCompNodeTest:
11003:  * @ctxt:  the XPath Parser context
11004:  * @test:  pointer to a xmlXPathTestVal
11005:  * @type:  pointer to a xmlXPathTypeVal
11006:  * @prefix:  placeholder for a possible name prefix
11007:  *
11008:  * [7] NodeTest ::=   NameTest
11009:  *		    | NodeType '(' ')'
11010:  *		    | 'processing-instruction' '(' Literal ')'
11011:  *
11012:  * [37] NameTest ::=  '*'
11013:  *		    | NCName ':' '*'
11014:  *		    | QName
11015:  * [38] NodeType ::= 'comment'
11016:  *		   | 'text'
11017:  *		   | 'processing-instruction'
11018:  *		   | 'node'
11019:  *
11020:  * Returns the name found and updates @test, @type and @prefix appropriately
11021:  */
11022: static xmlChar *
11023: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024: 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11025: 		     xmlChar *name) {
11026:     int blanks;
11027: 
11028:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029: 	STRANGE;
11030: 	return(NULL);
11031:     }
11032:     *type = (xmlXPathTypeVal) 0;
11033:     *test = (xmlXPathTestVal) 0;
11034:     *prefix = NULL;
11035:     SKIP_BLANKS;
11036: 
11037:     if ((name == NULL) && (CUR == '*')) {
11038: 	/*
11039: 	 * All elements
11040: 	 */
11041: 	NEXT;
11042: 	*test = NODE_TEST_ALL;
11043: 	return(NULL);
11044:     }
11045: 
11046:     if (name == NULL)
11047: 	name = xmlXPathParseNCName(ctxt);
11048:     if (name == NULL) {
11049: 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11050:     }
11051: 
11052:     blanks = IS_BLANK_CH(CUR);
11053:     SKIP_BLANKS;
11054:     if (CUR == '(') {
11055: 	NEXT;
11056: 	/*
11057: 	 * NodeType or PI search
11058: 	 */
11059: 	if (xmlStrEqual(name, BAD_CAST "comment"))
11060: 	    *type = NODE_TYPE_COMMENT;
11061: 	else if (xmlStrEqual(name, BAD_CAST "node"))
11062: 	    *type = NODE_TYPE_NODE;
11063: 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064: 	    *type = NODE_TYPE_PI;
11065: 	else if (xmlStrEqual(name, BAD_CAST "text"))
11066: 	    *type = NODE_TYPE_TEXT;
11067: 	else {
11068: 	    if (name != NULL)
11069: 		xmlFree(name);
11070: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11071: 	}
11072: 
11073: 	*test = NODE_TEST_TYPE;
11074: 
11075: 	SKIP_BLANKS;
11076: 	if (*type == NODE_TYPE_PI) {
11077: 	    /*
11078: 	     * Specific case: search a PI by name.
11079: 	     */
11080: 	    if (name != NULL)
11081: 		xmlFree(name);
11082: 	    name = NULL;
11083: 	    if (CUR != ')') {
11084: 		name = xmlXPathParseLiteral(ctxt);
11085: 		CHECK_ERROR NULL;
11086: 		*test = NODE_TEST_PI;
11087: 		SKIP_BLANKS;
11088: 	    }
11089: 	}
11090: 	if (CUR != ')') {
11091: 	    if (name != NULL)
11092: 		xmlFree(name);
11093: 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11094: 	}
11095: 	NEXT;
11096: 	return(name);
11097:     }
11098:     *test = NODE_TEST_NAME;
11099:     if ((!blanks) && (CUR == ':')) {
11100: 	NEXT;
11101: 
11102: 	/*
11103: 	 * Since currently the parser context don't have a
11104: 	 * namespace list associated:
11105: 	 * The namespace name for this prefix can be computed
11106: 	 * only at evaluation time. The compilation is done
11107: 	 * outside of any context.
11108: 	 */
11109: #if 0
11110: 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11111: 	if (name != NULL)
11112: 	    xmlFree(name);
11113: 	if (*prefix == NULL) {
11114: 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115: 	}
11116: #else
11117: 	*prefix = name;
11118: #endif
11119: 
11120: 	if (CUR == '*') {
11121: 	    /*
11122: 	     * All elements
11123: 	     */
11124: 	    NEXT;
11125: 	    *test = NODE_TEST_ALL;
11126: 	    return(NULL);
11127: 	}
11128: 
11129: 	name = xmlXPathParseNCName(ctxt);
11130: 	if (name == NULL) {
11131: 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11132: 	}
11133:     }
11134:     return(name);
11135: }
11136: 
11137: /**
11138:  * xmlXPathIsAxisName:
11139:  * @name:  a preparsed name token
11140:  *
11141:  * [6] AxisName ::=   'ancestor'
11142:  *                  | 'ancestor-or-self'
11143:  *                  | 'attribute'
11144:  *                  | 'child'
11145:  *                  | 'descendant'
11146:  *                  | 'descendant-or-self'
11147:  *                  | 'following'
11148:  *                  | 'following-sibling'
11149:  *                  | 'namespace'
11150:  *                  | 'parent'
11151:  *                  | 'preceding'
11152:  *                  | 'preceding-sibling'
11153:  *                  | 'self'
11154:  *
11155:  * Returns the axis or 0
11156:  */
11157: static xmlXPathAxisVal
11158: xmlXPathIsAxisName(const xmlChar *name) {
11159:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11160:     switch (name[0]) {
11161: 	case 'a':
11162: 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163: 		ret = AXIS_ANCESTOR;
11164: 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165: 		ret = AXIS_ANCESTOR_OR_SELF;
11166: 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11167: 		ret = AXIS_ATTRIBUTE;
11168: 	    break;
11169: 	case 'c':
11170: 	    if (xmlStrEqual(name, BAD_CAST "child"))
11171: 		ret = AXIS_CHILD;
11172: 	    break;
11173: 	case 'd':
11174: 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11175: 		ret = AXIS_DESCENDANT;
11176: 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177: 		ret = AXIS_DESCENDANT_OR_SELF;
11178: 	    break;
11179: 	case 'f':
11180: 	    if (xmlStrEqual(name, BAD_CAST "following"))
11181: 		ret = AXIS_FOLLOWING;
11182: 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183: 		ret = AXIS_FOLLOWING_SIBLING;
11184: 	    break;
11185: 	case 'n':
11186: 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11187: 		ret = AXIS_NAMESPACE;
11188: 	    break;
11189: 	case 'p':
11190: 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11191: 		ret = AXIS_PARENT;
11192: 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11193: 		ret = AXIS_PRECEDING;
11194: 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195: 		ret = AXIS_PRECEDING_SIBLING;
11196: 	    break;
11197: 	case 's':
11198: 	    if (xmlStrEqual(name, BAD_CAST "self"))
11199: 		ret = AXIS_SELF;
11200: 	    break;
11201:     }
11202:     return(ret);
11203: }
11204: 
11205: /**
11206:  * xmlXPathCompStep:
11207:  * @ctxt:  the XPath Parser context
11208:  *
11209:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11210:  *                  | AbbreviatedStep
11211:  *
11212:  * [12] AbbreviatedStep ::=   '.' | '..'
11213:  *
11214:  * [5] AxisSpecifier ::= AxisName '::'
11215:  *                  | AbbreviatedAxisSpecifier
11216:  *
11217:  * [13] AbbreviatedAxisSpecifier ::= '@'?
11218:  *
11219:  * Modified for XPtr range support as:
11220:  *
11221:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222:  *                     | AbbreviatedStep
11223:  *                     | 'range-to' '(' Expr ')' Predicate*
11224:  *
11225:  * Compile one step in a Location Path
11226:  * A location step of . is short for self::node(). This is
11227:  * particularly useful in conjunction with //. For example, the
11228:  * location path .//para is short for
11229:  * self::node()/descendant-or-self::node()/child::para
11230:  * and so will select all para descendant elements of the context
11231:  * node.
11232:  * Similarly, a location step of .. is short for parent::node().
11233:  * For example, ../title is short for parent::node()/child::title
11234:  * and so will select the title children of the parent of the context
11235:  * node.
11236:  */
11237: static void
11238: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239: #ifdef LIBXML_XPTR_ENABLED
11240:     int rangeto = 0;
11241:     int op2 = -1;
11242: #endif
11243: 
11244:     SKIP_BLANKS;
11245:     if ((CUR == '.') && (NXT(1) == '.')) {
11246: 	SKIP(2);
11247: 	SKIP_BLANKS;
11248: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249: 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250:     } else if (CUR == '.') {
11251: 	NEXT;
11252: 	SKIP_BLANKS;
11253:     } else {
11254: 	xmlChar *name = NULL;
11255: 	const xmlChar *prefix = NULL;
11256: 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257: 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258: 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11259: 	int op1;
11260: 
11261: 	/*
11262: 	 * The modification needed for XPointer change to the production
11263: 	 */
11264: #ifdef LIBXML_XPTR_ENABLED
11265: 	if (ctxt->xptr) {
11266: 	    name = xmlXPathParseNCName(ctxt);
11267: 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268:                 op2 = ctxt->comp->last;
11269: 		xmlFree(name);
11270: 		SKIP_BLANKS;
11271: 		if (CUR != '(') {
11272: 		    XP_ERROR(XPATH_EXPR_ERROR);
11273: 		}
11274: 		NEXT;
11275: 		SKIP_BLANKS;
11276: 
11277: 		xmlXPathCompileExpr(ctxt, 1);
11278: 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11279: 		CHECK_ERROR;
11280: 
11281: 		SKIP_BLANKS;
11282: 		if (CUR != ')') {
11283: 		    XP_ERROR(XPATH_EXPR_ERROR);
11284: 		}
11285: 		NEXT;
11286: 		rangeto = 1;
11287: 		goto eval_predicates;
11288: 	    }
11289: 	}
11290: #endif
11291: 	if (CUR == '*') {
11292: 	    axis = AXIS_CHILD;
11293: 	} else {
11294: 	    if (name == NULL)
11295: 		name = xmlXPathParseNCName(ctxt);
11296: 	    if (name != NULL) {
11297: 		axis = xmlXPathIsAxisName(name);
11298: 		if (axis != 0) {
11299: 		    SKIP_BLANKS;
11300: 		    if ((CUR == ':') && (NXT(1) == ':')) {
11301: 			SKIP(2);
11302: 			xmlFree(name);
11303: 			name = NULL;
11304: 		    } else {
11305: 			/* an element name can conflict with an axis one :-\ */
11306: 			axis = AXIS_CHILD;
11307: 		    }
11308: 		} else {
11309: 		    axis = AXIS_CHILD;
11310: 		}
11311: 	    } else if (CUR == '@') {
11312: 		NEXT;
11313: 		axis = AXIS_ATTRIBUTE;
11314: 	    } else {
11315: 		axis = AXIS_CHILD;
11316: 	    }
11317: 	}
11318: 
11319:         if (ctxt->error != XPATH_EXPRESSION_OK) {
11320:             xmlFree(name);
11321:             return;
11322:         }
11323: 
11324: 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11325: 	if (test == 0)
11326: 	    return;
11327: 
11328:         if ((prefix != NULL) && (ctxt->context != NULL) &&
11329: 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330: 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331: 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332: 	    }
11333: 	}
11334: #ifdef DEBUG_STEP
11335: 	xmlGenericError(xmlGenericErrorContext,
11336: 		"Basis : computing new set\n");
11337: #endif
11338: 
11339: #ifdef DEBUG_STEP
11340: 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341: 	if (ctxt->value == NULL)
11342: 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11343: 	else if (ctxt->value->nodesetval == NULL)
11344: 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345: 	else
11346: 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11347: #endif
11348: 
11349: #ifdef LIBXML_XPTR_ENABLED
11350: eval_predicates:
11351: #endif
11352: 	op1 = ctxt->comp->last;
11353: 	ctxt->comp->last = -1;
11354: 
11355: 	SKIP_BLANKS;
11356: 	while (CUR == '[') {
11357: 	    xmlXPathCompPredicate(ctxt, 0);
11358: 	}
11359: 
11360: #ifdef LIBXML_XPTR_ENABLED
11361: 	if (rangeto) {
11362: 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363: 	} else
11364: #endif
11365: 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366: 			   test, type, (void *)prefix, (void *)name);
11367: 
11368:     }
11369: #ifdef DEBUG_STEP
11370:     xmlGenericError(xmlGenericErrorContext, "Step : ");
11371:     if (ctxt->value == NULL)
11372: 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11373:     else if (ctxt->value->nodesetval == NULL)
11374: 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375:     else
11376: 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377: 		ctxt->value->nodesetval);
11378: #endif
11379: }
11380: 
11381: /**
11382:  * xmlXPathCompRelativeLocationPath:
11383:  * @ctxt:  the XPath Parser context
11384:  *
11385:  *  [3]   RelativeLocationPath ::=   Step
11386:  *                     | RelativeLocationPath '/' Step
11387:  *                     | AbbreviatedRelativeLocationPath
11388:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11389:  *
11390:  * Compile a relative location path.
11391:  */
11392: static void
11393: xmlXPathCompRelativeLocationPath
11394: (xmlXPathParserContextPtr ctxt) {
11395:     SKIP_BLANKS;
11396:     if ((CUR == '/') && (NXT(1) == '/')) {
11397: 	SKIP(2);
11398: 	SKIP_BLANKS;
11399: 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400: 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401:     } else if (CUR == '/') {
11402: 	    NEXT;
11403: 	SKIP_BLANKS;
11404:     }
11405:     xmlXPathCompStep(ctxt);
11406:     CHECK_ERROR;
11407:     SKIP_BLANKS;
11408:     while (CUR == '/') {
11409: 	if ((CUR == '/') && (NXT(1) == '/')) {
11410: 	    SKIP(2);
11411: 	    SKIP_BLANKS;
11412: 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414: 	    xmlXPathCompStep(ctxt);
11415: 	} else if (CUR == '/') {
11416: 	    NEXT;
11417: 	    SKIP_BLANKS;
11418: 	    xmlXPathCompStep(ctxt);
11419: 	}
11420: 	SKIP_BLANKS;
11421:     }
11422: }
11423: 
11424: /**
11425:  * xmlXPathCompLocationPath:
11426:  * @ctxt:  the XPath Parser context
11427:  *
11428:  *  [1]   LocationPath ::=   RelativeLocationPath
11429:  *                     | AbsoluteLocationPath
11430:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11431:  *                     | AbbreviatedAbsoluteLocationPath
11432:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11433:  *                           '//' RelativeLocationPath
11434:  *
11435:  * Compile a location path
11436:  *
11437:  * // is short for /descendant-or-self::node()/. For example,
11438:  * //para is short for /descendant-or-self::node()/child::para and
11439:  * so will select any para element in the document (even a para element
11440:  * that is a document element will be selected by //para since the
11441:  * document element node is a child of the root node); div//para is
11442:  * short for div/descendant-or-self::node()/child::para and so will
11443:  * select all para descendants of div children.
11444:  */
11445: static void
11446: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11447:     SKIP_BLANKS;
11448:     if (CUR != '/') {
11449:         xmlXPathCompRelativeLocationPath(ctxt);
11450:     } else {
11451: 	while (CUR == '/') {
11452: 	    if ((CUR == '/') && (NXT(1) == '/')) {
11453: 		SKIP(2);
11454: 		SKIP_BLANKS;
11455: 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456: 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457: 		xmlXPathCompRelativeLocationPath(ctxt);
11458: 	    } else if (CUR == '/') {
11459: 		NEXT;
11460: 		SKIP_BLANKS;
11461: 		if ((CUR != 0 ) &&
11462: 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463: 		     (CUR == '@') || (CUR == '*')))
11464: 		    xmlXPathCompRelativeLocationPath(ctxt);
11465: 	    }
11466: 	    CHECK_ERROR;
11467: 	}
11468:     }
11469: }
11470: 
11471: /************************************************************************
11472:  *									*
11473:  *		XPath precompiled expression evaluation			*
11474:  *									*
11475:  ************************************************************************/
11476: 
11477: static int
11478: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479: 
11480: #ifdef DEBUG_STEP
11481: static void
11482: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11483: 			  int nbNodes)
11484: {
11485:     xmlGenericError(xmlGenericErrorContext, "new step : ");
11486:     switch (op->value) {
11487:         case AXIS_ANCESTOR:
11488:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11489:             break;
11490:         case AXIS_ANCESTOR_OR_SELF:
11491:             xmlGenericError(xmlGenericErrorContext,
11492:                             "axis 'ancestors-or-self' ");
11493:             break;
11494:         case AXIS_ATTRIBUTE:
11495:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11496:             break;
11497:         case AXIS_CHILD:
11498:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11499:             break;
11500:         case AXIS_DESCENDANT:
11501:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11502:             break;
11503:         case AXIS_DESCENDANT_OR_SELF:
11504:             xmlGenericError(xmlGenericErrorContext,
11505:                             "axis 'descendant-or-self' ");
11506:             break;
11507:         case AXIS_FOLLOWING:
11508:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11509:             break;
11510:         case AXIS_FOLLOWING_SIBLING:
11511:             xmlGenericError(xmlGenericErrorContext,
11512:                             "axis 'following-siblings' ");
11513:             break;
11514:         case AXIS_NAMESPACE:
11515:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11516:             break;
11517:         case AXIS_PARENT:
11518:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11519:             break;
11520:         case AXIS_PRECEDING:
11521:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11522:             break;
11523:         case AXIS_PRECEDING_SIBLING:
11524:             xmlGenericError(xmlGenericErrorContext,
11525:                             "axis 'preceding-sibling' ");
11526:             break;
11527:         case AXIS_SELF:
11528:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11529:             break;
11530:     }
11531:     xmlGenericError(xmlGenericErrorContext,
11532: 	" context contains %d nodes\n", nbNodes);
11533:     switch (op->value2) {
11534:         case NODE_TEST_NONE:
11535:             xmlGenericError(xmlGenericErrorContext,
11536:                             "           searching for none !!!\n");
11537:             break;
11538:         case NODE_TEST_TYPE:
11539:             xmlGenericError(xmlGenericErrorContext,
11540:                             "           searching for type %d\n", op->value3);
11541:             break;
11542:         case NODE_TEST_PI:
11543:             xmlGenericError(xmlGenericErrorContext,
11544:                             "           searching for PI !!!\n");
11545:             break;
11546:         case NODE_TEST_ALL:
11547:             xmlGenericError(xmlGenericErrorContext,
11548:                             "           searching for *\n");
11549:             break;
11550:         case NODE_TEST_NS:
11551:             xmlGenericError(xmlGenericErrorContext,
11552:                             "           searching for namespace %s\n",
11553:                             op->value5);
11554:             break;
11555:         case NODE_TEST_NAME:
11556:             xmlGenericError(xmlGenericErrorContext,
11557:                             "           searching for name %s\n", op->value5);
11558:             if (op->value4)
11559:                 xmlGenericError(xmlGenericErrorContext,
11560:                                 "           with namespace %s\n", op->value4);
11561:             break;
11562:     }
11563:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11564: }
11565: #endif /* DEBUG_STEP */
11566: 
11567: static int
11568: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569: 			    xmlXPathStepOpPtr op,
11570: 			    xmlNodeSetPtr set,
11571: 			    int contextSize,
11572: 			    int hasNsNodes)
11573: {
11574:     if (op->ch1 != -1) {
11575: 	xmlXPathCompExprPtr comp = ctxt->comp;
11576: 	/*
11577: 	* Process inner predicates first.
11578: 	*/
11579: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580: 	    /*
11581: 	    * TODO: raise an internal error.
11582: 	    */
11583: 	}
11584: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586: 	CHECK_ERROR0;
11587: 	if (contextSize <= 0)
11588: 	    return(0);
11589:     }
11590:     if (op->ch2 != -1) {
11591: 	xmlXPathContextPtr xpctxt = ctxt->context;
11592: 	xmlNodePtr contextNode, oldContextNode;
11593: 	xmlDocPtr oldContextDoc;
11594: 	int i, res, contextPos = 0, newContextSize;
11595: 	xmlXPathStepOpPtr exprOp;
11596: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597: 
11598: #ifdef LIBXML_XPTR_ENABLED
11599: 	/*
11600: 	* URGENT TODO: Check the following:
11601: 	*  We don't expect location sets if evaluating prediates, right?
11602: 	*  Only filters should expect location sets, right?
11603: 	*/
11604: #endif
11605: 	/*
11606: 	* SPEC XPath 1.0:
11607: 	*  "For each node in the node-set to be filtered, the
11608: 	*  PredicateExpr is evaluated with that node as the
11609: 	*  context node, with the number of nodes in the
11610: 	*  node-set as the context size, and with the proximity
11611: 	*  position of the node in the node-set with respect to
11612: 	*  the axis as the context position;"
11613: 	* @oldset is the node-set" to be filtered.
11614: 	*
11615: 	* SPEC XPath 1.0:
11616: 	*  "only predicates change the context position and
11617: 	*  context size (see [2.4 Predicates])."
11618: 	* Example:
11619: 	*   node-set  context pos
11620: 	*    nA         1
11621: 	*    nB         2
11622: 	*    nC         3
11623: 	*   After applying predicate [position() > 1] :
11624: 	*   node-set  context pos
11625: 	*    nB         1
11626: 	*    nC         2
11627: 	*/
11628: 	oldContextNode = xpctxt->node;
11629: 	oldContextDoc = xpctxt->doc;
11630: 	/*
11631: 	* Get the expression of this predicate.
11632: 	*/
11633: 	exprOp = &ctxt->comp->steps[op->ch2];
11634: 	newContextSize = 0;
11635: 	for (i = 0; i < set->nodeNr; i++) {
11636: 	    if (set->nodeTab[i] == NULL)
11637: 		continue;
11638: 
11639: 	    contextNode = set->nodeTab[i];
11640: 	    xpctxt->node = contextNode;
11641: 	    xpctxt->contextSize = contextSize;
11642: 	    xpctxt->proximityPosition = ++contextPos;
11643: 
11644: 	    /*
11645: 	    * Also set the xpath document in case things like
11646: 	    * key() are evaluated in the predicate.
11647: 	    */
11648: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649: 		(contextNode->doc != NULL))
11650: 		xpctxt->doc = contextNode->doc;
11651: 	    /*
11652: 	    * Evaluate the predicate expression with 1 context node
11653: 	    * at a time; this node is packaged into a node set; this
11654: 	    * node set is handed over to the evaluation mechanism.
11655: 	    */
11656: 	    if (contextObj == NULL)
11657: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658: 	    else
11659: 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660: 		    contextNode);
11661: 
11662: 	    valuePush(ctxt, contextObj);
11663: 
11664: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11665: 
11666: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667: 		xmlXPathNodeSetClear(set, hasNsNodes);
11668: 		newContextSize = 0;
11669: 		goto evaluation_exit;
11670: 	    }
11671: 
11672: 	    if (res != 0) {
11673: 		newContextSize++;
11674: 	    } else {
11675: 		/*
11676: 		* Remove the entry from the initial node set.
11677: 		*/
11678: 		set->nodeTab[i] = NULL;
11679: 		if (contextNode->type == XML_NAMESPACE_DECL)
11680: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11681: 	    }
11682: 	    if (ctxt->value == contextObj) {
11683: 		/*
11684: 		* Don't free the temporary XPath object holding the
11685: 		* context node, in order to avoid massive recreation
11686: 		* inside this loop.
11687: 		*/
11688: 		valuePop(ctxt);
11689: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690: 	    } else {
11691: 		/*
11692: 		* TODO: The object was lost in the evaluation machinery.
11693: 		*  Can this happen? Maybe in internal-error cases.
11694: 		*/
11695: 		contextObj = NULL;
11696: 	    }
11697: 	}
11698: 
11699: 	if (contextObj != NULL) {
11700: 	    if (ctxt->value == contextObj)
11701: 		valuePop(ctxt);
11702: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11703: 	}
11704: evaluation_exit:
11705: 	if (exprRes != NULL)
11706: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11707: 	/*
11708: 	* Reset/invalidate the context.
11709: 	*/
11710: 	xpctxt->node = oldContextNode;
11711: 	xpctxt->doc = oldContextDoc;
11712: 	xpctxt->contextSize = -1;
11713: 	xpctxt->proximityPosition = -1;
11714: 	return(newContextSize);
11715:     }
11716:     return(contextSize);
11717: }
11718: 
11719: static int
11720: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721: 				      xmlXPathStepOpPtr op,
11722: 				      xmlNodeSetPtr set,
11723: 				      int contextSize,
11724: 				      int minPos,
11725: 				      int maxPos,
11726: 				      int hasNsNodes)
11727: {
11728:     if (op->ch1 != -1) {
11729: 	xmlXPathCompExprPtr comp = ctxt->comp;
11730: 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731: 	    /*
11732: 	    * TODO: raise an internal error.
11733: 	    */
11734: 	}
11735: 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736: 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737: 	CHECK_ERROR0;
11738: 	if (contextSize <= 0)
11739: 	    return(0);
11740:     }
11741:     /*
11742:     * Check if the node set contains a sufficient number of nodes for
11743:     * the requested range.
11744:     */
11745:     if (contextSize < minPos) {
11746: 	xmlXPathNodeSetClear(set, hasNsNodes);
11747: 	return(0);
11748:     }
11749:     if (op->ch2 == -1) {
11750: 	/*
11751: 	* TODO: Can this ever happen?
11752: 	*/
11753: 	return (contextSize);
11754:     } else {
11755: 	xmlDocPtr oldContextDoc;
11756: 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757: 	xmlXPathStepOpPtr exprOp;
11758: 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759: 	xmlNodePtr oldContextNode, contextNode = NULL;
11760: 	xmlXPathContextPtr xpctxt = ctxt->context;
11761:         int frame;
11762: 
11763: #ifdef LIBXML_XPTR_ENABLED
11764: 	    /*
11765: 	    * URGENT TODO: Check the following:
11766: 	    *  We don't expect location sets if evaluating prediates, right?
11767: 	    *  Only filters should expect location sets, right?
11768: 	*/
11769: #endif /* LIBXML_XPTR_ENABLED */
11770: 
11771: 	/*
11772: 	* Save old context.
11773: 	*/
11774: 	oldContextNode = xpctxt->node;
11775: 	oldContextDoc = xpctxt->doc;
11776: 	/*
11777: 	* Get the expression of this predicate.
11778: 	*/
11779: 	exprOp = &ctxt->comp->steps[op->ch2];
11780: 	for (i = 0; i < set->nodeNr; i++) {
11781:             xmlXPathObjectPtr tmp;
11782: 
11783: 	    if (set->nodeTab[i] == NULL)
11784: 		continue;
11785: 
11786: 	    contextNode = set->nodeTab[i];
11787: 	    xpctxt->node = contextNode;
11788: 	    xpctxt->contextSize = contextSize;
11789: 	    xpctxt->proximityPosition = ++contextPos;
11790: 
11791: 	    /*
11792: 	    * Initialize the new set.
11793: 	    * Also set the xpath document in case things like
11794: 	    * key() evaluation are attempted on the predicate
11795: 	    */
11796: 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797: 		(contextNode->doc != NULL))
11798: 		xpctxt->doc = contextNode->doc;
11799: 	    /*
11800: 	    * Evaluate the predicate expression with 1 context node
11801: 	    * at a time; this node is packaged into a node set; this
11802: 	    * node set is handed over to the evaluation mechanism.
11803: 	    */
11804: 	    if (contextObj == NULL)
11805: 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806: 	    else
11807: 		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808: 		    contextNode);
11809: 
11810:             frame = xmlXPathSetFrame(ctxt);
11811: 	    valuePush(ctxt, contextObj);
11812: 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11813:             tmp = valuePop(ctxt);
11814:             xmlXPathPopFrame(ctxt, frame);
11815: 
11816: 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11817:                 while (tmp != contextObj) {
11818:                     /*
11819:                      * Free up the result
11820:                      * then pop off contextObj, which will be freed later
11821:                      */
11822:                     xmlXPathReleaseObject(xpctxt, tmp);
11823:                     tmp = valuePop(ctxt);
11824:                 }
11825: 		goto evaluation_error;
11826: 	    }
11827:             /* push the result back onto the stack */
11828:             valuePush(ctxt, tmp);
11829: 
11830: 	    if (res)
11831: 		pos++;
11832: 
11833: 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11834: 		/*
11835: 		* Fits in the requested range.
11836: 		*/
11837: 		newContextSize++;
11838: 		if (minPos == maxPos) {
11839: 		    /*
11840: 		    * Only 1 node was requested.
11841: 		    */
11842: 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11843: 			/*
11844: 			* As always: take care of those nasty
11845: 			* namespace nodes.
11846: 			*/
11847: 			set->nodeTab[i] = NULL;
11848: 		    }
11849: 		    xmlXPathNodeSetClear(set, hasNsNodes);
11850: 		    set->nodeNr = 1;
11851: 		    set->nodeTab[0] = contextNode;
11852: 		    goto evaluation_exit;
11853: 		}
11854: 		if (pos == maxPos) {
11855: 		    /*
11856: 		    * We are done.
11857: 		    */
11858: 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859: 		    goto evaluation_exit;
11860: 		}
11861: 	    } else {
11862: 		/*
11863: 		* Remove the entry from the initial node set.
11864: 		*/
11865: 		set->nodeTab[i] = NULL;
11866: 		if (contextNode->type == XML_NAMESPACE_DECL)
11867: 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868: 	    }
11869: 	    if (exprRes != NULL) {
11870: 		xmlXPathReleaseObject(ctxt->context, exprRes);
11871: 		exprRes = NULL;
11872: 	    }
11873: 	    if (ctxt->value == contextObj) {
11874: 		/*
11875: 		* Don't free the temporary XPath object holding the
11876: 		* context node, in order to avoid massive recreation
11877: 		* inside this loop.
11878: 		*/
11879: 		valuePop(ctxt);
11880: 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881: 	    } else {
11882: 		/*
11883: 		* The object was lost in the evaluation machinery.
11884: 		* Can this happen? Maybe in case of internal-errors.
11885: 		*/
11886: 		contextObj = NULL;
11887: 	    }
11888: 	}
11889: 	goto evaluation_exit;
11890: 
11891: evaluation_error:
11892: 	xmlXPathNodeSetClear(set, hasNsNodes);
11893: 	newContextSize = 0;
11894: 
11895: evaluation_exit:
11896: 	if (contextObj != NULL) {
11897: 	    if (ctxt->value == contextObj)
11898: 		valuePop(ctxt);
11899: 	    xmlXPathReleaseObject(xpctxt, contextObj);
11900: 	}
11901: 	if (exprRes != NULL)
11902: 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11903: 	/*
11904: 	* Reset/invalidate the context.
11905: 	*/
11906: 	xpctxt->node = oldContextNode;
11907: 	xpctxt->doc = oldContextDoc;
11908: 	xpctxt->contextSize = -1;
11909: 	xpctxt->proximityPosition = -1;
11910: 	return(newContextSize);
11911:     }
11912:     return(contextSize);
11913: }
11914: 
11915: static int
11916: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917: 			    xmlXPathStepOpPtr op,
11918: 			    int *maxPos)
11919: {
11920: 
11921:     xmlXPathStepOpPtr exprOp;
11922: 
11923:     /*
11924:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925:     */
11926: 
11927:     /*
11928:     * If not -1, then ch1 will point to:
11929:     * 1) For predicates (XPATH_OP_PREDICATE):
11930:     *    - an inner predicate operator
11931:     * 2) For filters (XPATH_OP_FILTER):
11932:     *    - an inner filter operater OR
11933:     *    - an expression selecting the node set.
11934:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11935:     */
11936:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937: 	return(0);
11938: 
11939:     if (op->ch2 != -1) {
11940: 	exprOp = &ctxt->comp->steps[op->ch2];
11941:     } else
11942: 	return(0);
11943: 
11944:     if ((exprOp != NULL) &&
11945: 	(exprOp->op == XPATH_OP_VALUE) &&
11946: 	(exprOp->value4 != NULL) &&
11947: 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948:     {
11949: 	/*
11950: 	* We have a "[n]" predicate here.
11951: 	* TODO: Unfortunately this simplistic test here is not
11952: 	* able to detect a position() predicate in compound
11953: 	* expressions like "[@attr = 'a" and position() = 1],
11954: 	* and even not the usage of position() in
11955: 	* "[position() = 1]"; thus - obviously - a position-range,
11956: 	* like it "[position() < 5]", is also not detected.
11957: 	* Maybe we could rewrite the AST to ease the optimization.
11958: 	*/
11959: 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11960: 
11961: 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962: 	    (float) *maxPos)
11963: 	{
11964: 	    return(1);
11965: 	}
11966:     }
11967:     return(0);
11968: }
11969: 
11970: static int
11971: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972:                            xmlXPathStepOpPtr op,
11973: 			   xmlNodePtr * first, xmlNodePtr * last,
11974: 			   int toBool)
11975: {
11976: 
11977: #define XP_TEST_HIT \
11978:     if (hasAxisRange != 0) { \
11979: 	if (++pos == maxPos) { \
11980: 	    addNode(seq, cur); \
11981: 	goto axis_range_end; } \
11982:     } else { \
11983: 	addNode(seq, cur); \
11984: 	if (breakOnFirstHit) goto first_hit; }
11985: 
11986: #define XP_TEST_HIT_NS \
11987:     if (hasAxisRange != 0) { \
11988: 	if (++pos == maxPos) { \
11989: 	    hasNsNodes = 1; \
11990: 	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991: 	goto axis_range_end; } \
11992:     } else { \
11993: 	hasNsNodes = 1; \
11994: 	xmlXPathNodeSetAddNs(seq, \
11995: 	xpctxt->node, (xmlNsPtr) cur); \
11996: 	if (breakOnFirstHit) goto first_hit; }
11997: 
11998:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001:     const xmlChar *prefix = op->value4;
12002:     const xmlChar *name = op->value5;
12003:     const xmlChar *URI = NULL;
12004: 
12005: #ifdef DEBUG_STEP
12006:     int nbMatches = 0, prevMatches = 0;
12007: #endif
12008:     int total = 0, hasNsNodes = 0;
12009:     /* The popped object holding the context nodes */
12010:     xmlXPathObjectPtr obj;
12011:     /* The set of context nodes for the node tests */
12012:     xmlNodeSetPtr contextSeq;
12013:     int contextIdx;
12014:     xmlNodePtr contextNode;
12015:     /* The context node for a compound traversal */
12016:     xmlNodePtr outerContextNode;
12017:     /* The final resulting node set wrt to all context nodes */
12018:     xmlNodeSetPtr outSeq;
12019:     /*
12020:     * The temporary resulting node set wrt 1 context node.
12021:     * Used to feed predicate evaluation.
12022:     */
12023:     xmlNodeSetPtr seq;
12024:     xmlNodePtr cur;
12025:     /* First predicate operator */
12026:     xmlXPathStepOpPtr predOp;
12027:     int maxPos; /* The requested position() (when a "[n]" predicate) */
12028:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029:     int breakOnFirstHit;
12030: 
12031:     xmlXPathTraversalFunction next = NULL;
12032:     /* compound axis traversal */
12033:     xmlXPathTraversalFunctionExt outerNext = NULL;
12034:     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035:     xmlXPathNodeSetMergeFunction mergeAndClear;
12036:     xmlNodePtr oldContextNode;
12037:     xmlXPathContextPtr xpctxt = ctxt->context;
12038: 
12039: 
12040:     CHECK_TYPE0(XPATH_NODESET);
12041:     obj = valuePop(ctxt);
12042:     /*
12043:     * Setup namespaces.
12044:     */
12045:     if (prefix != NULL) {
12046:         URI = xmlXPathNsLookup(xpctxt, prefix);
12047:         if (URI == NULL) {
12048: 	    xmlXPathReleaseObject(xpctxt, obj);
12049:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050: 	}
12051:     }
12052:     /*
12053:     * Setup axis.
12054:     *
12055:     * MAYBE FUTURE TODO: merging optimizations:
12056:     * - If the nodes to be traversed wrt to the initial nodes and
12057:     *   the current axis cannot overlap, then we could avoid searching
12058:     *   for duplicates during the merge.
12059:     *   But the question is how/when to evaluate if they cannot overlap.
12060:     *   Example: if we know that for two initial nodes, the one is
12061:     *   not in the ancestor-or-self axis of the other, then we could safely
12062:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063:     *   the descendant-or-self axis.
12064:     */
12065:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066:     switch (axis) {
12067:         case AXIS_ANCESTOR:
12068:             first = NULL;
12069:             next = xmlXPathNextAncestor;
12070:             break;
12071:         case AXIS_ANCESTOR_OR_SELF:
12072:             first = NULL;
12073:             next = xmlXPathNextAncestorOrSelf;
12074:             break;
12075:         case AXIS_ATTRIBUTE:
12076:             first = NULL;
12077: 	    last = NULL;
12078:             next = xmlXPathNextAttribute;
12079: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080:             break;
12081:         case AXIS_CHILD:
12082: 	    last = NULL;
12083: 	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084: 		/*
12085: 		* This iterator will give us only nodes which can
12086: 		* hold element nodes.
12087: 		*/
12088: 		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089: 	    }
12090: 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091: 		(type == NODE_TYPE_NODE))
12092: 	    {
12093: 		/*
12094: 		* Optimization if an element node type is 'element'.
12095: 		*/
12096: 		next = xmlXPathNextChildElement;
12097: 	    } else
12098: 		next = xmlXPathNextChild;
12099: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100:             break;
12101:         case AXIS_DESCENDANT:
12102: 	    last = NULL;
12103:             next = xmlXPathNextDescendant;
12104:             break;
12105:         case AXIS_DESCENDANT_OR_SELF:
12106: 	    last = NULL;
12107:             next = xmlXPathNextDescendantOrSelf;
12108:             break;
12109:         case AXIS_FOLLOWING:
12110: 	    last = NULL;
12111:             next = xmlXPathNextFollowing;
12112:             break;
12113:         case AXIS_FOLLOWING_SIBLING:
12114: 	    last = NULL;
12115:             next = xmlXPathNextFollowingSibling;
12116:             break;
12117:         case AXIS_NAMESPACE:
12118:             first = NULL;
12119: 	    last = NULL;
12120:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122:             break;
12123:         case AXIS_PARENT:
12124:             first = NULL;
12125:             next = xmlXPathNextParent;
12126:             break;
12127:         case AXIS_PRECEDING:
12128:             first = NULL;
12129:             next = xmlXPathNextPrecedingInternal;
12130:             break;
12131:         case AXIS_PRECEDING_SIBLING:
12132:             first = NULL;
12133:             next = xmlXPathNextPrecedingSibling;
12134:             break;
12135:         case AXIS_SELF:
12136:             first = NULL;
12137: 	    last = NULL;
12138:             next = xmlXPathNextSelf;
12139: 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140:             break;
12141:     }
12142: 
12143: #ifdef DEBUG_STEP
12144:     xmlXPathDebugDumpStepAxis(op,
12145: 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12146: #endif
12147: 
12148:     if (next == NULL) {
12149: 	xmlXPathReleaseObject(xpctxt, obj);
12150:         return(0);
12151:     }
12152:     contextSeq = obj->nodesetval;
12153:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154: 	xmlXPathReleaseObject(xpctxt, obj);
12155:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156:         return(0);
12157:     }
12158:     /*
12159:     * Predicate optimization ---------------------------------------------
12160:     * If this step has a last predicate, which contains a position(),
12161:     * then we'll optimize (although not exactly "position()", but only
12162:     * the  short-hand form, i.e., "[n]".
12163:     *
12164:     * Example - expression "/foo[parent::bar][1]":
12165:     *
12166:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12167:     *   ROOT                               -- op->ch1
12168:     *   PREDICATE                          -- op->ch2 (predOp)
12169:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12170:     *       SORT
12171:     *         COLLECT  'parent' 'name' 'node' bar
12172:     *           NODE
12173:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12174:     *
12175:     */
12176:     maxPos = 0;
12177:     predOp = NULL;
12178:     hasPredicateRange = 0;
12179:     hasAxisRange = 0;
12180:     if (op->ch2 != -1) {
12181: 	/*
12182: 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183: 	*/
12184: 	predOp = &ctxt->comp->steps[op->ch2];
12185: 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186: 	    if (predOp->ch1 != -1) {
12187: 		/*
12188: 		* Use the next inner predicate operator.
12189: 		*/
12190: 		predOp = &ctxt->comp->steps[predOp->ch1];
12191: 		hasPredicateRange = 1;
12192: 	    } else {
12193: 		/*
12194: 		* There's no other predicate than the [n] predicate.
12195: 		*/
12196: 		predOp = NULL;
12197: 		hasAxisRange = 1;
12198: 	    }
12199: 	}
12200:     }
12201:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12202:     /*
12203:     * Axis traversal -----------------------------------------------------
12204:     */
12205:     /*
12206:      * 2.3 Node Tests
12207:      *  - For the attribute axis, the principal node type is attribute.
12208:      *  - For the namespace axis, the principal node type is namespace.
12209:      *  - For other axes, the principal node type is element.
12210:      *
12211:      * A node test * is true for any node of the
12212:      * principal node type. For example, child::* will
12213:      * select all element children of the context node
12214:      */
12215:     oldContextNode = xpctxt->node;
12216:     addNode = xmlXPathNodeSetAddUnique;
12217:     outSeq = NULL;
12218:     seq = NULL;
12219:     outerContextNode = NULL;
12220:     contextNode = NULL;
12221:     contextIdx = 0;
12222: 
12223: 
12224:     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225: 	if (outerNext != NULL) {
12226: 	    /*
12227: 	    * This is a compound traversal.
12228: 	    */
12229: 	    if (contextNode == NULL) {
12230: 		/*
12231: 		* Set the context for the outer traversal.
12232: 		*/
12233: 		outerContextNode = contextSeq->nodeTab[contextIdx++];
12234: 		contextNode = outerNext(NULL, outerContextNode);
12235: 	    } else
12236: 		contextNode = outerNext(contextNode, outerContextNode);
12237: 	    if (contextNode == NULL)
12238: 		continue;
12239: 	    /*
12240: 	    * Set the context for the main traversal.
12241: 	    */
12242: 	    xpctxt->node = contextNode;
12243: 	} else
12244: 	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245: 
12246: 	if (seq == NULL) {
12247: 	    seq = xmlXPathNodeSetCreate(NULL);
12248: 	    if (seq == NULL) {
12249: 		total = 0;
12250: 		goto error;
12251: 	    }
12252: 	}
12253: 	/*
12254: 	* Traverse the axis and test the nodes.
12255: 	*/
12256: 	pos = 0;
12257: 	cur = NULL;
12258: 	hasNsNodes = 0;
12259:         do {
12260:             cur = next(ctxt, cur);
12261:             if (cur == NULL)
12262:                 break;
12263: 
12264: 	    /*
12265: 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12266: 	    */
12267:             if ((first != NULL) && (*first != NULL)) {
12268: 		if (*first == cur)
12269: 		    break;
12270: 		if (((total % 256) == 0) &&
12271: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272: 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12273: #else
12274: 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12275: #endif
12276: 		{
12277: 		    break;
12278: 		}
12279: 	    }
12280: 	    if ((last != NULL) && (*last != NULL)) {
12281: 		if (*last == cur)
12282: 		    break;
12283: 		if (((total % 256) == 0) &&
12284: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285: 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12286: #else
12287: 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12288: #endif
12289: 		{
12290: 		    break;
12291: 		}
12292: 	    }
12293: 
12294:             total++;
12295: 
12296: #ifdef DEBUG_STEP
12297:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298: #endif
12299: 
12300: 	    switch (test) {
12301:                 case NODE_TEST_NONE:
12302: 		    total = 0;
12303:                     STRANGE
12304: 		    goto error;
12305:                 case NODE_TEST_TYPE:
12306: 		    /*
12307: 		    * TODO: Don't we need to use
12308: 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12309: 		    *  Surprisingly, some c14n tests fail, if we do this.
12310: 		    */
12311: 		    if (type == NODE_TYPE_NODE) {
12312: 			switch (cur->type) {
12313: 			    case XML_DOCUMENT_NODE:
12314: 			    case XML_HTML_DOCUMENT_NODE:
12315: #ifdef LIBXML_DOCB_ENABLED
12316: 			    case XML_DOCB_DOCUMENT_NODE:
12317: #endif
12318: 			    case XML_ELEMENT_NODE:
12319: 			    case XML_ATTRIBUTE_NODE:
12320: 			    case XML_PI_NODE:
12321: 			    case XML_COMMENT_NODE:
12322: 			    case XML_CDATA_SECTION_NODE:
12323: 			    case XML_TEXT_NODE:
12324: 			    case XML_NAMESPACE_DECL:
12325: 				XP_TEST_HIT
12326: 				break;
12327: 			    default:
12328: 				break;
12329: 			}
12330: 		    } else if (cur->type == type) {
12331: 			if (type == XML_NAMESPACE_DECL)
12332: 			    XP_TEST_HIT_NS
12333: 			else
12334: 			    XP_TEST_HIT
12335: 		    } else if ((type == NODE_TYPE_TEXT) &&
12336: 			 (cur->type == XML_CDATA_SECTION_NODE))
12337: 		    {
12338: 			XP_TEST_HIT
12339: 		    }
12340: 		    break;
12341:                 case NODE_TEST_PI:
12342:                     if ((cur->type == XML_PI_NODE) &&
12343:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12344: 		    {
12345: 			XP_TEST_HIT
12346:                     }
12347:                     break;
12348:                 case NODE_TEST_ALL:
12349:                     if (axis == AXIS_ATTRIBUTE) {
12350:                         if (cur->type == XML_ATTRIBUTE_NODE)
12351: 			{
12352: 			    XP_TEST_HIT
12353:                         }
12354:                     } else if (axis == AXIS_NAMESPACE) {
12355:                         if (cur->type == XML_NAMESPACE_DECL)
12356: 			{
12357: 			    XP_TEST_HIT_NS
12358:                         }
12359:                     } else {
12360:                         if (cur->type == XML_ELEMENT_NODE) {
12361:                             if (prefix == NULL)
12362: 			    {
12363: 				XP_TEST_HIT
12364: 
12365:                             } else if ((cur->ns != NULL) &&
12366: 				(xmlStrEqual(URI, cur->ns->href)))
12367: 			    {
12368: 				XP_TEST_HIT
12369:                             }
12370:                         }
12371:                     }
12372:                     break;
12373:                 case NODE_TEST_NS:{
12374:                         TODO;
12375:                         break;
12376:                     }
12377:                 case NODE_TEST_NAME:
12378:                     if (axis == AXIS_ATTRIBUTE) {
12379:                         if (cur->type != XML_ATTRIBUTE_NODE)
12380: 			    break;
12381: 		    } else if (axis == AXIS_NAMESPACE) {
12382:                         if (cur->type != XML_NAMESPACE_DECL)
12383: 			    break;
12384: 		    } else {
12385: 		        if (cur->type != XML_ELEMENT_NODE)
12386: 			    break;
12387: 		    }
12388:                     switch (cur->type) {
12389:                         case XML_ELEMENT_NODE:
12390:                             if (xmlStrEqual(name, cur->name)) {
12391:                                 if (prefix == NULL) {
12392:                                     if (cur->ns == NULL)
12393: 				    {
12394: 					XP_TEST_HIT
12395:                                     }
12396:                                 } else {
12397:                                     if ((cur->ns != NULL) &&
12398:                                         (xmlStrEqual(URI, cur->ns->href)))
12399: 				    {
12400: 					XP_TEST_HIT
12401:                                     }
12402:                                 }
12403:                             }
12404:                             break;
12405:                         case XML_ATTRIBUTE_NODE:{
12406:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12407: 
12408:                                 if (xmlStrEqual(name, attr->name)) {
12409:                                     if (prefix == NULL) {
12410:                                         if ((attr->ns == NULL) ||
12411:                                             (attr->ns->prefix == NULL))
12412: 					{
12413: 					    XP_TEST_HIT
12414:                                         }
12415:                                     } else {
12416:                                         if ((attr->ns != NULL) &&
12417:                                             (xmlStrEqual(URI,
12418: 					      attr->ns->href)))
12419: 					{
12420: 					    XP_TEST_HIT
12421:                                         }
12422:                                     }
12423:                                 }
12424:                                 break;
12425:                             }
12426:                         case XML_NAMESPACE_DECL:
12427:                             if (cur->type == XML_NAMESPACE_DECL) {
12428:                                 xmlNsPtr ns = (xmlNsPtr) cur;
12429: 
12430:                                 if ((ns->prefix != NULL) && (name != NULL)
12431:                                     && (xmlStrEqual(ns->prefix, name)))
12432: 				{
12433: 				    XP_TEST_HIT_NS
12434:                                 }
12435:                             }
12436:                             break;
12437:                         default:
12438:                             break;
12439:                     }
12440:                     break;
12441: 	    } /* switch(test) */
12442:         } while (cur != NULL);
12443: 
12444: 	goto apply_predicates;
12445: 
12446: axis_range_end: /* ----------------------------------------------------- */
12447: 	/*
12448: 	* We have a "/foo[n]", and position() = n was reached.
12449: 	* Note that we can have as well "/foo/::parent::foo[1]", so
12450: 	* a duplicate-aware merge is still needed.
12451: 	* Merge with the result.
12452: 	*/
12453: 	if (outSeq == NULL) {
12454: 	    outSeq = seq;
12455: 	    seq = NULL;
12456: 	} else
12457: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12458: 	/*
12459: 	* Break if only a true/false result was requested.
12460: 	*/
12461: 	if (toBool)
12462: 	    break;
12463: 	continue;
12464: 
12465: first_hit: /* ---------------------------------------------------------- */
12466: 	/*
12467: 	* Break if only a true/false result was requested and
12468: 	* no predicates existed and a node test succeeded.
12469: 	*/
12470: 	if (outSeq == NULL) {
12471: 	    outSeq = seq;
12472: 	    seq = NULL;
12473: 	} else
12474: 	    outSeq = mergeAndClear(outSeq, seq, 0);
12475: 	break;
12476: 
12477: #ifdef DEBUG_STEP
12478: 	if (seq != NULL)
12479: 	    nbMatches += seq->nodeNr;
12480: #endif
12481: 
12482: apply_predicates: /* --------------------------------------------------- */
12483:         /*
12484: 	* Apply predicates.
12485: 	*/
12486:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487: 	    /*
12488: 	    * E.g. when we have a "/foo[some expression][n]".
12489: 	    */	    
12490: 	    /*
12491: 	    * QUESTION TODO: The old predicate evaluation took into
12492: 	    *  account location-sets.
12493: 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494: 	    *  Do we expect such a set here?
12495: 	    *  All what I learned now from the evaluation semantics
12496: 	    *  does not indicate that a location-set will be processed
12497: 	    *  here, so this looks OK.
12498: 	    */	    
12499: 	    /*
12500: 	    * Iterate over all predicates, starting with the outermost
12501: 	    * predicate.
12502: 	    * TODO: Problem: we cannot execute the inner predicates first
12503: 	    *  since we cannot go back *up* the operator tree!
12504: 	    *  Options we have:
12505: 	    *  1) Use of recursive functions (like is it currently done
12506: 	    *     via xmlXPathCompOpEval())
12507: 	    *  2) Add a predicate evaluation information stack to the
12508: 	    *     context struct
12509: 	    *  3) Change the way the operators are linked; we need a
12510: 	    *     "parent" field on xmlXPathStepOp
12511: 	    *
12512: 	    * For the moment, I'll try to solve this with a recursive
12513: 	    * function: xmlXPathCompOpEvalPredicate().
12514: 	    */
12515: 	    size = seq->nodeNr;
12516: 	    if (hasPredicateRange != 0)
12517: 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518: 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519: 	    else
12520: 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521: 		    predOp, seq, size, hasNsNodes);
12522: 
12523: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12524: 		total = 0;
12525: 		goto error;
12526: 	    }
12527: 	    /*
12528: 	    * Add the filtered set of nodes to the result node set.
12529: 	    */
12530: 	    if (newSize == 0) {
12531: 		/*
12532: 		* The predicates filtered all nodes out.
12533: 		*/
12534: 		xmlXPathNodeSetClear(seq, hasNsNodes);
12535: 	    } else if (seq->nodeNr > 0) {
12536: 		/*
12537: 		* Add to result set.
12538: 		*/
12539: 		if (outSeq == NULL) {
12540: 		    if (size != newSize) {
12541: 			/*
12542: 			* We need to merge and clear here, since
12543: 			* the sequence will contained NULLed entries.
12544: 			*/
12545: 			outSeq = mergeAndClear(NULL, seq, 1);
12546: 		    } else {
12547: 			outSeq = seq;
12548: 			seq = NULL;
12549: 		    }
12550: 		} else
12551: 		    outSeq = mergeAndClear(outSeq, seq,
12552: 			(size != newSize) ? 1: 0);
12553: 		/*
12554: 		* Break if only a true/false result was requested.
12555: 		*/
12556: 		if (toBool)
12557: 		    break;
12558: 	    }
12559:         } else if (seq->nodeNr > 0) {
12560: 	    /*
12561: 	    * Add to result set.
12562: 	    */
12563: 	    if (outSeq == NULL) {
12564: 		outSeq = seq;
12565: 		seq = NULL;
12566: 	    } else {
12567: 		outSeq = mergeAndClear(outSeq, seq, 0);
12568: 	    }
12569: 	}
12570:     }
12571: 
12572: error:
12573:     if ((obj->boolval) && (obj->user != NULL)) {
12574: 	/*
12575: 	* QUESTION TODO: What does this do and why?
12576: 	* TODO: Do we have to do this also for the "error"
12577: 	* cleanup further down?
12578: 	*/
12579: 	ctxt->value->boolval = 1;
12580: 	ctxt->value->user = obj->user;
12581: 	obj->user = NULL;
12582: 	obj->boolval = 0;
12583:     }
12584:     xmlXPathReleaseObject(xpctxt, obj);
12585: 
12586:     /*
12587:     * Ensure we return at least an emtpy set.
12588:     */
12589:     if (outSeq == NULL) {
12590: 	if ((seq != NULL) && (seq->nodeNr == 0))
12591: 	    outSeq = seq;
12592: 	else
12593: 	    outSeq = xmlXPathNodeSetCreate(NULL);
12594:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12595:     }
12596:     if ((seq != NULL) && (seq != outSeq)) {
12597: 	 xmlXPathFreeNodeSet(seq);
12598:     }
12599:     /*
12600:     * Hand over the result. Better to push the set also in
12601:     * case of errors.
12602:     */
12603:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604:     /*
12605:     * Reset the context node.
12606:     */
12607:     xpctxt->node = oldContextNode;
12608: 
12609: #ifdef DEBUG_STEP
12610:     xmlGenericError(xmlGenericErrorContext,
12611: 	"\nExamined %d nodes, found %d nodes at that step\n",
12612: 	total, nbMatches);
12613: #endif
12614: 
12615:     return(total);
12616: }
12617: 
12618: static int
12619: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620: 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12621: 
12622: /**
12623:  * xmlXPathCompOpEvalFirst:
12624:  * @ctxt:  the XPath parser context with the compiled expression
12625:  * @op:  an XPath compiled operation
12626:  * @first:  the first elem found so far
12627:  *
12628:  * Evaluate the Precompiled XPath operation searching only the first
12629:  * element in document order
12630:  *
12631:  * Returns the number of examined objects.
12632:  */
12633: static int
12634: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12636: {
12637:     int total = 0, cur;
12638:     xmlXPathCompExprPtr comp;
12639:     xmlXPathObjectPtr arg1, arg2;
12640: 
12641:     CHECK_ERROR0;
12642:     comp = ctxt->comp;
12643:     switch (op->op) {
12644:         case XPATH_OP_END:
12645:             return (0);
12646:         case XPATH_OP_UNION:
12647:             total =
12648:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649:                                         first);
12650: 	    CHECK_ERROR0;
12651:             if ((ctxt->value != NULL)
12652:                 && (ctxt->value->type == XPATH_NODESET)
12653:                 && (ctxt->value->nodesetval != NULL)
12654:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655:                 /*
12656:                  * limit tree traversing to first node in the result
12657:                  */
12658: 		/*
12659: 		* OPTIMIZE TODO: This implicitely sorts
12660: 		*  the result, even if not needed. E.g. if the argument
12661: 		*  of the count() function, no sorting is needed.
12662: 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12663: 		*  aready sorted?
12664: 		*/
12665: 		if (ctxt->value->nodesetval->nodeNr > 1)
12666: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667:                 *first = ctxt->value->nodesetval->nodeTab[0];
12668:             }
12669:             cur =
12670:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671:                                         first);
12672: 	    CHECK_ERROR0;
12673:             CHECK_TYPE0(XPATH_NODESET);
12674:             arg2 = valuePop(ctxt);
12675: 
12676:             CHECK_TYPE0(XPATH_NODESET);
12677:             arg1 = valuePop(ctxt);
12678: 
12679:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680:                                                     arg2->nodesetval);
12681:             valuePush(ctxt, arg1);
12682: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12683:             /* optimizer */
12684: 	    if (total > cur)
12685: 		xmlXPathCompSwap(op);
12686:             return (total + cur);
12687:         case XPATH_OP_ROOT:
12688:             xmlXPathRoot(ctxt);
12689:             return (0);
12690:         case XPATH_OP_NODE:
12691:             if (op->ch1 != -1)
12692:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693: 	    CHECK_ERROR0;
12694:             if (op->ch2 != -1)
12695:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696: 	    CHECK_ERROR0;
12697: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698: 		ctxt->context->node));
12699:             return (total);
12700:         case XPATH_OP_RESET:
12701:             if (op->ch1 != -1)
12702:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12703: 	    CHECK_ERROR0;
12704:             if (op->ch2 != -1)
12705:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12706: 	    CHECK_ERROR0;
12707:             ctxt->context->node = NULL;
12708:             return (total);
12709:         case XPATH_OP_COLLECT:{
12710:                 if (op->ch1 == -1)
12711:                     return (total);
12712: 
12713:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12714: 		CHECK_ERROR0;
12715: 
12716:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12717:                 return (total);
12718:             }
12719:         case XPATH_OP_VALUE:
12720:             valuePush(ctxt,
12721:                       xmlXPathCacheObjectCopy(ctxt->context,
12722: 			(xmlXPathObjectPtr) op->value4));
12723:             return (0);
12724:         case XPATH_OP_SORT:
12725:             if (op->ch1 != -1)
12726:                 total +=
12727:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728:                                             first);
12729: 	    CHECK_ERROR0;
12730:             if ((ctxt->value != NULL)
12731:                 && (ctxt->value->type == XPATH_NODESET)
12732:                 && (ctxt->value->nodesetval != NULL)
12733: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12734:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735:             return (total);
12736: #ifdef XP_OPTIMIZED_FILTER_FIRST
12737: 	case XPATH_OP_FILTER:
12738:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12739:             return (total);
12740: #endif
12741:         default:
12742:             return (xmlXPathCompOpEval(ctxt, op));
12743:     }
12744: }
12745: 
12746: /**
12747:  * xmlXPathCompOpEvalLast:
12748:  * @ctxt:  the XPath parser context with the compiled expression
12749:  * @op:  an XPath compiled operation
12750:  * @last:  the last elem found so far
12751:  *
12752:  * Evaluate the Precompiled XPath operation searching only the last
12753:  * element in document order
12754:  *
12755:  * Returns the number of nodes traversed
12756:  */
12757: static int
12758: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759:                        xmlNodePtr * last)
12760: {
12761:     int total = 0, cur;
12762:     xmlXPathCompExprPtr comp;
12763:     xmlXPathObjectPtr arg1, arg2;
12764:     xmlNodePtr bak;
12765:     xmlDocPtr bakd;
12766:     int pp;
12767:     int cs;
12768: 
12769:     CHECK_ERROR0;
12770:     comp = ctxt->comp;
12771:     switch (op->op) {
12772:         case XPATH_OP_END:
12773:             return (0);
12774:         case XPATH_OP_UNION:
12775: 	    bakd = ctxt->context->doc;
12776: 	    bak = ctxt->context->node;
12777: 	    pp = ctxt->context->proximityPosition;
12778: 	    cs = ctxt->context->contextSize;
12779:             total =
12780:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12781: 	    CHECK_ERROR0;
12782:             if ((ctxt->value != NULL)
12783:                 && (ctxt->value->type == XPATH_NODESET)
12784:                 && (ctxt->value->nodesetval != NULL)
12785:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786:                 /*
12787:                  * limit tree traversing to first node in the result
12788:                  */
12789: 		if (ctxt->value->nodesetval->nodeNr > 1)
12790: 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12791:                 *last =
12792:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12793:                                                      nodesetval->nodeNr -
12794:                                                      1];
12795:             }
12796: 	    ctxt->context->doc = bakd;
12797: 	    ctxt->context->node = bak;
12798: 	    ctxt->context->proximityPosition = pp;
12799: 	    ctxt->context->contextSize = cs;
12800:             cur =
12801:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12802: 	    CHECK_ERROR0;
12803:             if ((ctxt->value != NULL)
12804:                 && (ctxt->value->type == XPATH_NODESET)
12805:                 && (ctxt->value->nodesetval != NULL)
12806:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12807:             }
12808:             CHECK_TYPE0(XPATH_NODESET);
12809:             arg2 = valuePop(ctxt);
12810: 
12811:             CHECK_TYPE0(XPATH_NODESET);
12812:             arg1 = valuePop(ctxt);
12813: 
12814:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815:                                                     arg2->nodesetval);
12816:             valuePush(ctxt, arg1);
12817: 	    xmlXPathReleaseObject(ctxt->context, arg2);
12818:             /* optimizer */
12819: 	    if (total > cur)
12820: 		xmlXPathCompSwap(op);
12821:             return (total + cur);
12822:         case XPATH_OP_ROOT:
12823:             xmlXPathRoot(ctxt);
12824:             return (0);
12825:         case XPATH_OP_NODE:
12826:             if (op->ch1 != -1)
12827:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12828: 	    CHECK_ERROR0;
12829:             if (op->ch2 != -1)
12830:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831: 	    CHECK_ERROR0;
12832: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833: 		ctxt->context->node));
12834:             return (total);
12835:         case XPATH_OP_RESET:
12836:             if (op->ch1 != -1)
12837:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838: 	    CHECK_ERROR0;
12839:             if (op->ch2 != -1)
12840:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12841: 	    CHECK_ERROR0;
12842:             ctxt->context->node = NULL;
12843:             return (total);
12844:         case XPATH_OP_COLLECT:{
12845:                 if (op->ch1 == -1)
12846:                     return (0);
12847: 
12848:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12849: 		CHECK_ERROR0;
12850: 
12851:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12852:                 return (total);
12853:             }
12854:         case XPATH_OP_VALUE:
12855:             valuePush(ctxt,
12856:                       xmlXPathCacheObjectCopy(ctxt->context,
12857: 			(xmlXPathObjectPtr) op->value4));
12858:             return (0);
12859:         case XPATH_OP_SORT:
12860:             if (op->ch1 != -1)
12861:                 total +=
12862:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863:                                            last);
12864: 	    CHECK_ERROR0;
12865:             if ((ctxt->value != NULL)
12866:                 && (ctxt->value->type == XPATH_NODESET)
12867:                 && (ctxt->value->nodesetval != NULL)
12868: 		&& (ctxt->value->nodesetval->nodeNr > 1))
12869:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870:             return (total);
12871:         default:
12872:             return (xmlXPathCompOpEval(ctxt, op));
12873:     }
12874: }
12875: 
12876: #ifdef XP_OPTIMIZED_FILTER_FIRST
12877: static int
12878: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879: 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12880: {
12881:     int total = 0;
12882:     xmlXPathCompExprPtr comp;
12883:     xmlXPathObjectPtr res;
12884:     xmlXPathObjectPtr obj;
12885:     xmlNodeSetPtr oldset;
12886:     xmlNodePtr oldnode;
12887:     xmlDocPtr oldDoc;
12888:     int i;
12889: 
12890:     CHECK_ERROR0;
12891:     comp = ctxt->comp;
12892:     /*
12893:     * Optimization for ()[last()] selection i.e. the last elem
12894:     */
12895:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896: 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897: 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898: 	int f = comp->steps[op->ch2].ch1;
12899: 
12900: 	if ((f != -1) &&
12901: 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902: 	    (comp->steps[f].value5 == NULL) &&
12903: 	    (comp->steps[f].value == 0) &&
12904: 	    (comp->steps[f].value4 != NULL) &&
12905: 	    (xmlStrEqual
12906: 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12907: 	    xmlNodePtr last = NULL;
12908: 
12909: 	    total +=
12910: 		xmlXPathCompOpEvalLast(ctxt,
12911: 		    &comp->steps[op->ch1],
12912: 		    &last);
12913: 	    CHECK_ERROR0;
12914: 	    /*
12915: 	    * The nodeset should be in document order,
12916: 	    * Keep only the last value
12917: 	    */
12918: 	    if ((ctxt->value != NULL) &&
12919: 		(ctxt->value->type == XPATH_NODESET) &&
12920: 		(ctxt->value->nodesetval != NULL) &&
12921: 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12922: 		(ctxt->value->nodesetval->nodeNr > 1)) {
12923: 		ctxt->value->nodesetval->nodeTab[0] =
12924: 		    ctxt->value->nodesetval->nodeTab[ctxt->
12925: 		    value->
12926: 		    nodesetval->
12927: 		    nodeNr -
12928: 		    1];
12929: 		ctxt->value->nodesetval->nodeNr = 1;
12930: 		*first = *(ctxt->value->nodesetval->nodeTab);
12931: 	    }
12932: 	    return (total);
12933: 	}
12934:     }
12935: 
12936:     if (op->ch1 != -1)
12937: 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938:     CHECK_ERROR0;
12939:     if (op->ch2 == -1)
12940: 	return (total);
12941:     if (ctxt->value == NULL)
12942: 	return (total);
12943: 
12944: #ifdef LIBXML_XPTR_ENABLED
12945:     oldnode = ctxt->context->node;
12946:     /*
12947:     * Hum are we filtering the result of an XPointer expression
12948:     */
12949:     if (ctxt->value->type == XPATH_LOCATIONSET) {
12950: 	xmlXPathObjectPtr tmp = NULL;
12951: 	xmlLocationSetPtr newlocset = NULL;
12952: 	xmlLocationSetPtr oldlocset;
12953: 
12954: 	/*
12955: 	* Extract the old locset, and then evaluate the result of the
12956: 	* expression for all the element in the locset. use it to grow
12957: 	* up a new locset.
12958: 	*/
12959: 	CHECK_TYPE0(XPATH_LOCATIONSET);
12960: 	obj = valuePop(ctxt);
12961: 	oldlocset = obj->user;
12962: 	ctxt->context->node = NULL;
12963: 
12964: 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965: 	    ctxt->context->contextSize = 0;
12966: 	    ctxt->context->proximityPosition = 0;
12967: 	    if (op->ch2 != -1)
12968: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969: 	    res = valuePop(ctxt);
12970: 	    if (res != NULL) {
12971: 		xmlXPathReleaseObject(ctxt->context, res);
12972: 	    }
12973: 	    valuePush(ctxt, obj);
12974: 	    CHECK_ERROR0;
12975: 	    return (total);
12976: 	}
12977: 	newlocset = xmlXPtrLocationSetCreate(NULL);
12978: 
12979: 	for (i = 0; i < oldlocset->locNr; i++) {
12980: 	    /*
12981: 	    * Run the evaluation with a node list made of a
12982: 	    * single item in the nodelocset.
12983: 	    */
12984: 	    ctxt->context->node = oldlocset->locTab[i]->user;
12985: 	    ctxt->context->contextSize = oldlocset->locNr;
12986: 	    ctxt->context->proximityPosition = i + 1;
12987: 	    if (tmp == NULL) {
12988: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989: 		    ctxt->context->node);
12990: 	    } else {
12991: 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992: 		    ctxt->context->node);
12993: 	    }
12994: 	    valuePush(ctxt, tmp);
12995: 	    if (op->ch2 != -1)
12996: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12998: 		xmlXPathFreeObject(obj);
12999: 		return(0);
13000: 	    }
13001: 	    /*
13002: 	    * The result of the evaluation need to be tested to
13003: 	    * decided whether the filter succeeded or not
13004: 	    */
13005: 	    res = valuePop(ctxt);
13006: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007: 		xmlXPtrLocationSetAdd(newlocset,
13008: 		    xmlXPathCacheObjectCopy(ctxt->context,
13009: 			oldlocset->locTab[i]));
13010: 	    }
13011: 	    /*
13012: 	    * Cleanup
13013: 	    */
13014: 	    if (res != NULL) {
13015: 		xmlXPathReleaseObject(ctxt->context, res);
13016: 	    }
13017: 	    if (ctxt->value == tmp) {
13018: 		valuePop(ctxt);
13019: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13020: 		/*
13021: 		* REVISIT TODO: Don't create a temporary nodeset
13022: 		* for everly iteration.
13023: 		*/
13024: 		/* OLD: xmlXPathFreeObject(res); */
13025: 	    } else
13026: 		tmp = NULL;
13027: 	    ctxt->context->node = NULL;
13028: 	    /*
13029: 	    * Only put the first node in the result, then leave.
13030: 	    */
13031: 	    if (newlocset->locNr > 0) {
13032: 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033: 		break;
13034: 	    }
13035: 	}
13036: 	if (tmp != NULL) {
13037: 	    xmlXPathReleaseObject(ctxt->context, tmp);
13038: 	}
13039: 	/*
13040: 	* The result is used as the new evaluation locset.
13041: 	*/
13042: 	xmlXPathReleaseObject(ctxt->context, obj);
13043: 	ctxt->context->node = NULL;
13044: 	ctxt->context->contextSize = -1;
13045: 	ctxt->context->proximityPosition = -1;
13046: 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047: 	ctxt->context->node = oldnode;
13048: 	return (total);
13049:     }
13050: #endif /* LIBXML_XPTR_ENABLED */
13051: 
13052:     /*
13053:     * Extract the old set, and then evaluate the result of the
13054:     * expression for all the element in the set. use it to grow
13055:     * up a new set.
13056:     */
13057:     CHECK_TYPE0(XPATH_NODESET);
13058:     obj = valuePop(ctxt);
13059:     oldset = obj->nodesetval;
13060: 
13061:     oldnode = ctxt->context->node;
13062:     oldDoc = ctxt->context->doc;
13063:     ctxt->context->node = NULL;
13064: 
13065:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066: 	ctxt->context->contextSize = 0;
13067: 	ctxt->context->proximityPosition = 0;
13068: 	/* QUESTION TODO: Why was this code commented out?
13069: 	    if (op->ch2 != -1)
13070: 		total +=
13071: 		    xmlXPathCompOpEval(ctxt,
13072: 			&comp->steps[op->ch2]);
13073: 	    CHECK_ERROR0;
13074: 	    res = valuePop(ctxt);
13075: 	    if (res != NULL)
13076: 		xmlXPathFreeObject(res);
13077: 	*/
13078: 	valuePush(ctxt, obj);
13079: 	ctxt->context->node = oldnode;
13080: 	CHECK_ERROR0;
13081:     } else {
13082: 	xmlNodeSetPtr newset;
13083: 	xmlXPathObjectPtr tmp = NULL;
13084: 	/*
13085: 	* Initialize the new set.
13086: 	* Also set the xpath document in case things like
13087: 	* key() evaluation are attempted on the predicate
13088: 	*/
13089: 	newset = xmlXPathNodeSetCreate(NULL);
13090:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13091: 
13092: 	for (i = 0; i < oldset->nodeNr; i++) {
13093: 	    /*
13094: 	    * Run the evaluation with a node list made of
13095: 	    * a single item in the nodeset.
13096: 	    */
13097: 	    ctxt->context->node = oldset->nodeTab[i];
13098: 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099: 		(oldset->nodeTab[i]->doc != NULL))
13100: 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13101: 	    if (tmp == NULL) {
13102: 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103: 		    ctxt->context->node);
13104: 	    } else {
13105: 		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106: 		    ctxt->context->node);
13107: 	    }
13108: 	    valuePush(ctxt, tmp);
13109: 	    ctxt->context->contextSize = oldset->nodeNr;
13110: 	    ctxt->context->proximityPosition = i + 1;
13111: 	    if (op->ch2 != -1)
13112: 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113: 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13114: 		xmlXPathFreeNodeSet(newset);
13115: 		xmlXPathFreeObject(obj);
13116: 		return(0);
13117: 	    }
13118: 	    /*
13119: 	    * The result of the evaluation needs to be tested to
13120: 	    * decide whether the filter succeeded or not
13121: 	    */
13122: 	    res = valuePop(ctxt);
13123: 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124: 		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13125: 	    }
13126: 	    /*
13127: 	    * Cleanup
13128: 	    */
13129: 	    if (res != NULL) {
13130: 		xmlXPathReleaseObject(ctxt->context, res);
13131: 	    }
13132: 	    if (ctxt->value == tmp) {
13133: 		valuePop(ctxt);
13134: 		/*
13135: 		* Don't free the temporary nodeset
13136: 		* in order to avoid massive recreation inside this
13137: 		* loop.
13138: 		*/
13139: 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13140: 	    } else
13141: 		tmp = NULL;
13142: 	    ctxt->context->node = NULL;
13143: 	    /*
13144: 	    * Only put the first node in the result, then leave.
13145: 	    */
13146: 	    if (newset->nodeNr > 0) {
13147: 		*first = *(newset->nodeTab);
13148: 		break;
13149: 	    }
13150: 	}
13151: 	if (tmp != NULL) {
13152: 	    xmlXPathReleaseObject(ctxt->context, tmp);
13153: 	}
13154: 	/*
13155: 	* The result is used as the new evaluation set.
13156: 	*/
13157: 	xmlXPathReleaseObject(ctxt->context, obj);
13158: 	ctxt->context->node = NULL;
13159: 	ctxt->context->contextSize = -1;
13160: 	ctxt->context->proximityPosition = -1;
13161: 	/* may want to move this past the '}' later */
13162: 	ctxt->context->doc = oldDoc;
13163: 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13164:     }
13165:     ctxt->context->node = oldnode;
13166:     return(total);
13167: }
13168: #endif /* XP_OPTIMIZED_FILTER_FIRST */
13169: 
13170: /**
13171:  * xmlXPathCompOpEval:
13172:  * @ctxt:  the XPath parser context with the compiled expression
13173:  * @op:  an XPath compiled operation
13174:  *
13175:  * Evaluate the Precompiled XPath operation
13176:  * Returns the number of nodes traversed
13177:  */
13178: static int
13179: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180: {
13181:     int total = 0;
13182:     int equal, ret;
13183:     xmlXPathCompExprPtr comp;
13184:     xmlXPathObjectPtr arg1, arg2;
13185:     xmlNodePtr bak;
13186:     xmlDocPtr bakd;
13187:     int pp;
13188:     int cs;
13189: 
13190:     CHECK_ERROR0;
13191:     comp = ctxt->comp;
13192:     switch (op->op) {
13193:         case XPATH_OP_END:
13194:             return (0);
13195:         case XPATH_OP_AND:
13196: 	    bakd = ctxt->context->doc;
13197: 	    bak = ctxt->context->node;
13198: 	    pp = ctxt->context->proximityPosition;
13199: 	    cs = ctxt->context->contextSize;
13200:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13201: 	    CHECK_ERROR0;
13202:             xmlXPathBooleanFunction(ctxt, 1);
13203:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204:                 return (total);
13205:             arg2 = valuePop(ctxt);
13206: 	    ctxt->context->doc = bakd;
13207: 	    ctxt->context->node = bak;
13208: 	    ctxt->context->proximityPosition = pp;
13209: 	    ctxt->context->contextSize = cs;
13210:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13211: 	    if (ctxt->error) {
13212: 		xmlXPathFreeObject(arg2);
13213: 		return(0);
13214: 	    }
13215:             xmlXPathBooleanFunction(ctxt, 1);
13216:             arg1 = valuePop(ctxt);
13217:             arg1->boolval &= arg2->boolval;
13218:             valuePush(ctxt, arg1);
13219: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13220:             return (total);
13221:         case XPATH_OP_OR:
13222: 	    bakd = ctxt->context->doc;
13223: 	    bak = ctxt->context->node;
13224: 	    pp = ctxt->context->proximityPosition;
13225: 	    cs = ctxt->context->contextSize;
13226:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227: 	    CHECK_ERROR0;
13228:             xmlXPathBooleanFunction(ctxt, 1);
13229:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230:                 return (total);
13231:             arg2 = valuePop(ctxt);
13232: 	    ctxt->context->doc = bakd;
13233: 	    ctxt->context->node = bak;
13234: 	    ctxt->context->proximityPosition = pp;
13235: 	    ctxt->context->contextSize = cs;
13236:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13237: 	    if (ctxt->error) {
13238: 		xmlXPathFreeObject(arg2);
13239: 		return(0);
13240: 	    }
13241:             xmlXPathBooleanFunction(ctxt, 1);
13242:             arg1 = valuePop(ctxt);
13243:             arg1->boolval |= arg2->boolval;
13244:             valuePush(ctxt, arg1);
13245: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13246:             return (total);
13247:         case XPATH_OP_EQUAL:
13248: 	    bakd = ctxt->context->doc;
13249: 	    bak = ctxt->context->node;
13250: 	    pp = ctxt->context->proximityPosition;
13251: 	    cs = ctxt->context->contextSize;
13252:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13253: 	    CHECK_ERROR0;
13254: 	    ctxt->context->doc = bakd;
13255: 	    ctxt->context->node = bak;
13256: 	    ctxt->context->proximityPosition = pp;
13257: 	    ctxt->context->contextSize = cs;
13258:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13259: 	    CHECK_ERROR0;
13260: 	    if (op->value)
13261: 		equal = xmlXPathEqualValues(ctxt);
13262: 	    else
13263: 		equal = xmlXPathNotEqualValues(ctxt);
13264: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13265:             return (total);
13266:         case XPATH_OP_CMP:
13267: 	    bakd = ctxt->context->doc;
13268: 	    bak = ctxt->context->node;
13269: 	    pp = ctxt->context->proximityPosition;
13270: 	    cs = ctxt->context->contextSize;
13271:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13272: 	    CHECK_ERROR0;
13273: 	    ctxt->context->doc = bakd;
13274: 	    ctxt->context->node = bak;
13275: 	    ctxt->context->proximityPosition = pp;
13276: 	    ctxt->context->contextSize = cs;
13277:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13278: 	    CHECK_ERROR0;
13279:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280: 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13281:             return (total);
13282:         case XPATH_OP_PLUS:
13283: 	    bakd = ctxt->context->doc;
13284: 	    bak = ctxt->context->node;
13285: 	    pp = ctxt->context->proximityPosition;
13286: 	    cs = ctxt->context->contextSize;
13287:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288: 	    CHECK_ERROR0;
13289:             if (op->ch2 != -1) {
13290: 		ctxt->context->doc = bakd;
13291: 		ctxt->context->node = bak;
13292: 		ctxt->context->proximityPosition = pp;
13293: 		ctxt->context->contextSize = cs;
13294:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295: 	    }
13296: 	    CHECK_ERROR0;
13297:             if (op->value == 0)
13298:                 xmlXPathSubValues(ctxt);
13299:             else if (op->value == 1)
13300:                 xmlXPathAddValues(ctxt);
13301:             else if (op->value == 2)
13302:                 xmlXPathValueFlipSign(ctxt);
13303:             else if (op->value == 3) {
13304:                 CAST_TO_NUMBER;
13305:                 CHECK_TYPE0(XPATH_NUMBER);
13306:             }
13307:             return (total);
13308:         case XPATH_OP_MULT:
13309: 	    bakd = ctxt->context->doc;
13310: 	    bak = ctxt->context->node;
13311: 	    pp = ctxt->context->proximityPosition;
13312: 	    cs = ctxt->context->contextSize;
13313:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13314: 	    CHECK_ERROR0;
13315: 	    ctxt->context->doc = bakd;
13316: 	    ctxt->context->node = bak;
13317: 	    ctxt->context->proximityPosition = pp;
13318: 	    ctxt->context->contextSize = cs;
13319:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13320: 	    CHECK_ERROR0;
13321:             if (op->value == 0)
13322:                 xmlXPathMultValues(ctxt);
13323:             else if (op->value == 1)
13324:                 xmlXPathDivValues(ctxt);
13325:             else if (op->value == 2)
13326:                 xmlXPathModValues(ctxt);
13327:             return (total);
13328:         case XPATH_OP_UNION:
13329: 	    bakd = ctxt->context->doc;
13330: 	    bak = ctxt->context->node;
13331: 	    pp = ctxt->context->proximityPosition;
13332: 	    cs = ctxt->context->contextSize;
13333:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334: 	    CHECK_ERROR0;
13335: 	    ctxt->context->doc = bakd;
13336: 	    ctxt->context->node = bak;
13337: 	    ctxt->context->proximityPosition = pp;
13338: 	    ctxt->context->contextSize = cs;
13339:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13340: 	    CHECK_ERROR0;
13341:             CHECK_TYPE0(XPATH_NODESET);
13342:             arg2 = valuePop(ctxt);
13343: 
13344:             CHECK_TYPE0(XPATH_NODESET);
13345:             arg1 = valuePop(ctxt);
13346: 
13347: 	    if ((arg1->nodesetval == NULL) ||
13348: 		((arg2->nodesetval != NULL) &&
13349: 		 (arg2->nodesetval->nodeNr != 0)))
13350: 	    {
13351: 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352: 							arg2->nodesetval);
13353: 	    }
13354: 
13355:             valuePush(ctxt, arg1);
13356: 	    xmlXPathReleaseObject(ctxt->context, arg2);
13357:             return (total);
13358:         case XPATH_OP_ROOT:
13359:             xmlXPathRoot(ctxt);
13360:             return (total);
13361:         case XPATH_OP_NODE:
13362:             if (op->ch1 != -1)
13363:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364: 	    CHECK_ERROR0;
13365:             if (op->ch2 != -1)
13366:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13367: 	    CHECK_ERROR0;
13368: 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369: 		ctxt->context->node));
13370:             return (total);
13371:         case XPATH_OP_RESET:
13372:             if (op->ch1 != -1)
13373:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374: 	    CHECK_ERROR0;
13375:             if (op->ch2 != -1)
13376:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13377: 	    CHECK_ERROR0;
13378:             ctxt->context->node = NULL;
13379:             return (total);
13380:         case XPATH_OP_COLLECT:{
13381:                 if (op->ch1 == -1)
13382:                     return (total);
13383: 
13384:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385: 		CHECK_ERROR0;
13386: 
13387:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13388:                 return (total);
13389:             }
13390:         case XPATH_OP_VALUE:
13391:             valuePush(ctxt,
13392:                       xmlXPathCacheObjectCopy(ctxt->context,
13393: 			(xmlXPathObjectPtr) op->value4));
13394:             return (total);
13395:         case XPATH_OP_VARIABLE:{
13396: 		xmlXPathObjectPtr val;
13397: 
13398:                 if (op->ch1 != -1)
13399:                     total +=
13400:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401:                 if (op->value5 == NULL) {
13402: 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403: 		    if (val == NULL) {
13404: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405: 			return(0);
13406: 		    }
13407:                     valuePush(ctxt, val);
13408: 		} else {
13409:                     const xmlChar *URI;
13410: 
13411:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412:                     if (URI == NULL) {
13413:                         xmlGenericError(xmlGenericErrorContext,
13414:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415:                                     (char *) op->value4, (char *)op->value5);
13416:                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13417:                         return (total);
13418:                     }
13419: 		    val = xmlXPathVariableLookupNS(ctxt->context,
13420:                                                        op->value4, URI);
13421: 		    if (val == NULL) {
13422: 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423: 			return(0);
13424: 		    }
13425:                     valuePush(ctxt, val);
13426:                 }
13427:                 return (total);
13428:             }
13429:         case XPATH_OP_FUNCTION:{
13430:                 xmlXPathFunction func;
13431:                 const xmlChar *oldFunc, *oldFuncURI;
13432: 		int i;
13433:                 int frame;
13434: 
13435:                 frame = xmlXPathSetFrame(ctxt);
13436:                 if (op->ch1 != -1)
13437:                     total +=
13438:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439: 		if (ctxt->valueNr < op->value) {
13440: 		    xmlGenericError(xmlGenericErrorContext,
13441: 			    "xmlXPathCompOpEval: parameter error\n");
13442: 		    ctxt->error = XPATH_INVALID_OPERAND;
13443:                     xmlXPathPopFrame(ctxt, frame);
13444: 		    return (total);
13445: 		}
13446: 		for (i = 0; i < op->value; i++) {
13447: 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448: 			xmlGenericError(xmlGenericErrorContext,
13449: 				"xmlXPathCompOpEval: parameter error\n");
13450: 			ctxt->error = XPATH_INVALID_OPERAND;
13451:                         xmlXPathPopFrame(ctxt, frame);
13452: 			return (total);
13453: 		    }
13454:                 }
13455:                 if (op->cache != NULL)
13456:                     XML_CAST_FPTR(func) = op->cache;
13457:                 else {
13458:                     const xmlChar *URI = NULL;
13459: 
13460:                     if (op->value5 == NULL)
13461:                         func =
13462:                             xmlXPathFunctionLookup(ctxt->context,
13463:                                                    op->value4);
13464:                     else {
13465:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466:                         if (URI == NULL) {
13467:                             xmlGenericError(xmlGenericErrorContext,
13468:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469:                                     (char *)op->value4, (char *)op->value5);
13470:                             xmlXPathPopFrame(ctxt, frame);
13471:                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13472:                             return (total);
13473:                         }
13474:                         func = xmlXPathFunctionLookupNS(ctxt->context,
13475:                                                         op->value4, URI);
13476:                     }
13477:                     if (func == NULL) {
13478:                         xmlGenericError(xmlGenericErrorContext,
13479:                                 "xmlXPathCompOpEval: function %s not found\n",
13480:                                         (char *)op->value4);
13481:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13482:                     }
13483:                     op->cache = XML_CAST_FPTR(func);
13484:                     op->cacheURI = (void *) URI;
13485:                 }
13486:                 oldFunc = ctxt->context->function;
13487:                 oldFuncURI = ctxt->context->functionURI;
13488:                 ctxt->context->function = op->value4;
13489:                 ctxt->context->functionURI = op->cacheURI;
13490:                 func(ctxt, op->value);
13491:                 ctxt->context->function = oldFunc;
13492:                 ctxt->context->functionURI = oldFuncURI;
13493:                 xmlXPathPopFrame(ctxt, frame);
13494:                 return (total);
13495:             }
13496:         case XPATH_OP_ARG:
13497: 	    bakd = ctxt->context->doc;
13498: 	    bak = ctxt->context->node;
13499: 	    pp = ctxt->context->proximityPosition;
13500: 	    cs = ctxt->context->contextSize;
13501:             if (op->ch1 != -1)
13502:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503: 	    ctxt->context->contextSize = cs;
13504: 	    ctxt->context->proximityPosition = pp;
13505: 	    ctxt->context->node = bak;
13506: 	    ctxt->context->doc = bakd;
13507: 	    CHECK_ERROR0;
13508:             if (op->ch2 != -1) {
13509:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510: 	        ctxt->context->doc = bakd;
13511: 	        ctxt->context->node = bak;
13512: 	        CHECK_ERROR0;
13513: 	    }
13514:             return (total);
13515:         case XPATH_OP_PREDICATE:
13516:         case XPATH_OP_FILTER:{
13517:                 xmlXPathObjectPtr res;
13518:                 xmlXPathObjectPtr obj, tmp;
13519:                 xmlNodeSetPtr newset = NULL;
13520:                 xmlNodeSetPtr oldset;
13521:                 xmlNodePtr oldnode;
13522: 		xmlDocPtr oldDoc;
13523:                 int i;
13524: 
13525:                 /*
13526:                  * Optimization for ()[1] selection i.e. the first elem
13527:                  */
13528:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529: #ifdef XP_OPTIMIZED_FILTER_FIRST
13530: 		    /*
13531: 		    * FILTER TODO: Can we assume that the inner processing
13532: 		    *  will result in an ordered list if we have an
13533: 		    *  XPATH_OP_FILTER?
13534: 		    *  What about an additional field or flag on
13535: 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13536: 		    *  to assume anything, so it would be more robust and
13537: 		    *  easier to optimize.
13538: 		    */
13539:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540: 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541: #else
13542: 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543: #endif
13544:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545:                     xmlXPathObjectPtr val;
13546: 
13547:                     val = comp->steps[op->ch2].value4;
13548:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549:                         (val->floatval == 1.0)) {
13550:                         xmlNodePtr first = NULL;
13551: 
13552:                         total +=
13553:                             xmlXPathCompOpEvalFirst(ctxt,
13554:                                                     &comp->steps[op->ch1],
13555:                                                     &first);
13556: 			CHECK_ERROR0;
13557:                         /*
13558:                          * The nodeset should be in document order,
13559:                          * Keep only the first value
13560:                          */
13561:                         if ((ctxt->value != NULL) &&
13562:                             (ctxt->value->type == XPATH_NODESET) &&
13563:                             (ctxt->value->nodesetval != NULL) &&
13564:                             (ctxt->value->nodesetval->nodeNr > 1))
13565:                             ctxt->value->nodesetval->nodeNr = 1;
13566:                         return (total);
13567:                     }
13568:                 }
13569:                 /*
13570:                  * Optimization for ()[last()] selection i.e. the last elem
13571:                  */
13572:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575:                     int f = comp->steps[op->ch2].ch1;
13576: 
13577:                     if ((f != -1) &&
13578:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579:                         (comp->steps[f].value5 == NULL) &&
13580:                         (comp->steps[f].value == 0) &&
13581:                         (comp->steps[f].value4 != NULL) &&
13582:                         (xmlStrEqual
13583:                          (comp->steps[f].value4, BAD_CAST "last"))) {
13584:                         xmlNodePtr last = NULL;
13585: 
13586:                         total +=
13587:                             xmlXPathCompOpEvalLast(ctxt,
13588:                                                    &comp->steps[op->ch1],
13589:                                                    &last);
13590: 			CHECK_ERROR0;
13591:                         /*
13592:                          * The nodeset should be in document order,
13593:                          * Keep only the last value
13594:                          */
13595:                         if ((ctxt->value != NULL) &&
13596:                             (ctxt->value->type == XPATH_NODESET) &&
13597:                             (ctxt->value->nodesetval != NULL) &&
13598:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13599:                             (ctxt->value->nodesetval->nodeNr > 1)) {
13600:                             ctxt->value->nodesetval->nodeTab[0] =
13601:                                 ctxt->value->nodesetval->nodeTab[ctxt->
13602:                                                                  value->
13603:                                                                  nodesetval->
13604:                                                                  nodeNr -
13605:                                                                  1];
13606:                             ctxt->value->nodesetval->nodeNr = 1;
13607:                         }
13608:                         return (total);
13609:                     }
13610:                 }
13611: 		/*
13612: 		* Process inner predicates first.
13613: 		* Example "index[parent::book][1]":
13614: 		* ...
13615: 		*   PREDICATE   <-- we are here "[1]"
13616: 		*     PREDICATE <-- process "[parent::book]" first
13617: 		*       SORT
13618: 		*         COLLECT  'parent' 'name' 'node' book
13619: 		*           NODE
13620: 		*     ELEM Object is a number : 1
13621: 		*/
13622:                 if (op->ch1 != -1)
13623:                     total +=
13624:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13625: 		CHECK_ERROR0;
13626:                 if (op->ch2 == -1)
13627:                     return (total);
13628:                 if (ctxt->value == NULL)
13629:                     return (total);
13630: 
13631:                 oldnode = ctxt->context->node;
13632: 
13633: #ifdef LIBXML_XPTR_ENABLED
13634:                 /*
13635:                  * Hum are we filtering the result of an XPointer expression
13636:                  */
13637:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13638:                     xmlLocationSetPtr newlocset = NULL;
13639:                     xmlLocationSetPtr oldlocset;
13640: 
13641:                     /*
13642:                      * Extract the old locset, and then evaluate the result of the
13643:                      * expression for all the element in the locset. use it to grow
13644:                      * up a new locset.
13645:                      */
13646:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13647:                     obj = valuePop(ctxt);
13648:                     oldlocset = obj->user;
13649:                     ctxt->context->node = NULL;
13650: 
13651:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652:                         ctxt->context->contextSize = 0;
13653:                         ctxt->context->proximityPosition = 0;
13654:                         if (op->ch2 != -1)
13655:                             total +=
13656:                                 xmlXPathCompOpEval(ctxt,
13657:                                                    &comp->steps[op->ch2]);
13658:                         res = valuePop(ctxt);
13659:                         if (res != NULL) {
13660: 			    xmlXPathReleaseObject(ctxt->context, res);
13661: 			}
13662:                         valuePush(ctxt, obj);
13663:                         CHECK_ERROR0;
13664:                         return (total);
13665:                     }
13666:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13667: 
13668:                     for (i = 0; i < oldlocset->locNr; i++) {
13669:                         /*
13670:                          * Run the evaluation with a node list made of a
13671:                          * single item in the nodelocset.
13672:                          */
13673:                         ctxt->context->node = oldlocset->locTab[i]->user;
13674:                         ctxt->context->contextSize = oldlocset->locNr;
13675:                         ctxt->context->proximityPosition = i + 1;
13676: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677: 			    ctxt->context->node);
13678:                         valuePush(ctxt, tmp);
13679: 
13680:                         if (op->ch2 != -1)
13681:                             total +=
13682:                                 xmlXPathCompOpEval(ctxt,
13683:                                                    &comp->steps[op->ch2]);
13684: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13685: 			    xmlXPathFreeObject(obj);
13686: 			    return(0);
13687: 			}
13688: 
13689:                         /*
13690:                          * The result of the evaluation need to be tested to
13691:                          * decided whether the filter succeeded or not
13692:                          */
13693:                         res = valuePop(ctxt);
13694:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695:                             xmlXPtrLocationSetAdd(newlocset,
13696:                                                   xmlXPathObjectCopy
13697:                                                   (oldlocset->locTab[i]));
13698:                         }
13699: 
13700:                         /*
13701:                          * Cleanup
13702:                          */
13703:                         if (res != NULL) {
13704: 			    xmlXPathReleaseObject(ctxt->context, res);
13705: 			}
13706:                         if (ctxt->value == tmp) {
13707:                             res = valuePop(ctxt);
13708: 			    xmlXPathReleaseObject(ctxt->context, res);
13709:                         }
13710: 
13711:                         ctxt->context->node = NULL;
13712:                     }
13713: 
13714:                     /*
13715:                      * The result is used as the new evaluation locset.
13716:                      */
13717: 		    xmlXPathReleaseObject(ctxt->context, obj);
13718:                     ctxt->context->node = NULL;
13719:                     ctxt->context->contextSize = -1;
13720:                     ctxt->context->proximityPosition = -1;
13721:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722:                     ctxt->context->node = oldnode;
13723:                     return (total);
13724:                 }
13725: #endif /* LIBXML_XPTR_ENABLED */
13726: 
13727:                 /*
13728:                  * Extract the old set, and then evaluate the result of the
13729:                  * expression for all the element in the set. use it to grow
13730:                  * up a new set.
13731:                  */
13732:                 CHECK_TYPE0(XPATH_NODESET);
13733:                 obj = valuePop(ctxt);
13734:                 oldset = obj->nodesetval;
13735: 
13736:                 oldnode = ctxt->context->node;
13737: 		oldDoc = ctxt->context->doc;
13738:                 ctxt->context->node = NULL;
13739: 
13740:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741:                     ctxt->context->contextSize = 0;
13742:                     ctxt->context->proximityPosition = 0;
13743: /*
13744:                     if (op->ch2 != -1)
13745:                         total +=
13746:                             xmlXPathCompOpEval(ctxt,
13747:                                                &comp->steps[op->ch2]);
13748: 		    CHECK_ERROR0;
13749:                     res = valuePop(ctxt);
13750:                     if (res != NULL)
13751:                         xmlXPathFreeObject(res);
13752: */
13753:                     valuePush(ctxt, obj);
13754:                     ctxt->context->node = oldnode;
13755:                     CHECK_ERROR0;
13756:                 } else {
13757: 		    tmp = NULL;
13758:                     /*
13759:                      * Initialize the new set.
13760: 		     * Also set the xpath document in case things like
13761: 		     * key() evaluation are attempted on the predicate
13762:                      */
13763:                     newset = xmlXPathNodeSetCreate(NULL);
13764: 		    /*
13765: 		    * SPEC XPath 1.0:
13766: 		    *  "For each node in the node-set to be filtered, the
13767: 		    *  PredicateExpr is evaluated with that node as the
13768: 		    *  context node, with the number of nodes in the
13769: 		    *  node-set as the context size, and with the proximity
13770: 		    *  position of the node in the node-set with respect to
13771: 		    *  the axis as the context position;"
13772: 		    * @oldset is the node-set" to be filtered.
13773: 		    *
13774: 		    * SPEC XPath 1.0:
13775: 		    *  "only predicates change the context position and
13776: 		    *  context size (see [2.4 Predicates])."
13777: 		    * Example:
13778: 		    *   node-set  context pos
13779: 		    *    nA         1
13780: 		    *    nB         2
13781: 		    *    nC         3
13782: 		    *   After applying predicate [position() > 1] :
13783: 		    *   node-set  context pos
13784: 		    *    nB         1
13785: 		    *    nC         2
13786: 		    *
13787: 		    * removed the first node in the node-set, then
13788: 		    * the context position of the
13789: 		    */
13790:                     for (i = 0; i < oldset->nodeNr; i++) {
13791:                         /*
13792:                          * Run the evaluation with a node list made of
13793:                          * a single item in the nodeset.
13794:                          */
13795:                         ctxt->context->node = oldset->nodeTab[i];
13796: 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797: 			    (oldset->nodeTab[i]->doc != NULL))
13798: 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13799: 			if (tmp == NULL) {
13800: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801: 				ctxt->context->node);
13802: 			} else {
13803: 			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804: 				ctxt->context->node);
13805: 			}
13806:                         valuePush(ctxt, tmp);
13807:                         ctxt->context->contextSize = oldset->nodeNr;
13808:                         ctxt->context->proximityPosition = i + 1;
13809: 			/*
13810: 			* Evaluate the predicate against the context node.
13811: 			* Can/should we optimize position() predicates
13812: 			* here (e.g. "[1]")?
13813: 			*/
13814:                         if (op->ch2 != -1)
13815:                             total +=
13816:                                 xmlXPathCompOpEval(ctxt,
13817:                                                    &comp->steps[op->ch2]);
13818: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13819: 			    xmlXPathFreeNodeSet(newset);
13820: 			    xmlXPathFreeObject(obj);
13821: 			    return(0);
13822: 			}
13823: 
13824:                         /*
13825:                          * The result of the evaluation needs to be tested to
13826:                          * decide whether the filter succeeded or not
13827:                          */
13828: 			/*
13829: 			* OPTIMIZE TODO: Can we use
13830: 			* xmlXPathNodeSetAdd*Unique()* instead?
13831: 			*/
13832:                         res = valuePop(ctxt);
13833:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834:                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835:                         }
13836: 
13837:                         /*
13838:                          * Cleanup
13839:                          */
13840:                         if (res != NULL) {
13841: 			    xmlXPathReleaseObject(ctxt->context, res);
13842: 			}
13843:                         if (ctxt->value == tmp) {
13844:                             valuePop(ctxt);
13845: 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13846: 			    /*
13847: 			    * Don't free the temporary nodeset
13848: 			    * in order to avoid massive recreation inside this
13849: 			    * loop.
13850: 			    */
13851:                         } else
13852: 			    tmp = NULL;
13853:                         ctxt->context->node = NULL;
13854:                     }
13855: 		    if (tmp != NULL)
13856: 			xmlXPathReleaseObject(ctxt->context, tmp);
13857:                     /*
13858:                      * The result is used as the new evaluation set.
13859:                      */
13860: 		    xmlXPathReleaseObject(ctxt->context, obj);
13861:                     ctxt->context->node = NULL;
13862:                     ctxt->context->contextSize = -1;
13863:                     ctxt->context->proximityPosition = -1;
13864: 		    /* may want to move this past the '}' later */
13865: 		    ctxt->context->doc = oldDoc;
13866: 		    valuePush(ctxt,
13867: 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13868:                 }
13869:                 ctxt->context->node = oldnode;
13870:                 return (total);
13871:             }
13872:         case XPATH_OP_SORT:
13873:             if (op->ch1 != -1)
13874:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13875: 	    CHECK_ERROR0;
13876:             if ((ctxt->value != NULL) &&
13877:                 (ctxt->value->type == XPATH_NODESET) &&
13878:                 (ctxt->value->nodesetval != NULL) &&
13879: 		(ctxt->value->nodesetval->nodeNr > 1))
13880: 	    {
13881:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13882: 	    }
13883:             return (total);
13884: #ifdef LIBXML_XPTR_ENABLED
13885:         case XPATH_OP_RANGETO:{
13886:                 xmlXPathObjectPtr range;
13887:                 xmlXPathObjectPtr res, obj;
13888:                 xmlXPathObjectPtr tmp;
13889:                 xmlLocationSetPtr newlocset = NULL;
13890: 		    xmlLocationSetPtr oldlocset;
13891:                 xmlNodeSetPtr oldset;
13892:                 int i, j;
13893: 
13894:                 if (op->ch1 != -1)
13895:                     total +=
13896:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897:                 if (op->ch2 == -1)
13898:                     return (total);
13899: 
13900:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13901:                     /*
13902:                      * Extract the old locset, and then evaluate the result of the
13903:                      * expression for all the element in the locset. use it to grow
13904:                      * up a new locset.
13905:                      */
13906:                     CHECK_TYPE0(XPATH_LOCATIONSET);
13907:                     obj = valuePop(ctxt);
13908:                     oldlocset = obj->user;
13909: 
13910:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911: 		        ctxt->context->node = NULL;
13912:                         ctxt->context->contextSize = 0;
13913:                         ctxt->context->proximityPosition = 0;
13914:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915:                         res = valuePop(ctxt);
13916:                         if (res != NULL) {
13917: 			    xmlXPathReleaseObject(ctxt->context, res);
13918: 			}
13919:                         valuePush(ctxt, obj);
13920:                         CHECK_ERROR0;
13921:                         return (total);
13922:                     }
13923:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13924: 
13925:                     for (i = 0; i < oldlocset->locNr; i++) {
13926:                         /*
13927:                          * Run the evaluation with a node list made of a
13928:                          * single item in the nodelocset.
13929:                          */
13930:                         ctxt->context->node = oldlocset->locTab[i]->user;
13931:                         ctxt->context->contextSize = oldlocset->locNr;
13932:                         ctxt->context->proximityPosition = i + 1;
13933: 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934: 			    ctxt->context->node);
13935:                         valuePush(ctxt, tmp);
13936: 
13937:                         if (op->ch2 != -1)
13938:                             total +=
13939:                                 xmlXPathCompOpEval(ctxt,
13940:                                                    &comp->steps[op->ch2]);
13941: 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13942: 			    xmlXPathFreeObject(obj);
13943: 			    return(0);
13944: 			}
13945: 
13946:                         res = valuePop(ctxt);
13947: 			if (res->type == XPATH_LOCATIONSET) {
13948: 			    xmlLocationSetPtr rloc =
13949: 			        (xmlLocationSetPtr)res->user;
13950: 			    for (j=0; j<rloc->locNr; j++) {
13951: 			        range = xmlXPtrNewRange(
13952: 				  oldlocset->locTab[i]->user,
13953: 				  oldlocset->locTab[i]->index,
13954: 				  rloc->locTab[j]->user2,
13955: 				  rloc->locTab[j]->index2);
13956: 				if (range != NULL) {
13957: 				    xmlXPtrLocationSetAdd(newlocset, range);
13958: 				}
13959: 			    }
13960: 			} else {
13961: 			    range = xmlXPtrNewRangeNodeObject(
13962: 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13963:                             if (range != NULL) {
13964:                                 xmlXPtrLocationSetAdd(newlocset,range);
13965: 			    }
13966:                         }
13967: 
13968:                         /*
13969:                          * Cleanup
13970:                          */
13971:                         if (res != NULL) {
13972: 			    xmlXPathReleaseObject(ctxt->context, res);
13973: 			}
13974:                         if (ctxt->value == tmp) {
13975:                             res = valuePop(ctxt);
13976: 			    xmlXPathReleaseObject(ctxt->context, res);
13977:                         }
13978: 
13979:                         ctxt->context->node = NULL;
13980:                     }
13981: 		} else {	/* Not a location set */
13982:                     CHECK_TYPE0(XPATH_NODESET);
13983:                     obj = valuePop(ctxt);
13984:                     oldset = obj->nodesetval;
13985:                     ctxt->context->node = NULL;
13986: 
13987:                     newlocset = xmlXPtrLocationSetCreate(NULL);
13988: 
13989:                     if (oldset != NULL) {
13990:                         for (i = 0; i < oldset->nodeNr; i++) {
13991:                             /*
13992:                              * Run the evaluation with a node list made of a single item
13993:                              * in the nodeset.
13994:                              */
13995:                             ctxt->context->node = oldset->nodeTab[i];
13996: 			    /*
13997: 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13998: 			    */
13999: 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000: 				ctxt->context->node);
14001:                             valuePush(ctxt, tmp);
14002: 
14003:                             if (op->ch2 != -1)
14004:                                 total +=
14005:                                     xmlXPathCompOpEval(ctxt,
14006:                                                    &comp->steps[op->ch2]);
14007: 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14008: 				xmlXPathFreeObject(obj);
14009: 				return(0);
14010: 			    }
14011: 
14012:                             res = valuePop(ctxt);
14013:                             range =
14014:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015:                                                       res);
14016:                             if (range != NULL) {
14017:                                 xmlXPtrLocationSetAdd(newlocset, range);
14018:                             }
14019: 
14020:                             /*
14021:                              * Cleanup
14022:                              */
14023:                             if (res != NULL) {
14024: 				xmlXPathReleaseObject(ctxt->context, res);
14025: 			    }
14026:                             if (ctxt->value == tmp) {
14027:                                 res = valuePop(ctxt);
14028: 				xmlXPathReleaseObject(ctxt->context, res);
14029:                             }
14030: 
14031:                             ctxt->context->node = NULL;
14032:                         }
14033:                     }
14034:                 }
14035: 
14036:                 /*
14037:                  * The result is used as the new evaluation set.
14038:                  */
14039: 		xmlXPathReleaseObject(ctxt->context, obj);
14040:                 ctxt->context->node = NULL;
14041:                 ctxt->context->contextSize = -1;
14042:                 ctxt->context->proximityPosition = -1;
14043:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14044:                 return (total);
14045:             }
14046: #endif /* LIBXML_XPTR_ENABLED */
14047:     }
14048:     xmlGenericError(xmlGenericErrorContext,
14049:                     "XPath: unknown precompiled operation %d\n", op->op);
14050:     ctxt->error = XPATH_INVALID_OPERAND;
14051:     return (total);
14052: }
14053: 
14054: /**
14055:  * xmlXPathCompOpEvalToBoolean:
14056:  * @ctxt:  the XPath parser context
14057:  *
14058:  * Evaluates if the expression evaluates to true.
14059:  *
14060:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061:  */
14062: static int
14063: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064: 			    xmlXPathStepOpPtr op,
14065: 			    int isPredicate)
14066: {
14067:     xmlXPathObjectPtr resObj = NULL;
14068: 
14069: start:
14070:     /* comp = ctxt->comp; */
14071:     switch (op->op) {
14072:         case XPATH_OP_END:
14073:             return (0);
14074: 	case XPATH_OP_VALUE:
14075: 	    resObj = (xmlXPathObjectPtr) op->value4;
14076: 	    if (isPredicate)
14077: 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078: 	    return(xmlXPathCastToBoolean(resObj));
14079: 	case XPATH_OP_SORT:
14080: 	    /*
14081: 	    * We don't need sorting for boolean results. Skip this one.
14082: 	    */
14083:             if (op->ch1 != -1) {
14084: 		op = &ctxt->comp->steps[op->ch1];
14085: 		goto start;
14086: 	    }
14087: 	    return(0);
14088: 	case XPATH_OP_COLLECT:
14089: 	    if (op->ch1 == -1)
14090: 		return(0);
14091: 
14092:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14094: 		return(-1);
14095: 
14096:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14098: 		return(-1);
14099: 
14100: 	    resObj = valuePop(ctxt);
14101: 	    if (resObj == NULL)
14102: 		return(-1);
14103: 	    break;
14104: 	default:
14105: 	    /*
14106: 	    * Fallback to call xmlXPathCompOpEval().
14107: 	    */
14108: 	    xmlXPathCompOpEval(ctxt, op);
14109: 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14110: 		return(-1);
14111: 
14112: 	    resObj = valuePop(ctxt);
14113: 	    if (resObj == NULL)
14114: 		return(-1);
14115: 	    break;
14116:     }
14117: 
14118:     if (resObj) {
14119: 	int res;
14120: 
14121: 	if (resObj->type == XPATH_BOOLEAN) {
14122: 	    res = resObj->boolval;
14123: 	} else if (isPredicate) {
14124: 	    /*
14125: 	    * For predicates a result of type "number" is handled
14126: 	    * differently:
14127: 	    * SPEC XPath 1.0:
14128: 	    * "If the result is a number, the result will be converted
14129: 	    *  to true if the number is equal to the context position
14130: 	    *  and will be converted to false otherwise;"
14131: 	    */
14132: 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14133: 	} else {
14134: 	    res = xmlXPathCastToBoolean(resObj);
14135: 	}
14136: 	xmlXPathReleaseObject(ctxt->context, resObj);
14137: 	return(res);
14138:     }
14139: 
14140:     return(0);
14141: }
14142: 
14143: #ifdef XPATH_STREAMING
14144: /**
14145:  * xmlXPathRunStreamEval:
14146:  * @ctxt:  the XPath parser context with the compiled expression
14147:  *
14148:  * Evaluate the Precompiled Streamable XPath expression in the given context.
14149:  */
14150: static int
14151: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152: 		      xmlXPathObjectPtr *resultSeq, int toBool)
14153: {
14154:     int max_depth, min_depth;
14155:     int from_root;
14156:     int ret, depth;
14157:     int eval_all_nodes;
14158:     xmlNodePtr cur = NULL, limit = NULL;
14159:     xmlStreamCtxtPtr patstream = NULL;
14160: 
14161:     int nb_nodes = 0;
14162: 
14163:     if ((ctxt == NULL) || (comp == NULL))
14164:         return(-1);
14165:     max_depth = xmlPatternMaxDepth(comp);
14166:     if (max_depth == -1)
14167:         return(-1);
14168:     if (max_depth == -2)
14169:         max_depth = 10000;
14170:     min_depth = xmlPatternMinDepth(comp);
14171:     if (min_depth == -1)
14172:         return(-1);
14173:     from_root = xmlPatternFromRoot(comp);
14174:     if (from_root < 0)
14175:         return(-1);
14176: #if 0
14177:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178: #endif
14179: 
14180:     if (! toBool) {
14181: 	if (resultSeq == NULL)
14182: 	    return(-1);
14183: 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184: 	if (*resultSeq == NULL)
14185: 	    return(-1);
14186:     }
14187: 
14188:     /*
14189:      * handle the special cases of "/" amd "." being matched
14190:      */
14191:     if (min_depth == 0) {
14192: 	if (from_root) {
14193: 	    /* Select "/" */
14194: 	    if (toBool)
14195: 		return(1);
14196: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197: 		(xmlNodePtr) ctxt->doc);
14198: 	} else {
14199: 	    /* Select "self::node()" */
14200: 	    if (toBool)
14201: 		return(1);
14202: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14203: 	}
14204:     }
14205:     if (max_depth == 0) {
14206: 	return(0);
14207:     }
14208: 
14209:     if (from_root) {
14210:         cur = (xmlNodePtr)ctxt->doc;
14211:     } else if (ctxt->node != NULL) {
14212:         switch (ctxt->node->type) {
14213:             case XML_ELEMENT_NODE:
14214:             case XML_DOCUMENT_NODE:
14215:             case XML_DOCUMENT_FRAG_NODE:
14216:             case XML_HTML_DOCUMENT_NODE:
14217: #ifdef LIBXML_DOCB_ENABLED
14218:             case XML_DOCB_DOCUMENT_NODE:
14219: #endif
14220: 	        cur = ctxt->node;
14221: 		break;
14222:             case XML_ATTRIBUTE_NODE:
14223:             case XML_TEXT_NODE:
14224:             case XML_CDATA_SECTION_NODE:
14225:             case XML_ENTITY_REF_NODE:
14226:             case XML_ENTITY_NODE:
14227:             case XML_PI_NODE:
14228:             case XML_COMMENT_NODE:
14229:             case XML_NOTATION_NODE:
14230:             case XML_DTD_NODE:
14231:             case XML_DOCUMENT_TYPE_NODE:
14232:             case XML_ELEMENT_DECL:
14233:             case XML_ATTRIBUTE_DECL:
14234:             case XML_ENTITY_DECL:
14235:             case XML_NAMESPACE_DECL:
14236:             case XML_XINCLUDE_START:
14237:             case XML_XINCLUDE_END:
14238: 		break;
14239: 	}
14240: 	limit = cur;
14241:     }
14242:     if (cur == NULL) {
14243:         return(0);
14244:     }
14245: 
14246:     patstream = xmlPatternGetStreamCtxt(comp);
14247:     if (patstream == NULL) {
14248: 	/*
14249: 	* QUESTION TODO: Is this an error?
14250: 	*/
14251: 	return(0);
14252:     }
14253: 
14254:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14255: 
14256:     if (from_root) {
14257: 	ret = xmlStreamPush(patstream, NULL, NULL);
14258: 	if (ret < 0) {
14259: 	} else if (ret == 1) {
14260: 	    if (toBool)
14261: 		goto return_1;
14262: 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14263: 	}
14264:     }
14265:     depth = 0;
14266:     goto scan_children;
14267: next_node:
14268:     do {
14269:         nb_nodes++;
14270: 
14271: 	switch (cur->type) {
14272: 	    case XML_ELEMENT_NODE:
14273: 	    case XML_TEXT_NODE:
14274: 	    case XML_CDATA_SECTION_NODE:
14275: 	    case XML_COMMENT_NODE:
14276: 	    case XML_PI_NODE:
14277: 		if (cur->type == XML_ELEMENT_NODE) {
14278: 		    ret = xmlStreamPush(patstream, cur->name,
14279: 				(cur->ns ? cur->ns->href : NULL));
14280: 		} else if (eval_all_nodes)
14281: 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282: 		else
14283: 		    break;
14284: 
14285: 		if (ret < 0) {
14286: 		    /* NOP. */
14287: 		} else if (ret == 1) {
14288: 		    if (toBool)
14289: 			goto return_1;
14290: 		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14291: 		}
14292: 		if ((cur->children == NULL) || (depth >= max_depth)) {
14293: 		    ret = xmlStreamPop(patstream);
14294: 		    while (cur->next != NULL) {
14295: 			cur = cur->next;
14296: 			if ((cur->type != XML_ENTITY_DECL) &&
14297: 			    (cur->type != XML_DTD_NODE))
14298: 			    goto next_node;
14299: 		    }
14300: 		}
14301: 	    default:
14302: 		break;
14303: 	}
14304: 
14305: scan_children:
14306: 	if ((cur->children != NULL) && (depth < max_depth)) {
14307: 	    /*
14308: 	     * Do not descend on entities declarations
14309: 	     */
14310: 	    if (cur->children->type != XML_ENTITY_DECL) {
14311: 		cur = cur->children;
14312: 		depth++;
14313: 		/*
14314: 		 * Skip DTDs
14315: 		 */
14316: 		if (cur->type != XML_DTD_NODE)
14317: 		    continue;
14318: 	    }
14319: 	}
14320: 
14321: 	if (cur == limit)
14322: 	    break;
14323: 
14324: 	while (cur->next != NULL) {
14325: 	    cur = cur->next;
14326: 	    if ((cur->type != XML_ENTITY_DECL) &&
14327: 		(cur->type != XML_DTD_NODE))
14328: 		goto next_node;
14329: 	}
14330: 
14331: 	do {
14332: 	    cur = cur->parent;
14333: 	    depth--;
14334: 	    if ((cur == NULL) || (cur == limit))
14335: 	        goto done;
14336: 	    if (cur->type == XML_ELEMENT_NODE) {
14337: 		ret = xmlStreamPop(patstream);
14338: 	    } else if ((eval_all_nodes) &&
14339: 		((cur->type == XML_TEXT_NODE) ||
14340: 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14341: 		 (cur->type == XML_COMMENT_NODE) ||
14342: 		 (cur->type == XML_PI_NODE)))
14343: 	    {
14344: 		ret = xmlStreamPop(patstream);
14345: 	    }
14346: 	    if (cur->next != NULL) {
14347: 		cur = cur->next;
14348: 		break;
14349: 	    }
14350: 	} while (cur != NULL);
14351: 
14352:     } while ((cur != NULL) && (depth >= 0));
14353: 
14354: done:
14355: 
14356: #if 0
14357:     printf("stream eval: checked %d nodes selected %d\n",
14358:            nb_nodes, retObj->nodesetval->nodeNr);
14359: #endif
14360: 
14361:     if (patstream)
14362: 	xmlFreeStreamCtxt(patstream);
14363:     return(0);
14364: 
14365: return_1:
14366:     if (patstream)
14367: 	xmlFreeStreamCtxt(patstream);
14368:     return(1);
14369: }
14370: #endif /* XPATH_STREAMING */
14371: 
14372: /**
14373:  * xmlXPathRunEval:
14374:  * @ctxt:  the XPath parser context with the compiled expression
14375:  * @toBool:  evaluate to a boolean result
14376:  *
14377:  * Evaluate the Precompiled XPath expression in the given context.
14378:  */
14379: static int
14380: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381: {
14382:     xmlXPathCompExprPtr comp;
14383: 
14384:     if ((ctxt == NULL) || (ctxt->comp == NULL))
14385: 	return(-1);
14386: 
14387:     if (ctxt->valueTab == NULL) {
14388: 	/* Allocate the value stack */
14389: 	ctxt->valueTab = (xmlXPathObjectPtr *)
14390: 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391: 	if (ctxt->valueTab == NULL) {
14392: 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14393: 	    xmlFree(ctxt);
14394: 	}
14395: 	ctxt->valueNr = 0;
14396: 	ctxt->valueMax = 10;
14397: 	ctxt->value = NULL;
14398:         ctxt->valueFrame = 0;
14399:     }
14400: #ifdef XPATH_STREAMING
14401:     if (ctxt->comp->stream) {
14402: 	int res;
14403: 
14404: 	if (toBool) {
14405: 	    /*
14406: 	    * Evaluation to boolean result.
14407: 	    */
14408: 	    res = xmlXPathRunStreamEval(ctxt->context,
14409: 		ctxt->comp->stream, NULL, 1);
14410: 	    if (res != -1)
14411: 		return(res);
14412: 	} else {
14413: 	    xmlXPathObjectPtr resObj = NULL;
14414: 
14415: 	    /*
14416: 	    * Evaluation to a sequence.
14417: 	    */
14418: 	    res = xmlXPathRunStreamEval(ctxt->context,
14419: 		ctxt->comp->stream, &resObj, 0);
14420: 
14421: 	    if ((res != -1) && (resObj != NULL)) {
14422: 		valuePush(ctxt, resObj);
14423: 		return(0);
14424: 	    }
14425: 	    if (resObj != NULL)
14426: 		xmlXPathReleaseObject(ctxt->context, resObj);
14427: 	}
14428: 	/*
14429: 	* QUESTION TODO: This falls back to normal XPath evaluation
14430: 	* if res == -1. Is this intended?
14431: 	*/
14432:     }
14433: #endif
14434:     comp = ctxt->comp;
14435:     if (comp->last < 0) {
14436: 	xmlGenericError(xmlGenericErrorContext,
14437: 	    "xmlXPathRunEval: last is less than zero\n");
14438: 	return(-1);
14439:     }
14440:     if (toBool)
14441: 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14442: 	    &comp->steps[comp->last], 0));
14443:     else
14444: 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445: 
14446:     return(0);
14447: }
14448: 
14449: /************************************************************************
14450:  *									*
14451:  *			Public interfaces				*
14452:  *									*
14453:  ************************************************************************/
14454: 
14455: /**
14456:  * xmlXPathEvalPredicate:
14457:  * @ctxt:  the XPath context
14458:  * @res:  the Predicate Expression evaluation result
14459:  *
14460:  * Evaluate a predicate result for the current node.
14461:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14462:  * the result to a boolean. If the result is a number, the result will
14463:  * be converted to true if the number is equal to the position of the
14464:  * context node in the context node list (as returned by the position
14465:  * function) and will be converted to false otherwise; if the result
14466:  * is not a number, then the result will be converted as if by a call
14467:  * to the boolean function.
14468:  *
14469:  * Returns 1 if predicate is true, 0 otherwise
14470:  */
14471: int
14472: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473:     if ((ctxt == NULL) || (res == NULL)) return(0);
14474:     switch (res->type) {
14475:         case XPATH_BOOLEAN:
14476: 	    return(res->boolval);
14477:         case XPATH_NUMBER:
14478: 	    return(res->floatval == ctxt->proximityPosition);
14479:         case XPATH_NODESET:
14480:         case XPATH_XSLT_TREE:
14481: 	    if (res->nodesetval == NULL)
14482: 		return(0);
14483: 	    return(res->nodesetval->nodeNr != 0);
14484:         case XPATH_STRING:
14485: 	    return((res->stringval != NULL) &&
14486: 	           (xmlStrlen(res->stringval) != 0));
14487:         default:
14488: 	    STRANGE
14489:     }
14490:     return(0);
14491: }
14492: 
14493: /**
14494:  * xmlXPathEvaluatePredicateResult:
14495:  * @ctxt:  the XPath Parser context
14496:  * @res:  the Predicate Expression evaluation result
14497:  *
14498:  * Evaluate a predicate result for the current node.
14499:  * A PredicateExpr is evaluated by evaluating the Expr and converting
14500:  * the result to a boolean. If the result is a number, the result will
14501:  * be converted to true if the number is equal to the position of the
14502:  * context node in the context node list (as returned by the position
14503:  * function) and will be converted to false otherwise; if the result
14504:  * is not a number, then the result will be converted as if by a call
14505:  * to the boolean function.
14506:  *
14507:  * Returns 1 if predicate is true, 0 otherwise
14508:  */
14509: int
14510: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511:                                 xmlXPathObjectPtr res) {
14512:     if ((ctxt == NULL) || (res == NULL)) return(0);
14513:     switch (res->type) {
14514:         case XPATH_BOOLEAN:
14515: 	    return(res->boolval);
14516:         case XPATH_NUMBER:
14517: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518: 	    return((res->floatval == ctxt->context->proximityPosition) &&
14519: 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14520: #else
14521: 	    return(res->floatval == ctxt->context->proximityPosition);
14522: #endif
14523:         case XPATH_NODESET:
14524:         case XPATH_XSLT_TREE:
14525: 	    if (res->nodesetval == NULL)
14526: 		return(0);
14527: 	    return(res->nodesetval->nodeNr != 0);
14528:         case XPATH_STRING:
14529: 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14530: #ifdef LIBXML_XPTR_ENABLED
14531: 	case XPATH_LOCATIONSET:{
14532: 	    xmlLocationSetPtr ptr = res->user;
14533: 	    if (ptr == NULL)
14534: 	        return(0);
14535: 	    return (ptr->locNr != 0);
14536: 	    }
14537: #endif
14538:         default:
14539: 	    STRANGE
14540:     }
14541:     return(0);
14542: }
14543: 
14544: #ifdef XPATH_STREAMING
14545: /**
14546:  * xmlXPathTryStreamCompile:
14547:  * @ctxt: an XPath context
14548:  * @str:  the XPath expression
14549:  *
14550:  * Try to compile the XPath expression as a streamable subset.
14551:  *
14552:  * Returns the compiled expression or NULL if failed to compile.
14553:  */
14554: static xmlXPathCompExprPtr
14555: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556:     /*
14557:      * Optimization: use streaming patterns when the XPath expression can
14558:      * be compiled to a stream lookup
14559:      */
14560:     xmlPatternPtr stream;
14561:     xmlXPathCompExprPtr comp;
14562:     xmlDictPtr dict = NULL;
14563:     const xmlChar **namespaces = NULL;
14564:     xmlNsPtr ns;
14565:     int i, j;
14566: 
14567:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568:         (!xmlStrchr(str, '@'))) {
14569: 	const xmlChar *tmp;
14570: 
14571: 	/*
14572: 	 * We don't try to handle expressions using the verbose axis
14573: 	 * specifiers ("::"), just the simplied form at this point.
14574: 	 * Additionally, if there is no list of namespaces available and
14575: 	 *  there's a ":" in the expression, indicating a prefixed QName,
14576: 	 *  then we won't try to compile either. xmlPatterncompile() needs
14577: 	 *  to have a list of namespaces at compilation time in order to
14578: 	 *  compile prefixed name tests.
14579: 	 */
14580: 	tmp = xmlStrchr(str, ':');
14581: 	if ((tmp != NULL) &&
14582: 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14583: 	    return(NULL);
14584: 
14585: 	if (ctxt != NULL) {
14586: 	    dict = ctxt->dict;
14587: 	    if (ctxt->nsNr > 0) {
14588: 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589: 		if (namespaces == NULL) {
14590: 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591: 		    return(NULL);
14592: 		}
14593: 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594: 		    ns = ctxt->namespaces[j];
14595: 		    namespaces[i++] = ns->href;
14596: 		    namespaces[i++] = ns->prefix;
14597: 		}
14598: 		namespaces[i++] = NULL;
14599: 		namespaces[i] = NULL;
14600: 	    }
14601: 	}
14602: 
14603: 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604: 			&namespaces[0]);
14605: 	if (namespaces != NULL) {
14606: 	    xmlFree((xmlChar **)namespaces);
14607: 	}
14608: 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609: 	    comp = xmlXPathNewCompExpr();
14610: 	    if (comp == NULL) {
14611: 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612: 		return(NULL);
14613: 	    }
14614: 	    comp->stream = stream;
14615: 	    comp->dict = dict;
14616: 	    if (comp->dict)
14617: 		xmlDictReference(comp->dict);
14618: 	    return(comp);
14619: 	}
14620: 	xmlFreePattern(stream);
14621:     }
14622:     return(NULL);
14623: }
14624: #endif /* XPATH_STREAMING */
14625: 
14626: static int
14627: xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628: {
14629:     if (expr == NULL)
14630: 	return(0);
14631:     do {
14632:         if ((*expr == '/') && (*(++expr) == '/'))
14633: 	    return(1);
14634:     } while (*expr++);
14635:     return(0);
14636: }
14637: static void
14638: xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639: {
14640:     /*
14641:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642:     * internal representation.
14643:     */
14644:     if (op->ch1 != -1) {
14645: 	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646: 	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647: 	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648: 	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649: 	{
14650: 	    /*
14651: 	    * This is a "child::foo"
14652: 	    */
14653: 	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14654: 
14655: 	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656: 		(prevop->ch1 != -1) &&
14657: 		((xmlXPathAxisVal) prevop->value ==
14658: 		    AXIS_DESCENDANT_OR_SELF) &&
14659: 		(prevop->ch2 == -1) &&
14660: 		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661: 		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662: 		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14663: 	    {
14664: 		/*
14665: 		* This is a "/descendant-or-self::node()" without predicates.
14666: 		* Eliminate it.
14667: 		*/
14668: 		op->ch1 = prevop->ch1;
14669: 		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14670: 	    }
14671: 	}
14672: 	if (op->ch1 != -1)
14673: 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674:     }
14675:     if (op->ch2 != -1)
14676: 	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677: }
14678: 
14679: /**
14680:  * xmlXPathCtxtCompile:
14681:  * @ctxt: an XPath context
14682:  * @str:  the XPath expression
14683:  *
14684:  * Compile an XPath expression
14685:  *
14686:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687:  *         the caller has to free the object.
14688:  */
14689: xmlXPathCompExprPtr
14690: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691:     xmlXPathParserContextPtr pctxt;
14692:     xmlXPathCompExprPtr comp;
14693: 
14694: #ifdef XPATH_STREAMING
14695:     comp = xmlXPathTryStreamCompile(ctxt, str);
14696:     if (comp != NULL)
14697:         return(comp);
14698: #endif
14699: 
14700:     xmlXPathInit();
14701: 
14702:     pctxt = xmlXPathNewParserContext(str, ctxt);
14703:     if (pctxt == NULL)
14704:         return NULL;
14705:     xmlXPathCompileExpr(pctxt, 1);
14706: 
14707:     if( pctxt->error != XPATH_EXPRESSION_OK )
14708:     {
14709:         xmlXPathFreeParserContext(pctxt);
14710:         return(NULL);
14711:     }
14712: 
14713:     if (*pctxt->cur != 0) {
14714: 	/*
14715: 	 * aleksey: in some cases this line prints *second* error message
14716: 	 * (see bug #78858) and probably this should be fixed.
14717: 	 * However, we are not sure that all error messages are printed
14718: 	 * out in other places. It's not critical so we leave it as-is for now
14719: 	 */
14720: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721: 	comp = NULL;
14722:     } else {
14723: 	comp = pctxt->comp;
14724: 	pctxt->comp = NULL;
14725:     }
14726:     xmlXPathFreeParserContext(pctxt);
14727: 
14728:     if (comp != NULL) {
14729: 	comp->expr = xmlStrdup(str);
14730: #ifdef DEBUG_EVAL_COUNTS
14731: 	comp->string = xmlStrdup(str);
14732: 	comp->nb = 0;
14733: #endif
14734: 	if ((comp->expr != NULL) &&
14735: 	    (comp->nbStep > 2) &&
14736: 	    (comp->last >= 0) &&
14737: 	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738: 	{
14739: 	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14740: 	}
14741:     }
14742:     return(comp);
14743: }
14744: 
14745: /**
14746:  * xmlXPathCompile:
14747:  * @str:  the XPath expression
14748:  *
14749:  * Compile an XPath expression
14750:  *
14751:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752:  *         the caller has to free the object.
14753:  */
14754: xmlXPathCompExprPtr
14755: xmlXPathCompile(const xmlChar *str) {
14756:     return(xmlXPathCtxtCompile(NULL, str));
14757: }
14758: 
14759: /**
14760:  * xmlXPathCompiledEvalInternal:
14761:  * @comp:  the compiled XPath expression
14762:  * @ctxt:  the XPath context
14763:  * @resObj: the resulting XPath object or NULL
14764:  * @toBool: 1 if only a boolean result is requested
14765:  *
14766:  * Evaluate the Precompiled XPath expression in the given context.
14767:  * The caller has to free @resObj.
14768:  *
14769:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770:  *         the caller has to free the object.
14771:  */
14772: static int
14773: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774: 			     xmlXPathContextPtr ctxt,
14775: 			     xmlXPathObjectPtr *resObj,
14776: 			     int toBool)
14777: {
14778:     xmlXPathParserContextPtr pctxt;
14779: #ifndef LIBXML_THREAD_ENABLED
14780:     static int reentance = 0;
14781: #endif
14782:     int res;
14783: 
14784:     CHECK_CTXT_NEG(ctxt)
14785: 
14786:     if (comp == NULL)
14787: 	return(-1);
14788:     xmlXPathInit();
14789: 
14790: #ifndef LIBXML_THREAD_ENABLED
14791:     reentance++;
14792:     if (reentance > 1)
14793: 	xmlXPathDisableOptimizer = 1;
14794: #endif
14795: 
14796: #ifdef DEBUG_EVAL_COUNTS
14797:     comp->nb++;
14798:     if ((comp->string != NULL) && (comp->nb > 100)) {
14799: 	fprintf(stderr, "100 x %s\n", comp->string);
14800: 	comp->nb = 0;
14801:     }
14802: #endif
14803:     pctxt = xmlXPathCompParserContext(comp, ctxt);
14804:     res = xmlXPathRunEval(pctxt, toBool);
14805: 
14806:     if (resObj) {
14807: 	if (pctxt->value == NULL) {
14808: 	    xmlGenericError(xmlGenericErrorContext,
14809: 		"xmlXPathCompiledEval: evaluation failed\n");
14810: 	    *resObj = NULL;
14811: 	} else {
14812: 	    *resObj = valuePop(pctxt);
14813: 	}
14814:     }
14815: 
14816:     /*
14817:     * Pop all remaining objects from the stack.
14818:     */
14819:     if (pctxt->valueNr > 0) {
14820: 	xmlXPathObjectPtr tmp;
14821: 	int stack = 0;
14822: 
14823: 	do {
14824: 	    tmp = valuePop(pctxt);
14825: 	    if (tmp != NULL) {
14826: 		stack++;
14827: 		xmlXPathReleaseObject(ctxt, tmp);
14828: 	    }
14829: 	} while (tmp != NULL);
14830: 	if ((stack != 0) &&
14831: 	    ((toBool) || ((resObj) && (*resObj))))
14832: 	{
14833: 	    xmlGenericError(xmlGenericErrorContext,
14834: 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14835: 		stack);
14836: 	}
14837:     }
14838: 
14839:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840: 	xmlXPathFreeObject(*resObj);
14841: 	*resObj = NULL;
14842:     }
14843:     pctxt->comp = NULL;
14844:     xmlXPathFreeParserContext(pctxt);
14845: #ifndef LIBXML_THREAD_ENABLED
14846:     reentance--;
14847: #endif
14848: 
14849:     return(res);
14850: }
14851: 
14852: /**
14853:  * xmlXPathCompiledEval:
14854:  * @comp:  the compiled XPath expression
14855:  * @ctx:  the XPath context
14856:  *
14857:  * Evaluate the Precompiled XPath expression in the given context.
14858:  *
14859:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860:  *         the caller has to free the object.
14861:  */
14862: xmlXPathObjectPtr
14863: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864: {
14865:     xmlXPathObjectPtr res = NULL;
14866: 
14867:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868:     return(res);
14869: }
14870: 
14871: /**
14872:  * xmlXPathCompiledEvalToBoolean:
14873:  * @comp:  the compiled XPath expression
14874:  * @ctxt:  the XPath context
14875:  *
14876:  * Applies the XPath boolean() function on the result of the given
14877:  * compiled expression.
14878:  *
14879:  * Returns 1 if the expression evaluated to true, 0 if to false and
14880:  *         -1 in API and internal errors.
14881:  */
14882: int
14883: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884: 			      xmlXPathContextPtr ctxt)
14885: {
14886:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887: }
14888: 
14889: /**
14890:  * xmlXPathEvalExpr:
14891:  * @ctxt:  the XPath Parser context
14892:  *
14893:  * Parse and evaluate an XPath expression in the given context,
14894:  * then push the result on the context stack
14895:  */
14896: void
14897: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898: #ifdef XPATH_STREAMING
14899:     xmlXPathCompExprPtr comp;
14900: #endif
14901: 
14902:     if (ctxt == NULL) return;
14903: 
14904: #ifdef XPATH_STREAMING
14905:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906:     if (comp != NULL) {
14907:         if (ctxt->comp != NULL)
14908: 	    xmlXPathFreeCompExpr(ctxt->comp);
14909:         ctxt->comp = comp;
14910: 	if (ctxt->cur != NULL)
14911: 	    while (*ctxt->cur != 0) ctxt->cur++;
14912:     } else
14913: #endif
14914:     {
14915: 	xmlXPathCompileExpr(ctxt, 1);
14916: 	/*
14917: 	* In this scenario the expression string will sit in ctxt->base.
14918: 	*/
14919: 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920: 	    (ctxt->comp != NULL) &&
14921: 	    (ctxt->base != NULL) &&
14922: 	    (ctxt->comp->nbStep > 2) &&
14923: 	    (ctxt->comp->last >= 0) &&
14924: 	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14925: 	{
14926: 	    xmlXPathRewriteDOSExpression(ctxt->comp,
14927: 		&ctxt->comp->steps[ctxt->comp->last]);
14928: 	}
14929:     }
14930:     CHECK_ERROR;
14931:     xmlXPathRunEval(ctxt, 0);
14932: }
14933: 
14934: /**
14935:  * xmlXPathEval:
14936:  * @str:  the XPath expression
14937:  * @ctx:  the XPath context
14938:  *
14939:  * Evaluate the XPath Location Path in the given context.
14940:  *
14941:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942:  *         the caller has to free the object.
14943:  */
14944: xmlXPathObjectPtr
14945: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946:     xmlXPathParserContextPtr ctxt;
14947:     xmlXPathObjectPtr res, tmp, init = NULL;
14948:     int stack = 0;
14949: 
14950:     CHECK_CTXT(ctx)
14951: 
14952:     xmlXPathInit();
14953: 
14954:     ctxt = xmlXPathNewParserContext(str, ctx);
14955:     if (ctxt == NULL)
14956:         return NULL;
14957:     xmlXPathEvalExpr(ctxt);
14958: 
14959:     if (ctxt->value == NULL) {
14960: 	xmlGenericError(xmlGenericErrorContext,
14961: 		"xmlXPathEval: evaluation failed\n");
14962: 	res = NULL;
14963:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964: #ifdef XPATH_STREAMING
14965:             && (ctxt->comp->stream == NULL)
14966: #endif
14967: 	      ) {
14968: 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969: 	res = NULL;
14970:     } else {
14971: 	res = valuePop(ctxt);
14972:     }
14973: 
14974:     do {
14975:         tmp = valuePop(ctxt);
14976: 	if (tmp != NULL) {
14977: 	    if (tmp != init)
14978: 		stack++;
14979: 	    xmlXPathReleaseObject(ctx, tmp);
14980:         }
14981:     } while (tmp != NULL);
14982:     if ((stack != 0) && (res != NULL)) {
14983: 	xmlGenericError(xmlGenericErrorContext,
14984: 		"xmlXPathEval: %d object left on the stack\n",
14985: 	        stack);
14986:     }
14987:     if (ctxt->error != XPATH_EXPRESSION_OK) {
14988: 	xmlXPathFreeObject(res);
14989: 	res = NULL;
14990:     }
14991: 
14992:     xmlXPathFreeParserContext(ctxt);
14993:     return(res);
14994: }
14995: 
14996: /**
14997:  * xmlXPathEvalExpression:
14998:  * @str:  the XPath expression
14999:  * @ctxt:  the XPath context
15000:  *
15001:  * Evaluate the XPath expression in the given context.
15002:  *
15003:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004:  *         the caller has to free the object.
15005:  */
15006: xmlXPathObjectPtr
15007: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008:     xmlXPathParserContextPtr pctxt;
15009:     xmlXPathObjectPtr res, tmp;
15010:     int stack = 0;
15011: 
15012:     CHECK_CTXT(ctxt)
15013: 
15014:     xmlXPathInit();
15015: 
15016:     pctxt = xmlXPathNewParserContext(str, ctxt);
15017:     if (pctxt == NULL)
15018:         return NULL;
15019:     xmlXPathEvalExpr(pctxt);
15020: 
15021:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022: 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023: 	res = NULL;
15024:     } else {
15025: 	res = valuePop(pctxt);
15026:     }
15027:     do {
15028:         tmp = valuePop(pctxt);
15029: 	if (tmp != NULL) {
15030: 	    xmlXPathReleaseObject(ctxt, tmp);
15031: 	    stack++;
15032: 	}
15033:     } while (tmp != NULL);
15034:     if ((stack != 0) && (res != NULL)) {
15035: 	xmlGenericError(xmlGenericErrorContext,
15036: 		"xmlXPathEvalExpression: %d object left on the stack\n",
15037: 	        stack);
15038:     }
15039:     xmlXPathFreeParserContext(pctxt);
15040:     return(res);
15041: }
15042: 
15043: /************************************************************************
15044:  *									*
15045:  *	Extra functions not pertaining to the XPath spec		*
15046:  *									*
15047:  ************************************************************************/
15048: /**
15049:  * xmlXPathEscapeUriFunction:
15050:  * @ctxt:  the XPath Parser context
15051:  * @nargs:  the number of arguments
15052:  *
15053:  * Implement the escape-uri() XPath function
15054:  *    string escape-uri(string $str, bool $escape-reserved)
15055:  *
15056:  * This function applies the URI escaping rules defined in section 2 of [RFC
15057:  * 2396] to the string supplied as $uri-part, which typically represents all
15058:  * or part of a URI. The effect of the function is to replace any special
15059:  * character in the string by an escape sequence of the form %xx%yy...,
15060:  * where xxyy... is the hexadecimal representation of the octets used to
15061:  * represent the character in UTF-8.
15062:  *
15063:  * The set of characters that are escaped depends on the setting of the
15064:  * boolean argument $escape-reserved.
15065:  *
15066:  * If $escape-reserved is true, all characters are escaped other than lower
15067:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071:  * A-F).
15072:  *
15073:  * If $escape-reserved is false, the behavior differs in that characters
15074:  * referred to in [RFC 2396] as reserved characters are not escaped. These
15075:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15076:  *
15077:  * [RFC 2396] does not define whether escaped URIs should use lower case or
15078:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079:  * compared using string comparison functions, this function must always use
15080:  * the upper-case letters A-F.
15081:  *
15082:  * Generally, $escape-reserved should be set to true when escaping a string
15083:  * that is to form a single part of a URI, and to false when escaping an
15084:  * entire URI or URI reference.
15085:  *
15086:  * In the case of non-ascii characters, the string is encoded according to
15087:  * utf-8 and then converted according to RFC 2396.
15088:  *
15089:  * Examples
15090:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094:  *
15095:  */
15096: static void
15097: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098:     xmlXPathObjectPtr str;
15099:     int escape_reserved;
15100:     xmlBufferPtr target;
15101:     xmlChar *cptr;
15102:     xmlChar escape[4];
15103: 
15104:     CHECK_ARITY(2);
15105: 
15106:     escape_reserved = xmlXPathPopBoolean(ctxt);
15107: 
15108:     CAST_TO_STRING;
15109:     str = valuePop(ctxt);
15110: 
15111:     target = xmlBufferCreate();
15112: 
15113:     escape[0] = '%';
15114:     escape[3] = 0;
15115: 
15116:     if (target) {
15117: 	for (cptr = str->stringval; *cptr; cptr++) {
15118: 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119: 		(*cptr >= 'a' && *cptr <= 'z') ||
15120: 		(*cptr >= '0' && *cptr <= '9') ||
15121: 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122: 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123: 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15124: 		(*cptr == '%' &&
15125: 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126: 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127: 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128: 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129: 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130: 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131: 		(!escape_reserved &&
15132: 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133: 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134: 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135: 		  *cptr == ','))) {
15136: 		xmlBufferAdd(target, cptr, 1);
15137: 	    } else {
15138: 		if ((*cptr >> 4) < 10)
15139: 		    escape[1] = '0' + (*cptr >> 4);
15140: 		else
15141: 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15142: 		if ((*cptr & 0xF) < 10)
15143: 		    escape[2] = '0' + (*cptr & 0xF);
15144: 		else
15145: 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15146: 
15147: 		xmlBufferAdd(target, &escape[0], 3);
15148: 	    }
15149: 	}
15150:     }
15151:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152: 	xmlBufferContent(target)));
15153:     xmlBufferFree(target);
15154:     xmlXPathReleaseObject(ctxt->context, str);
15155: }
15156: 
15157: /**
15158:  * xmlXPathRegisterAllFunctions:
15159:  * @ctxt:  the XPath context
15160:  *
15161:  * Registers all default XPath functions in this context
15162:  */
15163: void
15164: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165: {
15166:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167:                          xmlXPathBooleanFunction);
15168:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169:                          xmlXPathCeilingFunction);
15170:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171:                          xmlXPathCountFunction);
15172:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173:                          xmlXPathConcatFunction);
15174:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175:                          xmlXPathContainsFunction);
15176:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177:                          xmlXPathIdFunction);
15178:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179:                          xmlXPathFalseFunction);
15180:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181:                          xmlXPathFloorFunction);
15182:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183:                          xmlXPathLastFunction);
15184:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185:                          xmlXPathLangFunction);
15186:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187:                          xmlXPathLocalNameFunction);
15188:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189:                          xmlXPathNotFunction);
15190:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191:                          xmlXPathNameFunction);
15192:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193:                          xmlXPathNamespaceURIFunction);
15194:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195:                          xmlXPathNormalizeFunction);
15196:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197:                          xmlXPathNumberFunction);
15198:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199:                          xmlXPathPositionFunction);
15200:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201:                          xmlXPathRoundFunction);
15202:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203:                          xmlXPathStringFunction);
15204:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205:                          xmlXPathStringLengthFunction);
15206:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207:                          xmlXPathStartsWithFunction);
15208:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209:                          xmlXPathSubstringFunction);
15210:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211:                          xmlXPathSubstringBeforeFunction);
15212:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213:                          xmlXPathSubstringAfterFunction);
15214:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215:                          xmlXPathSumFunction);
15216:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217:                          xmlXPathTrueFunction);
15218:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219:                          xmlXPathTranslateFunction);
15220: 
15221:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222: 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223:                          xmlXPathEscapeUriFunction);
15224: }
15225: 
15226: #endif /* LIBXML_XPATH_ENABLED */
15227: #define bottom_xpath
15228: #include "elfgcchack.h"

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