webengine/osswebengine/WebCore/platform/symbian/Libxml2/Libxml2_xpath.c
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * xpath.c: XML Path Language implementation
       
     3  *          XPath is a language for addressing parts of an XML document,
       
     4  *          designed to be used by both XSLT and XPointer
       
     5  *
       
     6  * Reference: W3C Recommendation 16 November 1999
       
     7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
       
     8  * Public reference:
       
     9  *     http://www.w3.org/TR/xpath
       
    10  *
       
    11  * See Copyright for the status of this software
       
    12  *
       
    13  * Author: daniel@veillard.com
       
    14  *
       
    15  */
       
    16 
       
    17 #define IN_LIBXML
       
    18 #include "XmlEnglibxml.h"
       
    19 
       
    20 #include <string.h>
       
    21 
       
    22 // TODO: XE Cleanup
       
    23 #ifdef HAVE_SYS_TYPES_H
       
    24 #include <sys/types.h>
       
    25 #endif
       
    26 #ifdef HAVE_MATH_H
       
    27 #include <math.h>
       
    28 #endif
       
    29 #if defined(HAVE_CTYPE_H)
       
    30 #include <ctype.h>
       
    31 #endif
       
    32 #ifdef HAVE_SIGNAL_H
       
    33 #include <signal.h>
       
    34 #endif
       
    35 
       
    36 
       
    37 #include "Libxml2_globals.h"
       
    38 //#include "Libxml2_xmlmemory.h"
       
    39 //#include "Libxml2_xpath.h"
       
    40 //#include "Libxml2_tree.h"
       
    41 //#include "Libxml2_valid.h"
       
    42 #include "Libxml2_xpathInternals.h"
       
    43 #include "Libxml2_parserInternals.h"
       
    44 //#include "Libxml2_hash.h"
       
    45 
       
    46 #ifdef LIBXML_XPTR_ENABLED
       
    47 #include "Libxml2_xpointer.h"
       
    48 #endif
       
    49 
       
    50 #ifdef LIBXML_DEBUG_ENABLED
       
    51 #include <debugXML.h>
       
    52 #endif
       
    53 
       
    54 //#include "Libxml2_xmlerror.h"
       
    55 //#include "Libxml2_threads.h"
       
    56 
       
    57 // TODO: remove/rename TODO
       
    58 #define TODO                                                        \
       
    59     xmlGenericError(xmlGenericErrorContext,                         \
       
    60         EMBED_ERRTXT("Unimplemented block at %s:%d\n"),             \
       
    61             __FILE__, __LINE__);
       
    62 
       
    63 #if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
       
    64 /************************************************************************
       
    65  *                                                                      *
       
    66  *          Floating point stuff                                        *
       
    67  *                                                                      *
       
    68  ************************************************************************/
       
    69 
       
    70 #ifndef TRIO_REPLACE_STDIO
       
    71 //#define TRIO_PUBLIC static
       
    72 #endif
       
    73 #include "Libxml2_trionan.inc"
       
    74 
       
    75 /**
       
    76  * xmlXPathInit:
       
    77  *
       
    78  * Initialize the XPath environment
       
    79  *
       
    80  * OOM: never (so far -- soon hash tables will be created here)
       
    81  */
       
    82 void
       
    83 xmlXPathInit(void) {
       
    84     if (xmlXPathInitialized) return;
       
    85 
       
    86     xmlXPathPINF = trio_pinf();
       
    87     xmlXPathNINF = trio_ninf();
       
    88     xmlXPathNAN = trio_nan();
       
    89     xmlXPathNZERO = trio_nzero();
       
    90 
       
    91     xmlXPathInitialized = 1;
       
    92 
       
    93     // TODO: Register all XPath functions in reusable hash table here
       
    94 }
       
    95 
       
    96 /**
       
    97  * xeXPathCleanup:
       
    98  *
       
    99  * Free any reusable by XPath module resources
       
   100  */
       
   101 void xeXPathCleanup()
       
   102 {
       
   103 #ifdef XMLENGINE_XPATH_FUNC_HASH_OPTIMIZED
       
   104     if (xmlXPathDefaultFunctionsHash)
       
   105         xmlHashFree(xmlXPathDefaultFunctionsHash, NULL);
       
   106     xmlXPathDefaultFunctionsHash = NULL;
       
   107 
       
   108     if (xmlXPathIntermediaryExtensionFunctionsHash)
       
   109         xmlHashFree(xmlXPathIntermediaryExtensionFunctionsHash, NULL);
       
   110     xmlXPathIntermediaryExtensionFunctionsHash = NULL;
       
   111 #endif
       
   112 }
       
   113 
       
   114 // DONE: OPTIMIZE: Define as macro or inliner
       
   115 /**
       
   116  * xmlXPathIsNaN:
       
   117  * @val:  a double value
       
   118  *
       
   119  * Provides a portable isnan() function to detect whether a double
       
   120  * is a NotaNumber. Based on trio code
       
   121  * http://sourceforge.net/projects/ctrio/
       
   122  *
       
   123  * Returns 1 if the value is a NaN, 0 otherwise
       
   124  */
       
   125 /*
       
   126 inline int xmlXPathIsNaN(double val) {
       
   127     return(trio_isnan(val));
       
   128 }*/
       
   129 //#define xmlXPathIsNaN(val) trio_isnan(val)
       
   130 
       
   131 //#define xmlXPathIsNaN(val) trio_isnan(val)
       
   132 
       
   133 // DONE: OPTIMIZE: Define as macro or inliner
       
   134 /**
       
   135  * xmlXPathIsInf:
       
   136  * @val:  a double value
       
   137  *
       
   138  * Provides a portable isinf() function to detect whether a double
       
   139  * is a +Infinite or -Infinite. Based on trio code
       
   140  * http://sourceforge.net/projects/ctrio/
       
   141  *
       
   142  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
       
   143  */
       
   144 /*
       
   145 inline int xmlXPathIsInf(double val) {
       
   146     return(trio_isinf(val));
       
   147 }
       
   148 */
       
   149 #define xmlXPathIsInf(val) trio_isinf(val)
       
   150 
       
   151 #endif /* SCHEMAS or XPATH */
       
   152 
       
   153 
       
   154 #ifdef LIBXML_XPATH_ENABLED
       
   155 
       
   156 
       
   157 // TODO: OPTIMIZE: Define as macro or inliner
       
   158 /**
       
   159  * xmlXPathGetSign:
       
   160  * @val:  a double value
       
   161  *
       
   162  * Provides a portable function to detect the sign of a double
       
   163  * Modified from trio code
       
   164  * http://sourceforge.net/projects/ctrio/
       
   165  *
       
   166  * Returns 1 if the value is Negative, 0 if positive
       
   167  */
       
   168 /*
       
   169 inline int xmlXPathGetSign(double val) {
       
   170     return(trio_signbit(val));
       
   171 }
       
   172 */
       
   173 #define xmlXPathGetSign(val) trio_signbit(val)
       
   174 
       
   175 
       
   176 /*
       
   177  * TODO: when compatibility allows remove all "fake node libxslt" strings
       
   178  *       the test should just be name[0] = ' '
       
   179  */
       
   180 /* #define DEBUG */
       
   181 /* #define DEBUG_STEP */
       
   182 /* #define DEBUG_STEP_NTH */
       
   183 /* #define DEBUG_EXPR */
       
   184 /* #define DEBUG_EVAL_COUNTS */
       
   185 
       
   186 
       
   187 
       
   188 static const xmlNs xmlXPathXMLNamespaceStruct = {
       
   189     NULL,
       
   190     XML_NAMESPACE_DECL,
       
   191     XML_XML_NAMESPACE,
       
   192     BAD_CAST "xml",
       
   193     NULL
       
   194 };
       
   195 static const xmlNsPtr xmlXPathXMLNamespace = (xmlNsPtr)&xmlXPathXMLNamespaceStruct;
       
   196 
       
   197 /************************************************************************
       
   198  *                                                                      *
       
   199  *          Error handling routines                                     *
       
   200  *                                                                      *
       
   201  ************************************************************************/
       
   202 
       
   203 /*
       
   204  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
       
   205  */
       
   206 const char *const xmlXPathErrorMessages[] = {
       
   207     EMBED_ERRTXT("Ok\n"),
       
   208     EMBED_ERRTXT("Number encoding\n"),
       
   209     EMBED_ERRTXT("Unfinished literal\n"),
       
   210     EMBED_ERRTXT("Start of literal\n"),
       
   211     EMBED_ERRTXT("Expected $ for variable reference\n"),
       
   212     EMBED_ERRTXT("Undefined variable\n"),
       
   213     EMBED_ERRTXT("Invalid predicate\n"),
       
   214     EMBED_ERRTXT("Invalid expression\n"),
       
   215     EMBED_ERRTXT("Missing closing curly brace\n"),
       
   216     EMBED_ERRTXT("Unregistered function\n"),
       
   217     EMBED_ERRTXT("Invalid operand\n"),
       
   218     EMBED_ERRTXT("Invalid type\n"),
       
   219     EMBED_ERRTXT("Invalid number of arguments\n"),
       
   220     EMBED_ERRTXT("Invalid context size\n"),
       
   221     EMBED_ERRTXT("Invalid context position\n"),
       
   222     EMBED_ERRTXT("Memory allocation error\n"),
       
   223     EMBED_ERRTXT("Syntax error\n"),
       
   224     EMBED_ERRTXT("Resource error\n"),
       
   225     EMBED_ERRTXT("Sub resource error\n"),
       
   226     EMBED_ERRTXT("Undefined namespace prefix\n"),
       
   227     EMBED_ERRTXT("Encoding error\n"),
       
   228     EMBED_ERRTXT("Char out of XML range\n")
       
   229 };
       
   230 
       
   231 
       
   232 // TODO: OPTIMIZATION: Not required for Symbian
       
   233 /**
       
   234  * xmlXPathErrMemory:
       
   235  * @ctxt:  an XPath context
       
   236  * @extra:  extra informations
       
   237  *
       
   238  * Handle a redefinition of attribute error
       
   239  */
       
   240 static void
       
   241 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
       
   242 {
       
   243     if (ctxt != NULL) {
       
   244         if (extra) {
       
   245             xmlChar buf[200];
       
   246 
       
   247             xmlStrPrintf(buf, 200,
       
   248                   BAD_CAST EMBED_ERRTXT("Memory allocation failed : %s\n"), extra);
       
   249             ctxt->lastError.message = (char *) xmlStrdup(buf);
       
   250         } else {
       
   251             ctxt->lastError.message = (char *)
       
   252                 xmlStrdup(BAD_CAST EMBED_ERRTXT("Memory allocation failed\n"));
       
   253         }
       
   254         ctxt->lastError.domain = XML_FROM_XPATH;
       
   255         ctxt->lastError.code = XML_ERR_NO_MEMORY;
       
   256     if (ctxt->error != NULL)
       
   257         ctxt->error(ctxt->userData, &ctxt->lastError);
       
   258     } else {
       
   259         if (extra)
       
   260             __xmlRaiseError(NULL, NULL, NULL,
       
   261                             NULL, NULL, XML_FROM_XPATH,
       
   262                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
       
   263                             extra, NULL, NULL, 0, 0,
       
   264                             EMBED_ERRTXT("Memory allocation failed : %s\n"), extra);
       
   265         else
       
   266             __xmlRaiseError(NULL, NULL, NULL,
       
   267                             NULL, NULL, XML_FROM_XPATH,
       
   268                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
       
   269                             NULL, NULL, NULL, 0, 0,
       
   270                             EMBED_ERRTXT("Memory allocation failed\n"));
       
   271     }
       
   272 }
       
   273 
       
   274 /**
       
   275  * xmlXPathErrMemory:
       
   276  * @ctxt:  an XPath parser context
       
   277  * @extra:  extra informations
       
   278  *
       
   279  * Handle a redefinition of attribute error
       
   280  */
       
   281 // TODO: Obviously, something wrong here: ctxt!=NULL for sure
       
   282 static void
       
   283 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
       
   284 {
       
   285     ctxt->error = XPATH_MEMORY_ERROR;
       
   286     if (ctxt == NULL)
       
   287         xmlXPathErrMemory(NULL, extra);
       
   288     else
       
   289         xmlXPathErrMemory(ctxt->context, extra);
       
   290 }
       
   291 
       
   292 /**
       
   293  * xmlXPathErr:
       
   294  * @ctxt:  a XPath parser context
       
   295  * @error:  the error code
       
   296  *
       
   297  * Handle a Relax NG Parsing error
       
   298  */
       
   299 void
       
   300 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
       
   301 {
       
   302     // TODO: OPTIMIZE: Combine two (or even all three) IF blocks into one
       
   303     if (ctxt == NULL) {
       
   304         __xmlRaiseError(NULL, NULL, NULL,
       
   305                 NULL, NULL, XML_FROM_XPATH,
       
   306                 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
       
   307                 XML_ERR_ERROR, NULL, 0,
       
   308                 NULL, NULL, NULL, 0, 0,
       
   309                 xmlXPathErrorMessages[error]);
       
   310         return;
       
   311     }
       
   312     ctxt->error = error;
       
   313     if (ctxt->context == NULL) {
       
   314         __xmlRaiseError(NULL, NULL, NULL,
       
   315                 NULL, NULL, XML_FROM_XPATH,
       
   316                 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
       
   317                 XML_ERR_ERROR, NULL, 0,
       
   318                 (const char *) ctxt->base, NULL, NULL,
       
   319                 ctxt->cur - ctxt->base, 0,
       
   320                 xmlXPathErrorMessages[error]);
       
   321         return;
       
   322     }
       
   323     // TODO: OPTIMIZE: make a proxy for lastError
       
   324     ctxt->context->lastError.domain = XML_FROM_XPATH;
       
   325     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
       
   326     ctxt->context->lastError.level = XML_ERR_ERROR;
       
   327     if (ctxt->context->lastError.str1) // agathe added
       
   328         xmlFree(ctxt->context->lastError.str1);
       
   329     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
       
   330     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
       
   331     ctxt->context->lastError.node = ctxt->context->debugNode;
       
   332 
       
   333     if (ctxt->context->error != NULL) {
       
   334         ctxt->context->error(ctxt->context->userData, &ctxt->context->lastError);
       
   335     } else {
       
   336         __xmlRaiseError(NULL, NULL, NULL,
       
   337                 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
       
   338                 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
       
   339                 XML_ERR_ERROR, NULL, 0,
       
   340                 (const char *) ctxt->base, NULL, NULL,
       
   341                 ctxt->cur - ctxt->base, 0,
       
   342                 xmlXPathErrorMessages[error]);
       
   343     }
       
   344 }
       
   345 
       
   346 // DONE: OPTIMIZE: Use macro instead of function call
       
   347 //       Macro added in xpathInternals.h
       
   348 /**
       
   349  * xmlXPatherror:
       
   350  * @ctxt:  the XPath Parser context
       
   351  * @file:  the file name
       
   352  * @line:  the line number
       
   353  * @no:  the error number
       
   354  *
       
   355  * Formats an error message.
       
   356  */
       
   357 //void
       
   358 //xmlXPatherror(xmlXPathParserContextPtr ctxt, const char* file ATTRIBUTE_UNUSED,
       
   359 //              int line ATTRIBUTE_UNUSED , int no)
       
   360 //{
       
   361 //    xmlXPathErr(ctxt, no);
       
   362 //}
       
   363 
       
   364 
       
   365 /************************************************************************
       
   366  *                                                                      *
       
   367  *          Parser Types                                                *
       
   368  *                                                                      *
       
   369  ************************************************************************/
       
   370 
       
   371 /*
       
   372  * Types are private:
       
   373  */
       
   374 typedef enum {
       
   375     AXIS_ANCESTOR = 1,
       
   376     AXIS_ANCESTOR_OR_SELF,
       
   377     AXIS_ATTRIBUTE,
       
   378     AXIS_CHILD,
       
   379     AXIS_DESCENDANT,
       
   380     AXIS_DESCENDANT_OR_SELF,
       
   381     AXIS_FOLLOWING,
       
   382     AXIS_FOLLOWING_SIBLING,
       
   383     AXIS_NAMESPACE,
       
   384     AXIS_PARENT,
       
   385     AXIS_PRECEDING,
       
   386     AXIS_PRECEDING_SIBLING,
       
   387     AXIS_SELF
       
   388 } xmlXPathAxisVal;
       
   389 
       
   390 typedef enum {
       
   391     NODE_TEST_NONE  = 0,
       
   392     NODE_TEST_TYPE  = 1,
       
   393     NODE_TEST_PI    = 2,
       
   394     NODE_TEST_ALL   = 3,
       
   395     NODE_TEST_NS    = 4,
       
   396     NODE_TEST_NAME  = 5
       
   397 } xmlXPathTestVal;
       
   398 
       
   399 typedef enum {
       
   400     NODE_TYPE_NODE    = 0,
       
   401     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
       
   402     NODE_TYPE_TEXT    = XML_TEXT_NODE,
       
   403     NODE_TYPE_PI      = XML_PI_NODE
       
   404 } xmlXPathTypeVal;
       
   405 
       
   406 
       
   407 
       
   408 
       
   409 /************************************************************************
       
   410  *                                                                      *
       
   411  *          Parser Type functions                                       *
       
   412  *                                                                      *
       
   413  ************************************************************************/
       
   414 
       
   415 /**
       
   416  * xmlXPathNewCompExpr:
       
   417  *
       
   418  * Create a new Xpath component
       
   419  *
       
   420  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
       
   421  */
       
   422 static xmlXPathCompExprPtr
       
   423 xmlXPathNewCompExpr(void) {
       
   424     xmlXPathCompExprPtr cur;
       
   425 
       
   426     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
       
   427     if (cur == NULL) {
       
   428         xmlXPathErrMemory(NULL, EMBED_ERRTXT("allocating component\n"));
       
   429         return(NULL);
       
   430     }
       
   431     memset(cur, 0, sizeof(xmlXPathCompExpr));
       
   432     cur->maxStep = 10; /* TODO: XPath context can be configured by maxStep parameter */
       
   433     cur->nbStep = 0;
       
   434     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * sizeof(xmlXPathStepOp));
       
   435     if (cur->steps == NULL) {
       
   436         xmlXPathErrMemory(NULL, EMBED_ERRTXT("allocating steps\n"));
       
   437         xmlFree(cur);
       
   438         return(NULL);
       
   439     }
       
   440     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
       
   441     cur->last = -1;
       
   442 #ifdef DEBUG_EVAL_COUNTS
       
   443     cur->nb = 0;
       
   444 #endif
       
   445     return(cur);
       
   446 }
       
   447 
       
   448 /**
       
   449  * xmlXPathFreeCompExpr:
       
   450  * @comp:  an XPATH comp
       
   451  *
       
   452  * Free up the memory allocated by @comp
       
   453  */
       
   454 void
       
   455 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
       
   456 {
       
   457     xmlXPathStepOpPtr op;
       
   458     int i;
       
   459 
       
   460     if (comp == NULL)
       
   461         return;
       
   462     if (comp->dict == NULL) {
       
   463         for (i = 0; i < comp->nbStep; i++) {
       
   464             op = &comp->steps[i];
       
   465             if (op->value4 != NULL) {
       
   466                 if (op->op == XPATH_OP_VALUE)
       
   467                     xmlXPathFreeObject((xmlXPathObjectPtr)op->value4);
       
   468                 else
       
   469                     xmlFree(op->value4);
       
   470             }
       
   471             if (op->value5 != NULL)
       
   472                 xmlFree(op->value5);
       
   473         }
       
   474     } else {
       
   475         for (i = 0; i < comp->nbStep; i++) {
       
   476             op = &comp->steps[i];
       
   477             if (op->value4 != NULL) {
       
   478                 if (op->op == XPATH_OP_VALUE)
       
   479                     xmlXPathFreeObject((xmlXPathObjectPtr)op->value4);
       
   480             }
       
   481         }
       
   482         xmlDictFree(comp->dict);
       
   483     }
       
   484 
       
   485     if (comp->steps != NULL) {
       
   486         xmlFree(comp->steps);
       
   487     }
       
   488 #ifdef DEBUG_EVAL_COUNTS
       
   489     if (comp->string != NULL) {
       
   490         xmlFree(comp->string);
       
   491     }
       
   492 #endif
       
   493     if (comp->expr != NULL) {
       
   494         xmlFree(comp->expr);
       
   495     }
       
   496 
       
   497     xmlFree(comp);
       
   498 }
       
   499 
       
   500 /**
       
   501  * xmlXPathCompExprAdd:
       
   502  * @comp:  the compiled expression
       
   503  * @ch1: first child index
       
   504  * @ch2: second child index
       
   505  * @op:  an op
       
   506  * @value:  the first int value
       
   507  * @value2:  the second int value
       
   508  * @value3:  the third int value
       
   509  * @value4:  the first string value
       
   510  * @value5:  the second string value
       
   511  *
       
   512  * Add a step to an XPath Compiled Expression
       
   513  *
       
   514  * Returns -1 in case of failure, the index otherwise
       
   515  */
       
   516 static int
       
   517 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
       
   518                     xmlXPathOp op, int value,
       
   519                     int value2, int value3, void *value4, void *value5)
       
   520 {
       
   521     xmlXPathStepOpPtr step;
       
   522 
       
   523     if (comp->nbStep >= comp->maxStep)
       
   524     {
       
   525         xmlXPathStepOp *real;
       
   526 
       
   527         comp->maxStep *= 2;
       
   528         real = (xmlXPathStepOp *) xmlRealloc(comp->steps, comp->maxStep * sizeof(xmlXPathStepOp));
       
   529         if (real == NULL) {
       
   530             comp->maxStep /= 2;
       
   531             xmlXPathErrMemory(NULL, EMBED_ERRTXT("adding step\n"));
       
   532             return(-1);
       
   533         }
       
   534         comp->steps = real;
       
   535     }
       
   536     // DONE: OPTIMIZE: make a proxy for  comp->steps[comp->nbStep]
       
   537     step = &(comp->steps[comp->nbStep]);
       
   538     //
       
   539     comp->last = comp->nbStep;
       
   540     step->ch1 = ch1;
       
   541     step->ch2 = ch2;
       
   542     step->op = op;
       
   543     step->value = value;
       
   544     step->value2 = value2;
       
   545     step->value3 = value3;
       
   546 
       
   547     if ((comp->dict != NULL) &&
       
   548         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
       
   549          (op == XPATH_OP_COLLECT)))
       
   550     {
       
   551         if (value4 != NULL) {
       
   552             step->value4 = (xmlChar*)
       
   553                         (void*)xmlDictLookup(comp->dict, (xmlChar*) value4, -1);
       
   554             xmlFree(value4);
       
   555         } else
       
   556             step->value4 = NULL;
       
   557 
       
   558         if (value5 != NULL) {
       
   559             step->value5 = (xmlChar*)
       
   560                         (void*)xmlDictLookup(comp->dict, (xmlChar*)value5, -1);
       
   561             xmlFree(value5);
       
   562         }else
       
   563             step->value5 = NULL;
       
   564     }
       
   565     else
       
   566     {
       
   567         step->value4 = value4;
       
   568         step->value5 = value5;
       
   569     }
       
   570     step->cache = NULL;
       
   571     return(comp->nbStep++);
       
   572 }
       
   573 
       
   574 /**
       
   575  * xmlXPathCompSwap:
       
   576  * @comp:  the compiled expression
       
   577  * @op: operation index
       
   578  *
       
   579  * Swaps 2 operations in the compiled expression
       
   580  */
       
   581 static void
       
   582 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
       
   583     int tmp;
       
   584 
       
   585 #ifndef LIBXML_THREAD_ENABLED
       
   586     /*
       
   587      * Since this manipulates possibly shared variables, this is
       
   588      * disabled if one detects that the library is used in a multithreaded
       
   589      * application
       
   590      */
       
   591     if (xmlXPathDisableOptimizer)
       
   592         return;
       
   593 #endif
       
   594 
       
   595     tmp = op->ch1;
       
   596     op->ch1 = op->ch2;
       
   597     op->ch2 = tmp;
       
   598 }
       
   599 
       
   600 
       
   601 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)   \
       
   602     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), (op), (val), (val2), (val3), (val4), (val5))
       
   603 
       
   604 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)         \
       
   605     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, (op), (val), (val2), (val3), (val4), (val5))
       
   606 
       
   607 #define PUSH_LEAVE_EXPR(op, val, val2)                  \
       
   608     xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
       
   609 
       
   610 #define PUSH_UNARY_EXPR(op, ch, val, val2)              \
       
   611     xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
       
   612 
       
   613 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)           \
       
   614     xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
       
   615 
       
   616 /************************************************************************
       
   617  *                                                                      *
       
   618  *      Debugging related functions                                     *
       
   619  *                                                                      *
       
   620  ************************************************************************/
       
   621 
       
   622 // TODO: OPTIMIZE: Create a function and do function call in macro
       
   623 #define STRANGE                                     \
       
   624     xmlGenericError(xmlGenericErrorContext,         \
       
   625         EMBED_ERRTXT("Internal error at %s:%d\n"),  \
       
   626             __FILE__, __LINE__);
       
   627 
       
   628 #ifdef LIBXML_DEBUG_ENABLED
       
   629 static void
       
   630 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
       
   631     int i;
       
   632     char shift[100];
       
   633 
       
   634     for (i = 0;((i < depth) && (i < 25));i++)
       
   635         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   636     shift[2 * i] = shift[2 * i + 1] = 0;
       
   637     if (cur == NULL) {
       
   638     fprintf(output, shift);
       
   639     fprintf(output, "Node is NULL !\n");
       
   640     return;
       
   641 
       
   642     }
       
   643 
       
   644     if ((cur->type == XML_DOCUMENT_NODE) ||
       
   645          (cur->type == XML_HTML_DOCUMENT_NODE)) {
       
   646     fprintf(output, shift);
       
   647     fprintf(output, " /\n");
       
   648     } else if (cur->type == XML_ATTRIBUTE_NODE)
       
   649     xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
       
   650     else
       
   651     xmlDebugDumpOneNode(output, cur, depth);
       
   652 }
       
   653 
       
   654 static void
       
   655 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
       
   656     xmlNodePtr tmp;
       
   657     int i;
       
   658     char shift[100];
       
   659 
       
   660     for (i = 0;((i < depth) && (i < 25));i++)
       
   661         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   662     shift[2 * i] = shift[2 * i + 1] = 0;
       
   663     if (cur == NULL) {
       
   664         fprintf(output, shift);
       
   665         fprintf(output, "Node is NULL !\n");
       
   666         return;
       
   667     }
       
   668 
       
   669     while (cur != NULL) {
       
   670     tmp = cur;
       
   671     cur = cur->next;
       
   672     xmlDebugDumpOneNode(output, tmp, depth);
       
   673     }
       
   674 }
       
   675 
       
   676 static void
       
   677 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
       
   678     int i;
       
   679     char shift[100];
       
   680 
       
   681     for (i = 0;((i < depth) && (i < 25));i++)
       
   682         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   683 
       
   684     shift[2 * i] = shift[2 * i + 1] = 0;
       
   685 
       
   686     if (cur == NULL) {
       
   687         fprintf(output, shift);
       
   688         fprintf(output, "NodeSet is NULL !\n");
       
   689         return;
       
   690     }
       
   691 
       
   692     if (cur != NULL) {
       
   693         fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
       
   694         for (i = 0;i < cur->nodeNr;i++) {
       
   695             fprintf(output, shift);
       
   696             fprintf(output, "%d", i + 1);
       
   697             xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
       
   698         }
       
   699     }
       
   700 }
       
   701 
       
   702 static void
       
   703 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
       
   704     int i;
       
   705     char shift[100];
       
   706 
       
   707     for (i = 0;((i < depth) && (i < 25));i++)
       
   708         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   709     shift[2 * i] = shift[2 * i + 1] = 0;
       
   710 
       
   711     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
       
   712     fprintf(output, shift);
       
   713     fprintf(output, "Value Tree is NULL !\n");
       
   714     return;
       
   715 
       
   716     }
       
   717 
       
   718     fprintf(output, shift);
       
   719     fprintf(output, "%d", i + 1);
       
   720     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
       
   721 }
       
   722 #if defined(LIBXML_XPTR_ENABLED)
       
   723 static void
       
   724 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
       
   725     int i;
       
   726     char shift[100];
       
   727 
       
   728     for (i = 0;((i < depth) && (i < 25));i++)
       
   729         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   730     shift[2 * i] = shift[2 * i + 1] = 0;
       
   731 
       
   732     if (cur == NULL) {
       
   733     fprintf(output, shift);
       
   734     fprintf(output, "LocationSet is NULL !\n");
       
   735     return;
       
   736 
       
   737     }
       
   738 
       
   739     for (i = 0;i < cur->locNr;i++) {
       
   740     fprintf(output, shift);
       
   741         fprintf(output, "%d : ", i + 1);
       
   742     xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
       
   743     }
       
   744 }
       
   745 #endif /* LIBXML_XPTR_ENABLED */
       
   746 
       
   747 /**
       
   748  * xmlXPathDebugDumpObject:
       
   749  * @output:  the FILE * to dump the output
       
   750  * @cur:  the object to inspect
       
   751  * @depth:  indentation level
       
   752  *
       
   753  * Dump the content of the object for debugging purposes
       
   754  */
       
   755 void
       
   756 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
       
   757     int i;
       
   758     char shift[100];
       
   759 
       
   760     for (i = 0;((i < depth) && (i < 25));i++)
       
   761         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   762     shift[2 * i] = shift[2 * i + 1] = 0;
       
   763 
       
   764     fprintf(output, shift);
       
   765 
       
   766     if (cur == NULL) {
       
   767         fprintf(output, "Object is empty (NULL)\n");
       
   768     return;
       
   769     }
       
   770     switch(cur->type) {
       
   771         case XPATH_UNDEFINED:
       
   772         fprintf(output, "Object is uninitialized\n");
       
   773         break;
       
   774         case XPATH_NODESET:
       
   775         fprintf(output, "Object is a Node Set :\n");
       
   776         xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
       
   777         break;
       
   778     case XPATH_XSLT_TREE:
       
   779         fprintf(output, "Object is an XSLT value tree :\n");
       
   780         xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
       
   781         break;
       
   782         case XPATH_BOOLEAN:
       
   783         fprintf(output, "Object is a Boolean : ");
       
   784         if (cur->boolval) fprintf(output, "true\n");
       
   785         else fprintf(output, "false\n");
       
   786         break;
       
   787         case XPATH_NUMBER:
       
   788         switch (xmlXPathIsInf(cur->floatval)) {
       
   789         case 1:
       
   790         fprintf(output, "Object is a number : Infinity\n");
       
   791         break;
       
   792         case -1:
       
   793         fprintf(output, "Object is a number : -Infinity\n");
       
   794         break;
       
   795         default:
       
   796         if (xmlXPathIsNaN(cur->floatval)) {
       
   797             fprintf(output, "Object is a number : NaN\n");
       
   798         } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
       
   799             fprintf(output, "Object is a number : 0\n");
       
   800         } else {
       
   801             fprintf(output, "Object is a number : %0g\n", cur->floatval);
       
   802         }
       
   803         }
       
   804         break;
       
   805         case XPATH_STRING:
       
   806         fprintf(output, "Object is a string : ");
       
   807         xmlDebugDumpString(output, cur->stringval);
       
   808         fprintf(output, "\n");
       
   809         break;
       
   810     case XPATH_POINT:
       
   811         fprintf(output, "Object is a point : index %d in node", cur->index);
       
   812         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
       
   813         fprintf(output, "\n");
       
   814         break;
       
   815     case XPATH_RANGE:
       
   816         if ((cur->user2 == NULL) ||
       
   817         ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
       
   818         fprintf(output, "Object is a collapsed range :\n");
       
   819         fprintf(output, shift);
       
   820         if (cur->index >= 0)
       
   821             fprintf(output, "index %d in ", cur->index);
       
   822         fprintf(output, "node\n");
       
   823         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
       
   824                           depth + 1);
       
   825         } else  {
       
   826         fprintf(output, "Object is a range :\n");
       
   827         fprintf(output, shift);
       
   828         fprintf(output, "From ");
       
   829         if (cur->index >= 0)
       
   830             fprintf(output, "index %d in ", cur->index);
       
   831         fprintf(output, "node\n");
       
   832         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
       
   833                           depth + 1);
       
   834         fprintf(output, shift);
       
   835         fprintf(output, "To ");
       
   836         if (cur->index2 >= 0)
       
   837             fprintf(output, "index %d in ", cur->index2);
       
   838         fprintf(output, "node\n");
       
   839         xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
       
   840                           depth + 1);
       
   841         fprintf(output, "\n");
       
   842         }
       
   843         break;
       
   844     case XPATH_LOCATIONSET:
       
   845 #if defined(LIBXML_XPTR_ENABLED)
       
   846         fprintf(output, "Object is a Location Set:\n");
       
   847         xmlXPathDebugDumpLocationSet(output,
       
   848             (xmlLocationSetPtr) cur->user, depth);
       
   849 #endif
       
   850         break;
       
   851     case XPATH_USERS:
       
   852         fprintf(output, "Object is user defined\n");
       
   853         break;
       
   854     }
       
   855 }
       
   856 
       
   857 static void
       
   858 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
       
   859                          xmlXPathStepOpPtr op, int depth) {
       
   860     int i;
       
   861     char shift[100];
       
   862 
       
   863     for (i = 0;((i < depth) && (i < 25));i++)
       
   864         shift[2 * i] = shift[2 * i + 1] = ' ';
       
   865     shift[2 * i] = shift[2 * i + 1] = 0;
       
   866 
       
   867     fprintf(output, shift);
       
   868     if (op == NULL) {
       
   869     fprintf(output, "Step is NULL\n");
       
   870     return;
       
   871     }
       
   872     switch (op->op) {
       
   873         case XPATH_OP_END:
       
   874         fprintf(output, "END"); break;
       
   875         case XPATH_OP_AND:
       
   876         fprintf(output, "AND"); break;
       
   877         case XPATH_OP_OR:
       
   878         fprintf(output, "OR"); break;
       
   879         case XPATH_OP_EQUAL:
       
   880          if (op->value)
       
   881          fprintf(output, "EQUAL =");
       
   882          else
       
   883          fprintf(output, "EQUAL !=");
       
   884          break;
       
   885         case XPATH_OP_CMP:
       
   886          if (op->value)
       
   887          fprintf(output, "CMP <");
       
   888          else
       
   889          fprintf(output, "CMP >");
       
   890          if (!op->value2)
       
   891          fprintf(output, "=");
       
   892          break;
       
   893         case XPATH_OP_PLUS:
       
   894          if (op->value == 0)
       
   895          fprintf(output, "PLUS -");
       
   896          else if (op->value == 1)
       
   897          fprintf(output, "PLUS +");
       
   898          else if (op->value == 2)
       
   899          fprintf(output, "PLUS unary -");
       
   900          else if (op->value == 3)
       
   901          fprintf(output, "PLUS unary - -");
       
   902          break;
       
   903         case XPATH_OP_MULT:
       
   904          if (op->value == 0)
       
   905          fprintf(output, "MULT *");
       
   906          else if (op->value == 1)
       
   907          fprintf(output, "MULT div");
       
   908          else
       
   909          fprintf(output, "MULT mod");
       
   910          break;
       
   911         case XPATH_OP_UNION:
       
   912          fprintf(output, "UNION"); break;
       
   913         case XPATH_OP_ROOT:
       
   914          fprintf(output, "ROOT"); break;
       
   915         case XPATH_OP_NODE:
       
   916          fprintf(output, "NODE"); break;
       
   917         case XPATH_OP_RESET:
       
   918          fprintf(output, "RESET"); break;
       
   919         case XPATH_OP_SORT:
       
   920          fprintf(output, "SORT"); break;
       
   921         case XPATH_OP_COLLECT: {
       
   922         xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
       
   923         xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
       
   924         xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
       
   925         const xmlChar *prefix = op->value4;
       
   926         const xmlChar *name = op->value5;
       
   927 
       
   928         fprintf(output, "COLLECT ");
       
   929         switch (axis) {
       
   930         case AXIS_ANCESTOR:
       
   931             fprintf(output, " 'ancestors' "); break;
       
   932         case AXIS_ANCESTOR_OR_SELF:
       
   933             fprintf(output, " 'ancestors-or-self' "); break;
       
   934         case AXIS_ATTRIBUTE:
       
   935             fprintf(output, " 'attributes' "); break;
       
   936         case AXIS_CHILD:
       
   937             fprintf(output, " 'child' "); break;
       
   938         case AXIS_DESCENDANT:
       
   939             fprintf(output, " 'descendant' "); break;
       
   940         case AXIS_DESCENDANT_OR_SELF:
       
   941             fprintf(output, " 'descendant-or-self' "); break;
       
   942         case AXIS_FOLLOWING:
       
   943             fprintf(output, " 'following' "); break;
       
   944         case AXIS_FOLLOWING_SIBLING:
       
   945             fprintf(output, " 'following-siblings' "); break;
       
   946         case AXIS_NAMESPACE:
       
   947             fprintf(output, " 'namespace' "); break;
       
   948         case AXIS_PARENT:
       
   949             fprintf(output, " 'parent' "); break;
       
   950         case AXIS_PRECEDING:
       
   951             fprintf(output, " 'preceding' "); break;
       
   952         case AXIS_PRECEDING_SIBLING:
       
   953             fprintf(output, " 'preceding-sibling' "); break;
       
   954         case AXIS_SELF:
       
   955             fprintf(output, " 'self' "); break;
       
   956         }
       
   957         switch (test) {
       
   958                 case NODE_TEST_NONE:
       
   959             fprintf(output, "'none' "); break;
       
   960                 case NODE_TEST_TYPE:
       
   961             fprintf(output, "'type' "); break;
       
   962                 case NODE_TEST_PI:
       
   963             fprintf(output, "'PI' "); break;
       
   964                 case NODE_TEST_ALL:
       
   965             fprintf(output, "'all' "); break;
       
   966                 case NODE_TEST_NS:
       
   967             fprintf(output, "'namespace' "); break;
       
   968                 case NODE_TEST_NAME:
       
   969             fprintf(output, "'name' "); break;
       
   970         }
       
   971         switch (type) {
       
   972                 case NODE_TYPE_NODE:
       
   973             fprintf(output, "'node' "); break;
       
   974                 case NODE_TYPE_COMMENT:
       
   975             fprintf(output, "'comment' "); break;
       
   976                 case NODE_TYPE_TEXT:
       
   977             fprintf(output, "'text' "); break;
       
   978                 case NODE_TYPE_PI:
       
   979             fprintf(output, "'PI' "); break;
       
   980         }
       
   981         if (prefix != NULL)
       
   982         fprintf(output, "%s:", prefix);
       
   983         if (name != NULL)
       
   984         fprintf(output, "%s", (const char *) name);
       
   985         break;
       
   986 
       
   987         }
       
   988     case XPATH_OP_VALUE: {
       
   989         xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
       
   990 
       
   991         fprintf(output, "ELEM ");
       
   992         xmlXPathDebugDumpObject(output, object, 0);
       
   993         goto finish;
       
   994     }
       
   995     case XPATH_OP_VARIABLE: {
       
   996         const xmlChar *prefix = op->value5;
       
   997         const xmlChar *name = op->value4;
       
   998 
       
   999         if (prefix != NULL)
       
  1000         fprintf(output, "VARIABLE %s:%s", prefix, name);
       
  1001         else
       
  1002         fprintf(output, "VARIABLE %s", name);
       
  1003         break;
       
  1004     }
       
  1005     case XPATH_OP_FUNCTION: {
       
  1006         int nbargs = op->value;
       
  1007         const xmlChar *prefix = op->value5;
       
  1008         const xmlChar *name = op->value4;
       
  1009 
       
  1010         if (prefix != NULL)
       
  1011         fprintf(output, "FUNCTION %s:%s(%d args)",
       
  1012             prefix, name, nbargs);
       
  1013         else
       
  1014         fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
       
  1015         break;
       
  1016     }
       
  1017         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
       
  1018         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
       
  1019         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
       
  1020 #ifdef LIBXML_XPTR_ENABLED
       
  1021         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
       
  1022 #endif
       
  1023     default:
       
  1024         fprintf(output, "UNKNOWN %d\n", op->op); return;
       
  1025     }
       
  1026     fprintf(output, "\n");
       
  1027 finish:
       
  1028     if (op->ch1 >= 0)
       
  1029     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
       
  1030     if (op->ch2 >= 0)
       
  1031     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
       
  1032 }
       
  1033 
       
  1034 /**
       
  1035  * xmlXPathDebugDumpCompExpr:
       
  1036  * @output:  the FILE * for the output
       
  1037  * @comp:  the precompiled XPath expression
       
  1038  * @depth:  the indentation level.
       
  1039  *
       
  1040  * Dumps the tree of the compiled XPath expression.
       
  1041  */
       
  1042 void
       
  1043 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
       
  1044                       int depth) {
       
  1045     int i;
       
  1046     char shift[100];
       
  1047 
       
  1048     for (i = 0;((i < depth) && (i < 25));i++)
       
  1049         shift[2 * i] = shift[2 * i + 1] = ' ';
       
  1050     shift[2 * i] = shift[2 * i + 1] = 0;
       
  1051 
       
  1052     fprintf(output, shift);
       
  1053 
       
  1054     if (comp == NULL) {
       
  1055     fprintf(output, "Compiled Expression is NULL\n");
       
  1056     return;
       
  1057     }
       
  1058     fprintf(output, "Compiled Expression : %d elements\n",
       
  1059         comp->nbStep);
       
  1060     i = comp->last;
       
  1061     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
       
  1062 }
       
  1063 #endif /* LIBXML_DEBUG_ENABLED */
       
  1064 
       
  1065 /************************************************************************
       
  1066  *                                                                      *
       
  1067  *      Parser stacks related functions and macros                      *
       
  1068  *                                                                      *
       
  1069  ************************************************************************/
       
  1070 
       
  1071 /**
       
  1072  * valuePop:
       
  1073  * @ctxt: an XPath evaluation context
       
  1074  *
       
  1075  * Pops the top XPath object from the value stack
       
  1076  *
       
  1077  * Returns the XPath object just removed
       
  1078  */
       
  1079 extern xmlXPathObjectPtr
       
  1080 valuePop(xmlXPathParserContextPtr ctxt)
       
  1081 {
       
  1082     xmlXPathObjectPtr ret;
       
  1083 
       
  1084     if (ctxt->valueNr <= 0)
       
  1085         return (0);
       
  1086     ctxt->valueNr--;
       
  1087     if (ctxt->valueNr > 0)
       
  1088         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
       
  1089     else
       
  1090         ctxt->value = NULL;
       
  1091     ret = ctxt->valueTab[ctxt->valueNr];
       
  1092     ctxt->valueTab[ctxt->valueNr] = 0;
       
  1093     return (ret);
       
  1094 }
       
  1095 /**
       
  1096  * valuePush:
       
  1097  * @ctxt:  an XPath evaluation context
       
  1098  * @value:  the XPath object
       
  1099  *
       
  1100  * Pushes a new XPath object on top of the value stack
       
  1101  *
       
  1102  * returns the number of items on the value stack
       
  1103  *
       
  1104  * OOM: possible --> returns 0
       
  1105  */
       
  1106 int
       
  1107 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
       
  1108 {
       
  1109     if (ctxt->valueNr >= ctxt->valueMax)
       
  1110     {
       
  1111         xmlXPathObjectPtr* tmp;
       
  1112         // DONE: Fix xmlRealloc
       
  1113         tmp = (xmlXPathObjectPtr*)xmlRealloc(ctxt->valueTab,
       
  1114                                              ctxt->valueMax *
       
  1115                                              2 * sizeof(ctxt->valueTab[0]));
       
  1116         if (!tmp) {
       
  1117             xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("realloc failed !\n"));
       
  1118             return (0);
       
  1119         }
       
  1120         ctxt->valueTab = tmp;
       
  1121         ctxt->valueMax *= 2;
       
  1122     }
       
  1123     ctxt->valueTab[ctxt->valueNr] = value;
       
  1124     ctxt->value = value;
       
  1125     return (ctxt->valueNr++);
       
  1126 }
       
  1127 
       
  1128 /**
       
  1129  * xmlXPathPopBoolean:
       
  1130  * @ctxt:  an XPath parser context
       
  1131  *
       
  1132  * Pops a boolean from the stack, handling conversion if needed.
       
  1133  * Check error with #xmlXPathCheckError.
       
  1134  *
       
  1135  * Returns the boolean
       
  1136  */
       
  1137 int
       
  1138 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
       
  1139     xmlXPathObjectPtr obj;
       
  1140     int ret;
       
  1141 
       
  1142     obj = valuePop(ctxt);
       
  1143     if (obj == NULL) {
       
  1144         xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
       
  1145         return(0);
       
  1146     }
       
  1147     if (obj->type != XPATH_BOOLEAN)
       
  1148         ret = xmlXPathCastToBoolean(obj);
       
  1149     else
       
  1150         ret = obj->boolval;
       
  1151     xmlXPathFreeObject(obj);
       
  1152     return(ret);
       
  1153 }
       
  1154 
       
  1155 /**
       
  1156  * xmlXPathPopNumber:
       
  1157  * @ctxt:  an XPath parser context
       
  1158  *
       
  1159  * Pops a number from the stack, handling conversion if needed.
       
  1160  * Check error with #xmlXPathCheckError.
       
  1161  *
       
  1162  * Returns the number
       
  1163  */
       
  1164 double
       
  1165 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
       
  1166     xmlXPathObjectPtr obj;
       
  1167     double ret;
       
  1168 
       
  1169     obj = valuePop(ctxt);
       
  1170     if (obj == NULL) {
       
  1171     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
       
  1172     return(0);
       
  1173     }
       
  1174     if (obj->type != XPATH_NUMBER)
       
  1175     ret = xmlXPathCastToNumber(obj);
       
  1176     else
       
  1177         ret = obj->floatval;
       
  1178     xmlXPathFreeObject(obj);
       
  1179     return(ret);
       
  1180 }
       
  1181 
       
  1182 /**
       
  1183  * xmlXPathPopString:
       
  1184  * @ctxt:  an XPath parser context
       
  1185  *
       
  1186  * Pops a string from the stack, handling conversion if needed.
       
  1187  * Check error with #xmlXPathCheckError.
       
  1188  *
       
  1189  * Returns the string
       
  1190  */
       
  1191 xmlChar *
       
  1192 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
       
  1193     xmlXPathObjectPtr obj;
       
  1194     xmlChar * ret;
       
  1195 
       
  1196     obj = valuePop(ctxt);
       
  1197     if (obj == NULL) {
       
  1198     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
       
  1199     return(NULL);
       
  1200     }
       
  1201     ret = xmlXPathCastToString(obj);    /* this does required strdup */
       
  1202     /* TODO: needs refactoring somewhere else */
       
  1203     if (obj->stringval == ret)
       
  1204     obj->stringval = NULL;
       
  1205     xmlXPathFreeObject(obj);
       
  1206     return(ret);
       
  1207 }
       
  1208 
       
  1209 /**
       
  1210  * xmlXPathPopNodeSet:
       
  1211  * @ctxt:  an XPath parser context
       
  1212  *
       
  1213  * Pops a node-set from the stack, handling conversion if needed.
       
  1214  * Check error with #xmlXPathCheckError.
       
  1215  *
       
  1216  * Returns the node-set
       
  1217  */
       
  1218 xmlNodeSetPtr
       
  1219 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
       
  1220     xmlXPathObjectPtr obj;
       
  1221     xmlNodeSetPtr ret;
       
  1222 
       
  1223     if (ctxt->value == NULL) {
       
  1224     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
       
  1225     return(NULL);
       
  1226     }
       
  1227     if (!xmlXPathStackIsNodeSet(ctxt)) {
       
  1228     xmlXPathSetTypeError(ctxt);
       
  1229     return(NULL);
       
  1230     }
       
  1231     obj = valuePop(ctxt);
       
  1232     ret = obj->nodesetval;
       
  1233     /* to fix memory leak of not clearing obj->user */
       
  1234     if (obj->boolval && obj->user != NULL)
       
  1235         xmlFreeNodeList((xmlNodePtr) obj->user);
       
  1236     xmlXPathFreeNodeSetList(obj);
       
  1237     return(ret);
       
  1238 }
       
  1239 
       
  1240 /**
       
  1241  * xmlXPathPopExternal:
       
  1242  * @ctxt:  an XPath parser context
       
  1243  *
       
  1244  * Pops an external object from the stack, handling conversion if needed.
       
  1245  * Check error with #xmlXPathCheckError.
       
  1246  *
       
  1247  * Returns the object
       
  1248  */
       
  1249 void *
       
  1250 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
       
  1251     xmlXPathObjectPtr obj;
       
  1252     void * ret;
       
  1253 
       
  1254     if (ctxt->value == NULL) {
       
  1255     xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
       
  1256     return(NULL);
       
  1257     }
       
  1258     if (ctxt->value->type != XPATH_USERS) {
       
  1259     xmlXPathSetTypeError(ctxt);
       
  1260     return(NULL);
       
  1261     }
       
  1262     obj = valuePop(ctxt);
       
  1263     ret = obj->user;
       
  1264     xmlXPathFreeObject(obj);
       
  1265     return(ret);
       
  1266 }
       
  1267 
       
  1268 /*
       
  1269  * Macros for accessing the content. Those should be used only by the parser,
       
  1270  * and not exported.
       
  1271  *
       
  1272  * Dirty macros, i.e. one need to make assumption on the context to use them
       
  1273  *
       
  1274  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
       
  1275  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
       
  1276  *           in ISO-Latin or UTF-8.
       
  1277  *           This should be used internally by the parser
       
  1278  *           only to compare to ASCII values otherwise it would break when
       
  1279  *           running with UTF-8 encoding.
       
  1280  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
       
  1281  *           to compare on ASCII based substring.
       
  1282  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
       
  1283  *           strings within the parser.
       
  1284  *   CURRENT Returns the current char value, with the full decoding of
       
  1285  *           UTF-8 if we are using this mode. It returns an int.
       
  1286  *   NEXT    Skip to the next character, this does the proper decoding
       
  1287  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
       
  1288  *           It returns the pointer to the current xmlChar.
       
  1289  */
       
  1290 
       
  1291 #define CUR (*ctxt->cur)
       
  1292 #define SKIP(val) ctxt->cur += (val)
       
  1293 #define NXT(val) ctxt->cur[(val)]
       
  1294 #define CUR_PTR ctxt->cur
       
  1295 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
       
  1296 
       
  1297 #define COPY_BUF(len,b,i,v)                                              \
       
  1298     if (len == 1) b[i++] = (xmlChar) v;                                  \
       
  1299     else i += xmlCopyChar(len,&b[i],v)
       
  1300 
       
  1301 #define NEXTL(k)  ctxt->cur += k
       
  1302 
       
  1303 // XMLENGINE: NEXT was replaced with ctxt->cur++ since *ctxt->cur always !=0 there
       
  1304 // OOM: never
       
  1305 #define SKIP_BLANKS    while (IS_BLANK_CH(*(ctxt->cur))) ctxt->cur++
       
  1306 
       
  1307 #define CURRENT (*ctxt->cur)
       
  1308 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
       
  1309 
       
  1310 
       
  1311 #ifndef DBL_DIG
       
  1312 #define DBL_DIG 16
       
  1313 #endif
       
  1314 #ifndef DBL_EPSILON
       
  1315 #define DBL_EPSILON 1E-9
       
  1316 #endif
       
  1317 
       
  1318 #define UPPER_DOUBLE 1E9
       
  1319 #define LOWER_DOUBLE 1E-5
       
  1320 
       
  1321 #define INTEGER_DIGITS DBL_DIG
       
  1322 #define FRACTION_DIGITS (DBL_DIG + 1)
       
  1323 #define EXPONENT_DIGITS (3 + 2)
       
  1324 
       
  1325 #if (_MSC_VER >= 1300) && (WINVER < 0x0500)
       
  1326 //VC7 or later, building with pre-VC7 runtime libraries
       
  1327 //extern "C" long _ftol( double ); //defined by VC6 C libs
       
  1328 //extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); }
       
  1329 #endif
       
  1330 
       
  1331 /**
       
  1332  * xmlXPathFormatNumber:
       
  1333  * @number:     number to format
       
  1334  * @buffer:     output buffer
       
  1335  * @buffersize: size of output buffer
       
  1336  *
       
  1337  * Convert the number into a string representation.
       
  1338  *
       
  1339  * OOM: never
       
  1340  */
       
  1341 static void
       
  1342 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
       
  1343 {   // TODO: use IFs for clearer code / combine calls to snprintf()
       
  1344     switch (xmlXPathIsInf(number)) {
       
  1345     case 1:
       
  1346         if (buffersize > (int)sizeof("Infinity"))
       
  1347             snprintf(buffer, buffersize, "Infinity");
       
  1348         break;
       
  1349     case -1:
       
  1350         if (buffersize > (int)sizeof("-Infinity"))
       
  1351             snprintf(buffer, buffersize, "-Infinity");
       
  1352         break;
       
  1353     default:
       
  1354         if (xmlXPathIsNaN(number)) {
       
  1355             if (buffersize > (int)sizeof("NaN"))
       
  1356                 snprintf(buffer, buffersize, "NaN");
       
  1357         } else
       
  1358         if (number == 0 && xmlXPathGetSign(number) != 0) {
       
  1359             snprintf(buffer, buffersize, "0");
       
  1360         } else
       
  1361         if (number == ((int) number)) {
       
  1362             char work[30];
       
  1363             char *ptr, *cur;
       
  1364             int res, value = (int) number;
       
  1365 
       
  1366             ptr = &buffer[0];
       
  1367             if (value < 0) {
       
  1368                 *ptr++ = '-';
       
  1369                 value = -value;
       
  1370             }
       
  1371             if (value == 0) {
       
  1372                 *ptr++ = '0';
       
  1373             } else {
       
  1374                 cur = &work[0];
       
  1375                 while (value != 0) {
       
  1376                     res = value % 10;
       
  1377                     value = value / 10;
       
  1378                     *cur++ = '0' + res;
       
  1379                 }
       
  1380                 cur--;
       
  1381                 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
       
  1382                     *ptr++ = *cur--;
       
  1383                 }
       
  1384             }
       
  1385             if (ptr - buffer < buffersize) {
       
  1386                 *ptr = 0;
       
  1387             } else if (buffersize > 0) {
       
  1388                 ptr--;
       
  1389                 *ptr = 0;
       
  1390             }
       
  1391         } else {
       
  1392             /* 3 is sign, decimal point, and terminating zero */
       
  1393             char work[DBL_DIG + EXPONENT_DIGITS + 3];
       
  1394             int integer_place, fraction_place;
       
  1395             char *ptr;
       
  1396             char *after_fraction;
       
  1397             double absolute_value;
       
  1398             int size;
       
  1399 
       
  1400             absolute_value = fabs(number);
       
  1401 
       
  1402             /*
       
  1403              * First choose format - scientific or regular floating point.
       
  1404              * In either case, result is in work, and after_fraction points
       
  1405              * just past the fractional part.
       
  1406             */
       
  1407             if (((absolute_value > UPPER_DOUBLE) || (absolute_value < LOWER_DOUBLE)) &&
       
  1408                 (absolute_value != 0.0))
       
  1409             {
       
  1410                 /* Use scientific notation */
       
  1411                 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
       
  1412                 fraction_place = DBL_DIG - 1;
       
  1413                 snprintf(work, sizeof(work),"%*.*e",
       
  1414                      integer_place, fraction_place, number);
       
  1415                 after_fraction = strchr(work + DBL_DIG, 'e');
       
  1416             }
       
  1417             else {
       
  1418                 /* Use regular notation */
       
  1419                 if (absolute_value > 0.0)
       
  1420                     integer_place = 1 + (int)log10(absolute_value);
       
  1421                 else
       
  1422                     integer_place = 0;
       
  1423 
       
  1424                 fraction_place = (integer_place > 0)
       
  1425                         ? DBL_DIG - integer_place
       
  1426                         : DBL_DIG;
       
  1427                 size = snprintf(work, sizeof(work), "%0.*f", fraction_place, number);
       
  1428                 after_fraction = work + size;
       
  1429             }
       
  1430 
       
  1431             /* Remove fractional trailing zeroes */
       
  1432             ptr = after_fraction;
       
  1433             while (*(--ptr) == '0') {}// EMPTY LOOP
       
  1434 
       
  1435             if (*ptr != '.')
       
  1436                 ptr++;
       
  1437             while ((*ptr++ = *after_fraction++) != 0){} // EMPTY LOOP
       
  1438 
       
  1439             /* Finally copy result back to caller */
       
  1440             size = strlen(work) + 1;
       
  1441             if (size > buffersize) {
       
  1442                 work[buffersize - 1] = 0;
       
  1443                 size = buffersize;
       
  1444             }
       
  1445             memmove(buffer, work, size);
       
  1446         }
       
  1447         break;
       
  1448     }
       
  1449 }
       
  1450 
       
  1451 
       
  1452 /************************************************************************
       
  1453  *                                  *
       
  1454  *          Routines to handle NodeSets         *
       
  1455  *                                  *
       
  1456  ************************************************************************/
       
  1457 
       
  1458 /**
       
  1459  * xmlXPathOrderDocElems:
       
  1460  * @doc:  an input document
       
  1461  *
       
  1462  * Call this routine to speed up XPath computation on static documents.
       
  1463  * This stamps all the element nodes with the document order
       
  1464  * Like for line information, the order is kept in the element->content
       
  1465  * field, the value stored is actually - the node number (starting at -1)
       
  1466  * to be able to differentiate from line numbers.
       
  1467  *
       
  1468  * Returns the number of elements found in the document or -1 in case
       
  1469  *    of error.
       
  1470  */
       
  1471 long
       
  1472 xmlXPathOrderDocElems(xmlDocPtr doc) {
       
  1473     long count = 0;
       
  1474     xmlNodePtr cur;
       
  1475 
       
  1476     if (doc == NULL)
       
  1477     return(-1);
       
  1478     cur = doc->children;
       
  1479     while (cur != NULL) {
       
  1480     if (cur->type == XML_ELEMENT_NODE) {
       
  1481         cur->content = (xmlChar*)((void *) (-(++count)));
       
  1482         if (cur->children != NULL) {
       
  1483         cur = cur->children;
       
  1484         continue;
       
  1485         }
       
  1486     }
       
  1487     if (cur->next != NULL) {
       
  1488         cur = cur->next;
       
  1489         continue;
       
  1490     }
       
  1491     do {
       
  1492         cur = cur->parent;
       
  1493         if (cur == NULL)
       
  1494         break;
       
  1495         if (cur == (xmlNodePtr) doc) {
       
  1496         cur = NULL;
       
  1497         break;
       
  1498         }
       
  1499         if (cur->next != NULL) {
       
  1500         cur = cur->next;
       
  1501         break;
       
  1502         }
       
  1503     } while (cur != NULL);
       
  1504     }
       
  1505     return(count);
       
  1506 }
       
  1507 
       
  1508 /**
       
  1509  * xmlXPathCmpNodes:
       
  1510  * @node1:  the first node
       
  1511  * @node2:  the second node
       
  1512  *
       
  1513  * Compare two nodes w.r.t document order
       
  1514  *
       
  1515  * Returns -2 in case of error 1 if first point < second point, 0 if
       
  1516  *         it's the same node, -1 otherwise
       
  1517  *
       
  1518  * OOM: never
       
  1519  */
       
  1520 int
       
  1521 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
       
  1522     int depth1, depth2;
       
  1523     int attr1 = 0, attr2 = 0;
       
  1524     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
       
  1525     xmlNodePtr cur, root;
       
  1526 
       
  1527     if ((node1 == NULL) || (node2 == NULL))
       
  1528     return(-2);
       
  1529     /*
       
  1530      * a couple of optimizations which will avoid computations in most cases
       
  1531      */
       
  1532     if (node1->type == XML_ATTRIBUTE_NODE) {
       
  1533         attr1 = 1;
       
  1534         attrNode1 = node1;
       
  1535         node1 = node1->parent;
       
  1536     }
       
  1537     if (node2->type == XML_ATTRIBUTE_NODE) {
       
  1538         attr2 = 1;
       
  1539         attrNode2 = node2;
       
  1540         node2 = node2->parent;
       
  1541     }
       
  1542     if (node1 == node2) {
       
  1543     if (attr1 == attr2) {
       
  1544         /* not required, but we keep attributes in order */
       
  1545         if (attr1 != 0) {
       
  1546             cur = attrNode2->prev;
       
  1547         while (cur != NULL) {
       
  1548             if (cur == attrNode1)
       
  1549                 return (1);
       
  1550             cur = cur->prev;
       
  1551         }
       
  1552         return (-1);
       
  1553         }
       
  1554         return(0);
       
  1555     }
       
  1556     if (attr2 == 1)
       
  1557         return(1);
       
  1558     return(-1);
       
  1559     }
       
  1560     if ((node1->type == XML_NAMESPACE_DECL) ||
       
  1561         (node2->type == XML_NAMESPACE_DECL))
       
  1562         return(1);
       
  1563     if (node1 == node2->prev)
       
  1564         return(1);
       
  1565     if (node1 == node2->next)
       
  1566         return(-1);
       
  1567 
       
  1568     /*
       
  1569      * Speedup using document order if availble.
       
  1570      */
       
  1571     if ((node1->type == XML_ELEMENT_NODE) &&
       
  1572     (node2->type == XML_ELEMENT_NODE) &&
       
  1573     (0 > (long) node1->content) &&
       
  1574     (0 > (long) node2->content) &&
       
  1575     (node1->doc == node2->doc)) {
       
  1576     long l1, l2;
       
  1577 
       
  1578     l1 = -((long) node1->content);
       
  1579     l2 = -((long) node2->content);
       
  1580     if (l1 < l2)
       
  1581         return(1);
       
  1582     if (l1 > l2)
       
  1583         return(-1);
       
  1584     }
       
  1585 
       
  1586     /*
       
  1587      * compute depth to root
       
  1588      */
       
  1589     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
       
  1590     if (cur == node1)
       
  1591         return(1);
       
  1592     depth2++;
       
  1593     }
       
  1594     root = cur;
       
  1595     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
       
  1596     if (cur == node2)
       
  1597         return(-1);
       
  1598     depth1++;
       
  1599     }
       
  1600     /*
       
  1601      * Distinct document (or distinct entities :-( ) case.
       
  1602      */
       
  1603     if (root != cur) {
       
  1604         return(-2);
       
  1605     }
       
  1606     /*
       
  1607     * get the nearest common ancestor.
       
  1608     */
       
  1609     while (depth1 > depth2) {
       
  1610         depth1--;
       
  1611         node1 = node1->parent;
       
  1612     }
       
  1613     while (depth2 > depth1) {
       
  1614         depth2--;
       
  1615         node2 = node2->parent;
       
  1616     }
       
  1617     while (node1->parent != node2->parent) {
       
  1618         node1 = node1->parent;
       
  1619         node2 = node2->parent;
       
  1620         /* should not happen but just in case ... */
       
  1621         if ((node1 == NULL) || (node2 == NULL))
       
  1622             return(-2);
       
  1623     }
       
  1624     /*
       
  1625      * Find who's first.
       
  1626      */
       
  1627     if (node1 == node2->prev)
       
  1628         return(1);
       
  1629     if (node1 == node2->next)
       
  1630         return(-1);
       
  1631     /*
       
  1632      * Speedup using document order if availble.
       
  1633      */
       
  1634     if ((node1->type == XML_ELEMENT_NODE) &&
       
  1635         (node2->type == XML_ELEMENT_NODE) &&
       
  1636         (0 > (long) node1->content) &&
       
  1637         (0 > (long) node2->content) &&
       
  1638         (node1->doc == node2->doc)) {
       
  1639             long l1, l2;
       
  1640 
       
  1641             l1 = -((long) node1->content);
       
  1642             l2 = -((long) node2->content);
       
  1643             if (l1 < l2)
       
  1644                 return(1);
       
  1645             if (l1 > l2)
       
  1646                 return(-1);
       
  1647         }
       
  1648 
       
  1649     for (cur = node1->next;cur != NULL;cur = cur->next)
       
  1650     if (cur == node2)
       
  1651         return(1);
       
  1652     return(-1); /* assume there is no sibling list corruption */
       
  1653 }
       
  1654 
       
  1655 /**
       
  1656  * xmlXPathNodeSetSort:
       
  1657  * @set:  the node set
       
  1658  *
       
  1659  * Sort the node set in document order
       
  1660  *
       
  1661  * OOM: never
       
  1662  */
       
  1663 void
       
  1664 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
       
  1665     int i, j, incr, len;
       
  1666     xmlNodePtr tmp;
       
  1667 
       
  1668     if (set == NULL)
       
  1669         return;
       
  1670 
       
  1671     /* Use Shell's sort to sort the node-set */
       
  1672     len = set->nodeNr;
       
  1673     for (incr = len / 2; incr > 0; incr /= 2) {
       
  1674         for (i = incr; i < len; i++) {
       
  1675             j = i - incr;
       
  1676             while (j >= 0) {
       
  1677                 if (xmlXPathCmpNodes(set->nodeTab[j], set->nodeTab[j + incr]) == -1)
       
  1678                 {
       
  1679                     tmp = set->nodeTab[j];
       
  1680                     set->nodeTab[j] = set->nodeTab[j + incr];
       
  1681                     set->nodeTab[j + incr] = tmp;
       
  1682                     j -= incr;
       
  1683                 } else
       
  1684                     break;
       
  1685             }
       
  1686         }
       
  1687     }
       
  1688 }
       
  1689 
       
  1690 #define XML_NODESET_DEFAULT 10
       
  1691 /**
       
  1692  * xmlXPathNodeSetDupNs:
       
  1693  * @node:  the parent node of the namespace XPath node
       
  1694  * @ns:  the libxml namespace declaration node.
       
  1695  *
       
  1696  * Namespace node in libxml don't match the XPath semantic. In a node set
       
  1697  * the namespace nodes are duplicated and the next pointer is set to the
       
  1698  * parent node in the XPath semantic.
       
  1699  *
       
  1700  * Returns the newly created object.
       
  1701  *
       
  1702  * OOM: possible --> returns NULL for valid arguments, sets OOM flag
       
  1703  */
       
  1704 static xmlNodePtr
       
  1705 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
       
  1706     xmlNsPtr cur;
       
  1707 
       
  1708     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
       
  1709         return(NULL);
       
  1710     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
       
  1711         return((xmlNodePtr) ns);
       
  1712 
       
  1713     /*
       
  1714      * Allocate a new Namespace and fill the fields.
       
  1715      */
       
  1716     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
       
  1717     if (cur == NULL) {
       
  1718         xmlXPathErrMemory(NULL, EMBED_ERRTXT("duplicating namespace\n"));
       
  1719         return(NULL);
       
  1720     }
       
  1721     memset(cur, 0, sizeof(xmlNs));
       
  1722     cur->type = XML_NAMESPACE_DECL;
       
  1723     // TODO: Check OOM conditions..
       
  1724     if (ns->href != NULL)
       
  1725         if(! (cur->href = xmlStrdup(ns->href)))
       
  1726             goto OOM;;
       
  1727     if (ns->prefix != NULL)
       
  1728         if(! (cur->prefix = xmlStrdup(ns->prefix)))
       
  1729             goto OOM;
       
  1730 
       
  1731     cur->next = (xmlNsPtr) node;
       
  1732     return((xmlNodePtr) cur);
       
  1733 //---------------------
       
  1734 OOM:
       
  1735     xmlFree(cur);
       
  1736     return NULL;
       
  1737 }
       
  1738 
       
  1739 /**
       
  1740  * xmlXPathNodeSetFreeNs:
       
  1741  * @ns:  the XPath namespace node found in a nodeset.
       
  1742  *
       
  1743  * Namespace nodes in libxml don't match the XPath semantic. In a node set
       
  1744  * the namespace nodes are duplicated and the next pointer is set to the
       
  1745  * parent node in the XPath semantic. Check if such a node needs to be freed
       
  1746  *
       
  1747  * OOM: never
       
  1748  */
       
  1749 void
       
  1750 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
       
  1751     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
       
  1752         return;
       
  1753 
       
  1754     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
       
  1755         if (ns->href != NULL)
       
  1756             xmlFree((xmlChar *)ns->href);
       
  1757         if (ns->prefix != NULL)
       
  1758             xmlFree((xmlChar *)ns->prefix);
       
  1759         xmlFree(ns);
       
  1760     }
       
  1761 }
       
  1762 
       
  1763 /**
       
  1764  * xmlXPathNodeSetCreate:
       
  1765  * @val:  an initial xmlNodePtr, or NULL
       
  1766  *
       
  1767  * Create a new xmlNodeSetPtr of type double and of value @val
       
  1768  *
       
  1769  * Returns the newly created object.
       
  1770  *
       
  1771  * OOM: possible --> returns NULL and sets OOM flag
       
  1772  */
       
  1773 xmlNodeSetPtr
       
  1774 xmlXPathNodeSetCreate(xmlNodePtr val) {
       
  1775     xmlNodeSetPtr ret;
       
  1776 
       
  1777     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
       
  1778     if (ret == NULL) {
       
  1779         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating nodeset\n"));
       
  1780         return(NULL);
       
  1781     }
       
  1782     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
       
  1783 
       
  1784     if (val != NULL) {
       
  1785         xmlNodePtr nval;
       
  1786         // TODO:  Optimize or make adjustable the allocation size of NodeSet
       
  1787         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
       
  1788         if (ret->nodeTab == NULL) {
       
  1789             xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating nodeset\n"));
       
  1790             goto OOM;
       
  1791         }
       
  1792         memset(ret->nodeTab, 0, XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  1793         ret->nodeMax = XML_NODESET_DEFAULT;
       
  1794         if (val->type == XML_NAMESPACE_DECL) {
       
  1795             xmlNsPtr ns = (xmlNsPtr) val;
       
  1796             nval = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
       
  1797             // TODO: OOM: Chrck OOM
       
  1798             if(OOM_FLAG)
       
  1799                 goto OOM;
       
  1800         } else {
       
  1801             nval = val;
       
  1802         }
       
  1803         ret->nodeTab[ret->nodeNr++] = nval;
       
  1804     }
       
  1805     return(ret);
       
  1806 //-------------------
       
  1807 OOM:
       
  1808     xmlFree(ret);
       
  1809     return(NULL);
       
  1810 }
       
  1811 
       
  1812 /**
       
  1813  * xmlXPathNodeSetContains:
       
  1814  * @cur:  the node-set
       
  1815  * @val:  the node
       
  1816  *
       
  1817  * checks whether @cur contains @val
       
  1818  *
       
  1819  * Returns true (1) if @cur contains @val, false (0) otherwise
       
  1820  *
       
  1821  * OOM: never
       
  1822  */
       
  1823 int
       
  1824 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
       
  1825     int i;
       
  1826 
       
  1827     if (val->type == XML_NAMESPACE_DECL) {
       
  1828         for (i = 0; i < cur->nodeNr; i++) {
       
  1829             if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
       
  1830             xmlNsPtr ns1, ns2;
       
  1831 
       
  1832             ns1 = (xmlNsPtr) val;
       
  1833             ns2 = (xmlNsPtr) cur->nodeTab[i];
       
  1834             if (ns1 == ns2)
       
  1835                 return(1);
       
  1836             if ((ns1->next != NULL) &&
       
  1837                 (ns2->next == ns1->next) &&
       
  1838                 (xmlStrEqual(ns1->prefix, ns2->prefix)))
       
  1839                 return(1);
       
  1840             }
       
  1841         }
       
  1842     } else {
       
  1843         for (i = 0; i < cur->nodeNr; i++) {
       
  1844             if (cur->nodeTab[i] == val)
       
  1845                 return(1);
       
  1846         }
       
  1847     }
       
  1848     return(0);
       
  1849 }
       
  1850 
       
  1851 
       
  1852 
       
  1853 /*
       
  1854     TODO: OPTIMIZATION: xmlXPathNodeSetAddNs, xmlXPathNodeSetAdd and xmlXPathNodeSetAddUnique are the same code
       
  1855 
       
  1856 */
       
  1857 
       
  1858 /**
       
  1859  * xmlXPathNodeSetAddNs:
       
  1860  * @cur:  the initial node set
       
  1861  * @node:  the hosting node
       
  1862  * @ns:  a the namespace node
       
  1863  *
       
  1864  * add a new namespace node to an existing NodeSet
       
  1865  */
       
  1866 void
       
  1867 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
       
  1868     int i;
       
  1869 
       
  1870     if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
       
  1871     (node->type != XML_ELEMENT_NODE))
       
  1872     return;
       
  1873 
       
  1874     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  1875     /*
       
  1876      * prevent duplicates
       
  1877      */
       
  1878     for (i = 0;i < cur->nodeNr;i++) {
       
  1879         if ((cur->nodeTab[i] != NULL) &&
       
  1880         (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
       
  1881         (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
       
  1882         (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
       
  1883         return;
       
  1884     }
       
  1885 
       
  1886     /*
       
  1887      * grow the nodeTab if needed
       
  1888      */
       
  1889     if (cur->nodeMax == 0) {
       
  1890         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
       
  1891                          sizeof(xmlNodePtr));
       
  1892     if (cur->nodeTab == NULL) {
       
  1893         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  1894         return;
       
  1895     }
       
  1896     memset(cur->nodeTab, 0 ,
       
  1897            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  1898         cur->nodeMax = XML_NODESET_DEFAULT;
       
  1899     } else if (cur->nodeNr == cur->nodeMax) {
       
  1900         xmlNodePtr *temp;
       
  1901 
       
  1902         cur->nodeMax *= 2;
       
  1903     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
       
  1904                       sizeof(xmlNodePtr));
       
  1905     if (temp == NULL) {
       
  1906         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  1907         return;
       
  1908     }
       
  1909     cur->nodeTab = temp;
       
  1910     }
       
  1911     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
       
  1912 }
       
  1913 
       
  1914 /**
       
  1915  * xmlXPathNodeSetAdd:
       
  1916  * @cur:  the initial node set
       
  1917  * @val:  a new xmlNodePtr
       
  1918  *
       
  1919  * add a new xmlNodePtr to an existing NodeSet
       
  1920  */
       
  1921 void
       
  1922 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
       
  1923     int i;
       
  1924 
       
  1925     if (val == NULL) return;
       
  1926 
       
  1927 #if 0
       
  1928     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
       
  1929     return; /* an XSLT fake node */
       
  1930 #endif
       
  1931 
       
  1932     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  1933     /*
       
  1934      * prevent duplcates
       
  1935      */
       
  1936     for (i = 0;i < cur->nodeNr;i++)
       
  1937         if (cur->nodeTab[i] == val) return;
       
  1938 
       
  1939     /*
       
  1940      * grow the nodeTab if needed
       
  1941      */
       
  1942     if (cur->nodeMax == 0) {
       
  1943         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
       
  1944                          sizeof(xmlNodePtr));
       
  1945     if (cur->nodeTab == NULL) {
       
  1946         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  1947         return;
       
  1948     }
       
  1949     memset(cur->nodeTab, 0 ,
       
  1950            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  1951         cur->nodeMax = XML_NODESET_DEFAULT;
       
  1952     } else if (cur->nodeNr == cur->nodeMax) {
       
  1953         xmlNodePtr *temp;
       
  1954         // TODO:  Realocation policy may be managed
       
  1955         cur->nodeMax *= 2;
       
  1956     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
       
  1957                       sizeof(xmlNodePtr));
       
  1958     if (temp == NULL) {
       
  1959         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  1960         return;
       
  1961     }
       
  1962     cur->nodeTab = temp;
       
  1963     }
       
  1964     if (val->type == XML_NAMESPACE_DECL) {
       
  1965     xmlNsPtr ns = (xmlNsPtr) val;
       
  1966 
       
  1967     cur->nodeTab[cur->nodeNr++] =
       
  1968         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
       
  1969     } else
       
  1970     cur->nodeTab[cur->nodeNr++] = val;
       
  1971 }
       
  1972 
       
  1973 /**
       
  1974  * xmlXPathNodeSetAddUnique:
       
  1975  * @cur:  the initial node set
       
  1976  * @val:  a new xmlNodePtr
       
  1977  *
       
  1978  * add a new xmlNodePtr to an existing NodeSet, optimized version
       
  1979  * when we are sure the node is not already in the set.
       
  1980  */
       
  1981 void
       
  1982 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
       
  1983     if (val == NULL) return;
       
  1984 
       
  1985     // TODO: Rudiments of XSLT - find out how these affect the XPath implementation
       
  1986 #if 0
       
  1987     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
       
  1988     return; /* an XSLT fake node */
       
  1989 #endif
       
  1990 
       
  1991     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  1992     /*
       
  1993      * grow the nodeTab if needed
       
  1994      */
       
  1995     if (cur->nodeMax == 0) {
       
  1996         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
       
  1997 
       
  1998     if (cur->nodeTab == NULL) {
       
  1999         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  2000         return;
       
  2001     }
       
  2002     memset(cur->nodeTab, 0 , XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  2003 
       
  2004         cur->nodeMax = XML_NODESET_DEFAULT;
       
  2005     } else if (cur->nodeNr == cur->nodeMax) {
       
  2006         xmlNodePtr *temp;
       
  2007 
       
  2008         cur->nodeMax *= 2;
       
  2009     temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
       
  2010                       sizeof(xmlNodePtr));
       
  2011     if (temp == NULL) {
       
  2012         xmlXPathErrMemory(NULL, EMBED_ERRTXT("growing nodeset\n"));
       
  2013         return;
       
  2014     }
       
  2015     cur->nodeTab = temp;
       
  2016     }
       
  2017     if (val->type == XML_NAMESPACE_DECL) {
       
  2018     xmlNsPtr ns = (xmlNsPtr) val;
       
  2019 
       
  2020     cur->nodeTab[cur->nodeNr++] =
       
  2021         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
       
  2022     } else
       
  2023     cur->nodeTab[cur->nodeNr++] = val;
       
  2024 }
       
  2025 
       
  2026 /**
       
  2027  * xmlXPathNodeSetMerge:
       
  2028  * @val1:  the first NodeSet or NULL
       
  2029  * @val2:  the second NodeSet
       
  2030  *
       
  2031  * Merges two nodesets, all nodes from @val2 are added to @val1
       
  2032  * if @val1 is NULL, a new set is created and copied from @val2
       
  2033  *
       
  2034  * Returns @val1 once extended or NULL in case of error.
       
  2035  */
       
  2036 xmlNodeSetPtr
       
  2037 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
       
  2038     int i, j, initNr, skip;
       
  2039 
       
  2040     if (val2 == NULL) return(val1);
       
  2041     if (val1 == NULL) {
       
  2042     val1 = xmlXPathNodeSetCreate(NULL);
       
  2043     }
       
  2044 
       
  2045     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  2046     initNr = val1->nodeNr;
       
  2047 
       
  2048     for (i = 0;i < val2->nodeNr;i++) {
       
  2049     /*
       
  2050      * check against duplicates
       
  2051      */
       
  2052     skip = 0;
       
  2053     for (j = 0; j < initNr; j++) {
       
  2054         if (val1->nodeTab[j] == val2->nodeTab[i]) {
       
  2055         skip = 1;
       
  2056         break;
       
  2057         } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
       
  2058                (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
       
  2059         xmlNsPtr ns1, ns2;
       
  2060         ns1 = (xmlNsPtr) val1->nodeTab[j];
       
  2061         ns2 = (xmlNsPtr) val2->nodeTab[i];
       
  2062         if ((ns1->next == ns2->next) &&
       
  2063             (xmlStrEqual(ns1->prefix, ns2->prefix))) {
       
  2064             skip = 1;
       
  2065             break;
       
  2066         }
       
  2067         }
       
  2068     }
       
  2069     if (skip)
       
  2070         continue;
       
  2071 
       
  2072     /*
       
  2073      * grow the nodeTab if needed
       
  2074      */
       
  2075     if (val1->nodeMax == 0) {
       
  2076         val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
       
  2077                             sizeof(xmlNodePtr));
       
  2078         if (val1->nodeTab == NULL) {
       
  2079             xmlXPathErrMemory(NULL, EMBED_ERRTXT("merging nodeset\n"));
       
  2080         return(NULL);
       
  2081         }
       
  2082         memset(val1->nodeTab, 0 ,
       
  2083            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  2084         val1->nodeMax = XML_NODESET_DEFAULT;
       
  2085     } else if (val1->nodeNr == val1->nodeMax) {
       
  2086         xmlNodePtr *temp;
       
  2087 
       
  2088         val1->nodeMax *= 2;
       
  2089         temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
       
  2090                          sizeof(xmlNodePtr));
       
  2091         if (temp == NULL) {
       
  2092             xmlXPathErrMemory(NULL, EMBED_ERRTXT("merging nodeset\n"));
       
  2093         return(NULL);
       
  2094         }
       
  2095         val1->nodeTab = temp;
       
  2096     }
       
  2097     if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
       
  2098         xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
       
  2099 
       
  2100         val1->nodeTab[val1->nodeNr++] =
       
  2101         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
       
  2102     } else
       
  2103         val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
       
  2104     }
       
  2105 
       
  2106     return(val1);
       
  2107 }
       
  2108 
       
  2109 /**
       
  2110  * xmlXPathNodeSetMergeUnique:
       
  2111  * @val1:  the first NodeSet or NULL
       
  2112  * @val2:  the second NodeSet
       
  2113  *
       
  2114  * Merges two nodesets, all nodes from @val2 are added to @val1
       
  2115  * if @val1 is NULL, a new set is created and copied from @val2
       
  2116  *
       
  2117  * Returns @val1 once extended or NULL in case of error.
       
  2118  */
       
  2119 static xmlNodeSetPtr
       
  2120 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
       
  2121     int i;
       
  2122 
       
  2123     if (val2 == NULL) return(val1);
       
  2124     if (val1 == NULL) {
       
  2125     val1 = xmlXPathNodeSetCreate(NULL);
       
  2126     }
       
  2127 
       
  2128     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  2129 
       
  2130     for (i = 0;i < val2->nodeNr;i++) {
       
  2131     /*
       
  2132      * grow the nodeTab if needed
       
  2133      */
       
  2134     if (val1->nodeMax == 0) {
       
  2135         val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
       
  2136                             sizeof(xmlNodePtr));
       
  2137         if (val1->nodeTab == NULL) {
       
  2138             xmlXPathErrMemory(NULL, EMBED_ERRTXT("merging nodeset\n"));
       
  2139         return(NULL);
       
  2140         }
       
  2141         memset(val1->nodeTab, 0 ,
       
  2142            XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
       
  2143         val1->nodeMax = XML_NODESET_DEFAULT;
       
  2144     } else if (val1->nodeNr == val1->nodeMax) {
       
  2145         xmlNodePtr *temp;
       
  2146 
       
  2147         val1->nodeMax *= 2;
       
  2148         temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
       
  2149                          sizeof(xmlNodePtr));
       
  2150         if (temp == NULL) {
       
  2151             xmlXPathErrMemory(NULL, EMBED_ERRTXT("merging nodeset\n"));
       
  2152         return(NULL);
       
  2153         }
       
  2154         val1->nodeTab = temp;
       
  2155     }
       
  2156     if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
       
  2157         xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
       
  2158 
       
  2159         val1->nodeTab[val1->nodeNr++] =
       
  2160         xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
       
  2161     } else
       
  2162         val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
       
  2163     }
       
  2164 
       
  2165     return(val1);
       
  2166 }
       
  2167 
       
  2168 /**
       
  2169  * xmlXPathNodeSetDel:
       
  2170  * @cur:  the initial node set
       
  2171  * @val:  an xmlNodePtr
       
  2172  *
       
  2173  * Removes an xmlNodePtr from an existing NodeSet
       
  2174  */
       
  2175 void
       
  2176 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
       
  2177     int i;
       
  2178 
       
  2179     if (cur == NULL) return;
       
  2180     if (val == NULL) return;
       
  2181 
       
  2182     /*
       
  2183      * find node in nodeTab
       
  2184      */
       
  2185     for (i = 0;i < cur->nodeNr;i++)
       
  2186         if (cur->nodeTab[i] == val) break;
       
  2187 
       
  2188     if (i >= cur->nodeNr) { /* not found */
       
  2189 #ifdef DEBUG
       
  2190         xmlGenericError(xmlGenericErrorContext,
       
  2191             "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
       
  2192         val->name);
       
  2193 #endif
       
  2194         return;
       
  2195     }
       
  2196     if ((cur->nodeTab[i] != NULL) &&
       
  2197     (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
       
  2198     xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
       
  2199     cur->nodeNr--;
       
  2200     for (;i < cur->nodeNr;i++)
       
  2201         cur->nodeTab[i] = cur->nodeTab[i + 1];
       
  2202     cur->nodeTab[cur->nodeNr] = NULL;
       
  2203 }
       
  2204 
       
  2205 /**
       
  2206  * xmlXPathNodeSetRemove:
       
  2207  * @cur:  the initial node set
       
  2208  * @val:  the index to remove
       
  2209  *
       
  2210  * Removes an entry from an existing NodeSet list.
       
  2211  */
       
  2212 void
       
  2213 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
       
  2214     if (cur == NULL) return;
       
  2215     if (val >= cur->nodeNr) return;
       
  2216     if ((cur->nodeTab[val] != NULL) &&
       
  2217     (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
       
  2218     xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
       
  2219     cur->nodeNr--;
       
  2220     for (;val < cur->nodeNr;val++)
       
  2221         cur->nodeTab[val] = cur->nodeTab[val + 1];
       
  2222     cur->nodeTab[cur->nodeNr] = NULL;
       
  2223 }
       
  2224 
       
  2225 /**
       
  2226  * xmlXPathFreeNodeSet:
       
  2227  * @obj:  the xmlNodeSetPtr to free
       
  2228  *
       
  2229  * Free the NodeSet compound (not the actual nodes !).
       
  2230  */
       
  2231 void
       
  2232 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
       
  2233     if (obj == NULL) return;
       
  2234     if (obj->nodeTab != NULL) {
       
  2235     int i;
       
  2236 
       
  2237     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  2238     for (i = 0;i < obj->nodeNr;i++)
       
  2239         if ((obj->nodeTab[i] != NULL) &&
       
  2240         (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
       
  2241         xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
       
  2242     xmlFree(obj->nodeTab);
       
  2243     }
       
  2244     xmlFree(obj);
       
  2245 }
       
  2246 
       
  2247 /**
       
  2248  * xmlXPathFreeValueTree:
       
  2249  * @obj:  the xmlNodeSetPtr to free
       
  2250  *
       
  2251  * Free the NodeSet compound and the actual tree, this is different
       
  2252  * from xmlXPathFreeNodeSet()
       
  2253  */
       
  2254 static void
       
  2255 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
       
  2256     int i;
       
  2257 
       
  2258     if (obj == NULL) return;
       
  2259 
       
  2260     if (obj->nodeTab != NULL) {
       
  2261     for (i = 0;i < obj->nodeNr;i++) {
       
  2262         if (obj->nodeTab[i] != NULL) {
       
  2263         if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
       
  2264             xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
       
  2265         } else {
       
  2266             xmlFreeNodeList(obj->nodeTab[i]);
       
  2267         }
       
  2268         }
       
  2269     }
       
  2270     xmlFree(obj->nodeTab);
       
  2271     }
       
  2272     xmlFree(obj);
       
  2273 }
       
  2274 
       
  2275 #if defined(DEBUG) || defined(DEBUG_STEP)
       
  2276 /**
       
  2277  * xmlGenericErrorContextNodeSet:
       
  2278  * @output:  a FILE * for the output
       
  2279  * @obj:  the xmlNodeSetPtr to display
       
  2280  *
       
  2281  * Quick display of a NodeSet
       
  2282  */
       
  2283 void
       
  2284 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
       
  2285     int i;
       
  2286 
       
  2287     if (output == NULL) output = xmlGenericErrorContext;
       
  2288     if (obj == NULL)  {
       
  2289         fprintf(output, "NodeSet == NULL !\n");
       
  2290     return;
       
  2291     }
       
  2292     if (obj->nodeNr == 0) {
       
  2293         fprintf(output, "NodeSet is empty\n");
       
  2294     return;
       
  2295     }
       
  2296     if (obj->nodeTab == NULL) {
       
  2297     fprintf(output, " nodeTab == NULL !\n");
       
  2298     return;
       
  2299     }
       
  2300     for (i = 0; i < obj->nodeNr; i++) {
       
  2301         if (obj->nodeTab[i] == NULL) {
       
  2302         fprintf(output, " NULL !\n");
       
  2303         return;
       
  2304         }
       
  2305     if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
       
  2306         (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
       
  2307         fprintf(output, " /");
       
  2308     else if (obj->nodeTab[i]->name == NULL)
       
  2309         fprintf(output, " noname!");
       
  2310     else fprintf(output, " %s", obj->nodeTab[i]->name);
       
  2311     }
       
  2312     fprintf(output, "\n");
       
  2313 }
       
  2314 #endif
       
  2315 
       
  2316 /**
       
  2317  * xmlXPathNewNodeSet:
       
  2318  * @val:  the NodePtr value
       
  2319  *
       
  2320  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
       
  2321  * it with the single Node @val
       
  2322  *
       
  2323  * Returns the newly created object.
       
  2324  */
       
  2325 xmlXPathObjectPtr
       
  2326 xmlXPathNewNodeSet(xmlNodePtr val) {
       
  2327     xmlXPathObjectPtr ret;
       
  2328 
       
  2329     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  2330     if (ret == NULL) {
       
  2331         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating nodeset\n"));
       
  2332     return(NULL);
       
  2333     }
       
  2334     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  2335     ret->type = XPATH_NODESET;
       
  2336     ret->boolval = 0;
       
  2337     ret->nodesetval = xmlXPathNodeSetCreate(val);
       
  2338     if(OOM_FLAG)
       
  2339     	{
       
  2340     	xmlXPathFreeObject(ret);
       
  2341     	return(NULL);
       
  2342     	}
       
  2343     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
       
  2344     return(ret);
       
  2345 }
       
  2346 
       
  2347 /**
       
  2348  * xmlXPathNewValueTree:
       
  2349  * @val:  the NodePtr value
       
  2350  *
       
  2351  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
       
  2352  * it with the tree root @val
       
  2353  *
       
  2354  * Returns the newly created object.
       
  2355  */
       
  2356 xmlXPathObjectPtr
       
  2357 xmlXPathNewValueTree(xmlNodePtr val) {
       
  2358     xmlXPathObjectPtr ret;
       
  2359 
       
  2360     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  2361     if (ret == NULL) {
       
  2362         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating result value tree\n"));
       
  2363     return(NULL);
       
  2364     }
       
  2365     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  2366     ret->type = XPATH_XSLT_TREE;
       
  2367     ret->boolval = 1;
       
  2368     ret->user = (void *) val;
       
  2369     ret->nodesetval = xmlXPathNodeSetCreate(val);
       
  2370     return(ret);
       
  2371 }
       
  2372 
       
  2373 /**
       
  2374  * xmlXPathNewNodeSetList:
       
  2375  * @val:  an existing NodeSet
       
  2376  *
       
  2377  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
       
  2378  * it with the Nodeset @val
       
  2379  *
       
  2380  * Returns the newly created object.
       
  2381  */
       
  2382 xmlXPathObjectPtr
       
  2383 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
       
  2384 {
       
  2385     xmlXPathObjectPtr ret;
       
  2386     int i;
       
  2387     // TODO: CHECK OOM everywhere
       
  2388     if (val == NULL)
       
  2389         ret = NULL;
       
  2390     else if (val->nodeTab == NULL)
       
  2391         ret = xmlXPathNewNodeSet(NULL);
       
  2392     else {
       
  2393         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
       
  2394         for (i = 1; i < val->nodeNr; ++i)
       
  2395             xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
       
  2396     }
       
  2397 
       
  2398     return (ret);
       
  2399 }
       
  2400 
       
  2401 /**
       
  2402  * xmlXPathWrapNodeSet:
       
  2403  * @val:  the NodePtr value
       
  2404  *
       
  2405  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
       
  2406  *
       
  2407  * Returns the newly created object.
       
  2408  */
       
  2409 xmlXPathObjectPtr
       
  2410 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
       
  2411     xmlXPathObjectPtr ret;
       
  2412 
       
  2413     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  2414     if (ret == NULL) {
       
  2415         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating node set object\n"));
       
  2416     return(NULL);
       
  2417     }
       
  2418     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  2419     ret->type = XPATH_NODESET;
       
  2420     ret->nodesetval = val;
       
  2421     return(ret);
       
  2422 }
       
  2423 
       
  2424 /**
       
  2425  * xmlXPathFreeNodeSetList:
       
  2426  * @obj:  an existing NodeSetList object
       
  2427  *
       
  2428  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
       
  2429  * the list contrary to xmlXPathFreeObject().
       
  2430  */
       
  2431 void
       
  2432 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
       
  2433     if (obj == NULL) return;
       
  2434     xmlFree(obj);
       
  2435 }
       
  2436 
       
  2437 /**
       
  2438  * xmlXPathDifference:
       
  2439  * @nodes1:  a node-set
       
  2440  * @nodes2:  a node-set
       
  2441  *
       
  2442  * Implements the EXSLT - Sets difference() function:
       
  2443  *    node-set set:difference (node-set, node-set)
       
  2444  *
       
  2445  * Returns the difference between the two node sets, or nodes1 if
       
  2446  *         nodes2 is empty
       
  2447  */
       
  2448 xmlNodeSetPtr
       
  2449 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2450     xmlNodeSetPtr ret;
       
  2451     int i, l1;
       
  2452     xmlNodePtr cur;
       
  2453 
       
  2454     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2455     return(nodes1);
       
  2456 
       
  2457     ret = xmlXPathNodeSetCreate(NULL);
       
  2458     if (xmlXPathNodeSetIsEmpty(nodes1))
       
  2459     return(ret);
       
  2460 
       
  2461     l1 = xmlXPathNodeSetGetLength(nodes1);
       
  2462 
       
  2463     for (i = 0; i < l1; i++) {
       
  2464     cur = xmlXPathNodeSetItem(nodes1, i);
       
  2465     if (!xmlXPathNodeSetContains(nodes2, cur))
       
  2466         xmlXPathNodeSetAddUnique(ret, cur);
       
  2467     }
       
  2468     return(ret);
       
  2469 }
       
  2470 
       
  2471 /**
       
  2472  * xmlXPathIntersection:
       
  2473  * @nodes1:  a node-set
       
  2474  * @nodes2:  a node-set
       
  2475  *
       
  2476  * Implements the EXSLT - Sets intersection() function:
       
  2477  *    node-set set:intersection (node-set, node-set)
       
  2478  *
       
  2479  * Returns a node set comprising the nodes that are within both the
       
  2480  *         node sets passed as arguments
       
  2481  */
       
  2482 xmlNodeSetPtr
       
  2483 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2484     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
       
  2485     int i, l1;
       
  2486     xmlNodePtr cur;
       
  2487 
       
  2488     if (xmlXPathNodeSetIsEmpty(nodes1))
       
  2489     return(ret);
       
  2490     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2491     return(ret);
       
  2492 
       
  2493     l1 = xmlXPathNodeSetGetLength(nodes1);
       
  2494 
       
  2495     for (i = 0; i < l1; i++) {
       
  2496     cur = xmlXPathNodeSetItem(nodes1, i);
       
  2497     if (xmlXPathNodeSetContains(nodes2, cur))
       
  2498         xmlXPathNodeSetAddUnique(ret, cur);
       
  2499     }
       
  2500     return(ret);
       
  2501 }
       
  2502 
       
  2503 /**
       
  2504  * xmlXPathDistinctSorted:
       
  2505  * @nodes:  a node-set, sorted by document order
       
  2506  *
       
  2507  * Implements the EXSLT - Sets distinct() function:
       
  2508  *    node-set set:distinct (node-set)
       
  2509  *
       
  2510  * Returns a subset of the nodes contained in @nodes, or @nodes if
       
  2511  *         it is empty
       
  2512  */
       
  2513 xmlNodeSetPtr
       
  2514 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
       
  2515     xmlNodeSetPtr ret;
       
  2516     xmlHashTablePtr hash;
       
  2517     int i, l;
       
  2518     xmlChar * strval;
       
  2519     xmlNodePtr cur;
       
  2520 
       
  2521     if (xmlXPathNodeSetIsEmpty(nodes))
       
  2522     return(nodes);
       
  2523 
       
  2524     ret = xmlXPathNodeSetCreate(NULL);
       
  2525     l = xmlXPathNodeSetGetLength(nodes);
       
  2526     hash = xmlHashCreate (l);
       
  2527     for (i = 0; i < l; i++) {
       
  2528     cur = xmlXPathNodeSetItem(nodes, i);
       
  2529     strval = xmlXPathCastNodeToString(cur);
       
  2530     if (xmlHashLookup(hash, strval) == NULL) {
       
  2531         xmlHashAddEntry(hash, strval, strval);
       
  2532         xmlXPathNodeSetAddUnique(ret, cur);
       
  2533     } else {
       
  2534         xmlFree(strval);
       
  2535     }
       
  2536     }
       
  2537     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
       
  2538     return(ret);
       
  2539 }
       
  2540 
       
  2541 /**
       
  2542  * xmlXPathDistinct:
       
  2543  * @nodes:  a node-set
       
  2544  *
       
  2545  * Implements the EXSLT - Sets distinct() function:
       
  2546  *    node-set set:distinct (node-set)
       
  2547  * @nodes is sorted by document order, then #exslSetsDistinctSorted
       
  2548  * is called with the sorted node-set
       
  2549  *
       
  2550  * Returns a subset of the nodes contained in @nodes, or @nodes if
       
  2551  *         it is empty
       
  2552  */
       
  2553 xmlNodeSetPtr
       
  2554 xmlXPathDistinct (xmlNodeSetPtr nodes) {
       
  2555     if (xmlXPathNodeSetIsEmpty(nodes))
       
  2556     return(nodes);
       
  2557 
       
  2558     xmlXPathNodeSetSort(nodes);
       
  2559     return(xmlXPathDistinctSorted(nodes));
       
  2560 }
       
  2561 
       
  2562 /**
       
  2563  * xmlXPathHasSameNodes:
       
  2564  * @nodes1:  a node-set
       
  2565  * @nodes2:  a node-set
       
  2566  *
       
  2567  * Implements the EXSLT - Sets has-same-nodes function:
       
  2568  *    boolean set:has-same-node(node-set, node-set)
       
  2569  *
       
  2570  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
       
  2571  *         otherwise
       
  2572  */
       
  2573 int
       
  2574 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2575     int i, l;
       
  2576     xmlNodePtr cur;
       
  2577 
       
  2578     if (xmlXPathNodeSetIsEmpty(nodes1) ||
       
  2579     xmlXPathNodeSetIsEmpty(nodes2))
       
  2580     return(0);
       
  2581 
       
  2582     l = xmlXPathNodeSetGetLength(nodes1);
       
  2583     for (i = 0; i < l; i++) {
       
  2584     cur = xmlXPathNodeSetItem(nodes1, i);
       
  2585     if (xmlXPathNodeSetContains(nodes2, cur))
       
  2586         return(1);
       
  2587     }
       
  2588     return(0);
       
  2589 }
       
  2590 
       
  2591 /**
       
  2592  * xmlXPathNodeLeadingSorted:
       
  2593  * @nodes: a node-set, sorted by document order
       
  2594  * @node: a node
       
  2595  *
       
  2596  * Implements the EXSLT - Sets leading() function:
       
  2597  *    node-set set:leading (node-set, node-set)
       
  2598  *
       
  2599  * Returns the nodes in @nodes that precede @node in document order,
       
  2600  *         @nodes if @node is NULL or an empty node-set if @nodes
       
  2601  *         doesn't contain @node
       
  2602  */
       
  2603 xmlNodeSetPtr
       
  2604 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
       
  2605     int i, l;
       
  2606     xmlNodePtr cur;
       
  2607     xmlNodeSetPtr ret;
       
  2608 
       
  2609     if (node == NULL)
       
  2610     return(nodes);
       
  2611 
       
  2612     ret = xmlXPathNodeSetCreate(NULL);
       
  2613     if (xmlXPathNodeSetIsEmpty(nodes) ||
       
  2614     (!xmlXPathNodeSetContains(nodes, node)))
       
  2615     return(ret);
       
  2616 
       
  2617     l = xmlXPathNodeSetGetLength(nodes);
       
  2618     for (i = 0; i < l; i++) {
       
  2619     cur = xmlXPathNodeSetItem(nodes, i);
       
  2620     if (cur == node)
       
  2621         break;
       
  2622     xmlXPathNodeSetAddUnique(ret, cur);
       
  2623     }
       
  2624     return(ret);
       
  2625 }
       
  2626 
       
  2627 /**
       
  2628  * xmlXPathNodeLeading:
       
  2629  * @nodes:  a node-set
       
  2630  * @node:  a node
       
  2631  *
       
  2632  * Implements the EXSLT - Sets leading() function:
       
  2633  *    node-set set:leading (node-set, node-set)
       
  2634  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
       
  2635  * is called.
       
  2636  *
       
  2637  * Returns the nodes in @nodes that precede @node in document order,
       
  2638  *         @nodes if @node is NULL or an empty node-set if @nodes
       
  2639  *         doesn't contain @node
       
  2640  */
       
  2641 xmlNodeSetPtr
       
  2642 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
       
  2643     xmlXPathNodeSetSort(nodes);
       
  2644     return(xmlXPathNodeLeadingSorted(nodes, node));
       
  2645 }
       
  2646 
       
  2647 /**
       
  2648  * xmlXPathLeadingSorted:
       
  2649  * @nodes1:  a node-set, sorted by document order
       
  2650  * @nodes2:  a node-set, sorted by document order
       
  2651  *
       
  2652  * Implements the EXSLT - Sets leading() function:
       
  2653  *    node-set set:leading (node-set, node-set)
       
  2654  *
       
  2655  * Returns the nodes in @nodes1 that precede the first node in @nodes2
       
  2656  *         in document order, @nodes1 if @nodes2 is NULL or empty or
       
  2657  *         an empty node-set if @nodes1 doesn't contain @nodes2
       
  2658  */
       
  2659 xmlNodeSetPtr
       
  2660 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2661     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2662     return(nodes1);
       
  2663     return(xmlXPathNodeLeadingSorted(nodes1,
       
  2664                      xmlXPathNodeSetItem(nodes2, 1)));
       
  2665 }
       
  2666 
       
  2667 /**
       
  2668  * xmlXPathLeading:
       
  2669  * @nodes1:  a node-set
       
  2670  * @nodes2:  a node-set
       
  2671  *
       
  2672  * Implements the EXSLT - Sets leading() function:
       
  2673  *    node-set set:leading (node-set, node-set)
       
  2674  * @nodes1 and @nodes2 are sorted by document order, then
       
  2675  * #exslSetsLeadingSorted is called.
       
  2676  *
       
  2677  * Returns the nodes in @nodes1 that precede the first node in @nodes2
       
  2678  *         in document order, @nodes1 if @nodes2 is NULL or empty or
       
  2679  *         an empty node-set if @nodes1 doesn't contain @nodes2
       
  2680  */
       
  2681 xmlNodeSetPtr
       
  2682 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2683     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2684     return(nodes1);
       
  2685     if (xmlXPathNodeSetIsEmpty(nodes1))
       
  2686     return(xmlXPathNodeSetCreate(NULL));
       
  2687     xmlXPathNodeSetSort(nodes1);
       
  2688     xmlXPathNodeSetSort(nodes2);
       
  2689     return(xmlXPathNodeLeadingSorted(nodes1,
       
  2690                      xmlXPathNodeSetItem(nodes2, 1)));
       
  2691 }
       
  2692 
       
  2693 /**
       
  2694  * xmlXPathNodeTrailingSorted:
       
  2695  * @nodes: a node-set, sorted by document order
       
  2696  * @node: a node
       
  2697  *
       
  2698  * Implements the EXSLT - Sets trailing() function:
       
  2699  *    node-set set:trailing (node-set, node-set)
       
  2700  *
       
  2701  * Returns the nodes in @nodes that follow @node in document order,
       
  2702  *         @nodes if @node is NULL or an empty node-set if @nodes
       
  2703  *         doesn't contain @node
       
  2704  */
       
  2705 xmlNodeSetPtr
       
  2706 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
       
  2707     int i, l;
       
  2708     xmlNodePtr cur;
       
  2709     xmlNodeSetPtr ret;
       
  2710 
       
  2711     if (node == NULL)
       
  2712     return(nodes);
       
  2713 
       
  2714     ret = xmlXPathNodeSetCreate(NULL);
       
  2715     if (xmlXPathNodeSetIsEmpty(nodes) ||
       
  2716     (!xmlXPathNodeSetContains(nodes, node)))
       
  2717     return(ret);
       
  2718 
       
  2719     l = xmlXPathNodeSetGetLength(nodes);
       
  2720     for (i = l; i > 0; i--) {
       
  2721     cur = xmlXPathNodeSetItem(nodes, i);
       
  2722     if (cur == node)
       
  2723         break;
       
  2724     xmlXPathNodeSetAddUnique(ret, cur);
       
  2725     }
       
  2726     return(ret);
       
  2727 }
       
  2728 
       
  2729 /**
       
  2730  * xmlXPathNodeTrailing:
       
  2731  * @nodes:  a node-set
       
  2732  * @node:  a node
       
  2733  *
       
  2734  * Implements the EXSLT - Sets trailing() function:
       
  2735  *    node-set set:trailing (node-set, node-set)
       
  2736  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
       
  2737  * is called.
       
  2738  *
       
  2739  * Returns the nodes in @nodes that follow @node in document order,
       
  2740  *         @nodes if @node is NULL or an empty node-set if @nodes
       
  2741  *         doesn't contain @node
       
  2742  */
       
  2743 xmlNodeSetPtr
       
  2744 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
       
  2745     xmlXPathNodeSetSort(nodes);
       
  2746     return(xmlXPathNodeTrailingSorted(nodes, node));
       
  2747 }
       
  2748 
       
  2749 /**
       
  2750  * xmlXPathTrailingSorted:
       
  2751  * @nodes1:  a node-set, sorted by document order
       
  2752  * @nodes2:  a node-set, sorted by document order
       
  2753  *
       
  2754  * Implements the EXSLT - Sets trailing() function:
       
  2755  *    node-set set:trailing (node-set, node-set)
       
  2756  *
       
  2757  * Returns the nodes in @nodes1 that follow the first node in @nodes2
       
  2758  *         in document order, @nodes1 if @nodes2 is NULL or empty or
       
  2759  *         an empty node-set if @nodes1 doesn't contain @nodes2
       
  2760  */
       
  2761 xmlNodeSetPtr
       
  2762 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2763     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2764     return(nodes1);
       
  2765     return(xmlXPathNodeTrailingSorted(nodes1,
       
  2766                       xmlXPathNodeSetItem(nodes2, 0)));
       
  2767 }
       
  2768 
       
  2769 /**
       
  2770  * xmlXPathTrailing:
       
  2771  * @nodes1:  a node-set
       
  2772  * @nodes2:  a node-set
       
  2773  *
       
  2774  * Implements the EXSLT - Sets trailing() function:
       
  2775  *    node-set set:trailing (node-set, node-set)
       
  2776  * @nodes1 and @nodes2 are sorted by document order, then
       
  2777  * #xmlXPathTrailingSorted is called.
       
  2778  *
       
  2779  * Returns the nodes in @nodes1 that follow the first node in @nodes2
       
  2780  *         in document order, @nodes1 if @nodes2 is NULL or empty or
       
  2781  *         an empty node-set if @nodes1 doesn't contain @nodes2
       
  2782  */
       
  2783 xmlNodeSetPtr
       
  2784 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
       
  2785     if (xmlXPathNodeSetIsEmpty(nodes2))
       
  2786     return(nodes1);
       
  2787     if (xmlXPathNodeSetIsEmpty(nodes1))
       
  2788     return(xmlXPathNodeSetCreate(NULL));
       
  2789     xmlXPathNodeSetSort(nodes1);
       
  2790     xmlXPathNodeSetSort(nodes2);
       
  2791     return(xmlXPathNodeTrailingSorted(nodes1,
       
  2792                       xmlXPathNodeSetItem(nodes2, 0)));
       
  2793 }
       
  2794 
       
  2795 /************************************************************************
       
  2796  *                                                                      *
       
  2797  *      Routines to handle extra functions                              *
       
  2798  *                                                                      *
       
  2799  ************************************************************************/
       
  2800 
       
  2801 /**
       
  2802  * xmlXPathRegisterFunc:
       
  2803  * @ctxt:  the XPath context
       
  2804  * @name:  the function name
       
  2805  * @f:  the function implementation or NULL
       
  2806  *
       
  2807  * Register a new function. If @f is NULL it unregisters the function
       
  2808  *
       
  2809  * Returns 0 in case of success, -1 in case of error
       
  2810  */
       
  2811 int
       
  2812 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
       
  2813              xmlXPathFunction f) {
       
  2814     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
       
  2815 }
       
  2816 
       
  2817 /**
       
  2818  * xmlXPathRegisterFuncNS:
       
  2819  * @ctxt:  the XPath context
       
  2820  * @name:  the function name
       
  2821  * @ns_uri:  the function namespace URI
       
  2822  * @f:  the function implementation or NULL
       
  2823  *
       
  2824  * Register a new function. If @f is NULL it unregisters the function
       
  2825  *
       
  2826  * Returns 0 in case of success, -1 in case of error
       
  2827  */
       
  2828 int
       
  2829 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
       
  2830                const xmlChar *ns_uri, xmlXPathFunction f) {
       
  2831     if (ctxt == NULL || name == NULL)
       
  2832         return(-1);
       
  2833 
       
  2834     if (ctxt->funcHash == NULL)
       
  2835         ctxt->funcHash = xmlHashCreate(0);
       
  2836     if (ctxt->funcHash == NULL)
       
  2837         return(-1);
       
  2838 
       
  2839     if (f == NULL)
       
  2840         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
       
  2841     if( xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *)f) < 0)
       
  2842     	{
       
  2843     	xmlHashFree(ctxt->funcHash, NULL);
       
  2844     	return(-1);	
       
  2845     	}
       
  2846 	return(0);
       
  2847 }
       
  2848 
       
  2849 /**
       
  2850  * xmlXPathRegisterFuncLookup:
       
  2851  * @ctxt:  the XPath context
       
  2852  * @f:  the lookup function
       
  2853  * @funcCtxt:  the lookup data
       
  2854  *
       
  2855  * Registers an external mechanism to do function lookup.
       
  2856  */
       
  2857 void
       
  2858 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
       
  2859                 xmlXPathFuncLookupFunc f,
       
  2860                 void *funcCtxt) {
       
  2861     if (ctxt == NULL)
       
  2862         return;
       
  2863     ctxt->funcLookupFunc = (void *) f;
       
  2864     ctxt->funcLookupData = funcCtxt;
       
  2865 }
       
  2866 
       
  2867 /**
       
  2868  * xmlXPathFunctionLookup:
       
  2869  * @ctxt:  the XPath context
       
  2870  * @name:  the function name
       
  2871  *
       
  2872  * Search in the Function array of the context for the given
       
  2873  * function.
       
  2874  *
       
  2875  * Returns the xmlXPathFunction or NULL if not found
       
  2876  */
       
  2877 xmlXPathFunction
       
  2878 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
       
  2879     if (ctxt == NULL)
       
  2880         return (NULL);
       
  2881 
       
  2882     if (ctxt->funcLookupFunc != NULL) {
       
  2883         xmlXPathFunction ret;
       
  2884         xmlXPathFuncLookupFunc f;
       
  2885 
       
  2886         f =  (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
       
  2887         ret = f(ctxt->funcLookupData, name, NULL);
       
  2888         if (ret != NULL)
       
  2889             return(ret);
       
  2890     }
       
  2891     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
       
  2892 }
       
  2893 
       
  2894 /**
       
  2895  * xmlXPathFunctionLookupNS:
       
  2896  * @ctxt:  the XPath context
       
  2897  * @name:  the function name
       
  2898  * @ns_uri:  the function namespace URI
       
  2899  *
       
  2900  * Search in the Function array of the context for the given
       
  2901  * function.
       
  2902  *
       
  2903  * Returns the xmlXPathFunction or NULL if not found
       
  2904  */
       
  2905 xmlXPathFunction
       
  2906 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri) {
       
  2907     if (ctxt == NULL)
       
  2908         return(NULL);
       
  2909     if (name == NULL)
       
  2910         return(NULL);
       
  2911 
       
  2912     if (ctxt->funcLookupFunc != NULL) {
       
  2913         xmlXPathFunction ret;
       
  2914         xmlXPathFuncLookupFunc f;
       
  2915 
       
  2916         f =  (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
       
  2917         ret = f(ctxt->funcLookupData, name, ns_uri);
       
  2918         if (ret != NULL)
       
  2919             return(ret);
       
  2920     }
       
  2921 
       
  2922     if (ctxt->funcHash == NULL)
       
  2923         return(NULL);
       
  2924 
       
  2925     return (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
       
  2926 }
       
  2927 
       
  2928 /**
       
  2929  * xmlXPathRegisteredFuncsCleanup:
       
  2930  * @ctxt:  the XPath context
       
  2931  *
       
  2932  * Cleanup the XPath context data associated to registered functions
       
  2933  */
       
  2934 void
       
  2935 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
       
  2936     if (ctxt == NULL)
       
  2937         return;
       
  2938 
       
  2939     xmlHashFree(ctxt->funcHash, NULL);
       
  2940     ctxt->funcHash = NULL;
       
  2941 }
       
  2942 
       
  2943 /************************************************************************
       
  2944  *                                  *
       
  2945  *          Routines to handle Variables            *
       
  2946  *                                  *
       
  2947  ************************************************************************/
       
  2948 
       
  2949 /**
       
  2950  * xmlXPathRegisterVariable:
       
  2951  * @ctxt:  the XPath context
       
  2952  * @name:  the variable name
       
  2953  * @value:  the variable value or NULL
       
  2954  *
       
  2955  * Register a new variable value. If @value is NULL it unregisters
       
  2956  * the variable
       
  2957  *
       
  2958  * Returns 0 in case of success, -1 in case of error
       
  2959  */
       
  2960 int
       
  2961 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
       
  2962              xmlXPathObjectPtr value) {
       
  2963     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
       
  2964 }
       
  2965 
       
  2966 /**
       
  2967  * xmlXPathRegisterVariableNS:
       
  2968  * @ctxt:  the XPath context
       
  2969  * @name:  the variable name
       
  2970  * @ns_uri:  the variable namespace URI
       
  2971  * @value:  the variable value or NULL
       
  2972  *
       
  2973  * Register a new variable value. If @value is NULL it unregisters
       
  2974  * the variable
       
  2975  *
       
  2976  * Returns 0 in case of success, -1 in case of error
       
  2977  */
       
  2978 int
       
  2979 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
       
  2980                const xmlChar *ns_uri,
       
  2981                xmlXPathObjectPtr value) {
       
  2982     if (ctxt == NULL)
       
  2983     return(-1);
       
  2984     if (name == NULL)
       
  2985     return(-1);
       
  2986 
       
  2987     if (ctxt->varHash == NULL)
       
  2988     ctxt->varHash = xmlHashCreate(0);
       
  2989     if (ctxt->varHash == NULL)
       
  2990     return(-1);
       
  2991     if (value == NULL)
       
  2992         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
       
  2993                                (xmlHashDeallocator)xmlXPathFreeObject));
       
  2994     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
       
  2995                    (void *) value,
       
  2996                    (xmlHashDeallocator)xmlXPathFreeObject));
       
  2997 }
       
  2998 
       
  2999 /**
       
  3000  * xmlXPathRegisterVariableLookup:
       
  3001  * @ctxt:  the XPath context
       
  3002  * @f:  the lookup function
       
  3003  * @data:  the lookup data
       
  3004  *
       
  3005  * register an external mechanism to do variable lookup
       
  3006  */
       
  3007 void
       
  3008 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
       
  3009      xmlXPathVariableLookupFunc f, void *data) {
       
  3010     if (ctxt == NULL)
       
  3011     return;
       
  3012     ctxt->varLookupFunc = (void *) f;
       
  3013     ctxt->varLookupData = data;
       
  3014 }
       
  3015 
       
  3016 /**
       
  3017  * xmlXPathVariableLookup:
       
  3018  * @ctxt:  the XPath context
       
  3019  * @name:  the variable name
       
  3020  *
       
  3021  * Search in the Variable array of the context for the given
       
  3022  * variable value.
       
  3023  *
       
  3024  * Returns a copy of the value or NULL if not found
       
  3025  */
       
  3026 xmlXPathObjectPtr
       
  3027 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
       
  3028     if (ctxt == NULL)
       
  3029         return(NULL);
       
  3030 
       
  3031     if (ctxt->varLookupFunc != NULL) {
       
  3032         xmlXPathVariableLookupFunc func = (xmlXPathVariableLookupFunc)ctxt->varLookupFunc;
       
  3033         xmlXPathObjectPtr ret = func(ctxt->varLookupData, name, NULL);
       
  3034         return(ret);
       
  3035     }
       
  3036     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
       
  3037 }
       
  3038 
       
  3039 /**
       
  3040  * xmlXPathVariableLookupNS:
       
  3041  * @ctxt:  the XPath context
       
  3042  * @name:  the variable name
       
  3043  * @ns_uri:  the variable namespace URI
       
  3044  *
       
  3045  * Search in the Variable array of the context for the given
       
  3046  * variable value.
       
  3047  *
       
  3048  * Returns the a copy of the value or NULL if not found
       
  3049  */
       
  3050 xmlXPathObjectPtr
       
  3051 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
       
  3052              const xmlChar *ns_uri) {
       
  3053     if (ctxt == NULL)
       
  3054         return(NULL);
       
  3055 
       
  3056     if (ctxt->varLookupFunc != NULL) {
       
  3057         xmlXPathVariableLookupFunc lookupFunc = (xmlXPathVariableLookupFunc)ctxt->varLookupFunc;
       
  3058         xmlXPathObjectPtr ret = lookupFunc(ctxt->varLookupData, name, ns_uri);
       
  3059         if (ret != NULL)
       
  3060             return(ret);
       
  3061     }
       
  3062 
       
  3063     if (ctxt->varHash == NULL)
       
  3064         return(NULL);
       
  3065     if (name == NULL)
       
  3066         return(NULL);
       
  3067 
       
  3068     return(xmlXPathObjectCopy((xmlXPathObjectPtr)
       
  3069             xmlHashLookup2(ctxt->varHash, name, ns_uri)));
       
  3070 }
       
  3071 
       
  3072 /**
       
  3073  * xmlXPathRegisteredVariablesCleanup:
       
  3074  * @ctxt:  the XPath context
       
  3075  *
       
  3076  * Cleanup the XPath context data associated to registered variables
       
  3077  */
       
  3078 void
       
  3079 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
       
  3080     if (ctxt == NULL)
       
  3081     return;
       
  3082 
       
  3083     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
       
  3084     ctxt->varHash = NULL;
       
  3085 }
       
  3086 
       
  3087 /**
       
  3088  * xmlXPathRegisterNs:
       
  3089  * @ctxt:  the XPath context
       
  3090  * @prefix:  the namespace prefix
       
  3091  * @ns_uri:  the namespace name
       
  3092  *
       
  3093  * Register a new namespace. If @ns_uri is NULL it unregisters
       
  3094  * the namespace
       
  3095  *
       
  3096  * Returns 0 in case of success, -1 in case of error
       
  3097  */
       
  3098 int
       
  3099 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
       
  3100                const xmlChar *ns_uri) {
       
  3101     int res = -1;
       
  3102     xmlChar* uri = NULL;
       
  3103 
       
  3104     if (ctxt == NULL)
       
  3105         return(-1);
       
  3106     if (prefix == NULL)
       
  3107         return(-1);
       
  3108     
       
  3109     if (ctxt->nsHash == NULL)
       
  3110     ctxt->nsHash = xmlHashCreate(10);
       
  3111     if (ctxt->nsHash == NULL)
       
  3112     return(-1);
       
  3113     if (!ns_uri)
       
  3114         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,(xmlHashDeallocator)xmlFree));
       
  3115     uri = xmlStrdup(ns_uri);
       
  3116     if (uri) 
       
  3117         {
       
  3118         res = xmlHashUpdateEntry(ctxt->nsHash, prefix, (void*)uri,
       
  3119                   (xmlHashDeallocator)xmlFree);
       
  3120         if ( res == -1)
       
  3121             xmlFree( uri );
       
  3122         }    
       
  3123     return( res );
       
  3124 }
       
  3125 
       
  3126 /**
       
  3127  * xmlXPathNsLookup:
       
  3128  * @ctxt:  the XPath context
       
  3129  * @prefix:  the namespace prefix value
       
  3130  *
       
  3131  * Search in the namespace declaration array of the context for the given
       
  3132  * namespace name associated to the given prefix
       
  3133  *
       
  3134  * Returns the value or NULL if not found
       
  3135  */
       
  3136 const xmlChar *
       
  3137 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
       
  3138     if (ctxt == NULL)
       
  3139     return(NULL);
       
  3140     if (prefix == NULL)
       
  3141     return(NULL);
       
  3142 
       
  3143 #ifdef XML_XML_NAMESPACE
       
  3144     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
       
  3145     return(XML_XML_NAMESPACE);
       
  3146 #endif
       
  3147 
       
  3148     if (ctxt->namespaces != NULL) {
       
  3149     int i;
       
  3150 
       
  3151     for (i = 0;i < ctxt->nsNr;i++) {
       
  3152         if ((ctxt->namespaces[i] != NULL) &&
       
  3153         (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
       
  3154         return(ctxt->namespaces[i]->href);
       
  3155     }
       
  3156     }
       
  3157 
       
  3158     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
       
  3159 }
       
  3160 
       
  3161 /**
       
  3162  * xmlXPathRegisteredNsCleanup:
       
  3163  * @ctxt:  the XPath context
       
  3164  *
       
  3165  * Cleanup the XPath context data associated to registered variables
       
  3166  */
       
  3167 void
       
  3168 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
       
  3169     if (ctxt == NULL)
       
  3170     return;
       
  3171 
       
  3172     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
       
  3173     ctxt->nsHash = NULL;
       
  3174 }
       
  3175 
       
  3176 /************************************************************************
       
  3177  *                                  *
       
  3178  *          Routines to handle Values           *
       
  3179  *                                  *
       
  3180  ************************************************************************/
       
  3181 
       
  3182 /* Allocations are terrible, one needs to optimize all this !!! */
       
  3183 
       
  3184 /**
       
  3185  * xmlXPathNewFloat:
       
  3186  * @val:  the double value
       
  3187  *
       
  3188  * Create a new xmlXPathObjectPtr of type double and of value @val
       
  3189  *
       
  3190  * Returns the newly created object.
       
  3191  */
       
  3192 xmlXPathObjectPtr
       
  3193 xmlXPathNewFloat(double val) {
       
  3194     xmlXPathObjectPtr ret;
       
  3195 
       
  3196     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3197     if (ret == NULL) {
       
  3198         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating float object\n"));
       
  3199     return(NULL);
       
  3200     }
       
  3201     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3202     ret->type = XPATH_NUMBER;
       
  3203     ret->floatval = val;
       
  3204     return(ret);
       
  3205 }
       
  3206 
       
  3207 /**
       
  3208  * xmlXPathNewBoolean:
       
  3209  * @val:  the boolean value
       
  3210  *
       
  3211  * Create a new xmlXPathObjectPtr of type boolean and of value @val
       
  3212  *
       
  3213  * Returns the newly created object.
       
  3214  */
       
  3215 xmlXPathObjectPtr
       
  3216 xmlXPathNewBoolean(int val) {
       
  3217     xmlXPathObjectPtr ret;
       
  3218 
       
  3219     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3220     if (ret == NULL) {
       
  3221         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating boolean object\n"));
       
  3222     return(NULL);
       
  3223     }
       
  3224     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3225     ret->type = XPATH_BOOLEAN;
       
  3226     ret->boolval = (val != 0);
       
  3227     return(ret);
       
  3228 }
       
  3229 
       
  3230 /**
       
  3231  * xmlXPathNewString:
       
  3232  * @val:  the xmlChar * value
       
  3233  *
       
  3234  * Create a new xmlXPathObjectPtr of type string and of value @val
       
  3235  *
       
  3236  * Returns the newly created object or NULL if OOM
       
  3237  *
       
  3238  * OOM: possible --> sets OOM flag
       
  3239  */
       
  3240 xmlXPathObjectPtr
       
  3241 xmlXPathNewString(const xmlChar *val) {
       
  3242     xmlXPathObjectPtr ret;
       
  3243     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3244     if (ret == NULL) {
       
  3245         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating string object\n"));
       
  3246         return(NULL);
       
  3247     }
       
  3248     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3249     ret->type = XPATH_STRING;
       
  3250     ret->stringval = xmlStrdup(val ? val : (const xmlChar *)"");
       
  3251     if( OOM_FLAG ) 
       
  3252     	{
       
  3253       	xmlXPathFreeObject(ret);
       
  3254       	return(NULL);
       
  3255      	}    
       
  3256     return(ret);
       
  3257 }
       
  3258 
       
  3259 /**
       
  3260  * xmlXPathWrapString:
       
  3261  * @val:  the xmlChar * value
       
  3262  *
       
  3263  * Wraps the @val string into an XPath object.
       
  3264  *
       
  3265  * Returns the newly created object.
       
  3266  */
       
  3267 xmlXPathObjectPtr
       
  3268 xmlXPathWrapString (xmlChar *val) {
       
  3269     xmlXPathObjectPtr ret;
       
  3270 
       
  3271     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3272     if (ret == NULL) {
       
  3273         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating string object\n"));
       
  3274     return(NULL);
       
  3275     }
       
  3276     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3277     ret->type = XPATH_STRING;
       
  3278     ret->stringval = val;
       
  3279     return(ret);
       
  3280 }
       
  3281 
       
  3282 /**
       
  3283  * xmlXPathNewCString:
       
  3284  * @val:  the char * value
       
  3285  *
       
  3286  * Create a new xmlXPathObjectPtr of type string and of value @val
       
  3287  *
       
  3288  * Returns the newly created object.
       
  3289  */
       
  3290 xmlXPathObjectPtr
       
  3291 xmlXPathNewCString(const char *val) {
       
  3292     xmlXPathObjectPtr ret;
       
  3293 
       
  3294     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3295     if (ret == NULL) {
       
  3296         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating string object\n"));
       
  3297     return(NULL);
       
  3298     }
       
  3299     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3300     ret->type = XPATH_STRING;
       
  3301     ret->stringval = xmlStrdup(BAD_CAST val);
       
  3302     if(OOM_FLAG)
       
  3303     	{
       
  3304     	xmlXPathFreeObject(ret);
       
  3305     	return(NULL);
       
  3306     	}    
       
  3307     return(ret);
       
  3308 }
       
  3309 
       
  3310 /**
       
  3311  * xmlXPathWrapCString:
       
  3312  * @val:  the char * value
       
  3313  *
       
  3314  * Wraps a string into an XPath object.
       
  3315  *
       
  3316  * Returns the newly created object.
       
  3317  */
       
  3318 xmlXPathObjectPtr
       
  3319 xmlXPathWrapCString (char * val) {
       
  3320     return(xmlXPathWrapString((xmlChar *)(val)));
       
  3321 }
       
  3322 
       
  3323 /**
       
  3324  * xmlXPathWrapExternal:
       
  3325  * @val:  the user data
       
  3326  *
       
  3327  * Wraps the @val data into an XPath object.
       
  3328  *
       
  3329  * Returns the newly created object.
       
  3330  */
       
  3331 xmlXPathObjectPtr
       
  3332 xmlXPathWrapExternal (void *val) {
       
  3333     xmlXPathObjectPtr ret;
       
  3334 
       
  3335     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3336     if (ret == NULL) {
       
  3337         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating user object\n"));
       
  3338     return(NULL);
       
  3339     }
       
  3340     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
  3341     ret->type = XPATH_USERS;
       
  3342     ret->user = val;
       
  3343     return(ret);
       
  3344 }
       
  3345 
       
  3346 /**
       
  3347  * xmlXPathObjectCopy:
       
  3348  * @val:  the original object
       
  3349  *
       
  3350  * allocate a new copy of a given object
       
  3351  *
       
  3352  * Returns the newly created object or NULL if OOM
       
  3353  */
       
  3354 xmlXPathObjectPtr
       
  3355 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
       
  3356     xmlXPathObjectPtr ret;
       
  3357 
       
  3358     if (val == NULL)
       
  3359     return(NULL);
       
  3360 
       
  3361     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
  3362     if (ret == NULL) {
       
  3363         xmlXPathErrMemory(NULL, EMBED_ERRTXT("copying object\n"));
       
  3364     return(NULL);
       
  3365     }
       
  3366     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
       
  3367     switch (val->type) {
       
  3368     case XPATH_BOOLEAN:
       
  3369     case XPATH_NUMBER:
       
  3370     case XPATH_POINT:
       
  3371     case XPATH_RANGE:
       
  3372         break;
       
  3373     case XPATH_STRING:
       
  3374         ret->stringval = xmlStrdup(val->stringval);
       
  3375         if( OOM_FLAG ) 
       
  3376         	{
       
  3377         	xmlXPathFreeObject(ret);
       
  3378         	return(NULL);
       
  3379         	}
       
  3380         break;
       
  3381     case XPATH_XSLT_TREE:
       
  3382         if ((val->nodesetval != NULL) &&
       
  3383         (val->nodesetval->nodeTab != NULL)) {
       
  3384         xmlNodePtr cur, tmp;
       
  3385         xmlDocPtr top;
       
  3386 
       
  3387         ret->boolval = 1;
       
  3388         top =  xmlNewDoc(NULL);
       
  3389         top->name = (char *)
       
  3390             xmlStrdup(val->nodesetval->nodeTab[0]->name);
       
  3391         ret->user = top;
       
  3392         if (top != NULL) {
       
  3393             top->doc = top;
       
  3394             cur = val->nodesetval->nodeTab[0]->children;
       
  3395             while (cur != NULL) {
       
  3396             tmp = xmlDocCopyNode(cur, top, 1);
       
  3397             xmlAddChild((xmlNodePtr) top, tmp);
       
  3398             cur = cur->next;
       
  3399             }
       
  3400         }
       
  3401         ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
       
  3402         } else
       
  3403         ret->nodesetval = xmlXPathNodeSetCreate(NULL);
       
  3404         /* Deallocate the copied tree value */
       
  3405         break;
       
  3406     case XPATH_NODESET:
       
  3407         ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
       
  3408         /* Do not deallocate the copied tree value */
       
  3409         ret->boolval = 0;
       
  3410         break;
       
  3411     case XPATH_LOCATIONSET:
       
  3412 #ifdef LIBXML_XPTR_ENABLED
       
  3413     {
       
  3414         xmlLocationSetPtr loc = val->user;
       
  3415         ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
       
  3416         break;
       
  3417     }
       
  3418 #endif
       
  3419         case XPATH_USERS:
       
  3420         ret->user = val->user;
       
  3421         break;
       
  3422         case XPATH_UNDEFINED:
       
  3423         xmlGenericError(xmlGenericErrorContext,
       
  3424             EMBED_ERRTXT("xmlXPathObjectCopy: unsupported type %d\n"),
       
  3425             val->type);
       
  3426         break;
       
  3427     }
       
  3428     return(ret);
       
  3429 }
       
  3430 
       
  3431 /**
       
  3432  * xmlXPathFreeObject:
       
  3433  * @obj:  the object to free
       
  3434  *
       
  3435  * Free up an xmlXPathObjectPtr object.
       
  3436  */
       
  3437 // TODO: OPTIMIZE: Some reduction of function calls is possible...
       
  3438 //       Consider using own version of this function
       
  3439 void
       
  3440 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
       
  3441     if (obj == NULL) return;
       
  3442     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
       
  3443         if (obj->boolval) {
       
  3444             if (obj->user != NULL) {
       
  3445                 xmlXPathFreeNodeSet(obj->nodesetval);
       
  3446                 xmlFreeNodeList((xmlNodePtr) obj->user);
       
  3447             } else
       
  3448             if (obj->nodesetval != NULL)
       
  3449                 xmlXPathFreeValueTree(obj->nodesetval);
       
  3450         } else {
       
  3451             if (obj->nodesetval != NULL)
       
  3452                 xmlXPathFreeNodeSet(obj->nodesetval);
       
  3453         }
       
  3454 #ifdef LIBXML_XPTR_ENABLED
       
  3455     } else if (obj->type == XPATH_LOCATIONSET) {
       
  3456     if (obj->user != NULL)
       
  3457         xmlXPtrFreeLocationSet(obj->user);
       
  3458 #endif
       
  3459     } else if (obj->type == XPATH_STRING) {
       
  3460     if (obj->stringval != NULL)
       
  3461         xmlFree(obj->stringval);
       
  3462     }
       
  3463 
       
  3464     xmlFree(obj);
       
  3465 }
       
  3466 
       
  3467 
       
  3468 /************************************************************************
       
  3469  *                                                                      *
       
  3470  *          Type Casting Routines                                       *
       
  3471  *                                                                      *
       
  3472  ************************************************************************/
       
  3473 
       
  3474 /**
       
  3475  * xmlXPathCastBooleanToString:
       
  3476  * @val:  a boolean
       
  3477  *
       
  3478  * Converts a boolean to its string value.
       
  3479  *
       
  3480  * Returns a newly allocated string.
       
  3481  */
       
  3482 xmlChar *
       
  3483 xmlXPathCastBooleanToString (int val) {
       
  3484     xmlChar *ret;
       
  3485     if (val)
       
  3486         ret = xmlStrdup((const xmlChar*) "true");
       
  3487     else
       
  3488         ret = xmlStrdup((const xmlChar*) "false");
       
  3489     return(ret);
       
  3490 }
       
  3491 
       
  3492 /**
       
  3493  * xmlXPathCastNumberToString:
       
  3494  * @val:  a number
       
  3495  *
       
  3496  * Converts a number to its string value.
       
  3497  *
       
  3498  * Returns a newly allocated string.
       
  3499  *
       
  3500  * OOM: possible --> returns NULL, OOM flag is set
       
  3501  */
       
  3502 xmlChar*
       
  3503 xmlXPathCastNumberToString (double val) {
       
  3504     xmlChar *ret;
       
  3505     switch (xmlXPathIsInf(val)) {
       
  3506     case 1:
       
  3507         ret = xmlStrdup((const xmlChar*) "Infinity");
       
  3508         break;
       
  3509     case -1:
       
  3510         ret = xmlStrdup((const xmlChar*) "-Infinity");
       
  3511         break;
       
  3512     default:
       
  3513         if (xmlXPathIsNaN(val)) {
       
  3514             ret = xmlStrdup((const xmlChar*) "NaN");
       
  3515         } else if (val == 0 && xmlXPathGetSign(val) != 0) {
       
  3516             ret = xmlStrdup((const xmlChar*) "0");
       
  3517         } else {
       
  3518             /* TODO: could be improved */
       
  3519             char buf[100];
       
  3520             xmlXPathFormatNumber(val, buf, 100);
       
  3521             ret = xmlStrdup((const xmlChar *) buf);
       
  3522         }
       
  3523     }
       
  3524     return(ret);
       
  3525 }
       
  3526 
       
  3527 /**
       
  3528  * xmlXPathCastNodeToString:
       
  3529  * @node:  a node
       
  3530  *
       
  3531  * Converts a node to its string value.
       
  3532  *
       
  3533  * Returns a newly allocated string.
       
  3534  *
       
  3535  * OOM: possible --> returns NULL; OOM flag must be checked ALWAYS
       
  3536  */
       
  3537 xmlChar*
       
  3538 xmlXPathCastNodeToString (xmlNodePtr node) {
       
  3539     return(xmlNodeGetContent(node));
       
  3540 } // TODO: OPTIMIZE: define this as macro
       
  3541 
       
  3542 /**
       
  3543  * xmlXPathCastNodeSetToString:
       
  3544  * @ns:  a node-set
       
  3545  *
       
  3546  * Converts a node-set to its string value.
       
  3547  *
       
  3548  * Returns a newly allocated string.
       
  3549  *
       
  3550  * OOM: possible --> returns NULL, OOM flag is set
       
  3551  */
       
  3552 xmlChar *
       
  3553 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
       
  3554     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
       
  3555         return(xmlStrdup((const xmlChar *) ""));
       
  3556 
       
  3557     xmlXPathNodeSetSort(ns);
       
  3558     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
       
  3559 }
       
  3560 
       
  3561 /**
       
  3562  * xmlXPathCastToString:
       
  3563  * @val:  an XPath object
       
  3564  *
       
  3565  * Converts an existing object to its string() equivalent
       
  3566  *
       
  3567  * Returns the string value of the object, NULL in case of error.
       
  3568  *         A new string is allocated only if needed (@val isn't a
       
  3569  *         string object).
       
  3570  */
       
  3571 xmlChar *
       
  3572 xmlXPathCastToString(xmlXPathObjectPtr val) {
       
  3573     xmlChar *ret = NULL;
       
  3574 
       
  3575     if (val == NULL)
       
  3576         return(xmlStrdup((const xmlChar *) ""));
       
  3577 
       
  3578     switch (val->type) {
       
  3579     case XPATH_UNDEFINED:
       
  3580 #ifdef DEBUG_EXPR
       
  3581         xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
       
  3582 #endif
       
  3583         ret = xmlStrdup((const xmlChar *) "");
       
  3584         break;
       
  3585     case XPATH_NUMBER:
       
  3586         ret = xmlXPathCastNumberToString(val->floatval);
       
  3587         break;
       
  3588 
       
  3589     case XPATH_NODESET:
       
  3590     case XPATH_XSLT_TREE:
       
  3591         ret = xmlXPathCastNodeSetToString(val->nodesetval);
       
  3592         break;
       
  3593 
       
  3594     case XPATH_BOOLEAN:
       
  3595         ret = xmlXPathCastBooleanToString(val->boolval);
       
  3596         break;
       
  3597 
       
  3598     case XPATH_STRING:
       
  3599         return(xmlStrdup(val->stringval));
       
  3600 
       
  3601     case XPATH_USERS:
       
  3602     case XPATH_POINT:
       
  3603     case XPATH_RANGE:
       
  3604     case XPATH_LOCATIONSET:
       
  3605         // TODO
       
  3606         ret = xmlStrdup((const xmlChar *) "");
       
  3607         break;
       
  3608     }
       
  3609     return(ret);
       
  3610 }
       
  3611 
       
  3612 /**
       
  3613  * xmlXPathConvertString:
       
  3614  * @val:  an XPath object
       
  3615  *
       
  3616  * Converts an existing object to its string() equivalent
       
  3617  *
       
  3618  * Returns the new object, the old one is freed (or the operation
       
  3619  *         is done directly on @val) or NULL if OOM
       
  3620  */
       
  3621 xmlXPathObjectPtr
       
  3622 xmlXPathConvertString(xmlXPathObjectPtr val) {
       
  3623     xmlChar *res = NULL;
       
  3624     xmlXPathObjectPtr ret;
       
  3625 
       
  3626     if (val == NULL)
       
  3627     return(xmlXPathNewCString(""));
       
  3628 
       
  3629     switch (val->type) {
       
  3630     case XPATH_UNDEFINED:
       
  3631 #ifdef DEBUG_EXPR
       
  3632     xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
       
  3633 #endif
       
  3634     break;
       
  3635     case XPATH_NODESET:
       
  3636     case XPATH_XSLT_TREE:
       
  3637     res = xmlXPathCastNodeSetToString(val->nodesetval);
       
  3638     break;
       
  3639     case XPATH_STRING:
       
  3640     return(val);
       
  3641     case XPATH_BOOLEAN:
       
  3642     res = xmlXPathCastBooleanToString(val->boolval);
       
  3643     break;
       
  3644     case XPATH_NUMBER:
       
  3645     res = xmlXPathCastNumberToString(val->floatval);
       
  3646     break;
       
  3647     case XPATH_USERS:
       
  3648     case XPATH_POINT:
       
  3649     case XPATH_RANGE:
       
  3650     case XPATH_LOCATIONSET:
       
  3651     TODO;
       
  3652     break;
       
  3653     }
       
  3654     xmlXPathFreeObject(val);
       
  3655     if(OOM_FLAG) return(NULL);
       
  3656     if (res == NULL)
       
  3657     	return(xmlXPathNewCString(""));
       
  3658 	ret = xmlXPathWrapString(res);
       
  3659 	if(OOM_FLAG)
       
  3660 		{
       
  3661 		xmlFree(res);
       
  3662 		return(NULL);
       
  3663 		}
       
  3664 	return(ret);
       
  3665 }
       
  3666 
       
  3667 /**
       
  3668  * xmlXPathCastBooleanToNumber:
       
  3669  * @val:  a boolean
       
  3670  *
       
  3671  * Converts a boolean to its number value
       
  3672  *
       
  3673  * Returns the number value
       
  3674  */
       
  3675 double
       
  3676 xmlXPathCastBooleanToNumber(int val) {
       
  3677     return val ? (1.0) :(0.0);
       
  3678 }
       
  3679 
       
  3680 /**
       
  3681  * xmlXPathCastStringToNumber:
       
  3682  * @val:  a string
       
  3683  *
       
  3684  * Converts a string to its number value
       
  3685  *
       
  3686  * Returns the number value
       
  3687  *
       
  3688  * OOM: Never
       
  3689  */
       
  3690 double
       
  3691 xmlXPathCastStringToNumber(const xmlChar * val) {
       
  3692     return(xmlXPathStringEvalNumber(val));
       
  3693 }
       
  3694 
       
  3695 /**
       
  3696  * xmlXPathCastNodeToNumber:
       
  3697  * @node:  a node
       
  3698  *
       
  3699  * Converts a node to its number value
       
  3700  *
       
  3701  * Returns the number value
       
  3702  */
       
  3703 double
       
  3704 xmlXPathCastNodeToNumber (xmlNodePtr node) {
       
  3705     xmlChar *strval;
       
  3706     double ret;
       
  3707 
       
  3708     if (node == NULL)
       
  3709         return(xmlXPathNAN);
       
  3710     strval = xmlXPathCastNodeToString(node);
       
  3711     if (strval == NULL)
       
  3712         return(xmlXPathNAN);
       
  3713 
       
  3714     ret = xmlXPathCastStringToNumber(strval);
       
  3715     xmlFree(strval);
       
  3716 
       
  3717     return(ret);
       
  3718 }
       
  3719 
       
  3720 /**
       
  3721  * xmlXPathCastNodeSetToNumber:
       
  3722  * @ns:  a node-set
       
  3723  *
       
  3724  * Converts a node-set to its number value
       
  3725  *
       
  3726  * Returns the number value
       
  3727  *
       
  3728  * OOM: possible --> OOM flag must be checked
       
  3729  */
       
  3730 double
       
  3731 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
       
  3732     xmlChar *str;
       
  3733     double ret;
       
  3734 
       
  3735     if (ns == NULL)
       
  3736         return(xmlXPathNAN);
       
  3737     str = xmlXPathCastNodeSetToString(ns); // OOM is possible
       
  3738     if(str){
       
  3739         ret = xmlXPathCastStringToNumber(str);
       
  3740         xmlFree(str);
       
  3741         return(ret);
       
  3742     }
       
  3743     return 0;
       
  3744 }
       
  3745 
       
  3746 /**
       
  3747  * xmlXPathCastToNumber:
       
  3748  * @val:  an XPath object
       
  3749  *
       
  3750  * Converts an XPath object to its number value
       
  3751  *
       
  3752  * Returns the number value
       
  3753  */
       
  3754 double
       
  3755 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
       
  3756     double ret = 0.0;
       
  3757 
       
  3758     if (val == NULL)
       
  3759         return(xmlXPathNAN);
       
  3760     switch (val->type) {
       
  3761     case XPATH_UNDEFINED:
       
  3762 #ifdef DEGUB_EXPR
       
  3763     xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
       
  3764 #endif
       
  3765         ret = xmlXPathNAN;
       
  3766         break;
       
  3767     case XPATH_NODESET:
       
  3768     case XPATH_XSLT_TREE:
       
  3769         ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
       
  3770         break;
       
  3771     case XPATH_STRING:
       
  3772         ret = xmlXPathCastStringToNumber(val->stringval);
       
  3773         break;
       
  3774     case XPATH_NUMBER:
       
  3775         ret = val->floatval;
       
  3776         break;
       
  3777     case XPATH_BOOLEAN:
       
  3778         ret = xmlXPathCastBooleanToNumber(val->boolval);
       
  3779         break;
       
  3780     case XPATH_USERS:
       
  3781     case XPATH_POINT:
       
  3782     case XPATH_RANGE:
       
  3783     case XPATH_LOCATIONSET:
       
  3784         TODO;
       
  3785         ret = xmlXPathNAN;
       
  3786         break;
       
  3787     }
       
  3788     return(ret);
       
  3789 }
       
  3790 
       
  3791 /**
       
  3792  * xmlXPathConvertNumber:
       
  3793  * @val:  an XPath object
       
  3794  *
       
  3795  * Converts an existing object to its number() equivalent
       
  3796  *
       
  3797  * Returns the new object, the old one is freed (or the operation
       
  3798  *         is done directly on @val)
       
  3799  */
       
  3800 xmlXPathObjectPtr
       
  3801 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
       
  3802     xmlXPathObjectPtr ret;
       
  3803 
       
  3804     if (val == NULL)
       
  3805         return(xmlXPathNewFloat(0.0));
       
  3806     if (val->type == XPATH_NUMBER)
       
  3807         return(val);
       
  3808     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
       
  3809     xmlXPathFreeObject(val);
       
  3810     return(ret);
       
  3811 }
       
  3812 
       
  3813 /**
       
  3814  * xmlXPathCastNumberToBoolean:
       
  3815  * @val:  a number
       
  3816  *
       
  3817  * Converts a number to its boolean value
       
  3818  *
       
  3819  * Returns the boolean value
       
  3820  */
       
  3821 int
       
  3822 xmlXPathCastNumberToBoolean (double val) {
       
  3823      if (xmlXPathIsNaN(val) || (val == 0.0))
       
  3824      return(0);
       
  3825      return(1);
       
  3826 }
       
  3827 
       
  3828 /**
       
  3829  * xmlXPathCastStringToBoolean:
       
  3830  * @val:  a string
       
  3831  *
       
  3832  * Converts a string to its boolean value
       
  3833  *
       
  3834  * Returns the boolean value
       
  3835  *
       
  3836  * OOM: never
       
  3837  */
       
  3838 int
       
  3839 xmlXPathCastStringToBoolean (const xmlChar *val) {
       
  3840     if ((val == NULL) || (xmlStrlen(val) == 0))
       
  3841     return(0);
       
  3842     return(1);
       
  3843 }
       
  3844 
       
  3845 /**
       
  3846  * xmlXPathCastNodeSetToBoolean:
       
  3847  * @ns:  a node-set
       
  3848  *
       
  3849  * Converts a node-set to its boolean value
       
  3850  *
       
  3851  * Returns the boolean value
       
  3852  *
       
  3853  * OOM: never
       
  3854  */
       
  3855 int
       
  3856 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
       
  3857     if ((ns == NULL) || (ns->nodeNr == 0))
       
  3858     return(0);
       
  3859     return(1);
       
  3860 }
       
  3861 
       
  3862 /**
       
  3863  * xmlXPathCastToBoolean:
       
  3864  * @val:  an XPath object
       
  3865  *
       
  3866  * Converts an XPath object to its boolean value
       
  3867  *
       
  3868  * Returns the boolean value
       
  3869  */
       
  3870 int
       
  3871 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
       
  3872     int ret = 0;
       
  3873 
       
  3874     if (val == NULL)
       
  3875     return(0);
       
  3876     switch (val->type) {
       
  3877     case XPATH_UNDEFINED:
       
  3878 #ifdef DEBUG_EXPR
       
  3879     xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
       
  3880 #endif
       
  3881     ret = 0;
       
  3882     break;
       
  3883     case XPATH_NODESET:
       
  3884     case XPATH_XSLT_TREE:
       
  3885     ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
       
  3886     break;
       
  3887     case XPATH_STRING:
       
  3888     ret = xmlXPathCastStringToBoolean(val->stringval);
       
  3889     break;
       
  3890     case XPATH_NUMBER:
       
  3891     ret = xmlXPathCastNumberToBoolean(val->floatval);
       
  3892     break;
       
  3893     case XPATH_BOOLEAN:
       
  3894     ret = val->boolval;
       
  3895     break;
       
  3896     case XPATH_USERS:
       
  3897     case XPATH_POINT:
       
  3898     case XPATH_RANGE:
       
  3899     case XPATH_LOCATIONSET:
       
  3900     TODO;
       
  3901     ret = 0;
       
  3902     break;
       
  3903     }
       
  3904     return(ret);
       
  3905 }
       
  3906 
       
  3907 
       
  3908 /**
       
  3909  * xmlXPathConvertBoolean:
       
  3910  * @val:  an XPath object
       
  3911  *
       
  3912  * Converts an existing object to its boolean() equivalent
       
  3913  *
       
  3914  * Returns the new object, the old one is freed (or the operation
       
  3915  *         is done directly on @val)
       
  3916  */
       
  3917 xmlXPathObjectPtr
       
  3918 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
       
  3919     xmlXPathObjectPtr ret;
       
  3920 
       
  3921     if (val == NULL)
       
  3922     return(xmlXPathNewBoolean(0));
       
  3923     if (val->type == XPATH_BOOLEAN)
       
  3924     return(val);
       
  3925     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
       
  3926     xmlXPathFreeObject(val);
       
  3927     return(ret);
       
  3928 }
       
  3929 
       
  3930 /************************************************************************
       
  3931  *                                                                      *
       
  3932  *      Routines to handle XPath contexts                               *
       
  3933  *                                                                      *
       
  3934  ************************************************************************/
       
  3935 
       
  3936 #ifdef XMLENGINE_XPATH_FUNC_HASH_OPTIMIZED
       
  3937 /**
       
  3938  * xmlHashCopier:
       
  3939  * typedef void *(*xmlHashCopier)(void *payload, xmlChar *name);
       
  3940  */
       
  3941 void* xeSimpleHashEntryCopier(void *payload, xmlChar* name )
       
  3942 {
       
  3943     return payload; // just return the same value
       
  3944 }
       
  3945 #endif
       
  3946 
       
  3947 /**
       
  3948  * xmlXPathNewContext:
       
  3949  * @doc:  the XML document
       
  3950  *
       
  3951  * Create a new xmlXPathContext
       
  3952  *
       
  3953  * Returns the xmlXPathContext just allocated. The caller will need to free it.
       
  3954  */
       
  3955 xmlXPathContextPtr
       
  3956 xmlXPathNewContext(xmlDocPtr doc) {
       
  3957     xmlXPathContextPtr ret;
       
  3958     xmlHashTablePtr gFuncHash;
       
  3959 
       
  3960     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
       
  3961     if (ret == NULL) {
       
  3962         xmlXPathErrMemory(NULL, EMBED_ERRTXT("creating context\n"));
       
  3963         return(NULL);
       
  3964     }
       
  3965     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
       
  3966 
       
  3967     ret->doc = doc; // this is a context node in general, not always a document node
       
  3968 
       
  3969     // XMLENGINE: these are nullified already
       
  3970     //ret->node = NULL;
       
  3971     //ret->varHash = NULL;
       
  3972     //ret->nb_types = 0;
       
  3973     //ret->max_types = 0;
       
  3974     //ret->types = NULL;
       
  3975 
       
  3976 #ifdef XMLENGINE_XPATH_FUNC_HASH_OPTIMIZED
       
  3977 // XMLENGINE: BEGIN NEW CODE
       
  3978     // xmlXPathDefaultFunctionsHash is the new field in xmlGlobalState structure
       
  3979     gFuncHash = xmlXPathDefaultFunctionsHash;
       
  3980     if(!gFuncHash)
       
  3981     {   // global reusable hash table was not initialized yet
       
  3982         if( xmlXPathRegisterAllFunctions(ret) < 0 ) 
       
  3983         	{
       
  3984         	xmlFree(ret);
       
  3985         	return(NULL);
       
  3986         	}
       
  3987         if(xmlXPathDefineExtensionFunctionsGlobally)
       
  3988             {
       
  3989             xmlXPathDefaultFunctionsHash = ret->funcHash;
       
  3990             }
       
  3991         else
       
  3992             {
       
  3993             xmlXPathDefaultFunctionsHash = xmlHashCopy(ret->funcHash, xeSimpleHashEntryCopier);
       
  3994             }
       
  3995     }
       
  3996     else
       
  3997     {   // copy previously initialized hash table OR
       
  3998         // reuse the global hash, then, no cleanup is needed when
       
  3999         // XPath context is freed
       
  4000         if(xmlXPathDefineExtensionFunctionsGlobally)
       
  4001             {
       
  4002             ret->funcHash = gFuncHash;
       
  4003             }
       
  4004         else
       
  4005             {
       
  4006             ret->funcHash = xmlHashCopy( gFuncHash, xeSimpleHashEntryCopier );
       
  4007             }
       
  4008     }
       
  4009 // XMLENGINE: END NEW CODE
       
  4010 #else
       
  4011     /* original code*/
       
  4012     ret->funcHash = xmlHashCreate(0);
       
  4013     xmlXPathRegisterAllFunctions(ret); //TODO: check OOM
       
  4014 #endif /* else !XMLENGINE_XPATH_FUNC_HASH_OPTIMIZED */
       
  4015 
       
  4016     // XMLENGINE: these are nullified already
       
  4017     //ret->nb_axis = 0;
       
  4018     //ret->max_axis = 0;
       
  4019     //ret->axis = NULL;
       
  4020     //ret->nsHash = NULL;
       
  4021     //ret->user = NULL;
       
  4022 
       
  4023     ret->contextSize = -1;
       
  4024     ret->proximityPosition = -1;
       
  4025 
       
  4026     return(ret);
       
  4027 }
       
  4028 
       
  4029 /**
       
  4030  * xmlXPathFreeContext:
       
  4031  * @ctxt:  the context to free
       
  4032  *
       
  4033  * Free up an xmlXPathContext
       
  4034  */
       
  4035 void
       
  4036 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
       
  4037     // TODO: Check will this erase useful error info during ERR cleanup
       
  4038     // merge: i'm not sure if this is useful anymore...
       
  4039     if (&ctxt->lastError)
       
  4040         xmlResetError(&ctxt->lastError);
       
  4041 
       
  4042     xmlXPathRegisteredNsCleanup(ctxt);
       
  4043 #ifdef XMLENGINE_XPATH_FUNC_HASH_OPTIMIZED
       
  4044     // DO NOTHING HERE if global hash table is reused.
       
  4045     // The function hash is destroyed only if it is not reused,
       
  4046     // otherwise the reference to it is stored in global:
       
  4047     //      xmlXPathDefaultFunctionsHash  variable
       
  4048     //  and the hash table is freed during XML Engine cleanup with
       
  4049     //  xeXPathCleanup()
       
  4050     if(!xmlXPathDefineExtensionFunctionsGlobally)
       
  4051         {
       
  4052         xmlXPathRegisteredFuncsCleanup(ctxt);
       
  4053         }
       
  4054 #else
       
  4055     xmlXPathRegisteredFuncsCleanup(ctxt);
       
  4056 #endif
       
  4057     xmlXPathRegisteredVariablesCleanup(ctxt);
       
  4058     xmlFree(ctxt);
       
  4059 }
       
  4060 
       
  4061 /************************************************************************
       
  4062  *                                                                      *
       
  4063  *      Routines to handle XPath parser contexts                        *
       
  4064  *                                                                      *
       
  4065  ************************************************************************/
       
  4066 
       
  4067 #define CHECK_CTXT(ctxt)                                                \
       
  4068     if (ctxt == NULL) {                                                 \
       
  4069         xmlGenericError(xmlGenericErrorContext,                         \
       
  4070         EMBED_ERRTXT("%s:%d Internal error: ctxt == NULL\n"),           \
       
  4071             __FILE__, __LINE__);                                        \
       
  4072     }                                                                   \
       
  4073 
       
  4074 
       
  4075 // TODO: Quite big macro -- for release build it could be reduced by xmlGenericError calls
       
  4076 #define CHECK_CONTEXT(ctxt)                                             \
       
  4077     if (ctxt == NULL) {                                                 \
       
  4078         xmlGenericError(xmlGenericErrorContext,                         \
       
  4079         EMBED_ERRTXT("%s:%d Internal error: no context\n"),             \
       
  4080             __FILE__, __LINE__);                                        \
       
  4081     }                                                                   \
       
  4082     else if (ctxt->doc == NULL) {                                       \
       
  4083         xmlGenericError(xmlGenericErrorContext,                         \
       
  4084         EMBED_ERRTXT("%s:%d Internal error: no document\n"),            \
       
  4085             __FILE__, __LINE__);                                        \
       
  4086     }                                                                   \
       
  4087     else if (ctxt->doc->children == NULL) {                             \
       
  4088         xmlGenericError(xmlGenericErrorContext,                         \
       
  4089             EMBED_ERRTXT("%s:%d Internal error: document without root\n"),  \
       
  4090             __FILE__, __LINE__);                                        \
       
  4091     }                                                                   \
       
  4092 
       
  4093 
       
  4094 /**
       
  4095  * xmlXPathNewParserContext:
       
  4096  * @str:  the XPath expression
       
  4097  * @ctxt:  the XPath context
       
  4098  *
       
  4099  * Create a new xmlXPathParserContext
       
  4100  *
       
  4101  * Returns the xmlXPathParserContext just allocated.
       
  4102  */
       
  4103 xmlXPathParserContextPtr
       
  4104 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
       
  4105     xmlXPathParserContextPtr ret;
       
  4106 
       
  4107     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
       
  4108     if (ret == NULL) {
       
  4109         xmlXPathErrMemory(ctxt, EMBED_ERRTXT("creating parser context\n"));
       
  4110     return(NULL);
       
  4111     }
       
  4112     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
       
  4113     ret->cur = ret->base = str;
       
  4114     ret->context = ctxt;
       
  4115 
       
  4116     ret->comp = xmlXPathNewCompExpr();
       
  4117     if (ret->comp == NULL) {
       
  4118     xmlFree(ret->valueTab);
       
  4119     xmlFree(ret);
       
  4120     return(NULL);
       
  4121     }
       
  4122     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
       
  4123         ret->comp->dict = ctxt->dict;
       
  4124     xmlDictReference(ret->comp->dict);
       
  4125     }
       
  4126 
       
  4127     return(ret);
       
  4128 }
       
  4129 
       
  4130 /**
       
  4131  * xmlXPathCompParserContext:
       
  4132  * @comp:  the XPath compiled expression
       
  4133  * @ctxt:  the XPath context
       
  4134  *
       
  4135  * Create a new xmlXPathParserContext when processing a compiled expression
       
  4136  *
       
  4137  * Returns the xmlXPathParserContext just allocated.
       
  4138  */
       
  4139 static xmlXPathParserContextPtr
       
  4140 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
       
  4141     xmlXPathParserContextPtr ret;
       
  4142 
       
  4143     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
       
  4144     if (ret == NULL) {
       
  4145         xmlXPathErrMemory(ctxt, EMBED_ERRTXT("creating evaluation context\n"));
       
  4146         return(NULL);
       
  4147     }
       
  4148     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
       
  4149 
       
  4150     /* Allocate the value stack */
       
  4151     ret->valueTab = (xmlXPathObjectPtr *)
       
  4152                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
       
  4153     if (ret->valueTab == NULL) {
       
  4154         xmlFree(ret);
       
  4155         xmlXPathErrMemory(ctxt, EMBED_ERRTXT("creating evaluation context\n"));
       
  4156         return(NULL);
       
  4157     }
       
  4158     ret->valueNr = 0;
       
  4159     ret->valueMax = 10;
       
  4160     ret->value = NULL;
       
  4161 
       
  4162     ret->context = ctxt;
       
  4163     ret->comp = comp;
       
  4164 
       
  4165     return(ret);
       
  4166 }
       
  4167 
       
  4168 /**
       
  4169  * xmlXPathFreeParserContext:
       
  4170  * @ctxt:  the context to free
       
  4171  *
       
  4172  * Free up an xmlXPathParserContext
       
  4173  */
       
  4174 void
       
  4175 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
       
  4176     if (ctxt->valueTab != NULL) {
       
  4177         xmlFree(ctxt->valueTab);
       
  4178     }
       
  4179     if (ctxt->comp)
       
  4180         xmlXPathFreeCompExpr(ctxt->comp);
       
  4181     xmlFree(ctxt);
       
  4182 }
       
  4183 
       
  4184 /************************************************************************
       
  4185  *                                                                      *
       
  4186  *      The implicit core function library                              *
       
  4187  *                                                                      *
       
  4188  ************************************************************************/
       
  4189 
       
  4190 /**
       
  4191  * xmlXPathNodeValHash:
       
  4192  * @node:  a node pointer
       
  4193  *
       
  4194  * Function computing the beginning of the string value of the node,
       
  4195  * used to speed up comparisons
       
  4196  *
       
  4197  * Returns an int usable as a hash
       
  4198  */
       
  4199 static unsigned int
       
  4200 xmlXPathNodeValHash(xmlNodePtr node) {
       
  4201     int len = 2;
       
  4202     const xmlChar * string = NULL;
       
  4203     xmlNodePtr tmp = NULL;
       
  4204     unsigned int ret = 0;
       
  4205 
       
  4206     if (node == NULL)
       
  4207     return(0);
       
  4208 
       
  4209     if (node->type == XML_DOCUMENT_NODE) {
       
  4210         tmp = xmlDocGetRootElement((xmlDocPtr) node);
       
  4211         if (tmp == NULL)
       
  4212             node = node->children;
       
  4213         else
       
  4214             node = tmp;
       
  4215 
       
  4216         if (node == NULL)
       
  4217             return(0);
       
  4218     }
       
  4219 
       
  4220     switch (node->type) {
       
  4221     case XML_COMMENT_NODE:
       
  4222     case XML_PI_NODE:
       
  4223     case XML_CDATA_SECTION_NODE:
       
  4224     case XML_TEXT_NODE:
       
  4225         string = node->content;
       
  4226         if (string == NULL)
       
  4227             return(0);
       
  4228         if (string[0] == 0)
       
  4229             return(0);
       
  4230         return(((unsigned int) string[0]) +
       
  4231            (((unsigned int) string[1]) << 8));
       
  4232     case XML_NAMESPACE_DECL:
       
  4233         string = ((xmlNsPtr)node)->href;
       
  4234         if (string == NULL)
       
  4235             return(0);
       
  4236         if (string[0] == 0)
       
  4237             return(0);
       
  4238         return(((unsigned int) string[0]) +
       
  4239            (((unsigned int) string[1]) << 8));
       
  4240     case XML_ATTRIBUTE_NODE:
       
  4241         tmp = ((xmlAttrPtr) node)->children;
       
  4242         break;
       
  4243     case XML_ELEMENT_NODE:
       
  4244         tmp = node->children;
       
  4245         break;
       
  4246     default:
       
  4247         return(0);
       
  4248     }
       
  4249     while (tmp != NULL) {
       
  4250     switch (tmp->type) {
       
  4251         case XML_COMMENT_NODE:
       
  4252         case XML_PI_NODE:
       
  4253         case XML_CDATA_SECTION_NODE:
       
  4254         case XML_TEXT_NODE:
       
  4255             string = tmp->content;
       
  4256             break;
       
  4257         case XML_NAMESPACE_DECL:
       
  4258             string = ((xmlNsPtr)tmp)->href;
       
  4259             break;
       
  4260         default:
       
  4261             break;
       
  4262     }
       
  4263     if ((string != NULL) && (string[0] != 0)) {
       
  4264         if (len == 1) {
       
  4265             return(ret + (((unsigned int) string[0]) << 8));
       
  4266         }
       
  4267         if (string[1] == 0) {
       
  4268             len = 1;
       
  4269             ret = (unsigned int) string[0];
       
  4270         } else {
       
  4271             return(((unsigned int) string[0]) +
       
  4272                 (((unsigned int) string[1]) << 8));
       
  4273         }
       
  4274     }
       
  4275     /*
       
  4276      * Skip to next node
       
  4277      */
       
  4278     if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
       
  4279         if (tmp->children->type != XML_ENTITY_DECL) {
       
  4280             tmp = tmp->children;
       
  4281             continue;
       
  4282         }
       
  4283     }
       
  4284     if (tmp == node)
       
  4285         break;
       
  4286 
       
  4287     if (tmp->next != NULL) {
       
  4288         tmp = tmp->next;
       
  4289         continue;
       
  4290     }
       
  4291 
       
  4292     do {
       
  4293         tmp = tmp->parent;
       
  4294         if (tmp == NULL)
       
  4295             break;
       
  4296         if (tmp == node) {
       
  4297             tmp = NULL;
       
  4298             break;
       
  4299         }
       
  4300         if (tmp->next != NULL) {
       
  4301             tmp = tmp->next;
       
  4302             break;
       
  4303         }
       
  4304     } while (tmp != NULL);
       
  4305     }
       
  4306     return(ret);
       
  4307 }
       
  4308 
       
  4309 /**
       
  4310  * xmlXPathStringHash:
       
  4311  * @string:  a string
       
  4312  *
       
  4313  * Function computing the beginning of the string value of the node,
       
  4314  * used to speed up comparisons
       
  4315  *
       
  4316  * Returns an int usable as a hash
       
  4317  */
       
  4318 static unsigned int
       
  4319 xmlXPathStringHash(const xmlChar * string) {
       
  4320     if (string == NULL)
       
  4321     return((unsigned int) 0);
       
  4322     if (string[0] == 0)
       
  4323     return(0);
       
  4324     return(((unsigned int) string[0]) +
       
  4325        (((unsigned int) string[1]) << 8));
       
  4326 }
       
  4327 
       
  4328 /**
       
  4329  * xmlXPathCompareNodeSetFloat:
       
  4330  * @ctxt:  the XPath Parser context
       
  4331  * @inf:  less than (1) or greater than (0)
       
  4332  * @strict:  is the comparison strict
       
  4333  * @arg:  the node set
       
  4334  * @f:  the value
       
  4335  *
       
  4336  * Implement the compare operation between a nodeset and a number
       
  4337  *     @ns < @val    (1, 1, ...
       
  4338  *     @ns <= @val   (1, 0, ...
       
  4339  *     @ns > @val    (0, 1, ...
       
  4340  *     @ns >= @val   (0, 0, ...
       
  4341  *
       
  4342  * If one object to be compared is a node-set and the other is a number,
       
  4343  * then the comparison will be true if and only if there is a node in the
       
  4344  * node-set such that the result of performing the comparison on the number
       
  4345  * to be compared and on the result of converting the string-value of that
       
  4346  * node to a number using the number function is true.
       
  4347  *
       
  4348  * Returns 0 or 1 depending on the results of the test.
       
  4349  */
       
  4350 static int
       
  4351 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
       
  4352                         xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
       
  4353     int i, ret = 0;
       
  4354     xmlNodeSetPtr ns;
       
  4355     xmlChar *str2;
       
  4356 
       
  4357     if ((f == NULL) || (arg == NULL) ||
       
  4358     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
       
  4359     xmlXPathFreeObject(arg);
       
  4360     xmlXPathFreeObject(f);
       
  4361         return(0);
       
  4362     }
       
  4363     ns = arg->nodesetval;
       
  4364     if (ns != NULL) {
       
  4365     for (i = 0;i < ns->nodeNr;i++) {
       
  4366          str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
       
  4367          if (str2 != NULL) {
       
  4368          valuePush(ctxt,
       
  4369                xmlXPathNewString(str2));
       
  4370          xmlFree(str2);
       
  4371          xmlXPathNumberFunction(ctxt, 1);
       
  4372          valuePush(ctxt, xmlXPathObjectCopy(f));
       
  4373          ret = xmlXPathCompareValues(ctxt, inf, strict);
       
  4374          if (ret)
       
  4375              break;
       
  4376          }
       
  4377     }
       
  4378     }
       
  4379     xmlXPathFreeObject(arg);
       
  4380     xmlXPathFreeObject(f);
       
  4381     return(ret);
       
  4382 }
       
  4383 
       
  4384 /**
       
  4385  * xmlXPathCompareNodeSetString:
       
  4386  * @ctxt:  the XPath Parser context
       
  4387  * @inf:  less than (1) or greater than (0)
       
  4388  * @strict:  is the comparison strict
       
  4389  * @arg:  the node set
       
  4390  * @s:  the value
       
  4391  *
       
  4392  * Implement the compare operation between a nodeset and a string
       
  4393  *     @ns < @val    (1, 1, ...
       
  4394  *     @ns <= @val   (1, 0, ...
       
  4395  *     @ns > @val    (0, 1, ...
       
  4396  *     @ns >= @val   (0, 0, ...
       
  4397  *
       
  4398  * If one object to be compared is a node-set and the other is a string,
       
  4399  * then the comparison will be true if and only if there is a node in
       
  4400  * the node-set such that the result of performing the comparison on the
       
  4401  * string-value of the node and the other string is true.
       
  4402  *
       
  4403  * Returns 0 or 1 depending on the results of the test.
       
  4404  */
       
  4405 static int
       
  4406 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
       
  4407                         xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
       
  4408     int i, ret = 0;
       
  4409     xmlNodeSetPtr ns;
       
  4410     xmlChar *str2;
       
  4411 
       
  4412     if ((s == NULL) || (arg == NULL) ||
       
  4413     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
       
  4414     xmlXPathFreeObject(arg);
       
  4415     xmlXPathFreeObject(s);
       
  4416         return(0);
       
  4417     }
       
  4418     ns = arg->nodesetval;
       
  4419     if (ns != NULL) {
       
  4420     for (i = 0;i < ns->nodeNr;i++) {
       
  4421          str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
       
  4422          if (str2 != NULL) {
       
  4423          valuePush(ctxt,
       
  4424                xmlXPathNewString(str2));
       
  4425          xmlFree(str2);
       
  4426          valuePush(ctxt, xmlXPathObjectCopy(s));
       
  4427          ret = xmlXPathCompareValues(ctxt, inf, strict);
       
  4428          if (ret)
       
  4429              break;
       
  4430          }
       
  4431     }
       
  4432     }
       
  4433     xmlXPathFreeObject(arg);
       
  4434     xmlXPathFreeObject(s);
       
  4435     return(ret);
       
  4436 }
       
  4437 
       
  4438 /**
       
  4439  * xmlXPathCompareNodeSets:
       
  4440  * @inf:  less than (1) or greater than (0)
       
  4441  * @strict:  is the comparison strict
       
  4442  * @arg1:  the first node set object
       
  4443  * @arg2:  the second node set object
       
  4444  *
       
  4445  * Implement the compare operation on nodesets:
       
  4446  *
       
  4447  * If both objects to be compared are node-sets, then the comparison
       
  4448  * will be true if and only if there is a node in the first node-set
       
  4449  * and a node in the second node-set such that the result of performing
       
  4450  * the comparison on the string-values of the two nodes is true.
       
  4451  * ....
       
  4452  * When neither object to be compared is a node-set and the operator
       
  4453  * is <=, <, >= or >, then the objects are compared by converting both
       
  4454  * objects to numbers and comparing the numbers according to IEEE 754.
       
  4455  * ....
       
  4456  * The number function converts its argument to a number as follows:
       
  4457  *  - a string that consists of optional whitespace followed by an
       
  4458  *    optional minus sign followed by a Number followed by whitespace
       
  4459  *    is converted to the IEEE 754 number that is nearest (according
       
  4460  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
       
  4461  *    represented by the string; any other string is converted to NaN
       
  4462  *
       
  4463  * Conclusion all nodes need to be converted first to their string value
       
  4464  * and then the comparison must be done when possible
       
  4465  */
       
  4466 static int
       
  4467 xmlXPathCompareNodeSets(int inf, int strict,
       
  4468                     xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
       
  4469     int i, j, init = 0;
       
  4470     double val1;
       
  4471     double *values2;
       
  4472     int ret = 0;
       
  4473     xmlNodeSetPtr ns1;
       
  4474     xmlNodeSetPtr ns2;
       
  4475 
       
  4476     if ((arg1 == NULL) ||
       
  4477     ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
       
  4478     xmlXPathFreeObject(arg2);
       
  4479         return(0);
       
  4480     }
       
  4481     if ((arg2 == NULL) ||
       
  4482     ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
       
  4483     xmlXPathFreeObject(arg1);
       
  4484     xmlXPathFreeObject(arg2);
       
  4485         return(0);
       
  4486     }
       
  4487 
       
  4488     ns1 = arg1->nodesetval;
       
  4489     ns2 = arg2->nodesetval;
       
  4490 
       
  4491     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
       
  4492     xmlXPathFreeObject(arg1);
       
  4493     xmlXPathFreeObject(arg2);
       
  4494     return(0);
       
  4495     }
       
  4496     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
       
  4497     xmlXPathFreeObject(arg1);
       
  4498     xmlXPathFreeObject(arg2);
       
  4499     return(0);
       
  4500     }
       
  4501 
       
  4502     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
       
  4503     if (values2 == NULL) {
       
  4504         xmlXPathErrMemory(NULL, EMBED_ERRTXT("comparing nodesets\n"));
       
  4505     xmlXPathFreeObject(arg1);
       
  4506     xmlXPathFreeObject(arg2);
       
  4507     return(0);
       
  4508     }
       
  4509     for (i = 0;i < ns1->nodeNr;i++) {
       
  4510     val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
       
  4511     if (xmlXPathIsNaN(val1))
       
  4512         continue;
       
  4513     for (j = 0;j < ns2->nodeNr;j++) {
       
  4514         if (init == 0) {
       
  4515         values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
       
  4516         }
       
  4517         if (xmlXPathIsNaN(values2[j]))
       
  4518         continue;
       
  4519         if (inf && strict)
       
  4520         ret = (val1 < values2[j]);
       
  4521         else if (inf && !strict)
       
  4522         ret = (val1 <= values2[j]);
       
  4523         else if (!inf && strict)
       
  4524         ret = (val1 > values2[j]);
       
  4525         else if (!inf && !strict)
       
  4526         ret = (val1 >= values2[j]);
       
  4527         if (ret)
       
  4528         break;
       
  4529     }
       
  4530     if (ret)
       
  4531         break;
       
  4532     init = 1;
       
  4533     }
       
  4534     xmlFree(values2);
       
  4535     xmlXPathFreeObject(arg1);
       
  4536     xmlXPathFreeObject(arg2);
       
  4537     return(ret);
       
  4538 }
       
  4539 
       
  4540 /**
       
  4541  * xmlXPathCompareNodeSetValue:
       
  4542  * @ctxt:  the XPath Parser context
       
  4543  * @inf:  less than (1) or greater than (0)
       
  4544  * @strict:  is the comparison strict
       
  4545  * @arg:  the node set
       
  4546  * @val:  the value
       
  4547  *
       
  4548  * Implement the compare operation between a nodeset and a value
       
  4549  *     @ns < @val    (1, 1, ...
       
  4550  *     @ns <= @val   (1, 0, ...
       
  4551  *     @ns > @val    (0, 1, ...
       
  4552  *     @ns >= @val   (0, 0, ...
       
  4553  *
       
  4554  * If one object to be compared is a node-set and the other is a boolean,
       
  4555  * then the comparison will be true if and only if the result of performing
       
  4556  * the comparison on the boolean and on the result of converting
       
  4557  * the node-set to a boolean using the boolean function is true.
       
  4558  *
       
  4559  * Returns 0 or 1 depending on the results of the test.
       
  4560  */
       
  4561 static int
       
  4562 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
       
  4563                         xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
       
  4564     if ((val == NULL) || (arg == NULL) ||
       
  4565     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
       
  4566         return(0);
       
  4567 
       
  4568     switch(val->type) {
       
  4569         case XPATH_NUMBER:
       
  4570         return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
       
  4571         case XPATH_NODESET:
       
  4572         case XPATH_XSLT_TREE:
       
  4573         return(xmlXPathCompareNodeSets(inf, strict, arg, val));
       
  4574         case XPATH_STRING:
       
  4575         return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
       
  4576         case XPATH_BOOLEAN:
       
  4577         valuePush(ctxt, arg);
       
  4578         xmlXPathBooleanFunction(ctxt, 1);
       
  4579         valuePush(ctxt, val);
       
  4580         return(xmlXPathCompareValues(ctxt, inf, strict));
       
  4581     default:
       
  4582         TODO
       
  4583     }
       
  4584     return(0);
       
  4585 }
       
  4586 
       
  4587 /**
       
  4588  * xmlXPathEqualNodeSetString:
       
  4589  * @arg:  the nodeset object argument
       
  4590  * @str:  the string to compare to.
       
  4591  * @neq:  flag to show whether for '=' (0) or '!=' (1)
       
  4592  *
       
  4593  * Implement the equal operation on XPath objects content: @arg1 == @arg2
       
  4594  * If one object to be compared is a node-set and the other is a string,
       
  4595  * then the comparison will be true if and only if there is a node in
       
  4596  * the node-set such that the result of performing the comparison on the
       
  4597  * string-value of the node and the other string is true.
       
  4598  *
       
  4599  * Returns 0 or 1 depending on the results of the test.
       
  4600  */
       
  4601 static int
       
  4602 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
       
  4603 {
       
  4604     int i;
       
  4605     xmlNodeSetPtr ns;
       
  4606     xmlChar *str2;
       
  4607     unsigned int hash;
       
  4608 
       
  4609     if ((str == NULL) || (arg == NULL) ||
       
  4610         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
       
  4611         return (0);
       
  4612     ns = arg->nodesetval;
       
  4613     /*
       
  4614      * A NULL nodeset compared with a string is always false
       
  4615      * (since there is no node equal, and no node not equal)
       
  4616      */
       
  4617     if ((ns == NULL) || (ns->nodeNr <= 0) )
       
  4618         return (0);
       
  4619     hash = xmlXPathStringHash(str);
       
  4620     for (i = 0; i < ns->nodeNr; i++) {
       
  4621         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
       
  4622             str2 = xmlNodeGetContent(ns->nodeTab[i]);
       
  4623             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
       
  4624                 xmlFree(str2);
       
  4625         if (neq)
       
  4626             continue;
       
  4627                 return (1);
       
  4628         } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
       
  4629         if (neq)
       
  4630             continue;
       
  4631                 return (1);
       
  4632             } else if (neq) {
       
  4633         if (str2 != NULL)
       
  4634             xmlFree(str2);
       
  4635         return (1);
       
  4636         }
       
  4637             if (str2 != NULL)
       
  4638                 xmlFree(str2);
       
  4639         } else if (neq)
       
  4640         return (1);
       
  4641     }
       
  4642     return (0);
       
  4643 }
       
  4644 
       
  4645 /**
       
  4646  * xmlXPathEqualNodeSetFloat:
       
  4647  * @arg:  the nodeset object argument
       
  4648  * @f:  the float to compare to
       
  4649  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
       
  4650  *
       
  4651  * Implement the equal operation on XPath objects content: @arg1 == @arg2
       
  4652  * If one object to be compared is a node-set and the other is a number,
       
  4653  * then the comparison will be true if and only if there is a node in
       
  4654  * the node-set such that the result of performing the comparison on the
       
  4655  * number to be compared and on the result of converting the string-value
       
  4656  * of that node to a number using the number function is true.
       
  4657  *
       
  4658  * Returns 0 or 1 depending on the results of the test.
       
  4659  */
       
  4660 static int
       
  4661 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
       
  4662     xmlXPathObjectPtr arg, double f, int neq) {
       
  4663   int i, ret=0;
       
  4664   xmlNodeSetPtr ns;
       
  4665   xmlChar *str2;
       
  4666   xmlXPathObjectPtr val;
       
  4667   double v;
       
  4668 
       
  4669     if ((arg == NULL) ||
       
  4670     ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
       
  4671         return(0);
       
  4672 
       
  4673     ns = arg->nodesetval;
       
  4674     if (ns != NULL) {
       
  4675     for (i=0;i<ns->nodeNr;i++) {
       
  4676         str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
       
  4677         if (str2 != NULL) {
       
  4678         valuePush(ctxt, xmlXPathNewString(str2));
       
  4679         xmlFree(str2);
       
  4680         xmlXPathNumberFunction(ctxt, 1);
       
  4681         val = valuePop(ctxt);
       
  4682         v = val->floatval;
       
  4683         xmlXPathFreeObject(val);
       
  4684         if (!xmlXPathIsNaN(v)) {
       
  4685             if ((!neq) && (v==f)) {
       
  4686             ret = 1;
       
  4687             break;
       
  4688             } else if ((neq) && (v!=f)) {
       
  4689             ret = 1;
       
  4690             break;
       
  4691             }
       
  4692         }
       
  4693         }
       
  4694     }
       
  4695     }
       
  4696 
       
  4697     return(ret);
       
  4698 }
       
  4699 
       
  4700 
       
  4701 /**
       
  4702  * xmlXPathEqualNodeSets:
       
  4703  * @arg1:  first nodeset object argument
       
  4704  * @arg2:  second nodeset object argument
       
  4705  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
       
  4706  *
       
  4707  * Implement the equal / not equal operation on XPath nodesets:
       
  4708  * @arg1 == @arg2  or  @arg1 != @arg2
       
  4709  * If both objects to be compared are node-sets, then the comparison
       
  4710  * will be true if and only if there is a node in the first node-set and
       
  4711  * a node in the second node-set such that the result of performing the
       
  4712  * comparison on the string-values of the two nodes is true.
       
  4713  *
       
  4714  * (needless to say, this is a costly operation)
       
  4715  *
       
  4716  * Returns 0 or 1 depending on the results of the test.
       
  4717  */
       
  4718 static int
       
  4719 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
       
  4720     int i, j;
       
  4721     unsigned int *hashs1;
       
  4722     unsigned int *hashs2;
       
  4723     xmlChar **values1;
       
  4724     xmlChar **values2;
       
  4725     int ret = 0;
       
  4726     xmlNodeSetPtr ns1;
       
  4727     xmlNodeSetPtr ns2;
       
  4728 
       
  4729     if ((arg1 == NULL) ||
       
  4730     ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
       
  4731         return(0);
       
  4732     if ((arg2 == NULL) ||
       
  4733     ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
       
  4734         return(0);
       
  4735 
       
  4736     ns1 = arg1->nodesetval;
       
  4737     ns2 = arg2->nodesetval;
       
  4738 
       
  4739     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
       
  4740     return(0);
       
  4741     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
       
  4742     return(0);
       
  4743 
       
  4744     /*
       
  4745      * for equal, check if there is a node pertaining to both sets
       
  4746      */
       
  4747     if (neq == 0)
       
  4748     for (i = 0;i < ns1->nodeNr;i++)
       
  4749         for (j = 0;j < ns2->nodeNr;j++)
       
  4750         if (ns1->nodeTab[i] == ns2->nodeTab[j])
       
  4751             return(1);
       
  4752 
       
  4753     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
       
  4754     if (values1 == NULL) {
       
  4755         xmlXPathErrMemory(NULL, EMBED_ERRTXT("comparing nodesets\n"));
       
  4756     return(0);
       
  4757     }
       
  4758     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
       
  4759     if (hashs1 == NULL) {
       
  4760         xmlXPathErrMemory(NULL, EMBED_ERRTXT("comparing nodesets\n"));
       
  4761     xmlFree(values1);
       
  4762     return(0);
       
  4763     }
       
  4764     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
       
  4765     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
       
  4766     if (values2 == NULL) {
       
  4767         xmlXPathErrMemory(NULL, EMBED_ERRTXT("comparing nodesets\n"));
       
  4768     xmlFree(hashs1);
       
  4769     xmlFree(values1);
       
  4770     return(0);
       
  4771     }
       
  4772     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
       
  4773     if (hashs2 == NULL) {
       
  4774         xmlXPathErrMemory(NULL, EMBED_ERRTXT("comparing nodesets\n"));
       
  4775     xmlFree(hashs1);
       
  4776     xmlFree(values1);
       
  4777     xmlFree(values2);
       
  4778     return(0);
       
  4779     }
       
  4780     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
       
  4781     for (i = 0;i < ns1->nodeNr;i++) {
       
  4782     hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
       
  4783     for (j = 0;j < ns2->nodeNr;j++) {
       
  4784         if (i == 0)
       
  4785         hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
       
  4786         if (hashs1[i] != hashs2[j]) {
       
  4787         if (neq) {
       
  4788             ret = 1;
       
  4789             break;
       
  4790         }
       
  4791         }
       
  4792         else {
       
  4793         if (values1[i] == NULL)
       
  4794             values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
       
  4795         if (values2[j] == NULL)
       
  4796             values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
       
  4797         ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
       
  4798         if (ret)
       
  4799             break;
       
  4800         }
       
  4801     }
       
  4802     if (ret)
       
  4803         break;
       
  4804     }
       
  4805     for (i = 0;i < ns1->nodeNr;i++)
       
  4806     if (values1[i] != NULL)
       
  4807         xmlFree(values1[i]);
       
  4808     for (j = 0;j < ns2->nodeNr;j++)
       
  4809     if (values2[j] != NULL)
       
  4810         xmlFree(values2[j]);
       
  4811     xmlFree(values1);
       
  4812     xmlFree(values2);
       
  4813     xmlFree(hashs1);
       
  4814     xmlFree(hashs2);
       
  4815     return(ret);
       
  4816 }
       
  4817 
       
  4818 static int
       
  4819 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
       
  4820   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
       
  4821     int ret = 0;
       
  4822     /*
       
  4823      *At this point we are assured neither arg1 nor arg2
       
  4824      *is a nodeset, so we can just pick the appropriate routine.
       
  4825      */
       
  4826     switch (arg1->type) {
       
  4827         case XPATH_UNDEFINED:
       
  4828 #ifdef DEBUG_EXPR
       
  4829         xmlGenericError(xmlGenericErrorContext,
       
  4830             "Equal: undefined\n");
       
  4831 #endif
       
  4832         break;
       
  4833         case XPATH_BOOLEAN:
       
  4834         switch (arg2->type) {
       
  4835             case XPATH_UNDEFINED:
       
  4836 #ifdef DEBUG_EXPR
       
  4837             xmlGenericError(xmlGenericErrorContext,
       
  4838                 "Equal: undefined\n");
       
  4839 #endif
       
  4840             break;
       
  4841         case XPATH_BOOLEAN:
       
  4842 #ifdef DEBUG_EXPR
       
  4843             xmlGenericError(xmlGenericErrorContext,
       
  4844                 "Equal: %d boolean %d \n",
       
  4845                 arg1->boolval, arg2->boolval);
       
  4846 #endif
       
  4847             ret = (arg1->boolval == arg2->boolval);
       
  4848             break;
       
  4849         case XPATH_NUMBER:
       
  4850             ret = (arg1->boolval ==
       
  4851                xmlXPathCastNumberToBoolean(arg2->floatval));
       
  4852             break;
       
  4853         case XPATH_STRING:
       
  4854             if ((arg2->stringval == NULL) ||
       
  4855             (arg2->stringval[0] == 0)) ret = 0;
       
  4856             else
       
  4857             ret = 1;
       
  4858             ret = (arg1->boolval == ret);
       
  4859             break;
       
  4860         case XPATH_USERS:
       
  4861         case XPATH_POINT:
       
  4862         case XPATH_RANGE:
       
  4863         case XPATH_LOCATIONSET:
       
  4864             TODO
       
  4865             break;
       
  4866         case XPATH_NODESET:
       
  4867         case XPATH_XSLT_TREE:
       
  4868             break;
       
  4869         }
       
  4870         break;
       
  4871         case XPATH_NUMBER:
       
  4872         switch (arg2->type) {
       
  4873             case XPATH_UNDEFINED:
       
  4874 #ifdef DEBUG_EXPR
       
  4875             xmlGenericError(xmlGenericErrorContext,
       
  4876                 "Equal: undefined\n");
       
  4877 #endif
       
  4878             break;
       
  4879         case XPATH_BOOLEAN:
       
  4880             ret = (arg2->boolval==
       
  4881                xmlXPathCastNumberToBoolean(arg1->floatval));
       
  4882             break;
       
  4883         case XPATH_STRING:
       
  4884             valuePush(ctxt, arg2);
       
  4885             xmlXPathNumberFunction(ctxt, 1);
       
  4886             arg2 = valuePop(ctxt);
       
  4887             /* no break on purpose */
       
  4888         case XPATH_NUMBER:
       
  4889             /* Hand check NaN and Infinity equalities */
       
  4890             if (xmlXPathIsNaN(arg1->floatval) ||
       
  4891                     xmlXPathIsNaN(arg2->floatval)) {
       
  4892                 ret = 0;
       
  4893             } else if (xmlXPathIsInf(arg1->floatval) == 1) {
       
  4894                 if (xmlXPathIsInf(arg2->floatval) == 1)
       
  4895                 ret = 1;
       
  4896             else
       
  4897                 ret = 0;
       
  4898             } else if (xmlXPathIsInf(arg1->floatval) == -1) {
       
  4899             if (xmlXPathIsInf(arg2->floatval) == -1)
       
  4900                 ret = 1;
       
  4901             else
       
  4902                 ret = 0;
       
  4903             } else if (xmlXPathIsInf(arg2->floatval) == 1) {
       
  4904             if (xmlXPathIsInf(arg1->floatval) == 1)
       
  4905                 ret = 1;
       
  4906             else
       
  4907                 ret = 0;
       
  4908             } else if (xmlXPathIsInf(arg2->floatval) == -1) {
       
  4909             if (xmlXPathIsInf(arg1->floatval) == -1)
       
  4910                 ret = 1;
       
  4911             else
       
  4912                 ret = 0;
       
  4913             } else {
       
  4914                 ret = (arg1->floatval == arg2->floatval);
       
  4915             }
       
  4916             break;
       
  4917         case XPATH_USERS:
       
  4918         case XPATH_POINT:
       
  4919         case XPATH_RANGE:
       
  4920         case XPATH_LOCATIONSET:
       
  4921             TODO
       
  4922             break;
       
  4923         case XPATH_NODESET:
       
  4924         case XPATH_XSLT_TREE:
       
  4925             break;
       
  4926         }
       
  4927         break;
       
  4928         case XPATH_STRING:
       
  4929         switch (arg2->type) {
       
  4930             case XPATH_UNDEFINED:
       
  4931 #ifdef DEBUG_EXPR
       
  4932             xmlGenericError(xmlGenericErrorContext,
       
  4933                 "Equal: undefined\n");
       
  4934 #endif
       
  4935             break;
       
  4936         case XPATH_BOOLEAN:
       
  4937             if ((arg1->stringval == NULL) ||
       
  4938             (arg1->stringval[0] == 0)) ret = 0;
       
  4939             else
       
  4940             ret = 1;
       
  4941             ret = (arg2->boolval == ret);
       
  4942             break;
       
  4943         case XPATH_STRING:
       
  4944             ret = xmlStrEqual(arg1->stringval, arg2->stringval);
       
  4945             break;
       
  4946         case XPATH_NUMBER:
       
  4947             valuePush(ctxt, arg1);
       
  4948             xmlXPathNumberFunction(ctxt, 1);
       
  4949             arg1 = valuePop(ctxt);
       
  4950             /* Hand check NaN and Infinity equalities */
       
  4951             if (xmlXPathIsNaN(arg1->floatval) ||
       
  4952                     xmlXPathIsNaN(arg2->floatval)) {
       
  4953                 ret = 0;
       
  4954             } else if (xmlXPathIsInf(arg1->floatval) == 1) {
       
  4955             if (xmlXPathIsInf(arg2->floatval) == 1)
       
  4956                 ret = 1;
       
  4957             else
       
  4958                 ret = 0;
       
  4959             } else if (xmlXPathIsInf(arg1->floatval) == -1) {
       
  4960             if (xmlXPathIsInf(arg2->floatval) == -1)
       
  4961                 ret = 1;
       
  4962             else
       
  4963                 ret = 0;
       
  4964             } else if (xmlXPathIsInf(arg2->floatval) == 1) {
       
  4965             if (xmlXPathIsInf(arg1->floatval) == 1)
       
  4966                 ret = 1;
       
  4967             else
       
  4968                 ret = 0;
       
  4969             } else if (xmlXPathIsInf(arg2->floatval) == -1) {
       
  4970             if (xmlXPathIsInf(arg1->floatval) == -1)
       
  4971                 ret = 1;
       
  4972             else
       
  4973                 ret = 0;
       
  4974             } else {
       
  4975                 ret = (arg1->floatval == arg2->floatval);
       
  4976             }
       
  4977             break;
       
  4978         case XPATH_USERS:
       
  4979         case XPATH_POINT:
       
  4980         case XPATH_RANGE:
       
  4981         case XPATH_LOCATIONSET:
       
  4982             TODO
       
  4983             break;
       
  4984         case XPATH_NODESET:
       
  4985         case XPATH_XSLT_TREE:
       
  4986             break;
       
  4987         }
       
  4988         break;
       
  4989         case XPATH_USERS:
       
  4990     case XPATH_POINT:
       
  4991     case XPATH_RANGE:
       
  4992     case XPATH_LOCATIONSET:
       
  4993         TODO
       
  4994         break;
       
  4995     case XPATH_NODESET:
       
  4996     case XPATH_XSLT_TREE:
       
  4997         break;
       
  4998     }
       
  4999     xmlXPathFreeObject(arg1);
       
  5000     xmlXPathFreeObject(arg2);
       
  5001     return(ret);
       
  5002 }
       
  5003 
       
  5004 /**
       
  5005  * xmlXPathEqualValues:
       
  5006  * @ctxt:  the XPath Parser context
       
  5007  *
       
  5008  * Implement the equal operation on XPath objects content: @arg1 == @arg2
       
  5009  *
       
  5010  * Returns 0 or 1 depending on the results of the test.
       
  5011  */
       
  5012 int
       
  5013 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
       
  5014     xmlXPathObjectPtr arg1, arg2, argtmp;
       
  5015     int ret = 0;
       
  5016 
       
  5017     arg2 = valuePop(ctxt);
       
  5018     arg1 = valuePop(ctxt);
       
  5019     if ((arg1 == NULL) || (arg2 == NULL)) {
       
  5020     if (arg1 != NULL)
       
  5021         xmlXPathFreeObject(arg1);
       
  5022     else
       
  5023         xmlXPathFreeObject(arg2);
       
  5024     XP_ERROR0(XPATH_INVALID_OPERAND);
       
  5025     }
       
  5026 
       
  5027     if (arg1 == arg2) {
       
  5028 #ifdef DEBUG_EXPR
       
  5029         xmlGenericError(xmlGenericErrorContext,
       
  5030         "Equal: by pointer\n");
       
  5031 #endif
       
  5032         return(1);
       
  5033     }
       
  5034 
       
  5035     /*
       
  5036      *If either argument is a nodeset, it's a 'special case'
       
  5037      */
       
  5038     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
       
  5039       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
       
  5040     /*
       
  5041      *Hack it to assure arg1 is the nodeset
       
  5042      */
       
  5043     if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
       
  5044         argtmp = arg2;
       
  5045         arg2 = arg1;
       
  5046         arg1 = argtmp;
       
  5047     }
       
  5048     switch (arg2->type) {
       
  5049         case XPATH_UNDEFINED:
       
  5050 #ifdef DEBUG_EXPR
       
  5051         xmlGenericError(xmlGenericErrorContext,
       
  5052             "Equal: undefined\n");
       
  5053 #endif
       
  5054         break;
       
  5055         case XPATH_NODESET:
       
  5056         case XPATH_XSLT_TREE:
       
  5057         ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
       
  5058         break;
       
  5059         case XPATH_BOOLEAN:
       
  5060         if ((arg1->nodesetval == NULL) ||
       
  5061           (arg1->nodesetval->nodeNr == 0)) ret = 0;
       
  5062         else
       
  5063             ret = 1;
       
  5064         ret = (ret == arg2->boolval);
       
  5065         break;
       
  5066         case XPATH_NUMBER:
       
  5067         ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
       
  5068         break;
       
  5069         case XPATH_STRING:
       
  5070         ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
       
  5071         break;
       
  5072         case XPATH_USERS:
       
  5073         case XPATH_POINT:
       
  5074         case XPATH_RANGE:
       
  5075         case XPATH_LOCATIONSET:
       
  5076         TODO
       
  5077         break;
       
  5078     }
       
  5079     xmlXPathFreeObject(arg1);
       
  5080     xmlXPathFreeObject(arg2);
       
  5081     return(ret);
       
  5082     }
       
  5083 
       
  5084     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
       
  5085 }
       
  5086 
       
  5087 /**
       
  5088  * xmlXPathNotEqualValues:
       
  5089  * @ctxt:  the XPath Parser context
       
  5090  *
       
  5091  * Implement the equal operation on XPath objects content: @arg1 == @arg2
       
  5092  *
       
  5093  * Returns 0 or 1 depending on the results of the test.
       
  5094  */
       
  5095 int
       
  5096 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
       
  5097     xmlXPathObjectPtr arg1, arg2, argtmp;
       
  5098     int ret = 0;
       
  5099 
       
  5100     arg2 = valuePop(ctxt);
       
  5101     arg1 = valuePop(ctxt);
       
  5102     if ((arg1 == NULL) || (arg2 == NULL)) {
       
  5103     if (arg1 != NULL)
       
  5104         xmlXPathFreeObject(arg1);
       
  5105     else
       
  5106         xmlXPathFreeObject(arg2);
       
  5107     XP_ERROR0(XPATH_INVALID_OPERAND);
       
  5108     }
       
  5109 
       
  5110     if (arg1 == arg2) {
       
  5111 #ifdef DEBUG_EXPR
       
  5112         xmlGenericError(xmlGenericErrorContext,
       
  5113         "NotEqual: by pointer\n");
       
  5114 #endif
       
  5115         return(0);
       
  5116     }
       
  5117 
       
  5118     /*
       
  5119      *If either argument is a nodeset, it's a 'special case'
       
  5120      */
       
  5121     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
       
  5122       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
       
  5123     /*
       
  5124      *Hack it to assure arg1 is the nodeset
       
  5125      */
       
  5126     if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
       
  5127         argtmp = arg2;
       
  5128         arg2 = arg1;
       
  5129         arg1 = argtmp;
       
  5130     }
       
  5131     switch (arg2->type) {
       
  5132         case XPATH_UNDEFINED:
       
  5133 #ifdef DEBUG_EXPR
       
  5134         xmlGenericError(xmlGenericErrorContext,
       
  5135             "NotEqual: undefined\n");
       
  5136 #endif
       
  5137         break;
       
  5138         case XPATH_NODESET:
       
  5139         case XPATH_XSLT_TREE:
       
  5140         ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
       
  5141         break;
       
  5142         case XPATH_BOOLEAN:
       
  5143         if ((arg1->nodesetval == NULL) ||
       
  5144           (arg1->nodesetval->nodeNr == 0)) ret = 0;
       
  5145         else
       
  5146             ret = 1;
       
  5147         ret = (ret != arg2->boolval);
       
  5148         break;
       
  5149         case XPATH_NUMBER:
       
  5150         ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
       
  5151         break;
       
  5152         case XPATH_STRING:
       
  5153         ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
       
  5154         break;
       
  5155         case XPATH_USERS:
       
  5156         case XPATH_POINT:
       
  5157         case XPATH_RANGE:
       
  5158         case XPATH_LOCATIONSET:
       
  5159         TODO
       
  5160         break;
       
  5161     }
       
  5162     xmlXPathFreeObject(arg1);
       
  5163     xmlXPathFreeObject(arg2);
       
  5164     return(ret);
       
  5165     }
       
  5166 
       
  5167     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
       
  5168 }
       
  5169 
       
  5170 /**
       
  5171  * xmlXPathCompareValues:
       
  5172  * @ctxt:  the XPath Parser context
       
  5173  * @inf:  less than (1) or greater than (0)
       
  5174  * @strict:  is the comparison strict
       
  5175  *
       
  5176  * Implement the compare operation on XPath objects:
       
  5177  *     @arg1 < @arg2    (1, 1, ...
       
  5178  *     @arg1 <= @arg2   (1, 0, ...
       
  5179  *     @arg1 > @arg2    (0, 1, ...
       
  5180  *     @arg1 >= @arg2   (0, 0, ...
       
  5181  *
       
  5182  * When neither object to be compared is a node-set and the operator is
       
  5183  * <=, <, >=, >, then the objects are compared by converted both objects
       
  5184  * to numbers and comparing the numbers according to IEEE 754. The <
       
  5185  * comparison will be true if and only if the first number is less than the
       
  5186  * second number. The <= comparison will be true if and only if the first
       
  5187  * number is less than or equal to the second number. The > comparison
       
  5188  * will be true if and only if the first number is greater than the second
       
  5189  * number. The >= comparison will be true if and only if the first number
       
  5190  * is greater than or equal to the second number.
       
  5191  *
       
  5192  * Returns 1 if the comparison succeeded, 0 if it failed
       
  5193  */
       
  5194 int
       
  5195 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
       
  5196     int ret = 0, arg1i = 0, arg2i = 0;
       
  5197     xmlXPathObjectPtr arg1, arg2;
       
  5198 
       
  5199     arg2 = valuePop(ctxt);
       
  5200     arg1 = valuePop(ctxt);
       
  5201     if ((arg1 == NULL) || (arg2 == NULL)) {
       
  5202     if (arg1 != NULL)
       
  5203         xmlXPathFreeObject(arg1);
       
  5204     else
       
  5205         xmlXPathFreeObject(arg2);
       
  5206     XP_ERROR0(XPATH_INVALID_OPERAND);
       
  5207     }
       
  5208 
       
  5209     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
       
  5210       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
       
  5211     if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
       
  5212       ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
       
  5213         ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
       
  5214     } else {
       
  5215         if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
       
  5216         ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
       
  5217                                       arg1, arg2);
       
  5218         } else {
       
  5219         ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
       
  5220                                       arg2, arg1);
       
  5221         }
       
  5222     }
       
  5223     return(ret);
       
  5224     }
       
  5225 
       
  5226     if (arg1->type != XPATH_NUMBER) {
       
  5227     valuePush(ctxt, arg1);
       
  5228     xmlXPathNumberFunction(ctxt, 1);
       
  5229     arg1 = valuePop(ctxt);
       
  5230     }
       
  5231     if (arg1->type != XPATH_NUMBER) {
       
  5232     xmlXPathFreeObject(arg1);
       
  5233     xmlXPathFreeObject(arg2);
       
  5234     XP_ERROR0(XPATH_INVALID_OPERAND);
       
  5235     }
       
  5236     if (arg2->type != XPATH_NUMBER) {
       
  5237     valuePush(ctxt, arg2);
       
  5238     xmlXPathNumberFunction(ctxt, 1);
       
  5239     arg2 = valuePop(ctxt);
       
  5240     }
       
  5241     if (arg2->type != XPATH_NUMBER) {
       
  5242     xmlXPathFreeObject(arg1);
       
  5243     xmlXPathFreeObject(arg2);
       
  5244     XP_ERROR0(XPATH_INVALID_OPERAND);
       
  5245     }
       
  5246     /*
       
  5247      * Add tests for infinity and nan
       
  5248      * => feedback on 3.4 for Inf and NaN
       
  5249      */
       
  5250     /* Hand check NaN and Infinity comparisons */
       
  5251     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
       
  5252     ret=0;
       
  5253     } else {
       
  5254     arg1i=xmlXPathIsInf(arg1->floatval);
       
  5255     arg2i=xmlXPathIsInf(arg2->floatval);
       
  5256     if (inf && strict) {
       
  5257         if ((arg1i == -1 && arg2i != -1) ||
       
  5258         (arg2i == 1 && arg1i != 1)) {
       
  5259         ret = 1;
       
  5260         } else if (arg1i == 0 && arg2i == 0) {
       
  5261         ret = (arg1->floatval < arg2->floatval);
       
  5262         } else {
       
  5263         ret = 0;
       
  5264         }
       
  5265     }
       
  5266     else if (inf && !strict) {
       
  5267         if (arg1i == -1 || arg2i == 1) {
       
  5268         ret = 1;
       
  5269         } else if (arg1i == 0 && arg2i == 0) {
       
  5270         ret = (arg1->floatval <= arg2->floatval);
       
  5271         } else {
       
  5272         ret = 0;
       
  5273         }
       
  5274     }
       
  5275     else if (!inf && strict) {
       
  5276         if ((arg1i == 1 && arg2i != 1) ||
       
  5277         (arg2i == -1 && arg1i != -1)) {
       
  5278         ret = 1;
       
  5279         } else if (arg1i == 0 && arg2i == 0) {
       
  5280         ret = (arg1->floatval > arg2->floatval);
       
  5281         } else {
       
  5282         ret = 0;
       
  5283         }
       
  5284     }
       
  5285     else if (!inf && !strict) {
       
  5286         if (arg1i == 1 || arg2i == -1) {
       
  5287         ret = 1;
       
  5288         } else if (arg1i == 0 && arg2i == 0) {
       
  5289         ret = (arg1->floatval >= arg2->floatval);
       
  5290         } else {
       
  5291         ret = 0;
       
  5292         }
       
  5293     }
       
  5294     }
       
  5295     xmlXPathFreeObject(arg1);
       
  5296     xmlXPathFreeObject(arg2);
       
  5297     return(ret);
       
  5298 }
       
  5299 
       
  5300 /**
       
  5301  * xmlXPathValueFlipSign:
       
  5302  * @ctxt:  the XPath Parser context
       
  5303  *
       
  5304  * Implement the unary - operation on an XPath object
       
  5305  * The numeric operators convert their operands to numbers as if
       
  5306  * by calling the number function.
       
  5307  */
       
  5308 void
       
  5309 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
       
  5310     CAST_TO_NUMBER;
       
  5311     CHECK_TYPE(XPATH_NUMBER);
       
  5312     if (xmlXPathIsNaN(ctxt->value->floatval))
       
  5313         ctxt->value->floatval=xmlXPathNAN;
       
  5314     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
       
  5315         ctxt->value->floatval=xmlXPathNINF;
       
  5316     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
       
  5317         ctxt->value->floatval=xmlXPathPINF;
       
  5318     else if (ctxt->value->floatval == 0) {
       
  5319         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
       
  5320         ctxt->value->floatval = xmlXPathNZERO;
       
  5321     else
       
  5322         ctxt->value->floatval = 0;
       
  5323     }
       
  5324     else
       
  5325         ctxt->value->floatval = - ctxt->value->floatval;
       
  5326 }
       
  5327 
       
  5328 /**
       
  5329  * xmlXPathAddValues:
       
  5330  * @ctxt:  the XPath Parser context
       
  5331  *
       
  5332  * Implement the add operation on XPath objects:
       
  5333  * The numeric operators convert their operands to numbers as if
       
  5334  * by calling the number function.
       
  5335  */
       
  5336 void
       
  5337 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
       
  5338     xmlXPathObjectPtr arg;
       
  5339     double val;
       
  5340 
       
  5341     arg = valuePop(ctxt);
       
  5342     if (arg == NULL)
       
  5343     XP_ERROR(XPATH_INVALID_OPERAND);
       
  5344     val = xmlXPathCastToNumber(arg);
       
  5345     xmlXPathFreeObject(arg);
       
  5346 
       
  5347     CAST_TO_NUMBER;
       
  5348     CHECK_TYPE(XPATH_NUMBER);
       
  5349     ctxt->value->floatval += val;
       
  5350 }
       
  5351 
       
  5352 /**
       
  5353  * xmlXPathSubValues:
       
  5354  * @ctxt:  the XPath Parser context
       
  5355  *
       
  5356  * Implement the subtraction operation on XPath objects:
       
  5357  * The numeric operators convert their operands to numbers as if
       
  5358  * by calling the number function.
       
  5359  */
       
  5360 void
       
  5361 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
       
  5362     xmlXPathObjectPtr arg;
       
  5363     double val;
       
  5364 
       
  5365     arg = valuePop(ctxt);
       
  5366     if (arg == NULL)
       
  5367     XP_ERROR(XPATH_INVALID_OPERAND);
       
  5368     val = xmlXPathCastToNumber(arg);
       
  5369     xmlXPathFreeObject(arg);
       
  5370 
       
  5371     CAST_TO_NUMBER;
       
  5372     CHECK_TYPE(XPATH_NUMBER);
       
  5373     ctxt->value->floatval -= val;
       
  5374 }
       
  5375 
       
  5376 /**
       
  5377  * xmlXPathMultValues:
       
  5378  * @ctxt:  the XPath Parser context
       
  5379  *
       
  5380  * Implement the multiply operation on XPath objects:
       
  5381  * The numeric operators convert their operands to numbers as if
       
  5382  * by calling the number function.
       
  5383  */
       
  5384 void
       
  5385 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
       
  5386     xmlXPathObjectPtr arg;
       
  5387     double val;
       
  5388 
       
  5389     arg = valuePop(ctxt);
       
  5390     if (arg == NULL)
       
  5391     XP_ERROR(XPATH_INVALID_OPERAND);
       
  5392     val = xmlXPathCastToNumber(arg);
       
  5393     xmlXPathFreeObject(arg);
       
  5394 
       
  5395     CAST_TO_NUMBER;
       
  5396     CHECK_TYPE(XPATH_NUMBER);
       
  5397     ctxt->value->floatval *= val;
       
  5398 }
       
  5399 
       
  5400 /**
       
  5401  * xmlXPathDivValues:
       
  5402  * @ctxt:  the XPath Parser context
       
  5403  *
       
  5404  * Implement the div operation on XPath objects @arg1 / @arg2:
       
  5405  * The numeric operators convert their operands to numbers as if
       
  5406  * by calling the number function.
       
  5407  */
       
  5408 void
       
  5409 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
       
  5410     xmlXPathObjectPtr arg;
       
  5411     double val;
       
  5412 
       
  5413     arg = valuePop(ctxt);
       
  5414     if (arg == NULL)
       
  5415     XP_ERROR(XPATH_INVALID_OPERAND);
       
  5416     val = xmlXPathCastToNumber(arg);
       
  5417     xmlXPathFreeObject(arg);
       
  5418 
       
  5419     CAST_TO_NUMBER;
       
  5420     CHECK_TYPE(XPATH_NUMBER);
       
  5421     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
       
  5422     ctxt->value->floatval = xmlXPathNAN;
       
  5423     else if (val == 0 && xmlXPathGetSign(val) != 0) {
       
  5424     if (ctxt->value->floatval == 0)
       
  5425         ctxt->value->floatval = xmlXPathNAN;
       
  5426     else if (ctxt->value->floatval > 0)
       
  5427         ctxt->value->floatval = xmlXPathNINF;
       
  5428     else if (ctxt->value->floatval < 0)
       
  5429         ctxt->value->floatval = xmlXPathPINF;
       
  5430     }
       
  5431     else if (val == 0) {
       
  5432     if (ctxt->value->floatval == 0)
       
  5433         ctxt->value->floatval = xmlXPathNAN;
       
  5434     else if (ctxt->value->floatval > 0)
       
  5435         ctxt->value->floatval = xmlXPathPINF;
       
  5436     else if (ctxt->value->floatval < 0)
       
  5437         ctxt->value->floatval = xmlXPathNINF;
       
  5438     } else
       
  5439     ctxt->value->floatval /= val;
       
  5440 }
       
  5441 
       
  5442 /**
       
  5443  * xmlXPathModValues:
       
  5444  * @ctxt:  the XPath Parser context
       
  5445  *
       
  5446  * Implement the mod operation on XPath objects: @arg1 / @arg2
       
  5447  * The numeric operators convert their operands to numbers as if
       
  5448  * by calling the number function.
       
  5449  */
       
  5450 void
       
  5451 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
       
  5452     xmlXPathObjectPtr arg;
       
  5453     double arg1, arg2;
       
  5454 
       
  5455     arg = valuePop(ctxt);
       
  5456     if (arg == NULL)
       
  5457     XP_ERROR(XPATH_INVALID_OPERAND);
       
  5458     arg2 = xmlXPathCastToNumber(arg);
       
  5459     xmlXPathFreeObject(arg);
       
  5460 
       
  5461     CAST_TO_NUMBER;
       
  5462     CHECK_TYPE(XPATH_NUMBER);
       
  5463     arg1 = ctxt->value->floatval;
       
  5464     if (arg2 == 0)
       
  5465     ctxt->value->floatval = xmlXPathNAN;
       
  5466     else {
       
  5467     ctxt->value->floatval = fmod(arg1, arg2);
       
  5468     }
       
  5469 }
       
  5470 
       
  5471 /************************************************************************
       
  5472  *                                  *
       
  5473  *      The traversal functions                 *
       
  5474  *                                  *
       
  5475  ************************************************************************/
       
  5476 
       
  5477 /*
       
  5478  * A traversal function enumerates nodes along an axis.
       
  5479  * Initially it must be called with NULL, and it indicates
       
  5480  * termination on the axis by returning NULL.
       
  5481  */
       
  5482 typedef xmlNodePtr (*xmlXPathTraversalFunction)
       
  5483                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
       
  5484 
       
  5485 /**
       
  5486  * xmlXPathNextSelf:
       
  5487  * @ctxt:  the XPath Parser context
       
  5488  * @cur:  the current node in the traversal
       
  5489  *
       
  5490  * Traversal function for the "self" direction
       
  5491  * The self axis contains just the context node itself
       
  5492  *
       
  5493  * Returns the next element following that axis
       
  5494  */
       
  5495 xmlNodePtr
       
  5496 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5497     if (cur == NULL)
       
  5498         return(ctxt->context->node);
       
  5499     return(NULL);
       
  5500 }
       
  5501 
       
  5502 /**
       
  5503  * xmlXPathNextChild:
       
  5504  * @ctxt:  the XPath Parser context
       
  5505  * @cur:  the current node in the traversal
       
  5506  *
       
  5507  * Traversal function for the "child" direction
       
  5508  * The child axis contains the children of the context node in document order.
       
  5509  *
       
  5510  * Returns the next element following that axis
       
  5511  */
       
  5512 xmlNodePtr
       
  5513 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5514     if (cur == NULL) {
       
  5515     if (ctxt->context->node == NULL) return(NULL);
       
  5516     switch (ctxt->context->node->type) {
       
  5517             case XML_ELEMENT_NODE:
       
  5518             case XML_TEXT_NODE:
       
  5519             case XML_CDATA_SECTION_NODE:
       
  5520             case XML_ENTITY_REF_NODE:
       
  5521             case XML_ENTITY_NODE:
       
  5522             case XML_PI_NODE:
       
  5523             case XML_COMMENT_NODE:
       
  5524             case XML_NOTATION_NODE:
       
  5525             case XML_DTD_NODE:
       
  5526         return(ctxt->context->node->children);
       
  5527             case XML_DOCUMENT_NODE:
       
  5528             case XML_DOCUMENT_TYPE_NODE:
       
  5529             case XML_DOCUMENT_FRAG_NODE:
       
  5530             case XML_HTML_DOCUMENT_NODE:
       
  5531 #ifdef LIBXML_DOCB_ENABLED
       
  5532         case XML_DOCB_DOCUMENT_NODE:
       
  5533 #endif
       
  5534             return(((xmlDocPtr) ctxt->context->node)->children);
       
  5535         case XML_ELEMENT_DECL:
       
  5536         case XML_ATTRIBUTE_DECL:
       
  5537         case XML_ENTITY_DECL:
       
  5538             case XML_ATTRIBUTE_NODE:
       
  5539         case XML_NAMESPACE_DECL:
       
  5540         case XML_XINCLUDE_START:
       
  5541         case XML_XINCLUDE_END:
       
  5542         return(NULL);
       
  5543     }
       
  5544     return(NULL);
       
  5545     }
       
  5546     if ((cur->type == XML_DOCUMENT_NODE) ||
       
  5547         (cur->type == XML_HTML_DOCUMENT_NODE))
       
  5548     return(NULL);
       
  5549     return(cur->next);
       
  5550 }
       
  5551 
       
  5552 /**
       
  5553  * xmlXPathNextDescendant:
       
  5554  * @ctxt:  the XPath Parser context
       
  5555  * @cur:  the current node in the traversal
       
  5556  *
       
  5557  * Traversal function for the "descendant" direction
       
  5558  * the descendant axis contains the descendants of the context node in document
       
  5559  * order; a descendant is a child or a child of a child and so on.
       
  5560  *
       
  5561  * Returns the next element following that axis
       
  5562  */
       
  5563 xmlNodePtr
       
  5564 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5565     if (cur == NULL) {
       
  5566     if (ctxt->context->node == NULL)
       
  5567         return(NULL);
       
  5568     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
       
  5569         (ctxt->context->node->type == XML_NAMESPACE_DECL))
       
  5570         return(NULL);
       
  5571 
       
  5572         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
       
  5573             return(ctxt->context->doc->children);
       
  5574         return(ctxt->context->node->children);
       
  5575     }
       
  5576 
       
  5577     if (cur->children != NULL) {
       
  5578     /*
       
  5579      * Do not descend on entities declarations
       
  5580      */
       
  5581         if (cur->children->type != XML_ENTITY_DECL) {
       
  5582         cur = cur->children;
       
  5583         /*
       
  5584          * Skip DTDs
       
  5585          */
       
  5586         if (cur->type != XML_DTD_NODE)
       
  5587         return(cur);
       
  5588     }
       
  5589     }
       
  5590 
       
  5591     if (cur == ctxt->context->node) return(NULL);
       
  5592 
       
  5593     while (cur->next != NULL) {
       
  5594     cur = cur->next;
       
  5595     if ((cur->type != XML_ENTITY_DECL) &&
       
  5596         (cur->type != XML_DTD_NODE))
       
  5597         return(cur);
       
  5598     }
       
  5599 
       
  5600     do {
       
  5601         cur = cur->parent;
       
  5602     if (cur == NULL) return(NULL);
       
  5603     if (cur == ctxt->context->node) return(NULL);
       
  5604     if (cur->next != NULL) {
       
  5605         cur = cur->next;
       
  5606         return(cur);
       
  5607     }
       
  5608     } while (cur != NULL);
       
  5609     return(cur);
       
  5610 }
       
  5611 
       
  5612 /**
       
  5613  * xmlXPathNextDescendantOrSelf:
       
  5614  * @ctxt:  the XPath Parser context
       
  5615  * @cur:  the current node in the traversal
       
  5616  *
       
  5617  * Traversal function for the "descendant-or-self" direction
       
  5618  * the descendant-or-self axis contains the context node and the descendants
       
  5619  * of the context node in document order; thus the context node is the first
       
  5620  * node on the axis, and the first child of the context node is the second node
       
  5621  * on the axis
       
  5622  *
       
  5623  * Returns the next element following that axis
       
  5624  */
       
  5625 xmlNodePtr
       
  5626 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5627     if (cur == NULL) {
       
  5628     if (ctxt->context->node == NULL)
       
  5629         return(NULL);
       
  5630     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
       
  5631         (ctxt->context->node->type == XML_NAMESPACE_DECL))
       
  5632         return(NULL);
       
  5633         return(ctxt->context->node);
       
  5634     }
       
  5635 
       
  5636     return(xmlXPathNextDescendant(ctxt, cur));
       
  5637 }
       
  5638 
       
  5639 /**
       
  5640  * xmlXPathNextParent:
       
  5641  * @ctxt:  the XPath Parser context
       
  5642  * @cur:  the current node in the traversal
       
  5643  *
       
  5644  * Traversal function for the "parent" direction
       
  5645  * The parent axis contains the parent of the context node, if there is one.
       
  5646  *
       
  5647  * Returns the next element following that axis
       
  5648  */
       
  5649 xmlNodePtr
       
  5650 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5651     /*
       
  5652      * the parent of an attribute or namespace node is the element
       
  5653      * to which the attribute or namespace node is attached
       
  5654      * Namespace handling !!!
       
  5655      */
       
  5656     if (cur == NULL) {
       
  5657     if (ctxt->context->node == NULL) return(NULL);
       
  5658     switch (ctxt->context->node->type) {
       
  5659             case XML_ELEMENT_NODE:
       
  5660             case XML_TEXT_NODE:
       
  5661             case XML_CDATA_SECTION_NODE:
       
  5662             case XML_ENTITY_REF_NODE:
       
  5663             case XML_ENTITY_NODE:
       
  5664             case XML_PI_NODE:
       
  5665             case XML_COMMENT_NODE:
       
  5666             case XML_NOTATION_NODE:
       
  5667             case XML_DTD_NODE:
       
  5668         case XML_ELEMENT_DECL:
       
  5669         case XML_ATTRIBUTE_DECL:
       
  5670         case XML_XINCLUDE_START:
       
  5671         case XML_XINCLUDE_END:
       
  5672         case XML_ENTITY_DECL:
       
  5673         if (ctxt->context->node->parent == NULL)
       
  5674             return((xmlNodePtr) ctxt->context->doc);
       
  5675         if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
       
  5676             ((ctxt->context->node->parent->name[0] == ' ') ||
       
  5677              (xmlStrEqual(ctxt->context->node->parent->name,
       
  5678                  BAD_CAST "fake node libxslt"))))
       
  5679             return(NULL);
       
  5680         return(ctxt->context->node->parent);
       
  5681             case XML_ATTRIBUTE_NODE: {
       
  5682         xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
       
  5683 
       
  5684         return(att->parent);
       
  5685         }
       
  5686             case XML_DOCUMENT_NODE:
       
  5687             case XML_DOCUMENT_TYPE_NODE:
       
  5688             case XML_DOCUMENT_FRAG_NODE:
       
  5689             case XML_HTML_DOCUMENT_NODE:
       
  5690 #ifdef LIBXML_DOCB_ENABLED
       
  5691         case XML_DOCB_DOCUMENT_NODE:
       
  5692 #endif
       
  5693                 return(NULL);
       
  5694         case XML_NAMESPACE_DECL: {
       
  5695             xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
       
  5696 
       
  5697             if ((ns->next != NULL) &&
       
  5698                 (ns->next->type != XML_NAMESPACE_DECL))
       
  5699                 return((xmlNodePtr) ns->next);
       
  5700                     return(NULL);
       
  5701         }
       
  5702     }
       
  5703     }
       
  5704     return(NULL);
       
  5705 }
       
  5706 
       
  5707 /**
       
  5708  * xmlXPathNextAncestor:
       
  5709  * @ctxt:  the XPath Parser context
       
  5710  * @cur:  the current node in the traversal
       
  5711  *
       
  5712  * Traversal function for the "ancestor" direction
       
  5713  * the ancestor axis contains the ancestors of the context node; the ancestors
       
  5714  * of the context node consist of the parent of context node and the parent's
       
  5715  * parent and so on; the nodes are ordered in reverse document order; thus the
       
  5716  * parent is the first node on the axis, and the parent's parent is the second
       
  5717  * node on the axis
       
  5718  *
       
  5719  * Returns the next element following that axis
       
  5720  */
       
  5721 xmlNodePtr
       
  5722 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5723     /*
       
  5724      * the parent of an attribute or namespace node is the element
       
  5725      * to which the attribute or namespace node is attached
       
  5726      * !!!!!!!!!!!!!
       
  5727      */
       
  5728     if (cur == NULL) {
       
  5729     if (ctxt->context->node == NULL) return(NULL);
       
  5730     switch (ctxt->context->node->type) {
       
  5731             case XML_ELEMENT_NODE:
       
  5732             case XML_TEXT_NODE:
       
  5733             case XML_CDATA_SECTION_NODE:
       
  5734             case XML_ENTITY_REF_NODE:
       
  5735             case XML_ENTITY_NODE:
       
  5736             case XML_PI_NODE:
       
  5737             case XML_COMMENT_NODE:
       
  5738             case XML_DTD_NODE:
       
  5739             case XML_ELEMENT_DECL:
       
  5740             case XML_ATTRIBUTE_DECL:
       
  5741             case XML_ENTITY_DECL:
       
  5742             case XML_NOTATION_NODE:
       
  5743             case XML_XINCLUDE_START:
       
  5744             case XML_XINCLUDE_END:
       
  5745                 if (ctxt->context->node->parent == NULL)
       
  5746                     return((xmlNodePtr) ctxt->context->doc);
       
  5747                 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
       
  5748                     ((ctxt->context->node->parent->name[0] == ' ') ||
       
  5749                      (xmlStrEqual(ctxt->context->node->parent->name,
       
  5750                          BAD_CAST "fake node libxslt"))))
       
  5751                     return(NULL);
       
  5752                 return(ctxt->context->node->parent);
       
  5753             case XML_ATTRIBUTE_NODE: {
       
  5754                 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
       
  5755 
       
  5756                 return(tmp->parent);
       
  5757                 }
       
  5758              case XML_DOCUMENT_NODE:
       
  5759              case XML_DOCUMENT_TYPE_NODE:
       
  5760              case XML_DOCUMENT_FRAG_NODE:
       
  5761              case XML_HTML_DOCUMENT_NODE:
       
  5762 #ifdef LIBXML_DOCB_ENABLED
       
  5763             case XML_DOCB_DOCUMENT_NODE:
       
  5764 #endif
       
  5765                 return(NULL);
       
  5766             case XML_NAMESPACE_DECL: {
       
  5767                 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
       
  5768 
       
  5769                 if ((ns->next != NULL) &&
       
  5770                     (ns->next->type != XML_NAMESPACE_DECL))
       
  5771                     return((xmlNodePtr) ns->next);
       
  5772                 /* Bad, how did that namespace end up here ? */
       
  5773                         return(NULL);
       
  5774         }
       
  5775     }
       
  5776     return(NULL);
       
  5777     }
       
  5778     if (cur == ctxt->context->doc->children)
       
  5779     return((xmlNodePtr) ctxt->context->doc);
       
  5780     if (cur == (xmlNodePtr) ctxt->context->doc)
       
  5781     return(NULL);
       
  5782     switch (cur->type) {
       
  5783     case XML_ELEMENT_NODE:
       
  5784     case XML_TEXT_NODE:
       
  5785     case XML_CDATA_SECTION_NODE:
       
  5786     case XML_ENTITY_REF_NODE:
       
  5787     case XML_ENTITY_NODE:
       
  5788     case XML_PI_NODE:
       
  5789     case XML_COMMENT_NODE:
       
  5790     case XML_NOTATION_NODE:
       
  5791     case XML_DTD_NODE:
       
  5792         case XML_ELEMENT_DECL:
       
  5793         case XML_ATTRIBUTE_DECL:
       
  5794         case XML_ENTITY_DECL:
       
  5795     case XML_XINCLUDE_START:
       
  5796     case XML_XINCLUDE_END:
       
  5797         if (cur->parent == NULL)
       
  5798         return(NULL);
       
  5799         if ((cur->parent->type == XML_ELEMENT_NODE) &&
       
  5800         ((cur->parent->name[0] == ' ') ||
       
  5801          (xmlStrEqual(cur->parent->name,
       
  5802                   BAD_CAST "fake node libxslt"))))
       
  5803         return(NULL);
       
  5804         return(cur->parent);
       
  5805     case XML_ATTRIBUTE_NODE: {
       
  5806         xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
       
  5807 
       
  5808         return(att->parent);
       
  5809     }
       
  5810     case XML_NAMESPACE_DECL: {
       
  5811         xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
       
  5812 
       
  5813         if ((ns->next != NULL) &&
       
  5814             (ns->next->type != XML_NAMESPACE_DECL))
       
  5815             return((xmlNodePtr) ns->next);
       
  5816         /* Bad, how did that namespace end up here ? */
       
  5817             return(NULL);
       
  5818     }
       
  5819     case XML_DOCUMENT_NODE:
       
  5820     case XML_DOCUMENT_TYPE_NODE:
       
  5821     case XML_DOCUMENT_FRAG_NODE:
       
  5822     case XML_HTML_DOCUMENT_NODE:
       
  5823 #ifdef LIBXML_DOCB_ENABLED
       
  5824     case XML_DOCB_DOCUMENT_NODE:
       
  5825 #endif
       
  5826         return(NULL);
       
  5827     }
       
  5828     return(NULL);
       
  5829 }
       
  5830 
       
  5831 /**
       
  5832  * xmlXPathNextAncestorOrSelf:
       
  5833  * @ctxt:  the XPath Parser context
       
  5834  * @cur:  the current node in the traversal
       
  5835  *
       
  5836  * Traversal function for the "ancestor-or-self" direction
       
  5837  * he ancestor-or-self axis contains the context node and ancestors of
       
  5838  * the context node in reverse document order; thus the context node is
       
  5839  * the first node on the axis, and the context node's parent the second;
       
  5840  * parent here is defined the same as with the parent axis.
       
  5841  *
       
  5842  * Returns the next element following that axis
       
  5843  */
       
  5844 xmlNodePtr
       
  5845 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5846     if (cur == NULL)
       
  5847         return(ctxt->context->node);
       
  5848     return(xmlXPathNextAncestor(ctxt, cur));
       
  5849 }
       
  5850 
       
  5851 /**
       
  5852  * xmlXPathNextFollowingSibling:
       
  5853  * @ctxt:  the XPath Parser context
       
  5854  * @cur:  the current node in the traversal
       
  5855  *
       
  5856  * Traversal function for the "following-sibling" direction
       
  5857  * The following-sibling axis contains the following siblings of the context
       
  5858  * node in document order.
       
  5859  *
       
  5860  * Returns the next element following that axis
       
  5861  */
       
  5862 xmlNodePtr
       
  5863 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5864     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
       
  5865     (ctxt->context->node->type == XML_NAMESPACE_DECL))
       
  5866     return(NULL);
       
  5867     if (cur == (xmlNodePtr) ctxt->context->doc)
       
  5868         return(NULL);
       
  5869     if (cur == NULL)
       
  5870         return(ctxt->context->node->next);
       
  5871     return(cur->next);
       
  5872 }
       
  5873 
       
  5874 /**
       
  5875  * xmlXPathNextPrecedingSibling:
       
  5876  * @ctxt:  the XPath Parser context
       
  5877  * @cur:  the current node in the traversal
       
  5878  *
       
  5879  * Traversal function for the "preceding-sibling" direction
       
  5880  * The preceding-sibling axis contains the preceding siblings of the context
       
  5881  * node in reverse document order; the first preceding sibling is first on the
       
  5882  * axis; the sibling preceding that node is the second on the axis and so on.
       
  5883  *
       
  5884  * Returns the next element following that axis
       
  5885  */
       
  5886 xmlNodePtr
       
  5887 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5888     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
       
  5889     (ctxt->context->node->type == XML_NAMESPACE_DECL))
       
  5890     return(NULL);
       
  5891     if (cur == (xmlNodePtr) ctxt->context->doc)
       
  5892         return(NULL);
       
  5893     if (cur == NULL)
       
  5894         return(ctxt->context->node->prev);
       
  5895     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
       
  5896     cur = cur->prev;
       
  5897     if (cur == NULL)
       
  5898         return(ctxt->context->node->prev);
       
  5899     }
       
  5900     return(cur->prev);
       
  5901 }
       
  5902 
       
  5903 /**
       
  5904  * xmlXPathNextFollowing:
       
  5905  * @ctxt:  the XPath Parser context
       
  5906  * @cur:  the current node in the traversal
       
  5907  *
       
  5908  * Traversal function for the "following" direction
       
  5909  * The following axis contains all nodes in the same document as the context
       
  5910  * node that are after the context node in document order, excluding any
       
  5911  * descendants and excluding attribute nodes and namespace nodes; the nodes
       
  5912  * are ordered in document order
       
  5913  *
       
  5914  * Returns the next element following that axis
       
  5915  */
       
  5916 xmlNodePtr
       
  5917 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  5918     if (cur != NULL && cur->children != NULL)
       
  5919         return cur->children ;
       
  5920     if (cur == NULL) cur = ctxt->context->node;
       
  5921     if (cur == NULL) return(NULL) ; /* ERROR */
       
  5922     if (cur->next != NULL) return(cur->next) ;
       
  5923     do {
       
  5924         cur = cur->parent;
       
  5925         if (cur == NULL) return(NULL);
       
  5926         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
       
  5927         if (cur->next != NULL) return(cur->next);
       
  5928     } while (cur != NULL);
       
  5929     return(cur);
       
  5930 }
       
  5931 
       
  5932 /*
       
  5933  * xmlXPathIsAncestor:
       
  5934  * @ancestor:  the ancestor node
       
  5935  * @node:  the current node
       
  5936  *
       
  5937  * Check that @ancestor is a @node's ancestor
       
  5938  *
       
  5939  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
       
  5940  */
       
  5941 static int
       
  5942 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
       
  5943     if ((ancestor == NULL) || (node == NULL)) return(0);
       
  5944     /* nodes need to be in the same document */
       
  5945     if (ancestor->doc != node->doc) return(0);
       
  5946     /* avoid searching if ancestor or node is the root node */
       
  5947     if (ancestor == (xmlNodePtr) node->doc) return(1);
       
  5948     if (node == (xmlNodePtr) ancestor->doc) return(0);
       
  5949     while (node->parent != NULL) {
       
  5950         if (node->parent == ancestor)
       
  5951             return(1);
       
  5952     node = node->parent;
       
  5953     }
       
  5954     return(0);
       
  5955 }
       
  5956 
       
  5957 /**
       
  5958  * xmlXPathNextPreceding:
       
  5959  * @ctxt:  the XPath Parser context
       
  5960  * @cur:  the current node in the traversal
       
  5961  *
       
  5962  * Traversal function for the "preceding" direction
       
  5963  * the preceding axis contains all nodes in the same document as the context
       
  5964  * node that are before the context node in document order, excluding any
       
  5965  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
       
  5966  * ordered in reverse document order
       
  5967  *
       
  5968  * Returns the next element following that axis
       
  5969  */
       
  5970 xmlNodePtr
       
  5971 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
       
  5972 {
       
  5973     if (cur == NULL)
       
  5974         cur = ctxt->context->node;
       
  5975     if (cur == NULL)
       
  5976     return (NULL);
       
  5977     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
       
  5978     cur = cur->prev;
       
  5979     do {
       
  5980         if (cur->prev != NULL) {
       
  5981             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
       
  5982             return (cur);
       
  5983         }
       
  5984 
       
  5985         cur = cur->parent;
       
  5986         if (cur == NULL)
       
  5987             return (NULL);
       
  5988         if (cur == ctxt->context->doc->children)
       
  5989             return (NULL);
       
  5990     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
       
  5991     return (cur);
       
  5992 }
       
  5993 
       
  5994 /**
       
  5995  * xmlXPathNextPrecedingInternal:
       
  5996  * @ctxt:  the XPath Parser context
       
  5997  * @cur:  the current node in the traversal
       
  5998  *
       
  5999  * Traversal function for the "preceding" direction
       
  6000  * the preceding axis contains all nodes in the same document as the context
       
  6001  * node that are before the context node in document order, excluding any
       
  6002  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
       
  6003  * ordered in reverse document order
       
  6004  * This is a faster implementation but internal only since it requires a
       
  6005  * state kept in the parser context: ctxt->ancestor.
       
  6006  *
       
  6007  * Returns the next element following that axis
       
  6008  */
       
  6009 static xmlNodePtr
       
  6010 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
       
  6011                               xmlNodePtr cur)
       
  6012 {
       
  6013     if (cur == NULL) {
       
  6014         cur = ctxt->context->node;
       
  6015         if (cur == NULL)
       
  6016             return (NULL);
       
  6017     if (cur->type == XML_NAMESPACE_DECL)
       
  6018         cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
       
  6019         ctxt->ancestor = cur->parent;
       
  6020     }
       
  6021     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
       
  6022     cur = cur->prev;
       
  6023     while (cur->prev == NULL) {
       
  6024         cur = cur->parent;
       
  6025         if (cur == NULL)
       
  6026             return (NULL);
       
  6027         if (cur == ctxt->context->doc->children)
       
  6028             return (NULL);
       
  6029         if (cur != ctxt->ancestor)
       
  6030             return (cur);
       
  6031         ctxt->ancestor = cur->parent;
       
  6032     }
       
  6033     cur = cur->prev;
       
  6034     while (cur->last != NULL)
       
  6035         cur = cur->last;
       
  6036     return (cur);
       
  6037 }
       
  6038 
       
  6039 /**
       
  6040  * xmlXPathNextNamespace:
       
  6041  * @ctxt:  the XPath Parser context
       
  6042  * @cur:  the current attribute in the traversal
       
  6043  *
       
  6044  * Traversal function for the "namespace" direction
       
  6045  * the namespace axis contains the namespace nodes of the context node;
       
  6046  * the order of nodes on this axis is implementation-defined; the axis will
       
  6047  * be empty unless the context node is an element
       
  6048  *
       
  6049  * We keep the XML namespace node at the end of the list.
       
  6050  *
       
  6051  * Returns the next element following that axis
       
  6052  */
       
  6053 xmlNodePtr
       
  6054 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  6055     if (ctxt->context->node->type != XML_ELEMENT_NODE)
       
  6056          return(NULL);
       
  6057     if (ctxt->context->tmpNsList == NULL &&
       
  6058         cur != (xmlNodePtr) xmlXPathXMLNamespace)
       
  6059     {
       
  6060         if (ctxt->context->tmpNsList != NULL)
       
  6061             xmlFree(ctxt->context->tmpNsList);
       
  6062         ctxt->context->tmpNsList =
       
  6063             xmlGetNsList(ctxt->context->doc, ctxt->context->node);
       
  6064         ctxt->context->tmpNsNr = 0;
       
  6065         if (ctxt->context->tmpNsList != NULL) {
       
  6066             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
       
  6067                 ctxt->context->tmpNsNr++;
       
  6068             }
       
  6069         }
       
  6070         return((xmlNodePtr) xmlXPathXMLNamespace);
       
  6071     }
       
  6072     if (ctxt->context->tmpNsNr > 0) {
       
  6073         return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
       
  6074     } else {
       
  6075         if (ctxt->context->tmpNsList != NULL)
       
  6076             xmlFree(ctxt->context->tmpNsList);
       
  6077         ctxt->context->tmpNsList = NULL;
       
  6078         return(NULL);
       
  6079     }
       
  6080 }
       
  6081 
       
  6082 /**
       
  6083  * xmlXPathNextAttribute:
       
  6084  * @ctxt:  the XPath Parser context
       
  6085  * @cur:  the current attribute in the traversal
       
  6086  *
       
  6087  * Traversal function for the "attribute" direction
       
  6088  * TODO: support DTD inherited default attributes
       
  6089  *
       
  6090  * Returns the next element following that axis
       
  6091  */
       
  6092 xmlNodePtr
       
  6093 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
       
  6094     if (ctxt->context->node == NULL)
       
  6095     return(NULL);
       
  6096     if (ctxt->context->node->type != XML_ELEMENT_NODE)
       
  6097     return(NULL);
       
  6098     if (cur == NULL) {
       
  6099         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
       
  6100         return(NULL);
       
  6101         return((xmlNodePtr)ctxt->context->node->properties);
       
  6102     }
       
  6103     return((xmlNodePtr)cur->next);
       
  6104 }
       
  6105 
       
  6106 /************************************************************************
       
  6107  *                                  *
       
  6108  *      NodeTest Functions                  *
       
  6109  *                                  *
       
  6110  ************************************************************************/
       
  6111 
       
  6112 #define IS_FUNCTION         200
       
  6113 
       
  6114 
       
  6115 /************************************************************************
       
  6116  *                                  *
       
  6117  *      Implicit tree core function library         *
       
  6118  *                                  *
       
  6119  ************************************************************************/
       
  6120 
       
  6121 /**
       
  6122  * xmlXPathRoot:
       
  6123  * @ctxt:  the XPath Parser context
       
  6124  *
       
  6125  * Initialize the context to the root of the document
       
  6126  */
       
  6127 void
       
  6128 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
       
  6129     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
       
  6130     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
  6131 }
       
  6132 
       
  6133 /************************************************************************
       
  6134  *                                                                      *
       
  6135  *      The explicit core function library                              *
       
  6136  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
       
  6137  *                                                                      *
       
  6138  ************************************************************************/
       
  6139 
       
  6140 
       
  6141 /**
       
  6142  * xmlXPathLastFunction:
       
  6143  * @ctxt:  the XPath Parser context
       
  6144  * @nargs:  the number of arguments
       
  6145  *
       
  6146  * Implement the last() XPath function
       
  6147  *    number last()
       
  6148  * The last function returns the number of nodes in the context node list.
       
  6149  */
       
  6150 void
       
  6151 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6152     CHECK_ARITY(0);
       
  6153     if (ctxt->context->contextSize >= 0) {
       
  6154     valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
       
  6155 #ifdef DEBUG_EXPR
       
  6156     xmlGenericError(xmlGenericErrorContext,
       
  6157         "last() : %d\n", ctxt->context->contextSize);
       
  6158 #endif
       
  6159     } else {
       
  6160     XP_ERROR(XPATH_INVALID_CTXT_SIZE);
       
  6161     }
       
  6162 }
       
  6163 
       
  6164 /**
       
  6165  * xmlXPathPositionFunction:
       
  6166  * @ctxt:  the XPath Parser context
       
  6167  * @nargs:  the number of arguments
       
  6168  *
       
  6169  * Implement the position() XPath function
       
  6170  *    number position()
       
  6171  * The position function returns the position of the context node in the
       
  6172  * context node list. The first position is 1, and so the last position
       
  6173  * will be equal to last().
       
  6174  */
       
  6175 void
       
  6176 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6177     CHECK_ARITY(0);
       
  6178     if (ctxt->context->proximityPosition >= 0) {
       
  6179     valuePush(ctxt,
       
  6180           xmlXPathNewFloat((double) ctxt->context->proximityPosition));
       
  6181 #ifdef DEBUG_EXPR
       
  6182     xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
       
  6183         ctxt->context->proximityPosition);
       
  6184 #endif
       
  6185     } else {
       
  6186     XP_ERROR(XPATH_INVALID_CTXT_POSITION);
       
  6187     }
       
  6188 }
       
  6189 
       
  6190 /**
       
  6191  * xmlXPathCountFunction:
       
  6192  * @ctxt:  the XPath Parser context
       
  6193  * @nargs:  the number of arguments
       
  6194  *
       
  6195  * Implement the count() XPath function
       
  6196  *    number count(node-set)
       
  6197  */
       
  6198 void
       
  6199 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6200     xmlXPathObjectPtr cur;
       
  6201 
       
  6202     CHECK_ARITY(1);
       
  6203     if ((ctxt->value == NULL) ||
       
  6204     ((ctxt->value->type != XPATH_NODESET) &&
       
  6205      (ctxt->value->type != XPATH_XSLT_TREE)))
       
  6206     XP_ERROR(XPATH_INVALID_TYPE);
       
  6207     cur = valuePop(ctxt);
       
  6208 
       
  6209     if ((cur == NULL) || (cur->nodesetval == NULL))
       
  6210     valuePush(ctxt, xmlXPathNewFloat((double) 0));
       
  6211     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
       
  6212     valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
       
  6213     } else {
       
  6214     if ((cur->nodesetval->nodeNr != 1) ||
       
  6215         (cur->nodesetval->nodeTab == NULL)) {
       
  6216         valuePush(ctxt, xmlXPathNewFloat((double) 0));
       
  6217     } else {
       
  6218         xmlNodePtr tmp;
       
  6219         int i = 0;
       
  6220 
       
  6221         tmp = cur->nodesetval->nodeTab[0];
       
  6222         if (tmp != NULL) {
       
  6223         tmp = tmp->children;
       
  6224         while (tmp != NULL) {
       
  6225             tmp = tmp->next;
       
  6226             i++;
       
  6227         }
       
  6228         }
       
  6229         valuePush(ctxt, xmlXPathNewFloat((double) i));
       
  6230     }
       
  6231     }
       
  6232     xmlXPathFreeObject(cur);
       
  6233 }
       
  6234 
       
  6235 /**
       
  6236  * xmlXPathGetElementsByIds:
       
  6237  * @doc:  the document
       
  6238  * @ids:  a whitespace separated list of IDs
       
  6239  *
       
  6240  * Selects elements by their unique ID.
       
  6241  *
       
  6242  * Returns a node-set of selected elements.
       
  6243  */
       
  6244 static xmlNodeSetPtr
       
  6245 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
       
  6246     xmlNodeSetPtr ret;
       
  6247     const xmlChar *cur = ids;
       
  6248     xmlChar *ID;
       
  6249     xmlAttrPtr attr;
       
  6250     xmlNodePtr elem = NULL;
       
  6251 
       
  6252     if (ids == NULL) return(NULL);
       
  6253 
       
  6254     ret = xmlXPathNodeSetCreate(NULL);
       
  6255 
       
  6256     if ( !ret )
       
  6257         return NULL;
       
  6258     while (IS_BLANK_CH(*cur)) cur++;
       
  6259     while (*cur != 0) {
       
  6260     while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
       
  6261         cur++;
       
  6262 
       
  6263         ID = xmlStrndup(ids, cur - ids);
       
  6264     if (ID != NULL) {
       
  6265         /*
       
  6266          * We used to check the fact that the value passed
       
  6267          * was an NCName, but this generated much troubles for
       
  6268          * me and Aleksey Sanin, people blatantly violated that
       
  6269          * constaint, like Visa3D spec.
       
  6270          * if (xmlValidateNCName(ID, 1) == 0)
       
  6271          */
       
  6272         attr = xmlGetID(doc, ID);
       
  6273         if (attr != NULL) {
       
  6274         if (attr->type == XML_ATTRIBUTE_NODE)
       
  6275             elem = attr->parent;
       
  6276         else if (attr->type == XML_ELEMENT_NODE)
       
  6277             elem = (xmlNodePtr) attr;
       
  6278         else
       
  6279             elem = NULL;
       
  6280         if (elem != NULL)
       
  6281             xmlXPathNodeSetAdd(ret, elem);
       
  6282         }
       
  6283         xmlFree(ID);
       
  6284     }
       
  6285 
       
  6286     while (IS_BLANK_CH(*cur)) cur++;
       
  6287     ids = cur;
       
  6288     }
       
  6289     return(ret);
       
  6290 }
       
  6291 
       
  6292 /**
       
  6293  * xmlXPathIdFunction:
       
  6294  * @ctxt:  the XPath Parser context
       
  6295  * @nargs:  the number of arguments
       
  6296  *
       
  6297  * Implement the id() XPath function
       
  6298  *    node-set id(object)
       
  6299  * The id function selects elements by their unique ID
       
  6300  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
       
  6301  * then the result is the union of the result of applying id to the
       
  6302  * string value of each of the nodes in the argument node-set. When the
       
  6303  * argument to id is of any other type, the argument is converted to a
       
  6304  * string as if by a call to the string function; the string is split
       
  6305  * into a whitespace-separated list of tokens (whitespace is any sequence
       
  6306  * of characters matching the production S); the result is a node-set
       
  6307  * containing the elements in the same document as the context node that
       
  6308  * have a unique ID equal to any of the tokens in the list.
       
  6309  */
       
  6310 void
       
  6311 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6312     xmlChar *tokens;
       
  6313     xmlNodeSetPtr ret;
       
  6314     xmlXPathObjectPtr obj;
       
  6315     xmlXPathObjectPtr wrappedNodeSet;
       
  6316 
       
  6317     CHECK_ARITY(1);
       
  6318     obj = valuePop(ctxt);
       
  6319     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
       
  6320     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
       
  6321     xmlNodeSetPtr ns;
       
  6322     int i;
       
  6323 
       
  6324     ret = xmlXPathNodeSetCreate(NULL);
       
  6325 
       
  6326     if (obj->nodesetval != NULL) {
       
  6327         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
       
  6328         tokens =
       
  6329             xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
       
  6330         ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
       
  6331         ret = xmlXPathNodeSetMerge(ret, ns);
       
  6332         xmlXPathFreeNodeSet(ns);
       
  6333         if (tokens != NULL)
       
  6334             xmlFree(tokens);
       
  6335         }
       
  6336     }
       
  6337 
       
  6338     xmlXPathFreeObject(obj);
       
  6339     valuePush(ctxt, xmlXPathWrapNodeSet(ret));
       
  6340     return;
       
  6341     }
       
  6342     obj = xmlXPathConvertString(obj);
       
  6343 
       
  6344     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
       
  6345     wrappedNodeSet = xmlXPathWrapNodeSet(ret);
       
  6346     if ( !wrappedNodeSet )
       
  6347         {
       
  6348         xmlXPathFreeNodeSet( ret );        
       
  6349         }
       
  6350     valuePush(ctxt, wrappedNodeSet);
       
  6351 
       
  6352     xmlXPathFreeObject(obj);
       
  6353     return;
       
  6354 }
       
  6355 
       
  6356 /**
       
  6357  * xmlXPathLocalNameFunction:
       
  6358  * @ctxt:  the XPath Parser context
       
  6359  * @nargs:  the number of arguments
       
  6360  *
       
  6361  * Implement the local-name() XPath function
       
  6362  *    string local-name(node-set?)
       
  6363  * The local-name function returns a string containing the local part
       
  6364  * of the name of the node in the argument node-set that is first in
       
  6365  * document order. If the node-set is empty or the first node has no
       
  6366  * name, an empty string is returned. If the argument is omitted it
       
  6367  * defaults to the context node.
       
  6368  */
       
  6369 void
       
  6370 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6371     xmlXPathObjectPtr cur;
       
  6372 
       
  6373     if (nargs == 0) {
       
  6374     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
  6375     nargs = 1;
       
  6376     }
       
  6377 
       
  6378     CHECK_ARITY(1);
       
  6379     if ((ctxt->value == NULL) ||
       
  6380     ((ctxt->value->type != XPATH_NODESET) &&
       
  6381      (ctxt->value->type != XPATH_XSLT_TREE)))
       
  6382     XP_ERROR(XPATH_INVALID_TYPE);
       
  6383     cur = valuePop(ctxt);
       
  6384 
       
  6385     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
       
  6386     valuePush(ctxt, xmlXPathNewCString(""));
       
  6387     } else {
       
  6388     int i = 0; /* Should be first in document order !!!!! */
       
  6389     switch (cur->nodesetval->nodeTab[i]->type) {
       
  6390     case XML_ELEMENT_NODE:
       
  6391     case XML_ATTRIBUTE_NODE:
       
  6392     case XML_PI_NODE:
       
  6393         if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
       
  6394         valuePush(ctxt, xmlXPathNewCString(""));
       
  6395         else
       
  6396         valuePush(ctxt,
       
  6397               xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
       
  6398         break;
       
  6399     case XML_NAMESPACE_DECL:
       
  6400         valuePush(ctxt, xmlXPathNewString(
       
  6401             ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
       
  6402         break;
       
  6403     default:
       
  6404         valuePush(ctxt, xmlXPathNewCString(""));
       
  6405     }
       
  6406     }
       
  6407     xmlXPathFreeObject(cur);
       
  6408 }
       
  6409 
       
  6410 /**
       
  6411  * xmlXPathNamespaceURIFunction:
       
  6412  * @ctxt:  the XPath Parser context
       
  6413  * @nargs:  the number of arguments
       
  6414  *
       
  6415  * Implement the namespace-uri() XPath function
       
  6416  *    string namespace-uri(node-set?)
       
  6417  * The namespace-uri function returns a string containing the
       
  6418  * namespace URI of the expanded name of the node in the argument
       
  6419  * node-set that is first in document order. If the node-set is empty,
       
  6420  * the first node has no name, or the expanded name has no namespace
       
  6421  * URI, an empty string is returned. If the argument is omitted it
       
  6422  * defaults to the context node.
       
  6423  */
       
  6424 void
       
  6425 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6426     xmlXPathObjectPtr cur;
       
  6427 
       
  6428     if (nargs == 0) {
       
  6429         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
  6430     nargs = 1;
       
  6431     }
       
  6432     CHECK_ARITY(1);
       
  6433     if ((ctxt->value == NULL) ||
       
  6434     ((ctxt->value->type != XPATH_NODESET) &&
       
  6435      (ctxt->value->type != XPATH_XSLT_TREE)))
       
  6436     XP_ERROR(XPATH_INVALID_TYPE);
       
  6437     cur = valuePop(ctxt);
       
  6438 
       
  6439     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
       
  6440     valuePush(ctxt, xmlXPathNewCString(""));
       
  6441     } else {
       
  6442     int i = 0; /* Should be first in document order !!!!! */
       
  6443     switch (cur->nodesetval->nodeTab[i]->type) {
       
  6444     case XML_ELEMENT_NODE:
       
  6445     case XML_ATTRIBUTE_NODE:
       
  6446         if (cur->nodesetval->nodeTab[i]->ns == NULL)
       
  6447         valuePush(ctxt, xmlXPathNewCString(""));
       
  6448         else
       
  6449         valuePush(ctxt, xmlXPathNewString(
       
  6450               cur->nodesetval->nodeTab[i]->ns->href));
       
  6451         break;
       
  6452     default:
       
  6453         valuePush(ctxt, xmlXPathNewCString(""));
       
  6454     }
       
  6455     }
       
  6456     xmlXPathFreeObject(cur);
       
  6457 }
       
  6458 
       
  6459 /**
       
  6460  * xmlXPathNameFunction:
       
  6461  * @ctxt:  the XPath Parser context
       
  6462  * @nargs:  the number of arguments
       
  6463  *
       
  6464  * Implement the name() XPath function
       
  6465  *    string name(node-set?)
       
  6466  * The name function returns a string containing a QName representing
       
  6467  * the name of the node in the argument node-set that is first in document
       
  6468  * order. The QName must represent the name with respect to the namespace
       
  6469  * declarations in effect on the node whose name is being represented.
       
  6470  * Typically, this will be the form in which the name occurred in the XML
       
  6471  * source. This need not be the case if there are namespace declarations
       
  6472  * in effect on the node that associate multiple prefixes with the same
       
  6473  * namespace. However, an implementation may include information about
       
  6474  * the original prefix in its representation of nodes; in this case, an
       
  6475  * implementation can ensure that the returned string is always the same
       
  6476  * as the QName used in the XML source. If the argument it omitted it
       
  6477  * defaults to the context node.
       
  6478  * Libxml keep the original prefix so the "real qualified name" used is
       
  6479  * returned.
       
  6480  */
       
  6481 static void
       
  6482 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
       
  6483 {
       
  6484     xmlXPathObjectPtr cur;
       
  6485 
       
  6486     if (nargs == 0) {
       
  6487         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
  6488         nargs = 1;
       
  6489     }
       
  6490 
       
  6491     CHECK_ARITY(1);
       
  6492     if ((ctxt->value == NULL) ||
       
  6493         ((ctxt->value->type != XPATH_NODESET) &&
       
  6494          (ctxt->value->type != XPATH_XSLT_TREE)))
       
  6495         XP_ERROR(XPATH_INVALID_TYPE);
       
  6496     cur = valuePop(ctxt);
       
  6497 
       
  6498     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
       
  6499         valuePush(ctxt, xmlXPathNewCString(""));
       
  6500     } else {
       
  6501         int i = 0;              /* Should be first in document order !!!!! */
       
  6502 
       
  6503         switch (cur->nodesetval->nodeTab[i]->type) {
       
  6504             case XML_ELEMENT_NODE:
       
  6505             case XML_ATTRIBUTE_NODE:
       
  6506         if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
       
  6507             valuePush(ctxt, xmlXPathNewCString(""));
       
  6508         else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
       
  6509                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
       
  6510                     valuePush(ctxt,
       
  6511                 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
       
  6512 
       
  6513         } else {
       
  6514             xmlChar *fullname;
       
  6515 
       
  6516             fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
       
  6517                      cur->nodesetval->nodeTab[i]->ns->prefix,
       
  6518                      NULL, 0);
       
  6519             if (fullname == cur->nodesetval->nodeTab[i]->name)
       
  6520             fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
       
  6521             if (fullname == NULL) {
       
  6522             XP_ERROR(XPATH_MEMORY_ERROR);
       
  6523             }
       
  6524                     valuePush(ctxt, xmlXPathWrapString(fullname));
       
  6525                 }
       
  6526                 break;
       
  6527             default:
       
  6528                 valuePush(ctxt,
       
  6529                           xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
       
  6530                 xmlXPathLocalNameFunction(ctxt, 1);
       
  6531         }
       
  6532     }
       
  6533     xmlXPathFreeObject(cur);
       
  6534 }
       
  6535 
       
  6536 
       
  6537 /**
       
  6538  * xmlXPathStringFunction:
       
  6539  * @ctxt:  the XPath Parser context
       
  6540  * @nargs:  the number of arguments
       
  6541  *
       
  6542  * Implement the string() XPath function
       
  6543  *    string string(object?)
       
  6544  * The string function converts an object to a string as follows:
       
  6545  *    - A node-set is converted to a string by returning the value of
       
  6546  *      the node in the node-set that is first in document order.
       
  6547  *      If the node-set is empty, an empty string is returned.
       
  6548  *    - A number is converted to a string as follows
       
  6549  *      + NaN is converted to the string NaN
       
  6550  *      + positive zero is converted to the string 0
       
  6551  *      + negative zero is converted to the string 0
       
  6552  *      + positive infinity is converted to the string Infinity
       
  6553  *      + negative infinity is converted to the string -Infinity
       
  6554  *      + if the number is an integer, the number is represented in
       
  6555  *        decimal form as a Number with no decimal point and no leading
       
  6556  *        zeros, preceded by a minus sign (-) if the number is negative
       
  6557  *      + otherwise, the number is represented in decimal form as a
       
  6558  *        Number including a decimal point with at least one digit
       
  6559  *        before the decimal point and at least one digit after the
       
  6560  *        decimal point, preceded by a minus sign (-) if the number
       
  6561  *        is negative; there must be no leading zeros before the decimal
       
  6562  *        point apart possibly from the one required digit immediately
       
  6563  *        before the decimal point; beyond the one required digit
       
  6564  *        after the decimal point there must be as many, but only as
       
  6565  *        many, more digits as are needed to uniquely distinguish the
       
  6566  *        number from all other IEEE 754 numeric values.
       
  6567  *    - The boolean false value is converted to the string false.
       
  6568  *      The boolean true value is converted to the string true.
       
  6569  *
       
  6570  * If the argument is omitted, it defaults to a node-set with the
       
  6571  * context node as its only member.
       
  6572  */
       
  6573 void
       
  6574 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6575     xmlXPathObjectPtr cur;
       
  6576 
       
  6577     if (nargs == 0) {
       
  6578     valuePush(ctxt,
       
  6579           xmlXPathWrapString(
       
  6580             xmlXPathCastNodeToString(ctxt->context->node)));
       
  6581     return;
       
  6582     }
       
  6583 
       
  6584     CHECK_ARITY(1);
       
  6585     cur = valuePop(ctxt);
       
  6586     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
       
  6587     cur = xmlXPathConvertString(cur);
       
  6588     if(OOM_FLAG) return;
       
  6589     valuePush(ctxt, cur);
       
  6590 }
       
  6591 
       
  6592 /**
       
  6593  * xmlXPathStringLengthFunction:
       
  6594  * @ctxt:  the XPath Parser context
       
  6595  * @nargs:  the number of arguments
       
  6596  *
       
  6597  * Implement the string-length() XPath function
       
  6598  *    number string-length(string?)
       
  6599  * The string-length returns the number of characters in the string
       
  6600  * (see [3.6 Strings]). If the argument is omitted, it defaults to
       
  6601  * the context node converted to a string, in other words the value
       
  6602  * of the context node.
       
  6603  */
       
  6604 void
       
  6605 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6606     xmlXPathObjectPtr cur;
       
  6607 
       
  6608     if (nargs == 0) {
       
  6609     if (ctxt->context->node == NULL) {
       
  6610         valuePush(ctxt, xmlXPathNewFloat(0));
       
  6611     } else {
       
  6612         xmlChar *content;
       
  6613 
       
  6614         content = xmlXPathCastNodeToString(ctxt->context->node);
       
  6615         valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
       
  6616         xmlFree(content);
       
  6617     }
       
  6618     return;
       
  6619     }
       
  6620     CHECK_ARITY(1);
       
  6621     CAST_TO_STRING;
       
  6622     CHECK_TYPE(XPATH_STRING);
       
  6623     cur = valuePop(ctxt);
       
  6624     valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
       
  6625     xmlXPathFreeObject(cur);
       
  6626 }
       
  6627 
       
  6628 /**
       
  6629  * xmlXPathConcatFunction:
       
  6630  * @ctxt:  the XPath Parser context
       
  6631  * @nargs:  the number of arguments
       
  6632  *
       
  6633  * Implement the concat() XPath function
       
  6634  *    string concat(string, string, string*)
       
  6635  * The concat function returns the concatenation of its arguments.
       
  6636  */
       
  6637 void
       
  6638 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6639     xmlXPathObjectPtr cur, newobj;
       
  6640     xmlChar *tmp;
       
  6641 
       
  6642     if (nargs < 2) {
       
  6643     CHECK_ARITY(2);
       
  6644     }
       
  6645 
       
  6646     CAST_TO_STRING;
       
  6647     cur = valuePop(ctxt);
       
  6648     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
       
  6649         xmlXPathFreeObject(cur);
       
  6650     return;
       
  6651     }
       
  6652     nargs--;
       
  6653 
       
  6654     while (nargs > 0) {
       
  6655     CAST_TO_STRING;
       
  6656     newobj = valuePop(ctxt);
       
  6657     if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
       
  6658         xmlXPathFreeObject(newobj);
       
  6659         xmlXPathFreeObject(cur);
       
  6660         XP_ERROR(XPATH_INVALID_TYPE);
       
  6661     }
       
  6662     tmp = xmlStrcat(newobj->stringval, cur->stringval);
       
  6663     newobj->stringval = cur->stringval;
       
  6664     cur->stringval = tmp;
       
  6665 
       
  6666     xmlXPathFreeObject(newobj);
       
  6667     nargs--;
       
  6668     }
       
  6669     valuePush(ctxt, cur);
       
  6670 }
       
  6671 
       
  6672 /**
       
  6673  * xmlXPathContainsFunction:
       
  6674  * @ctxt:  the XPath Parser context
       
  6675  * @nargs:  the number of arguments
       
  6676  *
       
  6677  * Implement the contains() XPath function
       
  6678  *    boolean contains(string, string)
       
  6679  * The contains function returns true if the first argument string
       
  6680  * contains the second argument string, and otherwise returns false.
       
  6681  */
       
  6682 void
       
  6683 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6684     xmlXPathObjectPtr hay, needle;
       
  6685 
       
  6686     CHECK_ARITY(2);
       
  6687     CAST_TO_STRING;
       
  6688     CHECK_TYPE(XPATH_STRING);
       
  6689     needle = valuePop(ctxt);
       
  6690     CAST_TO_STRING;
       
  6691     hay = valuePop(ctxt);
       
  6692     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
       
  6693         xmlXPathFreeObject(hay);
       
  6694         xmlXPathFreeObject(needle);
       
  6695     XP_ERROR(XPATH_INVALID_TYPE);
       
  6696     }
       
  6697     if (xmlStrstr(hay->stringval, needle->stringval))
       
  6698         valuePush(ctxt, xmlXPathNewBoolean(1));
       
  6699     else
       
  6700         valuePush(ctxt, xmlXPathNewBoolean(0));
       
  6701     xmlXPathFreeObject(hay);
       
  6702     xmlXPathFreeObject(needle);
       
  6703 }
       
  6704 
       
  6705 /**
       
  6706  * xmlXPathStartsWithFunction:
       
  6707  * @ctxt:  the XPath Parser context
       
  6708  * @nargs:  the number of arguments
       
  6709  *
       
  6710  * Implement the starts-with() XPath function
       
  6711  *    boolean starts-with(string, string)
       
  6712  * The starts-with function returns true if the first argument string
       
  6713  * starts with the second argument string, and otherwise returns false.
       
  6714  */
       
  6715 void
       
  6716 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6717     xmlXPathObjectPtr hay, needle;
       
  6718     int n;
       
  6719 
       
  6720     CHECK_ARITY(2);
       
  6721     CAST_TO_STRING;
       
  6722     CHECK_TYPE(XPATH_STRING);
       
  6723     needle = valuePop(ctxt);
       
  6724     CAST_TO_STRING;
       
  6725     hay = valuePop(ctxt);
       
  6726     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
       
  6727         xmlXPathFreeObject(hay);
       
  6728         xmlXPathFreeObject(needle);
       
  6729     XP_ERROR(XPATH_INVALID_TYPE);
       
  6730     }
       
  6731     n = xmlStrlen(needle->stringval);
       
  6732     if (xmlStrncmp(hay->stringval, needle->stringval, n))
       
  6733         valuePush(ctxt, xmlXPathNewBoolean(0));
       
  6734     else
       
  6735         valuePush(ctxt, xmlXPathNewBoolean(1));
       
  6736     xmlXPathFreeObject(hay);
       
  6737     xmlXPathFreeObject(needle);
       
  6738 }
       
  6739 
       
  6740 /**
       
  6741  * xmlXPathSubstringFunction:
       
  6742  * @ctxt:  the XPath Parser context
       
  6743  * @nargs:  the number of arguments
       
  6744  *
       
  6745  * Implement the substring() XPath function
       
  6746  *    string substring(string, number, number?)
       
  6747  * The substring function returns the substring of the first argument
       
  6748  * starting at the position specified in the second argument with
       
  6749  * length specified in the third argument. For example,
       
  6750  * substring("12345",2,3) returns "234". If the third argument is not
       
  6751  * specified, it returns the substring starting at the position specified
       
  6752  * in the second argument and continuing to the end of the string. For
       
  6753  * example, substring("12345",2) returns "2345".  More precisely, each
       
  6754  * character in the string (see [3.6 Strings]) is considered to have a
       
  6755  * numeric position: the position of the first character is 1, the position
       
  6756  * of the second character is 2 and so on. The returned substring contains
       
  6757  * those characters for which the position of the character is greater than
       
  6758  * or equal to the second argument and, if the third argument is specified,
       
  6759  * less than the sum of the second and third arguments; the comparisons
       
  6760  * and addition used for the above follow the standard IEEE 754 rules. Thus:
       
  6761  *  - substring("12345", 1.5, 2.6) returns "234"
       
  6762  *  - substring("12345", 0, 3) returns "12"
       
  6763  *  - substring("12345", 0 div 0, 3) returns ""
       
  6764  *  - substring("12345", 1, 0 div 0) returns ""
       
  6765  *  - substring("12345", -42, 1 div 0) returns "12345"
       
  6766  *  - substring("12345", -1 div 0, 1 div 0) returns ""
       
  6767  */
       
  6768 void
       
  6769 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6770     xmlXPathObjectPtr str, start, len;
       
  6771     double le=0, in;
       
  6772     // TODO: Name "l" is bad for a variable -- refactor it
       
  6773     int i, l, m;
       
  6774     xmlChar *ret;
       
  6775 
       
  6776     if (nargs < 2) {
       
  6777         // TODO: Use of these CHECK_ARITY macros is bad ...
       
  6778         //       -- make check manually OR define normal macro for that
       
  6779         CHECK_ARITY(2);
       
  6780     }
       
  6781     if (nargs > 3) {
       
  6782         CHECK_ARITY(3);
       
  6783     }
       
  6784     /*
       
  6785      * take care of possible last (position) argument
       
  6786     */
       
  6787     if (nargs == 3) {
       
  6788         CAST_TO_NUMBER;
       
  6789         CHECK_TYPE(XPATH_NUMBER);
       
  6790         len = valuePop(ctxt);
       
  6791         le = len->floatval;
       
  6792             xmlXPathFreeObject(len);
       
  6793     }
       
  6794 
       
  6795     CAST_TO_NUMBER;
       
  6796     CHECK_TYPE(XPATH_NUMBER);
       
  6797     start = valuePop(ctxt);
       
  6798     in = start->floatval;
       
  6799     xmlXPathFreeObject(start);
       
  6800     CAST_TO_STRING;
       
  6801     CHECK_TYPE(XPATH_STRING);
       
  6802     str = valuePop(ctxt);
       
  6803     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
       
  6804 
       
  6805     /*
       
  6806      * If last pos not present, calculate last position
       
  6807     */
       
  6808     if (nargs != 3) {
       
  6809     le = (double)m;
       
  6810     if (in < 1.0)
       
  6811         in = 1.0;
       
  6812     }
       
  6813 
       
  6814     /* Need to check for the special cases where either
       
  6815      * the index is NaN, the length is NaN, or both
       
  6816      * arguments are infinity (relying on Inf + -Inf = NaN)
       
  6817      */
       
  6818     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
       
  6819         /*
       
  6820          * To meet the requirements of the spec, the arguments
       
  6821      * must be converted to integer format before
       
  6822      * initial index calculations are done
       
  6823          *
       
  6824          * First we go to integer form, rounding up
       
  6825      * and checking for special cases
       
  6826          */
       
  6827         i = (int) in;
       
  6828         if (((double)i)+0.5 <= in) i++;
       
  6829 
       
  6830     if (xmlXPathIsInf(le) == 1) {
       
  6831         l = m;
       
  6832         if (i < 1)
       
  6833         i = 1;
       
  6834     }
       
  6835     else if (xmlXPathIsInf(le) == -1 || le < 0.0)
       
  6836         l = 0;
       
  6837     else {
       
  6838         l = (int) le;
       
  6839         if (((double)l)+0.5 <= le) l++;
       
  6840     }
       
  6841 
       
  6842     /* Now we normalize inidices */
       
  6843         i -= 1;
       
  6844         l += i;
       
  6845         if (i < 0)
       
  6846             i = 0;
       
  6847         if (l > m)
       
  6848             l = m;
       
  6849 
       
  6850         /* number of chars to copy */
       
  6851         l -= i;
       
  6852 
       
  6853         ret = xmlUTF8Strsub(str->stringval, i, l);
       
  6854     }
       
  6855     else {
       
  6856         ret = NULL;
       
  6857     }
       
  6858 
       
  6859     if (ret == NULL)
       
  6860         valuePush(ctxt, xmlXPathNewCString(""));
       
  6861     else {
       
  6862         valuePush(ctxt, xmlXPathNewString(ret));
       
  6863         xmlFree(ret);
       
  6864     }
       
  6865 
       
  6866     xmlXPathFreeObject(str);
       
  6867 }
       
  6868 
       
  6869 /**
       
  6870  * xmlXPathSubstringBeforeFunction:
       
  6871  * @ctxt:  the XPath Parser context
       
  6872  * @nargs:  the number of arguments
       
  6873  *
       
  6874  * Implement the substring-before() XPath function
       
  6875  *    string substring-before(string, string)
       
  6876  * The substring-before function returns the substring of the first
       
  6877  * argument string that precedes the first occurrence of the second
       
  6878  * argument string in the first argument string, or the empty string
       
  6879  * if the first argument string does not contain the second argument
       
  6880  * string. For example, substring-before("1999/04/01","/") returns 1999.
       
  6881  */
       
  6882 void
       
  6883 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6884   xmlXPathObjectPtr str;
       
  6885   xmlXPathObjectPtr find;
       
  6886   xmlBufferPtr target;
       
  6887   const xmlChar *point;
       
  6888   int offset;
       
  6889 
       
  6890   CHECK_ARITY(2);
       
  6891   CAST_TO_STRING;
       
  6892   find = valuePop(ctxt);
       
  6893   CAST_TO_STRING;
       
  6894   str = valuePop(ctxt);
       
  6895 
       
  6896   target = xmlBufferCreate();
       
  6897   if (target) {
       
  6898     point = xmlStrstr(str->stringval, find->stringval);
       
  6899     if (point) {
       
  6900       offset = (int)(point - str->stringval);
       
  6901       xmlBufferAdd(target, str->stringval, offset);
       
  6902     }
       
  6903     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
       
  6904     xmlBufferFree(target);
       
  6905   }
       
  6906 
       
  6907   xmlXPathFreeObject(str);
       
  6908   xmlXPathFreeObject(find);
       
  6909 }
       
  6910 
       
  6911 /**
       
  6912  * xmlXPathSubstringAfterFunction:
       
  6913  * @ctxt:  the XPath Parser context
       
  6914  * @nargs:  the number of arguments
       
  6915  *
       
  6916  * Implement the substring-after() XPath function
       
  6917  *    string substring-after(string, string)
       
  6918  * The substring-after function returns the substring of the first
       
  6919  * argument string that follows the first occurrence of the second
       
  6920  * argument string in the first argument string, or the empty stringi
       
  6921  * if the first argument string does not contain the second argument
       
  6922  * string. For example, substring-after("1999/04/01","/") returns 04/01,
       
  6923  * and substring-after("1999/04/01","19") returns 99/04/01.
       
  6924  */
       
  6925 void
       
  6926 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6927   xmlXPathObjectPtr str;
       
  6928   xmlXPathObjectPtr find;
       
  6929   xmlBufferPtr target;
       
  6930   const xmlChar *point;
       
  6931   int offset;
       
  6932 
       
  6933   CHECK_ARITY(2);
       
  6934   CAST_TO_STRING;
       
  6935   find = valuePop(ctxt);
       
  6936   CAST_TO_STRING;
       
  6937   str = valuePop(ctxt);
       
  6938 
       
  6939   target = xmlBufferCreate();
       
  6940   if (target) {
       
  6941     point = xmlStrstr(str->stringval, find->stringval);
       
  6942     if (point) {
       
  6943       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
       
  6944       xmlBufferAdd(target, &str->stringval[offset],
       
  6945            xmlStrlen(str->stringval) - offset);
       
  6946     }
       
  6947     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
       
  6948     xmlBufferFree(target);
       
  6949   }
       
  6950 
       
  6951   xmlXPathFreeObject(str);
       
  6952   xmlXPathFreeObject(find);
       
  6953 }
       
  6954 
       
  6955 /**
       
  6956  * xmlXPathNormalizeFunction:
       
  6957  * @ctxt:  the XPath Parser context
       
  6958  * @nargs:  the number of arguments
       
  6959  *
       
  6960  * Implement the normalize-space() XPath function
       
  6961  *    string normalize-space(string?)
       
  6962  * The normalize-space function returns the argument string with white
       
  6963  * space normalized by stripping leading and trailing whitespace
       
  6964  * and replacing sequences of whitespace characters by a single
       
  6965  * space. Whitespace characters are the same allowed by the S production
       
  6966  * in XML. If the argument is omitted, it defaults to the context
       
  6967  * node converted to a string, in other words the value of the context node.
       
  6968  */
       
  6969 void
       
  6970 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  6971   xmlXPathObjectPtr obj = NULL;
       
  6972   xmlChar *source = NULL;
       
  6973   xmlBufferPtr target;
       
  6974   xmlChar blank;
       
  6975 
       
  6976   if (nargs == 0) {
       
  6977     /* Use current context node */
       
  6978     valuePush(ctxt,
       
  6979           xmlXPathWrapString(
       
  6980           xmlXPathCastNodeToString(ctxt->context->node)));
       
  6981     nargs = 1;
       
  6982   }
       
  6983 
       
  6984   CHECK_ARITY(1);
       
  6985   CAST_TO_STRING;
       
  6986   CHECK_TYPE(XPATH_STRING);
       
  6987   obj = valuePop(ctxt);
       
  6988   source = obj->stringval;
       
  6989 
       
  6990   target = xmlBufferCreate();
       
  6991   if (target && source) {
       
  6992 
       
  6993     /* Skip leading whitespaces */
       
  6994     while (IS_BLANK_CH(*source))
       
  6995       source++;
       
  6996 
       
  6997     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
       
  6998     blank = 0;
       
  6999     while (*source) {
       
  7000       if (IS_BLANK_CH(*source)) {
       
  7001     blank = 0x20;
       
  7002       } else {
       
  7003     if (blank) {
       
  7004       xmlBufferAdd(target, &blank, 1);
       
  7005       blank = 0;
       
  7006     }
       
  7007     xmlBufferAdd(target, source, 1);
       
  7008       }
       
  7009       source++;
       
  7010     }
       
  7011 
       
  7012     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
       
  7013     xmlBufferFree(target);
       
  7014   }
       
  7015   xmlXPathFreeObject(obj);
       
  7016 }
       
  7017 
       
  7018 /**
       
  7019  * xmlXPathTranslateFunction:
       
  7020  * @ctxt:  the XPath Parser context
       
  7021  * @nargs:  the number of arguments
       
  7022  *
       
  7023  * Implement the translate() XPath function
       
  7024  *    string translate(string, string, string)
       
  7025  * The translate function returns the first argument string with
       
  7026  * occurrences of characters in the second argument string replaced
       
  7027  * by the character at the corresponding position in the third argument
       
  7028  * string. For example, translate("bar","abc","ABC") returns the string
       
  7029  * BAr. If there is a character in the second argument string with no
       
  7030  * character at a corresponding position in the third argument string
       
  7031  * (because the second argument string is longer than the third argument
       
  7032  * string), then occurrences of that character in the first argument
       
  7033  * string are removed. For example, translate("--aaa--","abc-","ABC")
       
  7034  * returns "AAA". If a character occurs more than once in second
       
  7035  * argument string, then the first occurrence determines the replacement
       
  7036  * character. If the third argument string is longer than the second
       
  7037  * argument string, then excess characters are ignored.
       
  7038  */
       
  7039 void
       
  7040 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7041     xmlXPathObjectPtr str;
       
  7042     xmlXPathObjectPtr from;
       
  7043     xmlXPathObjectPtr to;
       
  7044     xmlBufferPtr target;
       
  7045     int offset, max;
       
  7046     xmlChar ch;
       
  7047     xmlChar *point;
       
  7048     xmlChar *cptr;
       
  7049 
       
  7050     CHECK_ARITY(3);
       
  7051 
       
  7052     CAST_TO_STRING;
       
  7053     to = valuePop(ctxt);
       
  7054     CAST_TO_STRING;
       
  7055     from = valuePop(ctxt);
       
  7056     CAST_TO_STRING;
       
  7057     str = valuePop(ctxt);
       
  7058 
       
  7059     target = xmlBufferCreate();
       
  7060     if (target) {
       
  7061     max = xmlUTF8Strlen(to->stringval);
       
  7062     for (cptr = str->stringval; (ch=*cptr); ) {
       
  7063         offset = xmlUTF8Strloc(from->stringval, cptr);
       
  7064         if (offset >= 0) {
       
  7065         if (offset < max) {
       
  7066             point = xmlUTF8Strpos(to->stringval, offset);
       
  7067             if (point)
       
  7068             xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
       
  7069         }
       
  7070         } else
       
  7071         xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
       
  7072 
       
  7073         /* Step to next character in input */
       
  7074         cptr++;
       
  7075         if ( ch & 0x80 ) {
       
  7076         /* if not simple ascii, verify proper format */
       
  7077         if ( (ch & 0xc0) != 0xc0 ) {
       
  7078             xmlGenericError(xmlGenericErrorContext,
       
  7079             EMBED_ERRTXT("xmlXPathTranslateFunction: Invalid UTF8 string\n"));
       
  7080             break;
       
  7081         }
       
  7082         /* then skip over remaining bytes for this char */
       
  7083         while ( (ch <<= 1) & 0x80 )
       
  7084             if ( (*cptr++ & 0xc0) != 0x80 ) {
       
  7085             xmlGenericError(xmlGenericErrorContext,
       
  7086                 EMBED_ERRTXT("xmlXPathTranslateFunction: Invalid UTF8 string\n"));
       
  7087             break;
       
  7088             }
       
  7089         if (ch & 0x80) /* must have had error encountered */
       
  7090             break;
       
  7091         }
       
  7092     }
       
  7093     }
       
  7094     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
       
  7095     xmlBufferFree(target);
       
  7096     xmlXPathFreeObject(str);
       
  7097     xmlXPathFreeObject(from);
       
  7098     xmlXPathFreeObject(to);
       
  7099 }
       
  7100 
       
  7101 /**
       
  7102  * xmlXPathBooleanFunction:
       
  7103  * @ctxt:  the XPath Parser context
       
  7104  * @nargs:  the number of arguments
       
  7105  *
       
  7106  * Implement the boolean() XPath function
       
  7107  *    boolean boolean(object)
       
  7108  * The boolean function converts its argument to a boolean as follows:
       
  7109  *    - a number is true if and only if it is neither positive or
       
  7110  *      negative zero nor NaN
       
  7111  *    - a node-set is true if and only if it is non-empty
       
  7112  *    - a string is true if and only if its length is non-zero
       
  7113  */
       
  7114 void
       
  7115 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7116     xmlXPathObjectPtr cur;
       
  7117 
       
  7118     CHECK_ARITY(1);
       
  7119     cur = valuePop(ctxt);
       
  7120     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
       
  7121     cur = xmlXPathConvertBoolean(cur);
       
  7122     valuePush(ctxt, cur);
       
  7123 }
       
  7124 
       
  7125 /**
       
  7126  * xmlXPathNotFunction:
       
  7127  * @ctxt:  the XPath Parser context
       
  7128  * @nargs:  the number of arguments
       
  7129  *
       
  7130  * Implement the not() XPath function
       
  7131  *    boolean not(boolean)
       
  7132  * The not function returns true if its argument is false,
       
  7133  * and false otherwise.
       
  7134  */
       
  7135 void
       
  7136 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7137     CHECK_ARITY(1);
       
  7138     CAST_TO_BOOLEAN;
       
  7139     CHECK_TYPE(XPATH_BOOLEAN);
       
  7140     ctxt->value->boolval = ! ctxt->value->boolval;
       
  7141 }
       
  7142 
       
  7143 /**
       
  7144  * xmlXPathTrueFunction:
       
  7145  * @ctxt:  the XPath Parser context
       
  7146  * @nargs:  the number of arguments
       
  7147  *
       
  7148  * Implement the true() XPath function
       
  7149  *    boolean true()
       
  7150  */
       
  7151 void
       
  7152 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7153     CHECK_ARITY(0);
       
  7154     valuePush(ctxt, xmlXPathNewBoolean(1));
       
  7155 }
       
  7156 
       
  7157 /**
       
  7158  * xmlXPathFalseFunction:
       
  7159  * @ctxt:  the XPath Parser context
       
  7160  * @nargs:  the number of arguments
       
  7161  *
       
  7162  * Implement the false() XPath function
       
  7163  *    boolean false()
       
  7164  */
       
  7165 void
       
  7166 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7167     CHECK_ARITY(0);
       
  7168     valuePush(ctxt, xmlXPathNewBoolean(0));
       
  7169 }
       
  7170 
       
  7171 /**
       
  7172  * xmlXPathLangFunction:
       
  7173  * @ctxt:  the XPath Parser context
       
  7174  * @nargs:  the number of arguments
       
  7175  *
       
  7176  * Implement the lang() XPath function
       
  7177  *    boolean lang(string)
       
  7178  * The lang function returns true or false depending on whether the
       
  7179  * language of the context node as specified by xml:lang attributes
       
  7180  * is the same as or is a sublanguage of the language specified by
       
  7181  * the argument string. The language of the context node is determined
       
  7182  * by the value of the xml:lang attribute on the context node, or, if
       
  7183  * the context node has no xml:lang attribute, by the value of the
       
  7184  * xml:lang attribute on the nearest ancestor of the context node that
       
  7185  * has an xml:lang attribute. If there is no such attribute, then lang
       
  7186  * returns false. If there is such an attribute, then lang returns
       
  7187  * true if the attribute value is equal to the argument ignoring case,
       
  7188  * or if there is some suffix starting with - such that the attribute
       
  7189  * value is equal to the argument ignoring that suffix of the attribute
       
  7190  * value and ignoring case.
       
  7191  */
       
  7192 void
       
  7193 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7194     xmlXPathObjectPtr val;
       
  7195     const xmlChar *theLang;
       
  7196     const xmlChar *lang;
       
  7197     int ret = 0;
       
  7198     int i;
       
  7199 
       
  7200     CHECK_ARITY(1);
       
  7201     CAST_TO_STRING;
       
  7202     CHECK_TYPE(XPATH_STRING);
       
  7203     val = valuePop(ctxt);
       
  7204     lang = val->stringval;
       
  7205     theLang = xmlNodeGetLang(ctxt->context->node);
       
  7206     if ((theLang != NULL) && (lang != NULL)) {
       
  7207         for (i = 0;lang[i] != 0;i++)
       
  7208         if (toupper(lang[i]) != toupper(theLang[i]))
       
  7209             goto not_equal;
       
  7210         ret = 1;
       
  7211     }
       
  7212 not_equal:
       
  7213     if (theLang)
       
  7214         xmlFree((void *)theLang);
       
  7215     xmlXPathFreeObject(val);
       
  7216     valuePush(ctxt, xmlXPathNewBoolean(ret));
       
  7217 }
       
  7218 
       
  7219 /**
       
  7220  * xmlXPathNumberFunction:
       
  7221  * @ctxt:  the XPath Parser context
       
  7222  * @nargs:  the number of arguments
       
  7223  *
       
  7224  * Implement the number() XPath function
       
  7225  *    number number(object?)
       
  7226  */
       
  7227 void
       
  7228 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7229     xmlXPathObjectPtr cur;
       
  7230     double res;
       
  7231 
       
  7232     if (nargs == 0) {
       
  7233     if (ctxt->context->node == NULL) {
       
  7234         valuePush(ctxt, xmlXPathNewFloat(0.0));
       
  7235     } else {
       
  7236         xmlChar* content = xmlNodeGetContent(ctxt->context->node);
       
  7237 
       
  7238         res = xmlXPathStringEvalNumber(content);
       
  7239         valuePush(ctxt, xmlXPathNewFloat(res));
       
  7240         xmlFree(content);
       
  7241     }
       
  7242     return;
       
  7243     }
       
  7244 
       
  7245     CHECK_ARITY(1);
       
  7246     cur = valuePop(ctxt);
       
  7247     cur = xmlXPathConvertNumber(cur);
       
  7248     valuePush(ctxt, cur);
       
  7249 }
       
  7250 
       
  7251 /**
       
  7252  * xmlXPathSumFunction:
       
  7253  * @ctxt:  the XPath Parser context
       
  7254  * @nargs:  the number of arguments
       
  7255  *
       
  7256  * Implement the sum() XPath function
       
  7257  *    number sum(node-set)
       
  7258  * The sum function returns the sum of the values of the nodes in
       
  7259  * the argument node-set.
       
  7260  */
       
  7261 void
       
  7262 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7263     xmlXPathObjectPtr cur;
       
  7264     int i;
       
  7265     double res = 0.0;
       
  7266 
       
  7267     CHECK_ARITY(1);
       
  7268     if ((ctxt->value == NULL) ||
       
  7269     ((ctxt->value->type != XPATH_NODESET) &&
       
  7270      (ctxt->value->type != XPATH_XSLT_TREE)))
       
  7271     XP_ERROR(XPATH_INVALID_TYPE);
       
  7272     cur = valuePop(ctxt);
       
  7273 
       
  7274     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
       
  7275     for (i = 0; i < cur->nodesetval->nodeNr; i++) {
       
  7276         res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
       
  7277     }
       
  7278     }
       
  7279     valuePush(ctxt, xmlXPathNewFloat(res));
       
  7280     xmlXPathFreeObject(cur);
       
  7281 }
       
  7282 
       
  7283 /**
       
  7284  * xmlXPathFloorFunction:
       
  7285  * @ctxt:  the XPath Parser context
       
  7286  * @nargs:  the number of arguments
       
  7287  *
       
  7288  * Implement the floor() XPath function
       
  7289  *    number floor(number)
       
  7290  * The floor function returns the largest (closest to positive infinity)
       
  7291  * number that is not greater than the argument and that is an integer.
       
  7292  */
       
  7293 void
       
  7294 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7295     double f;
       
  7296 
       
  7297     CHECK_ARITY(1);
       
  7298     CAST_TO_NUMBER;
       
  7299     CHECK_TYPE(XPATH_NUMBER);
       
  7300 
       
  7301     f = (double)((int) ctxt->value->floatval);
       
  7302     if (f != ctxt->value->floatval) {
       
  7303     if (ctxt->value->floatval > 0)
       
  7304         ctxt->value->floatval = f;
       
  7305     else
       
  7306         ctxt->value->floatval = f - 1;
       
  7307     }
       
  7308 }
       
  7309 
       
  7310 /**
       
  7311  * xmlXPathCeilingFunction:
       
  7312  * @ctxt:  the XPath Parser context
       
  7313  * @nargs:  the number of arguments
       
  7314  *
       
  7315  * Implement the ceiling() XPath function
       
  7316  *    number ceiling(number)
       
  7317  * The ceiling function returns the smallest (closest to negative infinity)
       
  7318  * number that is not less than the argument and that is an integer.
       
  7319  */
       
  7320 void
       
  7321 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7322     double f;
       
  7323 
       
  7324     CHECK_ARITY(1);
       
  7325     CAST_TO_NUMBER;
       
  7326     CHECK_TYPE(XPATH_NUMBER);
       
  7327 
       
  7328 #if 0
       
  7329     ctxt->value->floatval = ceil(ctxt->value->floatval);
       
  7330 #else
       
  7331     f = (double)((int) ctxt->value->floatval);
       
  7332     if (f != ctxt->value->floatval) {
       
  7333     if (ctxt->value->floatval > 0)
       
  7334         ctxt->value->floatval = f + 1;
       
  7335     else {
       
  7336         if (ctxt->value->floatval < 0 && f == 0)
       
  7337             ctxt->value->floatval = xmlXPathNZERO;
       
  7338         else
       
  7339             ctxt->value->floatval = f;
       
  7340     }
       
  7341 
       
  7342     }
       
  7343 #endif
       
  7344 }
       
  7345 
       
  7346 /**
       
  7347  * xmlXPathRoundFunction:
       
  7348  * @ctxt:  the XPath Parser context
       
  7349  * @nargs:  the number of arguments
       
  7350  *
       
  7351  * Implement the round() XPath function
       
  7352  *    number round(number)
       
  7353  * The round function returns the number that is closest to the
       
  7354  * argument and that is an integer. If there are two such numbers,
       
  7355  * then the one that is even is returned.
       
  7356  */
       
  7357 void
       
  7358 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  7359     double f;
       
  7360 
       
  7361     CHECK_ARITY(1);
       
  7362     CAST_TO_NUMBER;
       
  7363     CHECK_TYPE(XPATH_NUMBER);
       
  7364 
       
  7365     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
       
  7366     (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
       
  7367     (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
       
  7368     (ctxt->value->floatval == 0.0))
       
  7369     return;
       
  7370 
       
  7371     f = (double)((int) ctxt->value->floatval);
       
  7372     if (ctxt->value->floatval < 0) {
       
  7373     if (ctxt->value->floatval < f - 0.5)
       
  7374         ctxt->value->floatval = f - 1;
       
  7375     else
       
  7376         ctxt->value->floatval = f;
       
  7377     if (ctxt->value->floatval == 0)
       
  7378         ctxt->value->floatval = xmlXPathNZERO;
       
  7379     } else {
       
  7380     if (ctxt->value->floatval < f + 0.5)
       
  7381         ctxt->value->floatval = f;
       
  7382     else
       
  7383         ctxt->value->floatval = f + 1;
       
  7384     }
       
  7385 }
       
  7386 
       
  7387 /************************************************************************
       
  7388  *                                  *
       
  7389  *          The Parser                  *
       
  7390  *                                  *
       
  7391  ************************************************************************/
       
  7392 
       
  7393 /*
       
  7394  * a few forward declarations since we use a recursive call based
       
  7395  * implementation.
       
  7396  */
       
  7397 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
       
  7398 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
       
  7399 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
       
  7400 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
       
  7401 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
       
  7402                                       int qualified);
       
  7403 
       
  7404 /**
       
  7405  * xmlXPathCurrentChar:
       
  7406  * @ctxt:  the XPath parser context
       
  7407  * @cur:  pointer to the beginning of the char
       
  7408  * @len:  pointer to the length of the char read
       
  7409  *
       
  7410  * The current char value, if using UTF-8 this may actually span multiple
       
  7411  * bytes in the input buffer.
       
  7412  *
       
  7413  * Returns the current char value and its length
       
  7414  */
       
  7415 
       
  7416 static int
       
  7417 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
       
  7418     unsigned char c;
       
  7419     unsigned int val;
       
  7420     const xmlChar *cur;
       
  7421 
       
  7422     if (ctxt == NULL)
       
  7423     return(0);
       
  7424     cur = ctxt->cur;
       
  7425 
       
  7426     /*
       
  7427      * We are supposed to handle UTF8, check it's valid
       
  7428      * From rfc2044: encoding of the Unicode values on UTF-8:
       
  7429      *
       
  7430      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
       
  7431      * 0000 0000-0000 007F   0xxxxxxx
       
  7432      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
       
  7433      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
       
  7434      *
       
  7435      * Check for the 0x110000 limit too
       
  7436      */
       
  7437     c = *cur;
       
  7438     if (c & 0x80) {
       
  7439     if ((cur[1] & 0xc0) != 0x80)
       
  7440         goto encoding_error;
       
  7441     if ((c & 0xe0) == 0xe0) {
       
  7442 
       
  7443         if ((cur[2] & 0xc0) != 0x80)
       
  7444         goto encoding_error;
       
  7445         if ((c & 0xf0) == 0xf0) {
       
  7446         if (((c & 0xf8) != 0xf0) ||
       
  7447             ((cur[3] & 0xc0) != 0x80))
       
  7448             goto encoding_error;
       
  7449         /* 4-byte code */
       
  7450         *len = 4;
       
  7451         val = (cur[0] & 0x7) << 18;
       
  7452         val |= (cur[1] & 0x3f) << 12;
       
  7453         val |= (cur[2] & 0x3f) << 6;
       
  7454         val |= cur[3] & 0x3f;
       
  7455         } else {
       
  7456           /* 3-byte code */
       
  7457         *len = 3;
       
  7458         val = (cur[0] & 0xf) << 12;
       
  7459         val |= (cur[1] & 0x3f) << 6;
       
  7460         val |= cur[2] & 0x3f;
       
  7461         }
       
  7462     } else {
       
  7463       /* 2-byte code */
       
  7464         *len = 2;
       
  7465         val = (cur[0] & 0x1f) << 6;
       
  7466         val |= cur[1] & 0x3f;
       
  7467     }
       
  7468     if (!IS_CHAR(val)) {
       
  7469         XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
       
  7470     }
       
  7471     return(val);
       
  7472     } else {
       
  7473     /* 1-byte code */
       
  7474     *len = 1;
       
  7475     return((int) *cur);
       
  7476     }
       
  7477 encoding_error:
       
  7478     /*
       
  7479      * If we detect an UTF8 error that probably means that the
       
  7480      * input encoding didn't get properly advertised in the
       
  7481      * declaration header. Report the error and switch the encoding
       
  7482      * to ISO-Latin-1 (if you don't like this policy, just declare the
       
  7483      * encoding !)
       
  7484      */
       
  7485     *len = 0;
       
  7486     XP_ERROR0(XPATH_ENCODING_ERROR);
       
  7487 }
       
  7488 
       
  7489 /**
       
  7490  * xmlXPathParseNCName:
       
  7491  * @ctxt:  the XPath Parser context
       
  7492  *
       
  7493  * parse an XML namespace non qualified name.
       
  7494  *
       
  7495  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
       
  7496  *
       
  7497  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
       
  7498  *                       CombiningChar | Extender
       
  7499  *
       
  7500  * Returns the namespace name or NULL
       
  7501  */
       
  7502 
       
  7503 xmlChar *
       
  7504 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
       
  7505     const xmlChar *in;
       
  7506     xmlChar *ret;
       
  7507     int count = 0;
       
  7508 
       
  7509     /*
       
  7510      * Accelerator for simple ASCII names
       
  7511      */
       
  7512     in = ctxt->cur;
       
  7513     if (((*in >= 0x61) && (*in <= 0x7A)) ||
       
  7514     ((*in >= 0x41) && (*in <= 0x5A)) ||
       
  7515     (*in == '_')) {
       
  7516     in++;
       
  7517     while (((*in >= 0x61) && (*in <= 0x7A)) ||
       
  7518            ((*in >= 0x41) && (*in <= 0x5A)) ||
       
  7519            ((*in >= 0x30) && (*in <= 0x39)) ||
       
  7520            (*in == '_') || (*in == '.') ||
       
  7521            (*in == '-'))
       
  7522         in++;
       
  7523     if ((*in == ' ') || (*in == '>') || (*in == '/') ||
       
  7524             (*in == '[') || (*in == ']') || (*in == ':') ||
       
  7525             (*in == '@') || (*in == '*')) {
       
  7526         count = in - ctxt->cur;
       
  7527         if (count == 0)
       
  7528         return(NULL);
       
  7529         ret = xmlStrndup(ctxt->cur, count);
       
  7530         if(OOM_FLAG) return(NULL);
       
  7531         ctxt->cur = in;
       
  7532         return(ret);
       
  7533     }
       
  7534     }
       
  7535     return(xmlXPathParseNameComplex(ctxt, 0));
       
  7536 }
       
  7537 
       
  7538 
       
  7539 /**
       
  7540  * xmlXPathParseQName:
       
  7541  * @ctxt:  the XPath Parser context
       
  7542  * @prefix:  a xmlChar **
       
  7543  *
       
  7544  * parse an XML qualified name
       
  7545  *
       
  7546  * [NS 5] QName ::= (Prefix ':')? LocalPart
       
  7547  *
       
  7548  * [NS 6] Prefix ::= NCName
       
  7549  *
       
  7550  * [NS 7] LocalPart ::= NCName
       
  7551  *
       
  7552  * Returns the function returns the local part, and prefix is updated
       
  7553  *   to get the Prefix if any.
       
  7554  */
       
  7555 
       
  7556 static xmlChar *
       
  7557 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
       
  7558     xmlChar *ret = NULL;
       
  7559 
       
  7560     *prefix = NULL;
       
  7561     ret = xmlXPathParseNCName(ctxt);
       
  7562     if (CUR == ':') {
       
  7563         *prefix = ret;
       
  7564     NEXT;
       
  7565     ret = xmlXPathParseNCName(ctxt);
       
  7566     }
       
  7567     return(ret);
       
  7568 }
       
  7569 
       
  7570 /**
       
  7571  * xmlXPathParseName:
       
  7572  * @ctxt:  the XPath Parser context
       
  7573  *
       
  7574  * parse an XML name
       
  7575  *
       
  7576  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
       
  7577  *                  CombiningChar | Extender
       
  7578  *
       
  7579  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
       
  7580  *
       
  7581  * Returns the namespace name or NULL
       
  7582  */
       
  7583 
       
  7584 xmlChar *
       
  7585 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
       
  7586     const xmlChar *in;
       
  7587     xmlChar *ret;
       
  7588     int count = 0;
       
  7589 
       
  7590     /*
       
  7591      * Accelerator for simple ASCII names
       
  7592      */
       
  7593     in = ctxt->cur;
       
  7594     if (((*in >= 0x61) && (*in <= 0x7A)) ||
       
  7595     ((*in >= 0x41) && (*in <= 0x5A)) ||
       
  7596     (*in == '_') || (*in == ':')) {
       
  7597     in++;
       
  7598     while (((*in >= 0x61) && (*in <= 0x7A)) ||
       
  7599            ((*in >= 0x41) && (*in <= 0x5A)) ||
       
  7600            ((*in >= 0x30) && (*in <= 0x39)) ||
       
  7601            (*in == '_') || (*in == '-') ||
       
  7602            (*in == ':') || (*in == '.'))
       
  7603         in++;
       
  7604     if ((*in > 0) && (*in < 0x80)) {
       
  7605         count = in - ctxt->cur;
       
  7606         ret = xmlStrndup(ctxt->cur, count);
       
  7607         ctxt->cur = in;
       
  7608         return(ret);
       
  7609     }
       
  7610     }
       
  7611     return(xmlXPathParseNameComplex(ctxt, 1));
       
  7612 }
       
  7613 
       
  7614 /*
       
  7615  * OOM: possible --> check OOM flag
       
  7616  */
       
  7617 static xmlChar*
       
  7618 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified)
       
  7619 {
       
  7620     xmlChar buf[XML_MAX_NAMELEN + 5];
       
  7621     int len = 0, l; // TODO: rename 'l' variable
       
  7622     int c;
       
  7623 
       
  7624     /*
       
  7625      * Handler for more complex cases
       
  7626      */
       
  7627     c = CUR_CHAR(l);
       
  7628     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
       
  7629         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
       
  7630         (c == '*') || /* accelerators */
       
  7631             (!IS_LETTER(c) &&
       
  7632               (c != '_')   &&
       
  7633               qualified    &&
       
  7634               (c != ':')
       
  7635             )
       
  7636         )
       
  7637     {
       
  7638         return(NULL);
       
  7639     }
       
  7640 
       
  7641     while((c != ' ') && (c != '>') && (c != '/')
       
  7642             && /* test bigname.xml */
       
  7643             (
       
  7644              IS_LETTER(c) ||
       
  7645              IS_DIGIT(c)  ||
       
  7646              (c == '.')   ||
       
  7647              (c == '-')   ||
       
  7648              (c == '_')   ||
       
  7649              (qualified && (c == ':')) ||
       
  7650              IS_COMBINING(c) ||
       
  7651              IS_EXTENDER(c)
       
  7652              )
       
  7653           )
       
  7654     {
       
  7655         COPY_BUF(l,buf,len,c);
       
  7656         NEXTL(l);
       
  7657         c = CUR_CHAR(l);
       
  7658         if (len >= XML_MAX_NAMELEN)
       
  7659         {
       
  7660             /*
       
  7661              * Okay someone managed to make a huge name, so he's ready to pay
       
  7662              * for the processing speed.
       
  7663              */
       
  7664             xmlChar* buffer;
       
  7665             int max = len * 2;
       
  7666 
       
  7667             buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar));
       
  7668             if (!buffer) {
       
  7669                 XP_ERROR0(XPATH_MEMORY_ERROR);
       
  7670             }
       
  7671             memcpy(buffer, buf, len);
       
  7672             while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
       
  7673                (c == '.') || (c == '-') ||
       
  7674                (c == '_') || ((qualified) && (c == ':')) ||
       
  7675                (IS_COMBINING(c)) ||
       
  7676                (IS_EXTENDER(c)))
       
  7677             {
       
  7678                 if (len + 10 > max)
       
  7679                 {
       
  7680                     xmlChar* tmp;
       
  7681                     max *= 2;
       
  7682                     // DONE: Fix xmlRealloc
       
  7683                     tmp = (xmlChar*) xmlRealloc(buffer, max * sizeof(xmlChar));
       
  7684                     if (!tmp) {
       
  7685                         xmlFree(buffer);
       
  7686                         XP_ERROR0(XPATH_MEMORY_ERROR);
       
  7687                     }
       
  7688                     buffer = tmp;
       
  7689                 }
       
  7690                 COPY_BUF(l,buffer,len,c);
       
  7691                 NEXTL(l);
       
  7692                 c = CUR_CHAR(l);
       
  7693             }
       
  7694             buffer[len] = 0;
       
  7695             return(buffer);
       
  7696         }
       
  7697     }
       
  7698     if (len == 0)
       
  7699         return(NULL);
       
  7700     return(xmlStrndup(buf, len));
       
  7701 }
       
  7702 
       
  7703 #define MAX_FRAC 20
       
  7704 
       
  7705 /*
       
  7706  * These are used as divisors for the fractional part of a number.
       
  7707  * Since the table includes 1.0 (representing '0' fractional digits),
       
  7708  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
       
  7709  */
       
  7710 static const double my_pow10[MAX_FRAC+1] = {
       
  7711     1.0, 10.0, 100.0, 1000.0, 10000.0,
       
  7712     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
       
  7713     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
       
  7714     100000000000000.0,
       
  7715     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
       
  7716     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
       
  7717 };
       
  7718 
       
  7719 
       
  7720 /**
       
  7721  * xmlXPathStringEvalNumber:
       
  7722  * @str:  A string to scan
       
  7723  *
       
  7724  *  [30a]  Float  ::= Number ('e' Digits?)?
       
  7725  *
       
  7726  *  [30]   Number ::=   Digits ('.' Digits?)?
       
  7727  *                    | '.' Digits
       
  7728  *  [31]   Digits ::=   [0-9]+
       
  7729  *
       
  7730  * Compile a Number in the string
       
  7731  * In complement of the Number expression, this function also handles
       
  7732  * negative values : '-' Number.
       
  7733  *
       
  7734  * Returns the double value.
       
  7735  *
       
  7736  * OOM: never
       
  7737  */
       
  7738 double
       
  7739 xmlXPathStringEvalNumber(const xmlChar *str) {
       
  7740     const xmlChar *cur = str;
       
  7741     double ret;
       
  7742     int ok = 0;
       
  7743     int isneg = 0;
       
  7744     int exponent = 0;
       
  7745     int is_exponent_negative = 0;
       
  7746 #ifdef __GNUC__
       
  7747     unsigned long tmp = 0;
       
  7748     double temp;
       
  7749 #endif
       
  7750     if (cur == NULL) 
       
  7751         return(0);
       
  7752     //
       
  7753     while (IS_BLANK_CH(*cur)) 
       
  7754     {
       
  7755         cur++;
       
  7756     }
       
  7757 
       
  7758     if ((*cur != '.') && 
       
  7759         ((*cur < '0') || (*cur > '9')) && 
       
  7760         (*cur != '-')) 
       
  7761     {
       
  7762         return(xmlXPathNAN);
       
  7763     }
       
  7764     if (*cur == '-') {
       
  7765         isneg = 1;
       
  7766         cur++;
       
  7767     }
       
  7768 
       
  7769 #ifdef __GNUC__
       
  7770     /*
       
  7771      * tmp/temp is a workaround against a gcc compiler bug
       
  7772      * http://veillard.com/gcc.bug
       
  7773      */
       
  7774     ret = 0;
       
  7775     while ((*cur >= '0') && (*cur <= '9')) 
       
  7776     {
       
  7777         ret = ret * 10;
       
  7778         tmp = (*cur - '0');
       
  7779         ok = 1;
       
  7780         cur++;
       
  7781         temp = (double) tmp;
       
  7782         ret = ret + temp;
       
  7783     }
       
  7784 #else
       
  7785     ret = 0;
       
  7786     while ((*cur >= '0') && (*cur <= '9')) 
       
  7787     {
       
  7788         ret = ret * 10 + (*cur - '0');
       
  7789         ok = 1;
       
  7790         cur++;
       
  7791     }
       
  7792 #endif
       
  7793 
       
  7794     if (*cur == '.') 
       
  7795     {
       
  7796         int v, frac = 0;
       
  7797         double fraction = 0;
       
  7798 
       
  7799         cur++;
       
  7800         if (((*cur < '0') || (*cur > '9')) && (!ok)) 
       
  7801         {
       
  7802             return(xmlXPathNAN);
       
  7803         }
       
  7804         while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) 
       
  7805         {
       
  7806             v = (*cur - '0');
       
  7807             fraction = fraction * 10 + v;
       
  7808             frac = frac + 1;
       
  7809             cur++;
       
  7810         }
       
  7811         fraction /= my_pow10[frac];
       
  7812         ret = ret + fraction;
       
  7813         while ((*cur >= '0') && (*cur <= '9'))
       
  7814         {
       
  7815             cur++;
       
  7816         }
       
  7817     }
       
  7818     if ((*cur == 'e') || (*cur == 'E')) 
       
  7819     {
       
  7820         cur++;
       
  7821         if (*cur == '-') 
       
  7822         {
       
  7823             is_exponent_negative = 1;
       
  7824             cur++;
       
  7825         }
       
  7826         while ((*cur >= '0') && (*cur <= '9')) 
       
  7827         {
       
  7828             exponent = exponent * 10 + (*cur - '0');
       
  7829             cur++;
       
  7830         }
       
  7831     }
       
  7832     while (IS_BLANK_CH(*cur)) 
       
  7833     {
       
  7834         cur++;
       
  7835     }
       
  7836     if (*cur != 0) 
       
  7837         return(xmlXPathNAN);
       
  7838     if (isneg) 
       
  7839         ret = -ret;
       
  7840     if (is_exponent_negative) 
       
  7841         exponent = -exponent;
       
  7842     //
       
  7843     ret *= pow(10.0, (double)exponent);
       
  7844     return(ret);
       
  7845 }
       
  7846 
       
  7847 /**
       
  7848  * xmlXPathCompNumber:
       
  7849  * @ctxt:  the XPath Parser context
       
  7850  *
       
  7851  *  [30]   Number ::=   Digits ('.' Digits?)?
       
  7852  *                    | '.' Digits
       
  7853  *  [31]   Digits ::=   [0-9]+
       
  7854  *
       
  7855  * Compile a Number, then push it on the stack
       
  7856  *
       
  7857  */
       
  7858 static void
       
  7859 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
       
  7860 {
       
  7861     double ret = 0.0;
       
  7862     double mult = 1;
       
  7863     int ok = 0;
       
  7864     int exponent = 0;
       
  7865     int is_exponent_negative = 0;
       
  7866 #ifdef __GNUC__
       
  7867     unsigned long tmp = 0;
       
  7868     double temp;
       
  7869 #endif
       
  7870 
       
  7871     CHECK_ERROR;
       
  7872     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
       
  7873         XP_ERROR(XPATH_NUMBER_ERROR);
       
  7874     }
       
  7875 #ifdef __GNUC__
       
  7876     /*
       
  7877      * tmp/temp is a workaround against a gcc compiler bug
       
  7878      * http://veillard.com/gcc.bug
       
  7879      */
       
  7880     ret = 0;
       
  7881     while ((CUR >= '0') && (CUR <= '9')) {
       
  7882     ret = ret * 10;
       
  7883     tmp = (CUR - '0');
       
  7884         ok = 1;
       
  7885         NEXT;
       
  7886     temp = (double) tmp;
       
  7887     ret = ret + temp;
       
  7888     }
       
  7889 #else
       
  7890     ret = 0;
       
  7891     while ((CUR >= '0') && (CUR <= '9')) {
       
  7892     ret = ret * 10 + (CUR - '0');
       
  7893     ok = 1;
       
  7894     NEXT;
       
  7895     }
       
  7896 #endif
       
  7897     if (CUR == '.') {
       
  7898         NEXT;
       
  7899         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
       
  7900             XP_ERROR(XPATH_NUMBER_ERROR);
       
  7901         }
       
  7902         while ((CUR >= '0') && (CUR <= '9')) {
       
  7903             mult /= 10;
       
  7904             ret = ret + (CUR - '0') * mult;
       
  7905             NEXT;
       
  7906         }
       
  7907     }
       
  7908     if ((CUR == 'e') || (CUR == 'E')) {
       
  7909         NEXT;
       
  7910         if (CUR == '-') {
       
  7911             is_exponent_negative = 1;
       
  7912             NEXT;
       
  7913         }
       
  7914         while ((CUR >= '0') && (CUR <= '9')) {
       
  7915             exponent = exponent * 10 + (CUR - '0');
       
  7916             NEXT;
       
  7917         }
       
  7918         if (is_exponent_negative)
       
  7919             exponent = -exponent;
       
  7920         ret *= pow(10.0, (double) exponent);
       
  7921     }
       
  7922     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
       
  7923                    xmlXPathNewFloat(ret), NULL);
       
  7924 }
       
  7925 
       
  7926 /**
       
  7927  * xmlXPathParseLiteral:
       
  7928  * @ctxt:  the XPath Parser context
       
  7929  *
       
  7930  * Parse a Literal
       
  7931  *
       
  7932  *  [29]   Literal ::=   '"' [^"]* '"'
       
  7933  *                    | "'" [^']* "'"
       
  7934  *
       
  7935  * Returns the value found or NULL in case of error
       
  7936  */
       
  7937 static xmlChar *
       
  7938 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
       
  7939     const xmlChar *q;
       
  7940     xmlChar *ret = NULL;
       
  7941 
       
  7942     if (CUR == '"') {
       
  7943         NEXT;
       
  7944     q = CUR_PTR;
       
  7945     while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
       
  7946         NEXT;
       
  7947     if (!IS_CHAR_CH(CUR)) {
       
  7948         XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
       
  7949     } else {
       
  7950         ret = xmlStrndup(q, CUR_PTR - q);
       
  7951         NEXT;
       
  7952         }
       
  7953     } else if (CUR == '\'') {
       
  7954         NEXT;
       
  7955     q = CUR_PTR;
       
  7956     while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
       
  7957         NEXT;
       
  7958     if (!IS_CHAR_CH(CUR)) {
       
  7959         XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
       
  7960     } else {
       
  7961         ret = xmlStrndup(q, CUR_PTR - q);
       
  7962         NEXT;
       
  7963         }
       
  7964     } else {
       
  7965     XP_ERROR0(XPATH_START_LITERAL_ERROR);
       
  7966     }
       
  7967     return(ret);
       
  7968 }
       
  7969 
       
  7970 /**
       
  7971  * xmlXPathCompLiteral:
       
  7972  * @ctxt:  the XPath Parser context
       
  7973  *
       
  7974  * Parse a Literal and push it on the stack.
       
  7975  *
       
  7976  *  [29]   Literal ::=   '"' [^"]* '"'
       
  7977  *                    | "'" [^']* "'"
       
  7978  *
       
  7979  * TODO: xmlXPathCompLiteral memory allocation could be improved.
       
  7980  */
       
  7981 static void
       
  7982 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
       
  7983     const xmlChar *q;
       
  7984     xmlChar *ret = NULL;
       
  7985 
       
  7986     if (CUR == '"') {
       
  7987         NEXT;
       
  7988     q = CUR_PTR;
       
  7989     while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
       
  7990         NEXT;
       
  7991     if (!IS_CHAR_CH(CUR)) {
       
  7992         XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
       
  7993     } else {
       
  7994         ret = xmlStrndup(q, CUR_PTR - q);
       
  7995         NEXT;
       
  7996         }
       
  7997     } else if (CUR == '\'') {
       
  7998         NEXT;
       
  7999     q = CUR_PTR;
       
  8000     while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
       
  8001         NEXT;
       
  8002     if (!IS_CHAR_CH(CUR)) {
       
  8003         XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
       
  8004     } else {
       
  8005         ret = xmlStrndup(q, CUR_PTR - q);
       
  8006         NEXT;
       
  8007         }
       
  8008     } else {
       
  8009     XP_ERROR(XPATH_START_LITERAL_ERROR);
       
  8010     }
       
  8011     if (ret == NULL) return;
       
  8012     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
       
  8013                xmlXPathNewString(ret), NULL);
       
  8014     xmlFree(ret);
       
  8015 }
       
  8016 
       
  8017 /**
       
  8018  * xmlXPathCompVariableReference:
       
  8019  * @ctxt:  the XPath Parser context
       
  8020  *
       
  8021  * Parse a VariableReference, evaluate it and push it on the stack.
       
  8022  *
       
  8023  * The variable bindings consist of a mapping from variable names
       
  8024  * to variable values. The value of a variable is an object, which can be
       
  8025  * of any of the types that are possible for the value of an expression,
       
  8026  * and may also be of additional types not specified here.
       
  8027  *
       
  8028  * Early evaluation is possible since:
       
  8029  * The variable bindings [...] used to evaluate a subexpression are
       
  8030  * always the same as those used to evaluate the containing expression.
       
  8031  *
       
  8032  *  [36]   VariableReference ::=   '$' QName
       
  8033  */
       
  8034 static void
       
  8035 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
       
  8036     xmlChar *name;
       
  8037     xmlChar *prefix;
       
  8038 
       
  8039     SKIP_BLANKS;
       
  8040     if (CUR != '$') {
       
  8041     XP_ERROR(XPATH_VARIABLE_REF_ERROR);
       
  8042     }
       
  8043     NEXT;
       
  8044     name = xmlXPathParseQName(ctxt, &prefix);
       
  8045     if (name == NULL) {
       
  8046     XP_ERROR(XPATH_VARIABLE_REF_ERROR);
       
  8047     }
       
  8048     ctxt->comp->last = -1;
       
  8049     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
       
  8050                name, prefix);
       
  8051     SKIP_BLANKS;
       
  8052 }
       
  8053 
       
  8054 /**
       
  8055  * xmlXPathIsNodeType:
       
  8056  * @name:  a name string
       
  8057  *
       
  8058  * Is the name given a NodeType one.
       
  8059  *
       
  8060  *  [38]   NodeType ::=   'comment'
       
  8061  *                    | 'text'
       
  8062  *                    | 'processing-instruction'
       
  8063  *                    | 'node'
       
  8064  *
       
  8065  * Returns 1 if true 0 otherwise
       
  8066  */
       
  8067 int
       
  8068 xmlXPathIsNodeType(const xmlChar *name) {
       
  8069     if (name == NULL)
       
  8070     return(0);
       
  8071 
       
  8072     if (xmlStrEqual(name, BAD_CAST "node"))
       
  8073     return(1);
       
  8074     if (xmlStrEqual(name, BAD_CAST "text"))
       
  8075     return(1);
       
  8076     if (xmlStrEqual(name, BAD_CAST "comment"))
       
  8077     return(1);
       
  8078     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
       
  8079     return(1);
       
  8080     return(0);
       
  8081 }
       
  8082 
       
  8083 /**
       
  8084  * xmlXPathCompFunctionCall:
       
  8085  * @ctxt:  the XPath Parser context
       
  8086  *
       
  8087  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
       
  8088  *  [17]   Argument ::=   Expr
       
  8089  *
       
  8090  * Compile a function call, the evaluation of all arguments are
       
  8091  * pushed on the stack
       
  8092  */
       
  8093 static void
       
  8094 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
       
  8095     xmlChar *name;
       
  8096     xmlChar *prefix;
       
  8097     int nbargs = 0;
       
  8098 
       
  8099     name = xmlXPathParseQName(ctxt, &prefix);
       
  8100     if (name == NULL) {
       
  8101     XP_ERROR(XPATH_EXPR_ERROR);
       
  8102     }
       
  8103     SKIP_BLANKS;
       
  8104 #ifdef DEBUG_EXPR
       
  8105     if (prefix == NULL)
       
  8106     xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
       
  8107             name);
       
  8108     else
       
  8109     xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
       
  8110             prefix, name);
       
  8111 #endif
       
  8112 
       
  8113     if (CUR != '(') {
       
  8114     XP_ERROR(XPATH_EXPR_ERROR);
       
  8115     }
       
  8116     NEXT;
       
  8117     SKIP_BLANKS;
       
  8118 
       
  8119     ctxt->comp->last = -1;
       
  8120     if (CUR != ')') {
       
  8121     while (CUR != 0) {
       
  8122         int op1 = ctxt->comp->last;
       
  8123         ctxt->comp->last = -1;
       
  8124         xmlXPathCompileExpr(ctxt);
       
  8125         if(OOM_FLAG)
       
  8126         	{
       
  8127         	xmlFree(name);
       
  8128         	return;
       
  8129         	}
       
  8130         CHECK_ERROR;
       
  8131         PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
       
  8132         nbargs++;
       
  8133         if (CUR == ')') break;
       
  8134         if (CUR != ',') {
       
  8135         XP_ERROR(XPATH_EXPR_ERROR);
       
  8136         }
       
  8137         NEXT;
       
  8138         SKIP_BLANKS;
       
  8139     }
       
  8140     }
       
  8141     if ( PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1)
       
  8142         goto Err;
       
  8143     NEXT;
       
  8144     SKIP_BLANKS;
       
  8145     return;
       
  8146 Err:
       
  8147     if(name)
       
  8148         xmlFree(name);
       
  8149     if(prefix)
       
  8150          xmlFree(prefix);
       
  8151 }
       
  8152 
       
  8153 /**
       
  8154  * xmlXPathCompPrimaryExpr:
       
  8155  * @ctxt:  the XPath Parser context
       
  8156  *
       
  8157  *  [15]   PrimaryExpr ::=   VariableReference
       
  8158  *                | '(' Expr ')'
       
  8159  *                | Literal
       
  8160  *                | Number
       
  8161  *                | FunctionCall
       
  8162  *
       
  8163  * Compile a primary expression.
       
  8164  */
       
  8165 static void
       
  8166 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
       
  8167     SKIP_BLANKS;
       
  8168     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
       
  8169     else if (CUR == '(') {
       
  8170     NEXT;
       
  8171     SKIP_BLANKS;
       
  8172     xmlXPathCompileExpr(ctxt);
       
  8173     CHECK_ERROR;
       
  8174     if (CUR != ')') {
       
  8175         XP_ERROR(XPATH_EXPR_ERROR);
       
  8176     }
       
  8177     NEXT;
       
  8178     SKIP_BLANKS;
       
  8179     } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
       
  8180     xmlXPathCompNumber(ctxt);
       
  8181     } else if ((CUR == '\'') || (CUR == '"')) {
       
  8182     xmlXPathCompLiteral(ctxt);
       
  8183     } else {
       
  8184     xmlXPathCompFunctionCall(ctxt);
       
  8185     }
       
  8186     SKIP_BLANKS;
       
  8187 }
       
  8188 
       
  8189 /**
       
  8190  * xmlXPathCompFilterExpr:
       
  8191  * @ctxt:  the XPath Parser context
       
  8192  *
       
  8193  *  [20]   FilterExpr ::=   PrimaryExpr
       
  8194  *               | FilterExpr Predicate
       
  8195  *
       
  8196  * Compile a filter expression.
       
  8197  * Square brackets are used to filter expressions in the same way that
       
  8198  * they are used in location paths. It is an error if the expression to
       
  8199  * be filtered does not evaluate to a node-set. The context node list
       
  8200  * used for evaluating the expression in square brackets is the node-set
       
  8201  * to be filtered listed in document order.
       
  8202  */
       
  8203 
       
  8204 static void
       
  8205 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
       
  8206     xmlXPathCompPrimaryExpr(ctxt);
       
  8207     CHECK_ERROR;
       
  8208     SKIP_BLANKS;
       
  8209 
       
  8210     while (CUR == '[') {
       
  8211     xmlXPathCompPredicate(ctxt, 1);
       
  8212     SKIP_BLANKS;
       
  8213     }
       
  8214 
       
  8215 
       
  8216 }
       
  8217 
       
  8218 /**
       
  8219  * xmlXPathScanName:
       
  8220  * @ctxt:  the XPath Parser context
       
  8221  *
       
  8222  * Trickery: parse an XML name but without consuming the input flow
       
  8223  * Needed to avoid insanity in the parser state.
       
  8224  *
       
  8225  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
       
  8226  *                  CombiningChar | Extender
       
  8227  *
       
  8228  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
       
  8229  *
       
  8230  * [6] Names ::= Name (S Name)*
       
  8231  *
       
  8232  * Returns the Name parsed or NULL
       
  8233  *
       
  8234  * OOM: possible --> sets OOM when NULL is return
       
  8235  */
       
  8236 
       
  8237 static xmlChar*
       
  8238 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
       
  8239     xmlChar buf[XML_MAX_NAMELEN];
       
  8240     int len = 0;
       
  8241 
       
  8242     SKIP_BLANKS;
       
  8243     if (!IS_LETTER_CH(CUR) &&
       
  8244         (CUR != '_') &&
       
  8245         (CUR != ':'))
       
  8246     {
       
  8247         return(NULL);
       
  8248     }
       
  8249     // TODO: OPTIMIZE: Repeated while conditions: NXT(len)
       
  8250     while ((IS_LETTER_CH(NXT(len))) ||
       
  8251            (IS_DIGIT_CH(NXT(len)))  ||
       
  8252            (NXT(len) == '.') ||
       
  8253            (NXT(len) == '-') ||
       
  8254            (NXT(len) == '_') ||
       
  8255            (NXT(len) == ':') ||
       
  8256            (IS_COMBINING_CH(NXT(len))) ||
       
  8257            (IS_EXTENDER_CH(NXT(len))))
       
  8258     {
       
  8259         buf[len] = NXT(len);
       
  8260         len++;
       
  8261         if (len >= XML_MAX_NAMELEN) // TODO: Make a configurable parameter
       
  8262         {
       
  8263             xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("xmlScanName: reached XML_MAX_NAMELEN limit\n"));
       
  8264             while (
       
  8265                 (IS_LETTER_CH(NXT(len))) ||
       
  8266                 (IS_DIGIT_CH(NXT(len))) ||
       
  8267                 (NXT(len) == '.') ||
       
  8268                 (NXT(len) == '-') ||
       
  8269                 (NXT(len) == '_') ||
       
  8270                 (NXT(len) == ':') ||
       
  8271                 (IS_COMBINING_CH(NXT(len))) ||
       
  8272                 (IS_EXTENDER_CH(NXT(len))))
       
  8273             {
       
  8274              len++;
       
  8275             }
       
  8276             break; // while
       
  8277         }
       
  8278     }
       
  8279     return(xmlStrndup(buf, len)); // may cause OOM
       
  8280 }
       
  8281 
       
  8282 /**
       
  8283  * xmlXPathCompPathExpr:
       
  8284  * @ctxt:  the XPath Parser context
       
  8285  *
       
  8286  *  [19]   PathExpr ::=   LocationPath
       
  8287  *               | FilterExpr
       
  8288  *               | FilterExpr '/' RelativeLocationPath
       
  8289  *               | FilterExpr '//' RelativeLocationPath
       
  8290  *
       
  8291  * Compile a path expression.
       
  8292  * The / operator and // operators combine an arbitrary expression
       
  8293  * and a relative location path. It is an error if the expression
       
  8294  * does not evaluate to a node-set.
       
  8295  * The / operator does composition in the same way as when / is
       
  8296  * used in a location path. As in location paths, // is short for
       
  8297  * /descendant-or-self::node()/.
       
  8298  *
       
  8299  * OOM:
       
  8300  */
       
  8301 
       
  8302 static void
       
  8303 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
       
  8304     int lc = 1;           /* Should we branch to LocationPath ?         */
       
  8305     xmlChar *name = NULL; /* we may have to preparse a name to find out */
       
  8306 
       
  8307     SKIP_BLANKS;
       
  8308     if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
       
  8309         (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1))))
       
  8310     {
       
  8311     lc = 0;
       
  8312     } else if (CUR == '*') {
       
  8313         /* relative or absolute location path */
       
  8314         lc = 1;
       
  8315     } else if (CUR == '/') {
       
  8316         /* relative or absolute location path */
       
  8317         lc = 1;
       
  8318     } else if (CUR == '@') {
       
  8319         /* relative abbreviated attribute location path */
       
  8320         lc = 1;
       
  8321     } else if (CUR == '.') {
       
  8322         /* relative abbreviated attribute location path */
       
  8323         lc = 1;
       
  8324     } else {
       
  8325         /*
       
  8326          * Problem is finding if we have a name here whether it's:
       
  8327          *   - a nodetype
       
  8328          *   - a function call in which case it's followed by '('
       
  8329          *   - an axis in which case it's followed by ':'
       
  8330          *   - a element name
       
  8331          * We do an a priori analysis here rather than having to
       
  8332          * maintain parsed token content through the recursive function
       
  8333          * calls. This looks uglier but makes the code easier to
       
  8334          * read/write/debug.
       
  8335          */
       
  8336         SKIP_BLANKS;
       
  8337         name = xmlXPathScanName(ctxt);
       
  8338         if(OOM_FLAG) return;
       
  8339         if (name && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
       
  8340 #ifdef DEBUG_STEP
       
  8341             xmlGenericError(xmlGenericErrorContext, "PathExpr: Axis\n");
       
  8342 #endif
       
  8343             lc = 1;
       
  8344             xmlFree(name);
       
  8345         } else if (name != NULL) {
       
  8346             int len =xmlStrlen(name);
       
  8347 
       
  8348 
       
  8349             while (NXT(len) != 0) {
       
  8350             if (NXT(len) == '/') {
       
  8351             /* element name */
       
  8352 #ifdef DEBUG_STEP
       
  8353                 xmlGenericError(xmlGenericErrorContext, "PathExpr: AbbrRelLocation\n");
       
  8354 #endif
       
  8355                 lc = 1;
       
  8356                 break;
       
  8357             } else if (IS_BLANK_CH(NXT(len))) {
       
  8358                 /* ignore blanks */
       
  8359                 ;
       
  8360             } else if (NXT(len) == ':') {
       
  8361 #ifdef DEBUG_STEP
       
  8362                 xmlGenericError(xmlGenericErrorContext,  "PathExpr: AbbrRelLocation\n");
       
  8363 #endif
       
  8364                 lc = 1;
       
  8365                 break;
       
  8366             } else if ((NXT(len) == '(')) {
       
  8367                 /* Note Type or Function */
       
  8368                 if (xmlXPathIsNodeType(name)) {
       
  8369 #ifdef DEBUG_STEP
       
  8370                     xmlGenericError(xmlGenericErrorContext, "PathExpr: Type search\n");
       
  8371 #endif
       
  8372                     lc = 1;
       
  8373                 } else {
       
  8374 #ifdef DEBUG_STEP
       
  8375                     xmlGenericError(xmlGenericErrorContext, "PathExpr: function call\n");
       
  8376 #endif
       
  8377                     lc = 0;
       
  8378                 }
       
  8379                 break;
       
  8380             } else if ((NXT(len) == '[')) {
       
  8381                 /* element name */
       
  8382 #ifdef DEBUG_STEP
       
  8383                 xmlGenericError(xmlGenericErrorContext, "PathExpr: AbbrRelLocation\n");
       
  8384 #endif
       
  8385                 lc = 1;
       
  8386                 break;
       
  8387             } else if ((NXT(len) == '<') ||
       
  8388                        (NXT(len) == '>') ||
       
  8389                        (NXT(len) == '='))
       
  8390            {
       
  8391                lc = 1;
       
  8392                 break;
       
  8393             } else {
       
  8394                 lc = 1;
       
  8395                 break;
       
  8396             }
       
  8397             len++;
       
  8398             }
       
  8399             if (NXT(len) == 0) {
       
  8400 #ifdef DEBUG_STEP
       
  8401                 xmlGenericError(xmlGenericErrorContext, "PathExpr: AbbrRelLocation\n");
       
  8402 #endif
       
  8403                 /* element name */
       
  8404                 lc = 1;
       
  8405             }
       
  8406             xmlFree(name);
       
  8407         } else {
       
  8408             /* make sure all cases are covered explicitly */
       
  8409             XP_ERROR(XPATH_EXPR_ERROR);
       
  8410         }
       
  8411     }
       
  8412 
       
  8413     if (lc) {
       
  8414         if (CUR == '/') {
       
  8415             PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
       
  8416         } else {
       
  8417             PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
       
  8418         }
       
  8419         xmlXPathCompLocationPath(ctxt);
       
  8420         if(OOM_FLAG) return;
       
  8421     } else {
       
  8422         xmlXPathCompFilterExpr(ctxt);
       
  8423         CHECK_ERROR;
       
  8424         if ((CUR == '/') && (NXT(1) == '/'))
       
  8425         {
       
  8426             SKIP(2);
       
  8427             SKIP_BLANKS;
       
  8428 
       
  8429             PUSH_LONG_EXPR(
       
  8430                 XPATH_OP_COLLECT,
       
  8431                 AXIS_DESCENDANT_OR_SELF,
       
  8432                 NODE_TEST_TYPE,
       
  8433                 NODE_TYPE_NODE,
       
  8434                 NULL,
       
  8435                 NULL);
       
  8436 
       
  8437             PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
       
  8438 
       
  8439             xmlXPathCompRelativeLocationPath(ctxt);
       
  8440         } else if (CUR == '/') {
       
  8441             xmlXPathCompRelativeLocationPath(ctxt);
       
  8442         }
       
  8443     }
       
  8444     SKIP_BLANKS;
       
  8445 }
       
  8446 
       
  8447 /**
       
  8448  * xmlXPathCompUnionExpr:
       
  8449  * @ctxt:  the XPath Parser context
       
  8450  *
       
  8451  *  [18]   UnionExpr ::=   PathExpr
       
  8452  *               | UnionExpr '|' PathExpr
       
  8453  *
       
  8454  * Compile an union expression.
       
  8455  *
       
  8456  * OOM:
       
  8457  */
       
  8458 
       
  8459 static void
       
  8460 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
       
  8461     xmlXPathCompPathExpr(ctxt);
       
  8462     if(OOM_FLAG) return;
       
  8463     CHECK_ERROR;
       
  8464     SKIP_BLANKS;
       
  8465     while (CUR == '|') {
       
  8466     int op1 = ctxt->comp->last;
       
  8467     PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
       
  8468 
       
  8469     NEXT;
       
  8470     SKIP_BLANKS;
       
  8471     xmlXPathCompPathExpr(ctxt);
       
  8472 
       
  8473     PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
       
  8474 
       
  8475     SKIP_BLANKS;
       
  8476     }
       
  8477 }
       
  8478 
       
  8479 /**
       
  8480  * xmlXPathCompUnaryExpr:
       
  8481  * @ctxt:  the XPath Parser context
       
  8482  *
       
  8483  *  [27]   UnaryExpr ::=   UnionExpr
       
  8484  *                   | '-' UnaryExpr
       
  8485  *
       
  8486  * Compile an unary expression.
       
  8487  *
       
  8488  * OOM:
       
  8489  */
       
  8490 
       
  8491 static void
       
  8492 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
       
  8493     int minus = 0;
       
  8494     int found = 0;
       
  8495 
       
  8496     SKIP_BLANKS;
       
  8497     while (CUR == '-') {
       
  8498         minus = 1 - minus;
       
  8499     found = 1;
       
  8500     NEXT;
       
  8501     SKIP_BLANKS;
       
  8502     }
       
  8503 
       
  8504     xmlXPathCompUnionExpr(ctxt);
       
  8505     if(OOM_FLAG) return;
       
  8506     CHECK_ERROR;
       
  8507     if (found) {
       
  8508     if (minus)
       
  8509         PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
       
  8510     else
       
  8511         PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
       
  8512     }
       
  8513 }
       
  8514 
       
  8515 /**
       
  8516  * xmlXPathCompMultiplicativeExpr:
       
  8517  * @ctxt:  the XPath Parser context
       
  8518  *
       
  8519  *  [26]   MultiplicativeExpr ::=   UnaryExpr
       
  8520  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
       
  8521  *                   | MultiplicativeExpr 'div' UnaryExpr
       
  8522  *                   | MultiplicativeExpr 'mod' UnaryExpr
       
  8523  *  [34]   MultiplyOperator ::=   '*'
       
  8524  *
       
  8525  * Compile an Additive expression.
       
  8526  *
       
  8527  * OOM:
       
  8528  */
       
  8529 
       
  8530 static void
       
  8531 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
       
  8532     xmlXPathCompUnaryExpr(ctxt);
       
  8533     if(OOM_FLAG) return;
       
  8534     CHECK_ERROR;
       
  8535     SKIP_BLANKS;
       
  8536     while ((CUR == '*') ||
       
  8537            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
       
  8538            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
       
  8539     int op = -1;
       
  8540     int op1 = ctxt->comp->last;
       
  8541 
       
  8542         if (CUR == '*') {
       
  8543         op = 0;
       
  8544         NEXT;
       
  8545     } else if (CUR == 'd') {
       
  8546         op = 1;
       
  8547         SKIP(3);
       
  8548     } else if (CUR == 'm') {
       
  8549         op = 2;
       
  8550         SKIP(3);
       
  8551     }
       
  8552     SKIP_BLANKS;
       
  8553         xmlXPathCompUnaryExpr(ctxt);
       
  8554     CHECK_ERROR;
       
  8555     PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
       
  8556     SKIP_BLANKS;
       
  8557     }
       
  8558 }
       
  8559 
       
  8560 /**
       
  8561  * xmlXPathCompAdditiveExpr:
       
  8562  * @ctxt:  the XPath Parser context
       
  8563  *
       
  8564  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
       
  8565  *                   | AdditiveExpr '+' MultiplicativeExpr
       
  8566  *                   | AdditiveExpr '-' MultiplicativeExpr
       
  8567  *
       
  8568  * Compile an Additive expression.
       
  8569  *
       
  8570  * OOM:
       
  8571  */
       
  8572 
       
  8573 static void
       
  8574 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
       
  8575 
       
  8576     xmlXPathCompMultiplicativeExpr(ctxt);
       
  8577     if(OOM_FLAG) return;
       
  8578     CHECK_ERROR;
       
  8579     SKIP_BLANKS;
       
  8580     while ((CUR == '+') || (CUR == '-')) {
       
  8581         int plus;
       
  8582         int op1 = ctxt->comp->last;
       
  8583 
       
  8584             if (CUR == '+') plus = 1;
       
  8585         else plus = 0;
       
  8586         NEXT;
       
  8587         SKIP_BLANKS;
       
  8588         xmlXPathCompMultiplicativeExpr(ctxt);
       
  8589         CHECK_ERROR;
       
  8590         PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
       
  8591         SKIP_BLANKS;
       
  8592     }
       
  8593 }
       
  8594 
       
  8595 /**
       
  8596  * xmlXPathCompRelationalExpr:
       
  8597  * @ctxt:  the XPath Parser context
       
  8598  *
       
  8599  *  [24]   RelationalExpr ::=   AdditiveExpr
       
  8600  *                 | RelationalExpr '<' AdditiveExpr
       
  8601  *                 | RelationalExpr '>' AdditiveExpr
       
  8602  *                 | RelationalExpr '<=' AdditiveExpr
       
  8603  *                 | RelationalExpr '>=' AdditiveExpr
       
  8604  *
       
  8605  *  A <= B > C is allowed ? Answer from James, yes with
       
  8606  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
       
  8607  *  which is basically what got implemented.
       
  8608  *
       
  8609  * Compile a Relational expression, then push the result
       
  8610  * on the stack
       
  8611  *
       
  8612  * OOM:
       
  8613  */
       
  8614 
       
  8615 static void
       
  8616 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
       
  8617     xmlChar ch;
       
  8618     int* last;
       
  8619     // XML ENGINE: Changes/optimization were applied here
       
  8620     xmlXPathCompAdditiveExpr(ctxt);
       
  8621     if(OOM_FLAG) return;
       
  8622     CHECK_ERROR;
       
  8623     SKIP_BLANKS;
       
  8624     last = &(ctxt->comp->last);
       
  8625     // NOTE: this loop allows expressions like  A > B <= C < D ..  etc.
       
  8626     //       which will be evaluated in a way that may be unexpected:
       
  8627     //       e.g. the example above  is evaluated as
       
  8628     //       ((A > B) <= C) < D   with boolean results within parentheses
       
  8629     //       converted to 1 or 0 (from 'true' and 'false')
       
  8630     // TODO: Check how well this confoms to the spec
       
  8631     for(;;)
       
  8632     {
       
  8633         ch = *ctxt->cur;
       
  8634         if (ch == '<' || ch == '>')
       
  8635         {
       
  8636             int op1 = *last;
       
  8637             int strict = (*(++(ctxt->cur)) == '=') ? 0 : 1; // evaluate 'strict' and NEXT
       
  8638             if (!strict)
       
  8639                ctxt->cur++; // NEXT again if '='
       
  8640 
       
  8641             SKIP_BLANKS;
       
  8642             xmlXPathCompAdditiveExpr(ctxt);
       
  8643             CHECK_ERROR;
       
  8644             PUSH_BINARY_EXPR(
       
  8645                 XPATH_OP_CMP,
       
  8646                 op1,
       
  8647                 *last,
       
  8648                 (ch == '<') & 1,
       
  8649                 strict);
       
  8650             SKIP_BLANKS;
       
  8651         }
       
  8652         else
       
  8653             return;
       
  8654     } // for(;;)
       
  8655 }
       
  8656 
       
  8657 /**
       
  8658  * xmlXPathCompEqualityExpr:
       
  8659  * @ctxt:  the XPath Parser context
       
  8660  *
       
  8661  *  [23]   EqualityExpr ::=   RelationalExpr
       
  8662  *                 | EqualityExpr '=' RelationalExpr
       
  8663  *                 | EqualityExpr '!=' RelationalExpr
       
  8664  *
       
  8665  *  A != B != C is allowed ? Answer from James, yes with
       
  8666  *  (RelationalExpr = RelationalExpr) = RelationalExpr
       
  8667  *  (RelationalExpr != RelationalExpr) != RelationalExpr
       
  8668  *  which is basically what got implemented.
       
  8669  *
       
  8670  * Compile an Equality expression.
       
  8671  *
       
  8672  * OOM:
       
  8673  */
       
  8674 static void
       
  8675 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
       
  8676     xmlXPathCompRelationalExpr(ctxt);
       
  8677     if(OOM_FLAG) return;
       
  8678     CHECK_ERROR;
       
  8679     SKIP_BLANKS;
       
  8680     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
       
  8681     int eq;
       
  8682     int op1 = ctxt->comp->last;
       
  8683 
       
  8684         if (CUR == '=') eq = 1;
       
  8685     else eq = 0;
       
  8686     NEXT;
       
  8687     if (!eq) NEXT;
       
  8688     SKIP_BLANKS;
       
  8689         xmlXPathCompRelationalExpr(ctxt);
       
  8690     CHECK_ERROR;
       
  8691     PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
       
  8692     SKIP_BLANKS;
       
  8693     }
       
  8694 }
       
  8695 
       
  8696 /**
       
  8697  * xmlXPathCompAndExpr:
       
  8698  * @ctxt:  the XPath Parser context
       
  8699  *
       
  8700  *  [22]   AndExpr ::=   EqualityExpr
       
  8701  *                 | AndExpr 'and' EqualityExpr
       
  8702  *
       
  8703  * Compile an AND expression.
       
  8704  *
       
  8705  * OOM:
       
  8706  */
       
  8707 static void
       
  8708 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
       
  8709     xmlXPathCompEqualityExpr(ctxt);
       
  8710     if(OOM_FLAG) return;
       
  8711     CHECK_ERROR;
       
  8712     SKIP_BLANKS;
       
  8713     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
       
  8714     int op1 = ctxt->comp->last;
       
  8715         SKIP(3);
       
  8716     SKIP_BLANKS;
       
  8717         xmlXPathCompEqualityExpr(ctxt);
       
  8718     CHECK_ERROR;
       
  8719     PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
       
  8720     SKIP_BLANKS;
       
  8721     }
       
  8722 }
       
  8723 
       
  8724 #define XMLENGINE_OPTIMIZE_COMP_EXPR_STEPS
       
  8725 /**
       
  8726  * xmlXPathCompileExpr:
       
  8727  * @ctxt:  the XPath Parser context
       
  8728  *
       
  8729  *  [14]   Expr ::=   OrExpr
       
  8730  *  [21]   OrExpr ::=   AndExpr
       
  8731  *                 | OrExpr 'or' AndExpr
       
  8732  *
       
  8733  * Parse and compile an expression
       
  8734  *
       
  8735  * OOM: possible --> check OOM flag ////
       
  8736  */
       
  8737 static void
       
  8738 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt)
       
  8739 {
       
  8740     xmlXPathCompAndExpr(ctxt);
       
  8741     CHECK_ERROR;
       
  8742     if(OOM_FLAG){
       
  8743         XP_ERROR(XPATH_MEMORY_ERROR);
       
  8744     }
       
  8745     SKIP_BLANKS;
       
  8746     while ((CUR == 'o') && (NXT(1) == 'r')) {
       
  8747         int op1 = ctxt->comp->last;
       
  8748         SKIP(2);
       
  8749         SKIP_BLANKS;
       
  8750         xmlXPathCompAndExpr(ctxt);
       
  8751         CHECK_ERROR;
       
  8752         PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
       
  8753         op1 = ctxt->comp->nbStep;
       
  8754         SKIP_BLANKS;
       
  8755     }
       
  8756     if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
       
  8757         /* more ops could be optimized too */
       
  8758         PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
       
  8759     }
       
  8760 
       
  8761 #ifdef XMLENGINE_OPTIMIZE_COMP_EXPR_STEPS
       
  8762     // Free unused memory in the tail of ctxt->comp->steps array
       
  8763     {
       
  8764     xmlXPathStepOp* tmp;
       
  8765     // DONE: OPTIMIZE: free the rest of preallocated step table
       
  8766     // This is a exeprimental code in XML Engine
       
  8767     // DONE: Fix xmlRealloc (Note: OOM should not happen since the size is smaller, but...)
       
  8768     tmp = (xmlXPathStepOp*)xmlRealloc(ctxt->comp->steps, sizeof(xmlXPathStepOp) * ctxt->comp->nbStep);
       
  8769     if(tmp)
       
  8770         {
       
  8771         ctxt->comp->steps = tmp;
       
  8772         ctxt->comp->maxStep = ctxt->comp->nbStep;
       
  8773         }
       
  8774     }
       
  8775 #endif
       
  8776     //
       
  8777 }
       
  8778 
       
  8779 /**
       
  8780  * xmlXPathCompPredicate:
       
  8781  * @ctxt:  the XPath Parser context
       
  8782  * @filter:  act as a filter
       
  8783  *
       
  8784  *  [8]   Predicate ::=   '[' PredicateExpr ']'
       
  8785  *  [9]   PredicateExpr ::=   Expr
       
  8786  *
       
  8787  * Compile a predicate expression
       
  8788  */
       
  8789 static void
       
  8790 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
       
  8791     int op1 = ctxt->comp->last;
       
  8792 
       
  8793     SKIP_BLANKS;
       
  8794     if (CUR != '[') {
       
  8795     XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
       
  8796     }
       
  8797     NEXT;
       
  8798     SKIP_BLANKS;
       
  8799 
       
  8800     ctxt->comp->last = -1;
       
  8801     xmlXPathCompileExpr(ctxt);
       
  8802     CHECK_ERROR;
       
  8803 
       
  8804     if (CUR != ']') {
       
  8805     XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
       
  8806     }
       
  8807 
       
  8808     if (filter)
       
  8809     PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
       
  8810     else
       
  8811     PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
       
  8812 
       
  8813     NEXT;
       
  8814     SKIP_BLANKS;
       
  8815 }
       
  8816 
       
  8817 /**
       
  8818  * xmlXPathCompNodeTest:
       
  8819  * @ctxt:  the XPath Parser context
       
  8820  * @test:  pointer to a xmlXPathTestVal
       
  8821  * @type:  pointer to a xmlXPathTypeVal
       
  8822  * @prefix:  placeholder for a possible name prefix
       
  8823  *
       
  8824  * [7] NodeTest ::=   NameTest
       
  8825  *          | NodeType '(' ')'
       
  8826  *          | 'processing-instruction' '(' Literal ')'
       
  8827  *
       
  8828  * [37] NameTest ::=  '*'
       
  8829  *          | NCName ':' '*'
       
  8830  *          | QName
       
  8831  * [38] NodeType ::= 'comment'
       
  8832  *         | 'text'
       
  8833  *         | 'processing-instruction'
       
  8834  *         | 'node'
       
  8835  *
       
  8836  * Returns the name found and updates @test, @type and @prefix appropriately
       
  8837  */
       
  8838 static xmlChar *
       
  8839 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
       
  8840                  xmlXPathTypeVal *type, const xmlChar **prefix,
       
  8841              xmlChar *name) {
       
  8842     int blanks;
       
  8843 
       
  8844     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
       
  8845     STRANGE;
       
  8846     return(NULL);
       
  8847     }
       
  8848     *type = (xmlXPathTypeVal) 0;
       
  8849     *test = (xmlXPathTestVal) 0;
       
  8850     *prefix = NULL;
       
  8851     SKIP_BLANKS;
       
  8852 
       
  8853     if ((name == NULL) && (CUR == '*')) {
       
  8854     /*
       
  8855      * All elements
       
  8856      */
       
  8857     NEXT;
       
  8858     *test = NODE_TEST_ALL;
       
  8859     return(NULL);
       
  8860     }
       
  8861 
       
  8862     if (name == NULL)
       
  8863     name = xmlXPathParseNCName(ctxt);
       
  8864     if (name == NULL) {
       
  8865     XP_ERROR0(XPATH_EXPR_ERROR);
       
  8866     }
       
  8867 
       
  8868     blanks = IS_BLANK_CH(CUR);
       
  8869     SKIP_BLANKS;
       
  8870     if (CUR == '(') {
       
  8871     NEXT;
       
  8872     /*
       
  8873      * NodeType or PI search
       
  8874      */
       
  8875     if (xmlStrEqual(name, BAD_CAST "comment"))
       
  8876         *type = NODE_TYPE_COMMENT;
       
  8877     else if (xmlStrEqual(name, BAD_CAST "node"))
       
  8878         *type = NODE_TYPE_NODE;
       
  8879     else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
       
  8880         *type = NODE_TYPE_PI;
       
  8881     else if (xmlStrEqual(name, BAD_CAST "text"))
       
  8882         *type = NODE_TYPE_TEXT;
       
  8883     else {
       
  8884         if (name != NULL)
       
  8885         xmlFree(name);
       
  8886         XP_ERROR0(XPATH_EXPR_ERROR);
       
  8887     }
       
  8888 
       
  8889     *test = NODE_TEST_TYPE;
       
  8890 
       
  8891     SKIP_BLANKS;
       
  8892     if (*type == NODE_TYPE_PI) {
       
  8893         /*
       
  8894          * Specific case: search a PI by name.
       
  8895          */
       
  8896         if (name != NULL)
       
  8897         xmlFree(name);
       
  8898         name = NULL;
       
  8899         if (CUR != ')') {
       
  8900         name = xmlXPathParseLiteral(ctxt);
       
  8901         CHECK_ERROR 0;
       
  8902         *test = NODE_TEST_PI;
       
  8903         SKIP_BLANKS;
       
  8904         }
       
  8905     }
       
  8906     if (CUR != ')') {
       
  8907         if (name != NULL)
       
  8908         xmlFree(name);
       
  8909         XP_ERROR0(XPATH_UNCLOSED_ERROR);
       
  8910     }
       
  8911     NEXT;
       
  8912     return(name);
       
  8913     }
       
  8914     *test = NODE_TEST_NAME;
       
  8915     if ((!blanks) && (CUR == ':')) {
       
  8916     NEXT;
       
  8917 
       
  8918     /*
       
  8919      * Since currently the parser context don't have a
       
  8920      * namespace list associated:
       
  8921      * The namespace name for this prefix can be computed
       
  8922      * only at evaluation time. The compilation is done
       
  8923      * outside of any context.
       
  8924      */
       
  8925 #if 0
       
  8926     *prefix = xmlXPathNsLookup(ctxt->context, name);
       
  8927     if (name != NULL)
       
  8928         xmlFree(name);
       
  8929     if (*prefix == NULL) {
       
  8930         XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
       
  8931     }
       
  8932 #else
       
  8933     *prefix = name;
       
  8934 #endif
       
  8935 
       
  8936     if (CUR == '*') {
       
  8937         /*
       
  8938          * All elements
       
  8939          */
       
  8940         NEXT;
       
  8941         *test = NODE_TEST_ALL;
       
  8942         return(NULL);
       
  8943     }
       
  8944 
       
  8945     name = xmlXPathParseNCName(ctxt);
       
  8946     if (name == NULL) {
       
  8947         XP_ERROR0(XPATH_EXPR_ERROR);
       
  8948     }
       
  8949     }
       
  8950     return(name);
       
  8951 }
       
  8952 
       
  8953 /**
       
  8954  * xmlXPathIsAxisName:
       
  8955  * @name:  a preparsed name token
       
  8956  *
       
  8957  * [6] AxisName ::=   'ancestor'
       
  8958  *                  | 'ancestor-or-self'
       
  8959  *                  | 'attribute'
       
  8960  *                  | 'child'
       
  8961  *                  | 'descendant'
       
  8962  *                  | 'descendant-or-self'
       
  8963  *                  | 'following'
       
  8964  *                  | 'following-sibling'
       
  8965  *                  | 'namespace'
       
  8966  *                  | 'parent'
       
  8967  *                  | 'preceding'
       
  8968  *                  | 'preceding-sibling'
       
  8969  *                  | 'self'
       
  8970  *
       
  8971  * Returns the axis or 0
       
  8972  */
       
  8973 static xmlXPathAxisVal
       
  8974 xmlXPathIsAxisName(const xmlChar *name) {
       
  8975     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
       
  8976     switch (name[0]) {
       
  8977     // TODO: OPTIMIZE: Reorder case's optimally
       
  8978     case 'a':
       
  8979         if (xmlStrEqual(name, BAD_CAST "ancestor"))
       
  8980         ret = AXIS_ANCESTOR;
       
  8981         if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
       
  8982         ret = AXIS_ANCESTOR_OR_SELF;
       
  8983         if (xmlStrEqual(name, BAD_CAST "attribute"))
       
  8984         ret = AXIS_ATTRIBUTE;
       
  8985         break;
       
  8986     case 'c':
       
  8987         if (xmlStrEqual(name, BAD_CAST "child"))
       
  8988         ret = AXIS_CHILD;
       
  8989         break;
       
  8990     case 'd':
       
  8991         if (xmlStrEqual(name, BAD_CAST "descendant"))
       
  8992         ret = AXIS_DESCENDANT;
       
  8993         if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
       
  8994         ret = AXIS_DESCENDANT_OR_SELF;
       
  8995         break;
       
  8996     case 'f':
       
  8997         if (xmlStrEqual(name, BAD_CAST "following"))
       
  8998         ret = AXIS_FOLLOWING;
       
  8999         if (xmlStrEqual(name, BAD_CAST "following-sibling"))
       
  9000         ret = AXIS_FOLLOWING_SIBLING;
       
  9001         break;
       
  9002     case 'n':
       
  9003         if (xmlStrEqual(name, BAD_CAST "namespace"))
       
  9004         ret = AXIS_NAMESPACE;
       
  9005         break;
       
  9006     case 'p':
       
  9007         if (xmlStrEqual(name, BAD_CAST "parent"))
       
  9008         ret = AXIS_PARENT;
       
  9009         if (xmlStrEqual(name, BAD_CAST "preceding"))
       
  9010         ret = AXIS_PRECEDING;
       
  9011         if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
       
  9012         ret = AXIS_PRECEDING_SIBLING;
       
  9013         break;
       
  9014     case 's':
       
  9015         if (xmlStrEqual(name, BAD_CAST "self"))
       
  9016         ret = AXIS_SELF;
       
  9017         break;
       
  9018     }
       
  9019     return(ret);
       
  9020 }
       
  9021 
       
  9022 /**
       
  9023  * xmlXPathCompStep:
       
  9024  * @ctxt:  the XPath Parser context
       
  9025  *
       
  9026  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
       
  9027  *                  | AbbreviatedStep
       
  9028  *
       
  9029  * [12] AbbreviatedStep ::=   '.' | '..'
       
  9030  *
       
  9031  * [5] AxisSpecifier ::= AxisName '::'
       
  9032  *                  | AbbreviatedAxisSpecifier
       
  9033  *
       
  9034  * [13] AbbreviatedAxisSpecifier ::= '@'?
       
  9035  *
       
  9036  * Modified for XPtr range support as:
       
  9037  *
       
  9038  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
       
  9039  *                     | AbbreviatedStep
       
  9040  *                     | 'range-to' '(' Expr ')' Predicate*
       
  9041  *
       
  9042  * Compile one step in a Location Path
       
  9043  * A location step of . is short for self::node(). This is
       
  9044  * particularly useful in conjunction with //. For example, the
       
  9045  * location path .//para is short for
       
  9046  * self::node()/descendant-or-self::node()/child::para
       
  9047  * and so will select all para descendant elements of the context
       
  9048  * node.
       
  9049  * Similarly, a location step of .. is short for parent::node().
       
  9050  * For example, ../title is short for parent::node()/child::title
       
  9051  * and so will select the title children of the parent of the context
       
  9052  * node.
       
  9053  */
       
  9054 static void
       
  9055 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
       
  9056 #ifdef LIBXML_XPTR_ENABLED
       
  9057     int rangeto = 0;
       
  9058     int op2 = -1;
       
  9059 #endif
       
  9060 
       
  9061     SKIP_BLANKS;
       
  9062     if ((CUR == '.') && (NXT(1) == '.')) {
       
  9063     SKIP(2);
       
  9064     SKIP_BLANKS;
       
  9065     PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
       
  9066             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
       
  9067     } else if (CUR == '.') {
       
  9068     NEXT;
       
  9069     SKIP_BLANKS;
       
  9070     } else {
       
  9071     xmlChar *name = NULL;
       
  9072     const xmlChar *prefix = NULL;
       
  9073     xmlXPathTestVal test;
       
  9074     xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
       
  9075     xmlXPathTypeVal type;
       
  9076     int op1;
       
  9077 
       
  9078     /*
       
  9079      * The modification needed for XPointer change to the production
       
  9080      */
       
  9081 #ifdef LIBXML_XPTR_ENABLED
       
  9082     if (ctxt->xptr) {
       
  9083         name = xmlXPathParseNCName(ctxt);
       
  9084         if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
       
  9085                 op2 = ctxt->comp->last;
       
  9086         xmlFree(name);
       
  9087         SKIP_BLANKS;
       
  9088         if (CUR != '(') {
       
  9089             XP_ERROR(XPATH_EXPR_ERROR);
       
  9090         }
       
  9091         NEXT;
       
  9092         SKIP_BLANKS;
       
  9093 
       
  9094         xmlXPathCompileExpr(ctxt);
       
  9095         /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
       
  9096         CHECK_ERROR;
       
  9097 
       
  9098         SKIP_BLANKS;
       
  9099         if (CUR != ')') {
       
  9100             XP_ERROR(XPATH_EXPR_ERROR);
       
  9101         }
       
  9102         NEXT;
       
  9103         rangeto = 1;
       
  9104         goto eval_predicates;
       
  9105         }
       
  9106     }
       
  9107 #endif
       
  9108     if (CUR == '*') {
       
  9109         axis = AXIS_CHILD;
       
  9110     } else {
       
  9111         if (name == NULL)
       
  9112         name = xmlXPathParseNCName(ctxt);
       
  9113         if(OOM_FLAG) return;
       
  9114         if (name != NULL) {
       
  9115         axis = xmlXPathIsAxisName(name);
       
  9116         if (axis != 0) {
       
  9117             SKIP_BLANKS;
       
  9118             if ((CUR == ':') && (NXT(1) == ':')) {
       
  9119             SKIP(2);
       
  9120             xmlFree(name);
       
  9121             name = NULL;
       
  9122             } else {
       
  9123             /* an element name can conflict with an axis one :-\ */
       
  9124             axis = AXIS_CHILD;
       
  9125             }
       
  9126         } else {
       
  9127             axis = AXIS_CHILD;
       
  9128         }
       
  9129         } else if (CUR == '@') {
       
  9130         NEXT;
       
  9131         axis = AXIS_ATTRIBUTE;
       
  9132         } else {
       
  9133         axis = AXIS_CHILD;
       
  9134         }
       
  9135     }
       
  9136 
       
  9137     CHECK_ERROR;
       
  9138 
       
  9139     name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
       
  9140     if (test == 0)
       
  9141         return;
       
  9142 
       
  9143 #ifdef DEBUG_STEP
       
  9144     xmlGenericError(xmlGenericErrorContext,
       
  9145         "Basis : computing new set\n");
       
  9146 #endif
       
  9147 
       
  9148 #ifdef DEBUG_STEP
       
  9149     xmlGenericError(xmlGenericErrorContext, "Basis : ");
       
  9150     if (ctxt->value == NULL)
       
  9151         xmlGenericError(xmlGenericErrorContext, "no value\n");
       
  9152     else if (ctxt->value->nodesetval == NULL)
       
  9153         xmlGenericError(xmlGenericErrorContext, "Empty\n");
       
  9154     else
       
  9155         xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
       
  9156 #endif
       
  9157 
       
  9158 #ifdef LIBXML_XPTR_ENABLED
       
  9159 eval_predicates:
       
  9160 #endif
       
  9161     op1 = ctxt->comp->last;
       
  9162     ctxt->comp->last = -1;
       
  9163 
       
  9164     SKIP_BLANKS;
       
  9165     while (CUR == '[') {
       
  9166         xmlXPathCompPredicate(ctxt, 0);
       
  9167     }
       
  9168 
       
  9169 #ifdef LIBXML_XPTR_ENABLED
       
  9170     if (rangeto) {
       
  9171         PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
       
  9172     } else
       
  9173 #endif
       
  9174         PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
       
  9175                test, type, (void *)prefix, (void *)name);
       
  9176 
       
  9177     }
       
  9178 #ifdef DEBUG_STEP
       
  9179     xmlGenericError(xmlGenericErrorContext, "Step : ");
       
  9180     if (ctxt->value == NULL)
       
  9181     xmlGenericError(xmlGenericErrorContext, "no value\n");
       
  9182     else if (ctxt->value->nodesetval == NULL)
       
  9183     xmlGenericError(xmlGenericErrorContext, "Empty\n");
       
  9184     else
       
  9185     xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
       
  9186         ctxt->value->nodesetval);
       
  9187 #endif
       
  9188 }
       
  9189 
       
  9190 /**
       
  9191  * xmlXPathCompRelativeLocationPath:
       
  9192  * @ctxt:  the XPath Parser context
       
  9193  *
       
  9194  *  [3]   RelativeLocationPath ::=   Step
       
  9195  *                     | RelativeLocationPath '/' Step
       
  9196  *                     | AbbreviatedRelativeLocationPath
       
  9197  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
       
  9198  *
       
  9199  * Compile a relative location path.
       
  9200  */
       
  9201 static void
       
  9202 xmlXPathCompRelativeLocationPath
       
  9203 (xmlXPathParserContextPtr ctxt) {
       
  9204     SKIP_BLANKS;
       
  9205     if ((CUR == '/') && (NXT(1) == '/')) {
       
  9206     SKIP(2);
       
  9207     SKIP_BLANKS;
       
  9208     PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
       
  9209                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
       
  9210     } else if (CUR == '/') {
       
  9211         NEXT;
       
  9212     SKIP_BLANKS;
       
  9213     }
       
  9214     xmlXPathCompStep(ctxt);
       
  9215     if(OOM_FLAG) return;
       
  9216     SKIP_BLANKS;
       
  9217     while (CUR == '/') {
       
  9218     if ((CUR == '/') && (NXT(1) == '/')) {
       
  9219         SKIP(2);
       
  9220         SKIP_BLANKS;
       
  9221         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
       
  9222                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
       
  9223         xmlXPathCompStep(ctxt);
       
  9224         if(OOM_FLAG) return;
       
  9225     } else if (CUR == '/') {
       
  9226         NEXT;
       
  9227         SKIP_BLANKS;
       
  9228         xmlXPathCompStep(ctxt);
       
  9229     }
       
  9230     SKIP_BLANKS;
       
  9231     }
       
  9232 }
       
  9233 
       
  9234 /**
       
  9235  * xmlXPathCompLocationPath:
       
  9236  * @ctxt:  the XPath Parser context
       
  9237  *
       
  9238  *  [1]   LocationPath ::=   RelativeLocationPath
       
  9239  *                     | AbsoluteLocationPath
       
  9240  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
       
  9241  *                     | AbbreviatedAbsoluteLocationPath
       
  9242  *  [10]   AbbreviatedAbsoluteLocationPath ::=
       
  9243  *                           '//' RelativeLocationPath
       
  9244  *
       
  9245  * Compile a location path
       
  9246  *
       
  9247  * // is short for /descendant-or-self::node()/. For example,
       
  9248  * //para is short for /descendant-or-self::node()/child::para and
       
  9249  * so will select any para element in the document (even a para element
       
  9250  * that is a document element will be selected by //para since the
       
  9251  * document element node is a child of the root node); div//para is
       
  9252  * short for div/descendant-or-self::node()/child::para and so will
       
  9253  * select all para descendants of div children.
       
  9254  */
       
  9255 static void
       
  9256 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
       
  9257     SKIP_BLANKS;
       
  9258     if (CUR != '/') {
       
  9259         xmlXPathCompRelativeLocationPath(ctxt);
       
  9260     } else {
       
  9261     while (CUR == '/') {
       
  9262         if ((CUR == '/') && (NXT(1) == '/')) {
       
  9263         SKIP(2);
       
  9264         SKIP_BLANKS;
       
  9265         PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
       
  9266                  NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
       
  9267         xmlXPathCompRelativeLocationPath(ctxt);
       
  9268         if(OOM_FLAG) return;
       
  9269         } else if (CUR == '/') {
       
  9270         NEXT;
       
  9271         SKIP_BLANKS;
       
  9272         if ((CUR != 0 ) &&
       
  9273             ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
       
  9274              (CUR == '@') || (CUR == '*')))
       
  9275         	{
       
  9276              xmlXPathCompRelativeLocationPath(ctxt);
       
  9277              if(OOM_FLAG) return;        	
       
  9278         	}
       
  9279         }
       
  9280     }
       
  9281     }
       
  9282 }
       
  9283 
       
  9284 /************************************************************************
       
  9285  *                                  *
       
  9286  *      XPath precompiled expression evaluation         *
       
  9287  *                                  *
       
  9288  ************************************************************************/
       
  9289 
       
  9290 static int
       
  9291 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
       
  9292 
       
  9293 /**
       
  9294  * xmlXPathNodeCollectAndTest:
       
  9295  * @ctxt:  the XPath Parser context
       
  9296  * @op:  the XPath precompiled step operation
       
  9297  * @first:  pointer to the first element in document order
       
  9298  * @last:  pointer to the last element in document order
       
  9299  *
       
  9300  * This is the function implementing a step: based on the current list
       
  9301  * of nodes, it builds up a new list, looking at all nodes under that
       
  9302  * axis and selecting them. It also does the predicate filtering
       
  9303  *
       
  9304  * Pushes the new NodeSet resulting from the search.
       
  9305  *
       
  9306  * Returns the number of nodes traversed or -1 when OOM
       
  9307  */
       
  9308 static int
       
  9309 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
       
  9310                            xmlXPathStepOpPtr op,
       
  9311                            xmlNodePtr * first, xmlNodePtr * last)
       
  9312 {
       
  9313     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
       
  9314     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
       
  9315     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
       
  9316 
       
  9317     const xmlChar* prefix = (xmlChar*) op->value4;
       
  9318     const xmlChar* name = (xmlChar*) op->value5;
       
  9319     const xmlChar* URI = NULL;
       
  9320 
       
  9321 #ifdef DEBUG_STEP
       
  9322     int n = 0;
       
  9323 #endif
       
  9324 
       
  9325     int i, t = 0;
       
  9326     xmlNodeSetPtr ret = NULL;
       
  9327     xmlNodeSetPtr list = NULL;
       
  9328     xmlXPathTraversalFunction next = NULL;
       
  9329     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
       
  9330     xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
       
  9331     xmlNodePtr cur = NULL;
       
  9332     xmlXPathObjectPtr obj;
       
  9333     xmlNodeSetPtr nodelist;
       
  9334     xmlNodePtr tmp;
       
  9335 
       
  9336     CHECK_TYPE0(XPATH_NODESET);
       
  9337     obj = valuePop(ctxt);
       
  9338     addNode = xmlXPathNodeSetAdd;
       
  9339     mergeNodeSet = xmlXPathNodeSetMerge;
       
  9340     if (prefix != NULL) {
       
  9341         URI = xmlXPathNsLookup(ctxt->context, prefix);
       
  9342         if (URI == NULL)
       
  9343             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
       
  9344     }
       
  9345 
       
  9346 #ifdef DEBUG_STEP
       
  9347     xmlGenericError(xmlGenericErrorContext, "new step : ");
       
  9348 #endif
       
  9349 
       
  9350     switch (axis)
       
  9351     {
       
  9352     // TODO: OPTIMIZATION: Reorder options according to expectation of invocation
       
  9353     case AXIS_ANCESTOR: {
       
  9354 #ifdef DEBUG_STEP
       
  9355         xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
       
  9356 #endif
       
  9357         first = NULL;
       
  9358         next = xmlXPathNextAncestor;
       
  9359         break;
       
  9360     }
       
  9361 
       
  9362     case AXIS_ANCESTOR_OR_SELF: {
       
  9363 #ifdef DEBUG_STEP
       
  9364         xmlGenericError(xmlGenericErrorContext, "axis 'ancestors-or-self' ");
       
  9365 #endif
       
  9366         first = NULL;
       
  9367         next = xmlXPathNextAncestorOrSelf;
       
  9368         break;
       
  9369     }
       
  9370 
       
  9371     case AXIS_ATTRIBUTE:{
       
  9372 #ifdef DEBUG_STEP
       
  9373         xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
       
  9374 #endif
       
  9375         first = NULL;
       
  9376         last = NULL;
       
  9377         next = xmlXPathNextAttribute;
       
  9378         mergeNodeSet = xmlXPathNodeSetMergeUnique;
       
  9379         break;
       
  9380     }
       
  9381 
       
  9382     case AXIS_CHILD:{
       
  9383 #ifdef DEBUG_STEP
       
  9384         xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
       
  9385 #endif
       
  9386         last = NULL;
       
  9387         next = xmlXPathNextChild;
       
  9388         mergeNodeSet = xmlXPathNodeSetMergeUnique;
       
  9389         break;
       
  9390     }
       
  9391 
       
  9392     case AXIS_DESCENDANT:{
       
  9393 #ifdef DEBUG_STEP
       
  9394         xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
       
  9395 #endif
       
  9396         last = NULL;
       
  9397         next = xmlXPathNextDescendant;
       
  9398         break;
       
  9399     }
       
  9400 
       
  9401     case AXIS_DESCENDANT_OR_SELF:{
       
  9402 #ifdef DEBUG_STEP
       
  9403         xmlGenericError(xmlGenericErrorContext, "axis 'descendant-or-self' ");
       
  9404 #endif
       
  9405         last = NULL;
       
  9406         next = xmlXPathNextDescendantOrSelf;
       
  9407         break;
       
  9408     }
       
  9409 
       
  9410     case AXIS_FOLLOWING:{
       
  9411 #ifdef DEBUG_STEP
       
  9412         xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
       
  9413 #endif
       
  9414         last = NULL;
       
  9415         next = xmlXPathNextFollowing;
       
  9416         break;
       
  9417     }
       
  9418 
       
  9419     case AXIS_FOLLOWING_SIBLING:{
       
  9420 #ifdef DEBUG_STEP
       
  9421         xmlGenericError(xmlGenericErrorContext, "axis 'following-siblings' ");
       
  9422 #endif
       
  9423         last = NULL;
       
  9424         next = xmlXPathNextFollowingSibling;
       
  9425         break;
       
  9426     }
       
  9427 
       
  9428     case AXIS_NAMESPACE:{
       
  9429 #ifdef DEBUG_STEP
       
  9430         xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
       
  9431 #endif
       
  9432         first = NULL;
       
  9433         last = NULL;
       
  9434         next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
       
  9435         mergeNodeSet = xmlXPathNodeSetMergeUnique;
       
  9436         break;
       
  9437     }
       
  9438 
       
  9439     case AXIS_PARENT:{
       
  9440 #ifdef DEBUG_STEP
       
  9441         xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
       
  9442 #endif
       
  9443         first = NULL;
       
  9444         next = xmlXPathNextParent;
       
  9445         break;
       
  9446     }
       
  9447 
       
  9448     case AXIS_PRECEDING:{
       
  9449 #ifdef DEBUG_STEP
       
  9450         xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
       
  9451 #endif
       
  9452         first = NULL;
       
  9453         next = xmlXPathNextPrecedingInternal;
       
  9454         break;
       
  9455     }
       
  9456 
       
  9457     case AXIS_PRECEDING_SIBLING:{
       
  9458 #ifdef DEBUG_STEP
       
  9459         xmlGenericError(xmlGenericErrorContext, "axis 'preceding-sibling' ");
       
  9460 #endif
       
  9461         first = NULL;
       
  9462         next = xmlXPathNextPrecedingSibling;
       
  9463         break;
       
  9464     }
       
  9465 
       
  9466     case AXIS_SELF:{
       
  9467 #ifdef DEBUG_STEP
       
  9468         xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
       
  9469 #endif
       
  9470         first = NULL;
       
  9471         last = NULL;
       
  9472         next = xmlXPathNextSelf;
       
  9473         mergeNodeSet = xmlXPathNodeSetMergeUnique;
       
  9474         break;
       
  9475     }
       
  9476 
       
  9477     } // switch(axis)
       
  9478 
       
  9479     if (next == NULL)
       
  9480         return(0);
       
  9481 
       
  9482     nodelist = obj->nodesetval;
       
  9483     if (nodelist == NULL) {
       
  9484         xmlXPathFreeObject(obj);
       
  9485         valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
       
  9486         return(0);
       
  9487     }
       
  9488     addNode = xmlXPathNodeSetAddUnique;
       
  9489     ret = NULL;
       
  9490 
       
  9491 #ifdef DEBUG_STEP
       
  9492 {
       
  9493     xmlGenericError(xmlGenericErrorContext, " context contains %d nodes\n", nodelist->nodeNr);
       
  9494     switch (test) {
       
  9495         case NODE_TEST_NONE:
       
  9496             xmlGenericError(xmlGenericErrorContext, "           searching for none !!!\n");
       
  9497             break;
       
  9498         case NODE_TEST_TYPE:
       
  9499             xmlGenericError(xmlGenericErrorContext, "           searching for type %d\n", type);
       
  9500             break;
       
  9501         case NODE_TEST_PI:
       
  9502             xmlGenericError(xmlGenericErrorContext, "           searching for PI !!!\n");
       
  9503             break;
       
  9504         case NODE_TEST_ALL:
       
  9505             xmlGenericError(xmlGenericErrorContext, "           searching for *\n");
       
  9506             break;
       
  9507         case NODE_TEST_NS:
       
  9508             xmlGenericError(xmlGenericErrorContext, "           searching for namespace %s\n", prefix);
       
  9509             break;
       
  9510         case NODE_TEST_NAME:
       
  9511             xmlGenericError(xmlGenericErrorContext, "           searching for name %s\n", name);
       
  9512             if (prefix != NULL)
       
  9513                 xmlGenericError(xmlGenericErrorContext, "           with namespace %s\n", prefix);
       
  9514             break;
       
  9515     }
       
  9516     xmlGenericError(xmlGenericErrorContext, "Testing : ");
       
  9517 }
       
  9518 #endif
       
  9519     /*
       
  9520     * 2.3 Node Tests
       
  9521     *  - For the attribute axis, the principal node type is attribute.
       
  9522     *  - For the namespace axis, the principal node type is namespace.
       
  9523     *  - For other axes, the principal node type is element.
       
  9524     *
       
  9525     * A node test * is true for any node of the
       
  9526     * principal node type. For example, child::* will
       
  9527     * select all element children of the context node
       
  9528     */
       
  9529     tmp = ctxt->context->node;
       
  9530 
       
  9531     for (i = 0; i < nodelist->nodeNr; i++)
       
  9532     {
       
  9533         ctxt->context->node = nodelist->nodeTab[i];
       
  9534         cur = NULL;
       
  9535         list = xmlXPathNodeSetCreate(NULL);
       
  9536 	 if(OOM_FLAG) 
       
  9537 	 	{
       
  9538 	 	xmlXPathFreeObject(obj);
       
  9539 	 	xmlXPathFreeNodeSet(ret);	
       
  9540 	 	return(-1);
       
  9541 	 	}
       
  9542         //
       
  9543         do {
       
  9544             cur = next(ctxt, cur);
       
  9545             if (cur == NULL)
       
  9546                 break;
       
  9547             if ((first != NULL) && (*first == cur))
       
  9548                 break;
       
  9549             if (((t % 256) == 0) &&
       
  9550                 (first != NULL) && (*first != NULL) &&
       
  9551                 (xmlXPathCmpNodes(*first, cur) >= 0))
       
  9552                 break;
       
  9553             if ((last != NULL) && (*last == cur))
       
  9554                 break;
       
  9555             if (((t % 256) == 0) &&
       
  9556                 (last != NULL) && (*last != NULL) &&
       
  9557                 (xmlXPathCmpNodes(cur, *last) >= 0))
       
  9558                 break;
       
  9559 
       
  9560             t++;
       
  9561 #ifdef DEBUG_STEP
       
  9562             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
       
  9563 #endif
       
  9564             switch (test)
       
  9565             {
       
  9566             case NODE_TEST_NONE:{
       
  9567                 ctxt->context->node = tmp;
       
  9568                 STRANGE return(t);
       
  9569             }
       
  9570             case NODE_TEST_TYPE:{
       
  9571                 // TODO: OPTIMIZATION: Reorder to maximize performance of partial evaluation
       
  9572                 if ((cur->type == type) ||
       
  9573                     ((type == NODE_TYPE_NODE) &&
       
  9574                     ((cur->type == XML_DOCUMENT_NODE) ||
       
  9575                     (cur->type == XML_HTML_DOCUMENT_NODE) ||
       
  9576                     (cur->type == XML_ELEMENT_NODE) ||
       
  9577                     (cur->type == XML_NAMESPACE_DECL) ||
       
  9578                     (cur->type == XML_ATTRIBUTE_NODE) ||
       
  9579                     (cur->type == XML_PI_NODE) ||
       
  9580                     (cur->type == XML_COMMENT_NODE) ||
       
  9581                     (cur->type == XML_CDATA_SECTION_NODE) ||
       
  9582                     (cur->type == XML_TEXT_NODE))) ||
       
  9583                     ((type == NODE_TYPE_TEXT) &&
       
  9584                     (cur->type == XML_CDATA_SECTION_NODE)))
       
  9585                 {
       
  9586 #ifdef DEBUG_STEP
       
  9587                     n++;
       
  9588 #endif
       
  9589                         addNode(list, cur);
       
  9590                 }
       
  9591                 break;
       
  9592             }
       
  9593 
       
  9594             case NODE_TEST_PI:  {
       
  9595                 if (cur->type == XML_PI_NODE)
       
  9596                 {
       
  9597                     if ((name != NULL) && (!xmlStrEqual(name, cur->name)))
       
  9598                         break;
       
  9599 #ifdef DEBUG_STEP
       
  9600                     n++;
       
  9601 #endif
       
  9602                     addNode(list, cur);
       
  9603                 }
       
  9604                 break;
       
  9605             }
       
  9606 
       
  9607             case NODE_TEST_ALL: {
       
  9608                 if (axis == AXIS_ATTRIBUTE) {
       
  9609                     if (cur->type == XML_ATTRIBUTE_NODE) {
       
  9610 #ifdef DEBUG_STEP
       
  9611                         n++;
       
  9612 #endif
       
  9613                         addNode(list, cur);
       
  9614                     }
       
  9615                 } else
       
  9616                 if (axis == AXIS_NAMESPACE) {
       
  9617                     if (cur->type == XML_NAMESPACE_DECL) {
       
  9618 #ifdef DEBUG_STEP
       
  9619                         n++;
       
  9620 #endif
       
  9621                         xmlXPathNodeSetAddNs(list, ctxt->context->node, (xmlNsPtr) cur);
       
  9622                     }
       
  9623                 } else {
       
  9624                     if (cur->type == XML_ELEMENT_NODE) {
       
  9625                         if (prefix == NULL) {
       
  9626 #ifdef DEBUG_STEP
       
  9627                             n++;
       
  9628 #endif
       
  9629                             addNode(list, cur);
       
  9630                                 if(OOM_FLAG) 
       
  9631                                 	{
       
  9632                                 	xmlXPathFreeObject(obj);
       
  9633                                 	xmlXPathFreeNodeSet(list);
       
  9634                                 	xmlXPathFreeNodeSet(ret);
       
  9635                                 	return(-1);
       
  9636                                 	}                            
       
  9637                         } else
       
  9638                         if ((cur->ns != NULL) && (xmlStrEqual(URI, cur->ns->href))) {
       
  9639 #ifdef DEBUG_STEP
       
  9640                             n++;
       
  9641 #endif
       
  9642                             addNode(list, cur);
       
  9643                         }
       
  9644                     }
       
  9645                 }
       
  9646                 break;
       
  9647             }
       
  9648 
       
  9649             case NODE_TEST_NS:  {
       
  9650                     TODO;
       
  9651                     break;
       
  9652             }
       
  9653             case NODE_TEST_NAME:{
       
  9654                 switch (cur->type) {
       
  9655                 case XML_ELEMENT_NODE:  {
       
  9656                     if (xmlStrEqual(name, cur->name)) {
       
  9657                         if (prefix == NULL) {
       
  9658                             if (cur->ns == NULL) { // should we add here || cur->ns->pref == NULL ?
       
  9659 #ifdef DEBUG_STEP
       
  9660                                 n++;
       
  9661 #endif
       
  9662                                 addNode(list, cur);
       
  9663                                 if(OOM_FLAG) 
       
  9664                                 	{
       
  9665                                 	xmlXPathFreeObject(obj);
       
  9666                                 	xmlXPathFreeNodeSet(list);
       
  9667                                 	return(-1);
       
  9668                                 	}
       
  9669                             }
       
  9670                         } else {
       
  9671                             if ((cur->ns != NULL) && (xmlStrEqual(URI, cur->ns->href))) {
       
  9672 #ifdef DEBUG_STEP
       
  9673                                 n++;
       
  9674 #endif
       
  9675                                 addNode(list, cur);
       
  9676                             }
       
  9677                         }
       
  9678                     }
       
  9679                     break;
       
  9680                 }
       
  9681 
       
  9682                 case XML_ATTRIBUTE_NODE:{
       
  9683                     xmlAttrPtr attr = (xmlAttrPtr) cur;
       
  9684 
       
  9685                     if (xmlStrEqual(name, attr->name)) {
       
  9686                         if (prefix == NULL) {
       
  9687                             if ((attr->ns == NULL) || (attr->ns->prefix == NULL)) {
       
  9688 #ifdef DEBUG_STEP
       
  9689                                 n++;
       
  9690 #endif
       
  9691                                 addNode(list, (xmlNodePtr) attr);
       
  9692 				     if(OOM_FLAG)
       
  9693 				      	{
       
  9694 				    	xmlXPathFreeObject(obj);
       
  9695 				    	xmlXPathFreeNodeSet(list);
       
  9696 				    	return(-1);
       
  9697 				    	}                                
       
  9698                             }
       
  9699                         } else {
       
  9700                             if ((attr->ns != NULL) && (xmlStrEqual(URI, attr->ns->href))) {
       
  9701 #ifdef DEBUG_STEP
       
  9702                                 n++;
       
  9703 #endif
       
  9704                                 addNode(list, (xmlNodePtr) attr);
       
  9705                                 }
       
  9706                         }
       
  9707                     }
       
  9708                     break;
       
  9709                 }
       
  9710                 case XML_NAMESPACE_DECL:{
       
  9711                     if (cur->type == XML_NAMESPACE_DECL) {
       
  9712                         xmlNsPtr ns = (xmlNsPtr) cur;
       
  9713 
       
  9714                         if ((ns->prefix != NULL) && (name != NULL)
       
  9715                             && (xmlStrEqual(ns->prefix, name)))
       
  9716                         {
       
  9717 #ifdef DEBUG_STEP
       
  9718                             n++;
       
  9719 #endif
       
  9720                             xmlXPathNodeSetAddNs(list, ctxt->context->node, (xmlNsPtr) cur);
       
  9721                         }
       
  9722                     }
       
  9723                     break;
       
  9724                 }
       
  9725 
       
  9726                 default:
       
  9727                     break;
       
  9728                 }
       
  9729 
       
  9730                 break;
       
  9731                 break;
       
  9732                 }
       
  9733             } // switch(test)
       
  9734         } while (cur != NULL);
       
  9735 
       
  9736         /*
       
  9737         * If there is some predicate filtering do it now
       
  9738         */
       
  9739         if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0))
       
  9740         {
       
  9741             xmlXPathObjectPtr obj2;
       
  9742 
       
  9743             valuePush(ctxt, xmlXPathWrapNodeSet(list));
       
  9744 	     if(OOM_FLAG)
       
  9745 	    	{
       
  9746 	    	xmlXPathFreeObject(obj);
       
  9747 	    	xmlXPathFreeNodeSet(list);
       
  9748 	    	xmlXPathFreeNodeSet(ret);
       
  9749 	    	return(-1);
       
  9750 	    	}            
       
  9751             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
       
  9752             CHECK_TYPE0(XPATH_NODESET);
       
  9753             obj2 = valuePop(ctxt);
       
  9754             list = obj2->nodesetval;
       
  9755             obj2->nodesetval = NULL;
       
  9756             xmlXPathFreeObject(obj2);
       
  9757         }
       
  9758         if (ret == NULL) {
       
  9759             ret = list;
       
  9760         } else {
       
  9761             ret = mergeNodeSet(ret, list);
       
  9762             xmlXPathFreeNodeSet(list);
       
  9763         }
       
  9764     } // for (i = 0; i < nodelist->nodeNr; i++)
       
  9765 
       
  9766     ctxt->context->node = tmp;
       
  9767 
       
  9768 #ifdef DEBUG_STEP
       
  9769     xmlGenericError(xmlGenericErrorContext, "\nExamined %d nodes, found %d nodes at that step\n", t, n);
       
  9770 #endif
       
  9771 
       
  9772     valuePush(ctxt, xmlXPathWrapNodeSet(ret));
       
  9773     if(OOM_FLAG)
       
  9774     	{
       
  9775     	xmlXPathFreeObject(obj);
       
  9776     	xmlXPathFreeNodeSet(list);
       
  9777     	return(-1);
       
  9778     	}
       
  9779     if ((obj->boolval) && (obj->user != NULL)) {
       
  9780         ctxt->value->boolval = 1;
       
  9781         ctxt->value->user = obj->user;
       
  9782         obj->user = NULL;
       
  9783         obj->boolval = 0;
       
  9784     }
       
  9785     xmlXPathFreeObject(obj);
       
  9786     return(t);
       
  9787 }
       
  9788 
       
  9789 /**
       
  9790  * xmlXPathNodeCollectAndTestNth:
       
  9791  * @ctxt:  the XPath Parser context
       
  9792  * @op:  the XPath precompiled step operation
       
  9793  * @indx:  the index to collect
       
  9794  * @first:  pointer to the first element in document order
       
  9795  * @last:  pointer to the last element in document order
       
  9796  *
       
  9797  * This is the function implementing a step: based on the current list
       
  9798  * of nodes, it builds up a new list, looking at all nodes under that
       
  9799  * axis and selecting them. It also does the predicate filtering
       
  9800  *
       
  9801  * Pushes the new NodeSet resulting from the search.
       
  9802  * Returns the number of node traversed or -1 when OOM
       
  9803  */
       
  9804 static int
       
  9805 xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
       
  9806                               xmlXPathStepOpPtr op, int indx,
       
  9807                               xmlNodePtr * first, xmlNodePtr * last)
       
  9808 {
       
  9809     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
       
  9810     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
       
  9811     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
       
  9812     const xmlChar *prefix = (xmlChar*)op->value4;
       
  9813     const xmlChar *name = (xmlChar*)op->value5;
       
  9814     const xmlChar *URI = NULL;
       
  9815     int n = 0, t = 0;
       
  9816 
       
  9817     int i;
       
  9818     xmlNodeSetPtr list;
       
  9819     xmlXPathTraversalFunction next = NULL;
       
  9820     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
       
  9821     xmlNodePtr cur = NULL;
       
  9822     xmlXPathObjectPtr obj;
       
  9823     xmlNodeSetPtr nodelist;
       
  9824     xmlNodePtr tmp;
       
  9825 
       
  9826     CHECK_TYPE0(XPATH_NODESET);
       
  9827     obj = valuePop(ctxt);
       
  9828     addNode = xmlXPathNodeSetAdd;
       
  9829     if (prefix != NULL) {
       
  9830         URI = xmlXPathNsLookup(ctxt->context, prefix);
       
  9831         if (URI == NULL)
       
  9832             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
       
  9833     }
       
  9834 #ifdef DEBUG_STEP_NTH
       
  9835     xmlGenericError(xmlGenericErrorContext, "new step : ");
       
  9836     if (first != NULL) {
       
  9837     if (*first != NULL)
       
  9838         xmlGenericError(xmlGenericErrorContext, "first = %s ",
       
  9839             (*first)->name);
       
  9840     else
       
  9841         xmlGenericError(xmlGenericErrorContext, "first = NULL ");
       
  9842     }
       
  9843     if (last != NULL) {
       
  9844     if (*last != NULL)
       
  9845         xmlGenericError(xmlGenericErrorContext, "last = %s ",
       
  9846             (*last)->name);
       
  9847     else
       
  9848         xmlGenericError(xmlGenericErrorContext, "last = NULL ");
       
  9849     }
       
  9850 #endif
       
  9851     switch (axis) {
       
  9852         case AXIS_ANCESTOR:
       
  9853 #ifdef DEBUG_STEP_NTH
       
  9854             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
       
  9855 #endif
       
  9856             first = NULL;
       
  9857             next = xmlXPathNextAncestor;
       
  9858             break;
       
  9859         case AXIS_ANCESTOR_OR_SELF:
       
  9860 #ifdef DEBUG_STEP_NTH
       
  9861             xmlGenericError(xmlGenericErrorContext,
       
  9862                             "axis 'ancestors-or-self' ");
       
  9863 #endif
       
  9864             first = NULL;
       
  9865             next = xmlXPathNextAncestorOrSelf;
       
  9866             break;
       
  9867         case AXIS_ATTRIBUTE:
       
  9868 #ifdef DEBUG_STEP_NTH
       
  9869             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
       
  9870 #endif
       
  9871             first = NULL;
       
  9872         last = NULL;
       
  9873             next = xmlXPathNextAttribute;
       
  9874             break;
       
  9875         case AXIS_CHILD:
       
  9876 #ifdef DEBUG_STEP_NTH
       
  9877             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
       
  9878 #endif
       
  9879         last = NULL;
       
  9880             next = xmlXPathNextChild;
       
  9881             break;
       
  9882         case AXIS_DESCENDANT:
       
  9883 #ifdef DEBUG_STEP_NTH
       
  9884             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
       
  9885 #endif
       
  9886         last = NULL;
       
  9887             next = xmlXPathNextDescendant;
       
  9888             break;
       
  9889         case AXIS_DESCENDANT_OR_SELF:
       
  9890 #ifdef DEBUG_STEP_NTH
       
  9891             xmlGenericError(xmlGenericErrorContext,
       
  9892                             "axis 'descendant-or-self' ");
       
  9893 #endif
       
  9894         last = NULL;
       
  9895             next = xmlXPathNextDescendantOrSelf;
       
  9896             break;
       
  9897         case AXIS_FOLLOWING:
       
  9898 #ifdef DEBUG_STEP_NTH
       
  9899             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
       
  9900 #endif
       
  9901         last = NULL;
       
  9902             next = xmlXPathNextFollowing;
       
  9903             break;
       
  9904         case AXIS_FOLLOWING_SIBLING:
       
  9905 #ifdef DEBUG_STEP_NTH
       
  9906             xmlGenericError(xmlGenericErrorContext,
       
  9907                             "axis 'following-siblings' ");
       
  9908 #endif
       
  9909         last = NULL;
       
  9910             next = xmlXPathNextFollowingSibling;
       
  9911             break;
       
  9912         case AXIS_NAMESPACE:
       
  9913 #ifdef DEBUG_STEP_NTH
       
  9914             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
       
  9915 #endif
       
  9916         last = NULL;
       
  9917             first = NULL;
       
  9918             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
       
  9919             break;
       
  9920         case AXIS_PARENT:
       
  9921 #ifdef DEBUG_STEP_NTH
       
  9922             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
       
  9923 #endif
       
  9924             first = NULL;
       
  9925             next = xmlXPathNextParent;
       
  9926             break;
       
  9927         case AXIS_PRECEDING:
       
  9928 #ifdef DEBUG_STEP_NTH
       
  9929             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
       
  9930 #endif
       
  9931             first = NULL;
       
  9932             next = xmlXPathNextPrecedingInternal;
       
  9933             break;
       
  9934         case AXIS_PRECEDING_SIBLING:
       
  9935 #ifdef DEBUG_STEP_NTH
       
  9936             xmlGenericError(xmlGenericErrorContext,
       
  9937                             "axis 'preceding-sibling' ");
       
  9938 #endif
       
  9939             first = NULL;
       
  9940             next = xmlXPathNextPrecedingSibling;
       
  9941             break;
       
  9942         case AXIS_SELF:
       
  9943 #ifdef DEBUG_STEP_NTH
       
  9944             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
       
  9945 #endif
       
  9946             first = NULL;
       
  9947         last = NULL;
       
  9948             next = xmlXPathNextSelf;
       
  9949             break;
       
  9950     }
       
  9951     if (next == NULL)
       
  9952         return(0);
       
  9953 
       
  9954     nodelist = obj->nodesetval;
       
  9955     if (nodelist == NULL) {
       
  9956         xmlXPathFreeObject(obj);
       
  9957         valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
       
  9958         return(0);
       
  9959     }
       
  9960     addNode = xmlXPathNodeSetAddUnique;
       
  9961 #ifdef DEBUG_STEP_NTH
       
  9962     xmlGenericError(xmlGenericErrorContext,
       
  9963                     " context contains %d nodes\n", nodelist->nodeNr);
       
  9964     switch (test) {
       
  9965         case NODE_TEST_NONE:
       
  9966             xmlGenericError(xmlGenericErrorContext,
       
  9967                             "           searching for none !!!\n");
       
  9968             break;
       
  9969         case NODE_TEST_TYPE:
       
  9970             xmlGenericError(xmlGenericErrorContext,
       
  9971                             "           searching for type %d\n", type);
       
  9972             break;
       
  9973         case NODE_TEST_PI:
       
  9974             xmlGenericError(xmlGenericErrorContext,
       
  9975                             "           searching for PI !!!\n");
       
  9976             break;
       
  9977         case NODE_TEST_ALL:
       
  9978             xmlGenericError(xmlGenericErrorContext,
       
  9979                             "           searching for *\n");
       
  9980             break;
       
  9981         case NODE_TEST_NS:
       
  9982             xmlGenericError(xmlGenericErrorContext,
       
  9983                             "           searching for namespace %s\n",
       
  9984                             prefix);
       
  9985             break;
       
  9986         case NODE_TEST_NAME:
       
  9987             xmlGenericError(xmlGenericErrorContext,
       
  9988                             "           searching for name %s\n", name);
       
  9989             if (prefix != NULL)
       
  9990                 xmlGenericError(xmlGenericErrorContext,
       
  9991                                 "           with namespace %s\n", prefix);
       
  9992             break;
       
  9993     }
       
  9994     xmlGenericError(xmlGenericErrorContext, "Testing : ");
       
  9995 #endif
       
  9996     /*
       
  9997      * 2.3 Node Tests
       
  9998      *  - For the attribute axis, the principal node type is attribute.
       
  9999      *  - For the namespace axis, the principal node type is namespace.
       
 10000      *  - For other axes, the principal node type is element.
       
 10001      *
       
 10002      * A node test * is true for any node of the
       
 10003      * principal node type. For example, child::* will
       
 10004      * select all element children of the context node
       
 10005      */
       
 10006     tmp = ctxt->context->node;
       
 10007     list = xmlXPathNodeSetCreate(NULL);
       
 10008     if(OOM_FLAG)
       
 10009     	{
       
 10010     	xmlXPathFreeObject(obj);
       
 10011     	return(-1);
       
 10012     	}
       
 10013     for (i = 0; i < nodelist->nodeNr; i++) {
       
 10014         ctxt->context->node = nodelist->nodeTab[i];
       
 10015 
       
 10016         cur = NULL;
       
 10017         n = 0;
       
 10018         do {
       
 10019             cur = next(ctxt, cur);
       
 10020             if (cur == NULL)
       
 10021                 break;
       
 10022         if ((first != NULL) && (*first == cur))
       
 10023         break;
       
 10024         if (((t % 256) == 0) &&
       
 10025             (first != NULL) && (*first != NULL) &&
       
 10026         (xmlXPathCmpNodes(*first, cur) >= 0))
       
 10027         break;
       
 10028         if ((last != NULL) && (*last == cur))
       
 10029         break;
       
 10030         if (((t % 256) == 0) &&
       
 10031             (last != NULL) && (*last != NULL) &&
       
 10032         (xmlXPathCmpNodes(cur, *last) >= 0))
       
 10033         break;
       
 10034             t++;
       
 10035             switch (test) {
       
 10036                 case NODE_TEST_NONE:
       
 10037                     ctxt->context->node = tmp;
       
 10038                     STRANGE return(0);
       
 10039                 case NODE_TEST_TYPE:
       
 10040                     if ((cur->type == type) ||
       
 10041                         ((type == NODE_TYPE_NODE) &&
       
 10042                          ((cur->type == XML_DOCUMENT_NODE) ||
       
 10043                           (cur->type == XML_HTML_DOCUMENT_NODE) ||
       
 10044                           (cur->type == XML_ELEMENT_NODE) ||
       
 10045                           (cur->type == XML_PI_NODE) ||
       
 10046                           (cur->type == XML_COMMENT_NODE) ||
       
 10047                           (cur->type == XML_CDATA_SECTION_NODE) ||
       
 10048                           (cur->type == XML_TEXT_NODE))) ||
       
 10049             ((type == NODE_TYPE_TEXT) &&
       
 10050              (cur->type == XML_CDATA_SECTION_NODE))) {
       
 10051                         n++;
       
 10052                         if (n == indx)
       
 10053                             addNode(list, cur);
       
 10054                     }
       
 10055                     break;
       
 10056                 case NODE_TEST_PI:
       
 10057                     if (cur->type == XML_PI_NODE) {
       
 10058                         if ((name != NULL) &&
       
 10059                             (!xmlStrEqual(name, cur->name)))
       
 10060                             break;
       
 10061                         n++;
       
 10062                         if (n == indx)
       
 10063                             addNode(list, cur);
       
 10064                     }
       
 10065                     break;
       
 10066                 case NODE_TEST_ALL:
       
 10067                     if (axis == AXIS_ATTRIBUTE) {
       
 10068                         if (cur->type == XML_ATTRIBUTE_NODE) {
       
 10069                             n++;
       
 10070                             if (n == indx)
       
 10071                                 addNode(list, cur);
       
 10072                         }
       
 10073                     } else if (axis == AXIS_NAMESPACE) {
       
 10074                         if (cur->type == XML_NAMESPACE_DECL) {
       
 10075                             n++;
       
 10076                             if (n == indx)
       
 10077                 xmlXPathNodeSetAddNs(list, ctxt->context->node,
       
 10078                              (xmlNsPtr) cur);
       
 10079                         }
       
 10080                     } else {
       
 10081                         if (cur->type == XML_ELEMENT_NODE) {
       
 10082                             if (prefix == NULL) {
       
 10083                                 n++;
       
 10084                                 if (n == indx)
       
 10085                                     addNode(list, cur);
       
 10086                             } else if ((cur->ns != NULL) &&
       
 10087                                        (xmlStrEqual(URI, cur->ns->href))) {
       
 10088                                 n++;
       
 10089                                 if (n == indx)
       
 10090                                     addNode(list, cur);
       
 10091                             }
       
 10092                         }
       
 10093                     }
       
 10094                     break;
       
 10095                 case NODE_TEST_NS:{
       
 10096                         TODO;
       
 10097                         break;
       
 10098                     }
       
 10099                 case NODE_TEST_NAME:
       
 10100                     switch (cur->type) {
       
 10101                         case XML_ELEMENT_NODE:
       
 10102                             if (xmlStrEqual(name, cur->name)) {
       
 10103                                 if (prefix == NULL) {
       
 10104                                     if (cur->ns == NULL) {
       
 10105                                         n++;
       
 10106                                         if (n == indx)
       
 10107                                         	{
       
 10108                                         	addNode(list, cur);
       
 10109                                         	if(OOM_FLAG)
       
 10110 							   {
       
 10111 							   xmlXPathFreeObject(obj);
       
 10112 							   xmlXPathFreeNodeSet(list);
       
 10113 							   return(-1);
       
 10114 							   }
       
 10115                                         	}
       
 10116                                             
       
 10117                                     }
       
 10118                                 } else {
       
 10119                                     if ((cur->ns != NULL) &&
       
 10120                                         (xmlStrEqual(URI,
       
 10121                                                      cur->ns->href))) {
       
 10122                                         n++;
       
 10123                                         if (n == indx)
       
 10124                                             addNode(list, cur);
       
 10125                                     }
       
 10126                                 }
       
 10127                             }
       
 10128                             break;
       
 10129                         case XML_ATTRIBUTE_NODE:{
       
 10130                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
       
 10131 
       
 10132                                 if (xmlStrEqual(name, attr->name)) {
       
 10133                                     if (prefix == NULL) {
       
 10134                                         if ((attr->ns == NULL) ||
       
 10135                                             (attr->ns->prefix == NULL)) {
       
 10136                                             n++;
       
 10137                                             if (n == indx)
       
 10138                                                 addNode(list, cur);
       
 10139                                         }
       
 10140                                     } else {
       
 10141                                         if ((attr->ns != NULL) &&
       
 10142                                             (xmlStrEqual(URI,
       
 10143                                                          attr->ns->
       
 10144                                                          href))) {
       
 10145                                             n++;
       
 10146                                             if (n == indx)
       
 10147                                                 addNode(list, cur);
       
 10148                                         }
       
 10149                                     }
       
 10150                                 }
       
 10151                                 break;
       
 10152                             }
       
 10153                         case XML_NAMESPACE_DECL:
       
 10154                             if (cur->type == XML_NAMESPACE_DECL) {
       
 10155                                 xmlNsPtr ns = (xmlNsPtr) cur;
       
 10156 
       
 10157                                 if ((ns->prefix != NULL) && (name != NULL)
       
 10158                                     && (xmlStrEqual(ns->prefix, name))) {
       
 10159                                     n++;
       
 10160                                     if (n == indx)
       
 10161                     xmlXPathNodeSetAddNs(list,
       
 10162                        ctxt->context->node, (xmlNsPtr) cur);
       
 10163                                 }
       
 10164                             }
       
 10165                             break;
       
 10166                         default:
       
 10167                             break;
       
 10168                     }
       
 10169                     break;
       
 10170                     break;
       
 10171             }
       
 10172         } while (n < indx);
       
 10173     }
       
 10174     ctxt->context->node = tmp;
       
 10175 #ifdef DEBUG_STEP_NTH
       
 10176     xmlGenericError(xmlGenericErrorContext,
       
 10177                     "\nExamined %d nodes, found %d nodes at that step\n",
       
 10178                     t, list->nodeNr);
       
 10179 #endif
       
 10180     valuePush(ctxt, xmlXPathWrapNodeSet(list));
       
 10181     if(OOM_FLAG)
       
 10182     	{
       
 10183     	xmlXPathFreeObject(obj);
       
 10184    	xmlXPathFreeNodeSet(list);
       
 10185     	return(-1);
       
 10186     	}    
       
 10187     if ((obj->boolval) && (obj->user != NULL)) {
       
 10188     ctxt->value->boolval = 1;
       
 10189     ctxt->value->user = obj->user;
       
 10190     obj->user = NULL;
       
 10191     obj->boolval = 0;
       
 10192     }
       
 10193     xmlXPathFreeObject(obj);
       
 10194     return(t);
       
 10195 }
       
 10196 
       
 10197 /**
       
 10198  * xmlXPathCompOpEvalFirst:
       
 10199  * @ctxt:  the XPath parser context with the compiled expression
       
 10200  * @op:  an XPath compiled operation
       
 10201  * @first:  the first elem found so far
       
 10202  *
       
 10203  * Evaluate the Precompiled XPath operation searching only the first
       
 10204  * element in document order
       
 10205  *
       
 10206  * Returns the number of examined objects.
       
 10207  */
       
 10208 static int
       
 10209 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
       
 10210                         xmlXPathStepOpPtr op, xmlNodePtr * first)
       
 10211 {
       
 10212     int total = 0, cur;
       
 10213     xmlXPathCompExprPtr comp;
       
 10214     xmlXPathObjectPtr arg1, arg2;
       
 10215 
       
 10216     CHECK_ERROR0;
       
 10217     comp = ctxt->comp;
       
 10218     switch (op->op) {
       
 10219         case XPATH_OP_END:
       
 10220             return (0);
       
 10221         case XPATH_OP_UNION:
       
 10222             total =
       
 10223                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
       
 10224                                         first);
       
 10225         CHECK_ERROR0;
       
 10226             if ((ctxt->value != NULL)
       
 10227                 && (ctxt->value->type == XPATH_NODESET)
       
 10228                 && (ctxt->value->nodesetval != NULL)
       
 10229                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
       
 10230                 /*
       
 10231                  * limit tree traversing to first node in the result
       
 10232                  */
       
 10233                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
       
 10234                 *first = ctxt->value->nodesetval->nodeTab[0];
       
 10235             }
       
 10236             cur =
       
 10237                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
       
 10238                                         first);
       
 10239         CHECK_ERROR0;
       
 10240             CHECK_TYPE0(XPATH_NODESET);
       
 10241             arg2 = valuePop(ctxt);
       
 10242 
       
 10243             CHECK_TYPE0(XPATH_NODESET);
       
 10244             arg1 = valuePop(ctxt);
       
 10245 
       
 10246             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
       
 10247                                                     arg2->nodesetval);
       
 10248             valuePush(ctxt, arg1);
       
 10249             xmlXPathFreeObject(arg2);
       
 10250             /* optimizer */
       
 10251         if (total > cur)
       
 10252         xmlXPathCompSwap(op);
       
 10253             return (total + cur);
       
 10254         case XPATH_OP_ROOT:
       
 10255             xmlXPathRoot(ctxt);
       
 10256             return (0);
       
 10257         case XPATH_OP_NODE:
       
 10258             if (op->ch1 != -1)
       
 10259                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10260         CHECK_ERROR0;
       
 10261             if (op->ch2 != -1)
       
 10262                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10263         CHECK_ERROR0;
       
 10264             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
 10265             return (total);
       
 10266         case XPATH_OP_RESET:
       
 10267             if (op->ch1 != -1)
       
 10268                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10269         CHECK_ERROR0;
       
 10270             if (op->ch2 != -1)
       
 10271                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10272         CHECK_ERROR0;
       
 10273             ctxt->context->node = NULL;
       
 10274             return (total);
       
 10275         case XPATH_OP_COLLECT:{
       
 10276                 if (op->ch1 == -1)
       
 10277                     return (total);
       
 10278 
       
 10279                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10280         CHECK_ERROR0;
       
 10281 
       
 10282                 /*
       
 10283                  * Optimization for [n] selection where n is a number
       
 10284                  */
       
 10285                 if ((op->ch2 != -1) &&
       
 10286                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
       
 10287                     (comp->steps[op->ch2].ch1 == -1) &&
       
 10288                     (comp->steps[op->ch2].ch2 != -1) &&
       
 10289                     (comp->steps[comp->steps[op->ch2].ch2].op ==
       
 10290                      XPATH_OP_VALUE)) {
       
 10291                     xmlXPathObjectPtr val;
       
 10292 
       
 10293                     val = (xmlXPathObjectPtr)comp->steps[comp->steps[op->ch2].ch2].value4;
       
 10294                     if ((val != NULL) && (val->type == XPATH_NUMBER)) {
       
 10295                         int indx = (int) val->floatval;
       
 10296 
       
 10297                         if (val->floatval == (float) indx) {
       
 10298                             xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
       
 10299                                                           first, NULL);
       
 10300                             return (total);
       
 10301                         }
       
 10302                     }
       
 10303                 }
       
 10304                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
       
 10305                 return (total);
       
 10306             }
       
 10307         case XPATH_OP_VALUE:
       
 10308             valuePush(ctxt, xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
       
 10309             return (0);
       
 10310 
       
 10311         case XPATH_OP_SORT:
       
 10312             if (op->ch1 != -1)
       
 10313                 total += xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], first);
       
 10314             CHECK_ERROR0;
       
 10315             if ((ctxt->value != NULL)
       
 10316                 && (ctxt->value->type == XPATH_NODESET)
       
 10317                 && (ctxt->value->nodesetval != NULL))
       
 10318             {
       
 10319                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
       
 10320             }
       
 10321             return (total);
       
 10322 
       
 10323         default:
       
 10324             return (xmlXPathCompOpEval(ctxt, op));
       
 10325     }
       
 10326 }
       
 10327 
       
 10328 /**
       
 10329  * xmlXPathCompOpEvalLast:
       
 10330  * @ctxt:  the XPath parser context with the compiled expression
       
 10331  * @op:  an XPath compiled operation
       
 10332  * @last:  the last elem found so far
       
 10333  *
       
 10334  * Evaluate the Precompiled XPath operation searching only the last
       
 10335  * element in document order
       
 10336  *
       
 10337  * Returns the number of nodes traversed
       
 10338  */
       
 10339 static int
       
 10340 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
       
 10341                        xmlNodePtr * last)
       
 10342 {
       
 10343     int total = 0, cur;
       
 10344     xmlXPathCompExprPtr comp;
       
 10345     xmlXPathObjectPtr arg1, arg2;
       
 10346     xmlNodePtr bak;
       
 10347     xmlDocPtr bakd;
       
 10348     int pp;
       
 10349     int cs;
       
 10350 
       
 10351     CHECK_ERROR0;
       
 10352     comp = ctxt->comp;
       
 10353     switch (op->op) {
       
 10354         case XPATH_OP_END:
       
 10355             return (0);
       
 10356         case XPATH_OP_UNION:
       
 10357         bakd = ctxt->context->doc;
       
 10358         bak = ctxt->context->node;
       
 10359         pp = ctxt->context->proximityPosition;
       
 10360         cs = ctxt->context->contextSize;
       
 10361             total =
       
 10362                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
       
 10363         CHECK_ERROR0;
       
 10364             if ((ctxt->value != NULL)
       
 10365                 && (ctxt->value->type == XPATH_NODESET)
       
 10366                 && (ctxt->value->nodesetval != NULL)
       
 10367                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
       
 10368                 /*
       
 10369                  * limit tree traversing to first node in the result
       
 10370                  */
       
 10371                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
       
 10372                 *last =
       
 10373                     ctxt->value->nodesetval->nodeTab[ctxt->value->
       
 10374                                                      nodesetval->nodeNr -
       
 10375                                                      1];
       
 10376             }
       
 10377         ctxt->context->doc = bakd;
       
 10378         ctxt->context->node = bak;
       
 10379         ctxt->context->proximityPosition = pp;
       
 10380         ctxt->context->contextSize = cs;
       
 10381             cur =
       
 10382                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
       
 10383         CHECK_ERROR0;
       
 10384             if ((ctxt->value != NULL)
       
 10385                 && (ctxt->value->type == XPATH_NODESET)
       
 10386                 && (ctxt->value->nodesetval != NULL)
       
 10387                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
       
 10388             }
       
 10389             CHECK_TYPE0(XPATH_NODESET);
       
 10390             arg2 = valuePop(ctxt);
       
 10391 
       
 10392             CHECK_TYPE0(XPATH_NODESET);
       
 10393             arg1 = valuePop(ctxt);
       
 10394 
       
 10395             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
       
 10396                                                     arg2->nodesetval);
       
 10397             valuePush(ctxt, arg1);
       
 10398             xmlXPathFreeObject(arg2);
       
 10399             /* optimizer */
       
 10400         if (total > cur)
       
 10401         xmlXPathCompSwap(op);
       
 10402             return (total + cur);
       
 10403         case XPATH_OP_ROOT:
       
 10404             xmlXPathRoot(ctxt);
       
 10405             return (0);
       
 10406         case XPATH_OP_NODE:
       
 10407             if (op->ch1 != -1)
       
 10408                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10409         CHECK_ERROR0;
       
 10410             if (op->ch2 != -1)
       
 10411                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10412         CHECK_ERROR0;
       
 10413             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
 10414             return (total);
       
 10415         case XPATH_OP_RESET:
       
 10416             if (op->ch1 != -1)
       
 10417                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10418         CHECK_ERROR0;
       
 10419             if (op->ch2 != -1)
       
 10420                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10421         CHECK_ERROR0;
       
 10422             ctxt->context->node = NULL;
       
 10423             return (total);
       
 10424         case XPATH_OP_COLLECT:{
       
 10425                 if (op->ch1 == -1)
       
 10426                     return (0);
       
 10427 
       
 10428                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10429         CHECK_ERROR0;
       
 10430 
       
 10431                 /*
       
 10432                  * Optimization for [n] selection where n is a number
       
 10433                  */
       
 10434                 if ((op->ch2 != -1) &&
       
 10435                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
       
 10436                     (comp->steps[op->ch2].ch1 == -1) &&
       
 10437                     (comp->steps[op->ch2].ch2 != -1) &&
       
 10438                     (comp->steps[comp->steps[op->ch2].ch2].op ==
       
 10439                      XPATH_OP_VALUE)) {
       
 10440                     xmlXPathObjectPtr val;
       
 10441 
       
 10442                     val = (xmlXPathObjectPtr)comp->steps[comp->steps[op->ch2].ch2].value4;
       
 10443                     if ((val != NULL) && (val->type == XPATH_NUMBER)) {
       
 10444                         int indx = (int) val->floatval;
       
 10445 
       
 10446                         if (val->floatval == (float) indx) {
       
 10447                             total += xmlXPathNodeCollectAndTestNth(ctxt, op, indx, NULL, last);
       
 10448                             return (total);
       
 10449                         }
       
 10450                     }
       
 10451                 }
       
 10452                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
       
 10453                 return (total);
       
 10454             }
       
 10455         case XPATH_OP_VALUE:
       
 10456             valuePush(ctxt, xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
       
 10457             return (0);
       
 10458 
       
 10459         case XPATH_OP_SORT:
       
 10460             if (op->ch1 != -1)
       
 10461                 total += xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
       
 10462             CHECK_ERROR0;
       
 10463             if ((ctxt->value != NULL)
       
 10464                 && (ctxt->value->type == XPATH_NODESET)
       
 10465                 && (ctxt->value->nodesetval != NULL))
       
 10466                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
       
 10467             {
       
 10468                 return (total);
       
 10469             }
       
 10470 
       
 10471         default:
       
 10472             return (xmlXPathCompOpEval(ctxt, op));
       
 10473     }
       
 10474 }
       
 10475 
       
 10476 /**
       
 10477  * xmlXPathCompOpEval:
       
 10478  * @ctxt:  the XPath parser context with the compiled expression
       
 10479  * @op:  an XPath compiled operation
       
 10480  *
       
 10481  * Evaluate the Precompiled XPath operation
       
 10482  * Returns the number of nodes traversed or -1 when OOM
       
 10483  */
       
 10484 static int
       
 10485 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
       
 10486 {
       
 10487     int total = 0;
       
 10488     int equal, ret;
       
 10489     xmlXPathCompExprPtr comp;
       
 10490     xmlXPathObjectPtr arg1, arg2;
       
 10491     xmlNodePtr bak;
       
 10492     xmlDocPtr bakd;
       
 10493     int pp;
       
 10494     int cs;
       
 10495 
       
 10496     CHECK_ERROR0;
       
 10497 
       
 10498     comp = ctxt->comp;
       
 10499     //TODO: OPTIMIZE: xmlXPathContextPtr xpctxt = ctxt->context; // and reuse it below
       
 10500     switch (op->op)
       
 10501     {
       
 10502     case XPATH_OP_END:  return (0);
       
 10503     case XPATH_OP_AND:      {
       
 10504         bakd = ctxt->context->doc;
       
 10505         bak = ctxt->context->node;
       
 10506         pp = ctxt->context->proximityPosition;
       
 10507         cs = ctxt->context->contextSize;
       
 10508         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10509         CHECK_ERROR0;
       
 10510 
       
 10511 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10512         addNodeSetsFromStackToDependencyList(ctxt, 1);
       
 10513 #endif
       
 10514 
       
 10515         xmlXPathBooleanFunction(ctxt, 1);
       
 10516         if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
       
 10517             return (total);
       
 10518         arg2 = valuePop(ctxt);
       
 10519         ctxt->context->doc = bakd;
       
 10520         ctxt->context->node = bak;
       
 10521         ctxt->context->proximityPosition = pp;
       
 10522         ctxt->context->contextSize = cs;
       
 10523         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10524         if (ctxt->error) {
       
 10525             xmlXPathFreeObject(arg2);
       
 10526             return(0);
       
 10527         }
       
 10528 
       
 10529 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10530         addNodeSetsFromStackToDependencyList(ctxt, 1);
       
 10531 #endif
       
 10532         xmlXPathBooleanFunction(ctxt, 1);
       
 10533         arg1 = valuePop(ctxt);
       
 10534         arg1->boolval &= arg2->boolval;
       
 10535         valuePush(ctxt, arg1);
       
 10536         xmlXPathFreeObject(arg2);
       
 10537         return (total);
       
 10538     }
       
 10539 
       
 10540     case XPATH_OP_OR:       {
       
 10541         bakd = ctxt->context->doc;
       
 10542         bak = ctxt->context->node;
       
 10543         pp = ctxt->context->proximityPosition;
       
 10544         cs = ctxt->context->contextSize;
       
 10545         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10546         CHECK_ERROR0;
       
 10547 
       
 10548 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10549         addNodeSetsFromStackToDependencyList(ctxt, 1);
       
 10550 #endif
       
 10551         xmlXPathBooleanFunction(ctxt, 1);
       
 10552 /*
       
 10553 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10554         // in dependency evaluation mode we must always process both parts
       
 10555         // of OR operation in the XPath expression
       
 10556         if  (!ctxt->context->dependencyList && (ctxt->value || (ctxt->value->boolval == 1)))
       
 10557             return (total);
       
 10558 #else
       
 10559 */
       
 10560             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
       
 10561             return (total);
       
 10562 /*
       
 10563  #endif
       
 10564  */
       
 10565         arg2 = valuePop(ctxt);
       
 10566         ctxt->context->doc = bakd;
       
 10567         ctxt->context->node = bak;
       
 10568         ctxt->context->proximityPosition = pp;
       
 10569         ctxt->context->contextSize = cs;
       
 10570         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10571 
       
 10572         if (ctxt->error) {
       
 10573             xmlXPathFreeObject(arg2);
       
 10574             return(0);
       
 10575         }
       
 10576 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10577         addNodeSetsFromStackToDependencyList(ctxt, 1);
       
 10578 #endif
       
 10579         xmlXPathBooleanFunction(ctxt, 1);
       
 10580         arg1 = valuePop(ctxt);
       
 10581         arg1->boolval |= arg2->boolval;
       
 10582         valuePush(ctxt, arg1);
       
 10583         xmlXPathFreeObject(arg2);
       
 10584         return (total);
       
 10585     }
       
 10586 
       
 10587     case XPATH_OP_EQUAL:    {
       
 10588         bakd = ctxt->context->doc;
       
 10589         bak = ctxt->context->node;
       
 10590         pp = ctxt->context->proximityPosition;
       
 10591         cs = ctxt->context->contextSize;
       
 10592         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10593         CHECK_ERROR0;
       
 10594 
       
 10595         ctxt->context->doc = bakd;
       
 10596         ctxt->context->node = bak;
       
 10597         ctxt->context->proximityPosition = pp;
       
 10598         ctxt->context->contextSize = cs;
       
 10599         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10600         CHECK_ERROR0;
       
 10601 
       
 10602 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10603         addNodeSetsFromStackToDependencyList(ctxt, 2);
       
 10604 #endif
       
 10605 
       
 10606         if (op->value)
       
 10607             equal = xmlXPathEqualValues(ctxt);
       
 10608         else
       
 10609             equal = xmlXPathNotEqualValues(ctxt);
       
 10610 
       
 10611         valuePush(ctxt, xmlXPathNewBoolean(equal));
       
 10612         return (total);
       
 10613     }
       
 10614 
       
 10615     case XPATH_OP_CMP:      {
       
 10616         bakd = ctxt->context->doc;
       
 10617         bak = ctxt->context->node;
       
 10618         pp = ctxt->context->proximityPosition;
       
 10619         cs = ctxt->context->contextSize;
       
 10620         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10621         CHECK_ERROR0;
       
 10622 
       
 10623         ctxt->context->doc = bakd;
       
 10624         ctxt->context->node = bak;
       
 10625         ctxt->context->proximityPosition = pp;
       
 10626         ctxt->context->contextSize = cs;
       
 10627         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10628         CHECK_ERROR0;
       
 10629 
       
 10630 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10631         addNodeSetsFromStackToDependencyList(ctxt, 2);
       
 10632 #endif
       
 10633         ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
       
 10634         valuePush(ctxt, xmlXPathNewBoolean(ret));
       
 10635         return (total);
       
 10636     }
       
 10637 
       
 10638     case XPATH_OP_PLUS:     {
       
 10639         bakd = ctxt->context->doc;
       
 10640         bak = ctxt->context->node;
       
 10641         pp = ctxt->context->proximityPosition;
       
 10642         cs = ctxt->context->contextSize;
       
 10643         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10644         CHECK_ERROR0;
       
 10645 
       
 10646         if (op->ch2 != -1) {
       
 10647             ctxt->context->doc = bakd;
       
 10648             ctxt->context->node = bak;
       
 10649             ctxt->context->proximityPosition = pp;
       
 10650             ctxt->context->contextSize = cs;
       
 10651             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10652         }
       
 10653         CHECK_ERROR0;
       
 10654 
       
 10655 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10656         // TODO: OPTIMIZATION: Can we use (op->value!=2) here? / Is reordering required?
       
 10657         if (op->value == 0 || op->value == 1)
       
 10658             addNodeSetsFromStackToDependencyList(ctxt, 2);
       
 10659         else if (op->value == 2)
       
 10660             addNodeSetsFromStackToDependencyList(ctxt, 1);
       
 10661 #endif
       
 10662         // TODO: OPTIMIZATION: Reordering accordig to value type frequency
       
 10663         if (op->value == 0)
       
 10664             xmlXPathSubValues(ctxt);
       
 10665         else if (op->value == 1)
       
 10666             xmlXPathAddValues(ctxt);
       
 10667         else if (op->value == 2)
       
 10668             xmlXPathValueFlipSign(ctxt);
       
 10669         else if (op->value == 3) {
       
 10670             CAST_TO_NUMBER;
       
 10671             CHECK_TYPE0(XPATH_NUMBER);
       
 10672         }
       
 10673         return (total);
       
 10674     }
       
 10675 
       
 10676     case XPATH_OP_MULT:     {
       
 10677         bakd = ctxt->context->doc;
       
 10678         bak = ctxt->context->node;
       
 10679         pp = ctxt->context->proximityPosition;
       
 10680         cs = ctxt->context->contextSize;
       
 10681         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10682         CHECK_ERROR0;
       
 10683 
       
 10684         ctxt->context->doc = bakd;
       
 10685         ctxt->context->node = bak;
       
 10686         ctxt->context->proximityPosition = pp;
       
 10687         ctxt->context->contextSize = cs;
       
 10688         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10689         CHECK_ERROR0;
       
 10690 
       
 10691 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10692         addNodeSetsFromStackToDependencyList(ctxt, 2);
       
 10693 #endif
       
 10694 
       
 10695         if (op->value == 0)
       
 10696             xmlXPathMultValues(ctxt);
       
 10697         else if (op->value == 1)
       
 10698             xmlXPathDivValues(ctxt);
       
 10699         else if (op->value == 2)
       
 10700             xmlXPathModValues(ctxt);
       
 10701         return (total);
       
 10702     }
       
 10703 
       
 10704     case XPATH_OP_UNION:    {
       
 10705         bakd = ctxt->context->doc;
       
 10706         bak = ctxt->context->node;
       
 10707         pp = ctxt->context->proximityPosition;
       
 10708         cs = ctxt->context->contextSize;
       
 10709         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10710         CHECK_ERROR0;
       
 10711 
       
 10712         ctxt->context->doc = bakd;
       
 10713         ctxt->context->node = bak;
       
 10714         ctxt->context->proximityPosition = pp;
       
 10715         ctxt->context->contextSize = cs;
       
 10716         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10717         CHECK_ERROR0;
       
 10718 
       
 10719         CHECK_TYPE0(XPATH_NODESET);
       
 10720         arg2 = valuePop(ctxt);
       
 10721 
       
 10722         CHECK_TYPE0(XPATH_NODESET);
       
 10723         arg1 = valuePop(ctxt);
       
 10724 
       
 10725         arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, arg2->nodesetval);
       
 10726         valuePush(ctxt, arg1);
       
 10727         xmlXPathFreeObject(arg2);
       
 10728 
       
 10729         return (total);
       
 10730     }
       
 10731 
       
 10732     case XPATH_OP_ROOT:     {
       
 10733         xmlXPathRoot(ctxt);
       
 10734         return (total);
       
 10735     }
       
 10736 
       
 10737     case XPATH_OP_NODE:     {
       
 10738         if (op->ch1 != -1)
       
 10739             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10740         CHECK_ERROR0;
       
 10741 
       
 10742         if (op->ch2 != -1)
       
 10743             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10744         CHECK_ERROR0;
       
 10745 
       
 10746         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
       
 10747         if(OOM_FLAG) return(-1);
       
 10748         return (total);
       
 10749     }
       
 10750 
       
 10751     case XPATH_OP_RESET:    {
       
 10752         if (op->ch1 != -1)
       
 10753             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10754         CHECK_ERROR0;
       
 10755 
       
 10756         if (op->ch2 != -1)
       
 10757             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10758         CHECK_ERROR0;
       
 10759 
       
 10760         ctxt->context->node = NULL;
       
 10761         return (total);
       
 10762     }
       
 10763 
       
 10764     case XPATH_OP_COLLECT:  {
       
 10765             if (op->ch1 == -1)
       
 10766                 return (total);
       
 10767 
       
 10768             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10769             if(OOM_FLAG) return(-1);
       
 10770             CHECK_ERROR0;
       
 10771 
       
 10772             /*
       
 10773             * Optimization for [n] selection where n is a number
       
 10774             */
       
 10775             if ((op->ch2 != -1) &&
       
 10776                 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
       
 10777                 (comp->steps[op->ch2].ch1 == -1) &&
       
 10778                 (comp->steps[op->ch2].ch2 != -1) &&
       
 10779                 (comp->steps[comp->steps[op->ch2].ch2].op == XPATH_OP_VALUE))
       
 10780             {
       
 10781                 xmlXPathObjectPtr val;
       
 10782 
       
 10783                 val = (xmlXPathObjectPtr)comp->steps[comp->steps[op->ch2].ch2].value4;
       
 10784                 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
       
 10785                     int indx = (int) val->floatval;
       
 10786 
       
 10787                     if (val->floatval == (float) indx) {
       
 10788                         total += xmlXPathNodeCollectAndTestNth(ctxt, op, indx, NULL, NULL);
       
 10789                         if(OOM_FLAG) return(-1);
       
 10790                         return (total);
       
 10791                     }
       
 10792                 }
       
 10793             }
       
 10794 
       
 10795             total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
       
 10796             if(OOM_FLAG) return(-1);
       
 10797             return (total);
       
 10798     }
       
 10799 
       
 10800     case XPATH_OP_VALUE:    {
       
 10801         valuePush(ctxt, xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
       
 10802         return (total);
       
 10803     }
       
 10804 
       
 10805     case XPATH_OP_VARIABLE: {
       
 10806         xmlXPathObjectPtr val;
       
 10807 
       
 10808         if (op->ch1 != -1)
       
 10809             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10810 
       
 10811         if (op->value5 == NULL) {
       
 10812             val = xmlXPathVariableLookup(ctxt->context, (xmlChar*) op->value4);
       
 10813             if (val == NULL) {
       
 10814                 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
       
 10815                 return(0);
       
 10816             }
       
 10817             valuePush(ctxt, val);
       
 10818         } else {
       
 10819             const xmlChar *URI;
       
 10820 
       
 10821             URI = xmlXPathNsLookup(ctxt->context, (xmlChar*) op->value5);
       
 10822             if (URI == NULL) {
       
 10823                 xmlGenericError(xmlGenericErrorContext,
       
 10824                     EMBED_ERRTXT("xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n"),
       
 10825                     op->value4, op->value5);
       
 10826                 return (total);
       
 10827             }
       
 10828             val = xmlXPathVariableLookupNS(ctxt->context, (xmlChar*) op->value4, URI);
       
 10829             if (val == NULL) {
       
 10830                 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
       
 10831                 return(0);
       
 10832             }
       
 10833             valuePush(ctxt, val);
       
 10834         }
       
 10835         return (total);
       
 10836     }
       
 10837 
       
 10838     case XPATH_OP_FUNCTION: {
       
 10839         xmlXPathFunction func;
       
 10840         const xmlChar *oldFunc, *oldFuncURI;
       
 10841         int i;
       
 10842 
       
 10843         if (op->ch1 != -1)
       
 10844         	{
       
 10845         	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10846         	if(OOM_FLAG) return(-1);
       
 10847         	}
       
 10848 
       
 10849         if (ctxt->valueNr < op->value) {
       
 10850             xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("xmlXPathCompOpEval: parameter error\n"));
       
 10851             ctxt->error = XPATH_INVALID_OPERAND;
       
 10852             return (total);
       
 10853         }
       
 10854 
       
 10855         for (i = 0; i < op->value; i++)
       
 10856             if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
       
 10857                 xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("xmlXPathCompOpEval: parameter error\n"));
       
 10858                 ctxt->error = XPATH_INVALID_OPERAND;
       
 10859                 return (total);
       
 10860             }
       
 10861 
       
 10862         if (op->cache != NULL){
       
 10863             func = (xmlXPathFunction)op->cache;//(REINTERPRET_CAST(xmlXPathFunction,(op->cache)));
       
 10864         }else {
       
 10865             const xmlChar *URI = NULL;
       
 10866 
       
 10867             if (op->value5 == NULL)
       
 10868                 func = xmlXPathFunctionLookup(ctxt->context, (xmlChar*)op->value4);
       
 10869             else {
       
 10870                 URI = xmlXPathNsLookup(ctxt->context, (xmlChar*) op->value5);
       
 10871                 if (URI == NULL) {
       
 10872                     xmlGenericError(xmlGenericErrorContext,
       
 10873                         EMBED_ERRTXT("xmlXPathCompOpEval: function %s bound to undefined prefix %s\n"),
       
 10874                         op->value4, op->value5);
       
 10875                     return (total);
       
 10876                 }
       
 10877                 func = xmlXPathFunctionLookupNS(ctxt->context, (xmlChar*)op->value4, URI);
       
 10878             }
       
 10879 
       
 10880             if (func == NULL) {
       
 10881                 xmlGenericError(xmlGenericErrorContext,
       
 10882                     EMBED_ERRTXT("xmlXPathCompOpEval: function %s not found\n"), op->value4);
       
 10883                 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
       
 10884             }
       
 10885 
       
 10886             op->cache =  (void *) func;
       
 10887             op->cacheURI = (void *) URI;
       
 10888         } // if (op->cache != NULL)
       
 10889 
       
 10890         oldFunc = ctxt->context->function;
       
 10891         oldFuncURI = ctxt->context->functionURI;
       
 10892         ctxt->context->function = (xmlChar*) op->value4;
       
 10893         ctxt->context->functionURI = (xmlChar*) op->cacheURI;
       
 10894 
       
 10895 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 10896         addNodeSetsFromStackToDependencyList(ctxt, op->value);
       
 10897 #endif
       
 10898         func(ctxt, op->value);
       
 10899         if(OOM_FLAG) return(-1);
       
 10900         ctxt->context->function = oldFunc;
       
 10901         ctxt->context->functionURI = oldFuncURI;
       
 10902         return (total);
       
 10903     }
       
 10904 
       
 10905     case XPATH_OP_ARG:      {
       
 10906         bakd = ctxt->context->doc;
       
 10907         bak = ctxt->context->node;
       
 10908         if (op->ch1 != -1)
       
 10909             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 10910         ctxt->context->doc = bakd;
       
 10911         ctxt->context->node = bak;
       
 10912         CHECK_ERROR0;
       
 10913 
       
 10914         if (op->ch2 != -1) {
       
 10915             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 10916         	if(OOM_FLAG) return(-1);
       
 10917             ctxt->context->doc = bakd;
       
 10918             ctxt->context->node = bak;
       
 10919             CHECK_ERROR0;
       
 10920         }
       
 10921         return (total);
       
 10922     }
       
 10923 
       
 10924     case XPATH_OP_PREDICATE:
       
 10925     case XPATH_OP_FILTER:   {
       
 10926         xmlXPathObjectPtr res;
       
 10927         xmlXPathObjectPtr obj, tmp;
       
 10928         xmlNodeSetPtr newset = NULL;
       
 10929         xmlNodeSetPtr oldset;
       
 10930         xmlNodePtr oldnode;
       
 10931         int i;
       
 10932 
       
 10933         /*
       
 10934         * Optimization for ()[1] selection i.e. the first elem
       
 10935         */
       
 10936         if ((op->ch1 != -1) && (op->ch2 != -1) &&
       
 10937             (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
       
 10938             (comp->steps[op->ch2].op == XPATH_OP_VALUE))
       
 10939         {
       
 10940                 xmlXPathObjectPtr val;
       
 10941 
       
 10942                 val = (xmlXPathObjectPtr)comp->steps[op->ch2].value4;
       
 10943 
       
 10944                 if ((val != NULL) && (val->type == XPATH_NUMBER) && (val->floatval == 1.0))
       
 10945                 {
       
 10946                     xmlNodePtr first = NULL;
       
 10947 
       
 10948                     total += xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], &first);
       
 10949                     CHECK_ERROR0;
       
 10950                     /*
       
 10951                     * The nodeset should be in document order,
       
 10952                     * Keep only the first value
       
 10953                     */
       
 10954                     if ((ctxt->value != NULL) &&
       
 10955                         (ctxt->value->type == XPATH_NODESET) &&
       
 10956                         (ctxt->value->nodesetval != NULL) &&
       
 10957                         (ctxt->value->nodesetval->nodeNr > 1))
       
 10958                     {
       
 10959                         ctxt->value->nodesetval->nodeNr = 1;
       
 10960                     }
       
 10961                     return (total);
       
 10962                 }
       
 10963         }
       
 10964 
       
 10965         /*
       
 10966          * Optimization for ()[last()] selection i.e. the last elem
       
 10967          */
       
 10968         if ((op->ch1 != -1) && (op->ch2 != -1) &&
       
 10969             (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
       
 10970             (comp->steps[op->ch2].op == XPATH_OP_SORT))
       
 10971         {
       
 10972             int f = comp->steps[op->ch2].ch1;
       
 10973 
       
 10974             if ((f != -1) &&
       
 10975                 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
       
 10976                 (comp->steps[f].value5 == NULL) &&
       
 10977                 (comp->steps[f].value == 0) &&
       
 10978                 (comp->steps[f].value4 != NULL) &&
       
 10979                 (xmlStrEqual((xmlChar*)comp->steps[f].value4, BAD_CAST "last")))
       
 10980             {
       
 10981                 xmlNodePtr last = NULL;
       
 10982 
       
 10983                 total += xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], &last);
       
 10984                 CHECK_ERROR0;
       
 10985                 /*
       
 10986                 * The nodeset should be in document order,
       
 10987                 * Keep only the last value
       
 10988                 */
       
 10989                 if ((ctxt->value != NULL) &&
       
 10990                     (ctxt->value->type == XPATH_NODESET) &&
       
 10991                     (ctxt->value->nodesetval != NULL) &&
       
 10992                     (ctxt->value->nodesetval->nodeTab != NULL) &&
       
 10993                     (ctxt->value->nodesetval->nodeNr > 1))
       
 10994                 {
       
 10995                     ctxt->value->nodesetval->nodeTab[0] =
       
 10996                         ctxt->value->nodesetval->nodeTab[ctxt->value->nodesetval->nodeNr - 1];
       
 10997                     ctxt->value->nodesetval->nodeNr = 1;
       
 10998                 }
       
 10999                 return (total);
       
 11000             }
       
 11001         }
       
 11002 
       
 11003 
       
 11004         if (op->ch1 != -1)
       
 11005             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 11006 
       
 11007         CHECK_ERROR0;
       
 11008 
       
 11009         if (op->ch2 == -1)
       
 11010             return (total);
       
 11011 
       
 11012         if (ctxt->value == NULL)
       
 11013             return (total);
       
 11014 
       
 11015         oldnode = ctxt->context->node;
       
 11016 
       
 11017 #ifdef LIBXML_XPTR_ENABLED
       
 11018         /*
       
 11019         * Hum are we filtering the result of an XPointer expression
       
 11020         */
       
 11021         if (ctxt->value->type == XPATH_LOCATIONSET)
       
 11022         {
       
 11023             xmlLocationSetPtr newlocset = NULL;
       
 11024             xmlLocationSetPtr oldlocset;
       
 11025 
       
 11026             /*
       
 11027             * Extract the old locset, and then evaluate the result of the
       
 11028             * expression for all the element in the locset. use it to grow
       
 11029             * up a new locset.
       
 11030             */
       
 11031             CHECK_TYPE0(XPATH_LOCATIONSET);
       
 11032 
       
 11033             obj = valuePop(ctxt);
       
 11034             oldlocset = obj->user;
       
 11035             ctxt->context->node = NULL;
       
 11036 
       
 11037             if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
       
 11038                 ctxt->context->contextSize = 0;
       
 11039                 ctxt->context->proximityPosition = 0;
       
 11040 
       
 11041                 if (op->ch2 != -1)
       
 11042                     total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11043 
       
 11044                 res = valuePop(ctxt);
       
 11045 
       
 11046                 if (res != NULL)
       
 11047                     xmlXPathFreeObject(res);
       
 11048 
       
 11049                 valuePush(ctxt, obj);
       
 11050                 CHECK_ERROR0;
       
 11051 
       
 11052                 return (total);
       
 11053             }
       
 11054 
       
 11055             newlocset = xmlXPtrLocationSetCreate(NULL);
       
 11056 
       
 11057             for (i = 0; i < oldlocset->locNr; i++)
       
 11058             {
       
 11059                 /*
       
 11060                 * Run the evaluation with a node list made of a
       
 11061                 * single item in the nodelocset.
       
 11062                 */
       
 11063                 ctxt->context->node = oldlocset->locTab[i]->user;
       
 11064                 ctxt->context->contextSize = oldlocset->locNr;
       
 11065                 ctxt->context->proximityPosition = i + 1;
       
 11066                 tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
 11067                 valuePush(ctxt, tmp);
       
 11068 
       
 11069                 if (op->ch2 != -1)
       
 11070                     total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11071 
       
 11072                 CHECK_ERROR0;
       
 11073                 /*
       
 11074                 * The result of the evaluation need to be tested to
       
 11075                 * decided whether the filter succeeded or not
       
 11076                 */
       
 11077                 res = valuePop(ctxt);
       
 11078                 if (xmlXPathEvaluatePredicateResult(ctxt, res))
       
 11079                 {
       
 11080                     xmlXPtrLocationSetAdd(newlocset, xmlXPathObjectCopy(oldlocset->locTab[i]));
       
 11081                 }
       
 11082 
       
 11083                 /*
       
 11084                 * Cleanup
       
 11085                 */
       
 11086                 if (res != NULL)
       
 11087                     xmlXPathFreeObject(res);
       
 11088                 if (ctxt->value == tmp) {
       
 11089                     res = valuePop(ctxt);
       
 11090                     xmlXPathFreeObject(res);
       
 11091                 }
       
 11092 
       
 11093                 ctxt->context->node = NULL;
       
 11094             } // for (i = 0; i < oldlocset->locNr; i++)
       
 11095 
       
 11096             /*
       
 11097             * The result is used as the new evaluation locset.
       
 11098             */
       
 11099             xmlXPathFreeObject(obj);
       
 11100             ctxt->context->node = NULL;
       
 11101             ctxt->context->contextSize = -1;
       
 11102             ctxt->context->proximityPosition = -1;
       
 11103             valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
       
 11104             ctxt->context->node = oldnode;
       
 11105             return (total);
       
 11106         }
       
 11107 #endif /* LIBXML_XPTR_ENABLED */
       
 11108 
       
 11109         /*
       
 11110         * Extract the old set, and then evaluate the result of the
       
 11111         * expression for all the element in the set. use it to grow
       
 11112         * up a new set.
       
 11113         */
       
 11114         CHECK_TYPE0(XPATH_NODESET);
       
 11115 
       
 11116         obj = valuePop(ctxt);
       
 11117         oldset = obj->nodesetval;
       
 11118         oldnode = ctxt->context->node;
       
 11119         ctxt->context->node = NULL;
       
 11120 
       
 11121         if ((oldset == NULL) || (oldset->nodeNr == 0))
       
 11122         {
       
 11123             ctxt->context->contextSize = 0;
       
 11124             ctxt->context->proximityPosition = 0;
       
 11125 
       
 11126             if (op->ch2 != -1)
       
 11127                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11128 
       
 11129             CHECK_ERROR0;
       
 11130 
       
 11131             res = valuePop(ctxt);
       
 11132             if (res != NULL)
       
 11133                 xmlXPathFreeObject(res);
       
 11134 
       
 11135             valuePush(ctxt, obj);
       
 11136             ctxt->context->node = oldnode;
       
 11137             CHECK_ERROR0;
       
 11138         } else {
       
 11139             /*
       
 11140             * Initialize the new set.
       
 11141             */
       
 11142             newset = xmlXPathNodeSetCreate(NULL);
       
 11143             if(OOM_FLAG) return(-1);
       
 11144 
       
 11145             for (i = 0; i < oldset->nodeNr; i++) {
       
 11146                 /*
       
 11147                 * Run the evaluation with a node list made of
       
 11148                 * a single item in the nodeset.
       
 11149                 */
       
 11150                 ctxt->context->node = oldset->nodeTab[i];
       
 11151                 tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
 11152                 valuePush(ctxt, tmp);
       
 11153                 ctxt->context->contextSize = oldset->nodeNr;
       
 11154                 ctxt->context->proximityPosition = i + 1;
       
 11155 
       
 11156                 if (op->ch2 != -1)
       
 11157                     total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11158 
       
 11159                 CHECK_ERROR0;
       
 11160 
       
 11161                 /*
       
 11162                 * The result of the evaluation needs to be tested to
       
 11163                 * decide whether the filter succeeded or not
       
 11164                 */
       
 11165                 res = valuePop(ctxt);
       
 11166                 if (xmlXPathEvaluatePredicateResult(ctxt, res))
       
 11167                 {
       
 11168                     xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
       
 11169                 }
       
 11170 
       
 11171                 /*
       
 11172                 * Cleanup
       
 11173                 */
       
 11174                 if (res != NULL)
       
 11175                     xmlXPathFreeObject(res);
       
 11176                 if (ctxt->value == tmp) {
       
 11177                     res = valuePop(ctxt);
       
 11178                     xmlXPathFreeObject(res);
       
 11179                 }
       
 11180 
       
 11181                 ctxt->context->node = NULL;
       
 11182             } // (i = 0; i < oldset->nodeNr; i++)
       
 11183 
       
 11184             /*
       
 11185             * The result is used as the new evaluation set.
       
 11186             */
       
 11187             xmlXPathFreeObject(obj);
       
 11188             ctxt->context->node = NULL;
       
 11189             ctxt->context->contextSize = -1;
       
 11190             ctxt->context->proximityPosition = -1;
       
 11191             valuePush(ctxt, xmlXPathWrapNodeSet(newset));
       
 11192         }
       
 11193         ctxt->context->node = oldnode;
       
 11194         return (total);
       
 11195     }
       
 11196 
       
 11197     case XPATH_OP_SORT:     {
       
 11198         if (op->ch1 != -1)
       
 11199         	{
       
 11200         	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 11201         	if(OOM_FLAG) return(-1);
       
 11202         	}
       
 11203 
       
 11204         CHECK_ERROR0;
       
 11205 
       
 11206         if ((ctxt->value != NULL) &&
       
 11207             (ctxt->value->type == XPATH_NODESET) &&
       
 11208             (ctxt->value->nodesetval != NULL))
       
 11209         {
       
 11210             xmlXPathNodeSetSort(ctxt->value->nodesetval);
       
 11211         }
       
 11212         return (total);
       
 11213     }
       
 11214 
       
 11215 #ifdef LIBXML_XPTR_ENABLED
       
 11216     case XPATH_OP_RANGETO:  {
       
 11217         xmlXPathObjectPtr range;
       
 11218         xmlXPathObjectPtr res, obj;
       
 11219         xmlXPathObjectPtr tmp;
       
 11220         xmlLocationSetPtr newlocset = NULL;
       
 11221         xmlLocationSetPtr oldlocset;
       
 11222         xmlNodeSetPtr oldset;
       
 11223         int i, j;
       
 11224 
       
 11225         if (op->ch1 != -1)
       
 11226             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
       
 11227         if (op->ch2 == -1)
       
 11228             return (total);
       
 11229 
       
 11230         if (ctxt->value->type == XPATH_LOCATIONSET)
       
 11231         {
       
 11232             /*
       
 11233             * Extract the old locset, and then evaluate the result of the
       
 11234             * expression for all the element in the locset. use it to grow
       
 11235             * up a new locset.
       
 11236             */
       
 11237             CHECK_TYPE0(XPATH_LOCATIONSET);
       
 11238             obj = valuePop(ctxt);
       
 11239             oldlocset = obj->user;
       
 11240 
       
 11241             if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
       
 11242                 ctxt->context->node = NULL;
       
 11243                 ctxt->context->contextSize = 0;
       
 11244                 ctxt->context->proximityPosition = 0;
       
 11245 
       
 11246                 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
       
 11247 
       
 11248                 res = valuePop(ctxt);
       
 11249                 if (res != NULL)
       
 11250                     xmlXPathFreeObject(res);
       
 11251                 valuePush(ctxt, obj);
       
 11252                 CHECK_ERROR0;
       
 11253                 return (total);
       
 11254             }
       
 11255             newlocset = xmlXPtrLocationSetCreate(NULL);
       
 11256 
       
 11257             for (i = 0; i < oldlocset->locNr; i++) {
       
 11258                 /*
       
 11259                 * Run the evaluation with a node list made of a
       
 11260                 * single item in the nodelocset.
       
 11261                 */
       
 11262                 ctxt->context->node = oldlocset->locTab[i]->user;
       
 11263                 ctxt->context->contextSize = oldlocset->locNr;
       
 11264                 ctxt->context->proximityPosition = i + 1;
       
 11265                 tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
 11266                 valuePush(ctxt, tmp);
       
 11267 
       
 11268                 if (op->ch2 != -1)
       
 11269                     total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11270 
       
 11271                 CHECK_ERROR0;
       
 11272 
       
 11273                 res = valuePop(ctxt);
       
 11274                 if (res->type == XPATH_LOCATIONSET)
       
 11275                 {
       
 11276                     xmlLocationSetPtr rloc = (xmlLocationSetPtr)res->user;
       
 11277 
       
 11278                     for (j=0; j<rloc->locNr; j++) {
       
 11279                         range = xmlXPtrNewRange(
       
 11280                             oldlocset->locTab[i]->user,
       
 11281                             oldlocset->locTab[i]->index,
       
 11282                             rloc->locTab[j]->user2,
       
 11283                             rloc->locTab[j]->index2);
       
 11284 
       
 11285                         if (range != NULL) {
       
 11286                             xmlXPtrLocationSetAdd(newlocset, range);
       
 11287                         }
       
 11288                     }
       
 11289                 } else {
       
 11290                     range = xmlXPtrNewRangeNodeObject((xmlNodePtr)oldlocset->locTab[i]->user, res);
       
 11291                     if (range != NULL) {
       
 11292                         xmlXPtrLocationSetAdd(newlocset,range);
       
 11293                     }
       
 11294                 }
       
 11295 
       
 11296                 /*
       
 11297                 * Cleanup
       
 11298                 */
       
 11299                 if (res != NULL)
       
 11300                     xmlXPathFreeObject(res);
       
 11301                 if (ctxt->value == tmp) {
       
 11302                     res = valuePop(ctxt);
       
 11303                     xmlXPathFreeObject(res);
       
 11304                 }
       
 11305 
       
 11306                 ctxt->context->node = NULL;
       
 11307             }
       
 11308 
       
 11309         }
       
 11310         else
       
 11311         {   /* Not a location set */
       
 11312             CHECK_TYPE0(XPATH_NODESET);
       
 11313             obj = valuePop(ctxt);
       
 11314             oldset = obj->nodesetval;
       
 11315             ctxt->context->node = NULL;
       
 11316 
       
 11317             newlocset = xmlXPtrLocationSetCreate(NULL);
       
 11318 
       
 11319             if (oldset != NULL) {
       
 11320                 for (i = 0; i < oldset->nodeNr; i++) {
       
 11321                     /*
       
 11322                     * Run the evaluation with a node list made of a single item
       
 11323                     * in the nodeset.
       
 11324                     */
       
 11325                     ctxt->context->node = oldset->nodeTab[i];
       
 11326                     tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
 11327                     valuePush(ctxt, tmp);
       
 11328 
       
 11329                     if (op->ch2 != -1)
       
 11330                         total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
       
 11331 
       
 11332                     CHECK_ERROR0;
       
 11333 
       
 11334                     res = valuePop(ctxt);
       
 11335                     range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
       
 11336                     if (range != NULL) {
       
 11337                         xmlXPtrLocationSetAdd(newlocset, range);
       
 11338                     }
       
 11339 
       
 11340                     /*
       
 11341                     * Cleanup
       
 11342                     */
       
 11343                     if (res != NULL)
       
 11344                         xmlXPathFreeObject(res);
       
 11345                     if (ctxt->value == tmp) {
       
 11346                         res = valuePop(ctxt);
       
 11347                         xmlXPathFreeObject(res);
       
 11348                     }
       
 11349 
       
 11350                     ctxt->context->node = NULL;
       
 11351                 } // for
       
 11352             }
       
 11353         }
       
 11354 
       
 11355         /*
       
 11356         * The result is used as the new evaluation set.
       
 11357         */
       
 11358         xmlXPathFreeObject(obj);
       
 11359         ctxt->context->node = NULL;
       
 11360         ctxt->context->contextSize = -1;
       
 11361         ctxt->context->proximityPosition = -1;
       
 11362         valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
       
 11363         return (total);
       
 11364     }
       
 11365 #endif /* LIBXML_XPTR_ENABLED */
       
 11366     } // switch(op->op)
       
 11367 
       
 11368     // None of options matched
       
 11369     xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("XPath: unknown precompiled operation %d\n"), op->op);
       
 11370     return (total);
       
 11371 }
       
 11372 
       
 11373 /**
       
 11374 * xmlXPathRunEval:
       
 11375 * @ctxt:  the XPath parser context with the compiled expression
       
 11376 *
       
 11377 * Evaluate the Precompiled XPath expression in the given context.
       
 11378 */
       
 11379 static void
       
 11380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
       
 11381     xmlXPathCompExprPtr comp;
       
 11382 
       
 11383     if ((ctxt == NULL) || (ctxt->comp == NULL))
       
 11384         return;
       
 11385 
       
 11386     if (ctxt->valueTab == NULL) {
       
 11387         /* Allocate the value stack */
       
 11388         // TODO: Check what's the "magic" number here / Make a setup value
       
 11389         ctxt->valueTab = (xmlXPathObjectPtr *)
       
 11390             xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
       
 11391         if (ctxt->valueTab == NULL) {
       
 11392             xmlXPathPErrMemory(ctxt, EMBED_ERRTXT("creating evaluation context\n"));
       
 11393             xmlFree(ctxt);
       
 11394         }
       
 11395         ctxt->valueNr = 0;
       
 11396         ctxt->valueMax = 10;
       
 11397         ctxt->value = NULL;
       
 11398     }
       
 11399     comp = ctxt->comp;
       
 11400     if(comp->last < 0) {
       
 11401         xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("xmlXPathRunEval: last is less than zero\n"));
       
 11402         return;
       
 11403 
       
 11404     }
       
 11405     xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
       
 11406 }
       
 11407 
       
 11408 /************************************************************************
       
 11409  *                                                                      *
       
 11410  *          Public interfaces                                           *
       
 11411  *                                                                      *
       
 11412  ************************************************************************/
       
 11413 
       
 11414 /**
       
 11415  * xmlXPathEvalPredicate:
       
 11416  * @ctxt:  the XPath context
       
 11417  * @res:  the Predicate Expression evaluation result
       
 11418  *
       
 11419  * Evaluate a predicate result for the current node.
       
 11420  * A PredicateExpr is evaluated by evaluating the Expr and converting
       
 11421  * the result to a boolean. If the result is a number, the result will
       
 11422  * be converted to true if the number is equal to the position of the
       
 11423  * context node in the context node list (as returned by the position
       
 11424  * function) and will be converted to false otherwise; if the result
       
 11425  * is not a number, then the result will be converted as if by a call
       
 11426  * to the boolean function.
       
 11427  *
       
 11428  * Returns 1 if predicate is true, 0 otherwise
       
 11429  */
       
 11430 int
       
 11431 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
       
 11432     if (res == NULL) return(0);
       
 11433     switch (res->type) {
       
 11434         case XPATH_BOOLEAN:
       
 11435             return(res->boolval);
       
 11436         case XPATH_NUMBER:
       
 11437             return(res->floatval == ctxt->proximityPosition);
       
 11438         case XPATH_NODESET:
       
 11439         case XPATH_XSLT_TREE:
       
 11440             return res->nodesetval
       
 11441                    ?
       
 11442                    res->nodesetval->nodeNr != 0
       
 11443                    : 0;
       
 11444         case XPATH_STRING:
       
 11445             return
       
 11446                 res->stringval &&
       
 11447                 xmlStrlen(res->stringval) != 0;
       
 11448         default:
       
 11449             STRANGE
       
 11450     }
       
 11451     return(0);
       
 11452 }
       
 11453 
       
 11454 /**
       
 11455  * xmlXPathEvaluatePredicateResult:
       
 11456  * @ctxt:  the XPath Parser context
       
 11457  * @res:  the Predicate Expression evaluation result
       
 11458  *
       
 11459  * Evaluate a predicate result for the current node.
       
 11460  * A PredicateExpr is evaluated by evaluating the Expr and converting
       
 11461  * the result to a boolean. If the result is a number, the result will
       
 11462  * be converted to true if the number is equal to the position of the
       
 11463  * context node in the context node list (as returned by the position
       
 11464  * function) and will be converted to false otherwise; if the result
       
 11465  * is not a number, then the result will be converted as if by a call
       
 11466  * to the boolean function.
       
 11467  *
       
 11468  * Returns 1 if predicate is true, 0 otherwise
       
 11469  */
       
 11470 int
       
 11471 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
       
 11472                                 xmlXPathObjectPtr res) {
       
 11473     if (res == NULL) return(0);
       
 11474     switch (res->type) {
       
 11475         case XPATH_BOOLEAN:
       
 11476         return(res->boolval);
       
 11477         case XPATH_NUMBER:
       
 11478 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
       
 11479         return((res->floatval == ctxt->context->proximityPosition) &&
       
 11480                (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
       
 11481 #else
       
 11482         return(res->floatval == ctxt->context->proximityPosition);
       
 11483 #endif
       
 11484         case XPATH_NODESET:
       
 11485         case XPATH_XSLT_TREE:
       
 11486         if (res->nodesetval == NULL)
       
 11487         return(0);
       
 11488         return(res->nodesetval->nodeNr != 0);
       
 11489         case XPATH_STRING:
       
 11490         return((res->stringval != NULL) &&
       
 11491                (xmlStrlen(res->stringval) != 0));
       
 11492 #ifdef LIBXML_XPTR_ENABLED
       
 11493     case XPATH_LOCATIONSET:{
       
 11494         xmlLocationSetPtr ptr = res->user;
       
 11495         if (ptr == NULL)
       
 11496             return(0);
       
 11497         return (ptr->locNr != 0);
       
 11498         }
       
 11499 #endif
       
 11500         default:
       
 11501         STRANGE
       
 11502     }
       
 11503     return(0);
       
 11504 }
       
 11505 
       
 11506 /**
       
 11507  * xmlXPathCtxtCompile:
       
 11508  * @ctxt: an XPath context
       
 11509  * @str:  the XPath expression
       
 11510  *
       
 11511  * Compile an XPath expression
       
 11512  *
       
 11513  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
       
 11514  *         the caller has to free the object.
       
 11515  */
       
 11516 xmlXPathCompExprPtr
       
 11517 
       
 11518 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
       
 11519     xmlXPathParserContextPtr pctxt;
       
 11520     xmlXPathCompExprPtr comp;
       
 11521 
       
 11522     xmlXPathInit();
       
 11523 
       
 11524     pctxt = xmlXPathNewParserContext(str, ctxt);
       
 11525     if(OOM_FLAG) return(NULL);
       
 11526     xmlXPathCompileExpr(pctxt);
       
 11527     if(OOM_FLAG)
       
 11528     	{
       
 11529     	xmlXPathFreeParserContext(pctxt);
       
 11530     	return(NULL);
       
 11531     	}
       
 11532     if( pctxt->error != XPATH_EXPRESSION_OK )
       
 11533     {
       
 11534         xmlXPathFreeParserContext(pctxt);
       
 11535         return (0);
       
 11536     }
       
 11537 
       
 11538     if (*pctxt->cur != 0) {
       
 11539     /*
       
 11540      * aleksey: in some cases this line prints *second* error message
       
 11541      * (see bug #78858) and probably this should be fixed.
       
 11542      * However, we are not sure that all error messages are printed
       
 11543      * out in other places. It's not critical so we leave it as-is for now
       
 11544      */
       
 11545     xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
       
 11546     comp = NULL;
       
 11547     } else {
       
 11548     comp = pctxt->comp;
       
 11549     pctxt->comp = NULL;
       
 11550     }
       
 11551     xmlXPathFreeParserContext(pctxt);
       
 11552     if (comp != NULL) {
       
 11553     comp->expr = xmlStrdup(str);
       
 11554 #ifdef DEBUG_EVAL_COUNTS
       
 11555     comp->string = xmlStrdup(str);
       
 11556     comp->nb = 0;
       
 11557 #endif
       
 11558     }
       
 11559     return(comp);
       
 11560 }
       
 11561 
       
 11562 /**
       
 11563  * xmlXPathCompile:
       
 11564  * @str:  the XPath expression
       
 11565  *
       
 11566  * Compile an XPath expression
       
 11567  *
       
 11568  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
       
 11569  *         the caller has to free the object.
       
 11570  */
       
 11571 xmlXPathCompExprPtr
       
 11572 xmlXPathCompile(const xmlChar *str) {
       
 11573     return(xmlXPathCtxtCompile(NULL, str));
       
 11574 }
       
 11575 
       
 11576 /**
       
 11577  * xmlXPathCompiledEval:
       
 11578  * @comp:  the compiled XPath expression
       
 11579  * @ctx:  the XPath context
       
 11580  *
       
 11581  * Evaluate the Precompiled XPath expression in the given context.
       
 11582  *
       
 11583  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
       
 11584  *         the caller has to free the object.
       
 11585  */
       
 11586 xmlXPathObjectPtr
       
 11587 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
       
 11588     xmlXPathParserContextPtr ctxt;
       
 11589     xmlXPathObjectPtr res, tmp, init = NULL;
       
 11590     int stack = 0;
       
 11591 #ifndef LIBXML_THREAD_ENABLED
       
 11592     //FIXIT
       
 11593     //static
       
 11594         int reentance = 0;
       
 11595 #endif
       
 11596 
       
 11597     if ((comp == NULL) || (ctx == NULL))
       
 11598         return(NULL);
       
 11599     xmlXPathInit();
       
 11600     // TODO: CHECK_CONTEXT -- Replace macro with a function (too big for reuse more then once)
       
 11601     CHECK_CONTEXT(ctx)
       
 11602 
       
 11603 #ifndef LIBXML_THREAD_ENABLED
       
 11604     reentance++;
       
 11605     if (reentance > 1)
       
 11606         xmlXPathDisableOptimizer = 1;
       
 11607 #endif
       
 11608 
       
 11609 #ifdef DEBUG_EVAL_COUNTS
       
 11610     comp->nb++;
       
 11611     if ((comp->string != NULL) && (comp->nb > 100)) {
       
 11612         fprintf(stderr, "100 x %s\n", comp->string);
       
 11613         comp->nb = 0;
       
 11614     }
       
 11615 #endif
       
 11616     ctxt = xmlXPathCompParserContext(comp, ctx);
       
 11617     xmlXPathRunEval(ctxt); //might set OOM flag
       
 11618     if(OOM_FLAG) 
       
 11619     	{
       
 11620     	if(ctxt)
       
 11621     		{
       
 11622 			ctxt->comp = NULL;     	  	
       
 11623 	    	xmlXPathFreeParserContext(ctxt);    		
       
 11624     		}
       
 11625     	return(NULL);
       
 11626     	}
       
 11627 
       
 11628     if (ctxt->value == NULL) {
       
 11629         xmlGenericError(xmlGenericErrorContext,
       
 11630                 EMBED_ERRTXT("xmlXPathCompiledEval: evaluation failed\n"));
       
 11631         res = NULL;
       
 11632     } else {
       
 11633         res = valuePop(ctxt);
       
 11634     }
       
 11635 
       
 11636 
       
 11637     do {
       
 11638         tmp = valuePop(ctxt);
       
 11639         if (tmp != NULL) {
       
 11640             if (tmp != init)
       
 11641                 stack++;
       
 11642             xmlXPathFreeObject(tmp);
       
 11643         }
       
 11644     } while (tmp != NULL);
       
 11645     if ((stack != 0) && (res != NULL)) {
       
 11646         xmlGenericError(xmlGenericErrorContext,
       
 11647                 EMBED_ERRTXT("xmlXPathCompiledEval: %d object left on the stack\n"),
       
 11648                 stack);
       
 11649     }
       
 11650     if (ctxt->error != XPATH_EXPRESSION_OK) {
       
 11651         xmlXPathFreeObject(res);
       
 11652         res = NULL;
       
 11653     }
       
 11654 
       
 11655 
       
 11656     ctxt->comp = NULL;
       
 11657     xmlXPathFreeParserContext(ctxt);
       
 11658 #ifndef LIBXML_THREAD_ENABLED
       
 11659     reentance--;
       
 11660 #endif
       
 11661     return(res);
       
 11662 }
       
 11663 
       
 11664 /**
       
 11665  * xmlXPathEvalExpr:
       
 11666  * @ctxt:  the XPath Parser context
       
 11667  *
       
 11668  * Parse and evaluate an XPath expression in the given context,
       
 11669  * then push the result on the context stack
       
 11670  *
       
 11671  * OOM: possible --> check OOM flag
       
 11672  */
       
 11673 void
       
 11674 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
       
 11675     xmlXPathCompileExpr(ctxt);
       
 11676     CHECK_ERROR;
       
 11677     xmlXPathRunEval(ctxt);
       
 11678 }
       
 11679 
       
 11680 /**
       
 11681  * xmlXPathEval:
       
 11682  * @str:  the XPath expression
       
 11683  * @ctx:  the XPath context
       
 11684  *
       
 11685  * Evaluate the XPath Location Path in the given context.
       
 11686  *
       
 11687  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
       
 11688  *         the caller has to free the object.
       
 11689  */
       
 11690 xmlXPathObjectPtr
       
 11691 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
       
 11692     xmlXPathParserContextPtr ctxt;
       
 11693     xmlXPathObjectPtr res, tmp, init = NULL;
       
 11694     int stack = 0;
       
 11695 
       
 11696     xmlXPathInit();
       
 11697 
       
 11698     CHECK_CONTEXT(ctx)
       
 11699 
       
 11700     ctxt = xmlXPathNewParserContext(str, ctx);
       
 11701     xmlXPathEvalExpr(ctxt);
       
 11702 
       
 11703     if (ctxt->value == NULL) {
       
 11704     xmlGenericError(xmlGenericErrorContext,
       
 11705         EMBED_ERRTXT("xmlXPathEval: evaluation failed\n"));
       
 11706     res = NULL;
       
 11707     } else if (*ctxt->cur != 0) {
       
 11708     xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
       
 11709     res = NULL;
       
 11710     } else {
       
 11711     res = valuePop(ctxt);
       
 11712     }
       
 11713 
       
 11714     do {
       
 11715         tmp = valuePop(ctxt);
       
 11716     if (tmp != NULL) {
       
 11717         if (tmp != init)
       
 11718         stack++;
       
 11719         xmlXPathFreeObject(tmp);
       
 11720         }
       
 11721     } while (tmp != NULL);
       
 11722     if ((stack != 0) && (res != NULL)) {
       
 11723     xmlGenericError(xmlGenericErrorContext,
       
 11724         EMBED_ERRTXT("xmlXPathEval: %d object left on the stack\n"),
       
 11725             stack);
       
 11726     }
       
 11727     if (ctxt->error != XPATH_EXPRESSION_OK) {
       
 11728     xmlXPathFreeObject(res);
       
 11729     res = NULL;
       
 11730     }
       
 11731 
       
 11732     xmlXPathFreeParserContext(ctxt);
       
 11733     return(res);
       
 11734 }
       
 11735 
       
 11736 /**
       
 11737  * xmlXPathEvalExpression:
       
 11738  * @str:  the XPath expression
       
 11739  * @ctxt:  the XPath context
       
 11740  *
       
 11741  * Evaluate the XPath expression in the given context.
       
 11742  *
       
 11743  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
       
 11744  *         the caller has to free the object.
       
 11745  */
       
 11746 xmlXPathObjectPtr
       
 11747 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
       
 11748     xmlXPathParserContextPtr pctxt;
       
 11749     xmlXPathObjectPtr res, tmp;
       
 11750     int stack = 0;
       
 11751 
       
 11752     xmlXPathInit();
       
 11753 
       
 11754     CHECK_CONTEXT(ctxt)
       
 11755 
       
 11756     pctxt = xmlXPathNewParserContext(str, ctxt);
       
 11757     xmlXPathEvalExpr(pctxt);
       
 11758 
       
 11759     if (*pctxt->cur != 0) {
       
 11760         xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
       
 11761         res = NULL;
       
 11762     } else {
       
 11763         res = valuePop(pctxt);
       
 11764     }
       
 11765 
       
 11766     do {
       
 11767         tmp = valuePop(pctxt);
       
 11768         if (tmp != NULL) {
       
 11769             xmlXPathFreeObject(tmp);
       
 11770             stack++;
       
 11771         }
       
 11772     } while (tmp != NULL);
       
 11773 
       
 11774     if ((stack != 0) && (res != NULL)) {
       
 11775         xmlGenericError(xmlGenericErrorContext,
       
 11776             EMBED_ERRTXT("xmlXPathEvalExpression: %d object left on the stack\n"),
       
 11777             stack);
       
 11778     }
       
 11779     xmlXPathFreeParserContext(pctxt);
       
 11780     return(res);
       
 11781 }
       
 11782 
       
 11783 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 11784 
       
 11785 /* First initialises static nodeset variable from deplist (argument).
       
 11786 * Calls xmlXPathCompiledEval. If the result is a nodeset it is copied
       
 11787 * to the deplist. Otherwise modifications in xmlXPathCompOpEval have
       
 11788 * already filled deplist.
       
 11789 */
       
 11790 xmlXPathObjectPtr
       
 11791 xmlXPathCompiledEvalWithDependencies(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx, xmlNodeSetPtr deplist)
       
 11792 {
       
 11793     xmlXPathObjectPtr res = NULL;
       
 11794     ctx->dependencyList = deplist;
       
 11795     res = xmlXPathCompiledEval(comp, ctx);
       
 11796 
       
 11797     /* if the result is nodeset there are no other dependencies */
       
 11798     if (res != NULL && res->type == XPATH_NODESET) {
       
 11799         if (!xmlXPathNodeSetIsEmpty(deplist)) {
       
 11800             ;/* this should not happen */
       
 11801         }
       
 11802         xmlXPathNodeSetMerge(deplist, res->nodesetval);
       
 11803         // KO: moved out of IF block // xmlXPathNodeSetSort(deplist);
       
 11804     }
       
 11805     // KO: moved out of IF block //else xmlXPathNodeSetSort(deplist);
       
 11806 
       
 11807     xmlXPathNodeSetSort(deplist); /* dep has been filled with nodes */
       
 11808 
       
 11809     ctx->dependencyList = NULL;
       
 11810 
       
 11811     return res;
       
 11812 }
       
 11813 
       
 11814 /* First pops of nargs values from stack (ctxt) and stores them in temporary
       
 11815 * array. Adds all values of type nodeset to deplist and pushes everything back
       
 11816 * on the stack.
       
 11817 */
       
 11818 void addNodeSetsFromStackToDependencyList(xmlXPathParserContextPtr ctxt, int nargs)
       
 11819 {
       
 11820     xmlNodeSetPtr deplist = ctxt->context->dependencyList;
       
 11821 #define MAXTMPSTACK 10
       
 11822     xmlXPathObjectPtr tmpStack[MAXTMPSTACK] = {0,0,0,0,0,0,0,0,0,0};
       
 11823     int i=0;
       
 11824 
       
 11825     if(!deplist) return;
       
 11826 
       
 11827     // TODO: improve code
       
 11828     // KO: If to decide number of popped elements first (min(nargs,MAXTMPSTACK))
       
 11829     //     then no need to prefill tmpStack with zeros and make checks in the second loop
       
 11830     /* copy all arguments of type nodeset to deplist */
       
 11831     // KO: it is better not to pop and push arguments back, but rather PEEK the values from
       
 11832     //     the internal stack:  PEEK(i)  = ctxt->valueTab[ctxt->valueNr - i - 1];
       
 11833     //     where  'i=1' is the index of the top-most element on the stack
       
 11834     for (i=0; (i < nargs) && (i < MAXTMPSTACK); i++) {
       
 11835         tmpStack[i] = valuePop(ctxt);
       
 11836     }
       
 11837 
       
 11838     for (i= MAXTMPSTACK-1; i>=0 ; i--) {
       
 11839         if (tmpStack[i] != NULL) {
       
 11840             if (tmpStack[i]->type == XPATH_NODESET)
       
 11841                 xmlXPathNodeSetMerge(deplist, tmpStack[i]->nodesetval);
       
 11842             valuePush(ctxt, tmpStack[i]);
       
 11843         }
       
 11844     }
       
 11845 
       
 11846 #define p__enable_this_test
       
 11847 #ifdef __enable_this_test
       
 11848     // TODO: OPTIMIZE: try how this new version of addNodeSetsFromStackToDependencyList works
       
 11849     xmlXPathObjectPtr* stack = ctxt->valueTab;
       
 11850     int index = ctxt->valueNr - 1;
       
 11851     for (i= 0; i < nargs ; i++) {
       
 11852         xmlXPathObjectPtr obj = stack[index--];
       
 11853         if (obj->type == XPATH_NODESET)
       
 11854             xmlXPathNodeSetMerge(deplist, obj->nodesetval);
       
 11855     }
       
 11856 #endif
       
 11857 
       
 11858 #undef __enable_this_test
       
 11859 }
       
 11860 
       
 11861 /*
       
 11862  * xmlXFormsInstanceFunction:
       
 11863  * @ctxt:  the XPath Parser context
       
 11864  * @nargs:  the number of arguments
       
 11865  *
       
 11866  * Implement the instance() XForms function
       
 11867  *    nodeset instance(string)
       
 11868  */
       
 11869 void
       
 11870 xmlXFormsInstanceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
 11871     xmlXPathObjectPtr cur = NULL;
       
 11872     xmlXPathObjectPtr ret = NULL;
       
 11873     xmlDocPtr doc = NULL;
       
 11874 
       
 11875     CHECK_ARITY(1);
       
 11876     cur = valuePop(ctxt);
       
 11877     if (cur == NULL)
       
 11878         XP_ERROR(XPATH_INVALID_OPERAND);
       
 11879 
       
 11880     /* convert argument to string */
       
 11881     cur = xmlXPathConvertString(cur);
       
 11882 
       
 11883     /* TODO: get document from store */
       
 11884     if (ctxt->context->instanceDocs)
       
 11885         {
       
 11886         doc = (xmlDocPtr)xmlHashLookup(ctxt->context->instanceDocs, cur->stringval);
       
 11887         }
       
 11888 
       
 11889     /* create a node set and change context, which will be reset by
       
 11890     the operations: AND, OR, EQUAL, CMP, MULT, UNION, ARG */
       
 11891     if (doc)
       
 11892         {
       
 11893         ctxt->context->doc = doc;
       
 11894         ctxt->context->node = xmlDocGetRootElement(doc);
       
 11895         ret = xmlXPathNewNodeSet(ctxt->context->node);
       
 11896         }
       
 11897     else
       
 11898         {
       
 11899         ret = xmlXPathNewNodeSet(NULL);
       
 11900         }
       
 11901 
       
 11902     /* push the instance on the stack */
       
 11903     valuePush(ctxt, ret);
       
 11904 
       
 11905     /* free cur*/
       
 11906     xmlXPathFreeObject(cur);
       
 11907 }
       
 11908 
       
 11909 
       
 11910 #endif // XMLENGINE_XFROMS_EXTENSIONS
       
 11911 
       
 11912 /************************************************************************
       
 11913  *                                  *
       
 11914  *  Extra functions not pertaining to the XPath spec        *
       
 11915  *                                  *
       
 11916  ************************************************************************/
       
 11917 /**
       
 11918  * xmlXPathEscapeUriFunction:
       
 11919  * @ctxt:  the XPath Parser context
       
 11920  * @nargs:  the number of arguments
       
 11921  *
       
 11922  * Implement the escape-uri() XPath function
       
 11923  *    string escape-uri(string $str, bool $escape-reserved)
       
 11924  *
       
 11925  * This function applies the URI escaping rules defined in section 2 of [RFC
       
 11926  * 2396] to the string supplied as $uri-part, which typically represents all
       
 11927  * or part of a URI. The effect of the function is to replace any special
       
 11928  * character in the string by an escape sequence of the form %xx%yy...,
       
 11929  * where xxyy... is the hexadecimal representation of the octets used to
       
 11930  * represent the character in UTF-8.
       
 11931  *
       
 11932  * The set of characters that are escaped depends on the setting of the
       
 11933  * boolean argument $escape-reserved.
       
 11934  *
       
 11935  * If $escape-reserved is true, all characters are escaped other than lower
       
 11936  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
       
 11937  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
       
 11938  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
       
 11939  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
       
 11940  * A-F).
       
 11941  *
       
 11942  * If $escape-reserved is false, the behavior differs in that characters
       
 11943  * referred to in [RFC 2396] as reserved characters are not escaped. These
       
 11944  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
       
 11945  *
       
 11946  * [RFC 2396] does not define whether escaped URIs should use lower case or
       
 11947  * upper case for hexadecimal digits. To ensure that escaped URIs can be
       
 11948  * compared using string comparison functions, this function must always use
       
 11949  * the upper-case letters A-F.
       
 11950  *
       
 11951  * Generally, $escape-reserved should be set to true when escaping a string
       
 11952  * that is to form a single part of a URI, and to false when escaping an
       
 11953  * entire URI or URI reference.
       
 11954  *
       
 11955  * In the case of non-ascii characters, the string is encoded according to
       
 11956  * utf-8 and then converted according to RFC 2396.
       
 11957  *
       
 11958  * Examples
       
 11959  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
       
 11960  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
       
 11961  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
       
 11962  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
       
 11963  *
       
 11964  */
       
 11965 static void
       
 11966 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
 11967     xmlXPathObjectPtr str;
       
 11968     int escape_reserved;
       
 11969     xmlBufferPtr target;
       
 11970     xmlChar *cptr;
       
 11971     xmlChar escape[4];
       
 11972 
       
 11973     CHECK_ARITY(2);
       
 11974 
       
 11975     escape_reserved = xmlXPathPopBoolean(ctxt);
       
 11976 
       
 11977     CAST_TO_STRING;
       
 11978     str = valuePop(ctxt);
       
 11979 
       
 11980     target = xmlBufferCreate();
       
 11981 
       
 11982     escape[0] = '%';
       
 11983     escape[3] = 0;
       
 11984 
       
 11985     if (target) {
       
 11986         for (cptr = str->stringval; *cptr; cptr++) {
       
 11987             if ((*cptr >= 'A' && *cptr <= 'Z') ||
       
 11988             (*cptr >= 'a' && *cptr <= 'z') ||
       
 11989             (*cptr >= '0' && *cptr <= '9') ||
       
 11990             *cptr == '-' || *cptr == '_' || *cptr == '.' ||
       
 11991             *cptr == '!' || *cptr == '~' || *cptr == '*' ||
       
 11992             *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
       
 11993             (*cptr == '%' &&
       
 11994              ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
       
 11995               (cptr[1] >= 'a' && cptr[1] <= 'f') ||
       
 11996               (cptr[1] >= '0' && cptr[1] <= '9')) &&
       
 11997              ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
       
 11998               (cptr[2] >= 'a' && cptr[2] <= 'f') ||
       
 11999               (cptr[2] >= '0' && cptr[2] <= '9'))) ||
       
 12000             (!escape_reserved &&
       
 12001              (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
       
 12002               *cptr == ':' || *cptr == '@' || *cptr == '&' ||
       
 12003               *cptr == '=' || *cptr == '+' || *cptr == '$' ||
       
 12004               *cptr == ',')))
       
 12005             {
       
 12006                 xmlBufferAdd(target, cptr, 1);
       
 12007             } else {
       
 12008             if ((*cptr >> 4) < 10)
       
 12009                 escape[1] = '0' + (*cptr >> 4);
       
 12010             else
       
 12011                 escape[1] = 'A' - 10 + (*cptr >> 4);
       
 12012             if ((*cptr & 0xF) < 10)
       
 12013                 escape[2] = '0' + (*cptr & 0xF);
       
 12014             else
       
 12015                 escape[2] = 'A' - 10 + (*cptr & 0xF);
       
 12016 
       
 12017             xmlBufferAdd(target, &escape[0], 3);
       
 12018             }
       
 12019         }
       
 12020     }
       
 12021     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
       
 12022     xmlBufferFree(target);
       
 12023     xmlXPathFreeObject(str);
       
 12024 }
       
 12025 
       
 12026 /**
       
 12027  * xmlXPathRegisterAllFunctions:
       
 12028  * @ctxt:  the XPath context
       
 12029  *
       
 12030  * Registers all default XPath functions in this context
       
 12031  *
       
 12032  * Returns 0 in case of success, -1 in case of error
       
 12033  */
       
 12034 int
       
 12035 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
       
 12036 {   // TODO: CHECK OOM after all these and cleanup funcHash if needed
       
 12037     // TODO: return error code OR setup global OOM flag
       
 12038     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"boolean", xmlXPathBooleanFunction) < 0) return(-1);
       
 12039     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"ceiling", xmlXPathCeilingFunction) < 0) return(-1);
       
 12040     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"count",   xmlXPathCountFunction) < 0) return(-1);
       
 12041     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"concat",  xmlXPathConcatFunction) < 0) return(-1);
       
 12042     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"contains",xmlXPathContainsFunction) < 0) return(-1);
       
 12043     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"id",      xmlXPathIdFunction) < 0) return(-1);
       
 12044     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"false",   xmlXPathFalseFunction) < 0) return(-1);
       
 12045     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"floor",   xmlXPathFloorFunction) < 0) return(-1);
       
 12046     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"last",    xmlXPathLastFunction) < 0) return(-1);
       
 12047     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"lang",    xmlXPathLangFunction) < 0) return(-1);
       
 12048     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"local-name", xmlXPathLocalNameFunction) < 0) return(-1);
       
 12049     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"not",      xmlXPathNotFunction) < 0) return(-1);
       
 12050     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"name",     xmlXPathNameFunction) < 0) return(-1);
       
 12051     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"namespace-uri", xmlXPathNamespaceURIFunction) < 0) return(-1);
       
 12052     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"normalize-space", xmlXPathNormalizeFunction) < 0) return(-1);
       
 12053     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"number", xmlXPathNumberFunction) < 0) return(-1);
       
 12054     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"position", xmlXPathPositionFunction) < 0) return(-1);
       
 12055     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"round",   xmlXPathRoundFunction) < 0) return(-1);
       
 12056     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"string",  xmlXPathStringFunction) < 0) return(-1);
       
 12057     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"string-length", xmlXPathStringLengthFunction) < 0) return(-1);
       
 12058     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"starts-with", xmlXPathStartsWithFunction) < 0) return(-1);
       
 12059     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"substring", xmlXPathSubstringFunction) < 0) return(-1);
       
 12060     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"substring-before", xmlXPathSubstringBeforeFunction) < 0) return(-1);
       
 12061     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"substring-after", xmlXPathSubstringAfterFunction) < 0) return(-1);
       
 12062     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"sum", xmlXPathSumFunction) < 0) return(-1);
       
 12063     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"true", xmlXPathTrueFunction) < 0) return(-1);
       
 12064     if( xmlXPathRegisterFunc(ctxt, (const xmlChar*)"translate", xmlXPathTranslateFunction) < 0) return(-1);
       
 12065 
       
 12066     if( xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
       
 12067      (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", xmlXPathEscapeUriFunction) < 0) return(-1);
       
 12068 
       
 12069     // TODO: define special function that will register instance() function for XForms support
       
 12070 #ifdef XMLENGINE_XFORMS_EXTENSIONS
       
 12071     if( xmlXPathRegisterFunc(ctxt, (const xmlChar *)"instance", xmlXFormsInstanceFunction) < 0) return(-1);
       
 12072 #endif
       
 12073 	return(0);
       
 12074 }
       
 12075 
       
 12076 #endif /* LIBXML_XPATH_ENABLED */
       
 12077