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