aboutsummaryrefslogtreecommitdiff
path: root/gnu/services/avahi.scm
diff options
context:
space:
mode:
authorRicardo Wurmus <rekado@elephly.net>2023-12-28 00:44:38 +0100
committerRicardo Wurmus <rekado@elephly.net>2024-01-01 14:35:15 +0100
commit8b5768d5093d384d2154a759d3b5e99998a5e0f0 (patch)
tree51978e4bac3a674490a1c5f50d4ed78eeccc2c0b /gnu/services/avahi.scm
parentea6b9e91ff61f038d4b6e2120f8c981cf17a2af8 (diff)
downloadguix-8b5768d5093d384d2154a759d3b5e99998a5e0f0.tar.gz
guix-8b5768d5093d384d2154a759d3b5e99998a5e0f0.zip
gnu: r-terra: Update to 1.7-65.
* gnu/packages/cran.scm (r-terra): Update to 1.7-65. Change-Id: I4fbb281b56600d51e59c863e5cfba00005db91de
Diffstat (limited to 'gnu/services/avahi.scm')
0 files changed, 0 insertions, 0 deletions
+#include <signal.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include <libxml/hash.h>
+#ifdef LIBXML_XPTR_ENABLED
+#include <libxml/xpointer.h>
+#endif
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
+#include <libxml/xmlerror.h>
+#include <libxml/threads.h>
+#include <libxml/globals.h>
+#ifdef LIBXML_PATTERN_ENABLED
+#include <libxml/pattern.h>
+#endif
+
+#include "buf.h"
+
+#ifdef LIBXML_PATTERN_ENABLED
+#define XPATH_STREAMING
+#endif
+
+#define TODO \
+ xmlGenericError(xmlGenericErrorContext, \
+ "Unimplemented block at %s:%d\n", \
+ __FILE__, __LINE__);
+
+/**
+ * WITH_TIM_SORT:
+ *
+ * Use the Timsort algorithm provided in timsort.h to sort
+ * nodeset as this is a great improvement over the old Shell sort
+ * used in xmlXPathNodeSetSort()
+ */
+#define WITH_TIM_SORT
+
+/*
+* XP_OPTIMIZED_NON_ELEM_COMPARISON:
+* If defined, this will use xmlXPathCmpNodesExt() instead of
+* xmlXPathCmpNodes(). The new function is optimized comparison of
+* non-element nodes; actually it will speed up comparison only if
+* xmlXPathOrderDocElems() was called in order to index the elements of
+* a tree in document order; Libxslt does such an indexing, thus it will
+* benefit from this optimization.
+*/
+#define XP_OPTIMIZED_NON_ELEM_COMPARISON
+
+/*
+* XP_OPTIMIZED_FILTER_FIRST:
+* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
+* in a way, that it stop evaluation at the first node.
+*/
+#define XP_OPTIMIZED_FILTER_FIRST
+
+/*
+* XP_DEBUG_OBJ_USAGE:
+* Internal flag to enable tracking of how much XPath objects have been
+* created.
+*/
+/* #define XP_DEBUG_OBJ_USAGE */
+
+/*
+ * XPATH_MAX_STEPS:
+ * when compiling an XPath expression we arbitrary limit the maximum
+ * number of step operation in the compiled expression. 1000000 is
+ * an insanely large value which should never be reached under normal
+ * circumstances
+ */
+#define XPATH_MAX_STEPS 1000000
+
+/*
+ * XPATH_MAX_STACK_DEPTH:
+ * when evaluating an XPath expression we arbitrary limit the maximum
+ * number of object allowed to be pushed on the stack. 1000000 is
+ * an insanely large value which should never be reached under normal
+ * circumstances
+ */
+#define XPATH_MAX_STACK_DEPTH 1000000
+
+/*
+ * XPATH_MAX_NODESET_LENGTH:
+ * when evaluating an XPath expression nodesets are created and we
+ * arbitrary limit the maximum length of those node set. 10000000 is
+ * an insanely large value which should never be reached under normal
+ * circumstances, one would first need to construct an in memory tree
+ * with more than 10 millions nodes.
+ */
+#define XPATH_MAX_NODESET_LENGTH 10000000
+
+/*
+ * TODO:
+ * There are a few spots where some tests are done which depend upon ascii
+ * data. These should be enhanced for full UTF8 support (see particularly
+ * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
+ */
+
+#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
+/**
+ * xmlXPathCmpNodesExt:
+ * @node1: the first node
+ * @node2: the second node
+ *
+ * Compare two nodes w.r.t document order.
+ * This one is optimized for handling of non-element nodes.
+ *
+ * Returns -2 in case of error 1 if first point < second point, 0 if
+ * it's the same node, -1 otherwise
+ */
+static int
+xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
+ int depth1, depth2;
+ int misc = 0, precedence1 = 0, precedence2 = 0;
+ xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
+ xmlNodePtr cur, root;
+ ptrdiff_t l1, l2;
+
+ if ((node1 == NULL) || (node2 == NULL))
+ return(-2);
+
+ if (node1 == node2)
+ return(0);
+
+ /*
+ * a couple of optimizations which will avoid computations in most cases
+ */
+ switch (node1->type) {
+ case XML_ELEMENT_NODE:
+ if (node2->type == XML_ELEMENT_NODE) {
+ if ((0 > (ptrdiff_t) node1->content) &&
+ (0 > (ptrdiff_t) node2->content) &&
+ (node1->doc == node2->doc))
+ {
+ l1 = -((ptrdiff_t) node1->content);
+ l2 = -((ptrdiff_t) node2->content);
+ if (l1 < l2)
+ return(1);
+ if (l1 > l2)
+ return(-1);
+ } else
+ goto turtle_comparison;
+ }
+ break;
+ case XML_ATTRIBUTE_NODE:
+ precedence1 = 1; /* element is owner */
+ miscNode1 = node1;
+ node1 = node1->parent;
+ misc = 1;
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE: {
+ miscNode1 = node1;
+ /*
+ * Find nearest element node.
+ */
+ if (node1->prev != NULL) {
+ do {
+ node1 = node1->prev;
+ if (node1->type == XML_ELEMENT_NODE) {
+ precedence1 = 3; /* element in prev-sibl axis */
+ break;
+ }
+ if (node1->prev == NULL) {
+ precedence1 = 2; /* element is parent */
+ /*
+ * URGENT TODO: Are there any cases, where the
+ * parent of such a node is not an element node?
+ */
+ node1 = node1->parent;
+ break;
+ }
+ } while (1);
+ } else {
+ precedence1 = 2; /* element is parent */
+ node1 = node1->parent;
+ }
+ if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
+ (0 <= (ptrdiff_t) node1->content)) {
+ /*
+ * Fallback for whatever case.
+ */
+ node1 = miscNode1;
+ precedence1 = 0;
+ } else
+ misc = 1;
+ }
+ break;
+ case XML_NAMESPACE_DECL:
+ /*
+ * TODO: why do we return 1 for namespace nodes?
+ */
+ return(1);
+ default:
+ break;
+ }
+ switch (node2->type) {
+ case XML_ELEMENT_NODE:
+ break;
+ case XML_ATTRIBUTE_NODE:
+ precedence2 = 1; /* element is owner */
+ miscNode2 = node2;
+ node2 = node2->parent;
+ misc = 1;
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE: {
+ miscNode2 = node2;
+ if (node2->prev != NULL) {
+ do {
+ node2 = node2->prev;
+ if (node2->type == XML_ELEMENT_NODE) {
+ precedence2 = 3; /* element in prev-sibl axis */
+ break;
+ }
+ if (node2->prev == NULL) {
+ precedence2 = 2; /* element is parent */
+ node2 = node2->parent;
+ break;
+ }
+ } while (1);
+ } else {
+ precedence2 = 2; /* element is parent */
+ node2 = node2->parent;
+ }
+ if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
+ (0 <= (ptrdiff_t) node2->content))
+ {
+ node2 = miscNode2;
+ precedence2 = 0;
+ } else
+ misc = 1;
+ }
+ break;
+ case XML_NAMESPACE_DECL:
+ return(1);
+ default:
+ break;
+ }
+ if (misc) {
+ if (node1 == node2) {
+ if (precedence1 == precedence2) {
+ /*
+ * The ugly case; but normally there aren't many
+ * adjacent non-element nodes around.
+ */
+ cur = miscNode2->prev;
+ while (cur != NULL) {
+ if (cur == miscNode1)
+ return(1);
+ if (cur->type == XML_ELEMENT_NODE)
+ return(-1);
+ cur = cur->prev;
+ }
+ return (-1);
+ } else {
+ /*
+ * Evaluate based on higher precedence wrt to the element.
+ * TODO: This assumes attributes are sorted before content.
+ * Is this 100% correct?
+ */
+ if (precedence1 < precedence2)
+ return(1);
+ else
+ return(-1);
+ }
+ }
+ /*
+ * Special case: One of the helper-elements is contained by the other.
+ * <foo>
+ * <node2>
+ * <node1>Text-1(precedence1 == 2)</node1>
+ * </node2>
+ * Text-6(precedence2 == 3)
+ * </foo>
+ */
+ if ((precedence2 == 3) && (precedence1 > 1)) {
+ cur = node1->parent;
+ while (cur) {
+ if (cur == node2)
+ return(1);
+ cur = cur->parent;
+ }
+ }
+ if ((precedence1 == 3) && (precedence2 > 1)) {
+ cur = node2->parent;
+ while (cur) {
+ if (cur == node1)
+ return(-1);
+ cur = cur->parent;
+ }
+ }
+ }
+
+ /*
+ * Speedup using document order if available.
+ */
+ if ((node1->type == XML_ELEMENT_NODE) &&
+ (node2->type == XML_ELEMENT_NODE) &&
+ (0 > (ptrdiff_t) node1->content) &&
+ (0 > (ptrdiff_t) node2->content) &&
+ (node1->doc == node2->doc)) {
+
+ l1 = -((ptrdiff_t) node1->content);
+ l2 = -((ptrdiff_t) node2->content);
+ if (l1 < l2)
+ return(1);
+ if (l1 > l2)
+ return(-1);
+ }
+
+turtle_comparison:
+
+ if (node1 == node2->prev)
+ return(1);
+ if (node1 == node2->next)
+ return(-1);
+ /*
+ * compute depth to root
+ */
+ for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
+ if (cur->parent == node1)
+ return(1);
+ depth2++;
+ }
+ root = cur;
+ for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
+ if (cur->parent == node2)
+ return(-1);
+ depth1++;
+ }
+ /*
+ * Distinct document (or distinct entities :-( ) case.
+ */
+ if (root != cur) {
+ return(-2);
+ }
+ /*
+ * get the nearest common ancestor.
+ */
+ while (depth1 > depth2) {
+ depth1--;
+ node1 = node1->parent;
+ }
+ while (depth2 > depth1) {
+ depth2--;
+ node2 = node2->parent;
+ }
+ while (node1->parent != node2->parent) {
+ node1 = node1->parent;
+ node2 = node2->parent;
+ /* should not happen but just in case ... */
+ if ((node1 == NULL) || (node2 == NULL))
+ return(-2);
+ }
+ /*
+ * Find who's first.
+ */
+ if (node1 == node2->prev)
+ return(1);
+ if (node1 == node2->next)
+ return(-1);
+ /*
+ * Speedup using document order if available.
+ */
+ if ((node1->type == XML_ELEMENT_NODE) &&
+ (node2->type == XML_ELEMENT_NODE) &&
+ (0 > (ptrdiff_t) node1->content) &&
+ (0 > (ptrdiff_t) node2->content) &&
+ (node1->doc == node2->doc)) {
+
+ l1 = -((ptrdiff_t) node1->content);
+ l2 = -((ptrdiff_t) node2->content);
+ if (l1 < l2)
+ return(1);
+ if (l1 > l2)
+ return(-1);
+ }
+
+ for (cur = node1->next;cur != NULL;cur = cur->next)
+ if (cur == node2)
+ return(1);
+ return(-1); /* assume there is no sibling list corruption */
+}
+#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
+
+/*
+ * Wrapper for the Timsort algorithm from timsort.h
+ */
+#ifdef WITH_TIM_SORT
+#define SORT_NAME libxml_domnode
+#define SORT_TYPE xmlNodePtr
+/**
+ * wrap_cmp:
+ * @x: a node
+ * @y: another node
+ *
+ * Comparison function for the Timsort implementation
+ *
+ * Returns -2 in case of error -1 if first point < second point, 0 if
+ * it's the same node, +1 otherwise
+ */
+static
+int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
+#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
+ static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
+ {
+ int res = xmlXPathCmpNodesExt(x, y);
+ return res == -2 ? res : -res;
+ }
+#else
+ static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
+ {
+ int res = xmlXPathCmpNodes(x, y);
+ return res == -2 ? res : -res;
+ }
+#endif
+#define SORT_CMP(x, y) (wrap_cmp(x, y))
+#include "timsort.h"
+#endif /* WITH_TIM_SORT */
+
+#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
+
+/************************************************************************
+ * *
+ * Floating point stuff *
+ * *
+ ************************************************************************/
+
+#ifndef INFINITY
+#define INFINITY (DBL_MAX * DBL_MAX)
+#endif
+
+#ifndef NAN
+#define NAN (INFINITY / INFINITY)
+#endif
+
+double xmlXPathNAN;
+double xmlXPathPINF;
+double xmlXPathNINF;
+
+/**
+ * xmlXPathInit:
+ *
+ * Initialize the XPath environment
+ */
+void
+xmlXPathInit(void) {
+ xmlXPathNAN = NAN;
+ xmlXPathPINF = INFINITY;
+ xmlXPathNINF = -INFINITY;
+}
+
+/**
+ * xmlXPathIsNaN:
+ * @val: a double value
+ *
+ * Returns 1 if the value is a NaN, 0 otherwise
+ */
+int
+xmlXPathIsNaN(double val) {
+#ifdef isnan
+ return isnan(val);
+#else
+ return !(val == val);
+#endif
+}
+
+/**
+ * xmlXPathIsInf:
+ * @val: a double value
+ *
+ * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
+ */
+int
+xmlXPathIsInf(double val) {
+#ifdef isinf
+ return isinf(val) ? (val > 0 ? 1 : -1) : 0;
+#else
+ if (val >= INFINITY)
+ return 1;
+ if (val <= -INFINITY)
+ return -1;
+ return 0;
+#endif
+}
+
+#endif /* SCHEMAS or XPATH */
+
+#ifdef LIBXML_XPATH_ENABLED
+
+/*
+ * TODO: when compatibility allows remove all "fake node libxslt" strings
+ * the test should just be name[0] = ' '
+ */
+#ifdef DEBUG_XPATH_EXPRESSION
+#define DEBUG_STEP
+#define DEBUG_EXPR
+#define DEBUG_EVAL_COUNTS
+#endif
+
+static xmlNs xmlXPathXMLNamespaceStruct = {
+ NULL,
+ XML_NAMESPACE_DECL,
+ XML_XML_NAMESPACE,
+ BAD_CAST "xml",
+ NULL,
+ NULL
+};
+static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
+#ifndef LIBXML_THREAD_ENABLED
+/*
+ * Optimizer is disabled only when threaded apps are detected while
+ * the library ain't compiled for thread safety.
+ */
+static int xmlXPathDisableOptimizer = 0;
+#endif
+
+/************************************************************************
+ * *
+ * Error handling routines *
+ * *
+ ************************************************************************/
+
+/**
+ * XP_ERRORNULL:
+ * @X: the error code
+ *
+ * Macro to raise an XPath error and return NULL.
+ */
+#define XP_ERRORNULL(X) \
+ { xmlXPathErr(ctxt, X); return(NULL); }
+
+/*
+ * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
+ */
+static const char *xmlXPathErrorMessages[] = {
+ "Ok\n",
+ "Number encoding\n",
+ "Unfinished literal\n",
+ "Start of literal\n",
+ "Expected $ for variable reference\n",
+ "Undefined variable\n",
+ "Invalid predicate\n",
+ "Invalid expression\n",
+ "Missing closing curly brace\n",
+ "Unregistered function\n",
+ "Invalid operand\n",
+ "Invalid type\n",
+ "Invalid number of arguments\n",
+ "Invalid context size\n",
+ "Invalid context position\n",
+ "Memory allocation error\n",
+ "Syntax error\n",
+ "Resource error\n",
+ "Sub resource error\n",
+ "Undefined namespace prefix\n",
+ "Encoding error\n",
+ "Char out of XML range\n",
+ "Invalid or incomplete context\n",
+ "Stack usage error\n",
+ "Forbidden variable\n",
+ "Operation limit exceeded\n",
+ "Recursion limit exceeded\n",
+ "?? Unknown error ??\n" /* Must be last in the list! */
+};
+#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
+ sizeof(xmlXPathErrorMessages[0])) - 1)
+/**
+ * xmlXPathErrMemory:
+ * @ctxt: an XPath context
+ * @extra: extra informations
+ *
+ * Handle a redefinition of attribute error
+ */
+static void
+xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
+{
+ if (ctxt != NULL) {
+ xmlResetError(&ctxt->lastError);
+ if (extra) {
+ xmlChar buf[200];
+
+ xmlStrPrintf(buf, 200,
+ "Memory allocation failed : %s\n",
+ extra);
+ ctxt->lastError.message = (char *) xmlStrdup(buf);
+ } else {
+ ctxt->lastError.message = (char *)
+ xmlStrdup(BAD_CAST "Memory allocation failed\n");
+ }
+ ctxt->lastError.domain = XML_FROM_XPATH;
+ ctxt->lastError.code = XML_ERR_NO_MEMORY;
+ if (ctxt->error != NULL)
+ ctxt->error(ctxt->userData, &ctxt->lastError);
+ } else {
+ if (extra)
+ __xmlRaiseError(NULL, NULL, NULL,
+ NULL, NULL, XML_FROM_XPATH,
+ XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
+ extra, NULL, NULL, 0, 0,
+ "Memory allocation failed : %s\n", extra);
+ else
+ __xmlRaiseError(NULL, NULL, NULL,
+ NULL, NULL, XML_FROM_XPATH,
+ XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
+ NULL, NULL, NULL, 0, 0,
+ "Memory allocation failed\n");
+ }
+}
+
+/**
+ * xmlXPathPErrMemory:
+ * @ctxt: an XPath parser context
+ * @extra: extra informations
+ *
+ * Handle a redefinition of attribute error
+ */
+static void
+xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
+{
+ if (ctxt == NULL)
+ xmlXPathErrMemory(NULL, extra);
+ else {
+ ctxt->error = XPATH_MEMORY_ERROR;
+ xmlXPathErrMemory(ctxt->context, extra);
+ }
+}
+
+/**
+ * xmlXPathErr:
+ * @ctxt: a XPath parser context
+ * @error: the error code
+ *
+ * Handle an XPath error
+ */
+void
+xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
+{
+ if ((error < 0) || (error > MAXERRNO))
+ error = MAXERRNO;
+ if (ctxt == NULL) {
+ __xmlRaiseError(NULL, NULL, NULL,
+ NULL, NULL, XML_FROM_XPATH,
+ error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
+ XML_ERR_ERROR, NULL, 0,
+ NULL, NULL, NULL, 0, 0,
+ "%s", xmlXPathErrorMessages[error]);
+ return;
+ }
+ ctxt->error = error;
+ if (ctxt->context == NULL) {
+ __xmlRaiseError(NULL, NULL, NULL,
+ NULL, NULL, XML_FROM_XPATH,
+ error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
+ XML_ERR_ERROR, NULL, 0,
+ (const char *) ctxt->base, NULL, NULL,
+ ctxt->cur - ctxt->base, 0,
+ "%s", xmlXPathErrorMessages[error]);
+ return;
+ }
+
+ /* cleanup current last error */
+ xmlResetError(&ctxt->context->lastError);
+
+ ctxt->context->lastError.domain = XML_FROM_XPATH;
+ ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
+ XPATH_EXPRESSION_OK;
+ ctxt->context->lastError.level = XML_ERR_ERROR;
+ ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
+ ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
+ ctxt->context->lastError.node = ctxt->context->debugNode;
+ if (ctxt->context->error != NULL) {
+ ctxt->context->error(ctxt->context->userData,
+ &ctxt->context->lastError);
+ } else {
+ __xmlRaiseError(NULL, NULL, NULL,
+ NULL, ctxt->context->debugNode, XML_FROM_XPATH,
+ error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
+ XML_ERR_ERROR, NULL, 0,
+ (const char *) ctxt->base, NULL, NULL,
+ ctxt->cur - ctxt->base, 0,
+ "%s", xmlXPathErrorMessages[error]);
+ }
+
+}
+
+/**
+ * xmlXPatherror:
+ * @ctxt: the XPath Parser context
+ * @file: the file name
+ * @line: the line number
+ * @no: the error number
+ *
+ * Formats an error message.
+ */
+void
+xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
+ int line ATTRIBUTE_UNUSED, int no) {
+ xmlXPathErr(ctxt, no);
+}
+
+/**
+ * xmlXPathCheckOpLimit:
+ * @ctxt: the XPath Parser context
+ * @opCount: the number of operations to be added
+ *
+ * Adds opCount to the running total of operations and returns -1 if the
+ * operation limit is exceeded. Returns 0 otherwise.
+ */
+static int
+xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
+ xmlXPathContextPtr xpctxt = ctxt->context;
+
+ if ((opCount > xpctxt->opLimit) ||
+ (xpctxt->opCount > xpctxt->opLimit - opCount)) {
+ xpctxt->opCount = xpctxt->opLimit;
+ xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
+ return(-1);
+ }
+
+ xpctxt->opCount += opCount;
+ return(0);
+}
+
+#define OP_LIMIT_EXCEEDED(ctxt, n) \
+ ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
+
+/************************************************************************
+ * *
+ * Utilities *
+ * *
+ ************************************************************************/
+
+/**
+ * xsltPointerList:
+ *
+ * Pointer-list for various purposes.
+ */
+typedef struct _xmlPointerList xmlPointerList;
+typedef xmlPointerList *xmlPointerListPtr;
+struct _xmlPointerList {
+ void **items;
+ int number;
+ int size;
+};
+/*
+* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
+* and here, we should make the functions public.
+*/
+static int
+xmlPointerListAddSize(xmlPointerListPtr list,
+ void *item,
+ int initialSize)
+{
+ if (list->items == NULL) {
+ if (initialSize <= 0)
+ initialSize = 1;
+ list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
+ if (list->items == NULL) {
+ xmlXPathErrMemory(NULL,
+ "xmlPointerListCreate: allocating item\n");
+ return(-1);
+ }
+ list->number = 0;
+ list->size = initialSize;
+ } else if (list->size <= list->number) {
+ if (list->size > 50000000) {
+ xmlXPathErrMemory(NULL,
+ "xmlPointerListAddSize: re-allocating item\n");
+ return(-1);
+ }
+ list->size *= 2;
+ list->items = (void **) xmlRealloc(list->items,
+ list->size * sizeof(void *));
+ if (list->items == NULL) {
+ xmlXPathErrMemory(NULL,
+ "xmlPointerListAddSize: re-allocating item\n");
+ list->size = 0;
+ return(-1);
+ }
+ }
+ list->items[list->number++] = item;
+ return(0);
+}
+
+/**
+ * xsltPointerListCreate:
+ *
+ * Creates an xsltPointerList structure.
+ *
+ * Returns a xsltPointerList structure or NULL in case of an error.
+ */
+static xmlPointerListPtr
+xmlPointerListCreate(int initialSize)
+{
+ xmlPointerListPtr ret;
+
+ ret = xmlMalloc(sizeof(xmlPointerList));
+ if (ret == NULL) {
+ xmlXPathErrMemory(NULL,
+ "xmlPointerListCreate: allocating item\n");
+ return (NULL);
+ }
+ memset(ret, 0, sizeof(xmlPointerList));
+ if (initialSize > 0) {
+ xmlPointerListAddSize(ret, NULL, initialSize);
+ ret->number = 0;
+ }
+ return (ret);
+}
+
+/**
+ * xsltPointerListFree:
+ *
+ * Frees the xsltPointerList structure. This does not free
+ * the content of the list.
+ */
+static void
+xmlPointerListFree(xmlPointerListPtr list)
+{
+ if (list == NULL)
+ return;
+ if (list->items != NULL)
+ xmlFree(list->items);
+ xmlFree(list);
+}
+
+/************************************************************************
+ * *
+ * Parser Types *
+ * *
+ ************************************************************************/
+
+/*
+ * Types are private:
+ */
+
+typedef enum {
+ XPATH_OP_END=0,
+ XPATH_OP_AND,
+ XPATH_OP_OR,
+ XPATH_OP_EQUAL,
+ XPATH_OP_CMP,
+ XPATH_OP_PLUS,
+ XPATH_OP_MULT,
+ XPATH_OP_UNION,
+ XPATH_OP_ROOT,
+ XPATH_OP_NODE,
+ XPATH_OP_COLLECT,
+ XPATH_OP_VALUE, /* 11 */
+ XPATH_OP_VARIABLE,
+ XPATH_OP_FUNCTION,
+ XPATH_OP_ARG,
+ XPATH_OP_PREDICATE,
+ XPATH_OP_FILTER, /* 16 */
+ XPATH_OP_SORT /* 17 */
+#ifdef LIBXML_XPTR_ENABLED
+ ,XPATH_OP_RANGETO
+#endif
+} xmlXPathOp;
+
+typedef enum {
+ AXIS_ANCESTOR = 1,
+ AXIS_ANCESTOR_OR_SELF,
+ AXIS_ATTRIBUTE,
+ AXIS_CHILD,
+ AXIS_DESCENDANT,
+ AXIS_DESCENDANT_OR_SELF,
+ AXIS_FOLLOWING,
+ AXIS_FOLLOWING_SIBLING,
+ AXIS_NAMESPACE,
+ AXIS_PARENT,
+ AXIS_PRECEDING,
+ AXIS_PRECEDING_SIBLING,
+ AXIS_SELF
+} xmlXPathAxisVal;
+
+typedef enum {
+ NODE_TEST_NONE = 0,
+ NODE_TEST_TYPE = 1,
+ NODE_TEST_PI = 2,
+ NODE_TEST_ALL = 3,
+ NODE_TEST_NS = 4,
+ NODE_TEST_NAME = 5
+} xmlXPathTestVal;
+
+typedef enum {
+ NODE_TYPE_NODE = 0,
+ NODE_TYPE_COMMENT = XML_COMMENT_NODE,
+ NODE_TYPE_TEXT = XML_TEXT_NODE,
+ NODE_TYPE_PI = XML_PI_NODE
+} xmlXPathTypeVal;
+
+typedef struct _xmlXPathStepOp xmlXPathStepOp;
+typedef xmlXPathStepOp *xmlXPathStepOpPtr;
+struct _xmlXPathStepOp {
+ xmlXPathOp op; /* The identifier of the operation */
+ int ch1; /* First child */
+ int ch2; /* Second child */
+ int value;
+ int value2;
+ int value3;
+ void *value4;
+ void *value5;
+ xmlXPathFunction cache;
+ void *cacheURI;
+};
+
+struct _xmlXPathCompExpr {
+ int nbStep; /* Number of steps in this expression */
+ int maxStep; /* Maximum number of steps allocated */
+ xmlXPathStepOp *steps; /* ops for computation of this expression */
+ int last; /* index of last step in expression */
+ xmlChar *expr; /* the expression being computed */
+ xmlDictPtr dict; /* the dictionary to use if any */
+#ifdef DEBUG_EVAL_COUNTS
+ int nb;
+ xmlChar *string;
+#endif
+#ifdef XPATH_STREAMING
+ xmlPatternPtr stream;
+#endif
+};
+
+/************************************************************************
+ * *
+ * Forward declarations *
+ * *
+ ************************************************************************/
+static void
+xmlXPathFreeValueTree(xmlNodeSetPtr obj);
+static void
+xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
+static int
+xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
+ xmlXPathStepOpPtr op, xmlNodePtr *first);
+static int
+xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
+ xmlXPathStepOpPtr op,
+ int isPredicate);
+static void
+xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
+
+/************************************************************************
+ * *
+ * Parser Type functions *
+ * *
+ ************************************************************************/
+
+/**
+ * xmlXPathNewCompExpr:
+ *
+ * Create a new Xpath component
+ *
+ * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
+ */
+static xmlXPathCompExprPtr
+xmlXPathNewCompExpr(void) {
+ xmlXPathCompExprPtr cur;
+
+ cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
+ if (cur == NULL) {
+ xmlXPathErrMemory(NULL, "allocating component\n");
+ return(NULL);
+ }
+ memset(cur, 0, sizeof(xmlXPathCompExpr));
+ cur->maxStep = 10;
+ cur->nbStep = 0;
+ cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
+ sizeof(xmlXPathStepOp));
+ if (cur->steps == NULL) {
+ xmlXPathErrMemory(NULL, "allocating steps\n");
+ xmlFree(cur);
+ return(NULL);
+ }
+ memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
+ cur->last = -1;
+#ifdef DEBUG_EVAL_COUNTS
+ cur->nb = 0;
+#endif
+ return(cur);
+}
+
+/**
+ * xmlXPathFreeCompExpr:
+ * @comp: an XPATH comp
+ *
+ * Free up the memory allocated by @comp
+ */
+void
+xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
+{
+ xmlXPathStepOpPtr op;
+ int i;
+
+ if (comp == NULL)
+ return;
+ if (comp->dict == NULL) {
+ for (i = 0; i < comp->nbStep; i++) {
+ op = &comp->steps[i];
+ if (op->value4 != NULL) {
+ if (op->op == XPATH_OP_VALUE)
+ xmlXPathFreeObject(op->value4);
+ else
+ xmlFree(op->value4);
+ }
+ if (op->value5 != NULL)
+ xmlFree(op->value5);
+ }
+ } else {
+ for (i = 0; i < comp->nbStep; i++) {
+ op = &comp->steps[i];
+ if (op->value4 != NULL) {
+ if (op->op == XPATH_OP_VALUE)
+ xmlXPathFreeObject(op->value4);
+ }
+ }
+ xmlDictFree(comp->dict);
+ }
+ if (comp->steps != NULL) {
+ xmlFree(comp->steps);
+ }
+#ifdef DEBUG_EVAL_COUNTS
+ if (comp->string != NULL) {
+ xmlFree(comp->string);
+ }
+#endif
+#ifdef XPATH_STREAMING
+ if (comp->stream != NULL) {
+ xmlFreePatternList(comp->stream);
+ }
+#endif
+ if (comp->expr != NULL) {
+ xmlFree(comp->expr);
+ }
+
+ xmlFree(comp);
+}
+
+/**
+ * xmlXPathCompExprAdd:
+ * @comp: the compiled expression
+ * @ch1: first child index
+ * @ch2: second child index
+ * @op: an op
+ * @value: the first int value
+ * @value2: the second int value
+ * @value3: the third int value
+ * @value4: the first string value
+ * @value5: the second string value
+ *
+ * Add a step to an XPath Compiled Expression
+ *
+ * Returns -1 in case of failure, the index otherwise
+ */
+static int
+xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
+ xmlXPathOp op, int value,
+ int value2, int value3, void *value4, void *value5) {
+ xmlXPathCompExprPtr comp = ctxt->comp;
+ if (comp->nbStep >= comp->maxStep) {
+ xmlXPathStepOp *real;
+
+ if (comp->maxStep >= XPATH_MAX_STEPS) {
+ xmlXPathPErrMemory(ctxt, "adding step\n");
+ return(-1);
+ }
+ comp->maxStep *= 2;
+ real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
+ comp->maxStep * sizeof(xmlXPathStepOp));
+ if (real == NULL) {
+ comp->maxStep /= 2;
+ xmlXPathPErrMemory(ctxt, "adding step\n");
+ return(-1);
+ }
+ comp->steps = real;
+ }
+ comp->last = comp->nbStep;
+ comp->steps[comp->nbStep].ch1 = ch1;
+ comp->steps[comp->nbStep].ch2 = ch2;
+ comp->steps[comp->nbStep].op = op;
+ comp->steps[comp->nbStep].value = value;
+ comp->steps[comp->nbStep].value2 = value2;
+ comp->steps[comp->nbStep].value3 = value3;
+ if ((comp->dict != NULL) &&
+ ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
+ (op == XPATH_OP_COLLECT))) {
+ if (value4 != NULL) {
+ comp->steps[comp->nbStep].value4 = (xmlChar *)
+ (void *)xmlDictLookup(comp->dict, value4, -1);
+ xmlFree(value4);
+ } else
+ comp->steps[comp->nbStep].value4 = NULL;
+ if (value5 != NULL) {
+ comp->steps[comp->nbStep].value5 = (xmlChar *)
+ (void *)xmlDictLookup(comp->dict, value5, -1);
+ xmlFree(value5);
+ } else
+ comp->steps[comp->nbStep].value5 = NULL;
+ } else {
+ comp->steps[comp->nbStep].value4 = value4;
+ comp->steps[comp->nbStep].value5 = value5;
+ }
+ comp->steps[comp->nbStep].cache = NULL;
+ return(comp->nbStep++);
+}
+
+/**
+ * xmlXPathCompSwap:
+ * @comp: the compiled expression
+ * @op: operation index
+ *
+ * Swaps 2 operations in the compiled expression
+ */
+static void
+xmlXPathCompSwap(xmlXPathStepOpPtr op) {
+ int tmp;
+
+#ifndef LIBXML_THREAD_ENABLED
+ /*
+ * Since this manipulates possibly shared variables, this is
+ * disabled if one detects that the library is used in a multithreaded
+ * application
+ */
+ if (xmlXPathDisableOptimizer)
+ return;
+#endif
+
+ tmp = op->ch1;
+ op->ch1 = op->ch2;
+ op->ch2 = tmp;
+}
+
+#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
+ xmlXPathCompExprAdd(ctxt, (op1), (op2), \
+ (op), (val), (val2), (val3), (val4), (val5))
+#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
+ xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
+ (op), (val), (val2), (val3), (val4), (val5))
+
+#define PUSH_LEAVE_EXPR(op, val, val2) \
+xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
+
+#define PUSH_UNARY_EXPR(op, ch, val, val2) \
+xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
+
+#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
+xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
+ (val), (val2), 0 ,NULL ,NULL)
+
+/************************************************************************
+ * *
+ * XPath object cache structures *
+ * *
+ ************************************************************************/
+
+/* #define XP_DEFAULT_CACHE_ON */
+
+#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
+
+typedef struct _xmlXPathContextCache xmlXPathContextCache;
+typedef xmlXPathContextCache *xmlXPathContextCachePtr;
+struct _xmlXPathContextCache {
+ xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
+ xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
+ xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
+ xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
+ xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
+ int maxNodeset;
+ int maxString;
+ int maxBoolean;
+ int maxNumber;
+ int maxMisc;
+#ifdef XP_DEBUG_OBJ_USAGE
+ int dbgCachedAll;
+ int dbgCachedNodeset;
+ int dbgCachedString;
+ int dbgCachedBool;
+ int dbgCachedNumber;
+ int dbgCachedPoint;
+ int dbgCachedRange;
+ int dbgCachedLocset;
+ int dbgCachedUsers;
+ int dbgCachedXSLTTree;
+ int dbgCachedUndefined;
+
+
+ int dbgReusedAll;
+ int dbgReusedNodeset;
+ int dbgReusedString;
+ int dbgReusedBool;
+ int dbgReusedNumber;
+ int dbgReusedPoint;
+ int dbgReusedRange;
+ int dbgReusedLocset;
+ int dbgReusedUsers;
+ int dbgReusedXSLTTree;
+ int dbgReusedUndefined;
+
+#endif
+};
+
+/************************************************************************
+ * *
+ * Debugging related functions *
+ * *
+ ************************************************************************/
+
+#define STRANGE \
+ xmlGenericError(xmlGenericErrorContext, \
+ "Internal error at %s:%d\n", \
+ __FILE__, __LINE__);
+
+#ifdef LIBXML_DEBUG_ENABLED
+static void
+xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+ if (cur == NULL) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "Node is NULL !\n");
+ return;
+
+ }
+
+ if ((cur->type == XML_DOCUMENT_NODE) ||
+ (cur->type == XML_HTML_DOCUMENT_NODE)) {
+ fprintf(output, "%s", shift);
+ fprintf(output, " /\n");
+ } else if (cur->type == XML_ATTRIBUTE_NODE)
+ xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
+ else
+ xmlDebugDumpOneNode(output, cur, depth);
+}
+static void
+xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
+ xmlNodePtr tmp;
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+ if (cur == NULL) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "Node is NULL !\n");
+ return;
+
+ }
+
+ while (cur != NULL) {
+ tmp = cur;
+ cur = cur->next;
+ xmlDebugDumpOneNode(output, tmp, depth);
+ }
+}
+
+static void
+xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+ if (cur == NULL) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "NodeSet is NULL !\n");
+ return;
+
+ }
+
+ if (cur != NULL) {
+ fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
+ for (i = 0;i < cur->nodeNr;i++) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "%d", i + 1);
+ xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
+ }
+ }
+}
+
+static void
+xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+ if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "Value Tree is NULL !\n");
+ return;
+
+ }
+
+ fprintf(output, "%s", shift);
+ fprintf(output, "%d", i + 1);
+ xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
+}
+#if defined(LIBXML_XPTR_ENABLED)
+static void
+xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+ if (cur == NULL) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "LocationSet is NULL !\n");
+ return;
+
+ }
+
+ for (i = 0;i < cur->locNr;i++) {
+ fprintf(output, "%s", shift);
+ fprintf(output, "%d : ", i + 1);
+ xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
+ }
+}
+#endif /* LIBXML_XPTR_ENABLED */
+
+/**
+ * xmlXPathDebugDumpObject:
+ * @output: the FILE * to dump the output
+ * @cur: the object to inspect
+ * @depth: indentation level
+ *
+ * Dump the content of the object for debugging purposes
+ */
+void
+xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
+ int i;
+ char shift[100];
+
+ if (output == NULL) return;
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+
+ fprintf(output, "%s", shift);
+
+ if (cur == NULL) {
+ fprintf(output, "Object is empty (NULL)\n");
+ return;
+ }
+ switch(cur->type) {
+ case XPATH_UNDEFINED:
+ fprintf(output, "Object is uninitialized\n");
+ break;
+ case XPATH_NODESET:
+ fprintf(output, "Object is a Node Set :\n");
+ xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
+ break;
+ case XPATH_XSLT_TREE:
+ fprintf(output, "Object is an XSLT value tree :\n");
+ xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
+ break;
+ case XPATH_BOOLEAN:
+ fprintf(output, "Object is a Boolean : ");
+ if (cur->boolval) fprintf(output, "true\n");
+ else fprintf(output, "false\n");
+ break;
+ case XPATH_NUMBER:
+ switch (xmlXPathIsInf(cur->floatval)) {
+ case 1:
+ fprintf(output, "Object is a number : Infinity\n");
+ break;
+ case -1:
+ fprintf(output, "Object is a number : -Infinity\n");
+ break;
+ default:
+ if (xmlXPathIsNaN(cur->floatval)) {
+ fprintf(output, "Object is a number : NaN\n");
+ } else if (cur->floatval == 0) {
+ /* Omit sign for negative zero. */
+ fprintf(output, "Object is a number : 0\n");
+ } else {
+ fprintf(output, "Object is a number : %0g\n", cur->floatval);
+ }
+ }
+ break;
+ case XPATH_STRING:
+ fprintf(output, "Object is a string : ");
+ xmlDebugDumpString(output, cur->stringval);
+ fprintf(output, "\n");
+ break;
+ case XPATH_POINT:
+ fprintf(output, "Object is a point : index %d in node", cur->index);
+ xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
+ fprintf(output, "\n");
+ break;
+ case XPATH_RANGE:
+ if ((cur->user2 == NULL) ||
+ ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
+ fprintf(output, "Object is a collapsed range :\n");
+ fprintf(output, "%s", shift);
+ if (cur->index >= 0)
+ fprintf(output, "index %d in ", cur->index);
+ fprintf(output, "node\n");
+ xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+ depth + 1);
+ } else {
+ fprintf(output, "Object is a range :\n");
+ fprintf(output, "%s", shift);
+ fprintf(output, "From ");
+ if (cur->index >= 0)
+ fprintf(output, "index %d in ", cur->index);
+ fprintf(output, "node\n");
+ xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+ depth + 1);
+ fprintf(output, "%s", shift);
+ fprintf(output, "To ");
+ if (cur->index2 >= 0)
+ fprintf(output, "index %d in ", cur->index2);
+ fprintf(output, "node\n");
+ xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
+ depth + 1);
+ fprintf(output, "\n");
+ }
+ break;
+ case XPATH_LOCATIONSET:
+#if defined(LIBXML_XPTR_ENABLED)
+ fprintf(output, "Object is a Location Set:\n");
+ xmlXPathDebugDumpLocationSet(output,
+ (xmlLocationSetPtr) cur->user, depth);
+#endif
+ break;
+ case XPATH_USERS:
+ fprintf(output, "Object is user defined\n");
+ break;
+ }
+}
+
+static void
+xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
+ xmlXPathStepOpPtr op, int depth) {
+ int i;
+ char shift[100];
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+ fprintf(output, "%s", shift);
+ if (op == NULL) {
+ fprintf(output, "Step is NULL\n");
+ return;
+ }
+ switch (op->op) {
+ case XPATH_OP_END:
+ fprintf(output, "END"); break;
+ case XPATH_OP_AND:
+ fprintf(output, "AND"); break;
+ case XPATH_OP_OR:
+ fprintf(output, "OR"); break;
+ case XPATH_OP_EQUAL:
+ if (op->value)
+ fprintf(output, "EQUAL =");
+ else
+ fprintf(output, "EQUAL !=");
+ break;
+ case XPATH_OP_CMP:
+ if (op->value)
+ fprintf(output, "CMP <");
+ else
+ fprintf(output, "CMP >");
+ if (!op->value2)
+ fprintf(output, "=");
+ break;
+ case XPATH_OP_PLUS:
+ if (op->value == 0)
+ fprintf(output, "PLUS -");
+ else if (op->value == 1)
+ fprintf(output, "PLUS +");
+ else if (op->value == 2)
+ fprintf(output, "PLUS unary -");
+ else if (op->value == 3)
+ fprintf(output, "PLUS unary - -");
+ break;
+ case XPATH_OP_MULT:
+ if (op->value == 0)
+ fprintf(output, "MULT *");
+ else if (op->value == 1)
+ fprintf(output, "MULT div");
+ else
+ fprintf(output, "MULT mod");
+ break;
+ case XPATH_OP_UNION:
+ fprintf(output, "UNION"); break;
+ case XPATH_OP_ROOT:
+ fprintf(output, "ROOT"); break;
+ case XPATH_OP_NODE:
+ fprintf(output, "NODE"); break;
+ case XPATH_OP_SORT:
+ fprintf(output, "SORT"); break;
+ case XPATH_OP_COLLECT: {
+ xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
+ xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
+ xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
+ const xmlChar *prefix = op->value4;
+ const xmlChar *name = op->value5;
+
+ fprintf(output, "COLLECT ");
+ switch (axis) {
+ case AXIS_ANCESTOR:
+ fprintf(output, " 'ancestors' "); break;
+ case AXIS_ANCESTOR_OR_SELF:
+ fprintf(output, " 'ancestors-or-self' "); break;
+ case AXIS_ATTRIBUTE:
+ fprintf(output, " 'attributes' "); break;
+ case AXIS_CHILD:
+ fprintf(output, " 'child' "); break;
+ case AXIS_DESCENDANT:
+ fprintf(output, " 'descendant' "); break;
+ case AXIS_DESCENDANT_OR_SELF:
+ fprintf(output, " 'descendant-or-self' "); break;
+ case AXIS_FOLLOWING:
+ fprintf(output, " 'following' "); break;
+ case AXIS_FOLLOWING_SIBLING:
+ fprintf(output, " 'following-siblings' "); break;
+ case AXIS_NAMESPACE:
+ fprintf(output, " 'namespace' "); break;
+ case AXIS_PARENT:
+ fprintf(output, " 'parent' "); break;
+ case AXIS_PRECEDING:
+ fprintf(output, " 'preceding' "); break;
+ case AXIS_PRECEDING_SIBLING:
+ fprintf(output, " 'preceding-sibling' "); break;
+ case AXIS_SELF:
+ fprintf(output, " 'self' "); break;
+ }
+ switch (test) {
+ case NODE_TEST_NONE:
+ fprintf(output, "'none' "); break;
+ case NODE_TEST_TYPE:
+ fprintf(output, "'type' "); break;
+ case NODE_TEST_PI:
+ fprintf(output, "'PI' "); break;
+ case NODE_TEST_ALL:
+ fprintf(output, "'all' "); break;
+ case NODE_TEST_NS:
+ fprintf(output, "'namespace' "); break;
+ case NODE_TEST_NAME:
+ fprintf(output, "'name' "); break;
+ }
+ switch (type) {
+ case NODE_TYPE_NODE:
+ fprintf(output, "'node' "); break;
+ case NODE_TYPE_COMMENT:
+ fprintf(output, "'comment' "); break;
+ case NODE_TYPE_TEXT:
+ fprintf(output, "'text' "); break;
+ case NODE_TYPE_PI:
+ fprintf(output, "'PI' "); break;
+ }
+ if (prefix != NULL)
+ fprintf(output, "%s:", prefix);
+ if (name != NULL)
+ fprintf(output, "%s", (const char *) name);
+ break;
+
+ }
+ case XPATH_OP_VALUE: {
+ xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
+
+ fprintf(output, "ELEM ");
+ xmlXPathDebugDumpObject(output, object, 0);
+ goto finish;
+ }
+ case XPATH_OP_VARIABLE: {
+ const xmlChar *prefix = op->value5;
+ const xmlChar *name = op->value4;
+
+ if (prefix != NULL)
+ fprintf(output, "VARIABLE %s:%s", prefix, name);
+ else
+ fprintf(output, "VARIABLE %s", name);
+ break;
+ }
+ case XPATH_OP_FUNCTION: {
+ int nbargs = op->value;
+ const xmlChar *prefix = op->value5;
+ const xmlChar *name = op->value4;
+
+ if (prefix != NULL)
+ fprintf(output, "FUNCTION %s:%s(%d args)",
+ prefix, name, nbargs);
+ else
+ fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
+ break;
+ }
+ case XPATH_OP_ARG: fprintf(output, "ARG"); break;
+ case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
+ case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
+#ifdef LIBXML_XPTR_ENABLED
+ case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
+#endif
+ default:
+ fprintf(output, "UNKNOWN %d\n", op->op); return;
+ }
+ fprintf(output, "\n");
+finish:
+ if (op->ch1 >= 0)
+ xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
+ if (op->ch2 >= 0)
+ xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
+}
+
+/**
+ * xmlXPathDebugDumpCompExpr:
+ * @output: the FILE * for the output
+ * @comp: the precompiled XPath expression
+ * @depth: the indentation level.
+ *
+ * Dumps the tree of the compiled XPath expression.
+ */
+void
+xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
+ int depth) {
+ int i;
+ char shift[100];
+
+ if ((output == NULL) || (comp == NULL)) return;
+
+ for (i = 0;((i < depth) && (i < 25));i++)
+ shift[2 * i] = shift[2 * i + 1] = ' ';
+ shift[2 * i] = shift[2 * i + 1] = 0;
+
+ fprintf(output, "%s", shift);
+
+#ifdef XPATH_STREAMING
+ if (comp->stream) {
+ fprintf(output, "Streaming Expression\n");
+ } else
+#endif
+ {
+ fprintf(output, "Compiled Expression : %d elements\n",
+ comp->nbStep);
+ i = comp->last;
+ xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
+ }
+}
+
+#ifdef XP_DEBUG_OBJ_USAGE
+
+/*
+* XPath object usage related debugging variables.
+*/
+static int xmlXPathDebugObjCounterUndefined = 0;
+static int xmlXPathDebugObjCounterNodeset = 0;
+static int xmlXPathDebugObjCounterBool = 0;
+static int xmlXPathDebugObjCounterNumber = 0;
+static int xmlXPathDebugObjCounterString = 0;
+static int xmlXPathDebugObjCounterPoint = 0;
+static int xmlXPathDebugObjCounterRange = 0;
+static int xmlXPathDebugObjCounterLocset = 0;
+static int xmlXPathDebugObjCounterUsers = 0;
+static int xmlXPathDebugObjCounterXSLTTree = 0;
+static int xmlXPathDebugObjCounterAll = 0;
+
+static int xmlXPathDebugObjTotalUndefined = 0;
+static int xmlXPathDebugObjTotalNodeset = 0;
+static int xmlXPathDebugObjTotalBool = 0;
+static int xmlXPathDebugObjTotalNumber = 0;
+static int xmlXPathDebugObjTotalString = 0;
+static int xmlXPathDebugObjTotalPoint = 0;
+static int xmlXPathDebugObjTotalRange = 0;
+static int xmlXPathDebugObjTotalLocset = 0;
+static int xmlXPathDebugObjTotalUsers = 0;
+static int xmlXPathDebugObjTotalXSLTTree = 0;
+static int xmlXPathDebugObjTotalAll = 0;
+
+static int xmlXPathDebugObjMaxUndefined = 0;
+static int xmlXPathDebugObjMaxNodeset = 0;
+static int xmlXPathDebugObjMaxBool = 0;
+static int xmlXPathDebugObjMaxNumber = 0;
+static int xmlXPathDebugObjMaxString = 0;
+static int xmlXPathDebugObjMaxPoint = 0;
+static int xmlXPathDebugObjMaxRange = 0;
+static int xmlXPathDebugObjMaxLocset = 0;
+static int xmlXPathDebugObjMaxUsers = 0;
+static int xmlXPathDebugObjMaxXSLTTree = 0;
+static int xmlXPathDebugObjMaxAll = 0;
+
+/* REVISIT TODO: Make this static when committing */
+static void
+xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
+{
+ if (ctxt != NULL) {
+ if (ctxt->cache != NULL) {
+ xmlXPathContextCachePtr cache =
+ (xmlXPathContextCachePtr) ctxt->cache;
+
+ cache->dbgCachedAll = 0;
+ cache->dbgCachedNodeset = 0;
+ cache->dbgCachedString = 0;
+ cache->dbgCachedBool = 0;
+ cache->dbgCachedNumber = 0;
+ cache->dbgCachedPoint = 0;
+ cache->dbgCachedRange = 0;
+ cache->dbgCachedLocset = 0;
+ cache->dbgCachedUsers = 0;
+ cache->dbgCachedXSLTTree = 0;
+ cache->dbgCachedUndefined = 0;
+
+ cache->dbgReusedAll = 0;
+ cache->dbgReusedNodeset = 0;
+ cache->dbgReusedString = 0;
+ cache->dbgReusedBool = 0;
+ cache->dbgReusedNumber = 0;
+ cache->dbgReusedPoint = 0;
+ cache->dbgReusedRange = 0;
+ cache->dbgReusedLocset = 0;
+ cache->dbgReusedUsers = 0;
+ cache->dbgReusedXSLTTree = 0;
+ cache->dbgReusedUndefined = 0;
+ }
+ }
+
+ xmlXPathDebugObjCounterUndefined = 0;
+ xmlXPathDebugObjCounterNodeset = 0;
+ xmlXPathDebugObjCounterBool = 0;
+ xmlXPathDebugObjCounterNumber = 0;
+ xmlXPathDebugObjCounterString = 0;
+ xmlXPathDebugObjCounterPoint = 0;
+ xmlXPathDebugObjCounterRange = 0;
+ xmlXPathDebugObjCounterLocset = 0;
+ xmlXPathDebugObjCounterUsers = 0;
+ xmlXPathDebugObjCounterXSLTTree = 0;
+ xmlXPathDebugObjCounterAll = 0;
+
+ xmlXPathDebugObjTotalUndefined = 0;
+ xmlXPathDebugObjTotalNodeset = 0;
+ xmlXPathDebugObjTotalBool = 0;
+ xmlXPathDebugObjTotalNumber = 0;
+ xmlXPathDebugObjTotalString = 0;
+ xmlXPathDebugObjTotalPoint = 0;
+ xmlXPathDebugObjTotalRange = 0;
+ xmlXPathDebugObjTotalLocset = 0;
+ xmlXPathDebugObjTotalUsers = 0;
+ xmlXPathDebugObjTotalXSLTTree = 0;
+ xmlXPathDebugObjTotalAll = 0;
+
+ xmlXPathDebugObjMaxUndefined = 0;
+ xmlXPathDebugObjMaxNodeset = 0;
+ xmlXPathDebugObjMaxBool = 0;
+ xmlXPathDebugObjMaxNumber = 0;
+ xmlXPathDebugObjMaxString = 0;
+ xmlXPathDebugObjMaxPoint = 0;
+ xmlXPathDebugObjMaxRange = 0;
+ xmlXPathDebugObjMaxLocset = 0;
+ xmlXPathDebugObjMaxUsers = 0;
+ xmlXPathDebugObjMaxXSLTTree = 0;
+ xmlXPathDebugObjMaxAll = 0;
+
+}
+
+static void
+xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
+ xmlXPathObjectType objType)
+{
+ int isCached = 0;
+
+ if (ctxt != NULL) {
+ if (ctxt->cache != NULL) {
+ xmlXPathContextCachePtr cache =
+ (xmlXPathContextCachePtr) ctxt->cache;
+
+ isCached = 1;
+
+ cache->dbgReusedAll++;
+ switch (objType) {
+ case XPATH_UNDEFINED:
+ cache->dbgReusedUndefined++;
+ break;
+ case XPATH_NODESET:
+ cache->dbgReusedNodeset++;
+ break;
+ case XPATH_BOOLEAN:
+ cache->dbgReusedBool++;
+ break;
+ case XPATH_NUMBER:
+ cache->dbgReusedNumber++;
+ break;
+ case XPATH_STRING:
+ cache->dbgReusedString++;
+ break;
+ case XPATH_POINT:
+ cache->dbgReusedPoint++;
+ break;
+ case XPATH_RANGE:
+ cache->dbgReusedRange++;
+ break;
+ case XPATH_LOCATIONSET:
+ cache->dbgReusedLocset++;
+ break;
+ case XPATH_USERS:
+ cache->dbgReusedUsers++;
+ break;
+ case XPATH_XSLT_TREE:
+ cache->dbgReusedXSLTTree++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ switch (objType) {
+ case XPATH_UNDEFINED:
+ if (! isCached)
+ xmlXPathDebugObjTotalUndefined++;
+ xmlXPathDebugObjCounterUndefined++;
+ if (xmlXPathDebugObjCounterUndefined >
+ xmlXPathDebugObjMaxUndefined)
+ xmlXPathDebugObjMaxUndefined =
+ xmlXPathDebugObjCounterUndefined;
+ break;
+ case XPATH_NODESET:
+ if (! isCached)
+ xmlXPathDebugObjTotalNodeset++;
+ xmlXPathDebugObjCounterNodeset++;
+ if (xmlXPathDebugObjCounterNodeset >
+ xmlXPathDebugObjMaxNodeset)
+ xmlXPathDebugObjMaxNodeset =
+ xmlXPathDebugObjCounterNodeset;
+ break;
+ case XPATH_BOOLEAN:
+ if (! isCached)
+ xmlXPathDebugObjTotalBool++;
+ xmlXPathDebugObjCounterBool++;
+ if (xmlXPathDebugObjCounterBool >
+ xmlXPathDebugObjMaxBool)
+ xmlXPathDebugObjMaxBool =
+ xmlXPathDebugObjCounterBool;
+ break;
+ case XPATH_NUMBER:
+ if (! isCached)
+ xmlXPathDebugObjTotalNumber++;
+ xmlXPathDebugObjCounterNumber++;
+ if (xmlXPathDebugObjCounterNumber >
+ xmlXPathDebugObjMaxNumber)
+ xmlXPathDebugObjMaxNumber =
+ xmlXPathDebugObjCounterNumber;
+ break;
+ case XPATH_STRING:
+ if (! isCached)
+ xmlXPathDebugObjTotalString++;
+ xmlXPathDebugObjCounterString++;
+ if (xmlXPathDebugObjCounterString >
+ xmlXPathDebugObjMaxString)
+ xmlXPathDebugObjMaxString =
+ xmlXPathDebugObjCounterString;
+ break;
+ case XPATH_POINT:
+ if (! isCached)
+ xmlXPathDebugObjTotalPoint++;
+ xmlXPathDebugObjCounterPoint++;
+ if (xmlXPathDebugObjCounterPoint >
+ xmlXPathDebugObjMaxPoint)
+ xmlXPathDebugObjMaxPoint =
+ xmlXPathDebugObjCounterPoint;
+ break;
+ case XPATH_RANGE:
+ if (! isCached)
+ xmlXPathDebugObjTotalRange++;
+ xmlXPathDebugObjCounterRange++;
+ if (xmlXPathDebugObjCounterRange >
+ xmlXPathDebugObjMaxRange)
+ xmlXPathDebugObjMaxRange =
+ xmlXPathDebugObjCounterRange;
+ break;
+ case XPATH_LOCATIONSET:
+ if (! isCached)
+ xmlXPathDebugObjTotalLocset++;
+ xmlXPathDebugObjCounterLocset++;
+ if (xmlXPathDebugObjCounterLocset >
+ xmlXPathDebugObjMaxLocset)
+ xmlXPathDebugObjMaxLocset =
+ xmlXPathDebugObjCounterLocset;
+ break;
+ case XPATH_USERS:
+ if (! isCached)
+ xmlXPathDebugObjTotalUsers++;
+ xmlXPathDebugObjCounterUsers++;
+ if (xmlXPathDebugObjCounterUsers >
+ xmlXPathDebugObjMaxUsers)
+ xmlXPathDebugObjMaxUsers =
+ xmlXPathDebugObjCounterUsers;
+ break;
+ case XPATH_XSLT_TREE:
+ if (! isCached)
+ xmlXPathDebugObjTotalXSLTTree++;
+ xmlXPathDebugObjCounterXSLTTree++;
+ if (xmlXPathDebugObjCounterXSLTTree >
+ xmlXPathDebugObjMaxXSLTTree)
+ xmlXPathDebugObjMaxXSLTTree =
+ xmlXPathDebugObjCounterXSLTTree;
+ break;
+ default:
+ break;
+ }
+ if (! isCached)
+ xmlXPathDebugObjTotalAll++;
+ xmlXPathDebugObjCounterAll++;
+ if (xmlXPathDebugObjCounterAll >
+ xmlXPathDebugObjMaxAll)
+ xmlXPathDebugObjMaxAll =
+ xmlXPathDebugObjCounterAll;
+}
+
+static void
+xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
+ xmlXPathObjectType objType)
+{
+ int isCached = 0;
+
+ if (ctxt != NULL) {
+ if (ctxt->cache != NULL) {
+ xmlXPathContextCachePtr cache =
+ (xmlXPathContextCachePtr) ctxt->cache;
+
+ isCached = 1;
+
+ cache->dbgCachedAll++;
+ switch (objType) {
+ case XPATH_UNDEFINED:
+ cache->dbgCachedUndefined++;
+ break;
+ case XPATH_NODESET:
+ cache->dbgCachedNodeset++;
+ break;
+ case XPATH_BOOLEAN:
+ cache->dbgCachedBool++;
+ break;
+ case XPATH_NUMBER:
+ cache->dbgCachedNumber++;
+ break;
+ case XPATH_STRING:
+ cache->dbgCachedString++;
+ break;
+ case XPATH_POINT:
+ cache->dbgCachedPoint++;
+ break;
+ case XPATH_RANGE:
+ cache->dbgCachedRange++;
+ break;
+ case XPATH_LOCATIONSET:
+ cache->dbgCachedLocset++;
+ break;
+ case XPATH_USERS:
+ cache->dbgCachedUsers++;
+ break;
+ case XPATH_XSLT_TREE:
+ cache->dbgCachedXSLTTree++;
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+ switch (objType) {
+ case XPATH_UNDEFINED:
+ xmlXPathDebugObjCounterUndefined--;
+ break;
+ case XPATH_NODESET:
+ xmlXPathDebugObjCounterNodeset--;
+ break;
+ case XPATH_BOOLEAN:
+ xmlXPathDebugObjCounterBool--;
+ break;
+ case XPATH_NUMBER:
+ xmlXPathDebugObjCounterNumber--;
+ break;
+ case XPATH_STRING:
+ xmlXPathDebugObjCounterString--;
+ break;
+ case XPATH_POINT:
+ xmlXPathDebugObjCounterPoint--;
+ break;
+ case XPATH_RANGE:
+ xmlXPathDebugObjCounterRange--;
+ break;
+ case XPATH_LOCATIONSET:
+ xmlXPathDebugObjCounterLocset--;
+ break;
+ case XPATH_USERS:
+ xmlXPathDebugObjCounterUsers--;
+ break;
+ case XPATH_XSLT_TREE:
+ xmlXPathDebugObjCounterXSLTTree--;
+ break;
+ default:
+ break;
+ }
+ xmlXPathDebugObjCounterAll--;
+}
+
+/* REVISIT TODO: Make this static when committing */
+static void
+xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
+{
+ int reqAll, reqNodeset, reqString, reqBool, reqNumber,
+ reqXSLTTree, reqUndefined;
+ int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
+ caNumber = 0, caXSLTTree = 0, caUndefined = 0;
+ int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
+ reNumber = 0, reXSLTTree = 0, reUndefined = 0;
+ int leftObjs = xmlXPathDebugObjCounterAll;
+
+ reqAll = xmlXPathDebugObjTotalAll;
+ reqNodeset = xmlXPathDebugObjTotalNodeset;
+ reqString = xmlXPathDebugObjTotalString;
+ reqBool = xmlXPathDebugObjTotalBool;
+ reqNumber = xmlXPathDebugObjTotalNumber;
+ reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
+ reqUndefined = xmlXPathDebugObjTotalUndefined;
+
+ printf("# XPath object usage:\n");
+
+ if (ctxt != NULL) {
+ if (ctxt->cache != NULL) {
+ xmlXPathContextCachePtr cache =
+ (xmlXPathContextCachePtr) ctxt->cache;
+
+ reAll = cache->dbgReusedAll;
+ reqAll += reAll;
+ reNodeset = cache->dbgReusedNodeset;
+ reqNodeset += reNodeset;
+ reString = cache->dbgReusedString;
+ reqString += reString;
+ reBool = cache->dbgReusedBool;
+ reqBool += reBool;
+ reNumber = cache->dbgReusedNumber;
+ reqNumber += reNumber;
+ reXSLTTree = cache->dbgReusedXSLTTree;
+ reqXSLTTree += reXSLTTree;
+ reUndefined = cache->dbgReusedUndefined;
+ reqUndefined += reUndefined;
+
+ caAll = cache->dbgCachedAll;
+ caBool = cache->dbgCachedBool;
+ caNodeset = cache->dbgCachedNodeset;
+ caString = cache->dbgCachedString;
+ caNumber = cache->dbgCachedNumber;
+ caXSLTTree = cache->dbgCachedXSLTTree;
+ caUndefined = cache->dbgCachedUndefined;
+
+ if (cache->nodesetObjs)
+ leftObjs -= cache->nodesetObjs->number;
+ if (cache->stringObjs)
+ leftObjs -= cache->stringObjs->number;
+ if (cache->booleanObjs)
+ leftObjs -= cache->booleanObjs->number;
+ if (cache->numberObjs)
+ leftObjs -= cache->numberObjs->number;
+ if (cache->miscObjs)
+ leftObjs -= cache->miscObjs->number;
+ }
+ }
+
+ printf("# all\n");
+ printf("# total : %d\n", reqAll);
+ printf("# left : %d\n", leftObjs);
+ printf("# created: %d\n", xmlXPathDebugObjTotalAll);
+ printf("# reused : %d\n", reAll);
+ printf("# max : %d\n", xmlXPathDebugObjMaxAll);
+
+ printf("# node-sets\n");
+ printf("# total : %d\n", reqNodeset);
+ printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
+ printf("# reused : %d\n", reNodeset);
+ printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
+
+ printf("# strings\n");
+ printf("# total : %d\n", reqString);
+ printf("# created: %d\n", xmlXPathDebugObjTotalString);
+ printf("# reused : %d\n", reString);
+ printf("# max : %d\n", xmlXPathDebugObjMaxString);
+
+ printf("# booleans\n");
+ printf("# total : %d\n", reqBool);
+ printf("# created: %d\n", xmlXPathDebugObjTotalBool);
+ printf("# reused : %d\n", reBool);
+ printf("# max : %d\n", xmlXPathDebugObjMaxBool);
+
+ printf("# numbers\n");
+ printf("# total : %d\n", reqNumber);
+ printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
+ printf("# reused : %d\n", reNumber);
+ printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
+
+ printf("# XSLT result tree fragments\n");
+ printf("# total : %d\n", reqXSLTTree);
+ printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
+ printf("# reused : %d\n", reXSLTTree);
+ printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
+
+ printf("# undefined\n");
+ printf("# total : %d\n", reqUndefined);
+ printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
+ printf("# reused : %d\n", reUndefined);
+ printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
+
+}
+
+#endif /* XP_DEBUG_OBJ_USAGE */
+
+#endif /* LIBXML_DEBUG_ENABLED */
+
+/************************************************************************
+ * *
+ * XPath object caching *
+ * *
+ ************************************************************************/
+
+/**
+ * xmlXPathNewCache:
+ *
+ * Create a new object cache
+ *
+ * Returns the xmlXPathCache just allocated.
+ */
+static xmlXPathContextCachePtr
+xmlXPathNewCache(void)
+{
+ xmlXPathContextCachePtr ret;
+
+ ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
+ if (ret == NULL) {
+ xmlXPathErrMemory(NULL, "creating object cache\n");
+ return(NULL);
+ }
+ memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
+ ret->maxNodeset = 100;
+ ret->maxString = 100;
+ ret->maxBoolean = 100;
+ ret->maxNumber = 100;
+ ret->maxMisc = 100;
+ return(ret);
+}
+
+static void
+xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
+{
+ int i;
+ xmlXPathObjectPtr obj;
+
+ if (list == NULL)
+ return;
+
+ for (i = 0; i < list->number; i++) {
+ obj = list->items[i];
+ /*
+ * Note that it is already assured that we don't need to
+ * look out for namespace nodes in the node-set.
+ */
+ if (obj->nodesetval != NULL) {
+ if (obj->nodesetval->nodeTab != NULL)
+ xmlFree(obj->nodesetval->nodeTab);
+ xmlFree(obj->nodesetval);
+ }
+ xmlFree(obj);
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjCounterAll--;
+#endif
+ }
+ xmlPointerListFree(list);
+}
+
+static void
+xmlXPathFreeCache(xmlXPathContextCachePtr cache)
+{
+ if (cache == NULL)
+ return;
+ if (cache->nodesetObjs)
+ xmlXPathCacheFreeObjectList(cache->nodesetObjs);
+ if (cache->stringObjs)
+ xmlXPathCacheFreeObjectList(cache->stringObjs);
+ if (cache->booleanObjs)
+ xmlXPathCacheFreeObjectList(cache->booleanObjs);
+ if (cache->numberObjs)
+ xmlXPathCacheFreeObjectList(cache->numberObjs);
+ if (cache->miscObjs)
+ xmlXPathCacheFreeObjectList(cache->miscObjs);
+ xmlFree(cache);
+}
+
+/**
+ * xmlXPathContextSetCache:
+ *
+ * @ctxt: the XPath context
+ * @active: enables/disables (creates/frees) the cache
+ * @value: a value with semantics dependent on @options
+ * @options: options (currently only the value 0 is used)
+ *
+ * Creates/frees an object cache on the XPath context.
+ * If activates XPath objects (xmlXPathObject) will be cached internally
+ * to be reused.
+ * @options:
+ * 0: This will set the XPath object caching:
+ * @value:
+ * This will set the maximum number of XPath objects
+ * to be cached per slot
+ * There are 5 slots for: node-set, string, number, boolean, and
+ * misc objects. Use <0 for the default number (100).
+ * Other values for @options have currently no effect.
+ *
+ * Returns 0 if the setting succeeded, and -1 on API or internal errors.
+ */
+int
+xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
+ int active,
+ int value,
+ int options)
+{
+ if (ctxt == NULL)
+ return(-1);
+ if (active) {
+ xmlXPathContextCachePtr cache;
+
+ if (ctxt->cache == NULL) {
+ ctxt->cache = xmlXPathNewCache();
+ if (ctxt->cache == NULL)
+ return(-1);
+ }
+ cache = (xmlXPathContextCachePtr) ctxt->cache;
+ if (options == 0) {
+ if (value < 0)
+ value = 100;
+ cache->maxNodeset = value;
+ cache->maxString = value;
+ cache->maxNumber = value;
+ cache->maxBoolean = value;
+ cache->maxMisc = value;
+ }
+ } else if (ctxt->cache != NULL) {
+ xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
+ ctxt->cache = NULL;
+ }
+ return(0);
+}
+
+/**
+ * xmlXPathCacheWrapNodeSet:
+ * @ctxt: the XPath context
+ * @val: the NodePtr value
+ *
+ * This is the cached version of xmlXPathWrapNodeSet().
+ * Wrap the Nodeset @val in a new xmlXPathObjectPtr
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
+{
+ if ((ctxt != NULL) && (ctxt->cache != NULL)) {
+ xmlXPathContextCachePtr cache =
+ (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+ ret->type = XPATH_NODESET;
+ ret->nodesetval = val;
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
+#endif
+ return(ret);
+ }
+ }
+
+ return(xmlXPathWrapNodeSet(val));
+
+}
+
+/**
+ * xmlXPathCacheWrapString:
+ * @ctxt: the XPath context
+ * @val: the xmlChar * value
+ *
+ * This is the cached version of xmlXPathWrapString().
+ * Wraps the @val string into an XPath object.
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
+{
+ if ((ctxt != NULL) && (ctxt->cache != NULL)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->stringObjs != NULL) &&
+ (cache->stringObjs->number != 0))
+ {
+
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->stringObjs->items[--cache->stringObjs->number];
+ ret->type = XPATH_STRING;
+ ret->stringval = val;
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+ /*
+ * Fallback to misc-cache.
+ */
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_STRING;
+ ret->stringval = val;
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathWrapString(val));
+}
+
+/**
+ * xmlXPathCacheNewNodeSet:
+ * @ctxt: the XPath context
+ * @val: the NodePtr value
+ *
+ * This is the cached version of xmlXPathNewNodeSet().
+ * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
+ * it with the single Node @val
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
+{
+ if ((ctxt != NULL) && (ctxt->cache)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->nodesetObjs != NULL) &&
+ (cache->nodesetObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+ /*
+ * Use the nodeset-cache.
+ */
+ ret = (xmlXPathObjectPtr)
+ cache->nodesetObjs->items[--cache->nodesetObjs->number];
+ ret->type = XPATH_NODESET;
+ ret->boolval = 0;
+ if (val) {
+ if ((ret->nodesetval->nodeMax == 0) ||
+ (val->type == XML_NAMESPACE_DECL))
+ {
+ /* TODO: Check memory error. */
+ xmlXPathNodeSetAddUnique(ret->nodesetval, val);
+ } else {
+ ret->nodesetval->nodeTab[0] = val;
+ ret->nodesetval->nodeNr = 1;
+ }
+ }
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+ /*
+ * Fallback to misc-cache.
+ */
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_NODESET;
+ ret->boolval = 0;
+ ret->nodesetval = xmlXPathNodeSetCreate(val);
+ if (ret->nodesetval == NULL) {
+ ctxt->lastError.domain = XML_FROM_XPATH;
+ ctxt->lastError.code = XML_ERR_NO_MEMORY;
+ return(NULL);
+ }
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathNewNodeSet(val));
+}
+
+/**
+ * xmlXPathCacheNewCString:
+ * @ctxt: the XPath context
+ * @val: the char * value
+ *
+ * This is the cached version of xmlXPathNewCString().
+ * Acquire an xmlXPathObjectPtr of type string and of value @val
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
+{
+ if ((ctxt != NULL) && (ctxt->cache)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->stringObjs != NULL) &&
+ (cache->stringObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->stringObjs->items[--cache->stringObjs->number];
+
+ ret->type = XPATH_STRING;
+ ret->stringval = xmlStrdup(BAD_CAST val);
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_STRING;
+ ret->stringval = xmlStrdup(BAD_CAST val);
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathNewCString(val));
+}
+
+/**
+ * xmlXPathCacheNewString:
+ * @ctxt: the XPath context
+ * @val: the xmlChar * value
+ *
+ * This is the cached version of xmlXPathNewString().
+ * Acquire an xmlXPathObjectPtr of type string and of value @val
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
+{
+ if ((ctxt != NULL) && (ctxt->cache)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->stringObjs != NULL) &&
+ (cache->stringObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->stringObjs->items[--cache->stringObjs->number];
+ ret->type = XPATH_STRING;
+ if (val != NULL)
+ ret->stringval = xmlStrdup(val);
+ else
+ ret->stringval = xmlStrdup((const xmlChar *)"");
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_STRING;
+ if (val != NULL)
+ ret->stringval = xmlStrdup(val);
+ else
+ ret->stringval = xmlStrdup((const xmlChar *)"");
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathNewString(val));
+}
+
+/**
+ * xmlXPathCacheNewBoolean:
+ * @ctxt: the XPath context
+ * @val: the boolean value
+ *
+ * This is the cached version of xmlXPathNewBoolean().
+ * Acquires an xmlXPathObjectPtr of type boolean and of value @val
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
+{
+ if ((ctxt != NULL) && (ctxt->cache)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->booleanObjs != NULL) &&
+ (cache->booleanObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->booleanObjs->items[--cache->booleanObjs->number];
+ ret->type = XPATH_BOOLEAN;
+ ret->boolval = (val != 0);
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_BOOLEAN;
+ ret->boolval = (val != 0);
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathNewBoolean(val));
+}
+
+/**
+ * xmlXPathCacheNewFloat:
+ * @ctxt: the XPath context
+ * @val: the double value
+ *
+ * This is the cached version of xmlXPathNewFloat().
+ * Acquires an xmlXPathObjectPtr of type double and of value @val
+ *
+ * Returns the created or reused object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
+{
+ if ((ctxt != NULL) && (ctxt->cache)) {
+ xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+
+ if ((cache->numberObjs != NULL) &&
+ (cache->numberObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->numberObjs->items[--cache->numberObjs->number];
+ ret->type = XPATH_NUMBER;
+ ret->floatval = val;
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
+#endif
+ return(ret);
+ } else if ((cache->miscObjs != NULL) &&
+ (cache->miscObjs->number != 0))
+ {
+ xmlXPathObjectPtr ret;
+
+ ret = (xmlXPathObjectPtr)
+ cache->miscObjs->items[--cache->miscObjs->number];
+
+ ret->type = XPATH_NUMBER;
+ ret->floatval = val;
+#ifdef XP_DEBUG_OBJ_USAGE
+ xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
+#endif
+ return(ret);
+ }
+ }
+ return(xmlXPathNewFloat(val));
+}
+
+/**
+ * xmlXPathCacheConvertString:
+ * @ctxt: the XPath context
+ * @val: an XPath object
+ *
+ * This is the cached version of xmlXPathConvertString().
+ * Converts an existing object to its string() equivalent
+ *
+ * Returns a created or reused object, the old one is freed (cached)
+ * (or the operation is done directly on @val)
+ */
+
+static xmlXPathObjectPtr
+xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
+ xmlChar *res = NULL;
+
+ if (val == NULL)
+ return(xmlXPathCacheNewCString(ctxt, ""));
+
+ switch (val->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ res = xmlXPathCastNodeSetToString(val->nodesetval);
+ break;
+ case XPATH_STRING:
+ return(val);
+ case XPATH_BOOLEAN:
+ res = xmlXPathCastBooleanToString(val->boolval);
+ break;
+ case XPATH_NUMBER:
+ res = xmlXPathCastNumberToString(val->floatval);
+ break;
+ case XPATH_USERS:
+ case XPATH_POINT:
+ case XPATH_RANGE:
+ case XPATH_LOCATIONSET:
+ TODO;
+ break;
+ }
+ xmlXPathReleaseObject(ctxt, val);
+ if (res == NULL)
+ return(xmlXPathCacheNewCString(ctxt, ""));
+ return(xmlXPathCacheWrapString(ctxt, res));
+}
+
+/**
+ * xmlXPathCacheObjectCopy:
+ * @ctxt: the XPath context
+ * @val: the original object
+ *
+ * This is the cached version of xmlXPathObjectCopy().
+ * Acquire a copy of a given object
+ *
+ * Returns a created or reused created object.
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
+{
+ if (val == NULL)
+ return(NULL);
+
+ if (XP_HAS_CACHE(ctxt)) {
+ switch (val->type) {
+ case XPATH_NODESET:
+ return(xmlXPathCacheWrapNodeSet(ctxt,
+ xmlXPathNodeSetMerge(NULL, val->nodesetval)));
+ case XPATH_STRING:
+ return(xmlXPathCacheNewString(ctxt, val->stringval));
+ case XPATH_BOOLEAN:
+ return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
+ case XPATH_NUMBER:
+ return(xmlXPathCacheNewFloat(ctxt, val->floatval));
+ default:
+ break;
+ }
+ }
+ return(xmlXPathObjectCopy(val));
+}
+
+/**
+ * xmlXPathCacheConvertBoolean:
+ * @ctxt: the XPath context
+ * @val: an XPath object
+ *
+ * This is the cached version of xmlXPathConvertBoolean().
+ * Converts an existing object to its boolean() equivalent
+ *
+ * Returns a created or reused object, the old one is freed (or the operation
+ * is done directly on @val)
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
+ xmlXPathObjectPtr ret;
+
+ if (val == NULL)
+ return(xmlXPathCacheNewBoolean(ctxt, 0));
+ if (val->type == XPATH_BOOLEAN)
+ return(val);
+ ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
+ xmlXPathReleaseObject(ctxt, val);
+ return(ret);
+}
+
+/**
+ * xmlXPathCacheConvertNumber:
+ * @ctxt: the XPath context
+ * @val: an XPath object
+ *
+ * This is the cached version of xmlXPathConvertNumber().
+ * Converts an existing object to its number() equivalent
+ *
+ * Returns a created or reused object, the old one is freed (or the operation
+ * is done directly on @val)
+ */
+static xmlXPathObjectPtr
+xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
+ xmlXPathObjectPtr ret;
+
+ if (val == NULL)
+ return(xmlXPathCacheNewFloat(ctxt, 0.0));
+ if (val->type == XPATH_NUMBER)
+ return(val);
+ ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
+ xmlXPathReleaseObject(ctxt, val);
+ return(ret);
+}
+
+/************************************************************************
+ * *
+ * Parser stacks related functions and macros *
+ * *
+ ************************************************************************/
+
+/**
+ * xmlXPathSetFrame:
+ * @ctxt: an XPath parser context
+ *
+ * Set the callee evaluation frame
+ *
+ * Returns the previous frame value to be restored once done
+ */
+static int
+xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
+ int ret;
+
+ if (ctxt == NULL)
+ return(0);
+ ret = ctxt->valueFrame;
+ ctxt->valueFrame = ctxt->valueNr;
+ return(ret);
+}
+
+/**
+ * xmlXPathPopFrame:
+ * @ctxt: an XPath parser context
+ * @frame: the previous frame value
+ *
+ * Remove the callee evaluation frame
+ */
+static void
+xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
+ if (ctxt == NULL)
+ return;
+ if (ctxt->valueNr < ctxt->valueFrame) {
+ xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
+ }
+ ctxt->valueFrame = frame;
+}
+
+/**
+ * valuePop:
+ * @ctxt: an XPath evaluation context
+ *
+ * Pops the top XPath object from the value stack
+ *
+ * Returns the XPath object just removed
+ */
+xmlXPathObjectPtr
+valuePop(xmlXPathParserContextPtr ctxt)
+{
+ xmlXPathObjectPtr ret;
+
+ if ((ctxt == NULL) || (ctxt->valueNr <= 0))
+ return (NULL);
+
+ if (ctxt->valueNr <= ctxt->valueFrame) {
+ xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
+ return (NULL);
+ }
+
+ ctxt->valueNr--;
+ if (ctxt->valueNr > 0)
+ ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
+ else
+ ctxt->value = NULL;
+ ret = ctxt->valueTab[ctxt->valueNr];
+ ctxt->valueTab[ctxt->valueNr] = NULL;
+ return (ret);
+}
+/**
+ * valuePush:
+ * @ctxt: an XPath evaluation context
+ * @value: the XPath object
+ *
+ * Pushes a new XPath object on top of the value stack. If value is NULL,
+ * a memory error is recorded in the parser context.
+ *
+ * Returns the number of items on the value stack, or -1 in case of error.
+ */
+int
+valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
+{
+ if (ctxt == NULL) return(-1);
+ if (value == NULL) {
+ /*
+ * A NULL value typically indicates that a memory allocation failed,
+ * so we set ctxt->error here to propagate the error.
+ */
+ ctxt->error = XPATH_MEMORY_ERROR;
+ return(-1);
+ }
+ if (ctxt->valueNr >= ctxt->valueMax) {
+ xmlXPathObjectPtr *tmp;
+
+ if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
+ xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
+ return (-1);
+ }
+ tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
+ 2 * ctxt->valueMax *
+ sizeof(ctxt->valueTab[0]));
+ if (tmp == NULL) {
+ xmlXPathPErrMemory(ctxt, "pushing value\n");
+ return (-1);
+ }
+ ctxt->valueMax *= 2;
+ ctxt->valueTab = tmp;
+ }
+ ctxt->valueTab[ctxt->valueNr] = value;
+ ctxt->value = value;
+ return (ctxt->valueNr++);
+}
+
+/**
+ * xmlXPathPopBoolean:
+ * @ctxt: an XPath parser context
+ *
+ * Pops a boolean from the stack, handling conversion if needed.
+ * Check error with #xmlXPathCheckError.
+ *
+ * Returns the boolean
+ */
+int
+xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr obj;
+ int ret;
+
+ obj = valuePop(ctxt);
+ if (obj == NULL) {
+ xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
+ return(0);
+ }
+ if (obj->type != XPATH_BOOLEAN)
+ ret = xmlXPathCastToBoolean(obj);
+ else
+ ret = obj->boolval;
+ xmlXPathReleaseObject(ctxt->context, obj);
+ return(ret);
+}
+
+/**
+ * xmlXPathPopNumber:
+ * @ctxt: an XPath parser context
+ *
+ * Pops a number from the stack, handling conversion if needed.
+ * Check error with #xmlXPathCheckError.
+ *
+ * Returns the number
+ */
+double
+xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr obj;
+ double ret;
+
+ obj = valuePop(ctxt);
+ if (obj == NULL) {
+ xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
+ return(0);
+ }
+ if (obj->type != XPATH_NUMBER)
+ ret = xmlXPathCastToNumber(obj);
+ else
+ ret = obj->floatval;
+ xmlXPathReleaseObject(ctxt->context, obj);
+ return(ret);
+}
+
+/**
+ * xmlXPathPopString:
+ * @ctxt: an XPath parser context
+ *
+ * Pops a string from the stack, handling conversion if needed.
+ * Check error with #xmlXPathCheckError.
+ *
+ * Returns the string
+ */
+xmlChar *
+xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr obj;
+ xmlChar * ret;
+
+ obj = valuePop(ctxt);
+ if (obj == NULL) {
+ xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
+ return(NULL);
+ }
+ ret = xmlXPathCastToString(obj); /* this does required strdup */
+ /* TODO: needs refactoring somewhere else */
+ if (obj->stringval == ret)
+ obj->stringval = NULL;
+ xmlXPathReleaseObject(ctxt->context, obj);
+ return(ret);
+}
+
+/**
+ * xmlXPathPopNodeSet:
+ * @ctxt: an XPath parser context
+ *
+ * Pops a node-set from the stack, handling conversion if needed.
+ * Check error with #xmlXPathCheckError.
+ *
+ * Returns the node-set
+ */
+xmlNodeSetPtr
+xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr obj;
+ xmlNodeSetPtr ret;
+
+ if (ctxt == NULL) return(NULL);
+ if (ctxt->value == NULL) {
+ xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
+ return(NULL);
+ }
+ if (!xmlXPathStackIsNodeSet(ctxt)) {
+ xmlXPathSetTypeError(ctxt);
+ return(NULL);
+ }
+ obj = valuePop(ctxt);
+ ret = obj->nodesetval;
+#if 0
+ /* to fix memory leak of not clearing obj->user */
+ if (obj->boolval && obj->user != NULL)
+ xmlFreeNodeList((xmlNodePtr) obj->user);
+#endif
+ obj->nodesetval = NULL;
+ xmlXPathReleaseObject(ctxt->context, obj);
+ return(ret);
+}
+
+/**
+ * xmlXPathPopExternal:
+ * @ctxt: an XPath parser context
+ *
+ * Pops an external object from the stack, handling conversion if needed.
+ * Check error with #xmlXPathCheckError.
+ *
+ * Returns the object
+ */
+void *
+xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr obj;
+ void * ret;
+
+ if ((ctxt == NULL) || (ctxt->value == NULL)) {
+ xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
+ return(NULL);
+ }
+ if (ctxt->value->type != XPATH_USERS) {
+ xmlXPathSetTypeError(ctxt);
+ return(NULL);
+ }
+ obj = valuePop(ctxt);
+ ret = obj->user;
+ obj->user = NULL;
+ xmlXPathReleaseObject(ctxt->context, obj);
+ return(ret);
+}
+
+/*
+ * Macros for accessing the content. Those should be used only by the parser,
+ * and not exported.
+ *
+ * Dirty macros, i.e. one need to make assumption on the context to use them
+ *
+ * CUR_PTR return the current pointer to the xmlChar to be parsed.
+ * CUR returns the current xmlChar value, i.e. a 8 bit value
+ * in ISO-Latin or UTF-8.
+ * This should be used internally by the parser
+ * only to compare to ASCII values otherwise it would break when
+ * running with UTF-8 encoding.
+ * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
+ * to compare on ASCII based substring.
+ * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
+ * strings within the parser.
+ * CURRENT Returns the current char value, with the full decoding of
+ * UTF-8 if we are using this mode. It returns an int.
+ * NEXT Skip to the next character, this does the proper decoding
+ * in UTF-8 mode. It also pop-up unfinished entities on the fly.
+ * It returns the pointer to the current xmlChar.
+ */
+
+#define CUR (*ctxt->cur)
+#define SKIP(val) ctxt->cur += (val)
+#define NXT(val) ctxt->cur[(val)]
+#define CUR_PTR ctxt->cur
+#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
+
+#define COPY_BUF(l,b,i,v) \
+ if (l == 1) b[i++] = (xmlChar) v; \
+ else i += xmlCopyChar(l,&b[i],v)
+
+#define NEXTL(l) ctxt->cur += l
+
+#define SKIP_BLANKS \
+ while (IS_BLANK_CH(*(ctxt->cur))) NEXT
+
+#define CURRENT (*ctxt->cur)
+#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
+
+
+#ifndef DBL_DIG