ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

xpath.c
Go to the documentation of this file.
00001 /*
00002  * xpath.c: XML Path Language implementation
00003  *          XPath is a language for addressing parts of an XML document,
00004  *          designed to be used by both XSLT and XPointer
00005  *f
00006  * Reference: W3C Recommendation 16 November 1999
00007  *     http://www.w3.org/TR/1999/REC-xpath-19991116
00008  * Public reference:
00009  *     http://www.w3.org/TR/xpath
00010  *
00011  * See Copyright for the status of this software
00012  *
00013  * Author: daniel@veillard.com
00014  *
00015  */
00016 
00017 #define IN_LIBXML
00018 #include "libxml.h"
00019 
00020 #include <string.h>
00021 
00022 #ifdef HAVE_SYS_TYPES_H
00023 #include <sys/types.h>
00024 #endif
00025 #ifdef HAVE_MATH_H
00026 #include <math.h>
00027 #endif
00028 #ifdef HAVE_FLOAT_H
00029 #include <float.h>
00030 #endif
00031 #ifdef HAVE_CTYPE_H
00032 #include <ctype.h>
00033 #endif
00034 #ifdef HAVE_SIGNAL_H
00035 #include <signal.h>
00036 #endif
00037 
00038 #include <libxml/xmlmemory.h>
00039 #include <libxml/tree.h>
00040 #include <libxml/valid.h>
00041 #include <libxml/xpath.h>
00042 #include <libxml/xpathInternals.h>
00043 #include <libxml/parserInternals.h>
00044 #include <libxml/hash.h>
00045 #ifdef LIBXML_XPTR_ENABLED
00046 #include <libxml/xpointer.h>
00047 #endif
00048 #ifdef LIBXML_DEBUG_ENABLED
00049 #include <libxml/debugXML.h>
00050 #endif
00051 #include <libxml/xmlerror.h>
00052 #include <libxml/threads.h>
00053 #include <libxml/globals.h>
00054 #ifdef LIBXML_PATTERN_ENABLED
00055 #include <libxml/pattern.h>
00056 #endif
00057 
00058 #ifdef LIBXML_PATTERN_ENABLED
00059 #define XPATH_STREAMING
00060 #endif
00061 
00062 #define TODO                                \
00063     xmlGenericError(xmlGenericErrorContext,             \
00064         "Unimplemented block at %s:%d\n",               \
00065             __FILE__, __LINE__);
00066 
00067 /*
00068 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
00069 * If defined, this will use xmlXPathCmpNodesExt() instead of
00070 * xmlXPathCmpNodes(). The new function is optimized comparison of
00071 * non-element nodes; actually it will speed up comparison only if
00072 * xmlXPathOrderDocElems() was called in order to index the elements of
00073 * a tree in document order; Libxslt does such an indexing, thus it will
00074 * benefit from this optimization.
00075 */
00076 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
00077 
00078 /*
00079 * XP_OPTIMIZED_FILTER_FIRST:
00080 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
00081 * in a way, that it stop evaluation at the first node.
00082 */
00083 #define XP_OPTIMIZED_FILTER_FIRST
00084 
00085 /*
00086 * XP_DEBUG_OBJ_USAGE:
00087 * Internal flag to enable tracking of how much XPath objects have been
00088 * created.
00089 */
00090 /* #define XP_DEBUG_OBJ_USAGE */
00091 
00092 /*
00093  * TODO:
00094  * There are a few spots where some tests are done which depend upon ascii
00095  * data.  These should be enhanced for full UTF8 support (see particularly
00096  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
00097  */
00098 
00099 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
00100 
00101 /************************************************************************
00102  *                                  *
00103  *          Floating point stuff                *
00104  *                                  *
00105  ************************************************************************/
00106 
00107 #ifndef TRIO_REPLACE_STDIO
00108 #define TRIO_PUBLIC static
00109 #endif
00110 #include "trionan.c"
00111 
00112 /*
00113  * The lack of portability of this section of the libc is annoying !
00114  */
00115 double xmlXPathNAN = 0;
00116 double xmlXPathPINF = 1;
00117 double xmlXPathNINF = -1;
00118 static double xmlXPathNZERO = 0; /* not exported from headers */
00119 static int xmlXPathInitialized = 0;
00120 
00126 void
00127 xmlXPathInit(void) {
00128     if (xmlXPathInitialized) return;
00129 
00130     xmlXPathPINF = trio_pinf();
00131     xmlXPathNINF = trio_ninf();
00132     xmlXPathNAN = trio_nan();
00133     xmlXPathNZERO = trio_nzero();
00134 
00135     xmlXPathInitialized = 1;
00136 }
00137 
00148 int
00149 xmlXPathIsNaN(double val) {
00150     return(trio_isnan(val));
00151 }
00152 
00163 int
00164 xmlXPathIsInf(double val) {
00165     return(trio_isinf(val));
00166 }
00167 
00168 #endif /* SCHEMAS or XPATH */
00169 #ifdef LIBXML_XPATH_ENABLED
00170 
00180 static int
00181 xmlXPathGetSign(double val) {
00182     return(trio_signbit(val));
00183 }
00184 
00185 
00186 /*
00187  * TODO: when compatibility allows remove all "fake node libxslt" strings
00188  *       the test should just be name[0] = ' '
00189  */
00190 #ifdef DEBUG_XPATH_EXPRESSION
00191 #define DEBUG_STEP
00192 #define DEBUG_EXPR
00193 #define DEBUG_EVAL_COUNTS
00194 #endif
00195 
00196 static xmlNs xmlXPathXMLNamespaceStruct = {
00197     NULL,
00198     XML_NAMESPACE_DECL,
00199     XML_XML_NAMESPACE,
00200     BAD_CAST "xml",
00201     NULL,
00202     NULL
00203 };
00204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
00205 #ifndef LIBXML_THREAD_ENABLED
00206 /*
00207  * Optimizer is disabled only when threaded apps are detected while
00208  * the library ain't compiled for thread safety.
00209  */
00210 static int xmlXPathDisableOptimizer = 0;
00211 #endif
00212 
00213 /************************************************************************
00214  *                                  *
00215  *          Error handling routines             *
00216  *                                  *
00217  ************************************************************************/
00218 
00225 #define XP_ERRORNULL(X)                         \
00226     { xmlXPathErr(ctxt, X); return(NULL); }
00227 
00228 /*
00229  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
00230  */
00231 static const char *xmlXPathErrorMessages[] = {
00232     "Ok\n",
00233     "Number encoding\n",
00234     "Unfinished literal\n",
00235     "Start of literal\n",
00236     "Expected $ for variable reference\n",
00237     "Undefined variable\n",
00238     "Invalid predicate\n",
00239     "Invalid expression\n",
00240     "Missing closing curly brace\n",
00241     "Unregistered function\n",
00242     "Invalid operand\n",
00243     "Invalid type\n",
00244     "Invalid number of arguments\n",
00245     "Invalid context size\n",
00246     "Invalid context position\n",
00247     "Memory allocation error\n",
00248     "Syntax error\n",
00249     "Resource error\n",
00250     "Sub resource error\n",
00251     "Undefined namespace prefix\n",
00252     "Encoding error\n",
00253     "Char out of XML range\n",
00254     "Invalid or incomplete context\n",
00255     "?? Unknown error ??\n" /* Must be last in the list! */
00256 };
00257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
00258            sizeof(xmlXPathErrorMessages[0])) - 1)
00259 
00266 static void
00267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
00268 {
00269     if (ctxt != NULL) {
00270         if (extra) {
00271             xmlChar buf[200];
00272 
00273             xmlStrPrintf(buf, 200,
00274                          BAD_CAST "Memory allocation failed : %s\n",
00275                          extra);
00276             ctxt->lastError.message = (char *) xmlStrdup(buf);
00277         } else {
00278             ctxt->lastError.message = (char *)
00279            xmlStrdup(BAD_CAST "Memory allocation failed\n");
00280         }
00281         ctxt->lastError.domain = XML_FROM_XPATH;
00282         ctxt->lastError.code = XML_ERR_NO_MEMORY;
00283     if (ctxt->error != NULL)
00284         ctxt->error(ctxt->userData, &ctxt->lastError);
00285     } else {
00286         if (extra)
00287             __xmlRaiseError(NULL, NULL, NULL,
00288                             NULL, NULL, XML_FROM_XPATH,
00289                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
00290                             extra, NULL, NULL, 0, 0,
00291                             "Memory allocation failed : %s\n", extra);
00292         else
00293             __xmlRaiseError(NULL, NULL, NULL,
00294                             NULL, NULL, XML_FROM_XPATH,
00295                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
00296                             NULL, NULL, NULL, 0, 0,
00297                             "Memory allocation failed\n");
00298     }
00299 }
00300 
00308 static void
00309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
00310 {
00311     if (ctxt == NULL)
00312     xmlXPathErrMemory(NULL, extra);
00313     else {
00314     ctxt->error = XPATH_MEMORY_ERROR;
00315     xmlXPathErrMemory(ctxt->context, extra);
00316     }
00317 }
00318 
00326 void
00327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
00328 {
00329     if ((error < 0) || (error > MAXERRNO))
00330     error = MAXERRNO;
00331     if (ctxt == NULL) {
00332     __xmlRaiseError(NULL, NULL, NULL,
00333             NULL, NULL, XML_FROM_XPATH,
00334             error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
00335             XML_ERR_ERROR, NULL, 0,
00336             NULL, NULL, NULL, 0, 0,
00337             "%s", xmlXPathErrorMessages[error]);
00338     return;
00339     }
00340     ctxt->error = error;
00341     if (ctxt->context == NULL) {
00342     __xmlRaiseError(NULL, NULL, NULL,
00343             NULL, NULL, XML_FROM_XPATH,
00344             error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
00345             XML_ERR_ERROR, NULL, 0,
00346             (const char *) ctxt->base, NULL, NULL,
00347             ctxt->cur - ctxt->base, 0,
00348             "%s", xmlXPathErrorMessages[error]);
00349     return;
00350     }
00351 
00352     /* cleanup current last error */
00353     xmlResetError(&ctxt->context->lastError);
00354 
00355     ctxt->context->lastError.domain = XML_FROM_XPATH;
00356     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
00357                            XPATH_EXPRESSION_OK;
00358     ctxt->context->lastError.level = XML_ERR_ERROR;
00359     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
00360     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
00361     ctxt->context->lastError.node = ctxt->context->debugNode;
00362     if (ctxt->context->error != NULL) {
00363     ctxt->context->error(ctxt->context->userData,
00364                          &ctxt->context->lastError);
00365     } else {
00366     __xmlRaiseError(NULL, NULL, NULL,
00367             NULL, ctxt->context->debugNode, XML_FROM_XPATH,
00368             error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
00369             XML_ERR_ERROR, NULL, 0,
00370             (const char *) ctxt->base, NULL, NULL,
00371             ctxt->cur - ctxt->base, 0,
00372             "%s", xmlXPathErrorMessages[error]);
00373     }
00374 
00375 }
00376 
00386 void
00387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
00388               int line ATTRIBUTE_UNUSED, int no) {
00389     xmlXPathErr(ctxt, no);
00390 }
00391 
00392 /************************************************************************
00393  *                                  *
00394  *          Utilities                   *
00395  *                                  *
00396  ************************************************************************/
00397 
00403 typedef struct _xmlPointerList xmlPointerList;
00404 typedef xmlPointerList *xmlPointerListPtr;
00405 struct _xmlPointerList {
00406     void **items;
00407     int number;
00408     int size;
00409 };
00410 /*
00411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
00412 * and here, we should make the functions public.
00413 */
00414 static int
00415 xmlPointerListAddSize(xmlPointerListPtr list,
00416                void *item,
00417                int initialSize)
00418 {
00419     if (list->items == NULL) {
00420     if (initialSize <= 0)
00421         initialSize = 1;
00422     list->items = (void **) xmlMalloc(
00423         initialSize * sizeof(void *));
00424     if (list->items == NULL) {
00425         xmlXPathErrMemory(NULL,
00426         "xmlPointerListCreate: allocating item\n");
00427         return(-1);
00428     }
00429     list->number = 0;
00430     list->size = initialSize;
00431     } else if (list->size <= list->number) {
00432     list->size *= 2;
00433     list->items = (void **) xmlRealloc(list->items,
00434         list->size * sizeof(void *));
00435     if (list->items == NULL) {
00436         xmlXPathErrMemory(NULL,
00437         "xmlPointerListCreate: re-allocating item\n");
00438         list->size = 0;
00439         return(-1);
00440     }
00441     }
00442     list->items[list->number++] = item;
00443     return(0);
00444 }
00445 
00453 static xmlPointerListPtr
00454 xmlPointerListCreate(int initialSize)
00455 {
00456     xmlPointerListPtr ret;
00457 
00458     ret = xmlMalloc(sizeof(xmlPointerList));
00459     if (ret == NULL) {
00460     xmlXPathErrMemory(NULL,
00461         "xmlPointerListCreate: allocating item\n");
00462     return (NULL);
00463     }
00464     memset(ret, 0, sizeof(xmlPointerList));
00465     if (initialSize > 0) {
00466     xmlPointerListAddSize(ret, NULL, initialSize);
00467     ret->number = 0;
00468     }
00469     return (ret);
00470 }
00471 
00478 static void
00479 xmlPointerListFree(xmlPointerListPtr list)
00480 {
00481     if (list == NULL)
00482     return;
00483     if (list->items != NULL)
00484     xmlFree(list->items);
00485     xmlFree(list);
00486 }
00487 
00488 /************************************************************************
00489  *                                  *
00490  *          Parser Types                    *
00491  *                                  *
00492  ************************************************************************/
00493 
00494 /*
00495  * Types are private:
00496  */
00497 
00498 typedef enum {
00499     XPATH_OP_END=0,
00500     XPATH_OP_AND,
00501     XPATH_OP_OR,
00502     XPATH_OP_EQUAL,
00503     XPATH_OP_CMP,
00504     XPATH_OP_PLUS,
00505     XPATH_OP_MULT,
00506     XPATH_OP_UNION,
00507     XPATH_OP_ROOT,
00508     XPATH_OP_NODE,
00509     XPATH_OP_RESET, /* 10 */
00510     XPATH_OP_COLLECT,
00511     XPATH_OP_VALUE, /* 12 */
00512     XPATH_OP_VARIABLE,
00513     XPATH_OP_FUNCTION,
00514     XPATH_OP_ARG,
00515     XPATH_OP_PREDICATE,
00516     XPATH_OP_FILTER, /* 17 */
00517     XPATH_OP_SORT /* 18 */
00518 #ifdef LIBXML_XPTR_ENABLED
00519     ,XPATH_OP_RANGETO
00520 #endif
00521 } xmlXPathOp;
00522 
00523 typedef enum {
00524     AXIS_ANCESTOR = 1,
00525     AXIS_ANCESTOR_OR_SELF,
00526     AXIS_ATTRIBUTE,
00527     AXIS_CHILD,
00528     AXIS_DESCENDANT,
00529     AXIS_DESCENDANT_OR_SELF,
00530     AXIS_FOLLOWING,
00531     AXIS_FOLLOWING_SIBLING,
00532     AXIS_NAMESPACE,
00533     AXIS_PARENT,
00534     AXIS_PRECEDING,
00535     AXIS_PRECEDING_SIBLING,
00536     AXIS_SELF
00537 } xmlXPathAxisVal;
00538 
00539 typedef enum {
00540     NODE_TEST_NONE = 0,
00541     NODE_TEST_TYPE = 1,
00542     NODE_TEST_PI = 2,
00543     NODE_TEST_ALL = 3,
00544     NODE_TEST_NS = 4,
00545     NODE_TEST_NAME = 5
00546 } xmlXPathTestVal;
00547 
00548 typedef enum {
00549     NODE_TYPE_NODE = 0,
00550     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
00551     NODE_TYPE_TEXT = XML_TEXT_NODE,
00552     NODE_TYPE_PI = XML_PI_NODE
00553 } xmlXPathTypeVal;
00554 
00555 #define XP_REWRITE_DOS_CHILD_ELEM 1
00556 
00557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
00558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
00559 struct _xmlXPathStepOp {
00560     xmlXPathOp op;      /* The identifier of the operation */
00561     int ch1;            /* First child */
00562     int ch2;            /* Second child */
00563     int value;
00564     int value2;
00565     int value3;
00566     void *value4;
00567     void *value5;
00568     void *cache;
00569     void *cacheURI;
00570     int rewriteType;
00571 };
00572 
00573 struct _xmlXPathCompExpr {
00574     int nbStep;         /* Number of steps in this expression */
00575     int maxStep;        /* Maximum number of steps allocated */
00576     xmlXPathStepOp *steps;  /* ops for computation of this expression */
00577     int last;           /* index of last step in expression */
00578     xmlChar *expr;      /* the expression being computed */
00579     xmlDictPtr dict;        /* the dictionnary to use if any */
00580 #ifdef DEBUG_EVAL_COUNTS
00581     int nb;
00582     xmlChar *string;
00583 #endif
00584 #ifdef XPATH_STREAMING
00585     xmlPatternPtr stream;
00586 #endif
00587 };
00588 
00589 /************************************************************************
00590  *                                  *
00591  *          Forward declarations                *
00592  *                                  *
00593  ************************************************************************/
00594 static void
00595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
00596 static void
00597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
00598 static int
00599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
00600                         xmlXPathStepOpPtr op, xmlNodePtr *first);
00601 static int
00602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
00603                 xmlXPathStepOpPtr op,
00604                 int isPredicate);
00605 
00606 /************************************************************************
00607  *                                  *
00608  *          Parser Type functions               *
00609  *                                  *
00610  ************************************************************************/
00611 
00619 static xmlXPathCompExprPtr
00620 xmlXPathNewCompExpr(void) {
00621     xmlXPathCompExprPtr cur;
00622 
00623     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
00624     if (cur == NULL) {
00625         xmlXPathErrMemory(NULL, "allocating component\n");
00626     return(NULL);
00627     }
00628     memset(cur, 0, sizeof(xmlXPathCompExpr));
00629     cur->maxStep = 10;
00630     cur->nbStep = 0;
00631     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
00632                                        sizeof(xmlXPathStepOp));
00633     if (cur->steps == NULL) {
00634         xmlXPathErrMemory(NULL, "allocating steps\n");
00635     xmlFree(cur);
00636     return(NULL);
00637     }
00638     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
00639     cur->last = -1;
00640 #ifdef DEBUG_EVAL_COUNTS
00641     cur->nb = 0;
00642 #endif
00643     return(cur);
00644 }
00645 
00652 void
00653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
00654 {
00655     xmlXPathStepOpPtr op;
00656     int i;
00657 
00658     if (comp == NULL)
00659         return;
00660     if (comp->dict == NULL) {
00661     for (i = 0; i < comp->nbStep; i++) {
00662         op = &comp->steps[i];
00663         if (op->value4 != NULL) {
00664         if (op->op == XPATH_OP_VALUE)
00665             xmlXPathFreeObject(op->value4);
00666         else
00667             xmlFree(op->value4);
00668         }
00669         if (op->value5 != NULL)
00670         xmlFree(op->value5);
00671     }
00672     } else {
00673     for (i = 0; i < comp->nbStep; i++) {
00674         op = &comp->steps[i];
00675         if (op->value4 != NULL) {
00676         if (op->op == XPATH_OP_VALUE)
00677             xmlXPathFreeObject(op->value4);
00678         }
00679     }
00680         xmlDictFree(comp->dict);
00681     }
00682     if (comp->steps != NULL) {
00683         xmlFree(comp->steps);
00684     }
00685 #ifdef DEBUG_EVAL_COUNTS
00686     if (comp->string != NULL) {
00687         xmlFree(comp->string);
00688     }
00689 #endif
00690 #ifdef XPATH_STREAMING
00691     if (comp->stream != NULL) {
00692         xmlFreePatternList(comp->stream);
00693     }
00694 #endif
00695     if (comp->expr != NULL) {
00696         xmlFree(comp->expr);
00697     }
00698 
00699     xmlFree(comp);
00700 }
00701 
00718 static int
00719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
00720    xmlXPathOp op, int value,
00721    int value2, int value3, void *value4, void *value5) {
00722     if (comp->nbStep >= comp->maxStep) {
00723     xmlXPathStepOp *real;
00724 
00725     comp->maxStep *= 2;
00726     real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
00727                               comp->maxStep * sizeof(xmlXPathStepOp));
00728     if (real == NULL) {
00729         comp->maxStep /= 2;
00730         xmlXPathErrMemory(NULL, "adding step\n");
00731         return(-1);
00732     }
00733     comp->steps = real;
00734     }
00735     comp->last = comp->nbStep;
00736     comp->steps[comp->nbStep].rewriteType = 0;
00737     comp->steps[comp->nbStep].ch1 = ch1;
00738     comp->steps[comp->nbStep].ch2 = ch2;
00739     comp->steps[comp->nbStep].op = op;
00740     comp->steps[comp->nbStep].value = value;
00741     comp->steps[comp->nbStep].value2 = value2;
00742     comp->steps[comp->nbStep].value3 = value3;
00743     if ((comp->dict != NULL) &&
00744         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
00745      (op == XPATH_OP_COLLECT))) {
00746         if (value4 != NULL) {
00747         comp->steps[comp->nbStep].value4 = (xmlChar *)
00748             (void *)xmlDictLookup(comp->dict, value4, -1);
00749         xmlFree(value4);
00750     } else
00751         comp->steps[comp->nbStep].value4 = NULL;
00752         if (value5 != NULL) {
00753         comp->steps[comp->nbStep].value5 = (xmlChar *)
00754             (void *)xmlDictLookup(comp->dict, value5, -1);
00755         xmlFree(value5);
00756     } else
00757         comp->steps[comp->nbStep].value5 = NULL;
00758     } else {
00759     comp->steps[comp->nbStep].value4 = value4;
00760     comp->steps[comp->nbStep].value5 = value5;
00761     }
00762     comp->steps[comp->nbStep].cache = NULL;
00763     return(comp->nbStep++);
00764 }
00765 
00773 static void
00774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
00775     int tmp;
00776 
00777 #ifndef LIBXML_THREAD_ENABLED
00778     /*
00779      * Since this manipulates possibly shared variables, this is
00780      * disabled if one detects that the library is used in a multithreaded
00781      * application
00782      */
00783     if (xmlXPathDisableOptimizer)
00784     return;
00785 #endif
00786 
00787     tmp = op->ch1;
00788     op->ch1 = op->ch2;
00789     op->ch2 = tmp;
00790 }
00791 
00792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)   \
00793     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),           \
00794                     (op), (val), (val2), (val3), (val4), (val5))
00795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)         \
00796     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,       \
00797                     (op), (val), (val2), (val3), (val4), (val5))
00798 
00799 #define PUSH_LEAVE_EXPR(op, val, val2)                  \
00800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
00801 
00802 #define PUSH_UNARY_EXPR(op, ch, val, val2)              \
00803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
00804 
00805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)           \
00806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),         \
00807             (val), (val2), 0 ,NULL ,NULL)
00808 
00809 /************************************************************************
00810  *                                  *
00811  *      XPath object cache structures               *
00812  *                                  *
00813  ************************************************************************/
00814 
00815 /* #define XP_DEFAULT_CACHE_ON */
00816 
00817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
00818 
00819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
00820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
00821 struct _xmlXPathContextCache {
00822     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
00823     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
00824     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
00825     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
00826     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
00827     int maxNodeset;
00828     int maxString;
00829     int maxBoolean;
00830     int maxNumber;
00831     int maxMisc;
00832 #ifdef XP_DEBUG_OBJ_USAGE
00833     int dbgCachedAll;
00834     int dbgCachedNodeset;
00835     int dbgCachedString;
00836     int dbgCachedBool;
00837     int dbgCachedNumber;
00838     int dbgCachedPoint;
00839     int dbgCachedRange;
00840     int dbgCachedLocset;
00841     int dbgCachedUsers;
00842     int dbgCachedXSLTTree;
00843     int dbgCachedUndefined;
00844 
00845 
00846     int dbgReusedAll;
00847     int dbgReusedNodeset;
00848     int dbgReusedString;
00849     int dbgReusedBool;
00850     int dbgReusedNumber;
00851     int dbgReusedPoint;
00852     int dbgReusedRange;
00853     int dbgReusedLocset;
00854     int dbgReusedUsers;
00855     int dbgReusedXSLTTree;
00856     int dbgReusedUndefined;
00857 
00858 #endif
00859 };
00860 
00861 /************************************************************************
00862  *                                  *
00863  *      Debugging related functions             *
00864  *                                  *
00865  ************************************************************************/
00866 
00867 #define STRANGE                         \
00868     xmlGenericError(xmlGenericErrorContext,             \
00869         "Internal error at %s:%d\n",                \
00870             __FILE__, __LINE__);
00871 
00872 #ifdef LIBXML_DEBUG_ENABLED
00873 static void
00874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
00875     int i;
00876     char shift[100];
00877 
00878     for (i = 0;((i < depth) && (i < 25));i++)
00879         shift[2 * i] = shift[2 * i + 1] = ' ';
00880     shift[2 * i] = shift[2 * i + 1] = 0;
00881     if (cur == NULL) {
00882     fprintf(output, "%s", shift);
00883     fprintf(output, "Node is NULL !\n");
00884     return;
00885 
00886     }
00887 
00888     if ((cur->type == XML_DOCUMENT_NODE) ||
00889          (cur->type == XML_HTML_DOCUMENT_NODE)) {
00890     fprintf(output, "%s", shift);
00891     fprintf(output, " /\n");
00892     } else if (cur->type == XML_ATTRIBUTE_NODE)
00893     xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
00894     else
00895     xmlDebugDumpOneNode(output, cur, depth);
00896 }
00897 static void
00898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
00899     xmlNodePtr tmp;
00900     int i;
00901     char shift[100];
00902 
00903     for (i = 0;((i < depth) && (i < 25));i++)
00904         shift[2 * i] = shift[2 * i + 1] = ' ';
00905     shift[2 * i] = shift[2 * i + 1] = 0;
00906     if (cur == NULL) {
00907     fprintf(output, "%s", shift);
00908     fprintf(output, "Node is NULL !\n");
00909     return;
00910 
00911     }
00912 
00913     while (cur != NULL) {
00914     tmp = cur;
00915     cur = cur->next;
00916     xmlDebugDumpOneNode(output, tmp, depth);
00917     }
00918 }
00919 
00920 static void
00921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
00922     int i;
00923     char shift[100];
00924 
00925     for (i = 0;((i < depth) && (i < 25));i++)
00926         shift[2 * i] = shift[2 * i + 1] = ' ';
00927     shift[2 * i] = shift[2 * i + 1] = 0;
00928 
00929     if (cur == NULL) {
00930     fprintf(output, "%s", shift);
00931     fprintf(output, "NodeSet is NULL !\n");
00932     return;
00933 
00934     }
00935 
00936     if (cur != NULL) {
00937     fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
00938     for (i = 0;i < cur->nodeNr;i++) {
00939         fprintf(output, "%s", shift);
00940         fprintf(output, "%d", i + 1);
00941         xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
00942     }
00943     }
00944 }
00945 
00946 static void
00947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
00948     int i;
00949     char shift[100];
00950 
00951     for (i = 0;((i < depth) && (i < 25));i++)
00952         shift[2 * i] = shift[2 * i + 1] = ' ';
00953     shift[2 * i] = shift[2 * i + 1] = 0;
00954 
00955     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
00956     fprintf(output, "%s", shift);
00957     fprintf(output, "Value Tree is NULL !\n");
00958     return;
00959 
00960     }
00961 
00962     fprintf(output, "%s", shift);
00963     fprintf(output, "%d", i + 1);
00964     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
00965 }
00966 #if defined(LIBXML_XPTR_ENABLED)
00967 static void
00968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
00969     int i;
00970     char shift[100];
00971 
00972     for (i = 0;((i < depth) && (i < 25));i++)
00973         shift[2 * i] = shift[2 * i + 1] = ' ';
00974     shift[2 * i] = shift[2 * i + 1] = 0;
00975 
00976     if (cur == NULL) {
00977     fprintf(output, "%s", shift);
00978     fprintf(output, "LocationSet is NULL !\n");
00979     return;
00980 
00981     }
00982 
00983     for (i = 0;i < cur->locNr;i++) {
00984     fprintf(output, "%s", shift);
00985         fprintf(output, "%d : ", i + 1);
00986     xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
00987     }
00988 }
00989 #endif /* LIBXML_XPTR_ENABLED */
00990 
00999 void
01000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
01001     int i;
01002     char shift[100];
01003 
01004     if (output == NULL) return;
01005 
01006     for (i = 0;((i < depth) && (i < 25));i++)
01007         shift[2 * i] = shift[2 * i + 1] = ' ';
01008     shift[2 * i] = shift[2 * i + 1] = 0;
01009 
01010 
01011     fprintf(output, "%s", shift);
01012 
01013     if (cur == NULL) {
01014         fprintf(output, "Object is empty (NULL)\n");
01015     return;
01016     }
01017     switch(cur->type) {
01018         case XPATH_UNDEFINED:
01019         fprintf(output, "Object is uninitialized\n");
01020         break;
01021         case XPATH_NODESET:
01022         fprintf(output, "Object is a Node Set :\n");
01023         xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
01024         break;
01025     case XPATH_XSLT_TREE:
01026         fprintf(output, "Object is an XSLT value tree :\n");
01027         xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
01028         break;
01029         case XPATH_BOOLEAN:
01030         fprintf(output, "Object is a Boolean : ");
01031         if (cur->boolval) fprintf(output, "true\n");
01032         else fprintf(output, "false\n");
01033         break;
01034         case XPATH_NUMBER:
01035         switch (xmlXPathIsInf(cur->floatval)) {
01036         case 1:
01037         fprintf(output, "Object is a number : Infinity\n");
01038         break;
01039         case -1:
01040         fprintf(output, "Object is a number : -Infinity\n");
01041         break;
01042         default:
01043         if (xmlXPathIsNaN(cur->floatval)) {
01044             fprintf(output, "Object is a number : NaN\n");
01045         } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
01046             fprintf(output, "Object is a number : 0\n");
01047         } else {
01048             fprintf(output, "Object is a number : %0g\n", cur->floatval);
01049         }
01050         }
01051         break;
01052         case XPATH_STRING:
01053         fprintf(output, "Object is a string : ");
01054         xmlDebugDumpString(output, cur->stringval);
01055         fprintf(output, "\n");
01056         break;
01057     case XPATH_POINT:
01058         fprintf(output, "Object is a point : index %d in node", cur->index);
01059         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
01060         fprintf(output, "\n");
01061         break;
01062     case XPATH_RANGE:
01063         if ((cur->user2 == NULL) ||
01064         ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
01065         fprintf(output, "Object is a collapsed range :\n");
01066         fprintf(output, "%s", shift);
01067         if (cur->index >= 0)
01068             fprintf(output, "index %d in ", cur->index);
01069         fprintf(output, "node\n");
01070         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
01071                           depth + 1);
01072         } else  {
01073         fprintf(output, "Object is a range :\n");
01074         fprintf(output, "%s", shift);
01075         fprintf(output, "From ");
01076         if (cur->index >= 0)
01077             fprintf(output, "index %d in ", cur->index);
01078         fprintf(output, "node\n");
01079         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
01080                           depth + 1);
01081         fprintf(output, "%s", shift);
01082         fprintf(output, "To ");
01083         if (cur->index2 >= 0)
01084             fprintf(output, "index %d in ", cur->index2);
01085         fprintf(output, "node\n");
01086         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
01087                           depth + 1);
01088         fprintf(output, "\n");
01089         }
01090         break;
01091     case XPATH_LOCATIONSET:
01092 #if defined(LIBXML_XPTR_ENABLED)
01093         fprintf(output, "Object is a Location Set:\n");
01094         xmlXPathDebugDumpLocationSet(output,
01095             (xmlLocationSetPtr) cur->user, depth);
01096 #endif
01097         break;
01098     case XPATH_USERS:
01099         fprintf(output, "Object is user defined\n");
01100         break;
01101     }
01102 }
01103 
01104 static void
01105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
01106                          xmlXPathStepOpPtr op, int depth) {
01107     int i;
01108     char shift[100];
01109 
01110     for (i = 0;((i < depth) && (i < 25));i++)
01111         shift[2 * i] = shift[2 * i + 1] = ' ';
01112     shift[2 * i] = shift[2 * i + 1] = 0;
01113 
01114     fprintf(output, "%s", shift);
01115     if (op == NULL) {
01116     fprintf(output, "Step is NULL\n");
01117     return;
01118     }
01119     switch (op->op) {
01120         case XPATH_OP_END:
01121         fprintf(output, "END"); break;
01122         case XPATH_OP_AND:
01123         fprintf(output, "AND"); break;
01124         case XPATH_OP_OR:
01125         fprintf(output, "OR"); break;
01126         case XPATH_OP_EQUAL:
01127          if (op->value)
01128          fprintf(output, "EQUAL =");
01129          else
01130          fprintf(output, "EQUAL !=");
01131          break;
01132         case XPATH_OP_CMP:
01133          if (op->value)
01134          fprintf(output, "CMP <");
01135          else
01136          fprintf(output, "CMP >");
01137          if (!op->value2)
01138          fprintf(output, "=");
01139          break;
01140         case XPATH_OP_PLUS:
01141          if (op->value == 0)
01142          fprintf(output, "PLUS -");
01143          else if (op->value == 1)
01144          fprintf(output, "PLUS +");
01145          else if (op->value == 2)
01146          fprintf(output, "PLUS unary -");
01147          else if (op->value == 3)
01148          fprintf(output, "PLUS unary - -");
01149          break;
01150         case XPATH_OP_MULT:
01151          if (op->value == 0)
01152          fprintf(output, "MULT *");
01153          else if (op->value == 1)
01154          fprintf(output, "MULT div");
01155          else
01156          fprintf(output, "MULT mod");
01157          break;
01158         case XPATH_OP_UNION:
01159          fprintf(output, "UNION"); break;
01160         case XPATH_OP_ROOT:
01161          fprintf(output, "ROOT"); break;
01162         case XPATH_OP_NODE:
01163          fprintf(output, "NODE"); break;
01164         case XPATH_OP_RESET:
01165          fprintf(output, "RESET"); break;
01166         case XPATH_OP_SORT:
01167          fprintf(output, "SORT"); break;
01168         case XPATH_OP_COLLECT: {
01169         xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
01170         xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
01171         xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
01172         const xmlChar *prefix = op->value4;
01173         const xmlChar *name = op->value5;
01174 
01175         fprintf(output, "COLLECT ");
01176         switch (axis) {
01177         case AXIS_ANCESTOR:
01178             fprintf(output, " 'ancestors' "); break;
01179         case AXIS_ANCESTOR_OR_SELF:
01180             fprintf(output, " 'ancestors-or-self' "); break;
01181         case AXIS_ATTRIBUTE:
01182             fprintf(output, " 'attributes' "); break;
01183         case AXIS_CHILD:
01184             fprintf(output, " 'child' "); break;
01185         case AXIS_DESCENDANT:
01186             fprintf(output, " 'descendant' "); break;
01187         case AXIS_DESCENDANT_OR_SELF:
01188             fprintf(output, " 'descendant-or-self' "); break;
01189         case AXIS_FOLLOWING:
01190             fprintf(output, " 'following' "); break;
01191         case AXIS_FOLLOWING_SIBLING:
01192             fprintf(output, " 'following-siblings' "); break;
01193         case AXIS_NAMESPACE:
01194             fprintf(output, " 'namespace' "); break;
01195         case AXIS_PARENT:
01196             fprintf(output, " 'parent' "); break;
01197         case AXIS_PRECEDING:
01198             fprintf(output, " 'preceding' "); break;
01199         case AXIS_PRECEDING_SIBLING:
01200             fprintf(output, " 'preceding-sibling' "); break;
01201         case AXIS_SELF:
01202             fprintf(output, " 'self' "); break;
01203         }
01204         switch (test) {
01205                 case NODE_TEST_NONE:
01206             fprintf(output, "'none' "); break;
01207                 case NODE_TEST_TYPE:
01208             fprintf(output, "'type' "); break;
01209                 case NODE_TEST_PI:
01210             fprintf(output, "'PI' "); break;
01211                 case NODE_TEST_ALL:
01212             fprintf(output, "'all' "); break;
01213                 case NODE_TEST_NS:
01214             fprintf(output, "'namespace' "); break;
01215                 case NODE_TEST_NAME:
01216             fprintf(output, "'name' "); break;
01217         }
01218         switch (type) {
01219                 case NODE_TYPE_NODE:
01220             fprintf(output, "'node' "); break;
01221                 case NODE_TYPE_COMMENT:
01222             fprintf(output, "'comment' "); break;
01223                 case NODE_TYPE_TEXT:
01224             fprintf(output, "'text' "); break;
01225                 case NODE_TYPE_PI:
01226             fprintf(output, "'PI' "); break;
01227         }
01228         if (prefix != NULL)
01229         fprintf(output, "%s:", prefix);
01230         if (name != NULL)
01231         fprintf(output, "%s", (const char *) name);
01232         break;
01233 
01234         }
01235     case XPATH_OP_VALUE: {
01236         xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
01237 
01238         fprintf(output, "ELEM ");
01239         xmlXPathDebugDumpObject(output, object, 0);
01240         goto finish;
01241     }
01242     case XPATH_OP_VARIABLE: {
01243         const xmlChar *prefix = op->value5;
01244         const xmlChar *name = op->value4;
01245 
01246         if (prefix != NULL)
01247         fprintf(output, "VARIABLE %s:%s", prefix, name);
01248         else
01249         fprintf(output, "VARIABLE %s", name);
01250         break;
01251     }
01252     case XPATH_OP_FUNCTION: {
01253         int nbargs = op->value;
01254         const xmlChar *prefix = op->value5;
01255         const xmlChar *name = op->value4;
01256 
01257         if (prefix != NULL)
01258         fprintf(output, "FUNCTION %s:%s(%d args)",
01259             prefix, name, nbargs);
01260         else
01261         fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
01262         break;
01263     }
01264         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
01265         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
01266         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
01267 #ifdef LIBXML_XPTR_ENABLED
01268         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
01269 #endif
01270     default:
01271         fprintf(output, "UNKNOWN %d\n", op->op); return;
01272     }
01273     fprintf(output, "\n");
01274 finish:
01275     if (op->ch1 >= 0)
01276     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
01277     if (op->ch2 >= 0)
01278     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
01279 }
01280 
01289 void
01290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
01291                       int depth) {
01292     int i;
01293     char shift[100];
01294 
01295     if ((output == NULL) || (comp == NULL)) return;
01296 
01297     for (i = 0;((i < depth) && (i < 25));i++)
01298         shift[2 * i] = shift[2 * i + 1] = ' ';
01299     shift[2 * i] = shift[2 * i + 1] = 0;
01300 
01301     fprintf(output, "%s", shift);
01302 
01303     fprintf(output, "Compiled Expression : %d elements\n",
01304         comp->nbStep);
01305     i = comp->last;
01306     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
01307 }
01308 
01309 #ifdef XP_DEBUG_OBJ_USAGE
01310 
01311 /*
01312 * XPath object usage related debugging variables.
01313 */
01314 static int xmlXPathDebugObjCounterUndefined = 0;
01315 static int xmlXPathDebugObjCounterNodeset = 0;
01316 static int xmlXPathDebugObjCounterBool = 0;
01317 static int xmlXPathDebugObjCounterNumber = 0;
01318 static int xmlXPathDebugObjCounterString = 0;
01319 static int xmlXPathDebugObjCounterPoint = 0;
01320 static int xmlXPathDebugObjCounterRange = 0;
01321 static int xmlXPathDebugObjCounterLocset = 0;
01322 static int xmlXPathDebugObjCounterUsers = 0;
01323 static int xmlXPathDebugObjCounterXSLTTree = 0;
01324 static int xmlXPathDebugObjCounterAll = 0;
01325 
01326 static int xmlXPathDebugObjTotalUndefined = 0;
01327 static int xmlXPathDebugObjTotalNodeset = 0;
01328 static int xmlXPathDebugObjTotalBool = 0;
01329 static int xmlXPathDebugObjTotalNumber = 0;
01330 static int xmlXPathDebugObjTotalString = 0;
01331 static int xmlXPathDebugObjTotalPoint = 0;
01332 static int xmlXPathDebugObjTotalRange = 0;
01333 static int xmlXPathDebugObjTotalLocset = 0;
01334 static int xmlXPathDebugObjTotalUsers = 0;
01335 static int xmlXPathDebugObjTotalXSLTTree = 0;
01336 static int xmlXPathDebugObjTotalAll = 0;
01337 
01338 static int xmlXPathDebugObjMaxUndefined = 0;
01339 static int xmlXPathDebugObjMaxNodeset = 0;
01340 static int xmlXPathDebugObjMaxBool = 0;
01341 static int xmlXPathDebugObjMaxNumber = 0;
01342 static int xmlXPathDebugObjMaxString = 0;
01343 static int xmlXPathDebugObjMaxPoint = 0;
01344 static int xmlXPathDebugObjMaxRange = 0;
01345 static int xmlXPathDebugObjMaxLocset = 0;
01346 static int xmlXPathDebugObjMaxUsers = 0;
01347 static int xmlXPathDebugObjMaxXSLTTree = 0;
01348 static int xmlXPathDebugObjMaxAll = 0;
01349 
01350 /* REVISIT TODO: Make this static when committing */
01351 static void
01352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
01353 {
01354     if (ctxt != NULL) {
01355     if (ctxt->cache != NULL) {
01356         xmlXPathContextCachePtr cache =
01357         (xmlXPathContextCachePtr) ctxt->cache;
01358 
01359         cache->dbgCachedAll = 0;
01360         cache->dbgCachedNodeset = 0;
01361         cache->dbgCachedString = 0;
01362         cache->dbgCachedBool = 0;
01363         cache->dbgCachedNumber = 0;
01364         cache->dbgCachedPoint = 0;
01365         cache->dbgCachedRange = 0;
01366         cache->dbgCachedLocset = 0;
01367         cache->dbgCachedUsers = 0;
01368         cache->dbgCachedXSLTTree = 0;
01369         cache->dbgCachedUndefined = 0;
01370 
01371         cache->dbgReusedAll = 0;
01372         cache->dbgReusedNodeset = 0;
01373         cache->dbgReusedString = 0;
01374         cache->dbgReusedBool = 0;
01375         cache->dbgReusedNumber = 0;
01376         cache->dbgReusedPoint = 0;
01377         cache->dbgReusedRange = 0;
01378         cache->dbgReusedLocset = 0;
01379         cache->dbgReusedUsers = 0;
01380         cache->dbgReusedXSLTTree = 0;
01381         cache->dbgReusedUndefined = 0;
01382     }
01383     }
01384 
01385     xmlXPathDebugObjCounterUndefined = 0;
01386     xmlXPathDebugObjCounterNodeset = 0;
01387     xmlXPathDebugObjCounterBool = 0;
01388     xmlXPathDebugObjCounterNumber = 0;
01389     xmlXPathDebugObjCounterString = 0;
01390     xmlXPathDebugObjCounterPoint = 0;
01391     xmlXPathDebugObjCounterRange = 0;
01392     xmlXPathDebugObjCounterLocset = 0;
01393     xmlXPathDebugObjCounterUsers = 0;
01394     xmlXPathDebugObjCounterXSLTTree = 0;
01395     xmlXPathDebugObjCounterAll = 0;
01396 
01397     xmlXPathDebugObjTotalUndefined = 0;
01398     xmlXPathDebugObjTotalNodeset = 0;
01399     xmlXPathDebugObjTotalBool = 0;
01400     xmlXPathDebugObjTotalNumber = 0;
01401     xmlXPathDebugObjTotalString = 0;
01402     xmlXPathDebugObjTotalPoint = 0;
01403     xmlXPathDebugObjTotalRange = 0;
01404     xmlXPathDebugObjTotalLocset = 0;
01405     xmlXPathDebugObjTotalUsers = 0;
01406     xmlXPathDebugObjTotalXSLTTree = 0;
01407     xmlXPathDebugObjTotalAll = 0;
01408 
01409     xmlXPathDebugObjMaxUndefined = 0;
01410     xmlXPathDebugObjMaxNodeset = 0;
01411     xmlXPathDebugObjMaxBool = 0;
01412     xmlXPathDebugObjMaxNumber = 0;
01413     xmlXPathDebugObjMaxString = 0;
01414     xmlXPathDebugObjMaxPoint = 0;
01415     xmlXPathDebugObjMaxRange = 0;
01416     xmlXPathDebugObjMaxLocset = 0;
01417     xmlXPathDebugObjMaxUsers = 0;
01418     xmlXPathDebugObjMaxXSLTTree = 0;
01419     xmlXPathDebugObjMaxAll = 0;
01420 
01421 }
01422 
01423 static void
01424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
01425                   xmlXPathObjectType objType)
01426 {
01427     int isCached = 0;
01428 
01429     if (ctxt != NULL) {
01430     if (ctxt->cache != NULL) {
01431         xmlXPathContextCachePtr cache =
01432         (xmlXPathContextCachePtr) ctxt->cache;
01433 
01434         isCached = 1;
01435 
01436         cache->dbgReusedAll++;
01437         switch (objType) {
01438         case XPATH_UNDEFINED:
01439             cache->dbgReusedUndefined++;
01440             break;
01441         case XPATH_NODESET:
01442             cache->dbgReusedNodeset++;
01443             break;
01444         case XPATH_BOOLEAN:
01445             cache->dbgReusedBool++;
01446             break;
01447         case XPATH_NUMBER:
01448             cache->dbgReusedNumber++;
01449             break;
01450         case XPATH_STRING:
01451             cache->dbgReusedString++;
01452             break;
01453         case XPATH_POINT:
01454             cache->dbgReusedPoint++;
01455             break;
01456         case XPATH_RANGE:
01457             cache->dbgReusedRange++;
01458             break;
01459         case XPATH_LOCATIONSET:
01460             cache->dbgReusedLocset++;
01461             break;
01462         case XPATH_USERS:
01463             cache->dbgReusedUsers++;
01464             break;
01465         case XPATH_XSLT_TREE:
01466             cache->dbgReusedXSLTTree++;
01467             break;
01468         default:
01469             break;
01470         }
01471     }
01472     }
01473 
01474     switch (objType) {
01475     case XPATH_UNDEFINED:
01476         if (! isCached)
01477         xmlXPathDebugObjTotalUndefined++;
01478         xmlXPathDebugObjCounterUndefined++;
01479         if (xmlXPathDebugObjCounterUndefined >
01480         xmlXPathDebugObjMaxUndefined)
01481         xmlXPathDebugObjMaxUndefined =
01482             xmlXPathDebugObjCounterUndefined;
01483         break;
01484     case XPATH_NODESET:
01485         if (! isCached)
01486         xmlXPathDebugObjTotalNodeset++;
01487         xmlXPathDebugObjCounterNodeset++;
01488         if (xmlXPathDebugObjCounterNodeset >
01489         xmlXPathDebugObjMaxNodeset)
01490         xmlXPathDebugObjMaxNodeset =
01491             xmlXPathDebugObjCounterNodeset;
01492         break;
01493     case XPATH_BOOLEAN:
01494         if (! isCached)
01495         xmlXPathDebugObjTotalBool++;
01496         xmlXPathDebugObjCounterBool++;
01497         if (xmlXPathDebugObjCounterBool >
01498         xmlXPathDebugObjMaxBool)
01499         xmlXPathDebugObjMaxBool =
01500             xmlXPathDebugObjCounterBool;
01501         break;
01502     case XPATH_NUMBER:
01503         if (! isCached)
01504         xmlXPathDebugObjTotalNumber++;
01505         xmlXPathDebugObjCounterNumber++;
01506         if (xmlXPathDebugObjCounterNumber >
01507         xmlXPathDebugObjMaxNumber)
01508         xmlXPathDebugObjMaxNumber =
01509             xmlXPathDebugObjCounterNumber;
01510         break;
01511     case XPATH_STRING:
01512         if (! isCached)
01513         xmlXPathDebugObjTotalString++;
01514         xmlXPathDebugObjCounterString++;
01515         if (xmlXPathDebugObjCounterString >
01516         xmlXPathDebugObjMaxString)
01517         xmlXPathDebugObjMaxString =
01518             xmlXPathDebugObjCounterString;
01519         break;
01520     case XPATH_POINT:
01521         if (! isCached)
01522         xmlXPathDebugObjTotalPoint++;
01523         xmlXPathDebugObjCounterPoint++;
01524         if (xmlXPathDebugObjCounterPoint >
01525         xmlXPathDebugObjMaxPoint)
01526         xmlXPathDebugObjMaxPoint =
01527             xmlXPathDebugObjCounterPoint;
01528         break;
01529     case XPATH_RANGE:
01530         if (! isCached)
01531         xmlXPathDebugObjTotalRange++;
01532         xmlXPathDebugObjCounterRange++;
01533         if (xmlXPathDebugObjCounterRange >
01534         xmlXPathDebugObjMaxRange)
01535         xmlXPathDebugObjMaxRange =
01536             xmlXPathDebugObjCounterRange;
01537         break;
01538     case XPATH_LOCATIONSET:
01539         if (! isCached)
01540         xmlXPathDebugObjTotalLocset++;
01541         xmlXPathDebugObjCounterLocset++;
01542         if (xmlXPathDebugObjCounterLocset >
01543         xmlXPathDebugObjMaxLocset)
01544         xmlXPathDebugObjMaxLocset =
01545             xmlXPathDebugObjCounterLocset;
01546         break;
01547     case XPATH_USERS:
01548         if (! isCached)
01549         xmlXPathDebugObjTotalUsers++;
01550         xmlXPathDebugObjCounterUsers++;
01551         if (xmlXPathDebugObjCounterUsers >
01552         xmlXPathDebugObjMaxUsers)
01553         xmlXPathDebugObjMaxUsers =
01554             xmlXPathDebugObjCounterUsers;
01555         break;
01556     case XPATH_XSLT_TREE:
01557         if (! isCached)
01558         xmlXPathDebugObjTotalXSLTTree++;
01559         xmlXPathDebugObjCounterXSLTTree++;
01560         if (xmlXPathDebugObjCounterXSLTTree >
01561         xmlXPathDebugObjMaxXSLTTree)
01562         xmlXPathDebugObjMaxXSLTTree =
01563             xmlXPathDebugObjCounterXSLTTree;
01564         break;
01565     default:
01566         break;
01567     }
01568     if (! isCached)
01569     xmlXPathDebugObjTotalAll++;
01570     xmlXPathDebugObjCounterAll++;
01571     if (xmlXPathDebugObjCounterAll >
01572     xmlXPathDebugObjMaxAll)
01573     xmlXPathDebugObjMaxAll =
01574         xmlXPathDebugObjCounterAll;
01575 }
01576 
01577 static void
01578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
01579                   xmlXPathObjectType objType)
01580 {
01581     int isCached = 0;
01582 
01583     if (ctxt != NULL) {
01584     if (ctxt->cache != NULL) {
01585         xmlXPathContextCachePtr cache =
01586         (xmlXPathContextCachePtr) ctxt->cache;
01587 
01588         isCached = 1;
01589 
01590         cache->dbgCachedAll++;
01591         switch (objType) {
01592         case XPATH_UNDEFINED:
01593             cache->dbgCachedUndefined++;
01594             break;
01595         case XPATH_NODESET:
01596             cache->dbgCachedNodeset++;
01597             break;
01598         case XPATH_BOOLEAN:
01599             cache->dbgCachedBool++;
01600             break;
01601         case XPATH_NUMBER:
01602             cache->dbgCachedNumber++;
01603             break;
01604         case XPATH_STRING:
01605             cache->dbgCachedString++;
01606             break;
01607         case XPATH_POINT:
01608             cache->dbgCachedPoint++;
01609             break;
01610         case XPATH_RANGE:
01611             cache->dbgCachedRange++;
01612             break;
01613         case XPATH_LOCATIONSET:
01614             cache->dbgCachedLocset++;
01615             break;
01616         case XPATH_USERS:
01617             cache->dbgCachedUsers++;
01618             break;
01619         case XPATH_XSLT_TREE:
01620             cache->dbgCachedXSLTTree++;
01621             break;
01622         default:
01623             break;
01624         }
01625 
01626     }
01627     }
01628     switch (objType) {
01629     case XPATH_UNDEFINED:
01630         xmlXPathDebugObjCounterUndefined--;
01631         break;
01632     case XPATH_NODESET:
01633         xmlXPathDebugObjCounterNodeset--;
01634         break;
01635     case XPATH_BOOLEAN:
01636         xmlXPathDebugObjCounterBool--;
01637         break;
01638     case XPATH_NUMBER:
01639         xmlXPathDebugObjCounterNumber--;
01640         break;
01641     case XPATH_STRING:
01642         xmlXPathDebugObjCounterString--;
01643         break;
01644     case XPATH_POINT:
01645         xmlXPathDebugObjCounterPoint--;
01646         break;
01647     case XPATH_RANGE:
01648         xmlXPathDebugObjCounterRange--;
01649         break;
01650     case XPATH_LOCATIONSET:
01651         xmlXPathDebugObjCounterLocset--;
01652         break;
01653     case XPATH_USERS:
01654         xmlXPathDebugObjCounterUsers--;
01655         break;
01656     case XPATH_XSLT_TREE:
01657         xmlXPathDebugObjCounterXSLTTree--;
01658         break;
01659     default:
01660         break;
01661     }
01662     xmlXPathDebugObjCounterAll--;
01663 }
01664 
01665 /* REVISIT TODO: Make this static when committing */
01666 static void
01667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
01668 {
01669     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
01670     reqXSLTTree, reqUndefined;
01671     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
01672     caNumber = 0, caXSLTTree = 0, caUndefined = 0;
01673     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
01674     reNumber = 0, reXSLTTree = 0, reUndefined = 0;
01675     int leftObjs = xmlXPathDebugObjCounterAll;
01676 
01677     reqAll = xmlXPathDebugObjTotalAll;
01678     reqNodeset = xmlXPathDebugObjTotalNodeset;
01679     reqString = xmlXPathDebugObjTotalString;
01680     reqBool = xmlXPathDebugObjTotalBool;
01681     reqNumber = xmlXPathDebugObjTotalNumber;
01682     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
01683     reqUndefined = xmlXPathDebugObjTotalUndefined;
01684 
01685     printf("# XPath object usage:\n");
01686 
01687     if (ctxt != NULL) {
01688     if (ctxt->cache != NULL) {
01689         xmlXPathContextCachePtr cache =
01690         (xmlXPathContextCachePtr) ctxt->cache;
01691 
01692         reAll = cache->dbgReusedAll;
01693         reqAll += reAll;
01694         reNodeset = cache->dbgReusedNodeset;
01695         reqNodeset += reNodeset;
01696         reString = cache->dbgReusedString;
01697         reqString += reString;
01698         reBool = cache->dbgReusedBool;
01699         reqBool += reBool;
01700         reNumber = cache->dbgReusedNumber;
01701         reqNumber += reNumber;
01702         reXSLTTree = cache->dbgReusedXSLTTree;
01703         reqXSLTTree += reXSLTTree;
01704         reUndefined = cache->dbgReusedUndefined;
01705         reqUndefined += reUndefined;
01706 
01707         caAll = cache->dbgCachedAll;
01708         caBool = cache->dbgCachedBool;
01709         caNodeset = cache->dbgCachedNodeset;
01710         caString = cache->dbgCachedString;
01711         caNumber = cache->dbgCachedNumber;
01712         caXSLTTree = cache->dbgCachedXSLTTree;
01713         caUndefined = cache->dbgCachedUndefined;
01714 
01715         if (cache->nodesetObjs)
01716         leftObjs -= cache->nodesetObjs->number;
01717         if (cache->stringObjs)
01718         leftObjs -= cache->stringObjs->number;
01719         if (cache->booleanObjs)
01720         leftObjs -= cache->booleanObjs->number;
01721         if (cache->numberObjs)
01722         leftObjs -= cache->numberObjs->number;
01723         if (cache->miscObjs)
01724         leftObjs -= cache->miscObjs->number;
01725     }
01726     }
01727 
01728     printf("# all\n");
01729     printf("#   total  : %d\n", reqAll);
01730     printf("#   left  : %d\n", leftObjs);
01731     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
01732     printf("#   reused : %d\n", reAll);
01733     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
01734 
01735     printf("# node-sets\n");
01736     printf("#   total  : %d\n", reqNodeset);
01737     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
01738     printf("#   reused : %d\n", reNodeset);
01739     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
01740 
01741     printf("# strings\n");
01742     printf("#   total  : %d\n", reqString);
01743     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
01744     printf("#   reused : %d\n", reString);
01745     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
01746 
01747     printf("# booleans\n");
01748     printf("#   total  : %d\n", reqBool);
01749     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
01750     printf("#   reused : %d\n", reBool);
01751     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
01752 
01753     printf("# numbers\n");
01754     printf("#   total  : %d\n", reqNumber);
01755     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
01756     printf("#   reused : %d\n", reNumber);
01757     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
01758 
01759     printf("# XSLT result tree fragments\n");
01760     printf("#   total  : %d\n", reqXSLTTree);
01761     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
01762     printf("#   reused : %d\n", reXSLTTree);
01763     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
01764 
01765     printf("# undefined\n");
01766     printf("#   total  : %d\n", reqUndefined);
01767     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
01768     printf("#   reused : %d\n", reUndefined);
01769     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
01770 
01771 }
01772 
01773 #endif /* XP_DEBUG_OBJ_USAGE */
01774 
01775 #endif /* LIBXML_DEBUG_ENABLED */
01776 
01777 /************************************************************************
01778  *                                  *
01779  *          XPath object caching                *
01780  *                                  *
01781  ************************************************************************/
01782 
01790 static xmlXPathContextCachePtr
01791 xmlXPathNewCache(void)
01792 {
01793     xmlXPathContextCachePtr ret;
01794 
01795     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
01796     if (ret == NULL) {
01797         xmlXPathErrMemory(NULL, "creating object cache\n");
01798     return(NULL);
01799     }
01800     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
01801     ret->maxNodeset = 100;
01802     ret->maxString = 100;
01803     ret->maxBoolean = 100;
01804     ret->maxNumber = 100;
01805     ret->maxMisc = 100;
01806     return(ret);
01807 }
01808 
01809 static void
01810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
01811 {
01812     int i;
01813     xmlXPathObjectPtr obj;
01814 
01815     if (list == NULL)
01816     return;
01817 
01818     for (i = 0; i < list->number; i++) {
01819     obj = list->items[i];
01820     /*
01821     * Note that it is already assured that we don't need to
01822     * look out for namespace nodes in the node-set.
01823     */
01824     if (obj->nodesetval != NULL) {
01825         if (obj->nodesetval->nodeTab != NULL)
01826         xmlFree(obj->nodesetval->nodeTab);
01827         xmlFree(obj->nodesetval);
01828     }
01829     xmlFree(obj);
01830 #ifdef XP_DEBUG_OBJ_USAGE
01831     xmlXPathDebugObjCounterAll--;
01832 #endif
01833     }
01834     xmlPointerListFree(list);
01835 }
01836 
01837 static void
01838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
01839 {
01840     if (cache == NULL)
01841     return;
01842     if (cache->nodesetObjs)
01843     xmlXPathCacheFreeObjectList(cache->nodesetObjs);
01844     if (cache->stringObjs)
01845     xmlXPathCacheFreeObjectList(cache->stringObjs);
01846     if (cache->booleanObjs)
01847     xmlXPathCacheFreeObjectList(cache->booleanObjs);
01848     if (cache->numberObjs)
01849     xmlXPathCacheFreeObjectList(cache->numberObjs);
01850     if (cache->miscObjs)
01851     xmlXPathCacheFreeObjectList(cache->miscObjs);
01852     xmlFree(cache);
01853 }
01854 
01877 int
01878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
01879             int active,
01880             int value,
01881             int options)
01882 {
01883     if (ctxt == NULL)
01884     return(-1);
01885     if (active) {
01886     xmlXPathContextCachePtr cache;
01887 
01888     if (ctxt->cache == NULL) {
01889         ctxt->cache = xmlXPathNewCache();
01890         if (ctxt->cache == NULL)
01891         return(-1);
01892     }
01893     cache = (xmlXPathContextCachePtr) ctxt->cache;
01894     if (options == 0) {
01895         if (value < 0)
01896         value = 100;
01897         cache->maxNodeset = value;
01898         cache->maxString = value;
01899         cache->maxNumber = value;
01900         cache->maxBoolean = value;
01901         cache->maxMisc = value;
01902     }
01903     } else if (ctxt->cache != NULL) {
01904     xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
01905     ctxt->cache = NULL;
01906     }
01907     return(0);
01908 }
01909 
01920 static xmlXPathObjectPtr
01921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
01922 {
01923     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
01924     xmlXPathContextCachePtr cache =
01925         (xmlXPathContextCachePtr) ctxt->cache;
01926 
01927     if ((cache->miscObjs != NULL) &&
01928         (cache->miscObjs->number != 0))
01929     {
01930         xmlXPathObjectPtr ret;
01931 
01932         ret = (xmlXPathObjectPtr)
01933         cache->miscObjs->items[--cache->miscObjs->number];
01934         ret->type = XPATH_NODESET;
01935         ret->nodesetval = val;
01936 #ifdef XP_DEBUG_OBJ_USAGE
01937         xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
01938 #endif
01939         return(ret);
01940     }
01941     }
01942 
01943     return(xmlXPathWrapNodeSet(val));
01944 
01945 }
01946 
01957 static xmlXPathObjectPtr
01958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
01959 {
01960     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
01961     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
01962 
01963     if ((cache->stringObjs != NULL) &&
01964         (cache->stringObjs->number != 0))
01965     {
01966 
01967         xmlXPathObjectPtr ret;
01968 
01969         ret = (xmlXPathObjectPtr)
01970         cache->stringObjs->items[--cache->stringObjs->number];
01971         ret->type = XPATH_STRING;
01972         ret->stringval = val;
01973 #ifdef XP_DEBUG_OBJ_USAGE
01974         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
01975 #endif
01976         return(ret);
01977     } else if ((cache->miscObjs != NULL) &&
01978         (cache->miscObjs->number != 0))
01979     {
01980         xmlXPathObjectPtr ret;
01981         /*
01982         * Fallback to misc-cache.
01983         */
01984         ret = (xmlXPathObjectPtr)
01985         cache->miscObjs->items[--cache->miscObjs->number];
01986 
01987         ret->type = XPATH_STRING;
01988         ret->stringval = val;
01989 #ifdef XP_DEBUG_OBJ_USAGE
01990         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
01991 #endif
01992         return(ret);
01993     }
01994     }
01995     return(xmlXPathWrapString(val));
01996 }
01997 
02009 static xmlXPathObjectPtr
02010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
02011 {
02012     if ((ctxt != NULL) && (ctxt->cache)) {
02013     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
02014 
02015     if ((cache->nodesetObjs != NULL) &&
02016         (cache->nodesetObjs->number != 0))
02017     {
02018         xmlXPathObjectPtr ret;
02019         /*
02020         * Use the nodset-cache.
02021         */
02022         ret = (xmlXPathObjectPtr)
02023         cache->nodesetObjs->items[--cache->nodesetObjs->number];
02024         ret->type = XPATH_NODESET;
02025         ret->boolval = 0;
02026         if (val) {
02027         if ((ret->nodesetval->nodeMax == 0) ||
02028             (val->type == XML_NAMESPACE_DECL))
02029         {
02030             xmlXPathNodeSetAddUnique(ret->nodesetval, val);
02031         } else {
02032             ret->nodesetval->nodeTab[0] = val;
02033             ret->nodesetval->nodeNr = 1;
02034         }
02035         }
02036 #ifdef XP_DEBUG_OBJ_USAGE
02037         xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
02038 #endif
02039         return(ret);
02040     } else if ((cache->miscObjs != NULL) &&
02041         (cache->miscObjs->number != 0))
02042     {
02043         xmlXPathObjectPtr ret;
02044         /*
02045         * Fallback to misc-cache.
02046         */
02047 
02048         ret = (xmlXPathObjectPtr)
02049         cache->miscObjs->items[--cache->miscObjs->number];
02050 
02051         ret->type = XPATH_NODESET;
02052         ret->boolval = 0;
02053         ret->nodesetval = xmlXPathNodeSetCreate(val);
02054 #ifdef XP_DEBUG_OBJ_USAGE
02055         xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
02056 #endif
02057         return(ret);
02058     }
02059     }
02060     return(xmlXPathNewNodeSet(val));
02061 }
02062 
02073 static xmlXPathObjectPtr
02074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
02075 {
02076     if ((ctxt != NULL) && (ctxt->cache)) {
02077     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
02078 
02079     if ((cache->stringObjs != NULL) &&
02080         (cache->stringObjs->number != 0))
02081     {
02082         xmlXPathObjectPtr ret;
02083 
02084         ret = (xmlXPathObjectPtr)
02085         cache->stringObjs->items[--cache->stringObjs->number];
02086 
02087         ret->type = XPATH_STRING;
02088         ret->stringval = xmlStrdup(BAD_CAST val);
02089 #ifdef XP_DEBUG_OBJ_USAGE
02090         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
02091 #endif
02092         return(ret);
02093     } else if ((cache->miscObjs != NULL) &&
02094         (cache->miscObjs->number != 0))
02095     {
02096         xmlXPathObjectPtr ret;
02097 
02098         ret = (xmlXPathObjectPtr)
02099         cache->miscObjs->items[--cache->miscObjs->number];
02100 
02101         ret->type = XPATH_STRING;
02102         ret->stringval = xmlStrdup(BAD_CAST val);
02103 #ifdef XP_DEBUG_OBJ_USAGE
02104         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
02105 #endif
02106         return(ret);
02107     }
02108     }
02109     return(xmlXPathNewCString(val));
02110 }
02111 
02122 static xmlXPathObjectPtr
02123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
02124 {
02125     if ((ctxt != NULL) && (ctxt->cache)) {
02126     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
02127 
02128     if ((cache->stringObjs != NULL) &&
02129         (cache->stringObjs->number != 0))
02130     {
02131         xmlXPathObjectPtr ret;
02132 
02133         ret = (xmlXPathObjectPtr)
02134         cache->stringObjs->items[--cache->stringObjs->number];
02135         ret->type = XPATH_STRING;
02136         if (val != NULL)
02137         ret->stringval = xmlStrdup(val);
02138         else
02139         ret->stringval = xmlStrdup((const xmlChar *)"");
02140 #ifdef XP_DEBUG_OBJ_USAGE
02141         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
02142 #endif
02143         return(ret);
02144     } else if ((cache->miscObjs != NULL) &&
02145         (cache->miscObjs->number != 0))
02146     {
02147         xmlXPathObjectPtr ret;
02148 
02149         ret = (xmlXPathObjectPtr)
02150         cache->miscObjs->items[--cache->miscObjs->number];
02151 
02152         ret->type = XPATH_STRING;
02153         if (val != NULL)
02154         ret->stringval = xmlStrdup(val);
02155         else
02156         ret->stringval = xmlStrdup((const xmlChar *)"");
02157 #ifdef XP_DEBUG_OBJ_USAGE
02158         xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
02159 #endif
02160         return(ret);
02161     }
02162     }
02163     return(xmlXPathNewString(val));
02164 }
02165 
02176 static xmlXPathObjectPtr
02177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
02178 {
02179     if ((ctxt != NULL) && (ctxt->cache)) {
02180     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
02181 
02182     if ((cache->booleanObjs != NULL) &&
02183         (cache->booleanObjs->number != 0))
02184     {
02185         xmlXPathObjectPtr ret;
02186 
02187         ret = (xmlXPathObjectPtr)
02188         cache->booleanObjs->items[--cache->booleanObjs->number];
02189         ret->type = XPATH_BOOLEAN;
02190         ret->boolval = (val != 0);
02191 #ifdef XP_DEBUG_OBJ_USAGE
02192         xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
02193 #endif
02194         return(ret);
02195     } else if ((cache->miscObjs != NULL) &&
02196         (cache->miscObjs->number != 0))
02197     {
02198         xmlXPathObjectPtr ret;
02199 
02200         ret = (xmlXPathObjectPtr)
02201         cache->miscObjs->items[--cache->miscObjs->number];
02202 
02203         ret->type = XPATH_BOOLEAN;
02204         ret->boolval = (val != 0);
02205 #ifdef XP_DEBUG_OBJ_USAGE
02206         xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
02207 #endif
02208         return(ret);
02209     }
02210     }
02211     return(xmlXPathNewBoolean(val));
02212 }
02213 
02224 static xmlXPathObjectPtr
02225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
02226 {
02227      if ((ctxt != NULL) && (ctxt->cache)) {
02228     xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
02229 
02230     if ((cache->numberObjs != NULL) &&
02231         (cache->numberObjs->number != 0))
02232     {
02233         xmlXPathObjectPtr ret;
02234 
02235         ret = (xmlXPathObjectPtr)
02236         cache->numberObjs->items[--cache->numberObjs->number];
02237         ret->type = XPATH_NUMBER;
02238         ret->floatval = val;
02239 #ifdef XP_DEBUG_OBJ_USAGE
02240         xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
02241 #endif
02242         return(ret);
02243     } else if ((cache->miscObjs != NULL) &&
02244         (cache->miscObjs->number != 0))
02245     {
02246         xmlXPathObjectPtr ret;
02247 
02248         ret = (xmlXPathObjectPtr)
02249         cache->miscObjs->items[--cache->miscObjs->number];
02250 
02251         ret->type = XPATH_NUMBER;
02252         ret->floatval = val;
02253 #ifdef XP_DEBUG_OBJ_USAGE
02254         xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
02255 #endif
02256         return(ret);
02257     }
02258     }
02259     return(xmlXPathNewFloat(val));
02260 }
02261 
02274 static xmlXPathObjectPtr
02275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
02276     xmlChar *res = NULL;
02277 
02278     if (val == NULL)
02279     return(xmlXPathCacheNewCString(ctxt, ""));
02280 
02281     switch (val->type) {
02282     case XPATH_UNDEFINED:
02283 #ifdef DEBUG_EXPR
02284     xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
02285 #endif
02286     break;
02287     case XPATH_NODESET:
02288     case XPATH_XSLT_TREE:
02289     res = xmlXPathCastNodeSetToString(val->nodesetval);
02290     break;
02291     case XPATH_STRING:
02292     return(val);
02293     case XPATH_BOOLEAN:
02294     res = xmlXPathCastBooleanToString(val->boolval);
02295     break;
02296     case XPATH_NUMBER:
02297     res = xmlXPathCastNumberToString(val->floatval);
02298     break;
02299     case XPATH_USERS:
02300     case XPATH_POINT:
02301     case XPATH_RANGE:
02302     case XPATH_LOCATIONSET:
02303     TODO;
02304     break;
02305     }
02306     xmlXPathReleaseObject(ctxt, val);
02307     if (res == NULL)
02308     return(xmlXPathCacheNewCString(ctxt, ""));
02309     return(xmlXPathCacheWrapString(ctxt, res));
02310 }
02311 
02322 static xmlXPathObjectPtr
02323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
02324 {
02325     if (val == NULL)
02326     return(NULL);
02327 
02328     if (XP_HAS_CACHE(ctxt)) {
02329     switch (val->type) {
02330         case XPATH_NODESET:
02331         return(xmlXPathCacheWrapNodeSet(ctxt,
02332             xmlXPathNodeSetMerge(NULL, val->nodesetval)));
02333         case XPATH_STRING:
02334         return(xmlXPathCacheNewString(ctxt, val->stringval));
02335         case XPATH_BOOLEAN:
02336         return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
02337         case XPATH_NUMBER:
02338         return(xmlXPathCacheNewFloat(ctxt, val->floatval));
02339         default:
02340         break;
02341     }
02342     }
02343     return(xmlXPathObjectCopy(val));
02344 }
02345 
02357 static xmlXPathObjectPtr
02358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
02359     xmlXPathObjectPtr ret;
02360 
02361     if (val == NULL)
02362     return(xmlXPathCacheNewBoolean(ctxt, 0));
02363     if (val->type == XPATH_BOOLEAN)
02364     return(val);
02365     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
02366     xmlXPathReleaseObject(ctxt, val);
02367     return(ret);
02368 }
02369 
02381 static xmlXPathObjectPtr
02382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
02383     xmlXPathObjectPtr ret;
02384 
02385     if (val == NULL)
02386     return(xmlXPathCacheNewFloat(ctxt, 0.0));
02387     if (val->type == XPATH_NUMBER)
02388     return(val);
02389     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
02390     xmlXPathReleaseObject(ctxt, val);
02391     return(ret);
02392 }
02393 
02394 /************************************************************************
02395  *                                  *
02396  *      Parser stacks related functions and macros      *
02397  *                                  *
02398  ************************************************************************/
02399 
02408 xmlXPathObjectPtr
02409 valuePop(xmlXPathParserContextPtr ctxt)
02410 {
02411     xmlXPathObjectPtr ret;
02412 
02413     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
02414         return (NULL);
02415     ctxt->valueNr--;
02416     if (ctxt->valueNr > 0)
02417         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
02418     else
02419         ctxt->value = NULL;
02420     ret = ctxt->valueTab[ctxt->valueNr];
02421     ctxt->valueTab[ctxt->valueNr] = NULL;
02422     return (ret);
02423 }
02433 int
02434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
02435 {
02436     if ((ctxt == NULL) || (value == NULL)) return(-1);
02437     if (ctxt->valueNr >= ctxt->valueMax) {
02438         xmlXPathObjectPtr *tmp;
02439 
02440         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
02441                                              2 * ctxt->valueMax *
02442                                              sizeof(ctxt->valueTab[0]));
02443         if (tmp == NULL) {
02444             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
02445             return (0);
02446         }
02447         ctxt->valueMax *= 2;
02448     ctxt->valueTab = tmp;
02449     }
02450     ctxt->valueTab[ctxt->valueNr] = value;
02451     ctxt->value = value;
02452     return (ctxt->valueNr++);
02453 }
02454 
02464 int
02465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
02466     xmlXPathObjectPtr obj;
02467     int ret;
02468 
02469     obj = valuePop(ctxt);
02470     if (obj == NULL) {
02471     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
02472     return(0);
02473     }
02474     if (obj->type != XPATH_BOOLEAN)
02475     ret = xmlXPathCastToBoolean(obj);
02476     else
02477         ret = obj->boolval;
02478     xmlXPathReleaseObject(ctxt->context, obj);
02479     return(ret);
02480 }
02481 
02491 double
02492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
02493     xmlXPathObjectPtr obj;
02494     double ret;
02495 
02496     obj = valuePop(ctxt);
02497     if (obj == NULL) {
02498     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
02499     return(0);
02500     }
02501     if (obj->type != XPATH_NUMBER)
02502     ret = xmlXPathCastToNumber(obj);
02503     else
02504         ret = obj->floatval;
02505     xmlXPathReleaseObject(ctxt->context, obj);
02506     return(ret);
02507 }
02508 
02518 xmlChar *
02519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
02520     xmlXPathObjectPtr obj;
02521     xmlChar * ret;
02522 
02523     obj = valuePop(ctxt);
02524     if (obj == NULL) {
02525     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
02526     return(NULL);
02527     }
02528     ret = xmlXPathCastToString(obj);    /* this does required strdup */
02529     /* TODO: needs refactoring somewhere else */
02530     if (obj->stringval == ret)
02531     obj->stringval = NULL;
02532     xmlXPathReleaseObject(ctxt->context, obj);
02533     return(ret);
02534 }
02535 
02545 xmlNodeSetPtr
02546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
02547     xmlXPathObjectPtr obj;
02548     xmlNodeSetPtr ret;
02549 
02550     if (ctxt == NULL) return(NULL);
02551     if (ctxt->value == NULL) {
02552     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
02553     return(NULL);
02554     }
02555     if (!xmlXPathStackIsNodeSet(ctxt)) {
02556     xmlXPathSetTypeError(ctxt);
02557     return(NULL);
02558     }
02559     obj = valuePop(ctxt);
02560     ret = obj->nodesetval;
02561 #if 0
02562     /* to fix memory leak of not clearing obj->user */
02563     if (obj->boolval && obj->user != NULL)
02564         xmlFreeNodeList((xmlNodePtr) obj->user);
02565 #endif
02566     obj->nodesetval = NULL;
02567     xmlXPathReleaseObject(ctxt->context, obj);
02568     return(ret);
02569 }
02570 
02580 void *
02581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
02582     xmlXPathObjectPtr obj;
02583     void * ret;
02584 
02585     if ((ctxt == NULL) || (ctxt->value == NULL)) {
02586     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
02587     return(NULL);
02588     }
02589     if (ctxt->value->type != XPATH_USERS) {
02590     xmlXPathSetTypeError(ctxt);
02591     return(NULL);
02592     }
02593     obj = valuePop(ctxt);
02594     ret = obj->user;
02595     obj->user = NULL;
02596     xmlXPathReleaseObject(ctxt->context, obj);
02597     return(ret);
02598 }
02599 
02600 /*
02601  * Macros for accessing the content. Those should be used only by the parser,
02602  * and not exported.
02603  *
02604  * Dirty macros, i.e. one need to make assumption on the context to use them
02605  *
02606  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
02607  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
02608  *           in ISO-Latin or UTF-8.
02609  *           This should be used internally by the parser
02610  *           only to compare to ASCII values otherwise it would break when
02611  *           running with UTF-8 encoding.
02612  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
02613  *           to compare on ASCII based substring.
02614  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
02615  *           strings within the parser.
02616  *   CURRENT Returns the current char value, with the full decoding of
02617  *           UTF-8 if we are using this mode. It returns an int.
02618  *   NEXT    Skip to the next character, this does the proper decoding
02619  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
02620  *           It returns the pointer to the current xmlChar.
02621  */
02622 
02623 #define CUR (*ctxt->cur)
02624 #define SKIP(val) ctxt->cur += (val)
02625 #define NXT(val) ctxt->cur[(val)]
02626 #define CUR_PTR ctxt->cur
02627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
02628 
02629 #define COPY_BUF(l,b,i,v)                                              \
02630     if (l == 1) b[i++] = (xmlChar) v;                                  \
02631     else i += xmlCopyChar(l,&b[i],v)
02632 
02633 #define NEXTL(l)  ctxt->cur += l
02634 
02635 #define SKIP_BLANKS                         \
02636     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
02637 
02638 #define CURRENT (*ctxt->cur)
02639 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
02640 
02641 
02642 #ifndef DBL_DIG
02643 #define DBL_DIG 16
02644 #endif
02645 #ifndef DBL_EPSILON
02646 #define DBL_EPSILON 1E-9
02647 #endif
02648 
02649 #define UPPER_DOUBLE 1E9
02650 #define LOWER_DOUBLE 1E-5
02651 #define LOWER_DOUBLE_EXP 5
02652 
02653 #define INTEGER_DIGITS DBL_DIG
02654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
02655 #define EXPONENT_DIGITS (3 + 2)
02656 
02665 static void
02666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
02667 {
02668     switch (xmlXPathIsInf(number)) {
02669     case 1:
02670     if (buffersize > (int)sizeof("Infinity"))
02671         snprintf(buffer, buffersize, "Infinity");
02672     break;
02673     case -1:
02674     if (buffersize > (int)sizeof("-Infinity"))
02675         snprintf(buffer, buffersize, "-Infinity");
02676     break;
02677     default:
02678     if (xmlXPathIsNaN(number)) {
02679         if (buffersize > (int)sizeof("NaN"))
02680         snprintf(buffer, buffersize, "NaN");
02681     } else if (number == 0 && xmlXPathGetSign(number) != 0) {
02682         snprintf(buffer, buffersize, "0");
02683     } else if (number == ((int) number)) {
02684         char work[30];
02685         char *ptr, *cur;
02686         int value = (int) number;
02687 
02688             ptr = &buffer[0];
02689         if (value == 0) {
02690         *ptr++ = '0';
02691         } else {
02692         snprintf(work, 29, "%d", value);
02693         cur = &work[0];
02694         while ((*cur) && (ptr - buffer < buffersize)) {
02695             *ptr++ = *cur++;
02696         }
02697         }
02698         if (ptr - buffer < buffersize) {
02699         *ptr = 0;
02700         } else if (buffersize > 0) {
02701         ptr--;
02702         *ptr = 0;
02703         }
02704     } else {
02705         /*
02706           For the dimension of work,
02707               DBL_DIG is number of significant digits
02708           EXPONENT is only needed for "scientific notation"
02709               3 is sign, decimal point, and terminating zero
02710           LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
02711           Note that this dimension is slightly (a few characters)
02712           larger than actually necessary.
02713         */
02714         char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
02715         int integer_place, fraction_place;
02716         char *ptr;
02717         char *after_fraction;
02718         double absolute_value;
02719         int size;
02720 
02721         absolute_value = fabs(number);
02722 
02723         /*
02724          * First choose format - scientific or regular floating point.
02725          * In either case, result is in work, and after_fraction points
02726          * just past the fractional part.
02727         */
02728         if ( ((absolute_value > UPPER_DOUBLE) ||
02729           (absolute_value < LOWER_DOUBLE)) &&
02730          (absolute_value != 0.0) ) {
02731         /* Use scientific notation */
02732         integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
02733         fraction_place = DBL_DIG - 1;
02734         size = snprintf(work, sizeof(work),"%*.*e",
02735              integer_place, fraction_place, number);
02736         while ((size > 0) && (work[size] != 'e')) size--;
02737 
02738         }
02739         else {
02740         /* Use regular notation */
02741         if (absolute_value > 0.0) {
02742             integer_place = (int)log10(absolute_value);
02743             if (integer_place > 0)
02744                 fraction_place = DBL_DIG - integer_place - 1;
02745             else
02746                 fraction_place = DBL_DIG - integer_place;
02747         } else {
02748             fraction_place = 1;
02749         }
02750         size = snprintf(work, sizeof(work), "%0.*f",
02751                 fraction_place, number);
02752         }
02753 
02754         /* Remove fractional trailing zeroes */
02755         after_fraction = work + size;
02756         ptr = after_fraction;
02757         while (*(--ptr) == '0')
02758         ;
02759         if (*ptr != '.')
02760             ptr++;
02761         while ((*ptr++ = *after_fraction++) != 0);
02762 
02763         /* Finally copy result back to caller */
02764         size = strlen(work) + 1;
02765         if (size > buffersize) {
02766         work[buffersize - 1] = 0;
02767         size = buffersize;
02768         }
02769         memmove(buffer, work, size);
02770     }
02771     break;
02772     }
02773 }
02774 
02775 
02776 /************************************************************************
02777  *                                  *
02778  *          Routines to handle NodeSets         *
02779  *                                  *
02780  ************************************************************************/
02781 
02795 long
02796 xmlXPathOrderDocElems(xmlDocPtr doc) {
02797     long count = 0;
02798     xmlNodePtr cur;
02799 
02800     if (doc == NULL)
02801     return(-1);
02802     cur = doc->children;
02803     while (cur != NULL) {
02804     if (cur->type == XML_ELEMENT_NODE) {
02805         cur->content = (void *) (-(++count));
02806         if (cur->children != NULL) {
02807         cur = cur->children;
02808         continue;
02809         }
02810     }
02811     if (cur->next != NULL) {
02812         cur = cur->next;
02813         continue;
02814     }
02815     do {
02816         cur = cur->parent;
02817         if (cur == NULL)
02818         break;
02819         if (cur == (xmlNodePtr) doc) {
02820         cur = NULL;
02821         break;
02822         }
02823         if (cur->next != NULL) {
02824         cur = cur->next;
02825         break;
02826         }
02827     } while (cur != NULL);
02828     }
02829     return(count);
02830 }
02831 
02842 int
02843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
02844     int depth1, depth2;
02845     int attr1 = 0, attr2 = 0;
02846     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
02847     xmlNodePtr cur, root;
02848 
02849     if ((node1 == NULL) || (node2 == NULL))
02850     return(-2);
02851     /*
02852      * a couple of optimizations which will avoid computations in most cases
02853      */
02854     if (node1 == node2)     /* trivial case */
02855     return(0);
02856     if (node1->type == XML_ATTRIBUTE_NODE) {
02857     attr1 = 1;
02858     attrNode1 = node1;
02859     node1 = node1->parent;
02860     }
02861     if (node2->type == XML_ATTRIBUTE_NODE) {
02862     attr2 = 1;
02863     attrNode2 = node2;
02864     node2 = node2->parent;
02865     }
02866     if (node1 == node2) {
02867     if (attr1 == attr2) {
02868         /* not required, but we keep attributes in order */
02869         if (attr1 != 0) {
02870             cur = attrNode2->prev;
02871         while (cur != NULL) {
02872             if (cur == attrNode1)
02873                 return (1);
02874             cur = cur->prev;
02875         }
02876         return (-1);
02877         }
02878         return(0);
02879     }
02880     if (attr2 == 1)
02881         return(1);
02882     return(-1);
02883     }
02884     if ((node1->type == XML_NAMESPACE_DECL) ||
02885         (node2->type == XML_NAMESPACE_DECL))
02886     return(1);
02887     if (node1 == node2->prev)
02888     return(1);
02889     if (node1 == node2->next)
02890     return(-1);
02891 
02892     /*
02893      * Speedup using document order if availble.
02894      */
02895     if ((node1->type == XML_ELEMENT_NODE) &&
02896     (node2->type == XML_ELEMENT_NODE) &&
02897     (0 > (long) node1->content) &&
02898     (0 > (long) node2->content) &&
02899     (node1->doc == node2->doc)) {
02900     long l1, l2;
02901 
02902     l1 = -((long) node1->content);
02903     l2 = -((long) node2->content);
02904     if (l1 < l2)
02905         return(1);
02906     if (l1 > l2)
02907         return(-1);
02908     }
02909 
02910     /*
02911      * compute depth to root
02912      */
02913     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
02914     if (cur == node1)
02915         return(1);
02916     depth2++;
02917     }
02918     root = cur;
02919     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
02920     if (cur == node2)
02921         return(-1);
02922     depth1++;
02923     }
02924     /*
02925      * Distinct document (or distinct entities :-( ) case.
02926      */
02927     if (root != cur) {
02928     return(-2);
02929     }
02930     /*
02931      * get the nearest common ancestor.
02932      */
02933     while (depth1 > depth2) {
02934     depth1--;
02935     node1 = node1->parent;
02936     }
02937     while (depth2 > depth1) {
02938     depth2--;
02939     node2 = node2->parent;
02940     }
02941     while (node1->parent != node2->parent) {
02942     node1 = node1->parent;
02943     node2 = node2->parent;
02944     /* should not happen but just in case ... */
02945     if ((node1 == NULL) || (node2 == NULL))
02946         return(-2);
02947     }
02948     /*
02949      * Find who's first.
02950      */
02951     if (node1 == node2->prev)
02952     return(1);
02953     if (node1 == node2->next)
02954     return(-1);
02955     /*
02956      * Speedup using document order if availble.
02957      */
02958     if ((node1->type == XML_ELEMENT_NODE) &&
02959     (node2->type == XML_ELEMENT_NODE) &&
02960     (0 > (long) node1->content) &&
02961     (0 > (long) node2->content) &&
02962     (node1->doc == node2->doc)) {
02963     long l1, l2;
02964 
02965     l1 = -((long) node1->content);
02966     l2 = -((long) node2->content);
02967     if (l1 < l2)
02968         return(1);
02969     if (l1 > l2)
02970         return(-1);
02971     }
02972 
02973     for (cur = node1->next;cur != NULL;cur = cur->next)
02974     if (cur == node2)
02975         return(1);
02976     return(-1); /* assume there is no sibling list corruption */
02977 }
02978 
02979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
02980 
02991 static int
02992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
02993     int depth1, depth2;
02994     int misc = 0, precedence1 = 0, precedence2 = 0;
02995     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
02996     xmlNodePtr cur, root;
02997     long l1, l2;
02998 
02999     if ((node1 == NULL) || (node2 == NULL))
03000     return(-2);
03001 
03002     if (node1 == node2)
03003     return(0);
03004 
03005     /*
03006      * a couple of optimizations which will avoid computations in most cases
03007      */
03008     switch (node1->type) {
03009     case XML_ELEMENT_NODE:
03010         if (node2->type == XML_ELEMENT_NODE) {
03011         if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
03012             (0 > (long) node2->content) &&
03013             (node1->doc == node2->doc))
03014         {
03015             l1 = -((long) node1->content);
03016             l2 = -((long) node2->content);
03017             if (l1 < l2)
03018             return(1);
03019             if (l1 > l2)
03020             return(-1);
03021         } else
03022             goto turtle_comparison;
03023         }
03024         break;
03025     case XML_ATTRIBUTE_NODE:
03026         precedence1 = 1; /* element is owner */
03027         miscNode1 = node1;
03028         node1 = node1->parent;
03029         misc = 1;
03030         break;
03031     case XML_TEXT_NODE:
03032     case XML_CDATA_SECTION_NODE:
03033     case XML_COMMENT_NODE:
03034     case XML_PI_NODE: {
03035         miscNode1 = node1;
03036         /*
03037         * Find nearest element node.
03038         */
03039         if (node1->prev != NULL) {
03040         do {
03041             node1 = node1->prev;
03042             if (node1->type == XML_ELEMENT_NODE) {
03043             precedence1 = 3; /* element in prev-sibl axis */
03044             break;
03045             }
03046             if (node1->prev == NULL) {
03047             precedence1 = 2; /* element is parent */
03048             /*
03049             * URGENT TODO: Are there any cases, where the
03050             * parent of such a node is not an element node?
03051             */
03052             node1 = node1->parent;
03053             break;
03054             }
03055         } while (1);
03056         } else {
03057         precedence1 = 2; /* element is parent */
03058         node1 = node1->parent;
03059         }
03060         if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
03061         (0 <= (long) node1->content)) {
03062         /*
03063         * Fallback for whatever case.
03064         */
03065         node1 = miscNode1;
03066         precedence1 = 0;
03067         } else
03068         misc = 1;
03069     }
03070         break;
03071     case XML_NAMESPACE_DECL:
03072         /*
03073         * TODO: why do we return 1 for namespace nodes?
03074         */
03075         return(1);
03076     default:
03077         break;
03078     }
03079     switch (node2->type) {
03080     case XML_ELEMENT_NODE:
03081         break;
03082     case XML_ATTRIBUTE_NODE:
03083         precedence2 = 1; /* element is owner */
03084         miscNode2 = node2;
03085         node2 = node2->parent;
03086         misc = 1;
03087         break;
03088     case XML_TEXT_NODE:
03089     case XML_CDATA_SECTION_NODE:
03090     case XML_COMMENT_NODE:
03091     case XML_PI_NODE: {
03092         miscNode2 = node2;
03093         if (node2->prev != NULL) {
03094         do {
03095             node2 = node2->prev;
03096             if (node2->type == XML_ELEMENT_NODE) {
03097             precedence2 = 3; /* element in prev-sibl axis */
03098             break;
03099             }
03100             if (node2->prev == NULL) {
03101             precedence2 = 2; /* element is parent */
03102             node2 = node2->parent;
03103             break;
03104             }
03105         } while (1);
03106         } else {
03107         precedence2 = 2; /* element is parent */
03108         node2 = node2->parent;
03109         }
03110         if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
03111         (0 <= (long) node1->content))
03112         {
03113         node2 = miscNode2;
03114         precedence2 = 0;
03115         } else
03116         misc = 1;
03117     }
03118         break;
03119     case XML_NAMESPACE_DECL:
03120         return(1);
03121     default:
03122         break;
03123     }
03124     if (misc) {
03125     if (node1 == node2) {
03126         if (precedence1 == precedence2) {
03127         /*
03128         * The ugly case; but normally there aren't many
03129         * adjacent non-element nodes around.
03130         */
03131         cur = miscNode2->prev;
03132         while (cur != NULL) {
03133             if (cur == miscNode1)
03134             return(1);
03135             if (cur->type == XML_ELEMENT_NODE)
03136             return(-1);
03137             cur = cur->prev;
03138         }
03139         return (-1);
03140         } else {
03141         /*
03142         * Evaluate based on higher precedence wrt to the element.
03143         * TODO: This assumes attributes are sorted before content.
03144         *   Is this 100% correct?
03145         */
03146         if (precedence1 < precedence2)
03147             return(1);
03148         else
03149             return(-1);
03150         }
03151     }
03152     /*
03153     * Special case: One of the helper-elements is contained by the other.
03154     * <foo>
03155     *   <node2>
03156     *     <node1>Text-1(precedence1 == 2)</node1>
03157     *   </node2>
03158     *   Text-6(precedence2 == 3)
03159     * </foo>
03160     */
03161     if ((precedence2 == 3) && (precedence1 > 1)) {
03162         cur = node1->parent;
03163         while (cur) {
03164         if (cur == node2)
03165             return(1);
03166         cur = cur->parent;
03167         }
03168     }
03169     if ((precedence1 == 3) && (precedence2 > 1)) {
03170         cur = node2->parent;
03171         while (cur) {
03172         if (cur == node1)
03173             return(-1);
03174         cur = cur->parent;
03175         }
03176     }
03177     }
03178 
03179     /*
03180      * Speedup using document order if availble.
03181      */
03182     if ((node1->type == XML_ELEMENT_NODE) &&
03183     (node2->type == XML_ELEMENT_NODE) &&
03184     (0 > (long) node1->content) &&
03185     (0 > (long) node2->content) &&
03186     (node1->doc == node2->doc)) {
03187 
03188     l1 = -((long) node1->content);
03189     l2 = -((long) node2->content);
03190     if (l1 < l2)
03191         return(1);
03192     if (l1 > l2)
03193         return(-1);
03194     }
03195 
03196 turtle_comparison:
03197 
03198     if (node1 == node2->prev)
03199     return(1);
03200     if (node1 == node2->next)
03201     return(-1);
03202     /*
03203      * compute depth to root
03204      */
03205     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
03206     if (cur == node1)
03207         return(1);
03208     depth2++;
03209     }
03210     root = cur;
03211     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
03212     if (cur == node2)
03213         return(-1);
03214     depth1++;
03215     }
03216     /*
03217      * Distinct document (or distinct entities :-( ) case.
03218      */
03219     if (root != cur) {
03220     return(-2);
03221     }
03222     /*
03223      * get the nearest common ancestor.
03224      */
03225     while (depth1 > depth2) {
03226     depth1--;
03227     node1 = node1->parent;
03228     }
03229     while (depth2 > depth1) {
03230     depth2--;
03231     node2 = node2->parent;
03232     }
03233     while (node1->parent != node2->parent) {
03234     node1 = node1->parent;
03235     node2 = node2->parent;
03236     /* should not happen but just in case ... */
03237     if ((node1 == NULL) || (node2 == NULL))
03238         return(-2);
03239     }
03240     /*
03241      * Find who's first.
03242      */
03243     if (node1 == node2->prev)
03244     return(1);
03245     if (node1 == node2->next)
03246     return(-1);
03247     /*
03248      * Speedup using document order if availble.
03249      */
03250     if ((node1->type == XML_ELEMENT_NODE) &&
03251     (node2->type == XML_ELEMENT_NODE) &&
03252     (0 > (long) node1->content) &&
03253     (0 > (long) node2->content) &&
03254     (node1->doc == node2->doc)) {
03255 
03256     l1 = -((long) node1->content);
03257     l2 = -((long) node2->content);
03258     if (l1 < l2)
03259         return(1);
03260     if (l1 > l2)
03261         return(-1);
03262     }
03263 
03264     for (cur = node1->next;cur != NULL;cur = cur->next)
03265     if (cur == node2)
03266         return(1);
03267     return(-1); /* assume there is no sibling list corruption */
03268 }
03269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
03270 
03277 void
03278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
03279     int i, j, incr, len;
03280     xmlNodePtr tmp;
03281 
03282     if (set == NULL)
03283     return;
03284 
03285     /* Use Shell's sort to sort the node-set */
03286     len = set->nodeNr;
03287     for (incr = len / 2; incr > 0; incr /= 2) {
03288     for (i = incr; i < len; i++) {
03289         j = i - incr;
03290         while (j >= 0) {
03291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
03292         if (xmlXPathCmpNodesExt(set->nodeTab[j],
03293             set->nodeTab[j + incr]) == -1)
03294 #else
03295         if (xmlXPathCmpNodes(set->nodeTab[j],
03296             set->nodeTab[j + incr]) == -1)
03297 #endif
03298         {
03299             tmp = set->nodeTab[j];
03300             set->nodeTab[j] = set->nodeTab[j + incr];
03301             set->nodeTab[j + incr] = tmp;
03302             j -= incr;
03303         } else
03304             break;
03305         }
03306     }
03307     }
03308 }
03309 
03310 #define XML_NODESET_DEFAULT 10
03311 
03322 static xmlNodePtr
03323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
03324     xmlNsPtr cur;
03325 
03326     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
03327     return(NULL);
03328     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
03329     return((xmlNodePtr) ns);
03330 
03331     /*
03332      * Allocate a new Namespace and fill the fields.
03333      */
03334     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
03335     if (cur == NULL) {
03336         xmlXPathErrMemory(NULL, "duplicating namespace\n");
03337     return(NULL);
03338     }
03339     memset(cur, 0, sizeof(xmlNs));
03340     cur->type = XML_NAMESPACE_DECL;
03341     if (ns->href != NULL)
03342     cur->href = xmlStrdup(ns->href);
03343     if (ns->prefix != NULL)
03344     cur->prefix = xmlStrdup(ns->prefix);
03345     cur->next = (xmlNsPtr) node;
03346     return((xmlNodePtr) cur);
03347 }
03348 
03357 void
03358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
03359     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
03360     return;
03361 
03362     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
03363     if (ns->href != NULL)
03364         xmlFree((xmlChar *)ns->href);
03365     if (ns->prefix != NULL)
03366         xmlFree((xmlChar *)ns->prefix);
03367     xmlFree(ns);
03368     }
03369 }
03370 
03379 xmlNodeSetPtr
03380 xmlXPathNodeSetCreate(xmlNodePtr val) {
03381     xmlNodeSetPtr ret;
03382 
03383     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
03384     if (ret == NULL) {
03385         xmlXPathErrMemory(NULL, "creating nodeset\n");
03386     return(NULL);
03387     }
03388     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
03389     if (val != NULL) {
03390         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03391                          sizeof(xmlNodePtr));
03392     if (ret->nodeTab == NULL) {
03393         xmlXPathErrMemory(NULL, "creating nodeset\n");
03394         xmlFree(ret);
03395         return(NULL);
03396     }
03397     memset(ret->nodeTab, 0 ,
03398            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03399         ret->nodeMax = XML_NODESET_DEFAULT;
03400     if (val->type == XML_NAMESPACE_DECL) {
03401         xmlNsPtr ns = (xmlNsPtr) val;
03402 
03403         ret->nodeTab[ret->nodeNr++] =
03404         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03405     } else
03406         ret->nodeTab[ret->nodeNr++] = val;
03407     }
03408     return(ret);
03409 }
03410 
03419 static xmlNodeSetPtr
03420 xmlXPathNodeSetCreateSize(int size) {
03421     xmlNodeSetPtr ret;
03422 
03423     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
03424     if (ret == NULL) {
03425         xmlXPathErrMemory(NULL, "creating nodeset\n");
03426     return(NULL);
03427     }
03428     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
03429     if (size < XML_NODESET_DEFAULT)
03430     size = XML_NODESET_DEFAULT;
03431     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
03432     if (ret->nodeTab == NULL) {
03433     xmlXPathErrMemory(NULL, "creating nodeset\n");
03434     xmlFree(ret);
03435     return(NULL);
03436     }
03437     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
03438     ret->nodeMax = size;
03439     return(ret);
03440 }
03441 
03451 int
03452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
03453     int i;
03454 
03455     if ((cur == NULL) || (val == NULL)) return(0);
03456     if (val->type == XML_NAMESPACE_DECL) {
03457     for (i = 0; i < cur->nodeNr; i++) {
03458         if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
03459         xmlNsPtr ns1, ns2;
03460 
03461         ns1 = (xmlNsPtr) val;
03462         ns2 = (xmlNsPtr) cur->nodeTab[i];
03463         if (ns1 == ns2)
03464             return(1);
03465         if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
03466                 (xmlStrEqual(ns1->prefix, ns2->prefix)))
03467             return(1);
03468         }
03469     }
03470     } else {
03471     for (i = 0; i < cur->nodeNr; i++) {
03472         if (cur->nodeTab[i] == val)
03473         return(1);
03474     }
03475     }
03476     return(0);
03477 }
03478 
03487 void
03488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
03489     int i;
03490 
03491 
03492     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
03493         (ns->type != XML_NAMESPACE_DECL) ||
03494     (node->type != XML_ELEMENT_NODE))
03495     return;
03496 
03497     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
03498     /*
03499      * prevent duplicates
03500      */
03501     for (i = 0;i < cur->nodeNr;i++) {
03502         if ((cur->nodeTab[i] != NULL) &&
03503         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
03504         (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
03505         (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
03506         return;
03507     }
03508 
03509     /*
03510      * grow the nodeTab if needed
03511      */
03512     if (cur->nodeMax == 0) {
03513         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03514                          sizeof(xmlNodePtr));
03515     if (cur->nodeTab == NULL) {
03516         xmlXPathErrMemory(NULL, "growing nodeset\n");
03517         return;
03518     }
03519     memset(cur->nodeTab, 0 ,
03520            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03521         cur->nodeMax = XML_NODESET_DEFAULT;
03522     } else if (cur->nodeNr == cur->nodeMax) {
03523         xmlNodePtr *temp;
03524 
03525         cur->nodeMax *= 2;
03526     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
03527                       sizeof(xmlNodePtr));
03528     if (temp == NULL) {
03529         xmlXPathErrMemory(NULL, "growing nodeset\n");
03530         return;
03531     }
03532     cur->nodeTab = temp;
03533     }
03534     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
03535 }
03536 
03544 void
03545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
03546     int i;
03547 
03548     if ((cur == NULL) || (val == NULL)) return;
03549 
03550 #if 0
03551     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
03552     return; /* an XSLT fake node */
03553 #endif
03554 
03555     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
03556     /*
03557      * prevent duplcates
03558      */
03559     for (i = 0;i < cur->nodeNr;i++)
03560         if (cur->nodeTab[i] == val) return;
03561 
03562     /*
03563      * grow the nodeTab if needed
03564      */
03565     if (cur->nodeMax == 0) {
03566         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03567                          sizeof(xmlNodePtr));
03568     if (cur->nodeTab == NULL) {
03569         xmlXPathErrMemory(NULL, "growing nodeset\n");
03570         return;
03571     }
03572     memset(cur->nodeTab, 0 ,
03573            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03574         cur->nodeMax = XML_NODESET_DEFAULT;
03575     } else if (cur->nodeNr == cur->nodeMax) {
03576         xmlNodePtr *temp;
03577 
03578         cur->nodeMax *= 2;
03579     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
03580                       sizeof(xmlNodePtr));
03581     if (temp == NULL) {
03582         xmlXPathErrMemory(NULL, "growing nodeset\n");
03583         return;
03584     }
03585     cur->nodeTab = temp;
03586     }
03587     if (val->type == XML_NAMESPACE_DECL) {
03588     xmlNsPtr ns = (xmlNsPtr) val;
03589 
03590     cur->nodeTab[cur->nodeNr++] =
03591         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03592     } else
03593     cur->nodeTab[cur->nodeNr++] = val;
03594 }
03595 
03604 void
03605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
03606     if ((cur == NULL) || (val == NULL)) return;
03607 
03608 #if 0
03609     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
03610     return; /* an XSLT fake node */
03611 #endif
03612 
03613     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
03614     /*
03615      * grow the nodeTab if needed
03616      */
03617     if (cur->nodeMax == 0) {
03618         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03619                          sizeof(xmlNodePtr));
03620     if (cur->nodeTab == NULL) {
03621         xmlXPathErrMemory(NULL, "growing nodeset\n");
03622         return;
03623     }
03624     memset(cur->nodeTab, 0 ,
03625            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03626         cur->nodeMax = XML_NODESET_DEFAULT;
03627     } else if (cur->nodeNr == cur->nodeMax) {
03628         xmlNodePtr *temp;
03629 
03630         cur->nodeMax *= 2;
03631     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
03632                       sizeof(xmlNodePtr));
03633     if (temp == NULL) {
03634         xmlXPathErrMemory(NULL, "growing nodeset\n");
03635         return;
03636     }
03637     cur->nodeTab = temp;
03638     }
03639     if (val->type == XML_NAMESPACE_DECL) {
03640     xmlNsPtr ns = (xmlNsPtr) val;
03641 
03642     cur->nodeTab[cur->nodeNr++] =
03643         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03644     } else
03645     cur->nodeTab[cur->nodeNr++] = val;
03646 }
03647 
03658 xmlNodeSetPtr
03659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
03660     int i, j, initNr, skip;
03661     xmlNodePtr n1, n2;
03662 
03663     if (val2 == NULL) return(val1);
03664     if (val1 == NULL) {
03665     val1 = xmlXPathNodeSetCreate(NULL);
03666     if (val1 == NULL)
03667         return (NULL);
03668 #if 0
03669     /*
03670     * TODO: The optimization won't work in every case, since
03671     *  those nasty namespace nodes need to be added with
03672     *  xmlXPathNodeSetDupNs() to the set; thus a pure
03673     *  memcpy is not possible.
03674     *  If there was a flag on the nodesetval, indicating that
03675     *  some temporary nodes are in, that would be helpfull.
03676     */
03677     /*
03678     * Optimization: Create an equally sized node-set
03679     * and memcpy the content.
03680     */
03681     val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
03682     if (val1 == NULL)
03683         return(NULL);
03684     if (val2->nodeNr != 0) {
03685         if (val2->nodeNr == 1)
03686         *(val1->nodeTab) = *(val2->nodeTab);
03687         else {
03688         memcpy(val1->nodeTab, val2->nodeTab,
03689             val2->nodeNr * sizeof(xmlNodePtr));
03690         }
03691         val1->nodeNr = val2->nodeNr;
03692     }
03693     return(val1);
03694 #endif
03695     }
03696 
03697     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
03698     initNr = val1->nodeNr;
03699 
03700     for (i = 0;i < val2->nodeNr;i++) {
03701     n2 = val2->nodeTab[i];
03702     /*
03703      * check against duplicates
03704      */
03705     skip = 0;
03706     for (j = 0; j < initNr; j++) {
03707         n1 = val1->nodeTab[j];
03708         if (n1 == n2) {
03709         skip = 1;
03710         break;
03711         } else if ((n1->type == XML_NAMESPACE_DECL) &&
03712                (n2->type == XML_NAMESPACE_DECL)) {
03713         if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
03714             (xmlStrEqual(((xmlNsPtr) n1)->prefix,
03715             ((xmlNsPtr) n2)->prefix)))
03716         {
03717             skip = 1;
03718             break;
03719         }
03720         }
03721     }
03722     if (skip)
03723         continue;
03724 
03725     /*
03726      * grow the nodeTab if needed
03727      */
03728     if (val1->nodeMax == 0) {
03729         val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03730                             sizeof(xmlNodePtr));
03731         if (val1->nodeTab == NULL) {
03732             xmlXPathErrMemory(NULL, "merging nodeset\n");
03733         return(NULL);
03734         }
03735         memset(val1->nodeTab, 0 ,
03736            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03737         val1->nodeMax = XML_NODESET_DEFAULT;
03738     } else if (val1->nodeNr == val1->nodeMax) {
03739         xmlNodePtr *temp;
03740 
03741         val1->nodeMax *= 2;
03742         temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
03743                          sizeof(xmlNodePtr));
03744         if (temp == NULL) {
03745             xmlXPathErrMemory(NULL, "merging nodeset\n");
03746         return(NULL);
03747         }
03748         val1->nodeTab = temp;
03749     }
03750     if (n2->type == XML_NAMESPACE_DECL) {
03751         xmlNsPtr ns = (xmlNsPtr) n2;
03752 
03753         val1->nodeTab[val1->nodeNr++] =
03754         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03755     } else
03756         val1->nodeTab[val1->nodeNr++] = n2;
03757     }
03758 
03759     return(val1);
03760 }
03761 
03762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
03763 
03773 static xmlNodeSetPtr
03774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
03775     int i;
03776 
03777     if (val2 == NULL) return(val1);
03778     if (val1 == NULL) {
03779     val1 = xmlXPathNodeSetCreate(NULL);
03780     }
03781     if (val1 == NULL)
03782         return (NULL);
03783 
03784     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
03785 
03786     for (i = 0;i < val2->nodeNr;i++) {
03787     /*
03788      * grow the nodeTab if needed
03789      */
03790     if (val1->nodeMax == 0) {
03791         val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
03792                             sizeof(xmlNodePtr));
03793         if (val1->nodeTab == NULL) {
03794             xmlXPathErrMemory(NULL, "merging nodeset\n");
03795         return(NULL);
03796         }
03797         memset(val1->nodeTab, 0 ,
03798            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03799         val1->nodeMax = XML_NODESET_DEFAULT;
03800     } else if (val1->nodeNr == val1->nodeMax) {
03801         xmlNodePtr *temp;
03802 
03803         val1->nodeMax *= 2;
03804         temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
03805                          sizeof(xmlNodePtr));
03806         if (temp == NULL) {
03807             xmlXPathErrMemory(NULL, "merging nodeset\n");
03808         return(NULL);
03809         }
03810         val1->nodeTab = temp;
03811     }
03812     if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
03813         xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
03814 
03815         val1->nodeTab[val1->nodeNr++] =
03816         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03817     } else
03818         val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
03819     }
03820 
03821     return(val1);
03822 }
03823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
03824 
03837 static xmlNodeSetPtr
03838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
03839                  int hasNullEntries)
03840 {
03841     if ((set1 == NULL) && (hasNullEntries == 0)) {
03842     /*
03843     * Note that doing a memcpy of the list, namespace nodes are
03844     * just assigned to set1, since set2 is cleared anyway.
03845     */
03846     set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
03847     if (set1 == NULL)
03848         return(NULL);
03849     if (set2->nodeNr != 0) {
03850         memcpy(set1->nodeTab, set2->nodeTab,
03851         set2->nodeNr * sizeof(xmlNodePtr));
03852         set1->nodeNr = set2->nodeNr;
03853     }
03854     } else {
03855     int i, j, initNbSet1;
03856     xmlNodePtr n1, n2;
03857 
03858     if (set1 == NULL)
03859             set1 = xmlXPathNodeSetCreate(NULL);
03860         if (set1 == NULL)
03861             return (NULL);
03862 
03863     initNbSet1 = set1->nodeNr;
03864     for (i = 0;i < set2->nodeNr;i++) {
03865         n2 = set2->nodeTab[i];
03866         /*
03867         * Skip NULLed entries.
03868         */
03869         if (n2 == NULL)
03870         continue;
03871         /*
03872         * Skip duplicates.
03873         */
03874         for (j = 0; j < initNbSet1; j++) {
03875         n1 = set1->nodeTab[j];
03876         if (n1 == n2) {
03877             goto skip_node;
03878         } else if ((n1->type == XML_NAMESPACE_DECL) &&
03879             (n2->type == XML_NAMESPACE_DECL))
03880         {
03881             if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
03882             (xmlStrEqual(((xmlNsPtr) n1)->prefix,
03883             ((xmlNsPtr) n2)->prefix)))
03884             {
03885             /*
03886             * Free the namespace node.
03887             */
03888             set2->nodeTab[i] = NULL;
03889             xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
03890             goto skip_node;
03891             }
03892         }
03893         }
03894         /*
03895         * grow the nodeTab if needed
03896         */
03897         if (set1->nodeMax == 0) {
03898         set1->nodeTab = (xmlNodePtr *) xmlMalloc(
03899             XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
03900         if (set1->nodeTab == NULL) {
03901             xmlXPathErrMemory(NULL, "merging nodeset\n");
03902             return(NULL);
03903         }
03904         memset(set1->nodeTab, 0,
03905             XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03906         set1->nodeMax = XML_NODESET_DEFAULT;
03907         } else if (set1->nodeNr >= set1->nodeMax) {
03908         xmlNodePtr *temp;
03909 
03910         set1->nodeMax *= 2;
03911         temp = (xmlNodePtr *) xmlRealloc(
03912             set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
03913         if (temp == NULL) {
03914             xmlXPathErrMemory(NULL, "merging nodeset\n");
03915             return(NULL);
03916         }
03917         set1->nodeTab = temp;
03918         }
03919         if (n2->type == XML_NAMESPACE_DECL) {
03920         xmlNsPtr ns = (xmlNsPtr) n2;
03921 
03922         set1->nodeTab[set1->nodeNr++] =
03923             xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
03924         } else
03925         set1->nodeTab[set1->nodeNr++] = n2;
03926 skip_node:
03927         {}
03928     }
03929     }
03930     set2->nodeNr = 0;
03931     return(set1);
03932 }
03933 
03946 static xmlNodeSetPtr
03947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
03948                     int hasNullEntries)
03949 {
03950     if (set2 == NULL)
03951     return(set1);
03952     if ((set1 == NULL) && (hasNullEntries == 0)) {
03953     /*
03954     * Note that doing a memcpy of the list, namespace nodes are
03955     * just assigned to set1, since set2 is cleared anyway.
03956     */
03957     set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
03958     if (set1 == NULL)
03959         return(NULL);
03960     if (set2->nodeNr != 0) {
03961         memcpy(set1->nodeTab, set2->nodeTab,
03962         set2->nodeNr * sizeof(xmlNodePtr));
03963         set1->nodeNr = set2->nodeNr;
03964     }
03965     } else {
03966     int i;
03967     xmlNodePtr n2;
03968 
03969     if (set1 == NULL)
03970         set1 = xmlXPathNodeSetCreate(NULL);
03971         if (set1 == NULL)
03972             return (NULL);
03973 
03974     for (i = 0;i < set2->nodeNr;i++) {
03975         n2 = set2->nodeTab[i];
03976         /*
03977         * Skip NULLed entries.
03978         */
03979         if (n2 == NULL)
03980         continue;
03981         if (set1->nodeMax == 0) {
03982         set1->nodeTab = (xmlNodePtr *) xmlMalloc(
03983             XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
03984         if (set1->nodeTab == NULL) {
03985             xmlXPathErrMemory(NULL, "merging nodeset\n");
03986             return(NULL);
03987         }
03988         memset(set1->nodeTab, 0,
03989             XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
03990         set1->nodeMax = XML_NODESET_DEFAULT;
03991         } else if (set1->nodeNr >= set1->nodeMax) {
03992         xmlNodePtr *temp;
03993 
03994         set1->nodeMax *= 2;
03995         temp = (xmlNodePtr *) xmlRealloc(
03996             set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
03997         if (temp == NULL) {
03998             xmlXPathErrMemory(NULL, "merging nodeset\n");
03999             return(NULL);
04000         }
04001         set1->nodeTab = temp;
04002         }
04003         set1->nodeTab[set1->nodeNr++] = n2;
04004     }
04005     }
04006     set2->nodeNr = 0;
04007     return(set1);
04008 }
04009 
04017 void
04018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
04019     int i;
04020 
04021     if (cur == NULL) return;
04022     if (val == NULL) return;
04023 
04024     /*
04025      * find node in nodeTab
04026      */
04027     for (i = 0;i < cur->nodeNr;i++)
04028         if (cur->nodeTab[i] == val) break;
04029 
04030     if (i >= cur->nodeNr) { /* not found */
04031 #ifdef DEBUG
04032         xmlGenericError(xmlGenericErrorContext,
04033             "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
04034         val->name);
04035 #endif
04036         return;
04037     }
04038     if ((cur->nodeTab[i] != NULL) &&
04039     (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
04040     xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
04041     cur->nodeNr--;
04042     for (;i < cur->nodeNr;i++)
04043         cur->nodeTab[i] = cur->nodeTab[i + 1];
04044     cur->nodeTab[cur->nodeNr] = NULL;
04045 }
04046 
04054 void
04055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
04056     if (cur == NULL) return;
04057     if (val >= cur->nodeNr) return;
04058     if ((cur->nodeTab[val] != NULL) &&
04059     (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
04060     xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
04061     cur->nodeNr--;
04062     for (;val < cur->nodeNr;val++)
04063         cur->nodeTab[val] = cur->nodeTab[val + 1];
04064     cur->nodeTab[cur->nodeNr] = NULL;
04065 }
04066 
04073 void
04074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
04075     if (obj == NULL) return;
04076     if (obj->nodeTab != NULL) {
04077     int i;
04078 
04079     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
04080     for (i = 0;i < obj->nodeNr;i++)
04081         if ((obj->nodeTab[i] != NULL) &&
04082         (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
04083         xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
04084     xmlFree(obj->nodeTab);
04085     }
04086     xmlFree(obj);
04087 }
04088 
04097 static void
04098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
04099 {
04100     if ((set == NULL) || (set->nodeNr <= 0))
04101     return;
04102     else if (hasNsNodes) {
04103     int i;
04104     xmlNodePtr node;
04105 
04106     for (i = 0; i < set->nodeNr; i++) {
04107         node = set->nodeTab[i];
04108         if ((node != NULL) &&
04109         (node->type == XML_NAMESPACE_DECL))
04110         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
04111     }
04112     }
04113     set->nodeNr = 0;
04114 }
04115 
04125 static void
04126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
04127 {
04128     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
04129     return;
04130     else if ((hasNsNodes)) {
04131     int i;
04132     xmlNodePtr node;
04133 
04134     for (i = pos; i < set->nodeNr; i++) {
04135         node = set->nodeTab[i];
04136         if ((node != NULL) &&
04137         (node->type == XML_NAMESPACE_DECL))
04138         xmlXPathNodeSetFreeNs((xmlNsPtr) node);
04139     }
04140     }
04141     set->nodeNr = pos;
04142 }
04143 
04151 static void
04152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
04153     int i;
04154 
04155     if (obj == NULL) return;
04156 
04157     if (obj->nodeTab != NULL) {
04158     for (i = 0;i < obj->nodeNr;i++) {
04159         if (obj->nodeTab[i] != NULL) {
04160         if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
04161             xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
04162         } else {
04163             xmlFreeNodeList(obj->nodeTab[i]);
04164         }
04165         }
04166     }
04167     xmlFree(obj->nodeTab);
04168     }
04169     xmlFree(obj);
04170 }
04171 
04172 #if defined(DEBUG) || defined(DEBUG_STEP)
04173 
04180 void
04181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
04182     int i;
04183 
04184     if (output == NULL) output = xmlGenericErrorContext;
04185     if (obj == NULL)  {
04186         fprintf(output, "NodeSet == NULL !\n");
04187     return;
04188     }
04189     if (obj->nodeNr == 0) {
04190         fprintf(output, "NodeSet is empty\n");
04191     return;
04192     }
04193     if (obj->nodeTab == NULL) {
04194     fprintf(output, " nodeTab == NULL !\n");
04195     return;
04196     }
04197     for (i = 0; i < obj->nodeNr; i++) {
04198         if (obj->nodeTab[i] == NULL) {
04199         fprintf(output, " NULL !\n");
04200         return;
04201         }
04202     if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
04203         (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
04204         fprintf(output, " /");
04205     else if (obj->nodeTab[i]->name == NULL)
04206         fprintf(output, " noname!");
04207     else fprintf(output, " %s", obj->nodeTab[i]->name);
04208     }
04209     fprintf(output, "\n");
04210 }
04211 #endif
04212 
04222 xmlXPathObjectPtr
04223 xmlXPathNewNodeSet(xmlNodePtr val) {
04224     xmlXPathObjectPtr ret;
04225 
04226     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
04227     if (ret == NULL) {
04228         xmlXPathErrMemory(NULL, "creating nodeset\n");
04229     return(NULL);
04230     }
04231     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
04232     ret->type = XPATH_NODESET;
04233     ret->boolval = 0;
04234     ret->nodesetval = xmlXPathNodeSetCreate(val);
04235     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
04236 #ifdef XP_DEBUG_OBJ_USAGE
04237     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
04238 #endif
04239     return(ret);
04240 }
04241 
04251 xmlXPathObjectPtr
04252 xmlXPathNewValueTree(xmlNodePtr val) {
04253     xmlXPathObjectPtr ret;
04254 
04255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
04256     if (ret == NULL) {
04257         xmlXPathErrMemory(NULL, "creating result value tree\n");
04258     return(NULL);
04259     }
04260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
04261     ret->type = XPATH_XSLT_TREE;
04262     ret->boolval = 1;
04263     ret->user = (void *) val;
04264     ret->nodesetval = xmlXPathNodeSetCreate(val);
04265 #ifdef XP_DEBUG_OBJ_USAGE
04266     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
04267 #endif
04268     return(ret);
04269 }
04270 
04280 xmlXPathObjectPtr
04281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
04282 {
04283     xmlXPathObjectPtr ret;
04284     int i;
04285 
04286     if (val == NULL)
04287         ret = NULL;
04288     else if (val->nodeTab == NULL)
04289         ret = xmlXPathNewNodeSet(NULL);
04290     else {
04291         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
04292         if (ret)
04293             for (i = 1; i < val->nodeNr; ++i)
04294                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
04295     }
04296 
04297     return (ret);
04298 }
04299 
04308 xmlXPathObjectPtr
04309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
04310     xmlXPathObjectPtr ret;
04311 
04312     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
04313     if (ret == NULL) {
04314         xmlXPathErrMemory(NULL, "creating node set object\n");
04315     return(NULL);
04316     }
04317     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
04318     ret->type = XPATH_NODESET;
04319     ret->nodesetval = val;
04320 #ifdef XP_DEBUG_OBJ_USAGE
04321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
04322 #endif
04323     return(ret);
04324 }
04325 
04333 void
04334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
04335     if (obj == NULL) return;
04336 #ifdef XP_DEBUG_OBJ_USAGE
04337     xmlXPathDebugObjUsageReleased(NULL, obj->type);
04338 #endif
04339     xmlFree(obj);
04340 }
04341 
04353 xmlNodeSetPtr
04354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04355     xmlNodeSetPtr ret;
04356     int i, l1;
04357     xmlNodePtr cur;
04358 
04359     if (xmlXPathNodeSetIsEmpty(nodes2))
04360     return(nodes1);
04361 
04362     ret = xmlXPathNodeSetCreate(NULL);
04363     if (xmlXPathNodeSetIsEmpty(nodes1))
04364     return(ret);
04365 
04366     l1 = xmlXPathNodeSetGetLength(nodes1);
04367 
04368     for (i = 0; i < l1; i++) {
04369     cur = xmlXPathNodeSetItem(nodes1, i);
04370     if (!xmlXPathNodeSetContains(nodes2, cur))
04371         xmlXPathNodeSetAddUnique(ret, cur);
04372     }
04373     return(ret);
04374 }
04375 
04387 xmlNodeSetPtr
04388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04389     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
04390     int i, l1;
04391     xmlNodePtr cur;
04392 
04393     if (ret == NULL)
04394         return(ret);
04395     if (xmlXPathNodeSetIsEmpty(nodes1))
04396     return(ret);
04397     if (xmlXPathNodeSetIsEmpty(nodes2))
04398     return(ret);
04399 
04400     l1 = xmlXPathNodeSetGetLength(nodes1);
04401 
04402     for (i = 0; i < l1; i++) {
04403     cur = xmlXPathNodeSetItem(nodes1, i);
04404     if (xmlXPathNodeSetContains(nodes2, cur))
04405         xmlXPathNodeSetAddUnique(ret, cur);
04406     }
04407     return(ret);
04408 }
04409 
04420 xmlNodeSetPtr
04421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
04422     xmlNodeSetPtr ret;
04423     xmlHashTablePtr hash;
04424     int i, l;
04425     xmlChar * strval;
04426     xmlNodePtr cur;
04427 
04428     if (xmlXPathNodeSetIsEmpty(nodes))
04429     return(nodes);
04430 
04431     ret = xmlXPathNodeSetCreate(NULL);
04432     if (ret == NULL)
04433         return(ret);
04434     l = xmlXPathNodeSetGetLength(nodes);
04435     hash = xmlHashCreate (l);
04436     for (i = 0; i < l; i++) {
04437     cur = xmlXPathNodeSetItem(nodes, i);
04438     strval = xmlXPathCastNodeToString(cur);
04439     if (xmlHashLookup(hash, strval) == NULL) {
04440         xmlHashAddEntry(hash, strval, strval);
04441         xmlXPathNodeSetAddUnique(ret, cur);
04442     } else {
04443         xmlFree(strval);
04444     }
04445     }
04446     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
04447     return(ret);
04448 }
04449 
04462 xmlNodeSetPtr
04463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
04464     if (xmlXPathNodeSetIsEmpty(nodes))
04465     return(nodes);
04466 
04467     xmlXPathNodeSetSort(nodes);
04468     return(xmlXPathDistinctSorted(nodes));
04469 }
04470 
04482 int
04483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04484     int i, l;
04485     xmlNodePtr cur;
04486 
04487     if (xmlXPathNodeSetIsEmpty(nodes1) ||
04488     xmlXPathNodeSetIsEmpty(nodes2))
04489     return(0);
04490 
04491     l = xmlXPathNodeSetGetLength(nodes1);
04492     for (i = 0; i < l; i++) {
04493     cur = xmlXPathNodeSetItem(nodes1, i);
04494     if (xmlXPathNodeSetContains(nodes2, cur))
04495         return(1);
04496     }
04497     return(0);
04498 }
04499 
04512 xmlNodeSetPtr
04513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
04514     int i, l;
04515     xmlNodePtr cur;
04516     xmlNodeSetPtr ret;
04517 
04518     if (node == NULL)
04519     return(nodes);
04520 
04521     ret = xmlXPathNodeSetCreate(NULL);
04522     if (ret == NULL)
04523         return(ret);
04524     if (xmlXPathNodeSetIsEmpty(nodes) ||
04525     (!xmlXPathNodeSetContains(nodes, node)))
04526     return(ret);
04527 
04528     l = xmlXPathNodeSetGetLength(nodes);
04529     for (i = 0; i < l; i++) {
04530     cur = xmlXPathNodeSetItem(nodes, i);
04531     if (cur == node)
04532         break;
04533     xmlXPathNodeSetAddUnique(ret, cur);
04534     }
04535     return(ret);
04536 }
04537 
04552 xmlNodeSetPtr
04553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
04554     xmlXPathNodeSetSort(nodes);
04555     return(xmlXPathNodeLeadingSorted(nodes, node));
04556 }
04557 
04570 xmlNodeSetPtr
04571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04572     if (xmlXPathNodeSetIsEmpty(nodes2))
04573     return(nodes1);
04574     return(xmlXPathNodeLeadingSorted(nodes1,
04575                      xmlXPathNodeSetItem(nodes2, 1)));
04576 }
04577 
04592 xmlNodeSetPtr
04593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04594     if (xmlXPathNodeSetIsEmpty(nodes2))
04595     return(nodes1);
04596     if (xmlXPathNodeSetIsEmpty(nodes1))
04597     return(xmlXPathNodeSetCreate(NULL));
04598     xmlXPathNodeSetSort(nodes1);
04599     xmlXPathNodeSetSort(nodes2);
04600     return(xmlXPathNodeLeadingSorted(nodes1,
04601                      xmlXPathNodeSetItem(nodes2, 1)));
04602 }
04603 
04616 xmlNodeSetPtr
04617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
04618     int i, l;
04619     xmlNodePtr cur;
04620     xmlNodeSetPtr ret;
04621 
04622     if (node == NULL)
04623     return(nodes);
04624 
04625     ret = xmlXPathNodeSetCreate(NULL);
04626     if (ret == NULL)
04627         return(ret);
04628     if (xmlXPathNodeSetIsEmpty(nodes) ||
04629     (!xmlXPathNodeSetContains(nodes, node)))
04630     return(ret);
04631 
04632     l = xmlXPathNodeSetGetLength(nodes);
04633     for (i = l - 1; i >= 0; i--) {
04634     cur = xmlXPathNodeSetItem(nodes, i);
04635     if (cur == node)
04636         break;
04637     xmlXPathNodeSetAddUnique(ret, cur);
04638     }
04639     xmlXPathNodeSetSort(ret);   /* bug 413451 */
04640     return(ret);
04641 }
04642 
04657 xmlNodeSetPtr
04658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
04659     xmlXPathNodeSetSort(nodes);
04660     return(xmlXPathNodeTrailingSorted(nodes, node));
04661 }
04662 
04675 xmlNodeSetPtr
04676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04677     if (xmlXPathNodeSetIsEmpty(nodes2))
04678     return(nodes1);
04679     return(xmlXPathNodeTrailingSorted(nodes1,
04680                       xmlXPathNodeSetItem(nodes2, 0)));
04681 }
04682 
04697 xmlNodeSetPtr
04698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
04699     if (xmlXPathNodeSetIsEmpty(nodes2))
04700     return(nodes1);
04701     if (xmlXPathNodeSetIsEmpty(nodes1))
04702     return(xmlXPathNodeSetCreate(NULL));
04703     xmlXPathNodeSetSort(nodes1);
04704     xmlXPathNodeSetSort(nodes2);
04705     return(xmlXPathNodeTrailingSorted(nodes1,
04706                       xmlXPathNodeSetItem(nodes2, 0)));
04707 }
04708 
04709 /************************************************************************
04710  *                                  *
04711  *      Routines to handle extra functions          *
04712  *                                  *
04713  ************************************************************************/
04714 
04725 int
04726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
04727              xmlXPathFunction f) {
04728     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
04729 }
04730 
04742 int
04743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
04744                const xmlChar *ns_uri, xmlXPathFunction f) {
04745     if (ctxt == NULL)
04746     return(-1);
04747     if (name == NULL)
04748     return(-1);
04749 
04750     if (ctxt->funcHash == NULL)
04751     ctxt->funcHash = xmlHashCreate(0);
04752     if (ctxt->funcHash == NULL)
04753     return(-1);
04754     if (f == NULL)
04755         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
04756     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
04757 }
04758 
04767 void
04768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
04769                 xmlXPathFuncLookupFunc f,
04770                 void *funcCtxt) {
04771     if (ctxt == NULL)
04772     return;
04773     ctxt->funcLookupFunc = f;
04774     ctxt->funcLookupData = funcCtxt;
04775 }
04776 
04787 xmlXPathFunction
04788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
04789     if (ctxt == NULL)
04790     return (NULL);
04791 
04792     if (ctxt->funcLookupFunc != NULL) {
04793     xmlXPathFunction ret;
04794     xmlXPathFuncLookupFunc f;
04795 
04796     f = ctxt->funcLookupFunc;
04797     ret = f(ctxt->funcLookupData, name, NULL);
04798     if (ret != NULL)
04799         return(ret);
04800     }
04801     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
04802 }
04803 
04815 xmlXPathFunction
04816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
04817              const xmlChar *ns_uri) {
04818     xmlXPathFunction ret;
04819 
04820     if (ctxt == NULL)
04821     return(NULL);
04822     if (name == NULL)
04823     return(NULL);
04824 
04825     if (ctxt->funcLookupFunc != NULL) {
04826     xmlXPathFuncLookupFunc f;
04827 
04828     f = ctxt->funcLookupFunc;
04829     ret = f(ctxt->funcLookupData, name, ns_uri);
04830     if (ret != NULL)
04831         return(ret);
04832     }
04833 
04834     if (ctxt->funcHash == NULL)
04835     return(NULL);
04836 
04837     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
04838     return(ret);
04839 }
04840 
04847 void
04848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
04849     if (ctxt == NULL)
04850     return;
04851 
04852     xmlHashFree(ctxt->funcHash, NULL);
04853     ctxt->funcHash = NULL;
04854 }
04855 
04856 /************************************************************************
04857  *                                  *
04858  *          Routines to handle Variables            *
04859  *                                  *
04860  ************************************************************************/
04861 
04873 int
04874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
04875              xmlXPathObjectPtr value) {
04876     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
04877 }
04878 
04891 int
04892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
04893                const xmlChar *ns_uri,
04894                xmlXPathObjectPtr value) {
04895     if (ctxt == NULL)
04896     return(-1);
04897     if (name == NULL)
04898     return(-1);
04899 
04900     if (ctxt->varHash == NULL)
04901     ctxt->varHash = xmlHashCreate(0);
04902     if (ctxt->varHash == NULL)
04903     return(-1);
04904     if (value == NULL)
04905         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
04906                                (xmlHashDeallocator)xmlXPathFreeObject));
04907     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
04908                    (void *) value,
04909                    (xmlHashDeallocator)xmlXPathFreeObject));
04910 }
04911 
04920 void
04921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
04922      xmlXPathVariableLookupFunc f, void *data) {
04923     if (ctxt == NULL)
04924     return;
04925     ctxt->varLookupFunc = f;
04926     ctxt->varLookupData = data;
04927 }
04928 
04939 xmlXPathObjectPtr
04940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
04941     if (ctxt == NULL)
04942     return(NULL);
04943 
04944     if (ctxt->varLookupFunc != NULL) {
04945     xmlXPathObjectPtr ret;
04946 
04947     ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
04948             (ctxt->varLookupData, name, NULL);
04949     return(ret);
04950     }
04951     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
04952 }
04953 
04965 xmlXPathObjectPtr
04966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
04967              const xmlChar *ns_uri) {
04968     if (ctxt == NULL)
04969     return(NULL);
04970 
04971     if (ctxt->varLookupFunc != NULL) {
04972     xmlXPathObjectPtr ret;
04973 
04974     ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
04975             (ctxt->varLookupData, name, ns_uri);
04976     if (ret != NULL) return(ret);
04977     }
04978 
04979     if (ctxt->varHash == NULL)
04980     return(NULL);
04981     if (name == NULL)
04982     return(NULL);
04983 
04984     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
04985         xmlHashLookup2(ctxt->varHash, name, ns_uri)));
04986 }
04987 
04994 void
04995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
04996     if (ctxt == NULL)
04997     return;
04998 
04999     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
05000     ctxt->varHash = NULL;
05001 }
05002 
05014 int
05015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
05016                const xmlChar *ns_uri) {
05017     if (ctxt == NULL)
05018     return(-1);
05019     if (prefix == NULL)
05020     return(-1);
05021     if (prefix[0] == 0)
05022     return(-1);
05023 
05024     if (ctxt->nsHash == NULL)
05025     ctxt->nsHash = xmlHashCreate(10);
05026     if (ctxt->nsHash == NULL)
05027     return(-1);
05028     if (ns_uri == NULL)
05029         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
05030                               (xmlHashDeallocator)xmlFree));
05031     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
05032                   (xmlHashDeallocator)xmlFree));
05033 }
05034 
05045 const xmlChar *
05046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
05047     if (ctxt == NULL)
05048     return(NULL);
05049     if (prefix == NULL)
05050     return(NULL);
05051 
05052 #ifdef XML_XML_NAMESPACE
05053     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
05054     return(XML_XML_NAMESPACE);
05055 #endif
05056 
05057     if (ctxt->namespaces != NULL) {
05058     int i;
05059 
05060     for (i = 0;i < ctxt->nsNr;i++) {
05061         if ((ctxt->namespaces[i] != NULL) &&
05062         (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
05063         return(ctxt->namespaces[i]->href);
05064     }
05065     }
05066 
05067     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
05068 }
05069 
05076 void
05077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
05078     if (ctxt == NULL)
05079     return;
05080 
05081     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
05082     ctxt->nsHash = NULL;
05083 }
05084 
05085 /************************************************************************
05086  *                                  *
05087  *          Routines to handle Values           *
05088  *                                  *
05089  ************************************************************************/
05090 
05091 /* Allocations are terrible, one needs to optimize all this !!! */
05092 
05101 xmlXPathObjectPtr
05102 xmlXPathNewFloat(double val) {
05103     xmlXPathObjectPtr ret;
05104 
05105     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05106     if (ret == NULL) {
05107         xmlXPathErrMemory(NULL, "creating float object\n");
05108     return(NULL);
05109     }
05110     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05111     ret->type = XPATH_NUMBER;
05112     ret->floatval = val;
05113 #ifdef XP_DEBUG_OBJ_USAGE
05114     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
05115 #endif
05116     return(ret);
05117 }
05118 
05127 xmlXPathObjectPtr
05128 xmlXPathNewBoolean(int val) {
05129     xmlXPathObjectPtr ret;
05130 
05131     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05132     if (ret == NULL) {
05133         xmlXPathErrMemory(NULL, "creating boolean object\n");
05134     return(NULL);
05135     }
05136     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05137     ret->type = XPATH_BOOLEAN;
05138     ret->boolval = (val != 0);
05139 #ifdef XP_DEBUG_OBJ_USAGE
05140     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
05141 #endif
05142     return(ret);
05143 }
05144 
05153 xmlXPathObjectPtr
05154 xmlXPathNewString(const xmlChar *val) {
05155     xmlXPathObjectPtr ret;
05156 
05157     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05158     if (ret == NULL) {
05159         xmlXPathErrMemory(NULL, "creating string object\n");
05160     return(NULL);
05161     }
05162     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05163     ret->type = XPATH_STRING;
05164     if (val != NULL)
05165     ret->stringval = xmlStrdup(val);
05166     else
05167     ret->stringval = xmlStrdup((const xmlChar *)"");
05168 #ifdef XP_DEBUG_OBJ_USAGE
05169     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
05170 #endif
05171     return(ret);
05172 }
05173 
05182 xmlXPathObjectPtr
05183 xmlXPathWrapString (xmlChar *val) {
05184     xmlXPathObjectPtr ret;
05185 
05186     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05187     if (ret == NULL) {
05188         xmlXPathErrMemory(NULL, "creating string object\n");
05189     return(NULL);
05190     }
05191     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05192     ret->type = XPATH_STRING;
05193     ret->stringval = val;
05194 #ifdef XP_DEBUG_OBJ_USAGE
05195     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
05196 #endif
05197     return(ret);
05198 }
05199 
05208 xmlXPathObjectPtr
05209 xmlXPathNewCString(const char *val) {
05210     xmlXPathObjectPtr ret;
05211 
05212     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05213     if (ret == NULL) {
05214         xmlXPathErrMemory(NULL, "creating string object\n");
05215     return(NULL);
05216     }
05217     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05218     ret->type = XPATH_STRING;
05219     ret->stringval = xmlStrdup(BAD_CAST val);
05220 #ifdef XP_DEBUG_OBJ_USAGE
05221     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
05222 #endif
05223     return(ret);
05224 }
05225 
05234 xmlXPathObjectPtr
05235 xmlXPathWrapCString (char * val) {
05236     return(xmlXPathWrapString((xmlChar *)(val)));
05237 }
05238 
05247 xmlXPathObjectPtr
05248 xmlXPathWrapExternal (void *val) {
05249     xmlXPathObjectPtr ret;
05250 
05251     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05252     if (ret == NULL) {
05253         xmlXPathErrMemory(NULL, "creating user object\n");
05254     return(NULL);
05255     }
05256     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
05257     ret->type = XPATH_USERS;
05258     ret->user = val;
05259 #ifdef XP_DEBUG_OBJ_USAGE
05260     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
05261 #endif
05262     return(ret);
05263 }
05264 
05273 xmlXPathObjectPtr
05274 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
05275     xmlXPathObjectPtr ret;
05276 
05277     if (val == NULL)
05278     return(NULL);
05279 
05280     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
05281     if (ret == NULL) {
05282         xmlXPathErrMemory(NULL, "copying object\n");
05283     return(NULL);
05284     }
05285     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
05286 #ifdef XP_DEBUG_OBJ_USAGE
05287     xmlXPathDebugObjUsageRequested(NULL, val->type);
05288 #endif
05289     switch (val->type) {
05290     case XPATH_BOOLEAN:
05291     case XPATH_NUMBER:
05292     case XPATH_POINT:
05293     case XPATH_RANGE:
05294         break;
05295     case XPATH_STRING:
05296         ret->stringval = xmlStrdup(val->stringval);
05297         break;
05298     case XPATH_XSLT_TREE:
05299 #if 0
05300 /*
05301   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
05302   this previous handling is no longer correct, and can cause some serious
05303   problems (ref. bug 145547)
05304 */
05305         if ((val->nodesetval != NULL) &&
05306         (val->nodesetval->nodeTab != NULL)) {
05307         xmlNodePtr cur, tmp;
05308         xmlDocPtr top;
05309 
05310         ret->boolval = 1;
05311         top =  xmlNewDoc(NULL);
05312         top->name = (char *)
05313             xmlStrdup(val->nodesetval->nodeTab[0]->name);
05314         ret->user = top;
05315         if (top != NULL) {
05316             top->doc = top;
05317             cur = val->nodesetval->nodeTab[0]->children;
05318             while (cur != NULL) {
05319             tmp = xmlDocCopyNode(cur, top, 1);
05320             xmlAddChild((xmlNodePtr) top, tmp);
05321             cur = cur->next;
05322             }
05323         }
05324 
05325         ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
05326         } else
05327         ret->nodesetval = xmlXPathNodeSetCreate(NULL);
05328         /* Deallocate the copied tree value */
05329         break;
05330 #endif
05331     case XPATH_NODESET:
05332         ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
05333         /* Do not deallocate the copied tree value */
05334         ret->boolval = 0;
05335         break;
05336     case XPATH_LOCATIONSET:
05337 #ifdef LIBXML_XPTR_ENABLED
05338     {
05339         xmlLocationSetPtr loc = val->user;
05340         ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
05341         break;
05342     }
05343 #endif
05344         case XPATH_USERS:
05345         ret->user = val->user;
05346         break;
05347         case XPATH_UNDEFINED:
05348         xmlGenericError(xmlGenericErrorContext,
05349             "xmlXPathObjectCopy: unsupported type %d\n",
05350             val->type);
05351         break;
05352     }
05353     return(ret);
05354 }
05355 
05362 void
05363 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
05364     if (obj == NULL) return;
05365     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
05366     if (obj->boolval) {
05367 #if 0
05368         if (obj->user != NULL) {
05369                 xmlXPathFreeNodeSet(obj->nodesetval);
05370         xmlFreeNodeList((xmlNodePtr) obj->user);
05371         } else
05372 #endif
05373         obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
05374         if (obj->nodesetval != NULL)
05375         xmlXPathFreeValueTree(obj->nodesetval);
05376     } else {
05377         if (obj->nodesetval != NULL)
05378         xmlXPathFreeNodeSet(obj->nodesetval);
05379     }
05380 #ifdef LIBXML_XPTR_ENABLED
05381     } else if (obj->type == XPATH_LOCATIONSET) {
05382     if (obj->user != NULL)
05383         xmlXPtrFreeLocationSet(obj->user);
05384 #endif
05385     } else if (obj->type == XPATH_STRING) {
05386     if (obj->stringval != NULL)
05387         xmlFree(obj->stringval);
05388     }
05389 #ifdef XP_DEBUG_OBJ_USAGE
05390     xmlXPathDebugObjUsageReleased(NULL, obj->type);
05391 #endif
05392     xmlFree(obj);
05393 }
05394 
05402 static void
05403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
05404 {
05405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
05406     sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
05407     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
05408 
05409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
05410 
05411     if (obj == NULL)
05412     return;
05413     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
05414      xmlXPathFreeObject(obj);
05415     } else {
05416     xmlXPathContextCachePtr cache =
05417         (xmlXPathContextCachePtr) ctxt->cache;
05418 
05419     switch (obj->type) {
05420         case XPATH_NODESET:
05421         case XPATH_XSLT_TREE:
05422         if (obj->nodesetval != NULL) {
05423             if (obj->boolval) {
05424             /*
05425             * It looks like the @boolval is used for
05426             * evaluation if this an XSLT Result Tree Fragment.
05427             * TODO: Check if this assumption is correct.
05428             */
05429             obj->type = XPATH_XSLT_TREE; /* just for debugging */
05430             xmlXPathFreeValueTree(obj->nodesetval);
05431             obj->nodesetval = NULL;
05432             } else if ((obj->nodesetval->nodeMax <= 40) &&
05433             (XP_CACHE_WANTS(cache->nodesetObjs,
05434                     cache->maxNodeset)))
05435             {
05436             XP_CACHE_ADD(cache->nodesetObjs, obj);
05437             goto obj_cached;
05438             } else {
05439             xmlXPathFreeNodeSet(obj->nodesetval);
05440             obj->nodesetval = NULL;
05441             }
05442         }
05443         break;
05444         case XPATH_STRING:
05445         if (obj->stringval != NULL)
05446             xmlFree(obj->stringval);
05447 
05448         if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
05449             XP_CACHE_ADD(cache->stringObjs, obj);
05450             goto obj_cached;
05451         }
05452         break;
05453         case XPATH_BOOLEAN:
05454         if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
05455             XP_CACHE_ADD(cache->booleanObjs, obj);
05456             goto obj_cached;
05457         }
05458         break;
05459         case XPATH_NUMBER:
05460         if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
05461             XP_CACHE_ADD(cache->numberObjs, obj);
05462             goto obj_cached;
05463         }
05464         break;
05465 #ifdef LIBXML_XPTR_ENABLED
05466         case XPATH_LOCATIONSET:
05467         if (obj->user != NULL) {
05468             xmlXPtrFreeLocationSet(obj->user);
05469         }
05470         goto free_obj;
05471 #endif
05472         default:
05473         goto free_obj;
05474     }
05475 
05476     /*
05477     * Fallback to adding to the misc-objects slot.
05478     */
05479     if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
05480         XP_CACHE_ADD(cache->miscObjs, obj);
05481     } else
05482         goto free_obj;
05483 
05484 obj_cached:
05485 
05486 #ifdef XP_DEBUG_OBJ_USAGE
05487     xmlXPathDebugObjUsageReleased(ctxt, obj->type);
05488 #endif
05489 
05490     if (obj->nodesetval != NULL) {
05491         xmlNodeSetPtr tmpset = obj->nodesetval;
05492 
05493         /*
05494         * TODO: Due to those nasty ns-nodes, we need to traverse
05495         *  the list and free the ns-nodes.
05496         * URGENT TODO: Check if it's actually slowing things down.
05497         *  Maybe we shouldn't try to preserve the list.
05498         */
05499         if (tmpset->nodeNr > 1) {
05500         int i;
05501         xmlNodePtr node;
05502 
05503         for (i = 0; i < tmpset->nodeNr; i++) {
05504             node = tmpset->nodeTab[i];
05505             if ((node != NULL) &&
05506             (node->type == XML_NAMESPACE_DECL))
05507             {
05508             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
05509             }
05510         }
05511         } else if (tmpset->nodeNr == 1) {
05512         if ((tmpset->nodeTab[0] != NULL) &&
05513             (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
05514             xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
05515         }
05516         tmpset->nodeNr = 0;
05517         memset(obj, 0, sizeof(xmlXPathObject));
05518         obj->nodesetval = tmpset;
05519     } else
05520         memset(obj, 0, sizeof(xmlXPathObject));
05521 
05522     return;
05523 
05524 free_obj:
05525     /*
05526     * Cache is full; free the object.
05527     */
05528     if (obj->nodesetval != NULL)
05529         xmlXPathFreeNodeSet(obj->nodesetval);
05530 #ifdef XP_DEBUG_OBJ_USAGE
05531     xmlXPathDebugObjUsageReleased(NULL, obj->type);
05532 #endif
05533     xmlFree(obj);
05534     }
05535     return;
05536 }
05537 
05538 
05539 /************************************************************************
05540  *                                  *
05541  *          Type Casting Routines               *
05542  *                                  *
05543  ************************************************************************/
05544 
05553 xmlChar *
05554 xmlXPathCastBooleanToString (int val) {
05555     xmlChar *ret;
05556     if (val)
05557     ret = xmlStrdup((const xmlChar *) "true");
05558     else
05559     ret = xmlStrdup((const xmlChar *) "false");
05560     return(ret);
05561 }
05562 
05571 xmlChar *
05572 xmlXPathCastNumberToString (double val) {
05573     xmlChar *ret;
05574     switch (xmlXPathIsInf(val)) {
05575     case 1:
05576     ret = xmlStrdup((const xmlChar *) "Infinity");
05577     break;
05578     case -1:
05579     ret = xmlStrdup((const xmlChar *) "-Infinity");
05580     break;
05581     default:
05582     if (xmlXPathIsNaN(val)) {
05583         ret = xmlStrdup((const xmlChar *) "NaN");
05584     } else if (val == 0 && xmlXPathGetSign(val) != 0) {
05585         ret = xmlStrdup((const xmlChar *) "0");
05586     } else {
05587         /* could be improved */
05588         char buf[100];
05589         xmlXPathFormatNumber(val, buf, 99);
05590         buf[99] = 0;
05591         ret = xmlStrdup((const xmlChar *) buf);
05592     }
05593     }
05594     return(ret);
05595 }
05596 
05605 xmlChar *
05606 xmlXPathCastNodeToString (xmlNodePtr node) {
05607 xmlChar *ret;
05608     if ((ret = xmlNodeGetContent(node)) == NULL)
05609     ret = xmlStrdup((const xmlChar *) "");
05610     return(ret);
05611 }
05612 
05621 xmlChar *
05622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
05623     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
05624     return(xmlStrdup((const xmlChar *) ""));
05625 
05626     if (ns->nodeNr > 1)
05627     xmlXPathNodeSetSort(ns);
05628     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
05629 }
05630 
05640 xmlChar *
05641 xmlXPathCastToString(xmlXPathObjectPtr val) {
05642     xmlChar *ret = NULL;
05643 
05644     if (val == NULL)
05645     return(xmlStrdup((const xmlChar *) ""));
05646     switch (val->type) {
05647     case XPATH_UNDEFINED:
05648 #ifdef DEBUG_EXPR
05649         xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
05650 #endif
05651         ret = xmlStrdup((const xmlChar *) "");
05652         break;
05653         case XPATH_NODESET:
05654         case XPATH_XSLT_TREE:
05655         ret = xmlXPathCastNodeSetToString(val->nodesetval);
05656         break;
05657     case XPATH_STRING:
05658         return(xmlStrdup(val->stringval));
05659         case XPATH_BOOLEAN:
05660         ret = xmlXPathCastBooleanToString(val->boolval);
05661         break;
05662     case XPATH_NUMBER: {
05663         ret = xmlXPathCastNumberToString(val->floatval);
05664         break;
05665     }
05666     case XPATH_USERS:
05667     case XPATH_POINT:
05668     case XPATH_RANGE:
05669     case XPATH_LOCATIONSET:
05670         TODO
05671         ret = xmlStrdup((const xmlChar *) "");
05672         break;
05673     }
05674     return(ret);
05675 }
05676 
05686 xmlXPathObjectPtr
05687 xmlXPathConvertString(xmlXPathObjectPtr val) {
05688     xmlChar *res = NULL;
05689 
05690     if (val == NULL)
05691     return(xmlXPathNewCString(""));
05692 
05693     switch (val->type) {
05694     case XPATH_UNDEFINED:
05695 #ifdef DEBUG_EXPR
05696     xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
05697 #endif
05698     break;
05699     case XPATH_NODESET:
05700     case XPATH_XSLT_TREE:
05701     res = xmlXPathCastNodeSetToString(val->nodesetval);
05702     break;
05703     case XPATH_STRING:
05704     return(val);
05705     case XPATH_BOOLEAN:
05706     res = xmlXPathCastBooleanToString(val->boolval);
05707     break;
05708     case XPATH_NUMBER:
05709     res = xmlXPathCastNumberToString(val->floatval);
05710     break;
05711     case XPATH_USERS:
05712     case XPATH_POINT:
05713     case XPATH_RANGE:
05714     case XPATH_LOCATIONSET:
05715     TODO;
05716     break;
05717     }
05718     xmlXPathFreeObject(val);
05719     if (res == NULL)
05720     return(xmlXPathNewCString(""));
05721     return(xmlXPathWrapString(res));
05722 }
05723 
05732 double
05733 xmlXPathCastBooleanToNumber(int val) {
05734     if (val)
05735     return(1.0);
05736     return(0.0);
05737 }
05738 
05747 double
05748 xmlXPathCastStringToNumber(const xmlChar * val) {
05749     return(xmlXPathStringEvalNumber(val));
05750 }
05751 
05760 double
05761 xmlXPathCastNodeToNumber (xmlNodePtr node) {
05762     xmlChar *strval;
05763     double ret;
05764 
05765     if (node == NULL)
05766     return(xmlXPathNAN);
05767     strval = xmlXPathCastNodeToString(node);
05768     if (strval == NULL)
05769     return(xmlXPathNAN);
05770     ret = xmlXPathCastStringToNumber(strval);
05771     xmlFree(strval);
05772 
05773     return(ret);
05774 }
05775 
05784 double
05785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
05786     xmlChar *str;
05787     double ret;
05788 
05789     if (ns == NULL)
05790     return(xmlXPathNAN);
05791     str = xmlXPathCastNodeSetToString(ns);
05792     ret = xmlXPathCastStringToNumber(str);
05793     xmlFree(str);
05794     return(ret);
05795 }
05796 
05805 double
05806 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
05807     double ret = 0.0;
05808 
05809     if (val == NULL)
05810     return(xmlXPathNAN);
05811     switch (val->type) {
05812     case XPATH_UNDEFINED:
05813 #ifdef DEGUB_EXPR
05814     xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
05815 #endif
05816     ret = xmlXPathNAN;
05817     break;
05818     case XPATH_NODESET:
05819     case XPATH_XSLT_TREE:
05820     ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
05821     break;
05822     case XPATH_STRING:
05823     ret = xmlXPathCastStringToNumber(val->stringval);
05824     break;
05825     case XPATH_NUMBER:
05826     ret = val->floatval;
05827     break;
05828     case XPATH_BOOLEAN:
05829     ret = xmlXPathCastBooleanToNumber(val->boolval);
05830     break;
05831     case XPATH_USERS:
05832     case XPATH_POINT:
05833     case XPATH_RANGE:
05834     case XPATH_LOCATIONSET:
05835     TODO;
05836     ret = xmlXPathNAN;
05837     break;
05838     }
05839     return(ret);
05840 }
05841 
05851 xmlXPathObjectPtr
05852 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
05853     xmlXPathObjectPtr ret;
05854 
05855     if (val == NULL)
05856     return(xmlXPathNewFloat(0.0));
05857     if (val->type == XPATH_NUMBER)
05858     return(val);
05859     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
05860     xmlXPathFreeObject(val);
05861     return(ret);
05862 }
05863 
05872 int
05873 xmlXPathCastNumberToBoolean (double val) {
05874      if (xmlXPathIsNaN(val) || (val == 0.0))
05875      return(0);
05876      return(1);
05877 }
05878 
05887 int
05888 xmlXPathCastStringToBoolean (const xmlChar *val) {
05889     if ((val == NULL) || (xmlStrlen(val) == 0))
05890     return(0);
05891     return(1);
05892 }
05893 
05902 int
05903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
05904     if ((ns == NULL) || (ns->nodeNr == 0))
05905     return(0);
05906     return(1);
05907 }
05908 
05917 int
05918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
05919     int ret = 0;
05920 
05921     if (val == NULL)
05922     return(0);
05923     switch (val->type) {
05924     case XPATH_UNDEFINED:
05925 #ifdef DEBUG_EXPR
05926     xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
05927 #endif
05928     ret = 0;
05929     break;
05930     case XPATH_NODESET:
05931     case XPATH_XSLT_TREE:
05932     ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
05933     break;
05934     case XPATH_STRING:
05935     ret = xmlXPathCastStringToBoolean(val->stringval);
05936     break;
05937     case XPATH_NUMBER:
05938     ret = xmlXPathCastNumberToBoolean(val->floatval);
05939     break;
05940     case XPATH_BOOLEAN:
05941     ret = val->boolval;
05942     break;
05943     case XPATH_USERS:
05944     case XPATH_POINT:
05945     case XPATH_RANGE:
05946     case XPATH_LOCATIONSET:
05947     TODO;
05948     ret = 0;
05949     break;
05950     }
05951     return(ret);
05952 }
05953 
05954 
05964 xmlXPathObjectPtr
05965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
05966     xmlXPathObjectPtr ret;
05967 
05968     if (val == NULL)
05969     return(xmlXPathNewBoolean(0));
05970     if (val->type == XPATH_BOOLEAN)
05971     return(val);
05972     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
05973     xmlXPathFreeObject(val);
05974     return(ret);
05975 }
05976 
05977 /************************************************************************
05978  *                                  *
05979  *      Routines to handle XPath contexts           *
05980  *                                  *
05981  ************************************************************************/
05982 
05991 xmlXPathContextPtr
05992 xmlXPathNewContext(xmlDocPtr doc) {
05993     xmlXPathContextPtr ret;
05994 
05995     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
05996     if (ret == NULL) {
05997         xmlXPathErrMemory(NULL, "creating context\n");
05998     return(NULL);
05999     }
06000     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
06001     ret->doc = doc;
06002     ret->node = NULL;
06003 
06004     ret->varHash = NULL;
06005 
06006     ret->nb_types = 0;
06007     ret->max_types = 0;
06008     ret->types = NULL;
06009 
06010     ret->funcHash = xmlHashCreate(0);
06011 
06012     ret->nb_axis = 0;
06013     ret->max_axis = 0;
06014     ret->axis = NULL;
06015 
06016     ret->nsHash = NULL;
06017     ret->user = NULL;
06018 
06019     ret->contextSize = -1;
06020     ret->proximityPosition = -1;
06021 
06022 #ifdef XP_DEFAULT_CACHE_ON
06023     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
06024     xmlXPathFreeContext(ret);
06025     return(NULL);
06026     }
06027 #endif
06028 
06029     xmlXPathRegisterAllFunctions(ret);
06030 
06031     return(ret);
06032 }
06033 
06040 void
06041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
06042     if (ctxt == NULL) return;
06043 
06044     if (ctxt->cache != NULL)
06045     xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
06046     xmlXPathRegisteredNsCleanup(ctxt);
06047     xmlXPathRegisteredFuncsCleanup(ctxt);
06048     xmlXPathRegisteredVariablesCleanup(ctxt);
06049     xmlResetError(&ctxt->lastError);
06050     xmlFree(ctxt);
06051 }
06052 
06053 /************************************************************************
06054  *                                  *
06055  *      Routines to handle XPath parser contexts        *
06056  *                                  *
06057  ************************************************************************/
06058 
06059 #define CHECK_CTXT(ctxt)                        \
06060     if (ctxt == NULL) {                     \
06061     __xmlRaiseError(NULL, NULL, NULL,               \
06062         NULL, NULL, XML_FROM_XPATH,             \
06063         XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,          \
06064         __FILE__, __LINE__,                 \
06065         NULL, NULL, NULL, 0, 0,                 \
06066         "NULL context pointer\n");              \
06067     return(NULL);                           \
06068     }                                   \
06069 
06070 #define CHECK_CTXT_NEG(ctxt)                        \
06071     if (ctxt == NULL) {                     \
06072     __xmlRaiseError(NULL, NULL, NULL,               \
06073         NULL, NULL, XML_FROM_XPATH,             \
06074         XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,          \
06075         __FILE__, __LINE__,                 \
06076         NULL, NULL, NULL, 0, 0,                 \
06077         "NULL context pointer\n");              \
06078     return(-1);                         \
06079     }                                   \
06080 
06081 
06082 #define CHECK_CONTEXT(ctxt)                     \
06083     if ((ctxt == NULL) || (ctxt->doc == NULL) ||            \
06084         (ctxt->doc->children == NULL)) {                \
06085     xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
06086     return(NULL);                           \
06087     }
06088 
06089 
06099 xmlXPathParserContextPtr
06100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
06101     xmlXPathParserContextPtr ret;
06102 
06103     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
06104     if (ret == NULL) {
06105         xmlXPathErrMemory(ctxt, "creating parser context\n");
06106     return(NULL);
06107     }
06108     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
06109     ret->cur = ret->base = str;
06110     ret->context = ctxt;
06111 
06112     ret->comp = xmlXPathNewCompExpr();
06113     if (ret->comp == NULL) {
06114     xmlFree(ret->valueTab);
06115     xmlFree(ret);
06116     return(NULL);
06117     }
06118     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
06119         ret->comp->dict = ctxt->dict;
06120     xmlDictReference(ret->comp->dict);
06121     }
06122 
06123     return(ret);
06124 }
06125 
06135 static xmlXPathParserContextPtr
06136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
06137     xmlXPathParserContextPtr ret;
06138 
06139     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
06140     if (ret == NULL) {
06141         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
06142     return(NULL);
06143     }
06144     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
06145 
06146     /* Allocate the value stack */
06147     ret->valueTab = (xmlXPathObjectPtr *)
06148                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
06149     if (ret->valueTab == NULL) {
06150     xmlFree(ret);
06151     xmlXPathErrMemory(ctxt, "creating evaluation context\n");
06152     return(NULL);
06153     }
06154     ret->valueNr = 0;
06155     ret->valueMax = 10;
06156     ret->value = NULL;
06157 
06158     ret->context = ctxt;
06159     ret->comp = comp;
06160 
06161     return(ret);
06162 }
06163 
06170 void
06171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
06172     if (ctxt->valueTab != NULL) {
06173         xmlFree(ctxt->valueTab);
06174     }
06175     if (ctxt->comp != NULL) {
06176 #ifdef XPATH_STREAMING
06177     if (ctxt->comp->stream != NULL) {
06178         xmlFreePatternList(ctxt->comp->stream);
06179         ctxt->comp->stream = NULL;
06180     }
06181 #endif
06182     xmlXPathFreeCompExpr(ctxt->comp);
06183     }
06184     xmlFree(ctxt);
06185 }
06186 
06187 /************************************************************************
06188  *                                  *
06189  *      The implicit core function library          *
06190  *                                  *
06191  ************************************************************************/
06192 
06202 static unsigned int
06203 xmlXPathNodeValHash(xmlNodePtr node) {
06204     int len = 2;
06205     const xmlChar * string = NULL;
06206     xmlNodePtr tmp = NULL;
06207     unsigned int ret = 0;
06208 
06209     if (node == NULL)
06210     return(0);
06211 
06212     if (node->type == XML_DOCUMENT_NODE) {
06213     tmp = xmlDocGetRootElement((xmlDocPtr) node);
06214     if (tmp == NULL)
06215         node = node->children;
06216     else
06217         node = tmp;
06218 
06219     if (node == NULL)
06220         return(0);
06221     }
06222 
06223     switch (node->type) {
06224     case XML_COMMENT_NODE:
06225     case XML_PI_NODE:
06226     case XML_CDATA_SECTION_NODE:
06227     case XML_TEXT_NODE:
06228         string = node->content;
06229         if (string == NULL)
06230         return(0);
06231         if (string[0] == 0)
06232         return(0);
06233         return(((unsigned int) string[0]) +
06234            (((unsigned int) string[1]) << 8));
06235     case XML_NAMESPACE_DECL:
06236         string = ((xmlNsPtr)node)->href;
06237         if (string == NULL)
06238         return(0);
06239         if (string[0] == 0)
06240         return(0);
06241         return(((unsigned int) string[0]) +
06242            (((unsigned int) string[1]) << 8));
06243     case XML_ATTRIBUTE_NODE:
06244         tmp = ((xmlAttrPtr) node)->children;
06245         break;
06246     case XML_ELEMENT_NODE:
06247         tmp = node->children;
06248         break;
06249     default:
06250         return(0);
06251     }
06252     while (tmp != NULL) {
06253     switch (tmp->type) {
06254         case XML_COMMENT_NODE:
06255         case XML_PI_NODE:
06256         case XML_CDATA_SECTION_NODE:
06257         case XML_TEXT_NODE:
06258         string = tmp->content;
06259         break;
06260         case XML_NAMESPACE_DECL:
06261         string = ((xmlNsPtr)tmp)->href;
06262         break;
06263         default:
06264         break;
06265     }
06266     if ((string != NULL) && (string[0] != 0)) {
06267         if (len == 1) {
06268         return(ret + (((unsigned int) string[0]) << 8));
06269         }
06270         if (string[1] == 0) {
06271         len = 1;
06272         ret = (unsigned int) string[0];
06273         } else {
06274         return(((unsigned int) string[0]) +
06275                (((unsigned int) string[1]) << 8));
06276         }
06277     }
06278     /*
06279      * Skip to next node
06280      */
06281     if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
06282         if (tmp->children->type != XML_ENTITY_DECL) {
06283         tmp = tmp->children;
06284         continue;
06285         }
06286     }
06287     if (tmp == node)
06288         break;
06289 
06290     if (tmp->next != NULL) {
06291         tmp = tmp->next;
06292         continue;
06293     }
06294 
06295     do {
06296         tmp = tmp->parent;
06297         if (tmp == NULL)
06298         break;
06299         if (tmp == node) {
06300         tmp = NULL;
06301         break;
06302         }
06303         if (tmp->next != NULL) {
06304         tmp = tmp->next;
06305         break;
06306         }
06307     } while (tmp != NULL);
06308     }
06309     return(ret);
06310 }
06311 
06321 static unsigned int
06322 xmlXPathStringHash(const xmlChar * string) {
06323     if (string == NULL)
06324     return((unsigned int) 0);
06325     if (string[0] == 0)
06326     return(0);
06327     return(((unsigned int) string[0]) +
06328        (((unsigned int) string[1]) << 8));
06329 }
06330 
06353 static int
06354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
06355                         xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
06356     int i, ret = 0;
06357     xmlNodeSetPtr ns;
06358     xmlChar *str2;
06359 
06360     if ((f == NULL) || (arg == NULL) ||
06361     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
06362     xmlXPathReleaseObject(ctxt->context, arg);
06363     xmlXPathReleaseObject(ctxt->context, f);
06364         return(0);
06365     }
06366     ns = arg->nodesetval;
06367     if (ns != NULL) {
06368     for (i = 0;i < ns->nodeNr;i++) {
06369          str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
06370          if (str2 != NULL) {
06371          valuePush(ctxt,
06372                xmlXPathCacheNewString(ctxt->context, str2));
06373          xmlFree(str2);
06374          xmlXPathNumberFunction(ctxt, 1);
06375          valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
06376          ret = xmlXPathCompareValues(ctxt, inf, strict);
06377          if (ret)
06378              break;
06379          }
06380     }
06381     }
06382     xmlXPathReleaseObject(ctxt->context, arg);
06383     xmlXPathReleaseObject(ctxt->context, f);
06384     return(ret);
06385 }
06386 
06408 static int
06409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
06410                         xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
06411     int i, ret = 0;
06412     xmlNodeSetPtr ns;
06413     xmlChar *str2;
06414 
06415     if ((s == NULL) || (arg == NULL) ||
06416     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
06417     xmlXPathReleaseObject(ctxt->context, arg);
06418     xmlXPathReleaseObject(ctxt->context, s);
06419         return(0);
06420     }
06421     ns = arg->nodesetval;
06422     if (ns != NULL) {
06423     for (i = 0;i < ns->nodeNr;i++) {
06424          str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
06425          if (str2 != NULL) {
06426          valuePush(ctxt,
06427                xmlXPathCacheNewString(ctxt->context, str2));
06428          xmlFree(str2);
06429          valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
06430          ret = xmlXPathCompareValues(ctxt, inf, strict);
06431          if (ret)
06432              break;
06433          }
06434     }
06435     }
06436     xmlXPathReleaseObject(ctxt->context, arg);
06437     xmlXPathReleaseObject(ctxt->context, s);
06438     return(ret);
06439 }
06440 
06469 static int
06470 xmlXPathCompareNodeSets(int inf, int strict,
06471                     xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
06472     int i, j, init = 0;
06473     double val1;
06474     double *values2;
06475     int ret = 0;
06476     xmlNodeSetPtr ns1;
06477     xmlNodeSetPtr ns2;
06478 
06479     if ((arg1 == NULL) ||
06480     ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
06481     xmlXPathFreeObject(arg2);
06482         return(0);
06483     }
06484     if ((arg2 == NULL) ||
06485     ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
06486     xmlXPathFreeObject(arg1);
06487     xmlXPathFreeObject(arg2);
06488         return(0);
06489     }
06490 
06491     ns1 = arg1->nodesetval;
06492     ns2 = arg2->nodesetval;
06493 
06494     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
06495     xmlXPathFreeObject(arg1);
06496     xmlXPathFreeObject(arg2);
06497     return(0);
06498     }
06499     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
06500     xmlXPathFreeObject(arg1);
06501     xmlXPathFreeObject(arg2);
06502     return(0);
06503     }
06504 
06505     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
06506     if (values2 == NULL) {
06507         xmlXPathErrMemory(NULL, "comparing nodesets\n");
06508     xmlXPathFreeObject(arg1);
06509     xmlXPathFreeObject(arg2);
06510     return(0);
06511     }
06512     for (i = 0;i < ns1->nodeNr;i++) {
06513     val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
06514     if (xmlXPathIsNaN(val1))
06515         continue;
06516     for (j = 0;j < ns2->nodeNr;j++) {
06517         if (init == 0) {
06518         values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
06519         }
06520         if (xmlXPathIsNaN(values2[j]))
06521         continue;
06522         if (inf && strict)
06523         ret = (val1 < values2[j]);
06524         else if (inf && !strict)
06525         ret = (val1 <= values2[j]);
06526         else if (!inf && strict)
06527         ret = (val1 > values2[j]);
06528         else if (!inf && !strict)
06529         ret = (val1 >= values2[j]);
06530         if (ret)
06531         break;
06532     }
06533     if (ret)
06534         break;
06535     init = 1;
06536     }
06537     xmlFree(values2);
06538     xmlXPathFreeObject(arg1);
06539     xmlXPathFreeObject(arg2);
06540     return(ret);
06541 }
06542 
06564 static int
06565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
06566                         xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
06567     if ((val == NULL) || (arg == NULL) ||
06568     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
06569         return(0);
06570 
06571     switch(val->type) {
06572         case XPATH_NUMBER:
06573         return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
06574         case XPATH_NODESET:
06575         case XPATH_XSLT_TREE:
06576         return(xmlXPathCompareNodeSets(inf, strict, arg, val));
06577         case XPATH_STRING:
06578         return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
06579         case XPATH_BOOLEAN:
06580         valuePush(ctxt, arg);
06581         xmlXPathBooleanFunction(ctxt, 1);
06582         valuePush(ctxt, val);
06583         return(xmlXPathCompareValues(ctxt, inf, strict));
06584     default:
06585         TODO
06586     }
06587     return(0);
06588 }
06589 
06604 static int
06605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
06606 {
06607     int i;
06608     xmlNodeSetPtr ns;
06609     xmlChar *str2;
06610     unsigned int hash;
06611 
06612     if ((str == NULL) || (arg == NULL) ||
06613         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
06614         return (0);
06615     ns = arg->nodesetval;
06616     /*
06617      * A NULL nodeset compared with a string is always false
06618      * (since there is no node equal, and no node not equal)
06619      */
06620     if ((ns == NULL) || (ns->nodeNr <= 0) )
06621         return (0);
06622     hash = xmlXPathStringHash(str);
06623     for (i = 0; i < ns->nodeNr; i++) {
06624         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
06625             str2 = xmlNodeGetContent(ns->nodeTab[i]);
06626             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
06627                 xmlFree(str2);
06628         if (neq)
06629             continue;
06630                 return (1);
06631         } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
06632         if (neq)
06633             continue;
06634                 return (1);
06635             } else if (neq) {
06636         if (str2 != NULL)
06637             xmlFree(str2);
06638         return (1);
06639         }
06640             if (str2 != NULL)
06641                 xmlFree(str2);
06642         } else if (neq)
06643         return (1);
06644     }
06645     return (0);
06646 }
06647 
06663 static int
06664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
06665     xmlXPathObjectPtr arg, double f, int neq) {
06666   int i, ret=0;
06667   xmlNodeSetPtr ns;
06668   xmlChar *str2;
06669   xmlXPathObjectPtr val;
06670   double v;
06671 
06672     if ((arg == NULL) ||
06673     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
06674         return(0);
06675 
06676     ns = arg->nodesetval;
06677     if (ns != NULL) {
06678     for (i=0;i<ns->nodeNr;i++) {
06679         str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
06680         if (str2 != NULL) {
06681         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
06682         xmlFree(str2);
06683         xmlXPathNumberFunction(ctxt, 1);
06684         val = valuePop(ctxt);
06685         v = val->floatval;
06686         xmlXPathReleaseObject(ctxt->context, val);
06687         if (!xmlXPathIsNaN(v)) {
06688             if ((!neq) && (v==f)) {
06689             ret = 1;
06690             break;
06691             } else if ((neq) && (v!=f)) {
06692             ret = 1;
06693             break;
06694             }
06695         } else {    /* NaN is unequal to any value */
06696             if (neq)
06697             ret = 1;
06698         }
06699         }
06700     }
06701     }
06702 
06703     return(ret);
06704 }
06705 
06706 
06724 static int
06725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
06726     int i, j;
06727     unsigned int *hashs1;
06728     unsigned int *hashs2;
06729     xmlChar **values1;
06730     xmlChar **values2;
06731     int ret = 0;
06732     xmlNodeSetPtr ns1;
06733     xmlNodeSetPtr ns2;
06734 
06735     if ((arg1 == NULL) ||
06736     ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
06737         return(0);
06738     if ((arg2 == NULL) ||
06739     ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
06740         return(0);
06741 
06742     ns1 = arg1->nodesetval;
06743     ns2 = arg2->nodesetval;
06744 
06745     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
06746     return(0);
06747     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
06748     return(0);
06749 
06750     /*
06751      * for equal, check if there is a node pertaining to both sets
06752      */
06753     if (neq == 0)
06754     for (i = 0;i < ns1->nodeNr;i++)
06755         for (j = 0;j < ns2->nodeNr;j++)
06756         if (ns1->nodeTab[i] == ns2->nodeTab[j])
06757             return(1);
06758 
06759     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
06760     if (values1 == NULL) {
06761         xmlXPathErrMemory(NULL, "comparing nodesets\n");
06762     return(0);
06763     }
06764     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
06765     if (hashs1 == NULL) {
06766         xmlXPathErrMemory(NULL, "comparing nodesets\n");
06767     xmlFree(values1);
06768     return(0);
06769     }
06770     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
06771     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
06772     if (values2 == NULL) {
06773         xmlXPathErrMemory(NULL, "comparing nodesets\n");
06774     xmlFree(hashs1);
06775     xmlFree(values1);
06776     return(0);
06777     }
06778     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
06779     if (hashs2 == NULL) {
06780         xmlXPathErrMemory(NULL, "comparing nodesets\n");
06781     xmlFree(hashs1);
06782     xmlFree(values1);
06783     xmlFree(values2);
06784     return(0);
06785     }
06786     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
06787     for (i = 0;i < ns1->nodeNr;i++) {
06788     hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
06789     for (j = 0;j < ns2->nodeNr;j++) {
06790         if (i == 0)
06791         hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
06792         if (hashs1[i] != hashs2[j]) {
06793         if (neq) {
06794             ret = 1;
06795             break;
06796         }
06797         }
06798         else {
06799         if (values1[i] == NULL)
06800             values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
06801         if (values2[j] == NULL)
06802             values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
06803         ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
06804         if (ret)
06805             break;
06806         }
06807     }
06808     if (ret)
06809         break;
06810     }
06811     for (i = 0;i < ns1->nodeNr;i++)
06812     if (values1[i] != NULL)
06813         xmlFree(values1[i]);
06814     for (j = 0;j < ns2->nodeNr;j++)
06815     if (values2[j] != NULL)
06816         xmlFree(values2[j]);
06817     xmlFree(values1);
06818     xmlFree(values2);
06819     xmlFree(hashs1);
06820     xmlFree(hashs2);
06821     return(ret);
06822 }
06823 
06824 static int
06825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
06826   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
06827     int ret = 0;
06828     /*
06829      *At this point we are assured neither arg1 nor arg2
06830      *is a nodeset, so we can just pick the appropriate routine.
06831      */
06832     switch (arg1->type) {
06833         case XPATH_UNDEFINED:
06834 #ifdef DEBUG_EXPR
06835         xmlGenericError(xmlGenericErrorContext,
06836             "Equal: undefined\n");
06837 #endif
06838         break;
06839         case XPATH_BOOLEAN:
06840         switch (arg2->type) {
06841             case XPATH_UNDEFINED:
06842 #ifdef DEBUG_EXPR
06843             xmlGenericError(xmlGenericErrorContext,
06844                 "Equal: undefined\n");
06845 #endif
06846             break;
06847         case XPATH_BOOLEAN:
06848 #ifdef DEBUG_EXPR
06849             xmlGenericError(xmlGenericErrorContext,
06850                 "Equal: %d boolean %d \n",
06851                 arg1->boolval, arg2->boolval);
06852 #endif
06853             ret = (arg1->boolval == arg2->boolval);
06854             break;
06855         case XPATH_NUMBER:
06856             ret = (arg1->boolval ==
06857                xmlXPathCastNumberToBoolean(arg2->floatval));
06858             break;
06859         case XPATH_STRING:
06860             if ((arg2->stringval == NULL) ||
06861             (arg2->stringval[0] == 0)) ret = 0;
06862             else
06863             ret = 1;
06864             ret = (arg1->boolval == ret);
06865             break;
06866         case XPATH_USERS:
06867         case XPATH_POINT:
06868         case XPATH_RANGE:
06869         case XPATH_LOCATIONSET:
06870             TODO
06871             break;
06872         case XPATH_NODESET:
06873         case XPATH_XSLT_TREE:
06874             break;
06875         }
06876         break;
06877         case XPATH_NUMBER:
06878         switch (arg2->type) {
06879             case XPATH_UNDEFINED:
06880 #ifdef DEBUG_EXPR
06881             xmlGenericError(xmlGenericErrorContext,
06882                 "Equal: undefined\n");
06883 #endif
06884             break;
06885         case XPATH_BOOLEAN:
06886             ret = (arg2->boolval==
06887                xmlXPathCastNumberToBoolean(arg1->floatval));
06888             break;
06889         case XPATH_STRING:
06890             valuePush(ctxt, arg2);
06891             xmlXPathNumberFunction(ctxt, 1);
06892             arg2 = valuePop(ctxt);
06893             /* no break on purpose */
06894         case XPATH_NUMBER:
06895             /* Hand check NaN and Infinity equalities */
06896             if (xmlXPathIsNaN(arg1->floatval) ||
06897                 xmlXPathIsNaN(arg2->floatval)) {
06898                 ret = 0;
06899             } else if (xmlXPathIsInf(arg1->floatval) == 1) {
06900                 if (xmlXPathIsInf(arg2->floatval) == 1)
06901                 ret = 1;
06902             else
06903                 ret = 0;
06904             } else if (xmlXPathIsInf(arg1->floatval) == -1) {
06905             if (xmlXPathIsInf(arg2->floatval) == -1)
06906                 ret = 1;
06907             else
06908                 ret = 0;
06909             } else if (xmlXPathIsInf(arg2->floatval) == 1) {
06910             if (xmlXPathIsInf(arg1->floatval) == 1)
06911                 ret = 1;
06912             else
06913                 ret = 0;
06914             } else if (xmlXPathIsInf(arg2->floatval) == -1) {
06915             if (xmlXPathIsInf(arg1->floatval) == -1)
06916                 ret = 1;
06917             else
06918                 ret = 0;
06919             } else {
06920                 ret = (arg1->floatval == arg2->floatval);
06921             }
06922             break;
06923         case XPATH_USERS:
06924         case XPATH_POINT:
06925         case XPATH_RANGE:
06926         case XPATH_LOCATIONSET:
06927             TODO
06928             break;
06929         case XPATH_NODESET:
06930         case XPATH_XSLT_TREE:
06931             break;
06932         }
06933         break;
06934         case XPATH_STRING:
06935         switch (arg2->type) {
06936             case XPATH_UNDEFINED:
06937 #ifdef DEBUG_EXPR
06938             xmlGenericError(xmlGenericErrorContext,
06939                 "Equal: undefined\n");
06940 #endif
06941             break;
06942         case XPATH_BOOLEAN:
06943             if ((arg1->stringval == NULL) ||
06944             (arg1->stringval[0] == 0)) ret = 0;
06945             else
06946             ret = 1;
06947             ret = (arg2->boolval == ret);
06948             break;
06949         case XPATH_STRING:
06950             ret = xmlStrEqual(arg1->stringval, arg2->stringval);
06951             break;
06952         case XPATH_NUMBER:
06953             valuePush(ctxt, arg1);
06954             xmlXPathNumberFunction(ctxt, 1);
06955             arg1 = valuePop(ctxt);
06956             /* Hand check NaN and Infinity equalities */
06957             if (xmlXPathIsNaN(arg1->floatval) ||
06958                 xmlXPathIsNaN(arg2->floatval)) {
06959                 ret = 0;
06960             } else if (xmlXPathIsInf(arg1->floatval) == 1) {
06961             if (xmlXPathIsInf(arg2->floatval) == 1)
06962                 ret = 1;
06963             else
06964                 ret = 0;
06965             } else if (xmlXPathIsInf(arg1->floatval) == -1) {
06966             if (xmlXPathIsInf(arg2->floatval) == -1)
06967                 ret = 1;
06968             else
06969                 ret = 0;
06970             } else if (xmlXPathIsInf(arg2->floatval) == 1) {
06971             if (xmlXPathIsInf(arg1->floatval) == 1)
06972                 ret = 1;
06973             else
06974                 ret = 0;
06975             } else if (xmlXPathIsInf(arg2->floatval) == -1) {
06976             if (xmlXPathIsInf(arg1->floatval) == -1)
06977                 ret = 1;
06978             else
06979                 ret = 0;
06980             } else {
06981                 ret = (arg1->floatval == arg2->floatval);
06982             }
06983             break;
06984         case XPATH_USERS:
06985         case XPATH_POINT:
06986         case XPATH_RANGE:
06987         case XPATH_LOCATIONSET:
06988             TODO
06989             break;
06990         case XPATH_NODESET:
06991         case XPATH_XSLT_TREE:
06992             break;
06993         }
06994         break;
06995         case XPATH_USERS:
06996     case XPATH_POINT:
06997     case XPATH_RANGE:
06998     case XPATH_LOCATIONSET:
06999         TODO
07000         break;
07001     case XPATH_NODESET:
07002     case XPATH_XSLT_TREE:
07003         break;
07004     }
07005     xmlXPathReleaseObject(ctxt->context, arg1);
07006     xmlXPathReleaseObject(ctxt->context, arg2);
07007     return(ret);
07008 }
07009 
07018 int
07019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
07020     xmlXPathObjectPtr arg1, arg2, argtmp;
07021     int ret = 0;
07022 
07023     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
07024     arg2 = valuePop(ctxt);
07025     arg1 = valuePop(ctxt);
07026     if ((arg1 == NULL) || (arg2 == NULL)) {
07027     if (arg1 != NULL)
07028         xmlXPathReleaseObject(ctxt->context, arg1);
07029     else
07030         xmlXPathReleaseObject(ctxt->context, arg2);
07031     XP_ERROR0(XPATH_INVALID_OPERAND);
07032     }
07033 
07034     if (arg1 == arg2) {
07035 #ifdef DEBUG_EXPR
07036         xmlGenericError(xmlGenericErrorContext,
07037         "Equal: by pointer\n");
07038 #endif
07039     xmlXPathFreeObject(arg1);
07040         return(1);
07041     }
07042 
07043     /*
07044      *If either argument is a nodeset, it's a 'special case'
07045      */
07046     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
07047       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
07048     /*
07049      *Hack it to assure arg1 is the nodeset
07050      */
07051     if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
07052         argtmp = arg2;
07053         arg2 = arg1;
07054         arg1 = argtmp;
07055     }
07056     switch (arg2->type) {
07057         case XPATH_UNDEFINED:
07058 #ifdef DEBUG_EXPR
07059         xmlGenericError(xmlGenericErrorContext,
07060             "Equal: undefined\n");
07061 #endif
07062         break;
07063         case XPATH_NODESET:
07064         case XPATH_XSLT_TREE:
07065         ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
07066         break;
07067         case XPATH_BOOLEAN:
07068         if ((arg1->nodesetval == NULL) ||
07069           (arg1->nodesetval->nodeNr == 0)) ret = 0;
07070         else
07071             ret = 1;
07072         ret = (ret == arg2->boolval);
07073         break;
07074         case XPATH_NUMBER:
07075         ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
07076         break;
07077         case XPATH_STRING:
07078         ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
07079         break;
07080         case XPATH_USERS:
07081         case XPATH_POINT:
07082         case XPATH_RANGE:
07083         case XPATH_LOCATIONSET:
07084         TODO
07085         break;
07086     }
07087     xmlXPathReleaseObject(ctxt->context, arg1);
07088     xmlXPathReleaseObject(ctxt->context, arg2);
07089     return(ret);
07090     }
07091 
07092     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
07093 }
07094 
07103 int
07104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
07105     xmlXPathObjectPtr arg1, arg2, argtmp;
07106     int ret = 0;
07107 
07108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
07109     arg2 = valuePop(ctxt);
07110     arg1 = valuePop(ctxt);
07111     if ((arg1 == NULL) || (arg2 == NULL)) {
07112     if (arg1 != NULL)
07113         xmlXPathReleaseObject(ctxt->context, arg1);
07114     else
07115         xmlXPathReleaseObject(ctxt->context, arg2);
07116     XP_ERROR0(XPATH_INVALID_OPERAND);
07117     }
07118 
07119     if (arg1 == arg2) {
07120 #ifdef DEBUG_EXPR
07121         xmlGenericError(xmlGenericErrorContext,
07122         "NotEqual: by pointer\n");
07123 #endif
07124     xmlXPathReleaseObject(ctxt->context, arg1);
07125         return(0);
07126     }
07127 
07128     /*
07129      *If either argument is a nodeset, it's a 'special case'
07130      */
07131     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
07132       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
07133     /*
07134      *Hack it to assure arg1 is the nodeset
07135      */
07136     if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
07137         argtmp = arg2;
07138         arg2 = arg1;
07139         arg1 = argtmp;
07140     }
07141     switch (arg2->type) {
07142         case XPATH_UNDEFINED:
07143 #ifdef DEBUG_EXPR
07144         xmlGenericError(xmlGenericErrorContext,
07145             "NotEqual: undefined\n");
07146 #endif
07147         break;
07148         case XPATH_NODESET:
07149         case XPATH_XSLT_TREE:
07150         ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
07151         break;
07152         case XPATH_BOOLEAN:
07153         if ((arg1->nodesetval == NULL) ||
07154           (arg1->nodesetval->nodeNr == 0)) ret = 0;
07155         else
07156             ret = 1;
07157         ret = (ret != arg2->boolval);
07158         break;
07159         case XPATH_NUMBER:
07160         ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
07161         break;
07162         case XPATH_STRING:
07163         ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
07164         break;
07165         case XPATH_USERS:
07166         case XPATH_POINT:
07167         case XPATH_RANGE:
07168         case XPATH_LOCATIONSET:
07169         TODO
07170         break;
07171     }
07172     xmlXPathReleaseObject(ctxt->context, arg1);
07173     xmlXPathReleaseObject(ctxt->context, arg2);
07174     return(ret);
07175     }
07176 
07177     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
07178 }
07179 
07204 int
07205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
07206     int ret = 0, arg1i = 0, arg2i = 0;
07207     xmlXPathObjectPtr arg1, arg2;
07208 
07209     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
07210     arg2 = valuePop(ctxt);
07211     arg1 = valuePop(ctxt);
07212     if ((arg1 == NULL) || (arg2 == NULL)) {
07213     if (arg1 != NULL)
07214         xmlXPathReleaseObject(ctxt->context, arg1);
07215     else
07216         xmlXPathReleaseObject(ctxt->context, arg2);
07217     XP_ERROR0(XPATH_INVALID_OPERAND);
07218     }
07219 
07220     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
07221       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
07222     /*
07223      * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
07224      * are not freed from within this routine; they will be freed from the
07225      * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
07226      */
07227     if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
07228       ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
07229         ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
07230     } else {
07231         if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
07232         ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
07233                                       arg1, arg2);
07234         } else {
07235         ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
07236                                       arg2, arg1);
07237         }
07238     }
07239     return(ret);
07240     }
07241 
07242     if (arg1->type != XPATH_NUMBER) {
07243     valuePush(ctxt, arg1);
07244     xmlXPathNumberFunction(ctxt, 1);
07245     arg1 = valuePop(ctxt);
07246     }
07247     if (arg1->type != XPATH_NUMBER) {
07248     xmlXPathFreeObject(arg1);
07249     xmlXPathFreeObject(arg2);
07250     XP_ERROR0(XPATH_INVALID_OPERAND);
07251     }
07252     if (arg2->type != XPATH_NUMBER) {
07253     valuePush(ctxt, arg2);
07254     xmlXPathNumberFunction(ctxt, 1);
07255     arg2 = valuePop(ctxt);
07256     }
07257     if (arg2->type != XPATH_NUMBER) {
07258     xmlXPathReleaseObject(ctxt->context, arg1);
07259     xmlXPathReleaseObject(ctxt->context, arg2);
07260     XP_ERROR0(XPATH_INVALID_OPERAND);
07261     }
07262     /*
07263      * Add tests for infinity and nan
07264      * => feedback on 3.4 for Inf and NaN
07265      */
07266     /* Hand check NaN and Infinity comparisons */
07267     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
07268     ret=0;
07269     } else {
07270     arg1i=xmlXPathIsInf(arg1->floatval);
07271     arg2i=xmlXPathIsInf(arg2->floatval);
07272     if (inf && strict) {
07273         if ((arg1i == -1 && arg2i != -1) ||
07274         (arg2i == 1 && arg1i != 1)) {
07275         ret = 1;
07276         } else if (arg1i == 0 && arg2i == 0) {
07277         ret = (arg1->floatval < arg2->floatval);
07278         } else {
07279         ret = 0;
07280         }
07281     }
07282     else if (inf && !strict) {
07283         if (arg1i == -1 || arg2i == 1) {
07284         ret = 1;
07285         } else if (arg1i == 0 && arg2i == 0) {
07286         ret = (arg1->floatval <= arg2->floatval);
07287         } else {
07288         ret = 0;
07289         }
07290     }
07291     else if (!inf && strict) {
07292         if ((arg1i == 1 && arg2i != 1) ||
07293         (arg2i == -1 && arg1i != -1)) {
07294         ret = 1;
07295         } else if (arg1i == 0 && arg2i == 0) {
07296         ret = (arg1->floatval > arg2->floatval);
07297         } else {
07298         ret = 0;
07299         }
07300     }
07301     else if (!inf && !strict) {
07302         if (arg1i == 1 || arg2i == -1) {
07303         ret = 1;
07304         } else if (arg1i == 0 && arg2i == 0) {
07305         ret = (arg1->floatval >= arg2->floatval);
07306         } else {
07307         ret = 0;
07308         }
07309     }
07310     }
07311     xmlXPathReleaseObject(ctxt->context, arg1);
07312     xmlXPathReleaseObject(ctxt->context, arg2);
07313     return(ret);
07314 }
07315 
07324 void
07325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
07326     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
07327     CAST_TO_NUMBER;
07328     CHECK_TYPE(XPATH_NUMBER);
07329     if (xmlXPathIsNaN(ctxt->value->floatval))
07330         ctxt->value->floatval=xmlXPathNAN;
07331     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
07332         ctxt->value->floatval=xmlXPathNINF;
07333     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
07334         ctxt->value->floatval=xmlXPathPINF;
07335     else if (ctxt->value->floatval == 0) {
07336         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
07337         ctxt->value->floatval = xmlXPathNZERO;
07338     else
07339         ctxt->value->floatval = 0;
07340     }
07341     else
07342         ctxt->value->floatval = - ctxt->value->floatval;
07343 }
07344 
07353 void
07354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
07355     xmlXPathObjectPtr arg;
07356     double val;
07357 
07358     arg = valuePop(ctxt);
07359     if (arg == NULL)
07360     XP_ERROR(XPATH_INVALID_OPERAND);
07361     val = xmlXPathCastToNumber(arg);
07362     xmlXPathReleaseObject(ctxt->context, arg);
07363     CAST_TO_NUMBER;
07364     CHECK_TYPE(XPATH_NUMBER);
07365     ctxt->value->floatval += val;
07366 }
07367 
07376 void
07377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
07378     xmlXPathObjectPtr arg;
07379     double val;
07380 
07381     arg = valuePop(ctxt);
07382     if (arg == NULL)
07383     XP_ERROR(XPATH_INVALID_OPERAND);
07384     val = xmlXPathCastToNumber(arg);
07385     xmlXPathReleaseObject(ctxt->context, arg);
07386     CAST_TO_NUMBER;
07387     CHECK_TYPE(XPATH_NUMBER);
07388     ctxt->value->floatval -= val;
07389 }
07390 
07399 void
07400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
07401     xmlXPathObjectPtr arg;
07402     double val;
07403 
07404     arg = valuePop(ctxt);
07405     if (arg == NULL)
07406     XP_ERROR(XPATH_INVALID_OPERAND);
07407     val = xmlXPathCastToNumber(arg);
07408     xmlXPathReleaseObject(ctxt->context, arg);
07409     CAST_TO_NUMBER;
07410     CHECK_TYPE(XPATH_NUMBER);
07411     ctxt->value->floatval *= val;
07412 }
07413 
07422 void
07423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
07424     xmlXPathObjectPtr arg;
07425     double val;
07426 
07427     arg = valuePop(ctxt);
07428     if (arg == NULL)
07429     XP_ERROR(XPATH_INVALID_OPERAND);
07430     val = xmlXPathCastToNumber(arg);
07431     xmlXPathReleaseObject(ctxt->context, arg);
07432     CAST_TO_NUMBER;
07433     CHECK_TYPE(XPATH_NUMBER);
07434     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
07435     ctxt->value->floatval = xmlXPathNAN;
07436     else if (val == 0 && xmlXPathGetSign(val) != 0) {
07437     if (ctxt->value->floatval == 0)
07438         ctxt->value->floatval = xmlXPathNAN;
07439     else if (ctxt->value->floatval > 0)
07440         ctxt->value->floatval = xmlXPathNINF;
07441     else if (ctxt->value->floatval < 0)
07442         ctxt->value->floatval = xmlXPathPINF;
07443     }
07444     else if (val == 0) {
07445     if (ctxt->value->floatval == 0)
07446         ctxt->value->floatval = xmlXPathNAN;
07447     else if (ctxt->value->floatval > 0)
07448         ctxt->value->floatval = xmlXPathPINF;
07449     else if (ctxt->value->floatval < 0)
07450         ctxt->value->floatval = xmlXPathNINF;
07451     } else
07452     ctxt->value->floatval /= val;
07453 }
07454 
07463 void
07464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
07465     xmlXPathObjectPtr arg;
07466     double arg1, arg2;
07467 
07468     arg = valuePop(ctxt);
07469     if (arg == NULL)
07470     XP_ERROR(XPATH_INVALID_OPERAND);
07471     arg2 = xmlXPathCastToNumber(arg);
07472     xmlXPathReleaseObject(ctxt->context, arg);
07473     CAST_TO_NUMBER;
07474     CHECK_TYPE(XPATH_NUMBER);
07475     arg1 = ctxt->value->floatval;
07476     if (arg2 == 0)
07477     ctxt->value->floatval = xmlXPathNAN;
07478     else {
07479     ctxt->value->floatval = fmod(arg1, arg2);
07480     }
07481 }
07482 
07483 /************************************************************************
07484  *                                  *
07485  *      The traversal functions                 *
07486  *                                  *
07487  ************************************************************************/
07488 
07489 /*
07490  * A traversal function enumerates nodes along an axis.
07491  * Initially it must be called with NULL, and it indicates
07492  * termination on the axis by returning NULL.
07493  */
07494 typedef xmlNodePtr (*xmlXPathTraversalFunction)
07495                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
07496 
07497 /*
07498  * xmlXPathTraversalFunctionExt:
07499  * A traversal function enumerates nodes along an axis.
07500  * Initially it must be called with NULL, and it indicates
07501  * termination on the axis by returning NULL.
07502  * The context node of the traversal is specified via @contextNode.
07503  */
07504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
07505                     (xmlNodePtr cur, xmlNodePtr contextNode);
07506 
07507 /*
07508  * xmlXPathNodeSetMergeFunction:
07509  * Used for merging node sets in xmlXPathCollectAndTest().
07510  */
07511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
07512             (xmlNodeSetPtr, xmlNodeSetPtr, int);
07513 
07514 
07525 xmlNodePtr
07526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07527     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07528     if (cur == NULL)
07529         return(ctxt->context->node);
07530     return(NULL);
07531 }
07532 
07543 xmlNodePtr
07544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07545     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07546     if (cur == NULL) {
07547     if (ctxt->context->node == NULL) return(NULL);
07548     switch (ctxt->context->node->type) {
07549             case XML_ELEMENT_NODE:
07550             case XML_TEXT_NODE:
07551             case XML_CDATA_SECTION_NODE:
07552             case XML_ENTITY_REF_NODE:
07553             case XML_ENTITY_NODE:
07554             case XML_PI_NODE:
07555             case XML_COMMENT_NODE:
07556             case XML_NOTATION_NODE:
07557             case XML_DTD_NODE:
07558         return(ctxt->context->node->children);
07559             case XML_DOCUMENT_NODE:
07560             case XML_DOCUMENT_TYPE_NODE:
07561             case XML_DOCUMENT_FRAG_NODE:
07562             case XML_HTML_DOCUMENT_NODE:
07563 #ifdef LIBXML_DOCB_ENABLED
07564         case XML_DOCB_DOCUMENT_NODE:
07565 #endif
07566         return(((xmlDocPtr) ctxt->context->node)->children);
07567         case XML_ELEMENT_DECL:
07568         case XML_ATTRIBUTE_DECL:
07569         case XML_ENTITY_DECL:
07570             case XML_ATTRIBUTE_NODE:
07571         case XML_NAMESPACE_DECL:
07572         case XML_XINCLUDE_START:
07573         case XML_XINCLUDE_END:
07574         return(NULL);
07575     }
07576     return(NULL);
07577     }
07578     if ((cur->type == XML_DOCUMENT_NODE) ||
07579         (cur->type == XML_HTML_DOCUMENT_NODE))
07580     return(NULL);
07581     return(cur->next);
07582 }
07583 
07594 static xmlNodePtr
07595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07596     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07597     if (cur == NULL) {
07598     cur = ctxt->context->node;
07599     if (cur == NULL) return(NULL);
07600     /*
07601     * Get the first element child.
07602     */
07603     switch (cur->type) {
07604             case XML_ELEMENT_NODE:
07605         case XML_DOCUMENT_FRAG_NODE:
07606         case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
07607             case XML_ENTITY_NODE:
07608         cur = cur->children;
07609         if (cur != NULL) {
07610             if (cur->type == XML_ELEMENT_NODE)
07611             return(cur);
07612             do {
07613             cur = cur->next;
07614             } while ((cur != NULL) &&
07615             (cur->type != XML_ELEMENT_NODE));
07616             return(cur);
07617         }
07618         return(NULL);
07619             case XML_DOCUMENT_NODE:
07620             case XML_HTML_DOCUMENT_NODE:
07621 #ifdef LIBXML_DOCB_ENABLED
07622         case XML_DOCB_DOCUMENT_NODE:
07623 #endif
07624         return(xmlDocGetRootElement((xmlDocPtr) cur));
07625         default:
07626         return(NULL);
07627     }
07628     return(NULL);
07629     }
07630     /*
07631     * Get the next sibling element node.
07632     */
07633     switch (cur->type) {
07634     case XML_ELEMENT_NODE:
07635     case XML_TEXT_NODE:
07636     case XML_ENTITY_REF_NODE:
07637     case XML_ENTITY_NODE:
07638     case XML_CDATA_SECTION_NODE:
07639     case XML_PI_NODE:
07640     case XML_COMMENT_NODE:
07641     case XML_XINCLUDE_END:
07642         break;
07643     /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
07644     default:
07645         return(NULL);
07646     }
07647     if (cur->next != NULL) {
07648     if (cur->next->type == XML_ELEMENT_NODE)
07649         return(cur->next);
07650     cur = cur->next;
07651     do {
07652         cur = cur->next;
07653     } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
07654     return(cur);
07655     }
07656     return(NULL);
07657 }
07658 
07671 static xmlNodePtr
07672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
07673                        xmlNodePtr contextNode)
07674 {
07675     if (cur == NULL) {
07676     if (contextNode == NULL)
07677         return(NULL);
07678     switch (contextNode->type) {
07679         case XML_ELEMENT_NODE:
07680         case XML_XINCLUDE_START:
07681         case XML_DOCUMENT_FRAG_NODE:
07682         case XML_DOCUMENT_NODE:
07683 #ifdef LIBXML_DOCB_ENABLED
07684         case XML_DOCB_DOCUMENT_NODE:
07685 #endif
07686         case XML_HTML_DOCUMENT_NODE:        
07687         return(contextNode);
07688         default:
07689         return(NULL);
07690     }
07691     return(NULL);
07692     } else {
07693     xmlNodePtr start = cur;
07694 
07695     while (cur != NULL) {
07696         switch (cur->type) {
07697         case XML_ELEMENT_NODE:
07698         /* TODO: OK to have XInclude here? */
07699         case XML_XINCLUDE_START:
07700         case XML_DOCUMENT_FRAG_NODE:
07701             if (cur != start)
07702             return(cur);
07703             if (cur->children != NULL) {
07704             cur = cur->children;
07705             continue;
07706             }
07707             break;
07708         /* Not sure if we need those here. */
07709         case XML_DOCUMENT_NODE:
07710 #ifdef LIBXML_DOCB_ENABLED
07711         case XML_DOCB_DOCUMENT_NODE:
07712 #endif
07713         case XML_HTML_DOCUMENT_NODE:
07714             if (cur != start)
07715             return(cur);
07716             return(xmlDocGetRootElement((xmlDocPtr) cur));
07717         default:
07718             break;
07719         }
07720 
07721 next_sibling:
07722         if ((cur == NULL) || (cur == contextNode))
07723         return(NULL);
07724         if (cur->next != NULL) {
07725         cur = cur->next;
07726         } else {
07727         cur = cur->parent;
07728         goto next_sibling;
07729         }
07730     }
07731     }
07732     return(NULL);
07733 }
07734 
07746 xmlNodePtr
07747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07748     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07749     if (cur == NULL) {
07750     if (ctxt->context->node == NULL)
07751         return(NULL);
07752     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
07753         (ctxt->context->node->type == XML_NAMESPACE_DECL))
07754         return(NULL);
07755 
07756         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
07757         return(ctxt->context->doc->children);
07758         return(ctxt->context->node->children);
07759     }
07760 
07761     if (cur->children != NULL) {
07762     /*
07763      * Do not descend on entities declarations
07764      */
07765     if (cur->children->type != XML_ENTITY_DECL) {
07766         cur = cur->children;
07767         /*
07768          * Skip DTDs
07769          */
07770         if (cur->type != XML_DTD_NODE)
07771         return(cur);
07772     }
07773     }
07774 
07775     if (cur == ctxt->context->node) return(NULL);
07776 
07777     while (cur->next != NULL) {
07778     cur = cur->next;
07779     if ((cur->type != XML_ENTITY_DECL) &&
07780         (cur->type != XML_DTD_NODE))
07781         return(cur);
07782     }
07783 
07784     do {
07785         cur = cur->parent;
07786     if (cur == NULL) break;
07787     if (cur == ctxt->context->node) return(NULL);
07788     if (cur->next != NULL) {
07789         cur = cur->next;
07790         return(cur);
07791     }
07792     } while (cur != NULL);
07793     return(cur);
07794 }
07795 
07809 xmlNodePtr
07810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07811     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07812     if (cur == NULL) {
07813     if (ctxt->context->node == NULL)
07814         return(NULL);
07815     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
07816         (ctxt->context->node->type == XML_NAMESPACE_DECL))
07817         return(NULL);
07818         return(ctxt->context->node);
07819     }
07820 
07821     return(xmlXPathNextDescendant(ctxt, cur));
07822 }
07823 
07834 xmlNodePtr
07835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07836     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07837     /*
07838      * the parent of an attribute or namespace node is the element
07839      * to which the attribute or namespace node is attached
07840      * Namespace handling !!!
07841      */
07842     if (cur == NULL) {
07843     if (ctxt->context->node == NULL) return(NULL);
07844     switch (ctxt->context->node->type) {
07845             case XML_ELEMENT_NODE:
07846             case XML_TEXT_NODE:
07847             case XML_CDATA_SECTION_NODE:
07848             case XML_ENTITY_REF_NODE:
07849             case XML_ENTITY_NODE:
07850             case XML_PI_NODE:
07851             case XML_COMMENT_NODE:
07852             case XML_NOTATION_NODE:
07853             case XML_DTD_NODE:
07854         case XML_ELEMENT_DECL:
07855         case XML_ATTRIBUTE_DECL:
07856         case XML_XINCLUDE_START:
07857         case XML_XINCLUDE_END:
07858         case XML_ENTITY_DECL:
07859         if (ctxt->context->node->parent == NULL)
07860             return((xmlNodePtr) ctxt->context->doc);
07861         if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
07862             ((ctxt->context->node->parent->name[0] == ' ') ||
07863              (xmlStrEqual(ctxt->context->node->parent->name,
07864                  BAD_CAST "fake node libxslt"))))
07865             return(NULL);
07866         return(ctxt->context->node->parent);
07867             case XML_ATTRIBUTE_NODE: {
07868         xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
07869 
07870         return(att->parent);
07871         }
07872             case XML_DOCUMENT_NODE:
07873             case XML_DOCUMENT_TYPE_NODE:
07874             case XML_DOCUMENT_FRAG_NODE:
07875             case XML_HTML_DOCUMENT_NODE:
07876 #ifdef LIBXML_DOCB_ENABLED
07877         case XML_DOCB_DOCUMENT_NODE:
07878 #endif
07879                 return(NULL);
07880         case XML_NAMESPACE_DECL: {
07881         xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
07882 
07883         if ((ns->next != NULL) &&
07884             (ns->next->type != XML_NAMESPACE_DECL))
07885             return((xmlNodePtr) ns->next);
07886                 return(NULL);
07887         }
07888     }
07889     }
07890     return(NULL);
07891 }
07892 
07907 xmlNodePtr
07908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
07909     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
07910     /*
07911      * the parent of an attribute or namespace node is the element
07912      * to which the attribute or namespace node is attached
07913      * !!!!!!!!!!!!!
07914      */
07915     if (cur == NULL) {
07916     if (ctxt->context->node == NULL) return(NULL);
07917     switch (ctxt->context->node->type) {
07918             case XML_ELEMENT_NODE:
07919             case XML_TEXT_NODE:
07920             case XML_CDATA_SECTION_NODE:
07921             case XML_ENTITY_REF_NODE:
07922             case XML_ENTITY_NODE:
07923             case XML_PI_NODE:
07924             case XML_COMMENT_NODE:
07925         case XML_DTD_NODE:
07926         case XML_ELEMENT_DECL:
07927         case XML_ATTRIBUTE_DECL:
07928         case XML_ENTITY_DECL:
07929             case XML_NOTATION_NODE:
07930         case XML_XINCLUDE_START:
07931         case XML_XINCLUDE_END:
07932         if (ctxt->context->node->parent == NULL)
07933             return((xmlNodePtr) ctxt->context->doc);
07934         if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
07935             ((ctxt->context->node->parent->name[0] == ' ') ||
07936              (xmlStrEqual(ctxt->context->node->parent->name,
07937                  BAD_CAST "fake node libxslt"))))
07938             return(NULL);
07939         return(ctxt->context->node->parent);
07940             case XML_ATTRIBUTE_NODE: {
07941         xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
07942 
07943         return(tmp->parent);
07944         }
07945             case XML_DOCUMENT_NODE:
07946             case XML_DOCUMENT_TYPE_NODE:
07947             case XML_DOCUMENT_FRAG_NODE:
07948             case XML_HTML_DOCUMENT_NODE:
07949 #ifdef LIBXML_DOCB_ENABLED
07950         case XML_DOCB_DOCUMENT_NODE:
07951 #endif
07952                 return(NULL);
07953         case XML_NAMESPACE_DECL: {
07954         xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
07955 
07956         if ((ns->next != NULL) &&
07957             (ns->next->type != XML_NAMESPACE_DECL))
07958             return((xmlNodePtr) ns->next);
07959         /* Bad, how did that namespace end up here ? */
07960                 return(NULL);
07961         }
07962     }
07963     return(NULL);
07964     }
07965     if (cur == ctxt->context->doc->children)
07966     return((xmlNodePtr) ctxt->context->doc);
07967     if (cur == (xmlNodePtr) ctxt->context->doc)
07968     return(NULL);
07969     switch (cur->type) {
07970     case XML_ELEMENT_NODE:
07971     case XML_TEXT_NODE:
07972     case XML_CDATA_SECTION_NODE:
07973     case XML_ENTITY_REF_NODE:
07974     case XML_ENTITY_NODE:
07975     case XML_PI_NODE:
07976     case XML_COMMENT_NODE:
07977     case XML_NOTATION_NODE:
07978     case XML_DTD_NODE:
07979         case XML_ELEMENT_DECL:
07980         case XML_ATTRIBUTE_DECL:
07981         case XML_ENTITY_DECL:
07982     case XML_XINCLUDE_START:
07983     case XML_XINCLUDE_END:
07984         if (cur->parent == NULL)
07985         return(NULL);
07986         if ((cur->parent->type == XML_ELEMENT_NODE) &&
07987         ((cur->parent->name[0] == ' ') ||
07988          (xmlStrEqual(cur->parent->name,
07989                   BAD_CAST "fake node libxslt"))))
07990         return(NULL);
07991         return(cur->parent);
07992     case XML_ATTRIBUTE_NODE: {
07993         xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
07994 
07995         return(att->parent);
07996     }
07997     case XML_NAMESPACE_DECL: {
07998         xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
07999 
08000         if ((ns->next != NULL) &&
08001             (ns->next->type != XML_NAMESPACE_DECL))
08002             return((xmlNodePtr) ns->next);
08003         /* Bad, how did that namespace end up here ? */
08004             return(NULL);
08005     }
08006     case XML_DOCUMENT_NODE:
08007     case XML_DOCUMENT_TYPE_NODE:
08008     case XML_DOCUMENT_FRAG_NODE:
08009     case XML_HTML_DOCUMENT_NODE:
08010 #ifdef LIBXML_DOCB_ENABLED
08011     case XML_DOCB_DOCUMENT_NODE:
08012 #endif
08013         return(NULL);
08014     }
08015     return(NULL);
08016 }
08017 
08031 xmlNodePtr
08032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08034     if (cur == NULL)
08035         return(ctxt->context->node);
08036     return(xmlXPathNextAncestor(ctxt, cur));
08037 }
08038 
08050 xmlNodePtr
08051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08052     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08053     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
08054     (ctxt->context->node->type == XML_NAMESPACE_DECL))
08055     return(NULL);
08056     if (cur == (xmlNodePtr) ctxt->context->doc)
08057         return(NULL);
08058     if (cur == NULL)
08059         return(ctxt->context->node->next);
08060     return(cur->next);
08061 }
08062 
08075 xmlNodePtr
08076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08077     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08078     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
08079     (ctxt->context->node->type == XML_NAMESPACE_DECL))
08080     return(NULL);
08081     if (cur == (xmlNodePtr) ctxt->context->doc)
08082         return(NULL);
08083     if (cur == NULL)
08084         return(ctxt->context->node->prev);
08085     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
08086     cur = cur->prev;
08087     if (cur == NULL)
08088         return(ctxt->context->node->prev);
08089     }
08090     return(cur->prev);
08091 }
08092 
08106 xmlNodePtr
08107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08108     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08109     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
08110         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
08111         return(cur->children);
08112 
08113     if (cur == NULL) {
08114         cur = ctxt->context->node;
08115         if (cur->type == XML_NAMESPACE_DECL)
08116             return(NULL);
08117         if (cur->type == XML_ATTRIBUTE_NODE)
08118             cur = cur->parent;
08119     }
08120     if (cur == NULL) return(NULL) ; /* ERROR */
08121     if (cur->next != NULL) return(cur->next) ;
08122     do {
08123         cur = cur->parent;
08124         if (cur == NULL) break;
08125         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
08126         if (cur->next != NULL) return(cur->next);
08127     } while (cur != NULL);
08128     return(cur);
08129 }
08130 
08131 /*
08132  * xmlXPathIsAncestor:
08133  * @ancestor:  the ancestor node
08134  * @node:  the current node
08135  *
08136  * Check that @ancestor is a @node's ancestor
08137  *
08138  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
08139  */
08140 static int
08141 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
08142     if ((ancestor == NULL) || (node == NULL)) return(0);
08143     /* nodes need to be in the same document */
08144     if (ancestor->doc != node->doc) return(0);
08145     /* avoid searching if ancestor or node is the root node */
08146     if (ancestor == (xmlNodePtr) node->doc) return(1);
08147     if (node == (xmlNodePtr) ancestor->doc) return(0);
08148     while (node->parent != NULL) {
08149         if (node->parent == ancestor)
08150             return(1);
08151     node = node->parent;
08152     }
08153     return(0);
08154 }
08155 
08169 xmlNodePtr
08170 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
08171 {
08172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08173     if (cur == NULL) {
08174         cur = ctxt->context->node;
08175         if (cur->type == XML_NAMESPACE_DECL)
08176             return(NULL);
08177         if (cur->type == XML_ATTRIBUTE_NODE)
08178             return(cur->parent);
08179     }
08180     if (cur == NULL)
08181     return (NULL);
08182     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
08183     cur = cur->prev;
08184     do {
08185         if (cur->prev != NULL) {
08186             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
08187             return (cur);
08188         }
08189 
08190         cur = cur->parent;
08191         if (cur == NULL)
08192             return (NULL);
08193         if (cur == ctxt->context->doc->children)
08194             return (NULL);
08195     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
08196     return (cur);
08197 }
08198 
08214 static xmlNodePtr
08215 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
08216                               xmlNodePtr cur)
08217 {
08218     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08219     if (cur == NULL) {
08220         cur = ctxt->context->node;
08221         if (cur == NULL)
08222             return (NULL);
08223         if (cur->type == XML_NAMESPACE_DECL)
08224             return (NULL);
08225         ctxt->ancestor = cur->parent;
08226     }
08227     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
08228     cur = cur->prev;
08229     while (cur->prev == NULL) {
08230         cur = cur->parent;
08231         if (cur == NULL)
08232             return (NULL);
08233         if (cur == ctxt->context->doc->children)
08234             return (NULL);
08235         if (cur != ctxt->ancestor)
08236             return (cur);
08237         ctxt->ancestor = cur->parent;
08238     }
08239     cur = cur->prev;
08240     while (cur->last != NULL)
08241         cur = cur->last;
08242     return (cur);
08243 }
08244 
08259 xmlNodePtr
08260 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08261     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08262     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
08263     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
08264         if (ctxt->context->tmpNsList != NULL)
08265         xmlFree(ctxt->context->tmpNsList);
08266     ctxt->context->tmpNsList =
08267         xmlGetNsList(ctxt->context->doc, ctxt->context->node);
08268     ctxt->context->tmpNsNr = 0;
08269     if (ctxt->context->tmpNsList != NULL) {
08270         while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
08271         ctxt->context->tmpNsNr++;
08272         }
08273     }
08274     return((xmlNodePtr) xmlXPathXMLNamespace);
08275     }
08276     if (ctxt->context->tmpNsNr > 0) {
08277     return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
08278     } else {
08279     if (ctxt->context->tmpNsList != NULL)
08280         xmlFree(ctxt->context->tmpNsList);
08281     ctxt->context->tmpNsList = NULL;
08282     return(NULL);
08283     }
08284 }
08285 
08296 xmlNodePtr
08297 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
08298     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
08299     if (ctxt->context->node == NULL)
08300     return(NULL);
08301     if (ctxt->context->node->type != XML_ELEMENT_NODE)
08302     return(NULL);
08303     if (cur == NULL) {
08304         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
08305         return(NULL);
08306         return((xmlNodePtr)ctxt->context->node->properties);
08307     }
08308     return((xmlNodePtr)cur->next);
08309 }
08310 
08311 /************************************************************************
08312  *                                  *
08313  *      NodeTest Functions                  *
08314  *                                  *
08315  ************************************************************************/
08316 
08317 #define IS_FUNCTION         200
08318 
08319 
08320 /************************************************************************
08321  *                                  *
08322  *      Implicit tree core function library         *
08323  *                                  *
08324  ************************************************************************/
08325 
08332 void
08333 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
08334     if ((ctxt == NULL) || (ctxt->context == NULL))
08335     return;
08336     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
08337     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
08338     ctxt->context->node));
08339 }
08340 
08341 /************************************************************************
08342  *                                  *
08343  *      The explicit core function library          *
08344  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
08345  *                                  *
08346  ************************************************************************/
08347 
08348 
08358 void
08359 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08360     CHECK_ARITY(0);
08361     if (ctxt->context->contextSize >= 0) {
08362     valuePush(ctxt,
08363         xmlXPathCacheNewFloat(ctxt->context,
08364         (double) ctxt->context->contextSize));
08365 #ifdef DEBUG_EXPR
08366     xmlGenericError(xmlGenericErrorContext,
08367         "last() : %d\n", ctxt->context->contextSize);
08368 #endif
08369     } else {
08370     XP_ERROR(XPATH_INVALID_CTXT_SIZE);
08371     }
08372 }
08373 
08385 void
08386 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08387     CHECK_ARITY(0);
08388     if (ctxt->context->proximityPosition >= 0) {
08389     valuePush(ctxt,
08390           xmlXPathCacheNewFloat(ctxt->context,
08391         (double) ctxt->context->proximityPosition));
08392 #ifdef DEBUG_EXPR
08393     xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
08394         ctxt->context->proximityPosition);
08395 #endif
08396     } else {
08397     XP_ERROR(XPATH_INVALID_CTXT_POSITION);
08398     }
08399 }
08400 
08409 void
08410 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08411     xmlXPathObjectPtr cur;
08412 
08413     CHECK_ARITY(1);
08414     if ((ctxt->value == NULL) ||
08415     ((ctxt->value->type != XPATH_NODESET) &&
08416      (ctxt->value->type != XPATH_XSLT_TREE)))
08417     XP_ERROR(XPATH_INVALID_TYPE);
08418     cur = valuePop(ctxt);
08419 
08420     if ((cur == NULL) || (cur->nodesetval == NULL))
08421     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
08422     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
08423     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
08424         (double) cur->nodesetval->nodeNr));
08425     } else {
08426     if ((cur->nodesetval->nodeNr != 1) ||
08427         (cur->nodesetval->nodeTab == NULL)) {
08428         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
08429     } else {
08430         xmlNodePtr tmp;
08431         int i = 0;
08432 
08433         tmp = cur->nodesetval->nodeTab[0];
08434         if (tmp != NULL) {
08435         tmp = tmp->children;
08436         while (tmp != NULL) {
08437             tmp = tmp->next;
08438             i++;
08439         }
08440         }
08441         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
08442     }
08443     }
08444     xmlXPathReleaseObject(ctxt->context, cur);
08445 }
08446 
08456 static xmlNodeSetPtr
08457 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
08458     xmlNodeSetPtr ret;
08459     const xmlChar *cur = ids;
08460     xmlChar *ID;
08461     xmlAttrPtr attr;
08462     xmlNodePtr elem = NULL;
08463 
08464     if (ids == NULL) return(NULL);
08465 
08466     ret = xmlXPathNodeSetCreate(NULL);
08467     if (ret == NULL)
08468         return(ret);
08469 
08470     while (IS_BLANK_CH(*cur)) cur++;
08471     while (*cur != 0) {
08472     while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
08473         cur++;
08474 
08475         ID = xmlStrndup(ids, cur - ids);
08476     if (ID != NULL) {
08477         /*
08478          * We used to check the fact that the value passed
08479          * was an NCName, but this generated much troubles for
08480          * me and Aleksey Sanin, people blatantly violated that
08481          * constaint, like Visa3D spec.
08482          * if (xmlValidateNCName(ID, 1) == 0)
08483          */
08484         attr = xmlGetID(doc, ID);
08485         if (attr != NULL) {
08486         if (attr->type == XML_ATTRIBUTE_NODE)
08487             elem = attr->parent;
08488         else if (attr->type == XML_ELEMENT_NODE)
08489             elem = (xmlNodePtr) attr;
08490         else
08491             elem = NULL;
08492         if (elem != NULL)
08493             xmlXPathNodeSetAdd(ret, elem);
08494         }
08495         xmlFree(ID);
08496     }
08497 
08498     while (IS_BLANK_CH(*cur)) cur++;
08499     ids = cur;
08500     }
08501     return(ret);
08502 }
08503 
08522 void
08523 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08524     xmlChar *tokens;
08525     xmlNodeSetPtr ret;
08526     xmlXPathObjectPtr obj;
08527 
08528     CHECK_ARITY(1);
08529     obj = valuePop(ctxt);
08530     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
08531     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
08532     xmlNodeSetPtr ns;
08533     int i;
08534 
08535     ret = xmlXPathNodeSetCreate(NULL);
08536         /*
08537          * FIXME -- in an out-of-memory condition this will behave badly.
08538          * The solution is not clear -- we already popped an item from
08539          * ctxt, so the object is in a corrupt state.
08540          */
08541 
08542     if (obj->nodesetval != NULL) {
08543         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
08544         tokens =
08545             xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
08546         ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
08547         ret = xmlXPathNodeSetMerge(ret, ns);
08548         xmlXPathFreeNodeSet(ns);
08549         if (tokens != NULL)
08550             xmlFree(tokens);
08551         }
08552     }
08553     xmlXPathReleaseObject(ctxt->context, obj);
08554     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
08555     return;
08556     }
08557     obj = xmlXPathCacheConvertString(ctxt->context, obj);
08558     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
08559     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
08560     xmlXPathReleaseObject(ctxt->context, obj);
08561     return;
08562 }
08563 
08577 void
08578 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08579     xmlXPathObjectPtr cur;
08580 
08581     if (ctxt == NULL) return;
08582 
08583     if (nargs == 0) {
08584     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
08585         ctxt->context->node));
08586     nargs = 1;
08587     }
08588 
08589     CHECK_ARITY(1);
08590     if ((ctxt->value == NULL) ||
08591     ((ctxt->value->type != XPATH_NODESET) &&
08592      (ctxt->value->type != XPATH_XSLT_TREE)))
08593     XP_ERROR(XPATH_INVALID_TYPE);
08594     cur = valuePop(ctxt);
08595 
08596     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
08597     valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08598     } else {
08599     int i = 0; /* Should be first in document order !!!!! */
08600     switch (cur->nodesetval->nodeTab[i]->type) {
08601     case XML_ELEMENT_NODE:
08602     case XML_ATTRIBUTE_NODE:
08603     case XML_PI_NODE:
08604         if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
08605         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08606         else
08607         valuePush(ctxt,
08608               xmlXPathCacheNewString(ctxt->context,
08609             cur->nodesetval->nodeTab[i]->name));
08610         break;
08611     case XML_NAMESPACE_DECL:
08612         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
08613             ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
08614         break;
08615     default:
08616         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08617     }
08618     }
08619     xmlXPathReleaseObject(ctxt->context, cur);
08620 }
08621 
08636 void
08637 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08638     xmlXPathObjectPtr cur;
08639 
08640     if (ctxt == NULL) return;
08641 
08642     if (nargs == 0) {
08643     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
08644         ctxt->context->node));
08645     nargs = 1;
08646     }
08647     CHECK_ARITY(1);
08648     if ((ctxt->value == NULL) ||
08649     ((ctxt->value->type != XPATH_NODESET) &&
08650      (ctxt->value->type != XPATH_XSLT_TREE)))
08651     XP_ERROR(XPATH_INVALID_TYPE);
08652     cur = valuePop(ctxt);
08653 
08654     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
08655     valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08656     } else {
08657     int i = 0; /* Should be first in document order !!!!! */
08658     switch (cur->nodesetval->nodeTab[i]->type) {
08659     case XML_ELEMENT_NODE:
08660     case XML_ATTRIBUTE_NODE:
08661         if (cur->nodesetval->nodeTab[i]->ns == NULL)
08662         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08663         else
08664         valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
08665               cur->nodesetval->nodeTab[i]->ns->href));
08666         break;
08667     default:
08668         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08669     }
08670     }
08671     xmlXPathReleaseObject(ctxt->context, cur);
08672 }
08673 
08696 static void
08697 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
08698 {
08699     xmlXPathObjectPtr cur;
08700 
08701     if (nargs == 0) {
08702     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
08703         ctxt->context->node));
08704         nargs = 1;
08705     }
08706 
08707     CHECK_ARITY(1);
08708     if ((ctxt->value == NULL) ||
08709         ((ctxt->value->type != XPATH_NODESET) &&
08710          (ctxt->value->type != XPATH_XSLT_TREE)))
08711         XP_ERROR(XPATH_INVALID_TYPE);
08712     cur = valuePop(ctxt);
08713 
08714     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
08715         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
08716     } else {
08717         int i = 0;              /* Should be first in document order !!!!! */
08718 
08719         switch (cur->nodesetval->nodeTab[i]->type) {
08720             case XML_ELEMENT_NODE:
08721             case XML_ATTRIBUTE_NODE:
08722         if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
08723             valuePush(ctxt,
08724             xmlXPathCacheNewCString(ctxt->context, ""));
08725         else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
08726                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
08727             valuePush(ctxt,
08728                 xmlXPathCacheNewString(ctxt->context,
08729                 cur->nodesetval->nodeTab[i]->name));
08730         } else {
08731             xmlChar *fullname;
08732 
08733             fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
08734                      cur->nodesetval->nodeTab[i]->ns->prefix,
08735                      NULL, 0);
08736             if (fullname == cur->nodesetval->nodeTab[i]->name)
08737             fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
08738             if (fullname == NULL) {
08739             XP_ERROR(XPATH_MEMORY_ERROR);
08740             }
08741             valuePush(ctxt, xmlXPathCacheWrapString(
08742             ctxt->context, fullname));
08743                 }
08744                 break;
08745             default:
08746         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
08747             cur->nodesetval->nodeTab[i]));
08748                 xmlXPathLocalNameFunction(ctxt, 1);
08749         }
08750     }
08751     xmlXPathReleaseObject(ctxt->context, cur);
08752 }
08753 
08754 
08791 void
08792 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08793     xmlXPathObjectPtr cur;
08794 
08795     if (ctxt == NULL) return;
08796     if (nargs == 0) {
08797     valuePush(ctxt,
08798     xmlXPathCacheWrapString(ctxt->context,
08799         xmlXPathCastNodeToString(ctxt->context->node)));
08800     return;
08801     }
08802 
08803     CHECK_ARITY(1);
08804     cur = valuePop(ctxt);
08805     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
08806     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
08807 }
08808 
08821 void
08822 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08823     xmlXPathObjectPtr cur;
08824 
08825     if (nargs == 0) {
08826         if ((ctxt == NULL) || (ctxt->context == NULL))
08827         return;
08828     if (ctxt->context->node == NULL) {
08829         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
08830     } else {
08831         xmlChar *content;
08832 
08833         content = xmlXPathCastNodeToString(ctxt->context->node);
08834         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
08835         xmlUTF8Strlen(content)));
08836         xmlFree(content);
08837     }
08838     return;
08839     }
08840     CHECK_ARITY(1);
08841     CAST_TO_STRING;
08842     CHECK_TYPE(XPATH_STRING);
08843     cur = valuePop(ctxt);
08844     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
08845     xmlUTF8Strlen(cur->stringval)));
08846     xmlXPathReleaseObject(ctxt->context, cur);
08847 }
08848 
08858 void
08859 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08860     xmlXPathObjectPtr cur, newobj;
08861     xmlChar *tmp;
08862 
08863     if (ctxt == NULL) return;
08864     if (nargs < 2) {
08865     CHECK_ARITY(2);
08866     }
08867 
08868     CAST_TO_STRING;
08869     cur = valuePop(ctxt);
08870     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
08871     xmlXPathReleaseObject(ctxt->context, cur);
08872     return;
08873     }
08874     nargs--;
08875 
08876     while (nargs > 0) {
08877     CAST_TO_STRING;
08878     newobj = valuePop(ctxt);
08879     if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
08880         xmlXPathReleaseObject(ctxt->context, newobj);
08881         xmlXPathReleaseObject(ctxt->context, cur);
08882         XP_ERROR(XPATH_INVALID_TYPE);
08883     }
08884     tmp = xmlStrcat(newobj->stringval, cur->stringval);
08885     newobj->stringval = cur->stringval;
08886     cur->stringval = tmp;
08887     xmlXPathReleaseObject(ctxt->context, newobj);
08888     nargs--;
08889     }
08890     valuePush(ctxt, cur);
08891 }
08892 
08903 void
08904 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08905     xmlXPathObjectPtr hay, needle;
08906 
08907     CHECK_ARITY(2);
08908     CAST_TO_STRING;
08909     CHECK_TYPE(XPATH_STRING);
08910     needle = valuePop(ctxt);
08911     CAST_TO_STRING;
08912     hay = valuePop(ctxt);
08913 
08914     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
08915     xmlXPathReleaseObject(ctxt->context, hay);
08916     xmlXPathReleaseObject(ctxt->context, needle);
08917     XP_ERROR(XPATH_INVALID_TYPE);
08918     }
08919     if (xmlStrstr(hay->stringval, needle->stringval))
08920     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
08921     else
08922     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
08923     xmlXPathReleaseObject(ctxt->context, hay);
08924     xmlXPathReleaseObject(ctxt->context, needle);
08925 }
08926 
08937 void
08938 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08939     xmlXPathObjectPtr hay, needle;
08940     int n;
08941 
08942     CHECK_ARITY(2);
08943     CAST_TO_STRING;
08944     CHECK_TYPE(XPATH_STRING);
08945     needle = valuePop(ctxt);
08946     CAST_TO_STRING;
08947     hay = valuePop(ctxt);
08948 
08949     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
08950     xmlXPathReleaseObject(ctxt->context, hay);
08951     xmlXPathReleaseObject(ctxt->context, needle);
08952     XP_ERROR(XPATH_INVALID_TYPE);
08953     }
08954     n = xmlStrlen(needle->stringval);
08955     if (xmlStrncmp(hay->stringval, needle->stringval, n))
08956         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
08957     else
08958         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
08959     xmlXPathReleaseObject(ctxt->context, hay);
08960     xmlXPathReleaseObject(ctxt->context, needle);
08961 }
08962 
08991 void
08992 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
08993     xmlXPathObjectPtr str, start, len;
08994     double le=0, in;
08995     int i, l, m;
08996     xmlChar *ret;
08997 
08998     if (nargs < 2) {
08999     CHECK_ARITY(2);
09000     }
09001     if (nargs > 3) {
09002     CHECK_ARITY(3);
09003     }
09004     /*
09005      * take care of possible last (position) argument
09006     */
09007     if (nargs == 3) {
09008     CAST_TO_NUMBER;
09009     CHECK_TYPE(XPATH_NUMBER);
09010     len = valuePop(ctxt);
09011     le = len->floatval;
09012     xmlXPathReleaseObject(ctxt->context, len);
09013     }
09014 
09015     CAST_TO_NUMBER;
09016     CHECK_TYPE(XPATH_NUMBER);
09017     start = valuePop(ctxt);
09018     in = start->floatval;
09019     xmlXPathReleaseObject(ctxt->context, start);
09020     CAST_TO_STRING;
09021     CHECK_TYPE(XPATH_STRING);
09022     str = valuePop(ctxt);
09023     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
09024 
09025     /*
09026      * If last pos not present, calculate last position
09027     */
09028     if (nargs != 3) {
09029     le = (double)m;
09030     if (in < 1.0)
09031         in = 1.0;
09032     }
09033 
09034     /* Need to check for the special cases where either
09035      * the index is NaN, the length is NaN, or both
09036      * arguments are infinity (relying on Inf + -Inf = NaN)
09037      */
09038     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
09039         /*
09040          * To meet the requirements of the spec, the arguments
09041      * must be converted to integer format before
09042      * initial index calculations are done
09043          *
09044          * First we go to integer form, rounding up
09045      * and checking for special cases
09046          */
09047         i = (int) in;
09048         if (((double)i)+0.5 <= in) i++;
09049 
09050     if (xmlXPathIsInf(le) == 1) {
09051         l = m;
09052         if (i < 1)
09053         i = 1;
09054     }
09055     else if (xmlXPathIsInf(le) == -1 || le < 0.0)
09056         l = 0;
09057     else {
09058         l = (int) le;
09059         if (((double)l)+0.5 <= le) l++;
09060     }
09061 
09062     /* Now we normalize inidices */
09063         i -= 1;
09064         l += i;
09065         if (i < 0)
09066             i = 0;
09067         if (l > m)
09068             l = m;
09069 
09070         /* number of chars to copy */
09071         l -= i;
09072 
09073         ret = xmlUTF8Strsub(str->stringval, i, l);
09074     }
09075     else {
09076         ret = NULL;
09077     }
09078     if (ret == NULL)
09079     valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
09080     else {
09081     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
09082     xmlFree(ret);
09083     }
09084     xmlXPathReleaseObject(ctxt->context, str);
09085 }
09086 
09100 void
09101 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09102   xmlXPathObjectPtr str;
09103   xmlXPathObjectPtr find;
09104   xmlBufferPtr target;
09105   const xmlChar *point;
09106   int offset;
09107 
09108   CHECK_ARITY(2);
09109   CAST_TO_STRING;
09110   find = valuePop(ctxt);
09111   CAST_TO_STRING;
09112   str = valuePop(ctxt);
09113 
09114   target = xmlBufferCreate();
09115   if (target) {
09116     point = xmlStrstr(str->stringval, find->stringval);
09117     if (point) {
09118       offset = (int)(point - str->stringval);
09119       xmlBufferAdd(target, str->stringval, offset);
09120     }
09121     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
09122     xmlBufferContent(target)));
09123     xmlBufferFree(target);
09124   }
09125   xmlXPathReleaseObject(ctxt->context, str);
09126   xmlXPathReleaseObject(ctxt->context, find);
09127 }
09128 
09143 void
09144 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09145   xmlXPathObjectPtr str;
09146   xmlXPathObjectPtr find;
09147   xmlBufferPtr target;
09148   const xmlChar *point;
09149   int offset;
09150 
09151   CHECK_ARITY(2);
09152   CAST_TO_STRING;
09153   find = valuePop(ctxt);
09154   CAST_TO_STRING;
09155   str = valuePop(ctxt);
09156 
09157   target = xmlBufferCreate();
09158   if (target) {
09159     point = xmlStrstr(str->stringval, find->stringval);
09160     if (point) {
09161       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
09162       xmlBufferAdd(target, &str->stringval[offset],
09163            xmlStrlen(str->stringval) - offset);
09164     }
09165     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
09166     xmlBufferContent(target)));
09167     xmlBufferFree(target);
09168   }
09169   xmlXPathReleaseObject(ctxt->context, str);
09170   xmlXPathReleaseObject(ctxt->context, find);
09171 }
09172 
09187 void
09188 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09189   xmlXPathObjectPtr obj = NULL;
09190   xmlChar *source = NULL;
09191   xmlBufferPtr target;
09192   xmlChar blank;
09193 
09194   if (ctxt == NULL) return;
09195   if (nargs == 0) {
09196     /* Use current context node */
09197       valuePush(ctxt,
09198       xmlXPathCacheWrapString(ctxt->context,
09199         xmlXPathCastNodeToString(ctxt->context->node)));
09200     nargs = 1;
09201   }
09202 
09203   CHECK_ARITY(1);
09204   CAST_TO_STRING;
09205   CHECK_TYPE(XPATH_STRING);
09206   obj = valuePop(ctxt);
09207   source = obj->stringval;
09208 
09209   target = xmlBufferCreate();
09210   if (target && source) {
09211 
09212     /* Skip leading whitespaces */
09213     while (IS_BLANK_CH(*source))
09214       source++;
09215 
09216     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
09217     blank = 0;
09218     while (*source) {
09219       if (IS_BLANK_CH(*source)) {
09220     blank = 0x20;
09221       } else {
09222     if (blank) {
09223       xmlBufferAdd(target, &blank, 1);
09224       blank = 0;
09225     }
09226     xmlBufferAdd(target, source, 1);
09227       }
09228       source++;
09229     }
09230     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
09231     xmlBufferContent(target)));
09232     xmlBufferFree(target);
09233   }
09234   xmlXPathReleaseObject(ctxt->context, obj);
09235 }
09236 
09258 void
09259 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09260     xmlXPathObjectPtr str;
09261     xmlXPathObjectPtr from;
09262     xmlXPathObjectPtr to;
09263     xmlBufferPtr target;
09264     int offset, max;
09265     xmlChar ch;
09266     const xmlChar *point;
09267     xmlChar *cptr;
09268 
09269     CHECK_ARITY(3);
09270 
09271     CAST_TO_STRING;
09272     to = valuePop(ctxt);
09273     CAST_TO_STRING;
09274     from = valuePop(ctxt);
09275     CAST_TO_STRING;
09276     str = valuePop(ctxt);
09277 
09278     target = xmlBufferCreate();
09279     if (target) {
09280     max = xmlUTF8Strlen(to->stringval);
09281     for (cptr = str->stringval; (ch=*cptr); ) {
09282         offset = xmlUTF8Strloc(from->stringval, cptr);
09283         if (offset >= 0) {
09284         if (offset < max) {
09285             point = xmlUTF8Strpos(to->stringval, offset);
09286             if (point)
09287             xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
09288         }
09289         } else
09290         xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
09291 
09292         /* Step to next character in input */
09293         cptr++;
09294         if ( ch & 0x80 ) {
09295         /* if not simple ascii, verify proper format */
09296         if ( (ch & 0xc0) != 0xc0 ) {
09297             xmlGenericError(xmlGenericErrorContext,
09298             "xmlXPathTranslateFunction: Invalid UTF8 string\n");
09299             break;
09300         }
09301         /* then skip over remaining bytes for this char */
09302         while ( (ch <<= 1) & 0x80 )
09303             if ( (*cptr++ & 0xc0) != 0x80 ) {
09304             xmlGenericError(xmlGenericErrorContext,
09305                 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
09306             break;
09307             }
09308         if (ch & 0x80) /* must have had error encountered */
09309             break;
09310         }
09311     }
09312     }
09313     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
09314     xmlBufferContent(target)));
09315     xmlBufferFree(target);
09316     xmlXPathReleaseObject(ctxt->context, str);
09317     xmlXPathReleaseObject(ctxt->context, from);
09318     xmlXPathReleaseObject(ctxt->context, to);
09319 }
09320 
09334 void
09335 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09336     xmlXPathObjectPtr cur;
09337 
09338     CHECK_ARITY(1);
09339     cur = valuePop(ctxt);
09340     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
09341     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
09342     valuePush(ctxt, cur);
09343 }
09344 
09355 void
09356 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09357     CHECK_ARITY(1);
09358     CAST_TO_BOOLEAN;
09359     CHECK_TYPE(XPATH_BOOLEAN);
09360     ctxt->value->boolval = ! ctxt->value->boolval;
09361 }
09362 
09371 void
09372 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09373     CHECK_ARITY(0);
09374     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
09375 }
09376 
09385 void
09386 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09387     CHECK_ARITY(0);
09388     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
09389 }
09390 
09412 void
09413 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09414     xmlXPathObjectPtr val = NULL;
09415     const xmlChar *theLang = NULL;
09416     const xmlChar *lang;
09417     int ret = 0;
09418     int i;
09419 
09420     CHECK_ARITY(1);
09421     CAST_TO_STRING;
09422     CHECK_TYPE(XPATH_STRING);
09423     val = valuePop(ctxt);
09424     lang = val->stringval;
09425     theLang = xmlNodeGetLang(ctxt->context->node);
09426     if ((theLang != NULL) && (lang != NULL)) {
09427         for (i = 0;lang[i] != 0;i++)
09428         if (toupper(lang[i]) != toupper(theLang[i]))
09429             goto not_equal;
09430     if ((theLang[i] == 0) || (theLang[i] == '-'))
09431         ret = 1;
09432     }
09433 not_equal:
09434     if (theLang != NULL)
09435     xmlFree((void *)theLang);
09436 
09437     xmlXPathReleaseObject(ctxt->context, val);
09438     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
09439 }
09440 
09449 void
09450 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09451     xmlXPathObjectPtr cur;
09452     double res;
09453 
09454     if (ctxt == NULL) return;
09455     if (nargs == 0) {
09456     if (ctxt->context->node == NULL) {
09457         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
09458     } else {
09459         xmlChar* content = xmlNodeGetContent(ctxt->context->node);
09460 
09461         res = xmlXPathStringEvalNumber(content);
09462         valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
09463         xmlFree(content);
09464     }
09465     return;
09466     }
09467 
09468     CHECK_ARITY(1);
09469     cur = valuePop(ctxt);
09470     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
09471 }
09472 
09483 void
09484 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09485     xmlXPathObjectPtr cur;
09486     int i;
09487     double res = 0.0;
09488 
09489     CHECK_ARITY(1);
09490     if ((ctxt->value == NULL) ||
09491     ((ctxt->value->type != XPATH_NODESET) &&
09492      (ctxt->value->type != XPATH_XSLT_TREE)))
09493     XP_ERROR(XPATH_INVALID_TYPE);
09494     cur = valuePop(ctxt);
09495 
09496     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
09497     for (i = 0; i < cur->nodesetval->nodeNr; i++) {
09498         res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
09499     }
09500     }
09501     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
09502     xmlXPathReleaseObject(ctxt->context, cur);
09503 }
09504 
09505 /*
09506  * To assure working code on multiple platforms, we want to only depend
09507  * upon the characteristic truncation of converting a floating point value
09508  * to an integer.  Unfortunately, because of the different storage sizes
09509  * of our internal floating point value (double) and integer (int), we
09510  * can't directly convert (see bug 301162).  This macro is a messy
09511  * 'workaround'
09512  */
09513 #define XTRUNC(f, v)            \
09514     f = fmod((v), INT_MAX);     \
09515     f = (v) - (f) + (double)((int)(f));
09516 
09527 void
09528 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09529     double f;
09530 
09531     CHECK_ARITY(1);
09532     CAST_TO_NUMBER;
09533     CHECK_TYPE(XPATH_NUMBER);
09534 
09535     XTRUNC(f, ctxt->value->floatval);
09536     if (f != ctxt->value->floatval) {
09537     if (ctxt->value->floatval > 0)
09538         ctxt->value->floatval = f;
09539     else
09540         ctxt->value->floatval = f - 1;
09541     }
09542 }
09543 
09554 void
09555 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09556     double f;
09557 
09558     CHECK_ARITY(1);
09559     CAST_TO_NUMBER;
09560     CHECK_TYPE(XPATH_NUMBER);
09561 
09562 #if 0
09563     ctxt->value->floatval = ceil(ctxt->value->floatval);
09564 #else
09565     XTRUNC(f, ctxt->value->floatval);
09566     if (f != ctxt->value->floatval) {
09567     if (ctxt->value->floatval > 0)
09568         ctxt->value->floatval = f + 1;
09569     else {
09570         if (ctxt->value->floatval < 0 && f == 0)
09571             ctxt->value->floatval = xmlXPathNZERO;
09572         else
09573             ctxt->value->floatval = f;
09574     }
09575 
09576     }
09577 #endif
09578 }
09579 
09591 void
09592 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
09593     double f;
09594 
09595     CHECK_ARITY(1);
09596     CAST_TO_NUMBER;
09597     CHECK_TYPE(XPATH_NUMBER);
09598 
09599     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
09600     (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
09601     (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
09602     (ctxt->value->floatval == 0.0))
09603     return;
09604 
09605     XTRUNC(f, ctxt->value->floatval);
09606     if (ctxt->value->floatval < 0) {
09607     if (ctxt->value->floatval < f - 0.5)
09608         ctxt->value->floatval = f - 1;
09609     else
09610         ctxt->value->floatval = f;
09611     if (ctxt->value->floatval == 0)
09612         ctxt->value->floatval = xmlXPathNZERO;
09613     } else {
09614     if (ctxt->value->floatval < f + 0.5)
09615         ctxt->value->floatval = f;
09616     else
09617         ctxt->value->floatval = f + 1;
09618     }
09619 }
09620 
09621 /************************************************************************
09622  *                                  *
09623  *          The Parser                  *
09624  *                                  *
09625  ************************************************************************/
09626 
09627 /*
09628  * a few forward declarations since we use a recursive call based
09629  * implementation.
09630  */
09631 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
09632 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
09633 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
09634 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
09635 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
09636                                       int qualified);
09637 
09650 static int
09651 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
09652     unsigned char c;
09653     unsigned int val;
09654     const xmlChar *cur;
09655 
09656     if (ctxt == NULL)
09657     return(0);
09658     cur = ctxt->cur;
09659 
09660     /*
09661      * We are supposed to handle UTF8, check it's valid
09662      * From rfc2044: encoding of the Unicode values on UTF-8:
09663      *
09664      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
09665      * 0000 0000-0000 007F   0xxxxxxx
09666      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
09667      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
09668      *
09669      * Check for the 0x110000 limit too
09670      */
09671     c = *cur;
09672     if (c & 0x80) {
09673     if ((cur[1] & 0xc0) != 0x80)
09674         goto encoding_error;
09675     if ((c & 0xe0) == 0xe0) {
09676 
09677         if ((cur[2] & 0xc0) != 0x80)
09678         goto encoding_error;
09679         if ((c & 0xf0) == 0xf0) {
09680         if (((c & 0xf8) != 0xf0) ||
09681             ((cur[3] & 0xc0) != 0x80))
09682             goto encoding_error;
09683         /* 4-byte code */
09684         *len = 4;
09685         val = (cur[0] & 0x7) << 18;
09686         val |= (cur[1] & 0x3f) << 12;
09687         val |= (cur[2] & 0x3f) << 6;
09688         val |= cur[3] & 0x3f;
09689         } else {
09690           /* 3-byte code */
09691         *len = 3;
09692         val = (cur[0] & 0xf) << 12;
09693         val |= (cur[1] & 0x3f) << 6;
09694         val |= cur[2] & 0x3f;
09695         }
09696     } else {
09697       /* 2-byte code */
09698         *len = 2;
09699         val = (cur[0] & 0x1f) << 6;
09700         val |= cur[1] & 0x3f;
09701     }
09702     if (!IS_CHAR(val)) {
09703         XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
09704     }
09705     return(val);
09706     } else {
09707     /* 1-byte code */
09708     *len = 1;
09709     return((int) *cur);
09710     }
09711 encoding_error:
09712     /*
09713      * If we detect an UTF8 error that probably means that the
09714      * input encoding didn't get properly advertised in the
09715      * declaration header. Report the error and switch the encoding
09716      * to ISO-Latin-1 (if you don't like this policy, just declare the
09717      * encoding !)
09718      */
09719     *len = 0;
09720     XP_ERROR0(XPATH_ENCODING_ERROR);
09721 }
09722 
09737 xmlChar *
09738 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
09739     const xmlChar *in;
09740     xmlChar *ret;
09741     int count = 0;
09742 
09743     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
09744     /*
09745      * Accelerator for simple ASCII names
09746      */
09747     in = ctxt->cur;
09748     if (((*in >= 0x61) && (*in <= 0x7A)) ||
09749     ((*in >= 0x41) && (*in <= 0x5A)) ||
09750     (*in == '_')) {
09751     in++;
09752     while (((*in >= 0x61) && (*in <= 0x7A)) ||
09753            ((*in >= 0x41) && (*in <= 0x5A)) ||
09754            ((*in >= 0x30) && (*in <= 0x39)) ||
09755            (*in == '_') || (*in == '.') ||
09756            (*in == '-'))
09757         in++;
09758     if ((*in == ' ') || (*in == '>') || (*in == '/') ||
09759             (*in == '[') || (*in == ']') || (*in == ':') ||
09760             (*in == '@') || (*in == '*')) {
09761         count = in - ctxt->cur;
09762         if (count == 0)
09763         return(NULL);
09764         ret = xmlStrndup(ctxt->cur, count);
09765         ctxt->cur = in;
09766         return(ret);
09767     }
09768     }
09769     return(xmlXPathParseNameComplex(ctxt, 0));
09770 }
09771 
09772 
09790 static xmlChar *
09791 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
09792     xmlChar *ret = NULL;
09793 
09794     *prefix = NULL;
09795     ret = xmlXPathParseNCName(ctxt);
09796     if (ret && CUR == ':') {
09797         *prefix = ret;
09798     NEXT;
09799     ret = xmlXPathParseNCName(ctxt);
09800     }
09801     return(ret);
09802 }
09803 
09818 xmlChar *
09819 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
09820     const xmlChar *in;
09821     xmlChar *ret;
09822     int count = 0;
09823 
09824     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
09825     /*
09826      * Accelerator for simple ASCII names
09827      */
09828     in = ctxt->cur;
09829     if (((*in >= 0x61) && (*in <= 0x7A)) ||
09830     ((*in >= 0x41) && (*in <= 0x5A)) ||
09831     (*in == '_') || (*in == ':')) {
09832     in++;
09833     while (((*in >= 0x61) && (*in <= 0x7A)) ||
09834            ((*in >= 0x41) && (*in <= 0x5A)) ||
09835            ((*in >= 0x30) && (*in <= 0x39)) ||
09836            (*in == '_') || (*in == '-') ||
09837            (*in == ':') || (*in == '.'))
09838         in++;
09839     if ((*in > 0) && (*in < 0x80)) {
09840         count = in - ctxt->cur;
09841         ret = xmlStrndup(ctxt->cur, count);
09842         ctxt->cur = in;
09843         return(ret);
09844     }
09845     }
09846     return(xmlXPathParseNameComplex(ctxt, 1));
09847 }
09848 
09849 static xmlChar *
09850 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
09851     xmlChar buf[XML_MAX_NAMELEN + 5];
09852     int len = 0, l;
09853     int c;
09854 
09855     /*
09856      * Handler for more complex cases
09857      */
09858     c = CUR_CHAR(l);
09859     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
09860         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
09861         (c == '*') || /* accelerators */
09862     (!IS_LETTER(c) && (c != '_') &&
09863          ((qualified) && (c != ':')))) {
09864     return(NULL);
09865     }
09866 
09867     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
09868        ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
09869             (c == '.') || (c == '-') ||
09870         (c == '_') || ((qualified) && (c == ':')) ||
09871         (IS_COMBINING(c)) ||
09872         (IS_EXTENDER(c)))) {
09873     COPY_BUF(l,buf,len,c);
09874     NEXTL(l);
09875     c = CUR_CHAR(l);
09876     if (len >= XML_MAX_NAMELEN) {
09877         /*
09878          * Okay someone managed to make a huge name, so he's ready to pay
09879          * for the processing speed.
09880          */
09881         xmlChar *buffer;
09882         int max = len * 2;
09883 
09884         buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
09885         if (buffer == NULL) {
09886         XP_ERRORNULL(XPATH_MEMORY_ERROR);
09887         }
09888         memcpy(buffer, buf, len);
09889         while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
09890            (c == '.') || (c == '-') ||
09891            (c == '_') || ((qualified) && (c == ':')) ||
09892            (IS_COMBINING(c)) ||
09893            (IS_EXTENDER(c))) {
09894         if (len + 10 > max) {
09895             max *= 2;
09896             buffer = (xmlChar *) xmlRealloc(buffer,
09897                                         max * sizeof(xmlChar));
09898             if (buffer == NULL) {
09899             XP_ERRORNULL(XPATH_MEMORY_ERROR);
09900             }
09901         }
09902         COPY_BUF(l,buffer,len,c);
09903         NEXTL(l);
09904         c = CUR_CHAR(l);
09905         }
09906         buffer[len] = 0;
09907         return(buffer);
09908     }
09909     }
09910     if (len == 0)
09911     return(NULL);
09912     return(xmlStrndup(buf, len));
09913 }
09914 
09915 #define MAX_FRAC 20
09916 
09917 /*
09918  * These are used as divisors for the fractional part of a number.
09919  * Since the table includes 1.0 (representing '0' fractional digits),
09920  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
09921  */
09922 static double my_pow10[MAX_FRAC+1] = {
09923     1.0, 10.0, 100.0, 1000.0, 10000.0,
09924     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
09925     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
09926     100000000000000.0,
09927     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
09928     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
09929 };
09930 
09947 double
09948 xmlXPathStringEvalNumber(const xmlChar *str) {
09949     const xmlChar *cur = str;
09950     double ret;
09951     int ok = 0;
09952     int isneg = 0;
09953     int exponent = 0;
09954     int is_exponent_negative = 0;
09955 #ifdef __GNUC__
09956     unsigned long tmp = 0;
09957     double temp;
09958 #endif
09959     if (cur == NULL) return(0);
09960     while (IS_BLANK_CH(*cur)) cur++;
09961     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
09962         return(xmlXPathNAN);
09963     }
09964     if (*cur == '-') {
09965     isneg = 1;
09966     cur++;
09967     }
09968 
09969 #ifdef __GNUC__
09970     /*
09971      * tmp/temp is a workaround against a gcc compiler bug
09972      * http://veillard.com/gcc.bug
09973      */
09974     ret = 0;
09975     while ((*cur >= '0') && (*cur <= '9')) {
09976     ret = ret * 10;
09977     tmp = (*cur - '0');
09978     ok = 1;
09979     cur++;
09980     temp = (double) tmp;
09981     ret = ret + temp;
09982     }
09983 #else
09984     ret = 0;
09985     while ((*cur >= '0') && (*cur <= '9')) {
09986     ret = ret * 10 + (*cur - '0');
09987     ok = 1;
09988     cur++;
09989     }
09990 #endif
09991 
09992     if (*cur == '.') {
09993     int v, frac = 0;
09994     double fraction = 0;
09995 
09996         cur++;
09997     if (((*cur < '0') || (*cur > '9')) && (!ok)) {
09998         return(xmlXPathNAN);
09999     }
10000     while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10001         v = (*cur - '0');
10002         fraction = fraction * 10 + v;
10003         frac = frac + 1;
10004         cur++;
10005     }
10006     fraction /= my_pow10[frac];
10007     ret = ret + fraction;
10008     while ((*cur >= '0') && (*cur <= '9'))
10009         cur++;
10010     }
10011     if ((*cur == 'e') || (*cur == 'E')) {
10012       cur++;
10013       if (*cur == '-') {
10014     is_exponent_negative = 1;
10015     cur++;
10016       } else if (*cur == '+') {
10017         cur++;
10018       }
10019       while ((*cur >= '0') && (*cur <= '9')) {
10020     exponent = exponent * 10 + (*cur - '0');
10021     cur++;
10022       }
10023     }
10024     while (IS_BLANK_CH(*cur)) cur++;
10025     if (*cur != 0) return(xmlXPathNAN);
10026     if (isneg) ret = -ret;
10027     if (is_exponent_negative) exponent = -exponent;
10028     ret *= pow(10.0, (double)exponent);
10029     return(ret);
10030 }
10031 
10043 static void
10044 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10045 {
10046     double ret = 0.0;
10047     double mult = 1;
10048     int ok = 0;
10049     int exponent = 0;
10050     int is_exponent_negative = 0;
10051 #ifdef __GNUC__
10052     unsigned long tmp = 0;
10053     double temp;
10054 #endif
10055 
10056     CHECK_ERROR;
10057     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10058         XP_ERROR(XPATH_NUMBER_ERROR);
10059     }
10060 #ifdef __GNUC__
10061     /*
10062      * tmp/temp is a workaround against a gcc compiler bug
10063      * http://veillard.com/gcc.bug
10064      */
10065     ret = 0;
10066     while ((CUR >= '0') && (CUR <= '9')) {
10067     ret = ret * 10;
10068     tmp = (CUR - '0');
10069         ok = 1;
10070         NEXT;
10071     temp = (double) tmp;
10072     ret = ret + temp;
10073     }
10074 #else
10075     ret = 0;
10076     while ((CUR >= '0') && (CUR <= '9')) {
10077     ret = ret * 10 + (CUR - '0');
10078     ok = 1;
10079     NEXT;
10080     }
10081 #endif
10082     if (CUR == '.') {
10083     int v, frac = 0;
10084     double fraction = 0;
10085 
10086         NEXT;
10087         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10088             XP_ERROR(XPATH_NUMBER_ERROR);
10089         }
10090         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10091         v = (CUR - '0');
10092         fraction = fraction * 10 + v;
10093         frac = frac + 1;
10094             NEXT;
10095         }
10096         fraction /= my_pow10[frac];
10097         ret = ret + fraction;
10098         while ((CUR >= '0') && (CUR <= '9'))
10099             NEXT;
10100     }
10101     if ((CUR == 'e') || (CUR == 'E')) {
10102         NEXT;
10103         if (CUR == '-') {
10104             is_exponent_negative = 1;
10105             NEXT;
10106         } else if (CUR == '+') {
10107         NEXT;
10108     }
10109         while ((CUR >= '0') && (CUR <= '9')) {
10110             exponent = exponent * 10 + (CUR - '0');
10111             NEXT;
10112         }
10113         if (is_exponent_negative)
10114             exponent = -exponent;
10115         ret *= pow(10.0, (double) exponent);
10116     }
10117     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10118                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10119 }
10120 
10132 static xmlChar *
10133 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10134     const xmlChar *q;
10135     xmlChar *ret = NULL;
10136 
10137     if (CUR == '"') {
10138         NEXT;
10139     q = CUR_PTR;
10140     while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10141         NEXT;
10142     if (!IS_CHAR_CH(CUR)) {
10143         XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10144     } else {
10145         ret = xmlStrndup(q, CUR_PTR - q);
10146         NEXT;
10147         }
10148     } else if (CUR == '\'') {
10149         NEXT;
10150     q = CUR_PTR;
10151     while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10152         NEXT;
10153     if (!IS_CHAR_CH(CUR)) {
10154         XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10155     } else {
10156         ret = xmlStrndup(q, CUR_PTR - q);
10157         NEXT;
10158         }
10159     } else {
10160     XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10161     }
10162     return(ret);
10163 }
10164 
10176 static void
10177 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10178     const xmlChar *q;
10179     xmlChar *ret = NULL;
10180 
10181     if (CUR == '"') {
10182         NEXT;
10183     q = CUR_PTR;
10184     while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10185         NEXT;
10186     if (!IS_CHAR_CH(CUR)) {
10187         XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10188     } else {
10189         ret = xmlStrndup(q, CUR_PTR - q);
10190         NEXT;
10191         }
10192     } else if (CUR == '\'') {
10193         NEXT;
10194     q = CUR_PTR;
10195     while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10196         NEXT;
10197     if (!IS_CHAR_CH(CUR)) {
10198         XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10199     } else {
10200         ret = xmlStrndup(q, CUR_PTR - q);
10201         NEXT;
10202         }
10203     } else {
10204     XP_ERROR(XPATH_START_LITERAL_ERROR);
10205     }
10206     if (ret == NULL) return;
10207     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10208                xmlXPathCacheNewString(ctxt->context, ret), NULL);
10209     xmlFree(ret);
10210 }
10211 
10229 static void
10230 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10231     xmlChar *name;
10232     xmlChar *prefix;
10233 
10234     SKIP_BLANKS;
10235     if (CUR != '$') {
10236     XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10237     }
10238     NEXT;
10239     name = xmlXPathParseQName(ctxt, &prefix);
10240     if (name == NULL) {
10241     XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10242     }
10243     ctxt->comp->last = -1;
10244     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10245                name, prefix);
10246     SKIP_BLANKS;
10247     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10248     XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10249     }
10250 }
10251 
10265 int
10266 xmlXPathIsNodeType(const xmlChar *name) {
10267     if (name == NULL)
10268     return(0);
10269 
10270     if (xmlStrEqual(name, BAD_CAST "node"))
10271     return(1);
10272     if (xmlStrEqual(name, BAD_CAST "text"))
10273     return(1);
10274     if (xmlStrEqual(name, BAD_CAST "comment"))
10275     return(1);
10276     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10277     return(1);
10278     return(0);
10279 }
10280 
10291 static void
10292 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10293     xmlChar *name;
10294     xmlChar *prefix;
10295     int nbargs = 0;
10296     int sort = 1;
10297 
10298     name = xmlXPathParseQName(ctxt, &prefix);
10299     if (name == NULL) {
10300     xmlFree(prefix);
10301     XP_ERROR(XPATH_EXPR_ERROR);
10302     }
10303     SKIP_BLANKS;
10304 #ifdef DEBUG_EXPR
10305     if (prefix == NULL)
10306     xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10307             name);
10308     else
10309     xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10310             prefix, name);
10311 #endif
10312 
10313     if (CUR != '(') {
10314     XP_ERROR(XPATH_EXPR_ERROR);
10315     }
10316     NEXT;
10317     SKIP_BLANKS;
10318 
10319     /*
10320     * Optimization for count(): we don't need the node-set to be sorted.
10321     */
10322     if ((prefix == NULL) && (name[0] == 'c') &&
10323     xmlStrEqual(name, BAD_CAST "count"))
10324     {
10325     sort = 0;
10326     }
10327     ctxt->comp->last = -1;
10328     if (CUR != ')') {
10329     while (CUR != 0) {
10330         int op1 = ctxt->comp->last;
10331         ctxt->comp->last = -1;
10332         xmlXPathCompileExpr(ctxt, sort);
10333         if (ctxt->error != XPATH_EXPRESSION_OK) {
10334         xmlFree(name);
10335         xmlFree(prefix);
10336         return;
10337         }
10338         PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10339         nbargs++;
10340         if (CUR == ')') break;
10341         if (CUR != ',') {
10342         XP_ERROR(XPATH_EXPR_ERROR);
10343         }
10344         NEXT;
10345         SKIP_BLANKS;
10346     }
10347     }
10348     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10349                name, prefix);
10350     NEXT;
10351     SKIP_BLANKS;
10352 }
10353 
10366 static void
10367 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10368     SKIP_BLANKS;
10369     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10370     else if (CUR == '(') {
10371     NEXT;
10372     SKIP_BLANKS;
10373     xmlXPathCompileExpr(ctxt, 1);
10374     CHECK_ERROR;
10375     if (CUR != ')') {
10376         XP_ERROR(XPATH_EXPR_ERROR);
10377     }
10378     NEXT;
10379     SKIP_BLANKS;
10380     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10381     xmlXPathCompNumber(ctxt);
10382     } else if ((CUR == '\'') || (CUR == '"')) {
10383     xmlXPathCompLiteral(ctxt);
10384     } else {
10385     xmlXPathCompFunctionCall(ctxt);
10386     }
10387     SKIP_BLANKS;
10388 }
10389 
10405 static void
10406 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10407     xmlXPathCompPrimaryExpr(ctxt);
10408     CHECK_ERROR;
10409     SKIP_BLANKS;
10410 
10411     while (CUR == '[') {
10412     xmlXPathCompPredicate(ctxt, 1);
10413     SKIP_BLANKS;
10414     }
10415 
10416 
10417 }
10418 
10436 static xmlChar *
10437 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10438     int len = 0, l;
10439     int c;
10440     const xmlChar *cur;
10441     xmlChar *ret;
10442 
10443     cur = ctxt->cur;
10444 
10445     c = CUR_CHAR(l);
10446     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10447     (!IS_LETTER(c) && (c != '_') &&
10448          (c != ':'))) {
10449     return(NULL);
10450     }
10451 
10452     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10453        ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10454             (c == '.') || (c == '-') ||
10455         (c == '_') || (c == ':') ||
10456         (IS_COMBINING(c)) ||
10457         (IS_EXTENDER(c)))) {
10458     len += l;
10459     NEXTL(l);
10460     c = CUR_CHAR(l);
10461     }
10462     ret = xmlStrndup(cur, ctxt->cur - cur);
10463     ctxt->cur = cur;
10464     return(ret);
10465 }
10466 
10485 static void
10486 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10487     int lc = 1;           /* Should we branch to LocationPath ?         */
10488     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10489 
10490     SKIP_BLANKS;
10491     if ((CUR == '$') || (CUR == '(') ||
10492     (IS_ASCII_DIGIT(CUR)) ||
10493         (CUR == '\'') || (CUR == '"') ||
10494     (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10495     lc = 0;
10496     } else if (CUR == '*') {
10497     /* relative or absolute location path */
10498     lc = 1;
10499     } else if (CUR == '/') {
10500     /* relative or absolute location path */
10501     lc = 1;
10502     } else if (CUR == '@') {
10503     /* relative abbreviated attribute location path */
10504     lc = 1;
10505     } else if (CUR == '.') {
10506     /* relative abbreviated attribute location path */
10507     lc = 1;
10508     } else {
10509     /*
10510      * Problem is finding if we have a name here whether it's:
10511      *   - a nodetype
10512      *   - a function call in which case it's followed by '('
10513      *   - an axis in which case it's followed by ':'
10514      *   - a element name
10515      * We do an a priori analysis here rather than having to
10516      * maintain parsed token content through the recursive function
10517      * calls. This looks uglier but makes the code easier to
10518      * read/write/debug.
10519      */
10520     SKIP_BLANKS;
10521     name = xmlXPathScanName(ctxt);
10522     if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10523 #ifdef DEBUG_STEP
10524         xmlGenericError(xmlGenericErrorContext,
10525             "PathExpr: Axis\n");
10526 #endif
10527         lc = 1;
10528         xmlFree(name);
10529     } else if (name != NULL) {
10530         int len =xmlStrlen(name);
10531 
10532 
10533         while (NXT(len) != 0) {
10534         if (NXT(len) == '/') {
10535             /* element name */
10536 #ifdef DEBUG_STEP
10537             xmlGenericError(xmlGenericErrorContext,
10538                 "PathExpr: AbbrRelLocation\n");
10539 #endif
10540             lc = 1;
10541             break;
10542         } else if (IS_BLANK_CH(NXT(len))) {
10543             /* ignore blanks */
10544             ;
10545         } else if (NXT(len) == ':') {
10546 #ifdef DEBUG_STEP
10547             xmlGenericError(xmlGenericErrorContext,
10548                 "PathExpr: AbbrRelLocation\n");
10549 #endif
10550             lc = 1;
10551             break;
10552         } else if ((NXT(len) == '(')) {
10553             /* Note Type or Function */
10554             if (xmlXPathIsNodeType(name)) {
10555 #ifdef DEBUG_STEP
10556                 xmlGenericError(xmlGenericErrorContext,
10557                 "PathExpr: Type search\n");
10558 #endif
10559             lc = 1;
10560             } else {
10561 #ifdef DEBUG_STEP
10562                 xmlGenericError(xmlGenericErrorContext,
10563                 "PathExpr: function call\n");
10564 #endif
10565             lc = 0;
10566             }
10567                     break;
10568         } else if ((NXT(len) == '[')) {
10569             /* element name */
10570 #ifdef DEBUG_STEP
10571             xmlGenericError(xmlGenericErrorContext,
10572                 "PathExpr: AbbrRelLocation\n");
10573 #endif
10574             lc = 1;
10575             break;
10576         } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10577                (NXT(len) == '=')) {
10578             lc = 1;
10579             break;
10580         } else {
10581             lc = 1;
10582             break;
10583         }
10584         len++;
10585         }
10586         if (NXT(len) == 0) {
10587 #ifdef DEBUG_STEP
10588         xmlGenericError(xmlGenericErrorContext,
10589             "PathExpr: AbbrRelLocation\n");
10590 #endif
10591         /* element name */
10592         lc = 1;
10593         }
10594         xmlFree(name);
10595     } else {
10596         /* make sure all cases are covered explicitly */
10597         XP_ERROR(XPATH_EXPR_ERROR);
10598     }
10599     }
10600 
10601     if (lc) {
10602     if (CUR == '/') {
10603         PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10604     } else {
10605         PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10606     }
10607     xmlXPathCompLocationPath(ctxt);
10608     } else {
10609     xmlXPathCompFilterExpr(ctxt);
10610     CHECK_ERROR;
10611     if ((CUR == '/') && (NXT(1) == '/')) {
10612         SKIP(2);
10613         SKIP_BLANKS;
10614 
10615         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10616             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10617         PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10618 
10619         xmlXPathCompRelativeLocationPath(ctxt);
10620     } else if (CUR == '/') {
10621         xmlXPathCompRelativeLocationPath(ctxt);
10622     }
10623     }
10624     SKIP_BLANKS;
10625 }
10626 
10637 static void
10638 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10639     xmlXPathCompPathExpr(ctxt);
10640     CHECK_ERROR;
10641     SKIP_BLANKS;
10642     while (CUR == '|') {
10643     int op1 = ctxt->comp->last;
10644     PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10645 
10646     NEXT;
10647     SKIP_BLANKS;
10648     xmlXPathCompPathExpr(ctxt);
10649 
10650     PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10651 
10652     SKIP_BLANKS;
10653     }
10654 }
10655 
10666 static void
10667 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10668     int minus = 0;
10669     int found = 0;
10670 
10671     SKIP_BLANKS;
10672     while (CUR == '-') {
10673         minus = 1 - minus;
10674     found = 1;
10675     NEXT;
10676     SKIP_BLANKS;
10677     }
10678 
10679     xmlXPathCompUnionExpr(ctxt);
10680     CHECK_ERROR;
10681     if (found) {
10682     if (minus)
10683         PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10684     else
10685         PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10686     }
10687 }
10688 
10702 static void
10703 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10704     xmlXPathCompUnaryExpr(ctxt);
10705     CHECK_ERROR;
10706     SKIP_BLANKS;
10707     while ((CUR == '*') ||
10708            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10709            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10710     int op = -1;
10711     int op1 = ctxt->comp->last;
10712 
10713         if (CUR == '*') {
10714         op = 0;
10715         NEXT;
10716     } else if (CUR == 'd') {
10717         op = 1;
10718         SKIP(3);
10719     } else if (CUR == 'm') {
10720         op = 2;
10721         SKIP(3);
10722     }
10723     SKIP_BLANKS;
10724         xmlXPathCompUnaryExpr(ctxt);
10725     CHECK_ERROR;
10726     PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10727     SKIP_BLANKS;
10728     }
10729 }
10730 
10742 static void
10743 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10744 
10745     xmlXPathCompMultiplicativeExpr(ctxt);
10746     CHECK_ERROR;
10747     SKIP_BLANKS;
10748     while ((CUR == '+') || (CUR == '-')) {
10749     int plus;
10750     int op1 = ctxt->comp->last;
10751 
10752         if (CUR == '+') plus = 1;
10753     else plus = 0;
10754     NEXT;
10755     SKIP_BLANKS;
10756         xmlXPathCompMultiplicativeExpr(ctxt);
10757     CHECK_ERROR;
10758     PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10759     SKIP_BLANKS;
10760     }
10761 }
10762 
10781 static void
10782 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10783     xmlXPathCompAdditiveExpr(ctxt);
10784     CHECK_ERROR;
10785     SKIP_BLANKS;
10786     while ((CUR == '<') ||
10787            (CUR == '>') ||
10788            ((CUR == '<') && (NXT(1) == '=')) ||
10789            ((CUR == '>') && (NXT(1) == '='))) {
10790     int inf, strict;
10791     int op1 = ctxt->comp->last;
10792 
10793         if (CUR == '<') inf = 1;
10794     else inf = 0;
10795     if (NXT(1) == '=') strict = 0;
10796     else strict = 1;
10797     NEXT;
10798     if (!strict) NEXT;
10799     SKIP_BLANKS;
10800         xmlXPathCompAdditiveExpr(ctxt);
10801     CHECK_ERROR;
10802     PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10803     SKIP_BLANKS;
10804     }
10805 }
10806 
10823 static void
10824 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10825     xmlXPathCompRelationalExpr(ctxt);
10826     CHECK_ERROR;
10827     SKIP_BLANKS;
10828     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10829     int eq;
10830     int op1 = ctxt->comp->last;
10831 
10832         if (CUR == '=') eq = 1;
10833     else eq = 0;
10834     NEXT;
10835     if (!eq) NEXT;
10836     SKIP_BLANKS;
10837         xmlXPathCompRelationalExpr(ctxt);
10838     CHECK_ERROR;
10839     PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10840     SKIP_BLANKS;
10841     }
10842 }
10843 
10854 static void
10855 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10856     xmlXPathCompEqualityExpr(ctxt);
10857     CHECK_ERROR;
10858     SKIP_BLANKS;
10859     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10860     int op1 = ctxt->comp->last;
10861         SKIP(3);
10862     SKIP_BLANKS;
10863         xmlXPathCompEqualityExpr(ctxt);
10864     CHECK_ERROR;
10865     PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10866     SKIP_BLANKS;
10867     }
10868 }
10869 
10880 static void
10881 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10882     xmlXPathCompAndExpr(ctxt);
10883     CHECK_ERROR;
10884     SKIP_BLANKS;
10885     while ((CUR == 'o') && (NXT(1) == 'r')) {
10886     int op1 = ctxt->comp->last;
10887         SKIP(2);
10888     SKIP_BLANKS;
10889         xmlXPathCompAndExpr(ctxt);
10890     CHECK_ERROR;
10891     PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10892     SKIP_BLANKS;
10893     }
10894     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10895     /* more ops could be optimized too */
10896     /*
10897     * This is the main place to eliminate sorting for
10898     * operations which don't require a sorted node-set.
10899     * E.g. count().
10900     */
10901     PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10902     }
10903 }
10904 
10915 static void
10916 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10917     int op1 = ctxt->comp->last;
10918 
10919     SKIP_BLANKS;
10920     if (CUR != '[') {
10921     XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922     }
10923     NEXT;
10924     SKIP_BLANKS;
10925 
10926     ctxt->comp->last = -1;
10927     /*
10928     * This call to xmlXPathCompileExpr() will deactivate sorting
10929     * of the predicate result.
10930     * TODO: Sorting is still activated for filters, since I'm not
10931     *  sure if needed. Normally sorting should not be needed, since
10932     *  a filter can only diminish the number of items in a sequence,
10933     *  but won't change its order; so if the initial sequence is sorted,
10934     *  subsequent sorting is not needed.
10935     */
10936     if (! filter)
10937     xmlXPathCompileExpr(ctxt, 0);
10938     else
10939     xmlXPathCompileExpr(ctxt, 1);
10940     CHECK_ERROR;
10941 
10942     if (CUR != ']') {
10943     XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10944     }
10945 
10946     if (filter)
10947     PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10948     else
10949     PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10950 
10951     NEXT;
10952     SKIP_BLANKS;
10953 }
10954 
10976 static xmlChar *
10977 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10978                  xmlXPathTypeVal *type, const xmlChar **prefix,
10979              xmlChar *name) {
10980     int blanks;
10981 
10982     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10983     STRANGE;
10984     return(NULL);
10985     }
10986     *type = (xmlXPathTypeVal) 0;
10987     *test = (xmlXPathTestVal) 0;
10988     *prefix = NULL;
10989     SKIP_BLANKS;
10990 
10991     if ((name == NULL) && (CUR == '*')) {
10992     /*
10993      * All elements
10994      */
10995     NEXT;
10996     *test = NODE_TEST_ALL;
10997     return(NULL);
10998     }
10999 
11000     if (name == NULL)
11001     name = xmlXPathParseNCName(ctxt);
11002     if (name == NULL) {
11003     XP_ERRORNULL(XPATH_EXPR_ERROR);
11004     }
11005 
11006     blanks = IS_BLANK_CH(CUR);
11007     SKIP_BLANKS;
11008     if (CUR == '(') {
11009     NEXT;
11010     /*
11011      * NodeType or PI search
11012      */
11013     if (xmlStrEqual(name, BAD_CAST "comment"))
11014         *type = NODE_TYPE_COMMENT;
11015     else if (xmlStrEqual(name, BAD_CAST "node"))
11016         *type = NODE_TYPE_NODE;
11017     else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11018         *type = NODE_TYPE_PI;
11019     else if (xmlStrEqual(name, BAD_CAST "text"))
11020         *type = NODE_TYPE_TEXT;
11021     else {
11022         if (name != NULL)
11023         xmlFree(name);
11024         XP_ERRORNULL(XPATH_EXPR_ERROR);
11025     }
11026 
11027     *test = NODE_TEST_TYPE;
11028 
11029     SKIP_BLANKS;
11030     if (*type == NODE_TYPE_PI) {
11031         /*
11032          * Specific case: search a PI by name.
11033          */
11034         if (name != NULL)
11035         xmlFree(name);
11036         name = NULL;
11037         if (CUR != ')') {
11038         name = xmlXPathParseLiteral(ctxt);
11039         CHECK_ERROR NULL;
11040         *test = NODE_TEST_PI;
11041         SKIP_BLANKS;
11042         }
11043     }
11044     if (CUR != ')') {
11045         if (name != NULL)
11046         xmlFree(name);
11047         XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11048     }
11049     NEXT;
11050     return(name);
11051     }
11052     *test = NODE_TEST_NAME;
11053     if ((!blanks) && (CUR == ':')) {
11054     NEXT;
11055 
11056     /*
11057      * Since currently the parser context don't have a
11058      * namespace list associated:
11059      * The namespace name for this prefix can be computed
11060      * only at evaluation time. The compilation is done
11061      * outside of any context.
11062      */
11063 #if 0
11064     *prefix = xmlXPathNsLookup(ctxt->context, name);
11065     if (name != NULL)
11066         xmlFree(name);
11067     if (*prefix == NULL) {
11068         XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11069     }
11070 #else
11071     *prefix = name;
11072 #endif
11073 
11074     if (CUR == '*') {
11075         /*
11076          * All elements
11077          */
11078         NEXT;
11079         *test = NODE_TEST_ALL;
11080         return(NULL);
11081     }
11082 
11083     name = xmlXPathParseNCName(ctxt);
11084     if (name == NULL) {
11085         XP_ERRORNULL(XPATH_EXPR_ERROR);
11086     }
11087     }
11088     return(name);
11089 }
11090 
11111 static xmlXPathAxisVal
11112 xmlXPathIsAxisName(const xmlChar *name) {
11113     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11114     switch (name[0]) {
11115     case 'a':
11116         if (xmlStrEqual(name, BAD_CAST "ancestor"))
11117         ret = AXIS_ANCESTOR;
11118         if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11119         ret = AXIS_ANCESTOR_OR_SELF;
11120         if (xmlStrEqual(name, BAD_CAST "attribute"))
11121         ret = AXIS_ATTRIBUTE;
11122         break;
11123     case 'c':
11124         if (xmlStrEqual(name, BAD_CAST "child"))
11125         ret = AXIS_CHILD;
11126         break;
11127     case 'd':
11128         if (xmlStrEqual(name, BAD_CAST "descendant"))
11129         ret = AXIS_DESCENDANT;
11130         if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11131         ret = AXIS_DESCENDANT_OR_SELF;
11132         break;
11133     case 'f':
11134         if (xmlStrEqual(name, BAD_CAST "following"))
11135         ret = AXIS_FOLLOWING;
11136         if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11137         ret = AXIS_FOLLOWING_SIBLING;
11138         break;
11139     case 'n':
11140         if (xmlStrEqual(name, BAD_CAST "namespace"))
11141         ret = AXIS_NAMESPACE;
11142         break;
11143     case 'p':
11144         if (xmlStrEqual(name, BAD_CAST "parent"))
11145         ret = AXIS_PARENT;
11146         if (xmlStrEqual(name, BAD_CAST "preceding"))
11147         ret = AXIS_PRECEDING;
11148         if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11149         ret = AXIS_PRECEDING_SIBLING;
11150         break;
11151     case 's':
11152         if (xmlStrEqual(name, BAD_CAST "self"))
11153         ret = AXIS_SELF;
11154         break;
11155     }
11156     return(ret);
11157 }
11158 
11191 static void
11192 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11193 #ifdef LIBXML_XPTR_ENABLED
11194     int rangeto = 0;
11195     int op2 = -1;
11196 #endif
11197 
11198     SKIP_BLANKS;
11199     if ((CUR == '.') && (NXT(1) == '.')) {
11200     SKIP(2);
11201     SKIP_BLANKS;
11202     PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11203             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11204     } else if (CUR == '.') {
11205     NEXT;
11206     SKIP_BLANKS;
11207     } else {
11208     xmlChar *name = NULL;
11209     const xmlChar *prefix = NULL;
11210     xmlXPathTestVal test = (xmlXPathTestVal) 0;
11211     xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11212     xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11213     int op1;
11214 
11215     /*
11216      * The modification needed for XPointer change to the production
11217      */
11218 #ifdef LIBXML_XPTR_ENABLED
11219     if (ctxt->xptr) {
11220         name = xmlXPathParseNCName(ctxt);
11221         if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11222                 op2 = ctxt->comp->last;
11223         xmlFree(name);
11224         SKIP_BLANKS;
11225         if (CUR != '(') {
11226             XP_ERROR(XPATH_EXPR_ERROR);
11227         }
11228         NEXT;
11229         SKIP_BLANKS;
11230 
11231         xmlXPathCompileExpr(ctxt, 1);
11232         /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11233         CHECK_ERROR;
11234 
11235         SKIP_BLANKS;
11236         if (CUR != ')') {
11237             XP_ERROR(XPATH_EXPR_ERROR);
11238         }
11239         NEXT;
11240         rangeto = 1;
11241         goto eval_predicates;
11242         }
11243     }
11244 #endif
11245     if (CUR == '*') {
11246         axis = AXIS_CHILD;
11247     } else {
11248         if (name == NULL)
11249         name = xmlXPathParseNCName(ctxt);
11250         if (name != NULL) {
11251         axis = xmlXPathIsAxisName(name);
11252         if (axis != 0) {
11253             SKIP_BLANKS;
11254             if ((CUR == ':') && (NXT(1) == ':')) {
11255             SKIP(2);
11256             xmlFree(name);
11257             name = NULL;
11258             } else {
11259             /* an element name can conflict with an axis one :-\ */
11260             axis = AXIS_CHILD;
11261             }
11262         } else {
11263             axis = AXIS_CHILD;
11264         }
11265         } else if (CUR == '@') {
11266         NEXT;
11267         axis = AXIS_ATTRIBUTE;
11268         } else {
11269         axis = AXIS_CHILD;
11270         }
11271     }
11272 
11273         if (ctxt->error != XPATH_EXPRESSION_OK) {
11274             xmlFree(name);
11275             return;
11276         }
11277 
11278     name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11279     if (test == 0)
11280         return;
11281 
11282         if ((prefix != NULL) && (ctxt->context != NULL) &&
11283         (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11284         if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11285         xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11286         }
11287     }
11288 #ifdef DEBUG_STEP
11289     xmlGenericError(xmlGenericErrorContext,
11290         "Basis : computing new set\n");
11291 #endif
11292 
11293 #ifdef DEBUG_STEP
11294     xmlGenericError(xmlGenericErrorContext, "Basis : ");
11295     if (ctxt->value == NULL)
11296         xmlGenericError(xmlGenericErrorContext, "no value\n");
11297     else if (ctxt->value->nodesetval == NULL)
11298         xmlGenericError(xmlGenericErrorContext, "Empty\n");
11299     else
11300         xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11301 #endif
11302 
11303 #ifdef LIBXML_XPTR_ENABLED
11304 eval_predicates:
11305 #endif
11306     op1 = ctxt->comp->last;
11307     ctxt->comp->last = -1;
11308 
11309     SKIP_BLANKS;
11310     while (CUR == '[') {
11311         xmlXPathCompPredicate(ctxt, 0);
11312     }
11313 
11314 #ifdef LIBXML_XPTR_ENABLED
11315     if (rangeto) {
11316         PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11317     } else
11318 #endif
11319         PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11320                test, type, (void *)prefix, (void *)name);
11321 
11322     }
11323 #ifdef DEBUG_STEP
11324     xmlGenericError(xmlGenericErrorContext, "Step : ");
11325     if (ctxt->value == NULL)
11326     xmlGenericError(xmlGenericErrorContext, "no value\n");
11327     else if (ctxt->value->nodesetval == NULL)
11328     xmlGenericError(xmlGenericErrorContext, "Empty\n");
11329     else
11330     xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11331         ctxt->value->nodesetval);
11332 #endif
11333 }
11334 
11346 static void
11347 xmlXPathCompRelativeLocationPath
11348 (xmlXPathParserContextPtr ctxt) {
11349     SKIP_BLANKS;
11350     if ((CUR == '/') && (NXT(1) == '/')) {
11351     SKIP(2);
11352     SKIP_BLANKS;
11353     PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11354                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11355     } else if (CUR == '/') {
11356         NEXT;
11357     SKIP_BLANKS;
11358     }
11359     xmlXPathCompStep(ctxt);
11360     CHECK_ERROR;
11361     SKIP_BLANKS;
11362     while (CUR == '/') {
11363     if ((CUR == '/') && (NXT(1) == '/')) {
11364         SKIP(2);
11365         SKIP_BLANKS;
11366         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11367                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11368         xmlXPathCompStep(ctxt);
11369     } else if (CUR == '/') {
11370         NEXT;
11371         SKIP_BLANKS;
11372         xmlXPathCompStep(ctxt);
11373     }
11374     SKIP_BLANKS;
11375     }
11376 }
11377 
11399 static void
11400 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11401     SKIP_BLANKS;
11402     if (CUR != '/') {
11403         xmlXPathCompRelativeLocationPath(ctxt);
11404     } else {
11405     while (CUR == '/') {
11406         if ((CUR == '/') && (NXT(1) == '/')) {
11407         SKIP(2);
11408         SKIP_BLANKS;
11409         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11410                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11411         xmlXPathCompRelativeLocationPath(ctxt);
11412         } else if (CUR == '/') {
11413         NEXT;
11414         SKIP_BLANKS;
11415         if ((CUR != 0 ) &&
11416             ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11417              (CUR == '@') || (CUR == '*')))
11418             xmlXPathCompRelativeLocationPath(ctxt);
11419         }
11420         CHECK_ERROR;
11421     }
11422     }
11423 }
11424 
11425 /************************************************************************
11426  *                                  *
11427  *      XPath precompiled expression evaluation         *
11428  *                                  *
11429  ************************************************************************/
11430 
11431 static int
11432 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11433 
11434 #ifdef DEBUG_STEP
11435 static void
11436 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11437               int nbNodes)
11438 {
11439     xmlGenericError(xmlGenericErrorContext, "new step : ");
11440     switch (op->value) {
11441         case AXIS_ANCESTOR:
11442             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11443             break;
11444         case AXIS_ANCESTOR_OR_SELF:
11445             xmlGenericError(xmlGenericErrorContext,
11446                             "axis 'ancestors-or-self' ");
11447             break;
11448         case AXIS_ATTRIBUTE:
11449             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11450             break;
11451         case AXIS_CHILD:
11452             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11453             break;
11454         case AXIS_DESCENDANT:
11455             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11456             break;
11457         case AXIS_DESCENDANT_OR_SELF:
11458             xmlGenericError(xmlGenericErrorContext,
11459                             "axis 'descendant-or-self' ");
11460             break;
11461         case AXIS_FOLLOWING:
11462             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11463             break;
11464         case AXIS_FOLLOWING_SIBLING:
11465             xmlGenericError(xmlGenericErrorContext,
11466                             "axis 'following-siblings' ");
11467             break;
11468         case AXIS_NAMESPACE:
11469             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11470             break;
11471         case AXIS_PARENT:
11472             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11473             break;
11474         case AXIS_PRECEDING:
11475             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11476             break;
11477         case AXIS_PRECEDING_SIBLING:
11478             xmlGenericError(xmlGenericErrorContext,
11479                             "axis 'preceding-sibling' ");
11480             break;
11481         case AXIS_SELF:
11482             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11483             break;
11484     }
11485     xmlGenericError(xmlGenericErrorContext,
11486     " context contains %d nodes\n", nbNodes);
11487     switch (op->value2) {
11488         case NODE_TEST_NONE:
11489             xmlGenericError(xmlGenericErrorContext,
11490                             "           searching for none !!!\n");
11491             break;
11492         case NODE_TEST_TYPE:
11493             xmlGenericError(xmlGenericErrorContext,
11494                             "           searching for type %d\n", op->value3);
11495             break;
11496         case NODE_TEST_PI:
11497             xmlGenericError(xmlGenericErrorContext,
11498                             "           searching for PI !!!\n");
11499             break;
11500         case NODE_TEST_ALL:
11501             xmlGenericError(xmlGenericErrorContext,
11502                             "           searching for *\n");
11503             break;
11504         case NODE_TEST_NS:
11505             xmlGenericError(xmlGenericErrorContext,
11506                             "           searching for namespace %s\n",
11507                             op->value5);
11508             break;
11509         case NODE_TEST_NAME:
11510             xmlGenericError(xmlGenericErrorContext,
11511                             "           searching for name %s\n", op->value5);
11512             if (op->value4)
11513                 xmlGenericError(xmlGenericErrorContext,
11514                                 "           with namespace %s\n", op->value4);
11515             break;
11516     }
11517     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11518 }
11519 #endif /* DEBUG_STEP */
11520 
11521 static int
11522 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11523                 xmlXPathStepOpPtr op,
11524                 xmlNodeSetPtr set,
11525                 int contextSize,
11526                 int hasNsNodes)
11527 {
11528     if (op->ch1 != -1) {
11529     xmlXPathCompExprPtr comp = ctxt->comp;
11530     /*
11531     * Process inner predicates first.
11532     */
11533     if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11534         /*
11535         * TODO: raise an internal error.
11536         */
11537     }
11538     contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11539         &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11540     CHECK_ERROR0;
11541     if (contextSize <= 0)
11542         return(0);
11543     }
11544     if (op->ch2 != -1) {
11545     xmlXPathContextPtr xpctxt = ctxt->context;
11546     xmlNodePtr contextNode, oldContextNode;
11547     xmlDocPtr oldContextDoc;
11548     int i, res, contextPos = 0, newContextSize;
11549     xmlXPathStepOpPtr exprOp;
11550     xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11551 
11552 #ifdef LIBXML_XPTR_ENABLED
11553     /*
11554     * URGENT TODO: Check the following:
11555     *  We don't expect location sets if evaluating prediates, right?
11556     *  Only filters should expect location sets, right?
11557     */
11558 #endif
11559     /*
11560     * SPEC XPath 1.0:
11561     *  "For each node in the node-set to be filtered, the
11562     *  PredicateExpr is evaluated with that node as the
11563     *  context node, with the number of nodes in the
11564     *  node-set as the context size, and with the proximity
11565     *  position of the node in the node-set with respect to
11566     *  the axis as the context position;"
11567     * @oldset is the node-set" to be filtered.
11568     *
11569     * SPEC XPath 1.0:
11570     *  "only predicates change the context position and
11571     *  context size (see [2.4 Predicates])."
11572     * Example:
11573     *   node-set  context pos
11574     *    nA         1
11575     *    nB         2
11576     *    nC         3
11577     *   After applying predicate [position() > 1] :
11578     *   node-set  context pos
11579     *    nB         1
11580     *    nC         2
11581     */
11582     oldContextNode = xpctxt->node;
11583     oldContextDoc = xpctxt->doc;
11584     /*
11585     * Get the expression of this predicate.
11586     */
11587     exprOp = &ctxt->comp->steps[op->ch2];
11588     newContextSize = 0;
11589     for (i = 0; i < set->nodeNr; i++) {
11590         if (set->nodeTab[i] == NULL)
11591         continue;
11592 
11593         contextNode = set->nodeTab[i];
11594         xpctxt->node = contextNode;
11595         xpctxt->contextSize = contextSize;
11596         xpctxt->proximityPosition = ++contextPos;
11597 
11598         /*
11599         * Also set the xpath document in case things like
11600         * key() are evaluated in the predicate.
11601         */
11602         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11603         (contextNode->doc != NULL))
11604         xpctxt->doc = contextNode->doc;
11605         /*
11606         * Evaluate the predicate expression with 1 context node
11607         * at a time; this node is packaged into a node set; this
11608         * node set is handed over to the evaluation mechanism.
11609         */
11610         if (contextObj == NULL)
11611         contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11612         else
11613         xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11614             contextNode);
11615 
11616         valuePush(ctxt, contextObj);
11617 
11618         res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11619 
11620         if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11621         xmlXPathNodeSetClear(set, hasNsNodes);
11622         newContextSize = 0;
11623         goto evaluation_exit;
11624         }
11625 
11626         if (res != 0) {
11627         newContextSize++;
11628         } else {
11629         /*
11630         * Remove the entry from the initial node set.
11631         */
11632         set->nodeTab[i] = NULL;
11633         if (contextNode->type == XML_NAMESPACE_DECL)
11634             xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11635         }
11636         if (ctxt->value == contextObj) {
11637         /*
11638         * Don't free the temporary XPath object holding the
11639         * context node, in order to avoid massive recreation
11640         * inside this loop.
11641         */
11642         valuePop(ctxt);
11643         xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11644         } else {
11645         /*
11646         * TODO: The object was lost in the evaluation machinery.
11647         *  Can this happen? Maybe in internal-error cases.
11648         */
11649         contextObj = NULL;
11650         }
11651     }
11652 
11653     if (contextObj != NULL) {
11654         if (ctxt->value == contextObj)
11655         valuePop(ctxt);
11656         xmlXPathReleaseObject(xpctxt, contextObj);
11657     }
11658 evaluation_exit:
11659     if (exprRes != NULL)
11660         xmlXPathReleaseObject(ctxt->context, exprRes);
11661     /*
11662     * Reset/invalidate the context.
11663     */
11664     xpctxt->node = oldContextNode;
11665     xpctxt->doc = oldContextDoc;
11666     xpctxt->contextSize = -1;
11667     xpctxt->proximityPosition = -1;
11668     return(newContextSize);
11669     }
11670     return(contextSize);
11671 }
11672 
11673 static int
11674 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11675                       xmlXPathStepOpPtr op,
11676                       xmlNodeSetPtr set,
11677                       int contextSize,
11678                       int minPos,
11679                       int maxPos,
11680                       int hasNsNodes)
11681 {
11682     if (op->ch1 != -1) {
11683     xmlXPathCompExprPtr comp = ctxt->comp;
11684     if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11685         /*
11686         * TODO: raise an internal error.
11687         */
11688     }
11689     contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11690         &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11691     CHECK_ERROR0;
11692     if (contextSize <= 0)
11693         return(0);
11694     }
11695     /*
11696     * Check if the node set contains a sufficient number of nodes for
11697     * the requested range.
11698     */
11699     if (contextSize < minPos) {
11700     xmlXPathNodeSetClear(set, hasNsNodes);
11701     return(0);
11702     }
11703     if (op->ch2 == -1) {
11704     /*
11705     * TODO: Can this ever happen?
11706     */
11707     return (contextSize);
11708     } else {
11709     xmlDocPtr oldContextDoc;
11710     int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11711     xmlXPathStepOpPtr exprOp;
11712     xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11713     xmlNodePtr oldContextNode, contextNode = NULL;
11714     xmlXPathContextPtr xpctxt = ctxt->context;
11715 
11716 #ifdef LIBXML_XPTR_ENABLED
11717         /*
11718         * URGENT TODO: Check the following:
11719         *  We don't expect location sets if evaluating prediates, right?
11720         *  Only filters should expect location sets, right?
11721     */
11722 #endif /* LIBXML_XPTR_ENABLED */
11723 
11724     /*
11725     * Save old context.
11726     */
11727     oldContextNode = xpctxt->node;
11728     oldContextDoc = xpctxt->doc;
11729     /*
11730     * Get the expression of this predicate.
11731     */
11732     exprOp = &ctxt->comp->steps[op->ch2];
11733     for (i = 0; i < set->nodeNr; i++) {
11734         if (set->nodeTab[i] == NULL)
11735         continue;
11736 
11737         contextNode = set->nodeTab[i];
11738         xpctxt->node = contextNode;
11739         xpctxt->contextSize = contextSize;
11740         xpctxt->proximityPosition = ++contextPos;
11741 
11742         /*
11743         * Initialize the new set.
11744         * Also set the xpath document in case things like
11745         * key() evaluation are attempted on the predicate
11746         */
11747         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11748         (contextNode->doc != NULL))
11749         xpctxt->doc = contextNode->doc;
11750         /*
11751         * Evaluate the predicate expression with 1 context node
11752         * at a time; this node is packaged into a node set; this
11753         * node set is handed over to the evaluation mechanism.
11754         */
11755         if (contextObj == NULL)
11756         contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11757         else
11758         xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11759             contextNode);
11760 
11761         valuePush(ctxt, contextObj);
11762         res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11763 
11764         if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11765             xmlXPathObjectPtr tmp;
11766         /* pop the result */
11767         tmp = valuePop(ctxt);
11768         xmlXPathReleaseObject(xpctxt, tmp);
11769         /* then pop off contextObj, which will be freed later */
11770         valuePop(ctxt);
11771         goto evaluation_error;
11772         }
11773 
11774         if (res)
11775         pos++;
11776 
11777         if (res && (pos >= minPos) && (pos <= maxPos)) {
11778         /*
11779         * Fits in the requested range.
11780         */
11781         newContextSize++;
11782         if (minPos == maxPos) {
11783             /*
11784             * Only 1 node was requested.
11785             */
11786             if (contextNode->type == XML_NAMESPACE_DECL) {
11787             /*
11788             * As always: take care of those nasty
11789             * namespace nodes.
11790             */
11791             set->nodeTab[i] = NULL;
11792             }
11793             xmlXPathNodeSetClear(set, hasNsNodes);
11794             set->nodeNr = 1;
11795             set->nodeTab[0] = contextNode;
11796             goto evaluation_exit;
11797         }
11798         if (pos == maxPos) {
11799             /*
11800             * We are done.
11801             */
11802             xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11803             goto evaluation_exit;
11804         }
11805         } else {
11806         /*
11807         * Remove the entry from the initial node set.
11808         */
11809         set->nodeTab[i] = NULL;
11810         if (contextNode->type == XML_NAMESPACE_DECL)
11811             xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11812         }
11813         if (exprRes != NULL) {
11814         xmlXPathReleaseObject(ctxt->context, exprRes);
11815         exprRes = NULL;
11816         }
11817         if (ctxt->value == contextObj) {
11818         /*
11819         * Don't free the temporary XPath object holding the
11820         * context node, in order to avoid massive recreation
11821         * inside this loop.
11822         */
11823         valuePop(ctxt);
11824         xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11825         } else {
11826         /*
11827         * The object was lost in the evaluation machinery.
11828         * Can this happen? Maybe in case of internal-errors.
11829         */
11830         contextObj = NULL;
11831         }
11832     }
11833     goto evaluation_exit;
11834 
11835 evaluation_error:
11836     xmlXPathNodeSetClear(set, hasNsNodes);
11837     newContextSize = 0;
11838 
11839 evaluation_exit:
11840     if (contextObj != NULL) {
11841         if (ctxt->value == contextObj)
11842         valuePop(ctxt);
11843         xmlXPathReleaseObject(xpctxt, contextObj);
11844     }
11845     if (exprRes != NULL)
11846         xmlXPathReleaseObject(ctxt->context, exprRes);
11847     /*
11848     * Reset/invalidate the context.
11849     */
11850     xpctxt->node = oldContextNode;
11851     xpctxt->doc = oldContextDoc;
11852     xpctxt->contextSize = -1;
11853     xpctxt->proximityPosition = -1;
11854     return(newContextSize);
11855     }
11856     return(contextSize);
11857 }
11858 
11859 static int
11860 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11861                 xmlXPathStepOpPtr op,
11862                 int *maxPos)
11863 {
11864 
11865     xmlXPathStepOpPtr exprOp;
11866 
11867     /*
11868     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11869     */
11870 
11871     /*
11872     * If not -1, then ch1 will point to:
11873     * 1) For predicates (XPATH_OP_PREDICATE):
11874     *    - an inner predicate operator
11875     * 2) For filters (XPATH_OP_FILTER):
11876     *    - an inner filter operater OR
11877     *    - an expression selecting the node set.
11878     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11879     */
11880     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11881     return(0);
11882 
11883     if (op->ch2 != -1) {
11884     exprOp = &ctxt->comp->steps[op->ch2];
11885     } else
11886     return(0);
11887 
11888     if ((exprOp != NULL) &&
11889     (exprOp->op == XPATH_OP_VALUE) &&
11890     (exprOp->value4 != NULL) &&
11891     (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11892     {
11893     /*
11894     * We have a "[n]" predicate here.
11895     * TODO: Unfortunately this simplistic test here is not
11896     * able to detect a position() predicate in compound
11897     * expressions like "[@attr = 'a" and position() = 1],
11898     * and even not the usage of position() in
11899     * "[position() = 1]"; thus - obviously - a position-range,
11900     * like it "[position() < 5]", is also not detected.
11901     * Maybe we could rewrite the AST to ease the optimization.
11902     */
11903     *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11904 
11905     if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11906         (float) *maxPos)
11907     {
11908         return(1);
11909     }
11910     }
11911     return(0);
11912 }
11913 
11914 static int
11915 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11916                            xmlXPathStepOpPtr op,
11917                xmlNodePtr * first, xmlNodePtr * last,
11918                int toBool)
11919 {
11920 
11921 #define XP_TEST_HIT \
11922     if (hasAxisRange != 0) { \
11923     if (++pos == maxPos) { \
11924         addNode(seq, cur); \
11925     goto axis_range_end; } \
11926     } else { \
11927     addNode(seq, cur); \
11928     if (breakOnFirstHit) goto first_hit; }
11929 
11930 #define XP_TEST_HIT_NS \
11931     if (hasAxisRange != 0) { \
11932     if (++pos == maxPos) { \
11933         hasNsNodes = 1; \
11934         xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11935     goto axis_range_end; } \
11936     } else { \
11937     hasNsNodes = 1; \
11938     xmlXPathNodeSetAddNs(seq, \
11939     xpctxt->node, (xmlNsPtr) cur); \
11940     if (breakOnFirstHit) goto first_hit; }
11941 
11942     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11943     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11944     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11945     const xmlChar *prefix = op->value4;
11946     const xmlChar *name = op->value5;
11947     const xmlChar *URI = NULL;
11948 
11949 #ifdef DEBUG_STEP
11950     int nbMatches = 0, prevMatches = 0;
11951 #endif
11952     int total = 0, hasNsNodes = 0;
11953     /* The popped object holding the context nodes */
11954     xmlXPathObjectPtr obj;
11955     /* The set of context nodes for the node tests */
11956     xmlNodeSetPtr contextSeq;
11957     int contextIdx;
11958     xmlNodePtr contextNode;
11959     /* The context node for a compound traversal */
11960     xmlNodePtr outerContextNode;
11961     /* The final resulting node set wrt to all context nodes */
11962     xmlNodeSetPtr outSeq;
11963     /*
11964     * The temporary resulting node set wrt 1 context node.
11965     * Used to feed predicate evaluation.
11966     */
11967     xmlNodeSetPtr seq;
11968     xmlNodePtr cur;
11969     /* First predicate operator */
11970     xmlXPathStepOpPtr predOp;
11971     int maxPos; /* The requested position() (when a "[n]" predicate) */
11972     int hasPredicateRange, hasAxisRange, pos, size, newSize;
11973     int breakOnFirstHit;
11974 
11975     xmlXPathTraversalFunction next = NULL;
11976     /* compound axis traversal */
11977     xmlXPathTraversalFunctionExt outerNext = NULL;
11978     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11979     xmlXPathNodeSetMergeFunction mergeAndClear;
11980     xmlNodePtr oldContextNode;
11981     xmlXPathContextPtr xpctxt = ctxt->context;
11982 
11983 
11984     CHECK_TYPE0(XPATH_NODESET);
11985     obj = valuePop(ctxt);
11986     /*
11987     * Setup namespaces.
11988     */
11989     if (prefix != NULL) {
11990         URI = xmlXPathNsLookup(xpctxt, prefix);
11991         if (URI == NULL) {
11992         xmlXPathReleaseObject(xpctxt, obj);
11993             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11994     }
11995     }
11996     /*
11997     * Setup axis.
11998     *
11999     * MAYBE FUTURE TODO: merging optimizations:
12000     * - If the nodes to be traversed wrt to the initial nodes and
12001     *   the current axis cannot overlap, then we could avoid searching
12002     *   for duplicates during the merge.
12003     *   But the question is how/when to evaluate if they cannot overlap.
12004     *   Example: if we know that for two initial nodes, the one is
12005     *   not in the ancestor-or-self axis of the other, then we could safely
12006     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12007     *   the descendant-or-self axis.
12008     */
12009     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12010     switch (axis) {
12011         case AXIS_ANCESTOR:
12012             first = NULL;
12013             next = xmlXPathNextAncestor;
12014             break;
12015         case AXIS_ANCESTOR_OR_SELF:
12016             first = NULL;
12017             next = xmlXPathNextAncestorOrSelf;
12018             break;
12019         case AXIS_ATTRIBUTE:
12020             first = NULL;
12021         last = NULL;
12022             next = xmlXPathNextAttribute;
12023         mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12024             break;
12025         case AXIS_CHILD:
12026         last = NULL;
12027         if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12028         /*
12029         * This iterator will give us only nodes which can
12030         * hold element nodes.
12031         */
12032         outerNext = xmlXPathNextDescendantOrSelfElemParent;
12033         }
12034         if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12035         (type == NODE_TYPE_NODE))
12036         {
12037         /*
12038         * Optimization if an element node type is 'element'.
12039         */
12040         next = xmlXPathNextChildElement;
12041         } else
12042         next = xmlXPathNextChild;
12043         mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12044             break;
12045         case AXIS_DESCENDANT:
12046         last = NULL;
12047             next = xmlXPathNextDescendant;
12048             break;
12049         case AXIS_DESCENDANT_OR_SELF:
12050         last = NULL;
12051             next = xmlXPathNextDescendantOrSelf;
12052             break;
12053         case AXIS_FOLLOWING:
12054         last = NULL;
12055             next = xmlXPathNextFollowing;
12056             break;
12057         case AXIS_FOLLOWING_SIBLING:
12058         last = NULL;
12059             next = xmlXPathNextFollowingSibling;
12060             break;
12061         case AXIS_NAMESPACE:
12062             first = NULL;
12063         last = NULL;
12064             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12065         mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12066             break;
12067         case AXIS_PARENT:
12068             first = NULL;
12069             next = xmlXPathNextParent;
12070             break;
12071         case AXIS_PRECEDING:
12072             first = NULL;
12073             next = xmlXPathNextPrecedingInternal;
12074             break;
12075         case AXIS_PRECEDING_SIBLING:
12076             first = NULL;
12077             next = xmlXPathNextPrecedingSibling;
12078             break;
12079         case AXIS_SELF:
12080             first = NULL;
12081         last = NULL;
12082             next = xmlXPathNextSelf;
12083         mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12084             break;
12085     }
12086 
12087 #ifdef DEBUG_STEP
12088     xmlXPathDebugDumpStepAxis(op,
12089     (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12090 #endif
12091 
12092     if (next == NULL) {
12093     xmlXPathReleaseObject(xpctxt, obj);
12094         return(0);
12095     }
12096     contextSeq = obj->nodesetval;
12097     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12098     xmlXPathReleaseObject(xpctxt, obj);
12099         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12100         return(0);
12101     }
12102     /*
12103     * Predicate optimization ---------------------------------------------
12104     * If this step has a last predicate, which contains a position(),
12105     * then we'll optimize (although not exactly "position()", but only
12106     * the  short-hand form, i.e., "[n]".
12107     *
12108     * Example - expression "/foo[parent::bar][1]":
12109     *
12110     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12111     *   ROOT                               -- op->ch1
12112     *   PREDICATE                          -- op->ch2 (predOp)
12113     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12114     *       SORT
12115     *         COLLECT  'parent' 'name' 'node' bar
12116     *           NODE
12117     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12118     *
12119     */
12120     maxPos = 0;
12121     predOp = NULL;
12122     hasPredicateRange = 0;
12123     hasAxisRange = 0;
12124     if (op->ch2 != -1) {
12125     /*
12126     * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12127     */
12128     predOp = &ctxt->comp->steps[op->ch2];
12129     if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12130         if (predOp->ch1 != -1) {
12131         /*
12132         * Use the next inner predicate operator.
12133         */
12134         predOp = &ctxt->comp->steps[predOp->ch1];
12135         hasPredicateRange = 1;
12136         } else {
12137         /*
12138         * There's no other predicate than the [n] predicate.
12139         */
12140         predOp = NULL;
12141         hasAxisRange = 1;
12142         }
12143     }
12144     }
12145     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12146     /*
12147     * Axis traversal -----------------------------------------------------
12148     */
12149     /*
12150      * 2.3 Node Tests
12151      *  - For the attribute axis, the principal node type is attribute.
12152      *  - For the namespace axis, the principal node type is namespace.
12153      *  - For other axes, the principal node type is element.
12154      *
12155      * A node test * is true for any node of the
12156      * principal node type. For example, child::* will
12157      * select all element children of the context node
12158      */
12159     oldContextNode = xpctxt->node;
12160     addNode = xmlXPathNodeSetAddUnique;
12161     outSeq = NULL;
12162     seq = NULL;
12163     outerContextNode = NULL;
12164     contextNode = NULL;
12165     contextIdx = 0;
12166 
12167 
12168     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12169     if (outerNext != NULL) {
12170         /*
12171         * This is a compound traversal.
12172         */
12173         if (contextNode == NULL) {
12174         /*
12175         * Set the context for the outer traversal.
12176         */
12177         outerContextNode = contextSeq->nodeTab[contextIdx++];
12178         contextNode = outerNext(NULL, outerContextNode);
12179         } else
12180         contextNode = outerNext(contextNode, outerContextNode);
12181         if (contextNode == NULL)
12182         continue;
12183         /*
12184         * Set the context for the main traversal.
12185         */
12186         xpctxt->node = contextNode;
12187     } else
12188         xpctxt->node = contextSeq->nodeTab[contextIdx++];
12189 
12190     if (seq == NULL) {
12191         seq = xmlXPathNodeSetCreate(NULL);
12192         if (seq == NULL) {
12193         total = 0;
12194         goto error;
12195         }
12196     }
12197     /*
12198     * Traverse the axis and test the nodes.
12199     */
12200     pos = 0;
12201     cur = NULL;
12202     hasNsNodes = 0;
12203         do {
12204             cur = next(ctxt, cur);
12205             if (cur == NULL)
12206                 break;
12207 
12208         /*
12209         * QUESTION TODO: What does the "first" and "last" stuff do?
12210         */
12211             if ((first != NULL) && (*first != NULL)) {
12212         if (*first == cur)
12213             break;
12214         if (((total % 256) == 0) &&
12215 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216             (xmlXPathCmpNodesExt(*first, cur) >= 0))
12217 #else
12218             (xmlXPathCmpNodes(*first, cur) >= 0))
12219 #endif
12220         {
12221             break;
12222         }
12223         }
12224         if ((last != NULL) && (*last != NULL)) {
12225         if (*last == cur)
12226             break;
12227         if (((total % 256) == 0) &&
12228 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229             (xmlXPathCmpNodesExt(cur, *last) >= 0))
12230 #else
12231             (xmlXPathCmpNodes(cur, *last) >= 0))
12232 #endif
12233         {
12234             break;
12235         }
12236         }
12237 
12238             total++;
12239 
12240 #ifdef DEBUG_STEP
12241             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12242 #endif
12243 
12244         switch (test) {
12245                 case NODE_TEST_NONE:
12246             total = 0;
12247                     STRANGE
12248             goto error;
12249                 case NODE_TEST_TYPE:
12250             /*
12251             * TODO: Don't we need to use
12252             *  xmlXPathNodeSetAddNs() for namespace nodes here?
12253             *  Surprisingly, some c14n tests fail, if we do this.
12254             */
12255             if (type == NODE_TYPE_NODE) {
12256             switch (cur->type) {
12257                 case XML_DOCUMENT_NODE:
12258                 case XML_HTML_DOCUMENT_NODE:
12259 #ifdef LIBXML_DOCB_ENABLED
12260                 case XML_DOCB_DOCUMENT_NODE:
12261 #endif
12262                 case XML_ELEMENT_NODE:
12263                 case XML_ATTRIBUTE_NODE:
12264                 case XML_PI_NODE:
12265                 case XML_COMMENT_NODE:
12266                 case XML_CDATA_SECTION_NODE:
12267                 case XML_TEXT_NODE:
12268                 case XML_NAMESPACE_DECL:
12269                 XP_TEST_HIT
12270                 break;
12271                 default:
12272                 break;
12273             }
12274             } else if (cur->type == type) {
12275             if (type == XML_NAMESPACE_DECL)
12276                 XP_TEST_HIT_NS
12277             else
12278                 XP_TEST_HIT
12279             } else if ((type == NODE_TYPE_TEXT) &&
12280              (cur->type == XML_CDATA_SECTION_NODE))
12281             {
12282             XP_TEST_HIT
12283             }
12284             break;
12285                 case NODE_TEST_PI:
12286                     if ((cur->type == XML_PI_NODE) &&
12287                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12288             {
12289             XP_TEST_HIT
12290                     }
12291                     break;
12292                 case NODE_TEST_ALL:
12293                     if (axis == AXIS_ATTRIBUTE) {
12294                         if (cur->type == XML_ATTRIBUTE_NODE)
12295             {
12296                 XP_TEST_HIT
12297                         }
12298                     } else if (axis == AXIS_NAMESPACE) {
12299                         if (cur->type == XML_NAMESPACE_DECL)
12300             {
12301                 XP_TEST_HIT_NS
12302                         }
12303                     } else {
12304                         if (cur->type == XML_ELEMENT_NODE) {
12305                             if (prefix == NULL)
12306                 {
12307                 XP_TEST_HIT
12308 
12309                             } else if ((cur->ns != NULL) &&
12310                 (xmlStrEqual(URI, cur->ns->href)))
12311                 {
12312                 XP_TEST_HIT
12313                             }
12314                         }
12315                     }
12316                     break;
12317                 case NODE_TEST_NS:{
12318                         TODO;
12319                         break;
12320                     }
12321                 case NODE_TEST_NAME:
12322                     if (axis == AXIS_ATTRIBUTE) {
12323                         if (cur->type != XML_ATTRIBUTE_NODE)
12324                 break;
12325             } else if (axis == AXIS_NAMESPACE) {
12326                         if (cur->type != XML_NAMESPACE_DECL)
12327                 break;
12328             } else {
12329                 if (cur->type != XML_ELEMENT_NODE)
12330                 break;
12331             }
12332                     switch (cur->type) {
12333                         case XML_ELEMENT_NODE:
12334                             if (xmlStrEqual(name, cur->name)) {
12335                                 if (prefix == NULL) {
12336                                     if (cur->ns == NULL)
12337                     {
12338                     XP_TEST_HIT
12339                                     }
12340                                 } else {
12341                                     if ((cur->ns != NULL) &&
12342                                         (xmlStrEqual(URI, cur->ns->href)))
12343                     {
12344                     XP_TEST_HIT
12345                                     }
12346                                 }
12347                             }
12348                             break;
12349                         case XML_ATTRIBUTE_NODE:{
12350                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12351 
12352                                 if (xmlStrEqual(name, attr->name)) {
12353                                     if (prefix == NULL) {
12354                                         if ((attr->ns == NULL) ||
12355                                             (attr->ns->prefix == NULL))
12356                     {
12357                         XP_TEST_HIT
12358                                         }
12359                                     } else {
12360                                         if ((attr->ns != NULL) &&
12361                                             (xmlStrEqual(URI,
12362                           attr->ns->href)))
12363                     {
12364                         XP_TEST_HIT
12365                                         }
12366                                     }
12367                                 }
12368                                 break;
12369                             }
12370                         case XML_NAMESPACE_DECL:
12371                             if (cur->type == XML_NAMESPACE_DECL) {
12372                                 xmlNsPtr ns = (xmlNsPtr) cur;
12373 
12374                                 if ((ns->prefix != NULL) && (name != NULL)
12375                                     && (xmlStrEqual(ns->prefix, name)))
12376                 {
12377                     XP_TEST_HIT_NS
12378                                 }
12379                             }
12380                             break;
12381                         default:
12382                             break;
12383                     }
12384                     break;
12385         } /* switch(test) */
12386         } while (cur != NULL);
12387 
12388     goto apply_predicates;
12389 
12390 axis_range_end: /* ----------------------------------------------------- */
12391     /*
12392     * We have a "/foo[n]", and position() = n was reached.
12393     * Note that we can have as well "/foo/::parent::foo[1]", so
12394     * a duplicate-aware merge is still needed.
12395     * Merge with the result.
12396     */
12397     if (outSeq == NULL) {
12398         outSeq = seq;
12399         seq = NULL;
12400     } else
12401         outSeq = mergeAndClear(outSeq, seq, 0);
12402     /*
12403     * Break if only a true/false result was requested.
12404     */
12405     if (toBool)
12406         break;
12407     continue;
12408 
12409 first_hit: /* ---------------------------------------------------------- */
12410     /*
12411     * Break if only a true/false result was requested and
12412     * no predicates existed and a node test succeeded.
12413     */
12414     if (outSeq == NULL) {
12415         outSeq = seq;
12416         seq = NULL;
12417     } else
12418         outSeq = mergeAndClear(outSeq, seq, 0);
12419     break;
12420 
12421 #ifdef DEBUG_STEP
12422     if (seq != NULL)
12423         nbMatches += seq->nodeNr;
12424 #endif
12425 
12426 apply_predicates: /* --------------------------------------------------- */
12427         /*
12428     * Apply predicates.
12429     */
12430         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12431         /*
12432         * E.g. when we have a "/foo[some expression][n]".
12433         */      
12434         /*
12435         * QUESTION TODO: The old predicate evaluation took into
12436         *  account location-sets.
12437         *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12438         *  Do we expect such a set here?
12439         *  All what I learned now from the evaluation semantics
12440         *  does not indicate that a location-set will be processed
12441         *  here, so this looks OK.
12442         */      
12443         /*
12444         * Iterate over all predicates, starting with the outermost
12445         * predicate.
12446         * TODO: Problem: we cannot execute the inner predicates first
12447         *  since we cannot go back *up* the operator tree!
12448         *  Options we have:
12449         *  1) Use of recursive functions (like is it currently done
12450         *     via xmlXPathCompOpEval())
12451         *  2) Add a predicate evaluation information stack to the
12452         *     context struct
12453         *  3) Change the way the operators are linked; we need a
12454         *     "parent" field on xmlXPathStepOp
12455         *
12456         * For the moment, I'll try to solve this with a recursive
12457         * function: xmlXPathCompOpEvalPredicate().
12458         */
12459         size = seq->nodeNr;
12460         if (hasPredicateRange != 0)
12461         newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12462             predOp, seq, size, maxPos, maxPos, hasNsNodes);
12463         else
12464         newSize = xmlXPathCompOpEvalPredicate(ctxt,
12465             predOp, seq, size, hasNsNodes);
12466 
12467         if (ctxt->error != XPATH_EXPRESSION_OK) {
12468         total = 0;
12469         goto error;
12470         }
12471         /*
12472         * Add the filtered set of nodes to the result node set.
12473         */
12474         if (newSize == 0) {
12475         /*
12476         * The predicates filtered all nodes out.
12477         */
12478         xmlXPathNodeSetClear(seq, hasNsNodes);
12479         } else if (seq->nodeNr > 0) {
12480         /*
12481         * Add to result set.
12482         */
12483         if (outSeq == NULL) {
12484             if (size != newSize) {
12485             /*
12486             * We need to merge and clear here, since
12487             * the sequence will contained NULLed entries.
12488             */
12489             outSeq = mergeAndClear(NULL, seq, 1);
12490             } else {
12491             outSeq = seq;
12492             seq = NULL;
12493             }
12494         } else
12495             outSeq = mergeAndClear(outSeq, seq,
12496             (size != newSize) ? 1: 0);
12497         /*
12498         * Break if only a true/false result was requested.
12499         */
12500         if (toBool)
12501             break;
12502         }
12503         } else if (seq->nodeNr > 0) {
12504         /*
12505         * Add to result set.
12506         */
12507         if (outSeq == NULL) {
12508         outSeq = seq;
12509         seq = NULL;
12510         } else {
12511         outSeq = mergeAndClear(outSeq, seq, 0);
12512         }
12513     }
12514     }
12515 
12516 error:
12517     if ((obj->boolval) && (obj->user != NULL)) {
12518     /*
12519     * QUESTION TODO: What does this do and why?
12520     * TODO: Do we have to do this also for the "error"
12521     * cleanup further down?
12522     */
12523     ctxt->value->boolval = 1;
12524     ctxt->value->user = obj->user;
12525     obj->user = NULL;
12526     obj->boolval = 0;
12527     }
12528     xmlXPathReleaseObject(xpctxt, obj);
12529 
12530     /*
12531     * Ensure we return at least an emtpy set.
12532     */
12533     if (outSeq == NULL) {
12534     if ((seq != NULL) && (seq->nodeNr == 0))
12535         outSeq = seq;
12536     else
12537         outSeq = xmlXPathNodeSetCreate(NULL);
12538         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12539     }
12540     if ((seq != NULL) && (seq != outSeq)) {
12541      xmlXPathFreeNodeSet(seq);
12542     }
12543     /*
12544     * Hand over the result. Better to push the set also in
12545     * case of errors.
12546     */
12547     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12548     /*
12549     * Reset the context node.
12550     */
12551     xpctxt->node = oldContextNode;
12552 
12553 #ifdef DEBUG_STEP
12554     xmlGenericError(xmlGenericErrorContext,
12555     "\nExamined %d nodes, found %d nodes at that step\n",
12556     total, nbMatches);
12557 #endif
12558 
12559     return(total);
12560 }
12561 
12562 static int
12563 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12564                   xmlXPathStepOpPtr op, xmlNodePtr * first);
12565 
12577 static int
12578 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12579                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12580 {
12581     int total = 0, cur;
12582     xmlXPathCompExprPtr comp;
12583     xmlXPathObjectPtr arg1, arg2;
12584 
12585     CHECK_ERROR0;
12586     comp = ctxt->comp;
12587     switch (op->op) {
12588         case XPATH_OP_END:
12589             return (0);
12590         case XPATH_OP_UNION:
12591             total =
12592                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12593                                         first);
12594         CHECK_ERROR0;
12595             if ((ctxt->value != NULL)
12596                 && (ctxt->value->type == XPATH_NODESET)
12597                 && (ctxt->value->nodesetval != NULL)
12598                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12599                 /*
12600                  * limit tree traversing to first node in the result
12601                  */
12602         /*
12603         * OPTIMIZE TODO: This implicitely sorts
12604         *  the result, even if not needed. E.g. if the argument
12605         *  of the count() function, no sorting is needed.
12606         * OPTIMIZE TODO: How do we know if the node-list wasn't
12607         *  aready sorted?
12608         */
12609         if (ctxt->value->nodesetval->nodeNr > 1)
12610             xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611                 *first = ctxt->value->nodesetval->nodeTab[0];
12612             }
12613             cur =
12614                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12615                                         first);
12616         CHECK_ERROR0;
12617             CHECK_TYPE0(XPATH_NODESET);
12618             arg2 = valuePop(ctxt);
12619 
12620             CHECK_TYPE0(XPATH_NODESET);
12621             arg1 = valuePop(ctxt);
12622 
12623             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12624                                                     arg2->nodesetval);
12625             valuePush(ctxt, arg1);
12626         xmlXPathReleaseObject(ctxt->context, arg2);
12627             /* optimizer */
12628         if (total > cur)
12629         xmlXPathCompSwap(op);
12630             return (total + cur);
12631         case XPATH_OP_ROOT:
12632             xmlXPathRoot(ctxt);
12633             return (0);
12634         case XPATH_OP_NODE:
12635             if (op->ch1 != -1)
12636                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12637         CHECK_ERROR0;
12638             if (op->ch2 != -1)
12639                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12640         CHECK_ERROR0;
12641         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12642         ctxt->context->node));
12643             return (total);
12644         case XPATH_OP_RESET:
12645             if (op->ch1 != -1)
12646                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12647         CHECK_ERROR0;
12648             if (op->ch2 != -1)
12649                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12650         CHECK_ERROR0;
12651             ctxt->context->node = NULL;
12652             return (total);
12653         case XPATH_OP_COLLECT:{
12654                 if (op->ch1 == -1)
12655                     return (total);
12656 
12657                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12658         CHECK_ERROR0;
12659 
12660                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12661                 return (total);
12662             }
12663         case XPATH_OP_VALUE:
12664             valuePush(ctxt,
12665                       xmlXPathCacheObjectCopy(ctxt->context,
12666             (xmlXPathObjectPtr) op->value4));
12667             return (0);
12668         case XPATH_OP_SORT:
12669             if (op->ch1 != -1)
12670                 total +=
12671                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12672                                             first);
12673         CHECK_ERROR0;
12674             if ((ctxt->value != NULL)
12675                 && (ctxt->value->type == XPATH_NODESET)
12676                 && (ctxt->value->nodesetval != NULL)
12677         && (ctxt->value->nodesetval->nodeNr > 1))
12678                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12679             return (total);
12680 #ifdef XP_OPTIMIZED_FILTER_FIRST
12681     case XPATH_OP_FILTER:
12682                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12683             return (total);
12684 #endif
12685         default:
12686             return (xmlXPathCompOpEval(ctxt, op));
12687     }
12688 }
12689 
12701 static int
12702 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12703                        xmlNodePtr * last)
12704 {
12705     int total = 0, cur;
12706     xmlXPathCompExprPtr comp;
12707     xmlXPathObjectPtr arg1, arg2;
12708     xmlNodePtr bak;
12709     xmlDocPtr bakd;
12710     int pp;
12711     int cs;
12712 
12713     CHECK_ERROR0;
12714     comp = ctxt->comp;
12715     switch (op->op) {
12716         case XPATH_OP_END:
12717             return (0);
12718         case XPATH_OP_UNION:
12719         bakd = ctxt->context->doc;
12720         bak = ctxt->context->node;
12721         pp = ctxt->context->proximityPosition;
12722         cs = ctxt->context->contextSize;
12723             total =
12724                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12725         CHECK_ERROR0;
12726             if ((ctxt->value != NULL)
12727                 && (ctxt->value->type == XPATH_NODESET)
12728                 && (ctxt->value->nodesetval != NULL)
12729                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12730                 /*
12731                  * limit tree traversing to first node in the result
12732                  */
12733         if (ctxt->value->nodesetval->nodeNr > 1)
12734             xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735                 *last =
12736                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12737                                                      nodesetval->nodeNr -
12738                                                      1];
12739             }
12740         ctxt->context->doc = bakd;
12741         ctxt->context->node = bak;
12742         ctxt->context->proximityPosition = pp;
12743         ctxt->context->contextSize = cs;
12744             cur =
12745                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12746         CHECK_ERROR0;
12747             if ((ctxt->value != NULL)
12748                 && (ctxt->value->type == XPATH_NODESET)
12749                 && (ctxt->value->nodesetval != NULL)
12750                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12751             }
12752             CHECK_TYPE0(XPATH_NODESET);
12753             arg2 = valuePop(ctxt);
12754 
12755             CHECK_TYPE0(XPATH_NODESET);
12756             arg1 = valuePop(ctxt);
12757 
12758             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12759                                                     arg2->nodesetval);
12760             valuePush(ctxt, arg1);
12761         xmlXPathReleaseObject(ctxt->context, arg2);
12762             /* optimizer */
12763         if (total > cur)
12764         xmlXPathCompSwap(op);
12765             return (total + cur);
12766         case XPATH_OP_ROOT:
12767             xmlXPathRoot(ctxt);
12768             return (0);
12769         case XPATH_OP_NODE:
12770             if (op->ch1 != -1)
12771                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12772         CHECK_ERROR0;
12773             if (op->ch2 != -1)
12774                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12775         CHECK_ERROR0;
12776         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12777         ctxt->context->node));
12778             return (total);
12779         case XPATH_OP_RESET:
12780             if (op->ch1 != -1)
12781                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12782         CHECK_ERROR0;
12783             if (op->ch2 != -1)
12784                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12785         CHECK_ERROR0;
12786             ctxt->context->node = NULL;
12787             return (total);
12788         case XPATH_OP_COLLECT:{
12789                 if (op->ch1 == -1)
12790                     return (0);
12791 
12792                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793         CHECK_ERROR0;
12794 
12795                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12796                 return (total);
12797             }
12798         case XPATH_OP_VALUE:
12799             valuePush(ctxt,
12800                       xmlXPathCacheObjectCopy(ctxt->context,
12801             (xmlXPathObjectPtr) op->value4));
12802             return (0);
12803         case XPATH_OP_SORT:
12804             if (op->ch1 != -1)
12805                 total +=
12806                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12807                                            last);
12808         CHECK_ERROR0;
12809             if ((ctxt->value != NULL)
12810                 && (ctxt->value->type == XPATH_NODESET)
12811                 && (ctxt->value->nodesetval != NULL)
12812         && (ctxt->value->nodesetval->nodeNr > 1))
12813                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12814             return (total);
12815         default:
12816             return (xmlXPathCompOpEval(ctxt, op));
12817     }
12818 }
12819 
12820 #ifdef XP_OPTIMIZED_FILTER_FIRST
12821 static int
12822 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12823                   xmlXPathStepOpPtr op, xmlNodePtr * first)
12824 {
12825     int total = 0;
12826     xmlXPathCompExprPtr comp;
12827     xmlXPathObjectPtr res;
12828     xmlXPathObjectPtr obj;
12829     xmlNodeSetPtr oldset;
12830     xmlNodePtr oldnode;
12831     xmlDocPtr oldDoc;
12832     int i;
12833 
12834     CHECK_ERROR0;
12835     comp = ctxt->comp;
12836     /*
12837     * Optimization for ()[last()] selection i.e. the last elem
12838     */
12839     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12840     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12841     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12842     int f = comp->steps[op->ch2].ch1;
12843 
12844     if ((f != -1) &&
12845         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12846         (comp->steps[f].value5 == NULL) &&
12847         (comp->steps[f].value == 0) &&
12848         (comp->steps[f].value4 != NULL) &&
12849         (xmlStrEqual
12850         (comp->steps[f].value4, BAD_CAST "last"))) {
12851         xmlNodePtr last = NULL;
12852 
12853         total +=
12854         xmlXPathCompOpEvalLast(ctxt,
12855             &comp->steps[op->ch1],
12856             &last);
12857         CHECK_ERROR0;
12858         /*
12859         * The nodeset should be in document order,
12860         * Keep only the last value
12861         */
12862         if ((ctxt->value != NULL) &&
12863         (ctxt->value->type == XPATH_NODESET) &&
12864         (ctxt->value->nodesetval != NULL) &&
12865         (ctxt->value->nodesetval->nodeTab != NULL) &&
12866         (ctxt->value->nodesetval->nodeNr > 1)) {
12867         ctxt->value->nodesetval->nodeTab[0] =
12868             ctxt->value->nodesetval->nodeTab[ctxt->
12869             value->
12870             nodesetval->
12871             nodeNr -
12872             1];
12873         ctxt->value->nodesetval->nodeNr = 1;
12874         *first = *(ctxt->value->nodesetval->nodeTab);
12875         }
12876         return (total);
12877     }
12878     }
12879 
12880     if (op->ch1 != -1)
12881     total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12882     CHECK_ERROR0;
12883     if (op->ch2 == -1)
12884     return (total);
12885     if (ctxt->value == NULL)
12886     return (total);
12887 
12888 #ifdef LIBXML_XPTR_ENABLED
12889     oldnode = ctxt->context->node;
12890     /*
12891     * Hum are we filtering the result of an XPointer expression
12892     */
12893     if (ctxt->value->type == XPATH_LOCATIONSET) {
12894     xmlXPathObjectPtr tmp = NULL;
12895     xmlLocationSetPtr newlocset = NULL;
12896     xmlLocationSetPtr oldlocset;
12897 
12898     /*
12899     * Extract the old locset, and then evaluate the result of the
12900     * expression for all the element in the locset. use it to grow
12901     * up a new locset.
12902     */
12903     CHECK_TYPE0(XPATH_LOCATIONSET);
12904     obj = valuePop(ctxt);
12905     oldlocset = obj->user;
12906     ctxt->context->node = NULL;
12907 
12908     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12909         ctxt->context->contextSize = 0;
12910         ctxt->context->proximityPosition = 0;
12911         if (op->ch2 != -1)
12912         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12913         res = valuePop(ctxt);
12914         if (res != NULL) {
12915         xmlXPathReleaseObject(ctxt->context, res);
12916         }
12917         valuePush(ctxt, obj);
12918         CHECK_ERROR0;
12919         return (total);
12920     }
12921     newlocset = xmlXPtrLocationSetCreate(NULL);
12922 
12923     for (i = 0; i < oldlocset->locNr; i++) {
12924         /*
12925         * Run the evaluation with a node list made of a
12926         * single item in the nodelocset.
12927         */
12928         ctxt->context->node = oldlocset->locTab[i]->user;
12929         ctxt->context->contextSize = oldlocset->locNr;
12930         ctxt->context->proximityPosition = i + 1;
12931         if (tmp == NULL) {
12932         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12933             ctxt->context->node);
12934         } else {
12935         xmlXPathNodeSetAddUnique(tmp->nodesetval,
12936             ctxt->context->node);
12937         }
12938         valuePush(ctxt, tmp);
12939         if (op->ch2 != -1)
12940         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12941         if (ctxt->error != XPATH_EXPRESSION_OK) {
12942         xmlXPathFreeObject(obj);
12943         return(0);
12944         }
12945         /*
12946         * The result of the evaluation need to be tested to
12947         * decided whether the filter succeeded or not
12948         */
12949         res = valuePop(ctxt);
12950         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12951         xmlXPtrLocationSetAdd(newlocset,
12952             xmlXPathCacheObjectCopy(ctxt->context,
12953             oldlocset->locTab[i]));
12954         }
12955         /*
12956         * Cleanup
12957         */
12958         if (res != NULL) {
12959         xmlXPathReleaseObject(ctxt->context, res);
12960         }
12961         if (ctxt->value == tmp) {
12962         valuePop(ctxt);
12963         xmlXPathNodeSetClear(tmp->nodesetval, 1);
12964         /*
12965         * REVISIT TODO: Don't create a temporary nodeset
12966         * for everly iteration.
12967         */
12968         /* OLD: xmlXPathFreeObject(res); */
12969         } else
12970         tmp = NULL;
12971         ctxt->context->node = NULL;
12972         /*
12973         * Only put the first node in the result, then leave.
12974         */
12975         if (newlocset->locNr > 0) {
12976         *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12977         break;
12978         }
12979     }
12980     if (tmp != NULL) {
12981         xmlXPathReleaseObject(ctxt->context, tmp);
12982     }
12983     /*
12984     * The result is used as the new evaluation locset.
12985     */
12986     xmlXPathReleaseObject(ctxt->context, obj);
12987     ctxt->context->node = NULL;
12988     ctxt->context->contextSize = -1;
12989     ctxt->context->proximityPosition = -1;
12990     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12991     ctxt->context->node = oldnode;
12992     return (total);
12993     }
12994 #endif /* LIBXML_XPTR_ENABLED */
12995 
12996     /*
12997     * Extract the old set, and then evaluate the result of the
12998     * expression for all the element in the set. use it to grow
12999     * up a new set.
13000     */
13001     CHECK_TYPE0(XPATH_NODESET);
13002     obj = valuePop(ctxt);
13003     oldset = obj->nodesetval;
13004 
13005     oldnode = ctxt->context->node;
13006     oldDoc = ctxt->context->doc;
13007     ctxt->context->node = NULL;
13008 
13009     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13010     ctxt->context->contextSize = 0;
13011     ctxt->context->proximityPosition = 0;
13012     /* QUESTION TODO: Why was this code commented out?
13013         if (op->ch2 != -1)
13014         total +=
13015             xmlXPathCompOpEval(ctxt,
13016             &comp->steps[op->ch2]);
13017         CHECK_ERROR0;
13018         res = valuePop(ctxt);
13019         if (res != NULL)
13020         xmlXPathFreeObject(res);
13021     */
13022     valuePush(ctxt, obj);
13023     ctxt->context->node = oldnode;
13024     CHECK_ERROR0;
13025     } else {
13026     xmlNodeSetPtr newset;
13027     xmlXPathObjectPtr tmp = NULL;
13028     /*
13029     * Initialize the new set.
13030     * Also set the xpath document in case things like
13031     * key() evaluation are attempted on the predicate
13032     */
13033     newset = xmlXPathNodeSetCreate(NULL);
13034         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13035 
13036     for (i = 0; i < oldset->nodeNr; i++) {
13037         /*
13038         * Run the evaluation with a node list made of
13039         * a single item in the nodeset.
13040         */
13041         ctxt->context->node = oldset->nodeTab[i];
13042         if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13043         (oldset->nodeTab[i]->doc != NULL))
13044         ctxt->context->doc = oldset->nodeTab[i]->doc;
13045         if (tmp == NULL) {
13046         tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13047             ctxt->context->node);
13048         } else {
13049         xmlXPathNodeSetAddUnique(tmp->nodesetval,
13050             ctxt->context->node);
13051         }
13052         valuePush(ctxt, tmp);
13053         ctxt->context->contextSize = oldset->nodeNr;
13054         ctxt->context->proximityPosition = i + 1;
13055         if (op->ch2 != -1)
13056         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057         if (ctxt->error != XPATH_EXPRESSION_OK) {
13058         xmlXPathFreeNodeSet(newset);
13059         xmlXPathFreeObject(obj);
13060         return(0);
13061         }
13062         /*
13063         * The result of the evaluation needs to be tested to
13064         * decide whether the filter succeeded or not
13065         */
13066         res = valuePop(ctxt);
13067         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13068         xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13069         }
13070         /*
13071         * Cleanup
13072         */
13073         if (res != NULL) {
13074         xmlXPathReleaseObject(ctxt->context, res);
13075         }
13076         if (ctxt->value == tmp) {
13077         valuePop(ctxt);
13078         /*
13079         * Don't free the temporary nodeset
13080         * in order to avoid massive recreation inside this
13081         * loop.
13082         */
13083         xmlXPathNodeSetClear(tmp->nodesetval, 1);
13084         } else
13085         tmp = NULL;
13086         ctxt->context->node = NULL;
13087         /*
13088         * Only put the first node in the result, then leave.
13089         */
13090         if (newset->nodeNr > 0) {
13091         *first = *(newset->nodeTab);
13092         break;
13093         }
13094     }
13095     if (tmp != NULL) {
13096         xmlXPathReleaseObject(ctxt->context, tmp);
13097     }
13098     /*
13099     * The result is used as the new evaluation set.
13100     */
13101     xmlXPathReleaseObject(ctxt->context, obj);
13102     ctxt->context->node = NULL;
13103     ctxt->context->contextSize = -1;
13104     ctxt->context->proximityPosition = -1;
13105     /* may want to move this past the '}' later */
13106     ctxt->context->doc = oldDoc;
13107     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13108     }
13109     ctxt->context->node = oldnode;
13110     return(total);
13111 }
13112 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13113 
13122 static int
13123 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13124 {
13125     int total = 0;
13126     int equal, ret;
13127     xmlXPathCompExprPtr comp;
13128     xmlXPathObjectPtr arg1, arg2;
13129     xmlNodePtr bak;
13130     xmlDocPtr bakd;
13131     int pp;
13132     int cs;
13133 
13134     CHECK_ERROR0;
13135     comp = ctxt->comp;
13136     switch (op->op) {
13137         case XPATH_OP_END:
13138             return (0);
13139         case XPATH_OP_AND:
13140         bakd = ctxt->context->doc;
13141         bak = ctxt->context->node;
13142         pp = ctxt->context->proximityPosition;
13143         cs = ctxt->context->contextSize;
13144             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145         CHECK_ERROR0;
13146             xmlXPathBooleanFunction(ctxt, 1);
13147             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13148                 return (total);
13149             arg2 = valuePop(ctxt);
13150         ctxt->context->doc = bakd;
13151         ctxt->context->node = bak;
13152         ctxt->context->proximityPosition = pp;
13153         ctxt->context->contextSize = cs;
13154             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155         if (ctxt->error) {
13156         xmlXPathFreeObject(arg2);
13157         return(0);
13158         }
13159             xmlXPathBooleanFunction(ctxt, 1);
13160             arg1 = valuePop(ctxt);
13161             arg1->boolval &= arg2->boolval;
13162             valuePush(ctxt, arg1);
13163         xmlXPathReleaseObject(ctxt->context, arg2);
13164             return (total);
13165         case XPATH_OP_OR:
13166         bakd = ctxt->context->doc;
13167         bak = ctxt->context->node;
13168         pp = ctxt->context->proximityPosition;
13169         cs = ctxt->context->contextSize;
13170             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171         CHECK_ERROR0;
13172             xmlXPathBooleanFunction(ctxt, 1);
13173             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13174                 return (total);
13175             arg2 = valuePop(ctxt);
13176         ctxt->context->doc = bakd;
13177         ctxt->context->node = bak;
13178         ctxt->context->proximityPosition = pp;
13179         ctxt->context->contextSize = cs;
13180             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13181         if (ctxt->error) {
13182         xmlXPathFreeObject(arg2);
13183         return(0);
13184         }
13185             xmlXPathBooleanFunction(ctxt, 1);
13186             arg1 = valuePop(ctxt);
13187             arg1->boolval |= arg2->boolval;
13188             valuePush(ctxt, arg1);
13189         xmlXPathReleaseObject(ctxt->context, arg2);
13190             return (total);
13191         case XPATH_OP_EQUAL:
13192         bakd = ctxt->context->doc;
13193         bak = ctxt->context->node;
13194         pp = ctxt->context->proximityPosition;
13195         cs = ctxt->context->contextSize;
13196             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13197         CHECK_ERROR0;
13198         ctxt->context->doc = bakd;
13199         ctxt->context->node = bak;
13200         ctxt->context->proximityPosition = pp;
13201         ctxt->context->contextSize = cs;
13202             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13203         CHECK_ERROR0;
13204         if (op->value)
13205         equal = xmlXPathEqualValues(ctxt);
13206         else
13207         equal = xmlXPathNotEqualValues(ctxt);
13208         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13209             return (total);
13210         case XPATH_OP_CMP:
13211         bakd = ctxt->context->doc;
13212         bak = ctxt->context->node;
13213         pp = ctxt->context->proximityPosition;
13214         cs = ctxt->context->contextSize;
13215             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13216         CHECK_ERROR0;
13217         ctxt->context->doc = bakd;
13218         ctxt->context->node = bak;
13219         ctxt->context->proximityPosition = pp;
13220         ctxt->context->contextSize = cs;
13221             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13222         CHECK_ERROR0;
13223             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13224         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13225             return (total);
13226         case XPATH_OP_PLUS:
13227         bakd = ctxt->context->doc;
13228         bak = ctxt->context->node;
13229         pp = ctxt->context->proximityPosition;
13230         cs = ctxt->context->contextSize;
13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232         CHECK_ERROR0;
13233             if (op->ch2 != -1) {
13234         ctxt->context->doc = bakd;
13235         ctxt->context->node = bak;
13236         ctxt->context->proximityPosition = pp;
13237         ctxt->context->contextSize = cs;
13238                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239         }
13240         CHECK_ERROR0;
13241             if (op->value == 0)
13242                 xmlXPathSubValues(ctxt);
13243             else if (op->value == 1)
13244                 xmlXPathAddValues(ctxt);
13245             else if (op->value == 2)
13246                 xmlXPathValueFlipSign(ctxt);
13247             else if (op->value == 3) {
13248                 CAST_TO_NUMBER;
13249                 CHECK_TYPE0(XPATH_NUMBER);
13250             }
13251             return (total);
13252         case XPATH_OP_MULT:
13253         bakd = ctxt->context->doc;
13254         bak = ctxt->context->node;
13255         pp = ctxt->context->proximityPosition;
13256         cs = ctxt->context->contextSize;
13257             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13258         CHECK_ERROR0;
13259         ctxt->context->doc = bakd;
13260         ctxt->context->node = bak;
13261         ctxt->context->proximityPosition = pp;
13262         ctxt->context->contextSize = cs;
13263             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13264         CHECK_ERROR0;
13265             if (op->value == 0)
13266                 xmlXPathMultValues(ctxt);
13267             else if (op->value == 1)
13268                 xmlXPathDivValues(ctxt);
13269             else if (op->value == 2)
13270                 xmlXPathModValues(ctxt);
13271             return (total);
13272         case XPATH_OP_UNION:
13273         bakd = ctxt->context->doc;
13274         bak = ctxt->context->node;
13275         pp = ctxt->context->proximityPosition;
13276         cs = ctxt->context->contextSize;
13277             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13278         CHECK_ERROR0;
13279         ctxt->context->doc = bakd;
13280         ctxt->context->node = bak;
13281         ctxt->context->proximityPosition = pp;
13282         ctxt->context->contextSize = cs;
13283             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13284         CHECK_ERROR0;
13285             CHECK_TYPE0(XPATH_NODESET);
13286             arg2 = valuePop(ctxt);
13287 
13288             CHECK_TYPE0(XPATH_NODESET);
13289             arg1 = valuePop(ctxt);
13290 
13291         if ((arg1->nodesetval == NULL) ||
13292         ((arg2->nodesetval != NULL) &&
13293          (arg2->nodesetval->nodeNr != 0)))
13294         {
13295         arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13296                             arg2->nodesetval);
13297         }
13298 
13299             valuePush(ctxt, arg1);
13300         xmlXPathReleaseObject(ctxt->context, arg2);
13301             return (total);
13302         case XPATH_OP_ROOT:
13303             xmlXPathRoot(ctxt);
13304             return (total);
13305         case XPATH_OP_NODE:
13306             if (op->ch1 != -1)
13307                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13308         CHECK_ERROR0;
13309             if (op->ch2 != -1)
13310                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13311         CHECK_ERROR0;
13312         valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13313         ctxt->context->node));
13314             return (total);
13315         case XPATH_OP_RESET:
13316             if (op->ch1 != -1)
13317                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13318         CHECK_ERROR0;
13319             if (op->ch2 != -1)
13320                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321         CHECK_ERROR0;
13322             ctxt->context->node = NULL;
13323             return (total);
13324         case XPATH_OP_COLLECT:{
13325                 if (op->ch1 == -1)
13326                     return (total);
13327 
13328                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329         CHECK_ERROR0;
13330 
13331                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13332                 return (total);
13333             }
13334         case XPATH_OP_VALUE:
13335             valuePush(ctxt,
13336                       xmlXPathCacheObjectCopy(ctxt->context,
13337             (xmlXPathObjectPtr) op->value4));
13338             return (total);
13339         case XPATH_OP_VARIABLE:{
13340         xmlXPathObjectPtr val;
13341 
13342                 if (op->ch1 != -1)
13343                     total +=
13344                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13345                 if (op->value5 == NULL) {
13346             val = xmlXPathVariableLookup(ctxt->context, op->value4);
13347             if (val == NULL) {
13348             ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13349             return(0);
13350             }
13351                     valuePush(ctxt, val);
13352         } else {
13353                     const xmlChar *URI;
13354 
13355                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13356                     if (URI == NULL) {
13357                         xmlGenericError(xmlGenericErrorContext,
13358             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13359                                     (char *) op->value4, (char *)op->value5);
13360                         return (total);
13361                     }
13362             val = xmlXPathVariableLookupNS(ctxt->context,
13363                                                        op->value4, URI);
13364             if (val == NULL) {
13365             ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13366             return(0);
13367             }
13368                     valuePush(ctxt, val);
13369                 }
13370                 return (total);
13371             }
13372         case XPATH_OP_FUNCTION:{
13373                 xmlXPathFunction func;
13374                 const xmlChar *oldFunc, *oldFuncURI;
13375         int i;
13376 
13377                 if (op->ch1 != -1)
13378                     total +=
13379                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380         if (ctxt->valueNr < op->value) {
13381             xmlGenericError(xmlGenericErrorContext,
13382                 "xmlXPathCompOpEval: parameter error\n");
13383             ctxt->error = XPATH_INVALID_OPERAND;
13384             return (total);
13385         }
13386         for (i = 0; i < op->value; i++)
13387             if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13388             xmlGenericError(xmlGenericErrorContext,
13389                 "xmlXPathCompOpEval: parameter error\n");
13390             ctxt->error = XPATH_INVALID_OPERAND;
13391             return (total);
13392             }
13393                 if (op->cache != NULL)
13394                     XML_CAST_FPTR(func) = op->cache;
13395                 else {
13396                     const xmlChar *URI = NULL;
13397 
13398                     if (op->value5 == NULL)
13399                         func =
13400                             xmlXPathFunctionLookup(ctxt->context,
13401                                                    op->value4);
13402                     else {
13403                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13404                         if (URI == NULL) {
13405                             xmlGenericError(xmlGenericErrorContext,
13406             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13407                                     (char *)op->value4, (char *)op->value5);
13408                             return (total);
13409                         }
13410                         func = xmlXPathFunctionLookupNS(ctxt->context,
13411                                                         op->value4, URI);
13412                     }
13413                     if (func == NULL) {
13414                         xmlGenericError(xmlGenericErrorContext,
13415                                 "xmlXPathCompOpEval: function %s not found\n",
13416                                         (char *)op->value4);
13417                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13418                     }
13419                     op->cache = XML_CAST_FPTR(func);
13420                     op->cacheURI = (void *) URI;
13421                 }
13422                 oldFunc = ctxt->context->function;
13423                 oldFuncURI = ctxt->context->functionURI;
13424                 ctxt->context->function = op->value4;
13425                 ctxt->context->functionURI = op->cacheURI;
13426                 func(ctxt, op->value);
13427                 ctxt->context->function = oldFunc;
13428                 ctxt->context->functionURI = oldFuncURI;
13429                 return (total);
13430             }
13431         case XPATH_OP_ARG:
13432         bakd = ctxt->context->doc;
13433         bak = ctxt->context->node;
13434         pp = ctxt->context->proximityPosition;
13435         cs = ctxt->context->contextSize;
13436             if (op->ch1 != -1)
13437                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438         ctxt->context->contextSize = cs;
13439         ctxt->context->proximityPosition = pp;
13440         ctxt->context->node = bak;
13441         ctxt->context->doc = bakd;
13442         CHECK_ERROR0;
13443             if (op->ch2 != -1) {
13444                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13445             ctxt->context->doc = bakd;
13446             ctxt->context->node = bak;
13447             CHECK_ERROR0;
13448         }
13449             return (total);
13450         case XPATH_OP_PREDICATE:
13451         case XPATH_OP_FILTER:{
13452                 xmlXPathObjectPtr res;
13453                 xmlXPathObjectPtr obj, tmp;
13454                 xmlNodeSetPtr newset = NULL;
13455                 xmlNodeSetPtr oldset;
13456                 xmlNodePtr oldnode;
13457         xmlDocPtr oldDoc;
13458                 int i;
13459 
13460                 /*
13461                  * Optimization for ()[1] selection i.e. the first elem
13462                  */
13463                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13464 #ifdef XP_OPTIMIZED_FILTER_FIRST
13465             /*
13466             * FILTER TODO: Can we assume that the inner processing
13467             *  will result in an ordered list if we have an
13468             *  XPATH_OP_FILTER?
13469             *  What about an additional field or flag on
13470             *  xmlXPathObject like @sorted ? This way we wouln'd need
13471             *  to assume anything, so it would be more robust and
13472             *  easier to optimize.
13473             */
13474                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13475              (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13476 #else
13477             (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13478 #endif
13479                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13480                     xmlXPathObjectPtr val;
13481 
13482                     val = comp->steps[op->ch2].value4;
13483                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13484                         (val->floatval == 1.0)) {
13485                         xmlNodePtr first = NULL;
13486 
13487                         total +=
13488                             xmlXPathCompOpEvalFirst(ctxt,
13489                                                     &comp->steps[op->ch1],
13490                                                     &first);
13491             CHECK_ERROR0;
13492                         /*
13493                          * The nodeset should be in document order,
13494                          * Keep only the first value
13495                          */
13496                         if ((ctxt->value != NULL) &&
13497                             (ctxt->value->type == XPATH_NODESET) &&
13498                             (ctxt->value->nodesetval != NULL) &&
13499                             (ctxt->value->nodesetval->nodeNr > 1))
13500                             ctxt->value->nodesetval->nodeNr = 1;
13501                         return (total);
13502                     }
13503                 }
13504                 /*
13505                  * Optimization for ()[last()] selection i.e. the last elem
13506                  */
13507                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13508                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13509                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13510                     int f = comp->steps[op->ch2].ch1;
13511 
13512                     if ((f != -1) &&
13513                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13514                         (comp->steps[f].value5 == NULL) &&
13515                         (comp->steps[f].value == 0) &&
13516                         (comp->steps[f].value4 != NULL) &&
13517                         (xmlStrEqual
13518                          (comp->steps[f].value4, BAD_CAST "last"))) {
13519                         xmlNodePtr last = NULL;
13520 
13521                         total +=
13522                             xmlXPathCompOpEvalLast(ctxt,
13523                                                    &comp->steps[op->ch1],
13524                                                    &last);
13525             CHECK_ERROR0;
13526                         /*
13527                          * The nodeset should be in document order,
13528                          * Keep only the last value
13529                          */
13530                         if ((ctxt->value != NULL) &&
13531                             (ctxt->value->type == XPATH_NODESET) &&
13532                             (ctxt->value->nodesetval != NULL) &&
13533                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13534                             (ctxt->value->nodesetval->nodeNr > 1)) {
13535                             ctxt->value->nodesetval->nodeTab[0] =
13536                                 ctxt->value->nodesetval->nodeTab[ctxt->
13537                                                                  value->
13538                                                                  nodesetval->
13539                                                                  nodeNr -
13540                                                                  1];
13541                             ctxt->value->nodesetval->nodeNr = 1;
13542                         }
13543                         return (total);
13544                     }
13545                 }
13546         /*
13547         * Process inner predicates first.
13548         * Example "index[parent::book][1]":
13549         * ...
13550         *   PREDICATE   <-- we are here "[1]"
13551         *     PREDICATE <-- process "[parent::book]" first
13552         *       SORT
13553         *         COLLECT  'parent' 'name' 'node' book
13554         *           NODE
13555         *     ELEM Object is a number : 1
13556         */
13557                 if (op->ch1 != -1)
13558                     total +=
13559                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13560         CHECK_ERROR0;
13561                 if (op->ch2 == -1)
13562                     return (total);
13563                 if (ctxt->value == NULL)
13564                     return (total);
13565 
13566                 oldnode = ctxt->context->node;
13567 
13568 #ifdef LIBXML_XPTR_ENABLED
13569                 /*
13570                  * Hum are we filtering the result of an XPointer expression
13571                  */
13572                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13573                     xmlLocationSetPtr newlocset = NULL;
13574                     xmlLocationSetPtr oldlocset;
13575 
13576                     /*
13577                      * Extract the old locset, and then evaluate the result of the
13578                      * expression for all the element in the locset. use it to grow
13579                      * up a new locset.
13580                      */
13581                     CHECK_TYPE0(XPATH_LOCATIONSET);
13582                     obj = valuePop(ctxt);
13583                     oldlocset = obj->user;
13584                     ctxt->context->node = NULL;
13585 
13586                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13587                         ctxt->context->contextSize = 0;
13588                         ctxt->context->proximityPosition = 0;
13589                         if (op->ch2 != -1)
13590                             total +=
13591                                 xmlXPathCompOpEval(ctxt,
13592                                                    &comp->steps[op->ch2]);
13593                         res = valuePop(ctxt);
13594                         if (res != NULL) {
13595                 xmlXPathReleaseObject(ctxt->context, res);
13596             }
13597                         valuePush(ctxt, obj);
13598                         CHECK_ERROR0;
13599                         return (total);
13600                     }
13601                     newlocset = xmlXPtrLocationSetCreate(NULL);
13602 
13603                     for (i = 0; i < oldlocset->locNr; i++) {
13604                         /*
13605                          * Run the evaluation with a node list made of a
13606                          * single item in the nodelocset.
13607                          */
13608                         ctxt->context->node = oldlocset->locTab[i]->user;
13609                         ctxt->context->contextSize = oldlocset->locNr;
13610                         ctxt->context->proximityPosition = i + 1;
13611             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13612                 ctxt->context->node);
13613                         valuePush(ctxt, tmp);
13614 
13615                         if (op->ch2 != -1)
13616                             total +=
13617                                 xmlXPathCompOpEval(ctxt,
13618                                                    &comp->steps[op->ch2]);
13619             if (ctxt->error != XPATH_EXPRESSION_OK) {
13620                 xmlXPathFreeObject(obj);
13621                 return(0);
13622             }
13623 
13624                         /*
13625                          * The result of the evaluation need to be tested to
13626                          * decided whether the filter succeeded or not
13627                          */
13628                         res = valuePop(ctxt);
13629                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13630                             xmlXPtrLocationSetAdd(newlocset,
13631                                                   xmlXPathObjectCopy
13632                                                   (oldlocset->locTab[i]));
13633                         }
13634 
13635                         /*
13636                          * Cleanup
13637                          */
13638                         if (res != NULL) {
13639                 xmlXPathReleaseObject(ctxt->context, res);
13640             }
13641                         if (ctxt->value == tmp) {
13642                             res = valuePop(ctxt);
13643                 xmlXPathReleaseObject(ctxt->context, res);
13644                         }
13645 
13646                         ctxt->context->node = NULL;
13647                     }
13648 
13649                     /*
13650                      * The result is used as the new evaluation locset.
13651                      */
13652             xmlXPathReleaseObject(ctxt->context, obj);
13653                     ctxt->context->node = NULL;
13654                     ctxt->context->contextSize = -1;
13655                     ctxt->context->proximityPosition = -1;
13656                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13657                     ctxt->context->node = oldnode;
13658                     return (total);
13659                 }
13660 #endif /* LIBXML_XPTR_ENABLED */
13661 
13662                 /*
13663                  * Extract the old set, and then evaluate the result of the
13664                  * expression for all the element in the set. use it to grow
13665                  * up a new set.
13666                  */
13667                 CHECK_TYPE0(XPATH_NODESET);
13668                 obj = valuePop(ctxt);
13669                 oldset = obj->nodesetval;
13670 
13671                 oldnode = ctxt->context->node;
13672         oldDoc = ctxt->context->doc;
13673                 ctxt->context->node = NULL;
13674 
13675                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13676                     ctxt->context->contextSize = 0;
13677                     ctxt->context->proximityPosition = 0;
13678 /*
13679                     if (op->ch2 != -1)
13680                         total +=
13681                             xmlXPathCompOpEval(ctxt,
13682                                                &comp->steps[op->ch2]);
13683             CHECK_ERROR0;
13684                     res = valuePop(ctxt);
13685                     if (res != NULL)
13686                         xmlXPathFreeObject(res);
13687 */
13688                     valuePush(ctxt, obj);
13689                     ctxt->context->node = oldnode;
13690                     CHECK_ERROR0;
13691                 } else {
13692             tmp = NULL;
13693                     /*
13694                      * Initialize the new set.
13695              * Also set the xpath document in case things like
13696              * key() evaluation are attempted on the predicate
13697                      */
13698                     newset = xmlXPathNodeSetCreate(NULL);
13699             /*
13700             * SPEC XPath 1.0:
13701             *  "For each node in the node-set to be filtered, the
13702             *  PredicateExpr is evaluated with that node as the
13703             *  context node, with the number of nodes in the
13704             *  node-set as the context size, and with the proximity
13705             *  position of the node in the node-set with respect to
13706             *  the axis as the context position;"
13707             * @oldset is the node-set" to be filtered.
13708             *
13709             * SPEC XPath 1.0:
13710             *  "only predicates change the context position and
13711             *  context size (see [2.4 Predicates])."
13712             * Example:
13713             *   node-set  context pos
13714             *    nA         1
13715             *    nB         2
13716             *    nC         3
13717             *   After applying predicate [position() > 1] :
13718             *   node-set  context pos
13719             *    nB         1
13720             *    nC         2
13721             *
13722             * removed the first node in the node-set, then
13723             * the context position of the
13724             */
13725                     for (i = 0; i < oldset->nodeNr; i++) {
13726                         /*
13727                          * Run the evaluation with a node list made of
13728                          * a single item in the nodeset.
13729                          */
13730                         ctxt->context->node = oldset->nodeTab[i];
13731             if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13732                 (oldset->nodeTab[i]->doc != NULL))
13733                     ctxt->context->doc = oldset->nodeTab[i]->doc;
13734             if (tmp == NULL) {
13735                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13736                 ctxt->context->node);
13737             } else {
13738                 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13739                 ctxt->context->node);
13740             }
13741                         valuePush(ctxt, tmp);
13742                         ctxt->context->contextSize = oldset->nodeNr;
13743                         ctxt->context->proximityPosition = i + 1;
13744             /*
13745             * Evaluate the predicate against the context node.
13746             * Can/should we optimize position() predicates
13747             * here (e.g. "[1]")?
13748             */
13749                         if (op->ch2 != -1)
13750                             total +=
13751                                 xmlXPathCompOpEval(ctxt,
13752                                                    &comp->steps[op->ch2]);
13753             if (ctxt->error != XPATH_EXPRESSION_OK) {
13754                 xmlXPathFreeNodeSet(newset);
13755                 xmlXPathFreeObject(obj);
13756                 return(0);
13757             }
13758 
13759                         /*
13760                          * The result of the evaluation needs to be tested to
13761                          * decide whether the filter succeeded or not
13762                          */
13763             /*
13764             * OPTIMIZE TODO: Can we use
13765             * xmlXPathNodeSetAdd*Unique()* instead?
13766             */
13767                         res = valuePop(ctxt);
13768                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13769                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13770                         }
13771 
13772                         /*
13773                          * Cleanup
13774                          */
13775                         if (res != NULL) {
13776                 xmlXPathReleaseObject(ctxt->context, res);
13777             }
13778                         if (ctxt->value == tmp) {
13779                             valuePop(ctxt);
13780                 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13781                 /*
13782                 * Don't free the temporary nodeset
13783                 * in order to avoid massive recreation inside this
13784                 * loop.
13785                 */
13786                         } else
13787                 tmp = NULL;
13788                         ctxt->context->node = NULL;
13789                     }
13790             if (tmp != NULL)
13791             xmlXPathReleaseObject(ctxt->context, tmp);
13792                     /*
13793                      * The result is used as the new evaluation set.
13794                      */
13795             xmlXPathReleaseObject(ctxt->context, obj);
13796                     ctxt->context->node = NULL;
13797                     ctxt->context->contextSize = -1;
13798                     ctxt->context->proximityPosition = -1;
13799             /* may want to move this past the '}' later */
13800             ctxt->context->doc = oldDoc;
13801             valuePush(ctxt,
13802             xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13803                 }
13804                 ctxt->context->node = oldnode;
13805                 return (total);
13806             }
13807         case XPATH_OP_SORT:
13808             if (op->ch1 != -1)
13809                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13810         CHECK_ERROR0;
13811             if ((ctxt->value != NULL) &&
13812                 (ctxt->value->type == XPATH_NODESET) &&
13813                 (ctxt->value->nodesetval != NULL) &&
13814         (ctxt->value->nodesetval->nodeNr > 1))
13815         {
13816                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13817         }
13818             return (total);
13819 #ifdef LIBXML_XPTR_ENABLED
13820         case XPATH_OP_RANGETO:{
13821                 xmlXPathObjectPtr range;
13822                 xmlXPathObjectPtr res, obj;
13823                 xmlXPathObjectPtr tmp;
13824                 xmlLocationSetPtr newlocset = NULL;
13825             xmlLocationSetPtr oldlocset;
13826                 xmlNodeSetPtr oldset;
13827                 int i, j;
13828 
13829                 if (op->ch1 != -1)
13830                     total +=
13831                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13832                 if (op->ch2 == -1)
13833                     return (total);
13834 
13835                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836                     /*
13837                      * Extract the old locset, and then evaluate the result of the
13838                      * expression for all the element in the locset. use it to grow
13839                      * up a new locset.
13840                      */
13841                     CHECK_TYPE0(XPATH_LOCATIONSET);
13842                     obj = valuePop(ctxt);
13843                     oldlocset = obj->user;
13844 
13845                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13846                 ctxt->context->node = NULL;
13847                         ctxt->context->contextSize = 0;
13848                         ctxt->context->proximityPosition = 0;
13849                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13850                         res = valuePop(ctxt);
13851                         if (res != NULL) {
13852                 xmlXPathReleaseObject(ctxt->context, res);
13853             }
13854                         valuePush(ctxt, obj);
13855                         CHECK_ERROR0;
13856                         return (total);
13857                     }
13858                     newlocset = xmlXPtrLocationSetCreate(NULL);
13859 
13860                     for (i = 0; i < oldlocset->locNr; i++) {
13861                         /*
13862                          * Run the evaluation with a node list made of a
13863                          * single item in the nodelocset.
13864                          */
13865                         ctxt->context->node = oldlocset->locTab[i]->user;
13866                         ctxt->context->contextSize = oldlocset->locNr;
13867                         ctxt->context->proximityPosition = i + 1;
13868             tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13869                 ctxt->context->node);
13870                         valuePush(ctxt, tmp);
13871 
13872                         if (op->ch2 != -1)
13873                             total +=
13874                                 xmlXPathCompOpEval(ctxt,
13875                                                    &comp->steps[op->ch2]);
13876             if (ctxt->error != XPATH_EXPRESSION_OK) {
13877                 xmlXPathFreeObject(obj);
13878                 return(0);
13879             }
13880 
13881                         res = valuePop(ctxt);
13882             if (res->type == XPATH_LOCATIONSET) {
13883                 xmlLocationSetPtr rloc =
13884                     (xmlLocationSetPtr)res->user;
13885                 for (j=0; j<rloc->locNr; j++) {
13886                     range = xmlXPtrNewRange(
13887                   oldlocset->locTab[i]->user,
13888                   oldlocset->locTab[i]->index,
13889                   rloc->locTab[j]->user2,
13890                   rloc->locTab[j]->index2);
13891                 if (range != NULL) {
13892                     xmlXPtrLocationSetAdd(newlocset, range);
13893                 }
13894                 }
13895             } else {
13896                 range = xmlXPtrNewRangeNodeObject(
13897                 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13898                             if (range != NULL) {
13899                                 xmlXPtrLocationSetAdd(newlocset,range);
13900                 }
13901                         }
13902 
13903                         /*
13904                          * Cleanup
13905                          */
13906                         if (res != NULL) {
13907                 xmlXPathReleaseObject(ctxt->context, res);
13908             }
13909                         if (ctxt->value == tmp) {
13910                             res = valuePop(ctxt);
13911                 xmlXPathReleaseObject(ctxt->context, res);
13912                         }
13913 
13914                         ctxt->context->node = NULL;
13915                     }
13916         } else {    /* Not a location set */
13917                     CHECK_TYPE0(XPATH_NODESET);
13918                     obj = valuePop(ctxt);
13919                     oldset = obj->nodesetval;
13920                     ctxt->context->node = NULL;
13921 
13922                     newlocset = xmlXPtrLocationSetCreate(NULL);
13923 
13924                     if (oldset != NULL) {
13925                         for (i = 0; i < oldset->nodeNr; i++) {
13926                             /*
13927                              * Run the evaluation with a node list made of a single item
13928                              * in the nodeset.
13929                              */
13930                             ctxt->context->node = oldset->nodeTab[i];
13931                 /*
13932                 * OPTIMIZE TODO: Avoid recreation for every iteration.
13933                 */
13934                 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13935                 ctxt->context->node);
13936                             valuePush(ctxt, tmp);
13937 
13938                             if (op->ch2 != -1)
13939                                 total +=
13940                                     xmlXPathCompOpEval(ctxt,
13941                                                    &comp->steps[op->ch2]);
13942                 if (ctxt->error != XPATH_EXPRESSION_OK) {
13943                 xmlXPathFreeObject(obj);
13944                 return(0);
13945                 }
13946 
13947                             res = valuePop(ctxt);
13948                             range =
13949                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13950                                                       res);
13951                             if (range != NULL) {
13952                                 xmlXPtrLocationSetAdd(newlocset, range);
13953                             }
13954 
13955                             /*
13956                              * Cleanup
13957                              */
13958                             if (res != NULL) {
13959                 xmlXPathReleaseObject(ctxt->context, res);
13960                 }
13961                             if (ctxt->value == tmp) {
13962                                 res = valuePop(ctxt);
13963                 xmlXPathReleaseObject(ctxt->context, res);
13964                             }
13965 
13966                             ctxt->context->node = NULL;
13967                         }
13968                     }
13969                 }
13970 
13971                 /*
13972                  * The result is used as the new evaluation set.
13973                  */
13974         xmlXPathReleaseObject(ctxt->context, obj);
13975                 ctxt->context->node = NULL;
13976                 ctxt->context->contextSize = -1;
13977                 ctxt->context->proximityPosition = -1;
13978                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13979                 return (total);
13980             }
13981 #endif /* LIBXML_XPTR_ENABLED */
13982     }
13983     xmlGenericError(xmlGenericErrorContext,
13984                     "XPath: unknown precompiled operation %d\n", op->op);
13985     return (total);
13986 }
13987 
13996 static int
13997 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13998                 xmlXPathStepOpPtr op,
13999                 int isPredicate)
14000 {
14001     xmlXPathObjectPtr resObj = NULL;
14002 
14003 start:
14004     /* comp = ctxt->comp; */
14005     switch (op->op) {
14006         case XPATH_OP_END:
14007             return (0);
14008     case XPATH_OP_VALUE:
14009         resObj = (xmlXPathObjectPtr) op->value4;
14010         if (isPredicate)
14011         return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14012         return(xmlXPathCastToBoolean(resObj));
14013     case XPATH_OP_SORT:
14014         /*
14015         * We don't need sorting for boolean results. Skip this one.
14016         */
14017             if (op->ch1 != -1) {
14018         op = &ctxt->comp->steps[op->ch1];
14019         goto start;
14020         }
14021         return(0);
14022     case XPATH_OP_COLLECT:
14023         if (op->ch1 == -1)
14024         return(0);
14025 
14026             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14027         if (ctxt->error != XPATH_EXPRESSION_OK)
14028         return(-1);
14029 
14030             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14031         if (ctxt->error != XPATH_EXPRESSION_OK)
14032         return(-1);
14033 
14034         resObj = valuePop(ctxt);
14035         if (resObj == NULL)
14036         return(-1);
14037         break;
14038     default:
14039         /*
14040         * Fallback to call xmlXPathCompOpEval().
14041         */
14042         xmlXPathCompOpEval(ctxt, op);
14043         if (ctxt->error != XPATH_EXPRESSION_OK)
14044         return(-1);
14045 
14046         resObj = valuePop(ctxt);
14047         if (resObj == NULL)
14048         return(-1);
14049         break;
14050     }
14051 
14052     if (resObj) {
14053     int res;
14054 
14055     if (resObj->type == XPATH_BOOLEAN) {
14056         res = resObj->boolval;
14057     } else if (isPredicate) {
14058         /*
14059         * For predicates a result of type "number" is handled
14060         * differently:
14061         * SPEC XPath 1.0:
14062         * "If the result is a number, the result will be converted
14063         *  to true if the number is equal to the context position
14064         *  and will be converted to false otherwise;"
14065         */
14066         res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14067     } else {
14068         res = xmlXPathCastToBoolean(resObj);
14069     }
14070     xmlXPathReleaseObject(ctxt->context, resObj);
14071     return(res);
14072     }
14073 
14074     return(0);
14075 }
14076 
14077 #ifdef XPATH_STREAMING
14078 
14084 static int
14085 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14086               xmlXPathObjectPtr *resultSeq, int toBool)
14087 {
14088     int max_depth, min_depth;
14089     int from_root;
14090     int ret, depth;
14091     int eval_all_nodes;
14092     xmlNodePtr cur = NULL, limit = NULL;
14093     xmlStreamCtxtPtr patstream = NULL;
14094 
14095     int nb_nodes = 0;
14096 
14097     if ((ctxt == NULL) || (comp == NULL))
14098         return(-1);
14099     max_depth = xmlPatternMaxDepth(comp);
14100     if (max_depth == -1)
14101         return(-1);
14102     if (max_depth == -2)
14103         max_depth = 10000;
14104     min_depth = xmlPatternMinDepth(comp);
14105     if (min_depth == -1)
14106         return(-1);
14107     from_root = xmlPatternFromRoot(comp);
14108     if (from_root < 0)
14109         return(-1);
14110 #if 0
14111     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14112 #endif
14113 
14114     if (! toBool) {
14115     if (resultSeq == NULL)
14116         return(-1);
14117     *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14118     if (*resultSeq == NULL)
14119         return(-1);
14120     }
14121 
14122     /*
14123      * handle the special cases of "/" amd "." being matched
14124      */
14125     if (min_depth == 0) {
14126     if (from_root) {
14127         /* Select "/" */
14128         if (toBool)
14129         return(1);
14130         xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14131         (xmlNodePtr) ctxt->doc);
14132     } else {
14133         /* Select "self::node()" */
14134         if (toBool)
14135         return(1);
14136         xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14137     }
14138     }
14139     if (max_depth == 0) {
14140     return(0);
14141     }
14142 
14143     if (from_root) {
14144         cur = (xmlNodePtr)ctxt->doc;
14145     } else if (ctxt->node != NULL) {
14146         switch (ctxt->node->type) {
14147             case XML_ELEMENT_NODE:
14148             case XML_DOCUMENT_NODE:
14149             case XML_DOCUMENT_FRAG_NODE:
14150             case XML_HTML_DOCUMENT_NODE:
14151 #ifdef LIBXML_DOCB_ENABLED
14152             case XML_DOCB_DOCUMENT_NODE:
14153 #endif
14154             cur = ctxt->node;
14155         break;
14156             case XML_ATTRIBUTE_NODE:
14157             case XML_TEXT_NODE:
14158             case XML_CDATA_SECTION_NODE:
14159             case XML_ENTITY_REF_NODE:
14160             case XML_ENTITY_NODE:
14161             case XML_PI_NODE:
14162             case XML_COMMENT_NODE:
14163             case XML_NOTATION_NODE:
14164             case XML_DTD_NODE:
14165             case XML_DOCUMENT_TYPE_NODE:
14166             case XML_ELEMENT_DECL:
14167             case XML_ATTRIBUTE_DECL:
14168             case XML_ENTITY_DECL:
14169             case XML_NAMESPACE_DECL:
14170             case XML_XINCLUDE_START:
14171             case XML_XINCLUDE_END:
14172         break;
14173     }
14174     limit = cur;
14175     }
14176     if (cur == NULL) {
14177         return(0);
14178     }
14179 
14180     patstream = xmlPatternGetStreamCtxt(comp);
14181     if (patstream == NULL) {
14182     /*
14183     * QUESTION TODO: Is this an error?
14184     */
14185     return(0);
14186     }
14187 
14188     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14189 
14190     if (from_root) {
14191     ret = xmlStreamPush(patstream, NULL, NULL);
14192     if (ret < 0) {
14193     } else if (ret == 1) {
14194         if (toBool)
14195         goto return_1;
14196         xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14197     }
14198     }
14199     depth = 0;
14200     goto scan_children;
14201 next_node:
14202     do {
14203         nb_nodes++;
14204 
14205     switch (cur->type) {
14206         case XML_ELEMENT_NODE:
14207         case XML_TEXT_NODE:
14208         case XML_CDATA_SECTION_NODE:
14209         case XML_COMMENT_NODE:
14210         case XML_PI_NODE:
14211         if (cur->type == XML_ELEMENT_NODE) {
14212             ret = xmlStreamPush(patstream, cur->name,
14213                 (cur->ns ? cur->ns->href : NULL));
14214         } else if (eval_all_nodes)
14215             ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14216         else
14217             break;
14218 
14219         if (ret < 0) {
14220             /* NOP. */
14221         } else if (ret == 1) {
14222             if (toBool)
14223             goto return_1;
14224             xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14225         }
14226         if ((cur->children == NULL) || (depth >= max_depth)) {
14227             ret = xmlStreamPop(patstream);
14228             while (cur->next != NULL) {
14229             cur = cur->next;
14230             if ((cur->type != XML_ENTITY_DECL) &&
14231                 (cur->type != XML_DTD_NODE))
14232                 goto next_node;
14233             }
14234         }
14235         default:
14236         break;
14237     }
14238 
14239 scan_children:
14240     if ((cur->children != NULL) && (depth < max_depth)) {
14241         /*
14242          * Do not descend on entities declarations
14243          */
14244         if (cur->children->type != XML_ENTITY_DECL) {
14245         cur = cur->children;
14246         depth++;
14247         /*
14248          * Skip DTDs
14249          */
14250         if (cur->type != XML_DTD_NODE)
14251             continue;
14252         }
14253     }
14254 
14255     if (cur == limit)
14256         break;
14257 
14258     while (cur->next != NULL) {
14259         cur = cur->next;
14260         if ((cur->type != XML_ENTITY_DECL) &&
14261         (cur->type != XML_DTD_NODE))
14262         goto next_node;
14263     }
14264 
14265     do {
14266         cur = cur->parent;
14267         depth--;
14268         if ((cur == NULL) || (cur == limit))
14269             goto done;
14270         if (cur->type == XML_ELEMENT_NODE) {
14271         ret = xmlStreamPop(patstream);
14272         } else if ((eval_all_nodes) &&
14273         ((cur->type == XML_TEXT_NODE) ||
14274          (cur->type == XML_CDATA_SECTION_NODE) ||
14275          (cur->type == XML_COMMENT_NODE) ||
14276          (cur->type == XML_PI_NODE)))
14277         {
14278         ret = xmlStreamPop(patstream);
14279         }
14280         if (cur->next != NULL) {
14281         cur = cur->next;
14282         break;
14283         }
14284     } while (cur != NULL);
14285 
14286     } while ((cur != NULL) && (depth >= 0));
14287 
14288 done:
14289 
14290 #if 0
14291     printf("stream eval: checked %d nodes selected %d\n",
14292            nb_nodes, retObj->nodesetval->nodeNr);
14293 #endif
14294 
14295     if (patstream)
14296     xmlFreeStreamCtxt(patstream);
14297     return(0);
14298 
14299 return_1:
14300     if (patstream)
14301     xmlFreeStreamCtxt(patstream);
14302     return(1);
14303 }
14304 #endif /* XPATH_STREAMING */
14305 
14313 static int
14314 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14315 {
14316     xmlXPathCompExprPtr comp;
14317 
14318     if ((ctxt == NULL) || (ctxt->comp == NULL))
14319     return(-1);
14320 
14321     if (ctxt->valueTab == NULL) {
14322     /* Allocate the value stack */
14323     ctxt->valueTab = (xmlXPathObjectPtr *)
14324              xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14325     if (ctxt->valueTab == NULL) {
14326         xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14327         xmlFree(ctxt);
14328     }
14329     ctxt->valueNr = 0;
14330     ctxt->valueMax = 10;
14331     ctxt->value = NULL;
14332     }
14333 #ifdef XPATH_STREAMING
14334     if (ctxt->comp->stream) {
14335     int res;
14336 
14337     if (toBool) {
14338         /*
14339         * Evaluation to boolean result.
14340         */
14341         res = xmlXPathRunStreamEval(ctxt->context,
14342         ctxt->comp->stream, NULL, 1);
14343         if (res != -1)
14344         return(res);
14345     } else {
14346         xmlXPathObjectPtr resObj = NULL;
14347 
14348         /*
14349         * Evaluation to a sequence.
14350         */
14351         res = xmlXPathRunStreamEval(ctxt->context,
14352         ctxt->comp->stream, &resObj, 0);
14353 
14354         if ((res != -1) && (resObj != NULL)) {
14355         valuePush(ctxt, resObj);
14356         return(0);
14357         }
14358         if (resObj != NULL)
14359         xmlXPathReleaseObject(ctxt->context, resObj);
14360     }
14361     /*
14362     * QUESTION TODO: This falls back to normal XPath evaluation
14363     * if res == -1. Is this intended?
14364     */
14365     }
14366 #endif
14367     comp = ctxt->comp;
14368     if (comp->last < 0) {
14369     xmlGenericError(xmlGenericErrorContext,
14370         "xmlXPathRunEval: last is less than zero\n");
14371     return(-1);
14372     }
14373     if (toBool)
14374     return(xmlXPathCompOpEvalToBoolean(ctxt,
14375         &comp->steps[comp->last], 0));
14376     else
14377     xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14378 
14379     return(0);
14380 }
14381 
14382 /************************************************************************
14383  *                                  *
14384  *          Public interfaces               *
14385  *                                  *
14386  ************************************************************************/
14387 
14404 int
14405 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14406     if ((ctxt == NULL) || (res == NULL)) return(0);
14407     switch (res->type) {
14408         case XPATH_BOOLEAN:
14409         return(res->boolval);
14410         case XPATH_NUMBER:
14411         return(res->floatval == ctxt->proximityPosition);
14412         case XPATH_NODESET:
14413         case XPATH_XSLT_TREE:
14414         if (res->nodesetval == NULL)
14415         return(0);
14416         return(res->nodesetval->nodeNr != 0);
14417         case XPATH_STRING:
14418         return((res->stringval != NULL) &&
14419                (xmlStrlen(res->stringval) != 0));
14420         default:
14421         STRANGE
14422     }
14423     return(0);
14424 }
14425 
14442 int
14443 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14444                                 xmlXPathObjectPtr res) {
14445     if ((ctxt == NULL) || (res == NULL)) return(0);
14446     switch (res->type) {
14447         case XPATH_BOOLEAN:
14448         return(res->boolval);
14449         case XPATH_NUMBER:
14450 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14451         return((res->floatval == ctxt->context->proximityPosition) &&
14452                (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14453 #else
14454         return(res->floatval == ctxt->context->proximityPosition);
14455 #endif
14456         case XPATH_NODESET:
14457         case XPATH_XSLT_TREE:
14458         if (res->nodesetval == NULL)
14459         return(0);
14460         return(res->nodesetval->nodeNr != 0);
14461         case XPATH_STRING:
14462         return((res->stringval != NULL) && (res->stringval[0] != 0));
14463 #ifdef LIBXML_XPTR_ENABLED
14464     case XPATH_LOCATIONSET:{
14465         xmlLocationSetPtr ptr = res->user;
14466         if (ptr == NULL)
14467             return(0);
14468         return (ptr->locNr != 0);
14469         }
14470 #endif
14471         default:
14472         STRANGE
14473     }
14474     return(0);
14475 }
14476 
14477 #ifdef XPATH_STREAMING
14478 
14487 static xmlXPathCompExprPtr
14488 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14489     /*
14490      * Optimization: use streaming patterns when the XPath expression can
14491      * be compiled to a stream lookup
14492      */
14493     xmlPatternPtr stream;
14494     xmlXPathCompExprPtr comp;
14495     xmlDictPtr dict = NULL;
14496     const xmlChar **namespaces = NULL;
14497     xmlNsPtr ns;
14498     int i, j;
14499 
14500     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14501         (!xmlStrchr(str, '@'))) {
14502     const xmlChar *tmp;
14503 
14504     /*
14505      * We don't try to handle expressions using the verbose axis
14506      * specifiers ("::"), just the simplied form at this point.
14507      * Additionally, if there is no list of namespaces available and
14508      *  there's a ":" in the expression, indicating a prefixed QName,
14509      *  then we won't try to compile either. xmlPatterncompile() needs
14510      *  to have a list of namespaces at compilation time in order to
14511      *  compile prefixed name tests.
14512      */
14513     tmp = xmlStrchr(str, ':');
14514     if ((tmp != NULL) &&
14515         ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14516         return(NULL);
14517 
14518     if (ctxt != NULL) {
14519         dict = ctxt->dict;
14520         if (ctxt->nsNr > 0) {
14521         namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14522         if (namespaces == NULL) {
14523             xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14524             return(NULL);
14525         }
14526         for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14527             ns = ctxt->namespaces[j];
14528             namespaces[i++] = ns->href;
14529             namespaces[i++] = ns->prefix;
14530         }
14531         namespaces[i++] = NULL;
14532         namespaces[i] = NULL;
14533         }
14534     }
14535 
14536     stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14537             &namespaces[0]);
14538     if (namespaces != NULL) {
14539         xmlFree((xmlChar **)namespaces);
14540     }
14541     if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14542         comp = xmlXPathNewCompExpr();
14543         if (comp == NULL) {
14544         xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14545         return(NULL);
14546         }
14547         comp->stream = stream;
14548         comp->dict = dict;
14549         if (comp->dict)
14550         xmlDictReference(comp->dict);
14551         return(comp);
14552     }
14553     xmlFreePattern(stream);
14554     }
14555     return(NULL);
14556 }
14557 #endif /* XPATH_STREAMING */
14558 
14559 static int
14560 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14561 {
14562     if (expr == NULL)
14563     return(0);
14564     do {
14565         if ((*expr == '/') && (*(++expr) == '/'))
14566         return(1);
14567     } while (*expr++);
14568     return(0);
14569 }
14570 static void
14571 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14572 {
14573     /*
14574     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14575     * internal representation.
14576     */
14577     if (op->ch1 != -1) {
14578     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14579         ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14580         ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14581         ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14582     {
14583         /*
14584         * This is a "child::foo"
14585         */
14586         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14587 
14588         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14589         (prevop->ch1 != -1) &&
14590         ((xmlXPathAxisVal) prevop->value ==
14591             AXIS_DESCENDANT_OR_SELF) &&
14592         (prevop->ch2 == -1) &&
14593         ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14594         ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14595         (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14596         {
14597         /*
14598         * This is a "/descendant-or-self::node()" without predicates.
14599         * Eliminate it.
14600         */
14601         op->ch1 = prevop->ch1;
14602         op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14603         }
14604     }
14605     if (op->ch1 != -1)
14606         xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14607     }
14608     if (op->ch2 != -1)
14609     xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14610 }
14611 
14622 xmlXPathCompExprPtr
14623 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14624     xmlXPathParserContextPtr pctxt;
14625     xmlXPathCompExprPtr comp;
14626 
14627 #ifdef XPATH_STREAMING
14628     comp = xmlXPathTryStreamCompile(ctxt, str);
14629     if (comp != NULL)
14630         return(comp);
14631 #endif
14632 
14633     xmlXPathInit();
14634 
14635     pctxt = xmlXPathNewParserContext(str, ctxt);
14636     if (pctxt == NULL)
14637         return NULL;
14638     xmlXPathCompileExpr(pctxt, 1);
14639 
14640     if( pctxt->error != XPATH_EXPRESSION_OK )
14641     {
14642         xmlXPathFreeParserContext(pctxt);
14643         return(NULL);
14644     }
14645 
14646     if (*pctxt->cur != 0) {
14647     /*
14648      * aleksey: in some cases this line prints *second* error message
14649      * (see bug #78858) and probably this should be fixed.
14650      * However, we are not sure that all error messages are printed
14651      * out in other places. It's not critical so we leave it as-is for now
14652      */
14653     xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14654     comp = NULL;
14655     } else {
14656     comp = pctxt->comp;
14657     pctxt->comp = NULL;
14658     }
14659     xmlXPathFreeParserContext(pctxt);
14660 
14661     if (comp != NULL) {
14662     comp->expr = xmlStrdup(str);
14663 #ifdef DEBUG_EVAL_COUNTS
14664     comp->string = xmlStrdup(str);
14665     comp->nb = 0;
14666 #endif
14667     if ((comp->expr != NULL) &&
14668         (comp->nbStep > 2) &&
14669         (comp->last >= 0) &&
14670         (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14671     {
14672         xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14673     }
14674     }
14675     return(comp);
14676 }
14677 
14687 xmlXPathCompExprPtr
14688 xmlXPathCompile(const xmlChar *str) {
14689     return(xmlXPathCtxtCompile(NULL, str));
14690 }
14691 
14705 static int
14706 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14707                  xmlXPathContextPtr ctxt,
14708                  xmlXPathObjectPtr *resObj,
14709                  int toBool)
14710 {
14711     xmlXPathParserContextPtr pctxt;
14712 #ifndef LIBXML_THREAD_ENABLED
14713     static int reentance = 0;
14714 #endif
14715     int res;
14716 
14717     CHECK_CTXT_NEG(ctxt)
14718 
14719     if (comp == NULL)
14720     return(-1);
14721     xmlXPathInit();
14722 
14723 #ifndef LIBXML_THREAD_ENABLED
14724     reentance++;
14725     if (reentance > 1)
14726     xmlXPathDisableOptimizer = 1;
14727 #endif
14728 
14729 #ifdef DEBUG_EVAL_COUNTS
14730     comp->nb++;
14731     if ((comp->string != NULL) && (comp->nb > 100)) {
14732     fprintf(stderr, "100 x %s\n", comp->string);
14733     comp->nb = 0;
14734     }
14735 #endif
14736     pctxt = xmlXPathCompParserContext(comp, ctxt);
14737     res = xmlXPathRunEval(pctxt, toBool);
14738 
14739     if (resObj) {
14740     if (pctxt->value == NULL) {
14741         xmlGenericError(xmlGenericErrorContext,
14742         "xmlXPathCompiledEval: evaluation failed\n");
14743         *resObj = NULL;
14744     } else {
14745         *resObj = valuePop(pctxt);
14746     }
14747     }
14748 
14749     /*
14750     * Pop all remaining objects from the stack.
14751     */
14752     if (pctxt->valueNr > 0) {
14753     xmlXPathObjectPtr tmp;
14754     int stack = 0;
14755 
14756     do {
14757         tmp = valuePop(pctxt);
14758         if (tmp != NULL) {
14759         stack++;
14760         xmlXPathReleaseObject(ctxt, tmp);
14761         }
14762     } while (tmp != NULL);
14763     if ((stack != 0) &&
14764         ((toBool) || ((resObj) && (*resObj))))
14765     {
14766         xmlGenericError(xmlGenericErrorContext,
14767         "xmlXPathCompiledEval: %d objects left on the stack.\n",
14768         stack);
14769     }
14770     }
14771 
14772     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14773     xmlXPathFreeObject(*resObj);
14774     *resObj = NULL;
14775     }
14776     pctxt->comp = NULL;
14777     xmlXPathFreeParserContext(pctxt);
14778 #ifndef LIBXML_THREAD_ENABLED
14779     reentance--;
14780 #endif
14781 
14782     return(res);
14783 }
14784 
14795 xmlXPathObjectPtr
14796 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14797 {
14798     xmlXPathObjectPtr res = NULL;
14799 
14800     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14801     return(res);
14802 }
14803 
14815 int
14816 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14817                   xmlXPathContextPtr ctxt)
14818 {
14819     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14820 }
14821 
14829 void
14830 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14831 #ifdef XPATH_STREAMING
14832     xmlXPathCompExprPtr comp;
14833 #endif
14834 
14835     if (ctxt == NULL) return;
14836 
14837 #ifdef XPATH_STREAMING
14838     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14839     if (comp != NULL) {
14840         if (ctxt->comp != NULL)
14841         xmlXPathFreeCompExpr(ctxt->comp);
14842         ctxt->comp = comp;
14843     if (ctxt->cur != NULL)
14844         while (*ctxt->cur != 0) ctxt->cur++;
14845     } else
14846 #endif
14847     {
14848     xmlXPathCompileExpr(ctxt, 1);
14849     /*
14850     * In this scenario the expression string will sit in ctxt->base.
14851     */
14852     if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14853         (ctxt->comp != NULL) &&
14854         (ctxt->base != NULL) &&
14855         (ctxt->comp->nbStep > 2) &&
14856         (ctxt->comp->last >= 0) &&
14857         (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14858     {
14859         xmlXPathRewriteDOSExpression(ctxt->comp,
14860         &ctxt->comp->steps[ctxt->comp->last]);
14861     }
14862     }
14863     CHECK_ERROR;
14864     xmlXPathRunEval(ctxt, 0);
14865 }
14866 
14877 xmlXPathObjectPtr
14878 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14879     xmlXPathParserContextPtr ctxt;
14880     xmlXPathObjectPtr res, tmp, init = NULL;
14881     int stack = 0;
14882 
14883     CHECK_CTXT(ctx)
14884 
14885     xmlXPathInit();
14886 
14887     ctxt = xmlXPathNewParserContext(str, ctx);
14888     if (ctxt == NULL)
14889         return NULL;
14890     xmlXPathEvalExpr(ctxt);
14891 
14892     if (ctxt->value == NULL) {
14893     xmlGenericError(xmlGenericErrorContext,
14894         "xmlXPathEval: evaluation failed\n");
14895     res = NULL;
14896     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14897 #ifdef XPATH_STREAMING
14898             && (ctxt->comp->stream == NULL)
14899 #endif
14900           ) {
14901     xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14902     res = NULL;
14903     } else {
14904     res = valuePop(ctxt);
14905     }
14906 
14907     do {
14908         tmp = valuePop(ctxt);
14909     if (tmp != NULL) {
14910         if (tmp != init)
14911         stack++;
14912         xmlXPathReleaseObject(ctx, tmp);
14913         }
14914     } while (tmp != NULL);
14915     if ((stack != 0) && (res != NULL)) {
14916     xmlGenericError(xmlGenericErrorContext,
14917         "xmlXPathEval: %d object left on the stack\n",
14918             stack);
14919     }
14920     if (ctxt->error != XPATH_EXPRESSION_OK) {
14921     xmlXPathFreeObject(res);
14922     res = NULL;
14923     }
14924 
14925     xmlXPathFreeParserContext(ctxt);
14926     return(res);
14927 }
14928 
14939 xmlXPathObjectPtr
14940 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14941     xmlXPathParserContextPtr pctxt;
14942     xmlXPathObjectPtr res, tmp;
14943     int stack = 0;
14944 
14945     CHECK_CTXT(ctxt)
14946 
14947     xmlXPathInit();
14948 
14949     pctxt = xmlXPathNewParserContext(str, ctxt);
14950     if (pctxt == NULL)
14951         return NULL;
14952     xmlXPathEvalExpr(pctxt);
14953 
14954     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14955     xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14956     res = NULL;
14957     } else {
14958     res = valuePop(pctxt);
14959     }
14960     do {
14961         tmp = valuePop(pctxt);
14962     if (tmp != NULL) {
14963         xmlXPathReleaseObject(ctxt, tmp);
14964         stack++;
14965     }
14966     } while (tmp != NULL);
14967     if ((stack != 0) && (res != NULL)) {
14968     xmlGenericError(xmlGenericErrorContext,
14969         "xmlXPathEvalExpression: %d object left on the stack\n",
14970             stack);
14971     }
14972     xmlXPathFreeParserContext(pctxt);
14973     return(res);
14974 }
14975 
14976 /************************************************************************
14977  *                                  *
14978  *  Extra functions not pertaining to the XPath spec        *
14979  *                                  *
14980  ************************************************************************/
15029 static void
15030 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15031     xmlXPathObjectPtr str;
15032     int escape_reserved;
15033     xmlBufferPtr target;
15034     xmlChar *cptr;
15035     xmlChar escape[4];
15036 
15037     CHECK_ARITY(2);
15038 
15039     escape_reserved = xmlXPathPopBoolean(ctxt);
15040 
15041     CAST_TO_STRING;
15042     str = valuePop(ctxt);
15043 
15044     target = xmlBufferCreate();
15045 
15046     escape[0] = '%';
15047     escape[3] = 0;
15048 
15049     if (target) {
15050     for (cptr = str->stringval; *cptr; cptr++) {
15051         if ((*cptr >= 'A' && *cptr <= 'Z') ||
15052         (*cptr >= 'a' && *cptr <= 'z') ||
15053         (*cptr >= '0' && *cptr <= '9') ||
15054         *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15055         *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15056         *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15057         (*cptr == '%' &&
15058          ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15059           (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15060           (cptr[1] >= '0' && cptr[1] <= '9')) &&
15061          ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15062           (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15063           (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15064         (!escape_reserved &&
15065          (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15066           *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15067           *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15068           *cptr == ','))) {
15069         xmlBufferAdd(target, cptr, 1);
15070         } else {
15071         if ((*cptr >> 4) < 10)
15072             escape[1] = '0' + (*cptr >> 4);
15073         else
15074             escape[1] = 'A' - 10 + (*cptr >> 4);
15075         if ((*cptr & 0xF) < 10)
15076             escape[2] = '0' + (*cptr & 0xF);
15077         else
15078             escape[2] = 'A' - 10 + (*cptr & 0xF);
15079 
15080         xmlBufferAdd(target, &escape[0], 3);
15081         }
15082     }
15083     }
15084     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15085     xmlBufferContent(target)));
15086     xmlBufferFree(target);
15087     xmlXPathReleaseObject(ctxt->context, str);
15088 }
15089 
15096 void
15097 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15098 {
15099     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15100                          xmlXPathBooleanFunction);
15101     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15102                          xmlXPathCeilingFunction);
15103     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15104                          xmlXPathCountFunction);
15105     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15106                          xmlXPathConcatFunction);
15107     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15108                          xmlXPathContainsFunction);
15109     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15110                          xmlXPathIdFunction);
15111     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15112                          xmlXPathFalseFunction);
15113     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15114                          xmlXPathFloorFunction);
15115     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15116                          xmlXPathLastFunction);
15117     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15118                          xmlXPathLangFunction);
15119     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15120                          xmlXPathLocalNameFunction);
15121     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15122                          xmlXPathNotFunction);
15123     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15124                          xmlXPathNameFunction);
15125     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15126                          xmlXPathNamespaceURIFunction);
15127     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15128                          xmlXPathNormalizeFunction);
15129     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15130                          xmlXPathNumberFunction);
15131     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15132                          xmlXPathPositionFunction);
15133     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15134                          xmlXPathRoundFunction);
15135     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15136                          xmlXPathStringFunction);
15137     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15138                          xmlXPathStringLengthFunction);
15139     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15140                          xmlXPathStartsWithFunction);
15141     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15142                          xmlXPathSubstringFunction);
15143     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15144                          xmlXPathSubstringBeforeFunction);
15145     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15146                          xmlXPathSubstringAfterFunction);
15147     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15148                          xmlXPathSumFunction);
15149     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15150                          xmlXPathTrueFunction);
15151     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15152                          xmlXPathTranslateFunction);
15153 
15154     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15155      (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15156                          xmlXPathEscapeUriFunction);
15157 }
15158 
15159 #endif /* LIBXML_XPATH_ENABLED */
15160 #define bottom_xpath
15161 #include "elfgcchack.h"

Generated on Fri May 25 2012 04:33:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.