Annotation of embedaddon/libxml2/xpath.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * xpath.c: XML Path Language implementation
        !             3:  *          XPath is a language for addressing parts of an XML document,
        !             4:  *          designed to be used by both XSLT and XPointer
        !             5:  *f
        !             6:  * Reference: W3C Recommendation 16 November 1999
        !             7:  *     http://www.w3.org/TR/1999/REC-xpath-19991116
        !             8:  * Public reference:
        !             9:  *     http://www.w3.org/TR/xpath
        !            10:  *
        !            11:  * See Copyright for the status of this software
        !            12:  *
        !            13:  * Author: daniel@veillard.com
        !            14:  *
        !            15:  */
        !            16: 
        !            17: #define IN_LIBXML
        !            18: #include "libxml.h"
        !            19: 
        !            20: #include <string.h>
        !            21: 
        !            22: #ifdef HAVE_SYS_TYPES_H
        !            23: #include <sys/types.h>
        !            24: #endif
        !            25: #ifdef HAVE_MATH_H
        !            26: #include <math.h>
        !            27: #endif
        !            28: #ifdef HAVE_FLOAT_H
        !            29: #include <float.h>
        !            30: #endif
        !            31: #ifdef HAVE_CTYPE_H
        !            32: #include <ctype.h>
        !            33: #endif
        !            34: #ifdef HAVE_SIGNAL_H
        !            35: #include <signal.h>
        !            36: #endif
        !            37: 
        !            38: #include <libxml/xmlmemory.h>
        !            39: #include <libxml/tree.h>
        !            40: #include <libxml/valid.h>
        !            41: #include <libxml/xpath.h>
        !            42: #include <libxml/xpathInternals.h>
        !            43: #include <libxml/parserInternals.h>
        !            44: #include <libxml/hash.h>
        !            45: #ifdef LIBXML_XPTR_ENABLED
        !            46: #include <libxml/xpointer.h>
        !            47: #endif
        !            48: #ifdef LIBXML_DEBUG_ENABLED
        !            49: #include <libxml/debugXML.h>
        !            50: #endif
        !            51: #include <libxml/xmlerror.h>
        !            52: #include <libxml/threads.h>
        !            53: #include <libxml/globals.h>
        !            54: #ifdef LIBXML_PATTERN_ENABLED
        !            55: #include <libxml/pattern.h>
        !            56: #endif
        !            57: 
        !            58: #ifdef LIBXML_PATTERN_ENABLED
        !            59: #define XPATH_STREAMING
        !            60: #endif
        !            61: 
        !            62: #define TODO                                                           \
        !            63:     xmlGenericError(xmlGenericErrorContext,                            \
        !            64:            "Unimplemented block at %s:%d\n",                           \
        !            65:             __FILE__, __LINE__);
        !            66: 
        !            67: /*
        !            68: * XP_OPTIMIZED_NON_ELEM_COMPARISON:
        !            69: * If defined, this will use xmlXPathCmpNodesExt() instead of
        !            70: * xmlXPathCmpNodes(). The new function is optimized comparison of
        !            71: * non-element nodes; actually it will speed up comparison only if
        !            72: * xmlXPathOrderDocElems() was called in order to index the elements of
        !            73: * a tree in document order; Libxslt does such an indexing, thus it will
        !            74: * benefit from this optimization.
        !            75: */
        !            76: #define XP_OPTIMIZED_NON_ELEM_COMPARISON
        !            77: 
        !            78: /*
        !            79: * XP_OPTIMIZED_FILTER_FIRST:
        !            80: * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
        !            81: * in a way, that it stop evaluation at the first node.
        !            82: */
        !            83: #define XP_OPTIMIZED_FILTER_FIRST
        !            84: 
        !            85: /*
        !            86: * XP_DEBUG_OBJ_USAGE:
        !            87: * Internal flag to enable tracking of how much XPath objects have been
        !            88: * created.
        !            89: */
        !            90: /* #define XP_DEBUG_OBJ_USAGE */
        !            91: 
        !            92: /*
        !            93:  * TODO:
        !            94:  * There are a few spots where some tests are done which depend upon ascii
        !            95:  * data.  These should be enhanced for full UTF8 support (see particularly
        !            96:  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
        !            97:  */
        !            98: 
        !            99: #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
        !           100: 
        !           101: /************************************************************************
        !           102:  *                                                                     *
        !           103:  *                     Floating point stuff                            *
        !           104:  *                                                                     *
        !           105:  ************************************************************************/
        !           106: 
        !           107: #ifndef TRIO_REPLACE_STDIO
        !           108: #define TRIO_PUBLIC static
        !           109: #endif
        !           110: #include "trionan.c"
        !           111: 
        !           112: /*
        !           113:  * The lack of portability of this section of the libc is annoying !
        !           114:  */
        !           115: double xmlXPathNAN = 0;
        !           116: double xmlXPathPINF = 1;
        !           117: double xmlXPathNINF = -1;
        !           118: static double xmlXPathNZERO = 0; /* not exported from headers */
        !           119: static int xmlXPathInitialized = 0;
        !           120: 
        !           121: /**
        !           122:  * xmlXPathInit:
        !           123:  *
        !           124:  * Initialize the XPath environment
        !           125:  */
        !           126: void
        !           127: xmlXPathInit(void) {
        !           128:     if (xmlXPathInitialized) return;
        !           129: 
        !           130:     xmlXPathPINF = trio_pinf();
        !           131:     xmlXPathNINF = trio_ninf();
        !           132:     xmlXPathNAN = trio_nan();
        !           133:     xmlXPathNZERO = trio_nzero();
        !           134: 
        !           135:     xmlXPathInitialized = 1;
        !           136: }
        !           137: 
        !           138: /**
        !           139:  * xmlXPathIsNaN:
        !           140:  * @val:  a double value
        !           141:  *
        !           142:  * Provides a portable isnan() function to detect whether a double
        !           143:  * is a NotaNumber. Based on trio code
        !           144:  * http://sourceforge.net/projects/ctrio/
        !           145:  *
        !           146:  * Returns 1 if the value is a NaN, 0 otherwise
        !           147:  */
        !           148: int
        !           149: xmlXPathIsNaN(double val) {
        !           150:     return(trio_isnan(val));
        !           151: }
        !           152: 
        !           153: /**
        !           154:  * xmlXPathIsInf:
        !           155:  * @val:  a double value
        !           156:  *
        !           157:  * Provides a portable isinf() function to detect whether a double
        !           158:  * is a +Infinite or -Infinite. Based on trio code
        !           159:  * http://sourceforge.net/projects/ctrio/
        !           160:  *
        !           161:  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
        !           162:  */
        !           163: int
        !           164: xmlXPathIsInf(double val) {
        !           165:     return(trio_isinf(val));
        !           166: }
        !           167: 
        !           168: #endif /* SCHEMAS or XPATH */
        !           169: #ifdef LIBXML_XPATH_ENABLED
        !           170: /**
        !           171:  * xmlXPathGetSign:
        !           172:  * @val:  a double value
        !           173:  *
        !           174:  * Provides a portable function to detect the sign of a double
        !           175:  * Modified from trio code
        !           176:  * http://sourceforge.net/projects/ctrio/
        !           177:  *
        !           178:  * Returns 1 if the value is Negative, 0 if positive
        !           179:  */
        !           180: static int
        !           181: xmlXPathGetSign(double val) {
        !           182:     return(trio_signbit(val));
        !           183: }
        !           184: 
        !           185: 
        !           186: /*
        !           187:  * TODO: when compatibility allows remove all "fake node libxslt" strings
        !           188:  *       the test should just be name[0] = ' '
        !           189:  */
        !           190: #ifdef DEBUG_XPATH_EXPRESSION
        !           191: #define DEBUG_STEP
        !           192: #define DEBUG_EXPR
        !           193: #define DEBUG_EVAL_COUNTS
        !           194: #endif
        !           195: 
        !           196: static xmlNs xmlXPathXMLNamespaceStruct = {
        !           197:     NULL,
        !           198:     XML_NAMESPACE_DECL,
        !           199:     XML_XML_NAMESPACE,
        !           200:     BAD_CAST "xml",
        !           201:     NULL,
        !           202:     NULL
        !           203: };
        !           204: static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
        !           205: #ifndef LIBXML_THREAD_ENABLED
        !           206: /*
        !           207:  * Optimizer is disabled only when threaded apps are detected while
        !           208:  * the library ain't compiled for thread safety.
        !           209:  */
        !           210: static int xmlXPathDisableOptimizer = 0;
        !           211: #endif
        !           212: 
        !           213: /************************************************************************
        !           214:  *                                                                     *
        !           215:  *                     Error handling routines                         *
        !           216:  *                                                                     *
        !           217:  ************************************************************************/
        !           218: 
        !           219: /**
        !           220:  * XP_ERRORNULL:
        !           221:  * @X:  the error code
        !           222:  *
        !           223:  * Macro to raise an XPath error and return NULL.
        !           224:  */
        !           225: #define XP_ERRORNULL(X)                                                        \
        !           226:     { xmlXPathErr(ctxt, X); return(NULL); }
        !           227: 
        !           228: /*
        !           229:  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
        !           230:  */
        !           231: static const char *xmlXPathErrorMessages[] = {
        !           232:     "Ok\n",
        !           233:     "Number encoding\n",
        !           234:     "Unfinished literal\n",
        !           235:     "Start of literal\n",
        !           236:     "Expected $ for variable reference\n",
        !           237:     "Undefined variable\n",
        !           238:     "Invalid predicate\n",
        !           239:     "Invalid expression\n",
        !           240:     "Missing closing curly brace\n",
        !           241:     "Unregistered function\n",
        !           242:     "Invalid operand\n",
        !           243:     "Invalid type\n",
        !           244:     "Invalid number of arguments\n",
        !           245:     "Invalid context size\n",
        !           246:     "Invalid context position\n",
        !           247:     "Memory allocation error\n",
        !           248:     "Syntax error\n",
        !           249:     "Resource error\n",
        !           250:     "Sub resource error\n",
        !           251:     "Undefined namespace prefix\n",
        !           252:     "Encoding error\n",
        !           253:     "Char out of XML range\n",
        !           254:     "Invalid or incomplete context\n",
        !           255:     "?? Unknown error ??\n"    /* Must be last in the list! */
        !           256: };
        !           257: #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /        \
        !           258:                   sizeof(xmlXPathErrorMessages[0])) - 1)
        !           259: /**
        !           260:  * xmlXPathErrMemory:
        !           261:  * @ctxt:  an XPath context
        !           262:  * @extra:  extra informations
        !           263:  *
        !           264:  * Handle a redefinition of attribute error
        !           265:  */
        !           266: static void
        !           267: xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
        !           268: {
        !           269:     if (ctxt != NULL) {
        !           270:         if (extra) {
        !           271:             xmlChar buf[200];
        !           272: 
        !           273:             xmlStrPrintf(buf, 200,
        !           274:                          BAD_CAST "Memory allocation failed : %s\n",
        !           275:                          extra);
        !           276:             ctxt->lastError.message = (char *) xmlStrdup(buf);
        !           277:         } else {
        !           278:             ctxt->lastError.message = (char *)
        !           279:               xmlStrdup(BAD_CAST "Memory allocation failed\n");
        !           280:         }
        !           281:         ctxt->lastError.domain = XML_FROM_XPATH;
        !           282:         ctxt->lastError.code = XML_ERR_NO_MEMORY;
        !           283:        if (ctxt->error != NULL)
        !           284:            ctxt->error(ctxt->userData, &ctxt->lastError);
        !           285:     } else {
        !           286:         if (extra)
        !           287:             __xmlRaiseError(NULL, NULL, NULL,
        !           288:                             NULL, NULL, XML_FROM_XPATH,
        !           289:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
        !           290:                             extra, NULL, NULL, 0, 0,
        !           291:                             "Memory allocation failed : %s\n", extra);
        !           292:         else
        !           293:             __xmlRaiseError(NULL, NULL, NULL,
        !           294:                             NULL, NULL, XML_FROM_XPATH,
        !           295:                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
        !           296:                             NULL, NULL, NULL, 0, 0,
        !           297:                             "Memory allocation failed\n");
        !           298:     }
        !           299: }
        !           300: 
        !           301: /**
        !           302:  * xmlXPathPErrMemory:
        !           303:  * @ctxt:  an XPath parser context
        !           304:  * @extra:  extra informations
        !           305:  *
        !           306:  * Handle a redefinition of attribute error
        !           307:  */
        !           308: static void
        !           309: xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
        !           310: {
        !           311:     if (ctxt == NULL)
        !           312:        xmlXPathErrMemory(NULL, extra);
        !           313:     else {
        !           314:        ctxt->error = XPATH_MEMORY_ERROR;
        !           315:        xmlXPathErrMemory(ctxt->context, extra);
        !           316:     }
        !           317: }
        !           318: 
        !           319: /**
        !           320:  * xmlXPathErr:
        !           321:  * @ctxt:  a XPath parser context
        !           322:  * @error:  the error code
        !           323:  *
        !           324:  * Handle an XPath error
        !           325:  */
        !           326: void
        !           327: xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
        !           328: {
        !           329:     if ((error < 0) || (error > MAXERRNO))
        !           330:        error = MAXERRNO;
        !           331:     if (ctxt == NULL) {
        !           332:        __xmlRaiseError(NULL, NULL, NULL,
        !           333:                        NULL, NULL, XML_FROM_XPATH,
        !           334:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
        !           335:                        XML_ERR_ERROR, NULL, 0,
        !           336:                        NULL, NULL, NULL, 0, 0,
        !           337:                        "%s", xmlXPathErrorMessages[error]);
        !           338:        return;
        !           339:     }
        !           340:     ctxt->error = error;
        !           341:     if (ctxt->context == NULL) {
        !           342:        __xmlRaiseError(NULL, NULL, NULL,
        !           343:                        NULL, NULL, XML_FROM_XPATH,
        !           344:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
        !           345:                        XML_ERR_ERROR, NULL, 0,
        !           346:                        (const char *) ctxt->base, NULL, NULL,
        !           347:                        ctxt->cur - ctxt->base, 0,
        !           348:                        "%s", xmlXPathErrorMessages[error]);
        !           349:        return;
        !           350:     }
        !           351: 
        !           352:     /* cleanup current last error */
        !           353:     xmlResetError(&ctxt->context->lastError);
        !           354: 
        !           355:     ctxt->context->lastError.domain = XML_FROM_XPATH;
        !           356:     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
        !           357:                            XPATH_EXPRESSION_OK;
        !           358:     ctxt->context->lastError.level = XML_ERR_ERROR;
        !           359:     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
        !           360:     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
        !           361:     ctxt->context->lastError.node = ctxt->context->debugNode;
        !           362:     if (ctxt->context->error != NULL) {
        !           363:        ctxt->context->error(ctxt->context->userData,
        !           364:                             &ctxt->context->lastError);
        !           365:     } else {
        !           366:        __xmlRaiseError(NULL, NULL, NULL,
        !           367:                        NULL, ctxt->context->debugNode, XML_FROM_XPATH,
        !           368:                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
        !           369:                        XML_ERR_ERROR, NULL, 0,
        !           370:                        (const char *) ctxt->base, NULL, NULL,
        !           371:                        ctxt->cur - ctxt->base, 0,
        !           372:                        "%s", xmlXPathErrorMessages[error]);
        !           373:     }
        !           374: 
        !           375: }
        !           376: 
        !           377: /**
        !           378:  * xmlXPatherror:
        !           379:  * @ctxt:  the XPath Parser context
        !           380:  * @file:  the file name
        !           381:  * @line:  the line number
        !           382:  * @no:  the error number
        !           383:  *
        !           384:  * Formats an error message.
        !           385:  */
        !           386: void
        !           387: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
        !           388:               int line ATTRIBUTE_UNUSED, int no) {
        !           389:     xmlXPathErr(ctxt, no);
        !           390: }
        !           391: 
        !           392: /************************************************************************
        !           393:  *                                                                     *
        !           394:  *                     Utilities                                       *
        !           395:  *                                                                     *
        !           396:  ************************************************************************/
        !           397: 
        !           398: /**
        !           399:  * xsltPointerList:
        !           400:  *
        !           401:  * Pointer-list for various purposes.
        !           402:  */
        !           403: typedef struct _xmlPointerList xmlPointerList;
        !           404: typedef xmlPointerList *xmlPointerListPtr;
        !           405: struct _xmlPointerList {
        !           406:     void **items;
        !           407:     int number;
        !           408:     int size;
        !           409: };
        !           410: /*
        !           411: * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
        !           412: * and here, we should make the functions public.
        !           413: */
        !           414: static int
        !           415: xmlPointerListAddSize(xmlPointerListPtr list,
        !           416:                       void *item,
        !           417:                       int initialSize)
        !           418: {
        !           419:     if (list->items == NULL) {
        !           420:        if (initialSize <= 0)
        !           421:            initialSize = 1;
        !           422:        list->items = (void **) xmlMalloc(
        !           423:            initialSize * sizeof(void *));
        !           424:        if (list->items == NULL) {
        !           425:            xmlXPathErrMemory(NULL,
        !           426:                "xmlPointerListCreate: allocating item\n");
        !           427:            return(-1);
        !           428:        }
        !           429:        list->number = 0;
        !           430:        list->size = initialSize;
        !           431:     } else if (list->size <= list->number) {
        !           432:        list->size *= 2;
        !           433:        list->items = (void **) xmlRealloc(list->items,
        !           434:            list->size * sizeof(void *));
        !           435:        if (list->items == NULL) {
        !           436:            xmlXPathErrMemory(NULL,
        !           437:                "xmlPointerListCreate: re-allocating item\n");
        !           438:            list->size = 0;
        !           439:            return(-1);
        !           440:        }
        !           441:     }
        !           442:     list->items[list->number++] = item;
        !           443:     return(0);
        !           444: }
        !           445: 
        !           446: /**
        !           447:  * xsltPointerListCreate:
        !           448:  *
        !           449:  * Creates an xsltPointerList structure.
        !           450:  *
        !           451:  * Returns a xsltPointerList structure or NULL in case of an error.
        !           452:  */
        !           453: static xmlPointerListPtr
        !           454: xmlPointerListCreate(int initialSize)
        !           455: {
        !           456:     xmlPointerListPtr ret;
        !           457: 
        !           458:     ret = xmlMalloc(sizeof(xmlPointerList));
        !           459:     if (ret == NULL) {
        !           460:        xmlXPathErrMemory(NULL,
        !           461:            "xmlPointerListCreate: allocating item\n");
        !           462:        return (NULL);
        !           463:     }
        !           464:     memset(ret, 0, sizeof(xmlPointerList));
        !           465:     if (initialSize > 0) {
        !           466:        xmlPointerListAddSize(ret, NULL, initialSize);
        !           467:        ret->number = 0;
        !           468:     }
        !           469:     return (ret);
        !           470: }
        !           471: 
        !           472: /**
        !           473:  * xsltPointerListFree:
        !           474:  *
        !           475:  * Frees the xsltPointerList structure. This does not free
        !           476:  * the content of the list.
        !           477:  */
        !           478: static void
        !           479: xmlPointerListFree(xmlPointerListPtr list)
        !           480: {
        !           481:     if (list == NULL)
        !           482:        return;
        !           483:     if (list->items != NULL)
        !           484:        xmlFree(list->items);
        !           485:     xmlFree(list);
        !           486: }
        !           487: 
        !           488: /************************************************************************
        !           489:  *                                                                     *
        !           490:  *                     Parser Types                                    *
        !           491:  *                                                                     *
        !           492:  ************************************************************************/
        !           493: 
        !           494: /*
        !           495:  * Types are private:
        !           496:  */
        !           497: 
        !           498: typedef enum {
        !           499:     XPATH_OP_END=0,
        !           500:     XPATH_OP_AND,
        !           501:     XPATH_OP_OR,
        !           502:     XPATH_OP_EQUAL,
        !           503:     XPATH_OP_CMP,
        !           504:     XPATH_OP_PLUS,
        !           505:     XPATH_OP_MULT,
        !           506:     XPATH_OP_UNION,
        !           507:     XPATH_OP_ROOT,
        !           508:     XPATH_OP_NODE,
        !           509:     XPATH_OP_RESET, /* 10 */
        !           510:     XPATH_OP_COLLECT,
        !           511:     XPATH_OP_VALUE, /* 12 */
        !           512:     XPATH_OP_VARIABLE,
        !           513:     XPATH_OP_FUNCTION,
        !           514:     XPATH_OP_ARG,
        !           515:     XPATH_OP_PREDICATE,
        !           516:     XPATH_OP_FILTER, /* 17 */
        !           517:     XPATH_OP_SORT /* 18 */
        !           518: #ifdef LIBXML_XPTR_ENABLED
        !           519:     ,XPATH_OP_RANGETO
        !           520: #endif
        !           521: } xmlXPathOp;
        !           522: 
        !           523: typedef enum {
        !           524:     AXIS_ANCESTOR = 1,
        !           525:     AXIS_ANCESTOR_OR_SELF,
        !           526:     AXIS_ATTRIBUTE,
        !           527:     AXIS_CHILD,
        !           528:     AXIS_DESCENDANT,
        !           529:     AXIS_DESCENDANT_OR_SELF,
        !           530:     AXIS_FOLLOWING,
        !           531:     AXIS_FOLLOWING_SIBLING,
        !           532:     AXIS_NAMESPACE,
        !           533:     AXIS_PARENT,
        !           534:     AXIS_PRECEDING,
        !           535:     AXIS_PRECEDING_SIBLING,
        !           536:     AXIS_SELF
        !           537: } xmlXPathAxisVal;
        !           538: 
        !           539: typedef enum {
        !           540:     NODE_TEST_NONE = 0,
        !           541:     NODE_TEST_TYPE = 1,
        !           542:     NODE_TEST_PI = 2,
        !           543:     NODE_TEST_ALL = 3,
        !           544:     NODE_TEST_NS = 4,
        !           545:     NODE_TEST_NAME = 5
        !           546: } xmlXPathTestVal;
        !           547: 
        !           548: typedef enum {
        !           549:     NODE_TYPE_NODE = 0,
        !           550:     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
        !           551:     NODE_TYPE_TEXT = XML_TEXT_NODE,
        !           552:     NODE_TYPE_PI = XML_PI_NODE
        !           553: } xmlXPathTypeVal;
        !           554: 
        !           555: #define XP_REWRITE_DOS_CHILD_ELEM 1
        !           556: 
        !           557: typedef struct _xmlXPathStepOp xmlXPathStepOp;
        !           558: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
        !           559: struct _xmlXPathStepOp {
        !           560:     xmlXPathOp op;             /* The identifier of the operation */
        !           561:     int ch1;                   /* First child */
        !           562:     int ch2;                   /* Second child */
        !           563:     int value;
        !           564:     int value2;
        !           565:     int value3;
        !           566:     void *value4;
        !           567:     void *value5;
        !           568:     void *cache;
        !           569:     void *cacheURI;
        !           570:     int rewriteType;
        !           571: };
        !           572: 
        !           573: struct _xmlXPathCompExpr {
        !           574:     int nbStep;                        /* Number of steps in this expression */
        !           575:     int maxStep;               /* Maximum number of steps allocated */
        !           576:     xmlXPathStepOp *steps;     /* ops for computation of this expression */
        !           577:     int last;                  /* index of last step in expression */
        !           578:     xmlChar *expr;             /* the expression being computed */
        !           579:     xmlDictPtr dict;           /* the dictionnary to use if any */
        !           580: #ifdef DEBUG_EVAL_COUNTS
        !           581:     int nb;
        !           582:     xmlChar *string;
        !           583: #endif
        !           584: #ifdef XPATH_STREAMING
        !           585:     xmlPatternPtr stream;
        !           586: #endif
        !           587: };
        !           588: 
        !           589: /************************************************************************
        !           590:  *                                                                     *
        !           591:  *                     Forward declarations                            *
        !           592:  *                                                                     *
        !           593:  ************************************************************************/
        !           594: static void
        !           595: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
        !           596: static void
        !           597: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
        !           598: static int
        !           599: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
        !           600:                         xmlXPathStepOpPtr op, xmlNodePtr *first);
        !           601: static int
        !           602: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
        !           603:                            xmlXPathStepOpPtr op,
        !           604:                            int isPredicate);
        !           605: 
        !           606: /************************************************************************
        !           607:  *                                                                     *
        !           608:  *                     Parser Type functions                           *
        !           609:  *                                                                     *
        !           610:  ************************************************************************/
        !           611: 
        !           612: /**
        !           613:  * xmlXPathNewCompExpr:
        !           614:  *
        !           615:  * Create a new Xpath component
        !           616:  *
        !           617:  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
        !           618:  */
        !           619: static xmlXPathCompExprPtr
        !           620: xmlXPathNewCompExpr(void) {
        !           621:     xmlXPathCompExprPtr cur;
        !           622: 
        !           623:     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
        !           624:     if (cur == NULL) {
        !           625:         xmlXPathErrMemory(NULL, "allocating component\n");
        !           626:        return(NULL);
        !           627:     }
        !           628:     memset(cur, 0, sizeof(xmlXPathCompExpr));
        !           629:     cur->maxStep = 10;
        !           630:     cur->nbStep = 0;
        !           631:     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
        !           632:                                           sizeof(xmlXPathStepOp));
        !           633:     if (cur->steps == NULL) {
        !           634:         xmlXPathErrMemory(NULL, "allocating steps\n");
        !           635:        xmlFree(cur);
        !           636:        return(NULL);
        !           637:     }
        !           638:     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
        !           639:     cur->last = -1;
        !           640: #ifdef DEBUG_EVAL_COUNTS
        !           641:     cur->nb = 0;
        !           642: #endif
        !           643:     return(cur);
        !           644: }
        !           645: 
        !           646: /**
        !           647:  * xmlXPathFreeCompExpr:
        !           648:  * @comp:  an XPATH comp
        !           649:  *
        !           650:  * Free up the memory allocated by @comp
        !           651:  */
        !           652: void
        !           653: xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
        !           654: {
        !           655:     xmlXPathStepOpPtr op;
        !           656:     int i;
        !           657: 
        !           658:     if (comp == NULL)
        !           659:         return;
        !           660:     if (comp->dict == NULL) {
        !           661:        for (i = 0; i < comp->nbStep; i++) {
        !           662:            op = &comp->steps[i];
        !           663:            if (op->value4 != NULL) {
        !           664:                if (op->op == XPATH_OP_VALUE)
        !           665:                    xmlXPathFreeObject(op->value4);
        !           666:                else
        !           667:                    xmlFree(op->value4);
        !           668:            }
        !           669:            if (op->value5 != NULL)
        !           670:                xmlFree(op->value5);
        !           671:        }
        !           672:     } else {
        !           673:        for (i = 0; i < comp->nbStep; i++) {
        !           674:            op = &comp->steps[i];
        !           675:            if (op->value4 != NULL) {
        !           676:                if (op->op == XPATH_OP_VALUE)
        !           677:                    xmlXPathFreeObject(op->value4);
        !           678:            }
        !           679:        }
        !           680:         xmlDictFree(comp->dict);
        !           681:     }
        !           682:     if (comp->steps != NULL) {
        !           683:         xmlFree(comp->steps);
        !           684:     }
        !           685: #ifdef DEBUG_EVAL_COUNTS
        !           686:     if (comp->string != NULL) {
        !           687:         xmlFree(comp->string);
        !           688:     }
        !           689: #endif
        !           690: #ifdef XPATH_STREAMING
        !           691:     if (comp->stream != NULL) {
        !           692:         xmlFreePatternList(comp->stream);
        !           693:     }
        !           694: #endif
        !           695:     if (comp->expr != NULL) {
        !           696:         xmlFree(comp->expr);
        !           697:     }
        !           698: 
        !           699:     xmlFree(comp);
        !           700: }
        !           701: 
        !           702: /**
        !           703:  * xmlXPathCompExprAdd:
        !           704:  * @comp:  the compiled expression
        !           705:  * @ch1: first child index
        !           706:  * @ch2: second child index
        !           707:  * @op:  an op
        !           708:  * @value:  the first int value
        !           709:  * @value2:  the second int value
        !           710:  * @value3:  the third int value
        !           711:  * @value4:  the first string value
        !           712:  * @value5:  the second string value
        !           713:  *
        !           714:  * Add a step to an XPath Compiled Expression
        !           715:  *
        !           716:  * Returns -1 in case of failure, the index otherwise
        !           717:  */
        !           718: static int
        !           719: xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
        !           720:    xmlXPathOp op, int value,
        !           721:    int value2, int value3, void *value4, void *value5) {
        !           722:     if (comp->nbStep >= comp->maxStep) {
        !           723:        xmlXPathStepOp *real;
        !           724: 
        !           725:        comp->maxStep *= 2;
        !           726:        real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
        !           727:                                      comp->maxStep * sizeof(xmlXPathStepOp));
        !           728:        if (real == NULL) {
        !           729:            comp->maxStep /= 2;
        !           730:            xmlXPathErrMemory(NULL, "adding step\n");
        !           731:            return(-1);
        !           732:        }
        !           733:        comp->steps = real;
        !           734:     }
        !           735:     comp->last = comp->nbStep;
        !           736:     comp->steps[comp->nbStep].rewriteType = 0;
        !           737:     comp->steps[comp->nbStep].ch1 = ch1;
        !           738:     comp->steps[comp->nbStep].ch2 = ch2;
        !           739:     comp->steps[comp->nbStep].op = op;
        !           740:     comp->steps[comp->nbStep].value = value;
        !           741:     comp->steps[comp->nbStep].value2 = value2;
        !           742:     comp->steps[comp->nbStep].value3 = value3;
        !           743:     if ((comp->dict != NULL) &&
        !           744:         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
        !           745:         (op == XPATH_OP_COLLECT))) {
        !           746:         if (value4 != NULL) {
        !           747:            comp->steps[comp->nbStep].value4 = (xmlChar *)
        !           748:                (void *)xmlDictLookup(comp->dict, value4, -1);
        !           749:            xmlFree(value4);
        !           750:        } else
        !           751:            comp->steps[comp->nbStep].value4 = NULL;
        !           752:         if (value5 != NULL) {
        !           753:            comp->steps[comp->nbStep].value5 = (xmlChar *)
        !           754:                (void *)xmlDictLookup(comp->dict, value5, -1);
        !           755:            xmlFree(value5);
        !           756:        } else
        !           757:            comp->steps[comp->nbStep].value5 = NULL;
        !           758:     } else {
        !           759:        comp->steps[comp->nbStep].value4 = value4;
        !           760:        comp->steps[comp->nbStep].value5 = value5;
        !           761:     }
        !           762:     comp->steps[comp->nbStep].cache = NULL;
        !           763:     return(comp->nbStep++);
        !           764: }
        !           765: 
        !           766: /**
        !           767:  * xmlXPathCompSwap:
        !           768:  * @comp:  the compiled expression
        !           769:  * @op: operation index
        !           770:  *
        !           771:  * Swaps 2 operations in the compiled expression
        !           772:  */
        !           773: static void
        !           774: xmlXPathCompSwap(xmlXPathStepOpPtr op) {
        !           775:     int tmp;
        !           776: 
        !           777: #ifndef LIBXML_THREAD_ENABLED
        !           778:     /*
        !           779:      * Since this manipulates possibly shared variables, this is
        !           780:      * disabled if one detects that the library is used in a multithreaded
        !           781:      * application
        !           782:      */
        !           783:     if (xmlXPathDisableOptimizer)
        !           784:        return;
        !           785: #endif
        !           786: 
        !           787:     tmp = op->ch1;
        !           788:     op->ch1 = op->ch2;
        !           789:     op->ch2 = tmp;
        !           790: }
        !           791: 
        !           792: #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)      \
        !           793:     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                      \
        !           794:                        (op), (val), (val2), (val3), (val4), (val5))
        !           795: #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                        \
        !           796:     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,              \
        !           797:                        (op), (val), (val2), (val3), (val4), (val5))
        !           798: 
        !           799: #define PUSH_LEAVE_EXPR(op, val, val2)                                 \
        !           800: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
        !           801: 
        !           802: #define PUSH_UNARY_EXPR(op, ch, val, val2)                             \
        !           803: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
        !           804: 
        !           805: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                      \
        !           806: xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                    \
        !           807:                        (val), (val2), 0 ,NULL ,NULL)
        !           808: 
        !           809: /************************************************************************
        !           810:  *                                                                     *
        !           811:  *             XPath object cache structures                           *
        !           812:  *                                                                     *
        !           813:  ************************************************************************/
        !           814: 
        !           815: /* #define XP_DEFAULT_CACHE_ON */
        !           816: 
        !           817: #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
        !           818: 
        !           819: typedef struct _xmlXPathContextCache xmlXPathContextCache;
        !           820: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
        !           821: struct _xmlXPathContextCache {
        !           822:     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
        !           823:     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
        !           824:     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
        !           825:     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
        !           826:     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
        !           827:     int maxNodeset;
        !           828:     int maxString;
        !           829:     int maxBoolean;
        !           830:     int maxNumber;
        !           831:     int maxMisc;
        !           832: #ifdef XP_DEBUG_OBJ_USAGE
        !           833:     int dbgCachedAll;
        !           834:     int dbgCachedNodeset;
        !           835:     int dbgCachedString;
        !           836:     int dbgCachedBool;
        !           837:     int dbgCachedNumber;
        !           838:     int dbgCachedPoint;
        !           839:     int dbgCachedRange;
        !           840:     int dbgCachedLocset;
        !           841:     int dbgCachedUsers;
        !           842:     int dbgCachedXSLTTree;
        !           843:     int dbgCachedUndefined;
        !           844: 
        !           845: 
        !           846:     int dbgReusedAll;
        !           847:     int dbgReusedNodeset;
        !           848:     int dbgReusedString;
        !           849:     int dbgReusedBool;
        !           850:     int dbgReusedNumber;
        !           851:     int dbgReusedPoint;
        !           852:     int dbgReusedRange;
        !           853:     int dbgReusedLocset;
        !           854:     int dbgReusedUsers;
        !           855:     int dbgReusedXSLTTree;
        !           856:     int dbgReusedUndefined;
        !           857: 
        !           858: #endif
        !           859: };
        !           860: 
        !           861: /************************************************************************
        !           862:  *                                                                     *
        !           863:  *             Debugging related functions                             *
        !           864:  *                                                                     *
        !           865:  ************************************************************************/
        !           866: 
        !           867: #define STRANGE                                                        \
        !           868:     xmlGenericError(xmlGenericErrorContext,                            \
        !           869:            "Internal error at %s:%d\n",                                \
        !           870:             __FILE__, __LINE__);
        !           871: 
        !           872: #ifdef LIBXML_DEBUG_ENABLED
        !           873: static void
        !           874: xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
        !           875:     int i;
        !           876:     char shift[100];
        !           877: 
        !           878:     for (i = 0;((i < depth) && (i < 25));i++)
        !           879:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           880:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           881:     if (cur == NULL) {
        !           882:        fprintf(output, "%s", shift);
        !           883:        fprintf(output, "Node is NULL !\n");
        !           884:        return;
        !           885: 
        !           886:     }
        !           887: 
        !           888:     if ((cur->type == XML_DOCUMENT_NODE) ||
        !           889:             (cur->type == XML_HTML_DOCUMENT_NODE)) {
        !           890:        fprintf(output, "%s", shift);
        !           891:        fprintf(output, " /\n");
        !           892:     } else if (cur->type == XML_ATTRIBUTE_NODE)
        !           893:        xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
        !           894:     else
        !           895:        xmlDebugDumpOneNode(output, cur, depth);
        !           896: }
        !           897: static void
        !           898: xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
        !           899:     xmlNodePtr tmp;
        !           900:     int i;
        !           901:     char shift[100];
        !           902: 
        !           903:     for (i = 0;((i < depth) && (i < 25));i++)
        !           904:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           905:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           906:     if (cur == NULL) {
        !           907:        fprintf(output, "%s", shift);
        !           908:        fprintf(output, "Node is NULL !\n");
        !           909:        return;
        !           910: 
        !           911:     }
        !           912: 
        !           913:     while (cur != NULL) {
        !           914:        tmp = cur;
        !           915:        cur = cur->next;
        !           916:        xmlDebugDumpOneNode(output, tmp, depth);
        !           917:     }
        !           918: }
        !           919: 
        !           920: static void
        !           921: xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
        !           922:     int i;
        !           923:     char shift[100];
        !           924: 
        !           925:     for (i = 0;((i < depth) && (i < 25));i++)
        !           926:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           927:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           928: 
        !           929:     if (cur == NULL) {
        !           930:        fprintf(output, "%s", shift);
        !           931:        fprintf(output, "NodeSet is NULL !\n");
        !           932:        return;
        !           933: 
        !           934:     }
        !           935: 
        !           936:     if (cur != NULL) {
        !           937:        fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
        !           938:        for (i = 0;i < cur->nodeNr;i++) {
        !           939:            fprintf(output, "%s", shift);
        !           940:            fprintf(output, "%d", i + 1);
        !           941:            xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
        !           942:        }
        !           943:     }
        !           944: }
        !           945: 
        !           946: static void
        !           947: xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
        !           948:     int i;
        !           949:     char shift[100];
        !           950: 
        !           951:     for (i = 0;((i < depth) && (i < 25));i++)
        !           952:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           953:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           954: 
        !           955:     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
        !           956:        fprintf(output, "%s", shift);
        !           957:        fprintf(output, "Value Tree is NULL !\n");
        !           958:        return;
        !           959: 
        !           960:     }
        !           961: 
        !           962:     fprintf(output, "%s", shift);
        !           963:     fprintf(output, "%d", i + 1);
        !           964:     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
        !           965: }
        !           966: #if defined(LIBXML_XPTR_ENABLED)
        !           967: static void
        !           968: xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
        !           969:     int i;
        !           970:     char shift[100];
        !           971: 
        !           972:     for (i = 0;((i < depth) && (i < 25));i++)
        !           973:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !           974:     shift[2 * i] = shift[2 * i + 1] = 0;
        !           975: 
        !           976:     if (cur == NULL) {
        !           977:        fprintf(output, "%s", shift);
        !           978:        fprintf(output, "LocationSet is NULL !\n");
        !           979:        return;
        !           980: 
        !           981:     }
        !           982: 
        !           983:     for (i = 0;i < cur->locNr;i++) {
        !           984:        fprintf(output, "%s", shift);
        !           985:         fprintf(output, "%d : ", i + 1);
        !           986:        xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
        !           987:     }
        !           988: }
        !           989: #endif /* LIBXML_XPTR_ENABLED */
        !           990: 
        !           991: /**
        !           992:  * xmlXPathDebugDumpObject:
        !           993:  * @output:  the FILE * to dump the output
        !           994:  * @cur:  the object to inspect
        !           995:  * @depth:  indentation level
        !           996:  *
        !           997:  * Dump the content of the object for debugging purposes
        !           998:  */
        !           999: void
        !          1000: xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
        !          1001:     int i;
        !          1002:     char shift[100];
        !          1003: 
        !          1004:     if (output == NULL) return;
        !          1005: 
        !          1006:     for (i = 0;((i < depth) && (i < 25));i++)
        !          1007:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !          1008:     shift[2 * i] = shift[2 * i + 1] = 0;
        !          1009: 
        !          1010: 
        !          1011:     fprintf(output, "%s", shift);
        !          1012: 
        !          1013:     if (cur == NULL) {
        !          1014:         fprintf(output, "Object is empty (NULL)\n");
        !          1015:        return;
        !          1016:     }
        !          1017:     switch(cur->type) {
        !          1018:         case XPATH_UNDEFINED:
        !          1019:            fprintf(output, "Object is uninitialized\n");
        !          1020:            break;
        !          1021:         case XPATH_NODESET:
        !          1022:            fprintf(output, "Object is a Node Set :\n");
        !          1023:            xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
        !          1024:            break;
        !          1025:        case XPATH_XSLT_TREE:
        !          1026:            fprintf(output, "Object is an XSLT value tree :\n");
        !          1027:            xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
        !          1028:            break;
        !          1029:         case XPATH_BOOLEAN:
        !          1030:            fprintf(output, "Object is a Boolean : ");
        !          1031:            if (cur->boolval) fprintf(output, "true\n");
        !          1032:            else fprintf(output, "false\n");
        !          1033:            break;
        !          1034:         case XPATH_NUMBER:
        !          1035:            switch (xmlXPathIsInf(cur->floatval)) {
        !          1036:            case 1:
        !          1037:                fprintf(output, "Object is a number : Infinity\n");
        !          1038:                break;
        !          1039:            case -1:
        !          1040:                fprintf(output, "Object is a number : -Infinity\n");
        !          1041:                break;
        !          1042:            default:
        !          1043:                if (xmlXPathIsNaN(cur->floatval)) {
        !          1044:                    fprintf(output, "Object is a number : NaN\n");
        !          1045:                } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
        !          1046:                    fprintf(output, "Object is a number : 0\n");
        !          1047:                } else {
        !          1048:                    fprintf(output, "Object is a number : %0g\n", cur->floatval);
        !          1049:                }
        !          1050:            }
        !          1051:            break;
        !          1052:         case XPATH_STRING:
        !          1053:            fprintf(output, "Object is a string : ");
        !          1054:            xmlDebugDumpString(output, cur->stringval);
        !          1055:            fprintf(output, "\n");
        !          1056:            break;
        !          1057:        case XPATH_POINT:
        !          1058:            fprintf(output, "Object is a point : index %d in node", cur->index);
        !          1059:            xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
        !          1060:            fprintf(output, "\n");
        !          1061:            break;
        !          1062:        case XPATH_RANGE:
        !          1063:            if ((cur->user2 == NULL) ||
        !          1064:                ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
        !          1065:                fprintf(output, "Object is a collapsed range :\n");
        !          1066:                fprintf(output, "%s", shift);
        !          1067:                if (cur->index >= 0)
        !          1068:                    fprintf(output, "index %d in ", cur->index);
        !          1069:                fprintf(output, "node\n");
        !          1070:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
        !          1071:                                      depth + 1);
        !          1072:            } else  {
        !          1073:                fprintf(output, "Object is a range :\n");
        !          1074:                fprintf(output, "%s", shift);
        !          1075:                fprintf(output, "From ");
        !          1076:                if (cur->index >= 0)
        !          1077:                    fprintf(output, "index %d in ", cur->index);
        !          1078:                fprintf(output, "node\n");
        !          1079:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
        !          1080:                                      depth + 1);
        !          1081:                fprintf(output, "%s", shift);
        !          1082:                fprintf(output, "To ");
        !          1083:                if (cur->index2 >= 0)
        !          1084:                    fprintf(output, "index %d in ", cur->index2);
        !          1085:                fprintf(output, "node\n");
        !          1086:                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
        !          1087:                                      depth + 1);
        !          1088:                fprintf(output, "\n");
        !          1089:            }
        !          1090:            break;
        !          1091:        case XPATH_LOCATIONSET:
        !          1092: #if defined(LIBXML_XPTR_ENABLED)
        !          1093:            fprintf(output, "Object is a Location Set:\n");
        !          1094:            xmlXPathDebugDumpLocationSet(output,
        !          1095:                    (xmlLocationSetPtr) cur->user, depth);
        !          1096: #endif
        !          1097:            break;
        !          1098:        case XPATH_USERS:
        !          1099:            fprintf(output, "Object is user defined\n");
        !          1100:            break;
        !          1101:     }
        !          1102: }
        !          1103: 
        !          1104: static void
        !          1105: xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
        !          1106:                             xmlXPathStepOpPtr op, int depth) {
        !          1107:     int i;
        !          1108:     char shift[100];
        !          1109: 
        !          1110:     for (i = 0;((i < depth) && (i < 25));i++)
        !          1111:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !          1112:     shift[2 * i] = shift[2 * i + 1] = 0;
        !          1113: 
        !          1114:     fprintf(output, "%s", shift);
        !          1115:     if (op == NULL) {
        !          1116:        fprintf(output, "Step is NULL\n");
        !          1117:        return;
        !          1118:     }
        !          1119:     switch (op->op) {
        !          1120:         case XPATH_OP_END:
        !          1121:            fprintf(output, "END"); break;
        !          1122:         case XPATH_OP_AND:
        !          1123:            fprintf(output, "AND"); break;
        !          1124:         case XPATH_OP_OR:
        !          1125:            fprintf(output, "OR"); break;
        !          1126:         case XPATH_OP_EQUAL:
        !          1127:             if (op->value)
        !          1128:                 fprintf(output, "EQUAL =");
        !          1129:             else
        !          1130:                 fprintf(output, "EQUAL !=");
        !          1131:             break;
        !          1132:         case XPATH_OP_CMP:
        !          1133:             if (op->value)
        !          1134:                 fprintf(output, "CMP <");
        !          1135:             else
        !          1136:                 fprintf(output, "CMP >");
        !          1137:             if (!op->value2)
        !          1138:                 fprintf(output, "=");
        !          1139:             break;
        !          1140:         case XPATH_OP_PLUS:
        !          1141:             if (op->value == 0)
        !          1142:                 fprintf(output, "PLUS -");
        !          1143:             else if (op->value == 1)
        !          1144:                 fprintf(output, "PLUS +");
        !          1145:             else if (op->value == 2)
        !          1146:                 fprintf(output, "PLUS unary -");
        !          1147:             else if (op->value == 3)
        !          1148:                 fprintf(output, "PLUS unary - -");
        !          1149:             break;
        !          1150:         case XPATH_OP_MULT:
        !          1151:             if (op->value == 0)
        !          1152:                 fprintf(output, "MULT *");
        !          1153:             else if (op->value == 1)
        !          1154:                 fprintf(output, "MULT div");
        !          1155:             else
        !          1156:                 fprintf(output, "MULT mod");
        !          1157:             break;
        !          1158:         case XPATH_OP_UNION:
        !          1159:             fprintf(output, "UNION"); break;
        !          1160:         case XPATH_OP_ROOT:
        !          1161:             fprintf(output, "ROOT"); break;
        !          1162:         case XPATH_OP_NODE:
        !          1163:             fprintf(output, "NODE"); break;
        !          1164:         case XPATH_OP_RESET:
        !          1165:             fprintf(output, "RESET"); break;
        !          1166:         case XPATH_OP_SORT:
        !          1167:             fprintf(output, "SORT"); break;
        !          1168:         case XPATH_OP_COLLECT: {
        !          1169:            xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
        !          1170:            xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
        !          1171:            xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
        !          1172:            const xmlChar *prefix = op->value4;
        !          1173:            const xmlChar *name = op->value5;
        !          1174: 
        !          1175:            fprintf(output, "COLLECT ");
        !          1176:            switch (axis) {
        !          1177:                case AXIS_ANCESTOR:
        !          1178:                    fprintf(output, " 'ancestors' "); break;
        !          1179:                case AXIS_ANCESTOR_OR_SELF:
        !          1180:                    fprintf(output, " 'ancestors-or-self' "); break;
        !          1181:                case AXIS_ATTRIBUTE:
        !          1182:                    fprintf(output, " 'attributes' "); break;
        !          1183:                case AXIS_CHILD:
        !          1184:                    fprintf(output, " 'child' "); break;
        !          1185:                case AXIS_DESCENDANT:
        !          1186:                    fprintf(output, " 'descendant' "); break;
        !          1187:                case AXIS_DESCENDANT_OR_SELF:
        !          1188:                    fprintf(output, " 'descendant-or-self' "); break;
        !          1189:                case AXIS_FOLLOWING:
        !          1190:                    fprintf(output, " 'following' "); break;
        !          1191:                case AXIS_FOLLOWING_SIBLING:
        !          1192:                    fprintf(output, " 'following-siblings' "); break;
        !          1193:                case AXIS_NAMESPACE:
        !          1194:                    fprintf(output, " 'namespace' "); break;
        !          1195:                case AXIS_PARENT:
        !          1196:                    fprintf(output, " 'parent' "); break;
        !          1197:                case AXIS_PRECEDING:
        !          1198:                    fprintf(output, " 'preceding' "); break;
        !          1199:                case AXIS_PRECEDING_SIBLING:
        !          1200:                    fprintf(output, " 'preceding-sibling' "); break;
        !          1201:                case AXIS_SELF:
        !          1202:                    fprintf(output, " 'self' "); break;
        !          1203:            }
        !          1204:            switch (test) {
        !          1205:                 case NODE_TEST_NONE:
        !          1206:                    fprintf(output, "'none' "); break;
        !          1207:                 case NODE_TEST_TYPE:
        !          1208:                    fprintf(output, "'type' "); break;
        !          1209:                 case NODE_TEST_PI:
        !          1210:                    fprintf(output, "'PI' "); break;
        !          1211:                 case NODE_TEST_ALL:
        !          1212:                    fprintf(output, "'all' "); break;
        !          1213:                 case NODE_TEST_NS:
        !          1214:                    fprintf(output, "'namespace' "); break;
        !          1215:                 case NODE_TEST_NAME:
        !          1216:                    fprintf(output, "'name' "); break;
        !          1217:            }
        !          1218:            switch (type) {
        !          1219:                 case NODE_TYPE_NODE:
        !          1220:                    fprintf(output, "'node' "); break;
        !          1221:                 case NODE_TYPE_COMMENT:
        !          1222:                    fprintf(output, "'comment' "); break;
        !          1223:                 case NODE_TYPE_TEXT:
        !          1224:                    fprintf(output, "'text' "); break;
        !          1225:                 case NODE_TYPE_PI:
        !          1226:                    fprintf(output, "'PI' "); break;
        !          1227:            }
        !          1228:            if (prefix != NULL)
        !          1229:                fprintf(output, "%s:", prefix);
        !          1230:            if (name != NULL)
        !          1231:                fprintf(output, "%s", (const char *) name);
        !          1232:            break;
        !          1233: 
        !          1234:         }
        !          1235:        case XPATH_OP_VALUE: {
        !          1236:            xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
        !          1237: 
        !          1238:            fprintf(output, "ELEM ");
        !          1239:            xmlXPathDebugDumpObject(output, object, 0);
        !          1240:            goto finish;
        !          1241:        }
        !          1242:        case XPATH_OP_VARIABLE: {
        !          1243:            const xmlChar *prefix = op->value5;
        !          1244:            const xmlChar *name = op->value4;
        !          1245: 
        !          1246:            if (prefix != NULL)
        !          1247:                fprintf(output, "VARIABLE %s:%s", prefix, name);
        !          1248:            else
        !          1249:                fprintf(output, "VARIABLE %s", name);
        !          1250:            break;
        !          1251:        }
        !          1252:        case XPATH_OP_FUNCTION: {
        !          1253:            int nbargs = op->value;
        !          1254:            const xmlChar *prefix = op->value5;
        !          1255:            const xmlChar *name = op->value4;
        !          1256: 
        !          1257:            if (prefix != NULL)
        !          1258:                fprintf(output, "FUNCTION %s:%s(%d args)",
        !          1259:                        prefix, name, nbargs);
        !          1260:            else
        !          1261:                fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
        !          1262:            break;
        !          1263:        }
        !          1264:         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
        !          1265:         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
        !          1266:         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
        !          1267: #ifdef LIBXML_XPTR_ENABLED
        !          1268:         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
        !          1269: #endif
        !          1270:        default:
        !          1271:         fprintf(output, "UNKNOWN %d\n", op->op); return;
        !          1272:     }
        !          1273:     fprintf(output, "\n");
        !          1274: finish:
        !          1275:     if (op->ch1 >= 0)
        !          1276:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
        !          1277:     if (op->ch2 >= 0)
        !          1278:        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
        !          1279: }
        !          1280: 
        !          1281: /**
        !          1282:  * xmlXPathDebugDumpCompExpr:
        !          1283:  * @output:  the FILE * for the output
        !          1284:  * @comp:  the precompiled XPath expression
        !          1285:  * @depth:  the indentation level.
        !          1286:  *
        !          1287:  * Dumps the tree of the compiled XPath expression.
        !          1288:  */
        !          1289: void
        !          1290: xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
        !          1291:                          int depth) {
        !          1292:     int i;
        !          1293:     char shift[100];
        !          1294: 
        !          1295:     if ((output == NULL) || (comp == NULL)) return;
        !          1296: 
        !          1297:     for (i = 0;((i < depth) && (i < 25));i++)
        !          1298:         shift[2 * i] = shift[2 * i + 1] = ' ';
        !          1299:     shift[2 * i] = shift[2 * i + 1] = 0;
        !          1300: 
        !          1301:     fprintf(output, "%s", shift);
        !          1302: 
        !          1303:     fprintf(output, "Compiled Expression : %d elements\n",
        !          1304:            comp->nbStep);
        !          1305:     i = comp->last;
        !          1306:     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
        !          1307: }
        !          1308: 
        !          1309: #ifdef XP_DEBUG_OBJ_USAGE
        !          1310: 
        !          1311: /*
        !          1312: * XPath object usage related debugging variables.
        !          1313: */
        !          1314: static int xmlXPathDebugObjCounterUndefined = 0;
        !          1315: static int xmlXPathDebugObjCounterNodeset = 0;
        !          1316: static int xmlXPathDebugObjCounterBool = 0;
        !          1317: static int xmlXPathDebugObjCounterNumber = 0;
        !          1318: static int xmlXPathDebugObjCounterString = 0;
        !          1319: static int xmlXPathDebugObjCounterPoint = 0;
        !          1320: static int xmlXPathDebugObjCounterRange = 0;
        !          1321: static int xmlXPathDebugObjCounterLocset = 0;
        !          1322: static int xmlXPathDebugObjCounterUsers = 0;
        !          1323: static int xmlXPathDebugObjCounterXSLTTree = 0;
        !          1324: static int xmlXPathDebugObjCounterAll = 0;
        !          1325: 
        !          1326: static int xmlXPathDebugObjTotalUndefined = 0;
        !          1327: static int xmlXPathDebugObjTotalNodeset = 0;
        !          1328: static int xmlXPathDebugObjTotalBool = 0;
        !          1329: static int xmlXPathDebugObjTotalNumber = 0;
        !          1330: static int xmlXPathDebugObjTotalString = 0;
        !          1331: static int xmlXPathDebugObjTotalPoint = 0;
        !          1332: static int xmlXPathDebugObjTotalRange = 0;
        !          1333: static int xmlXPathDebugObjTotalLocset = 0;
        !          1334: static int xmlXPathDebugObjTotalUsers = 0;
        !          1335: static int xmlXPathDebugObjTotalXSLTTree = 0;
        !          1336: static int xmlXPathDebugObjTotalAll = 0;
        !          1337: 
        !          1338: static int xmlXPathDebugObjMaxUndefined = 0;
        !          1339: static int xmlXPathDebugObjMaxNodeset = 0;
        !          1340: static int xmlXPathDebugObjMaxBool = 0;
        !          1341: static int xmlXPathDebugObjMaxNumber = 0;
        !          1342: static int xmlXPathDebugObjMaxString = 0;
        !          1343: static int xmlXPathDebugObjMaxPoint = 0;
        !          1344: static int xmlXPathDebugObjMaxRange = 0;
        !          1345: static int xmlXPathDebugObjMaxLocset = 0;
        !          1346: static int xmlXPathDebugObjMaxUsers = 0;
        !          1347: static int xmlXPathDebugObjMaxXSLTTree = 0;
        !          1348: static int xmlXPathDebugObjMaxAll = 0;
        !          1349: 
        !          1350: /* REVISIT TODO: Make this static when committing */
        !          1351: static void
        !          1352: xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
        !          1353: {
        !          1354:     if (ctxt != NULL) {
        !          1355:        if (ctxt->cache != NULL) {
        !          1356:            xmlXPathContextCachePtr cache =
        !          1357:                (xmlXPathContextCachePtr) ctxt->cache;
        !          1358: 
        !          1359:            cache->dbgCachedAll = 0;
        !          1360:            cache->dbgCachedNodeset = 0;
        !          1361:            cache->dbgCachedString = 0;
        !          1362:            cache->dbgCachedBool = 0;
        !          1363:            cache->dbgCachedNumber = 0;
        !          1364:            cache->dbgCachedPoint = 0;
        !          1365:            cache->dbgCachedRange = 0;
        !          1366:            cache->dbgCachedLocset = 0;
        !          1367:            cache->dbgCachedUsers = 0;
        !          1368:            cache->dbgCachedXSLTTree = 0;
        !          1369:            cache->dbgCachedUndefined = 0;
        !          1370: 
        !          1371:            cache->dbgReusedAll = 0;
        !          1372:            cache->dbgReusedNodeset = 0;
        !          1373:            cache->dbgReusedString = 0;
        !          1374:            cache->dbgReusedBool = 0;
        !          1375:            cache->dbgReusedNumber = 0;
        !          1376:            cache->dbgReusedPoint = 0;
        !          1377:            cache->dbgReusedRange = 0;
        !          1378:            cache->dbgReusedLocset = 0;
        !          1379:            cache->dbgReusedUsers = 0;
        !          1380:            cache->dbgReusedXSLTTree = 0;
        !          1381:            cache->dbgReusedUndefined = 0;
        !          1382:        }
        !          1383:     }
        !          1384: 
        !          1385:     xmlXPathDebugObjCounterUndefined = 0;
        !          1386:     xmlXPathDebugObjCounterNodeset = 0;
        !          1387:     xmlXPathDebugObjCounterBool = 0;
        !          1388:     xmlXPathDebugObjCounterNumber = 0;
        !          1389:     xmlXPathDebugObjCounterString = 0;
        !          1390:     xmlXPathDebugObjCounterPoint = 0;
        !          1391:     xmlXPathDebugObjCounterRange = 0;
        !          1392:     xmlXPathDebugObjCounterLocset = 0;
        !          1393:     xmlXPathDebugObjCounterUsers = 0;
        !          1394:     xmlXPathDebugObjCounterXSLTTree = 0;
        !          1395:     xmlXPathDebugObjCounterAll = 0;
        !          1396: 
        !          1397:     xmlXPathDebugObjTotalUndefined = 0;
        !          1398:     xmlXPathDebugObjTotalNodeset = 0;
        !          1399:     xmlXPathDebugObjTotalBool = 0;
        !          1400:     xmlXPathDebugObjTotalNumber = 0;
        !          1401:     xmlXPathDebugObjTotalString = 0;
        !          1402:     xmlXPathDebugObjTotalPoint = 0;
        !          1403:     xmlXPathDebugObjTotalRange = 0;
        !          1404:     xmlXPathDebugObjTotalLocset = 0;
        !          1405:     xmlXPathDebugObjTotalUsers = 0;
        !          1406:     xmlXPathDebugObjTotalXSLTTree = 0;
        !          1407:     xmlXPathDebugObjTotalAll = 0;
        !          1408: 
        !          1409:     xmlXPathDebugObjMaxUndefined = 0;
        !          1410:     xmlXPathDebugObjMaxNodeset = 0;
        !          1411:     xmlXPathDebugObjMaxBool = 0;
        !          1412:     xmlXPathDebugObjMaxNumber = 0;
        !          1413:     xmlXPathDebugObjMaxString = 0;
        !          1414:     xmlXPathDebugObjMaxPoint = 0;
        !          1415:     xmlXPathDebugObjMaxRange = 0;
        !          1416:     xmlXPathDebugObjMaxLocset = 0;
        !          1417:     xmlXPathDebugObjMaxUsers = 0;
        !          1418:     xmlXPathDebugObjMaxXSLTTree = 0;
        !          1419:     xmlXPathDebugObjMaxAll = 0;
        !          1420: 
        !          1421: }
        !          1422: 
        !          1423: static void
        !          1424: xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
        !          1425:                              xmlXPathObjectType objType)
        !          1426: {
        !          1427:     int isCached = 0;
        !          1428: 
        !          1429:     if (ctxt != NULL) {
        !          1430:        if (ctxt->cache != NULL) {
        !          1431:            xmlXPathContextCachePtr cache =
        !          1432:                (xmlXPathContextCachePtr) ctxt->cache;
        !          1433: 
        !          1434:            isCached = 1;
        !          1435: 
        !          1436:            cache->dbgReusedAll++;
        !          1437:            switch (objType) {
        !          1438:                case XPATH_UNDEFINED:
        !          1439:                    cache->dbgReusedUndefined++;
        !          1440:                    break;
        !          1441:                case XPATH_NODESET:
        !          1442:                    cache->dbgReusedNodeset++;
        !          1443:                    break;
        !          1444:                case XPATH_BOOLEAN:
        !          1445:                    cache->dbgReusedBool++;
        !          1446:                    break;
        !          1447:                case XPATH_NUMBER:
        !          1448:                    cache->dbgReusedNumber++;
        !          1449:                    break;
        !          1450:                case XPATH_STRING:
        !          1451:                    cache->dbgReusedString++;
        !          1452:                    break;
        !          1453:                case XPATH_POINT:
        !          1454:                    cache->dbgReusedPoint++;
        !          1455:                    break;
        !          1456:                case XPATH_RANGE:
        !          1457:                    cache->dbgReusedRange++;
        !          1458:                    break;
        !          1459:                case XPATH_LOCATIONSET:
        !          1460:                    cache->dbgReusedLocset++;
        !          1461:                    break;
        !          1462:                case XPATH_USERS:
        !          1463:                    cache->dbgReusedUsers++;
        !          1464:                    break;
        !          1465:                case XPATH_XSLT_TREE:
        !          1466:                    cache->dbgReusedXSLTTree++;
        !          1467:                    break;
        !          1468:                default:
        !          1469:                    break;
        !          1470:            }
        !          1471:        }
        !          1472:     }
        !          1473: 
        !          1474:     switch (objType) {
        !          1475:        case XPATH_UNDEFINED:
        !          1476:            if (! isCached)
        !          1477:                xmlXPathDebugObjTotalUndefined++;
        !          1478:            xmlXPathDebugObjCounterUndefined++;
        !          1479:            if (xmlXPathDebugObjCounterUndefined >
        !          1480:                xmlXPathDebugObjMaxUndefined)
        !          1481:                xmlXPathDebugObjMaxUndefined =
        !          1482:                    xmlXPathDebugObjCounterUndefined;
        !          1483:            break;
        !          1484:        case XPATH_NODESET:
        !          1485:            if (! isCached)
        !          1486:                xmlXPathDebugObjTotalNodeset++;
        !          1487:            xmlXPathDebugObjCounterNodeset++;
        !          1488:            if (xmlXPathDebugObjCounterNodeset >
        !          1489:                xmlXPathDebugObjMaxNodeset)
        !          1490:                xmlXPathDebugObjMaxNodeset =
        !          1491:                    xmlXPathDebugObjCounterNodeset;
        !          1492:            break;
        !          1493:        case XPATH_BOOLEAN:
        !          1494:            if (! isCached)
        !          1495:                xmlXPathDebugObjTotalBool++;
        !          1496:            xmlXPathDebugObjCounterBool++;
        !          1497:            if (xmlXPathDebugObjCounterBool >
        !          1498:                xmlXPathDebugObjMaxBool)
        !          1499:                xmlXPathDebugObjMaxBool =
        !          1500:                    xmlXPathDebugObjCounterBool;
        !          1501:            break;
        !          1502:        case XPATH_NUMBER:
        !          1503:            if (! isCached)
        !          1504:                xmlXPathDebugObjTotalNumber++;
        !          1505:            xmlXPathDebugObjCounterNumber++;
        !          1506:            if (xmlXPathDebugObjCounterNumber >
        !          1507:                xmlXPathDebugObjMaxNumber)
        !          1508:                xmlXPathDebugObjMaxNumber =
        !          1509:                    xmlXPathDebugObjCounterNumber;
        !          1510:            break;
        !          1511:        case XPATH_STRING:
        !          1512:            if (! isCached)
        !          1513:                xmlXPathDebugObjTotalString++;
        !          1514:            xmlXPathDebugObjCounterString++;
        !          1515:            if (xmlXPathDebugObjCounterString >
        !          1516:                xmlXPathDebugObjMaxString)
        !          1517:                xmlXPathDebugObjMaxString =
        !          1518:                    xmlXPathDebugObjCounterString;
        !          1519:            break;
        !          1520:        case XPATH_POINT:
        !          1521:            if (! isCached)
        !          1522:                xmlXPathDebugObjTotalPoint++;
        !          1523:            xmlXPathDebugObjCounterPoint++;
        !          1524:            if (xmlXPathDebugObjCounterPoint >
        !          1525:                xmlXPathDebugObjMaxPoint)
        !          1526:                xmlXPathDebugObjMaxPoint =
        !          1527:                    xmlXPathDebugObjCounterPoint;
        !          1528:            break;
        !          1529:        case XPATH_RANGE:
        !          1530:            if (! isCached)
        !          1531:                xmlXPathDebugObjTotalRange++;
        !          1532:            xmlXPathDebugObjCounterRange++;
        !          1533:            if (xmlXPathDebugObjCounterRange >
        !          1534:                xmlXPathDebugObjMaxRange)
        !          1535:                xmlXPathDebugObjMaxRange =
        !          1536:                    xmlXPathDebugObjCounterRange;
        !          1537:            break;
        !          1538:        case XPATH_LOCATIONSET:
        !          1539:            if (! isCached)
        !          1540:                xmlXPathDebugObjTotalLocset++;
        !          1541:            xmlXPathDebugObjCounterLocset++;
        !          1542:            if (xmlXPathDebugObjCounterLocset >
        !          1543:                xmlXPathDebugObjMaxLocset)
        !          1544:                xmlXPathDebugObjMaxLocset =
        !          1545:                    xmlXPathDebugObjCounterLocset;
        !          1546:            break;
        !          1547:        case XPATH_USERS:
        !          1548:            if (! isCached)
        !          1549:                xmlXPathDebugObjTotalUsers++;
        !          1550:            xmlXPathDebugObjCounterUsers++;
        !          1551:            if (xmlXPathDebugObjCounterUsers >
        !          1552:                xmlXPathDebugObjMaxUsers)
        !          1553:                xmlXPathDebugObjMaxUsers =
        !          1554:                    xmlXPathDebugObjCounterUsers;
        !          1555:            break;
        !          1556:        case XPATH_XSLT_TREE:
        !          1557:            if (! isCached)
        !          1558:                xmlXPathDebugObjTotalXSLTTree++;
        !          1559:            xmlXPathDebugObjCounterXSLTTree++;
        !          1560:            if (xmlXPathDebugObjCounterXSLTTree >
        !          1561:                xmlXPathDebugObjMaxXSLTTree)
        !          1562:                xmlXPathDebugObjMaxXSLTTree =
        !          1563:                    xmlXPathDebugObjCounterXSLTTree;
        !          1564:            break;
        !          1565:        default:
        !          1566:            break;
        !          1567:     }
        !          1568:     if (! isCached)
        !          1569:        xmlXPathDebugObjTotalAll++;
        !          1570:     xmlXPathDebugObjCounterAll++;
        !          1571:     if (xmlXPathDebugObjCounterAll >
        !          1572:        xmlXPathDebugObjMaxAll)
        !          1573:        xmlXPathDebugObjMaxAll =
        !          1574:            xmlXPathDebugObjCounterAll;
        !          1575: }
        !          1576: 
        !          1577: static void
        !          1578: xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
        !          1579:                              xmlXPathObjectType objType)
        !          1580: {
        !          1581:     int isCached = 0;
        !          1582: 
        !          1583:     if (ctxt != NULL) {
        !          1584:        if (ctxt->cache != NULL) {
        !          1585:            xmlXPathContextCachePtr cache =
        !          1586:                (xmlXPathContextCachePtr) ctxt->cache;
        !          1587: 
        !          1588:            isCached = 1;
        !          1589: 
        !          1590:            cache->dbgCachedAll++;
        !          1591:            switch (objType) {
        !          1592:                case XPATH_UNDEFINED:
        !          1593:                    cache->dbgCachedUndefined++;
        !          1594:                    break;
        !          1595:                case XPATH_NODESET:
        !          1596:                    cache->dbgCachedNodeset++;
        !          1597:                    break;
        !          1598:                case XPATH_BOOLEAN:
        !          1599:                    cache->dbgCachedBool++;
        !          1600:                    break;
        !          1601:                case XPATH_NUMBER:
        !          1602:                    cache->dbgCachedNumber++;
        !          1603:                    break;
        !          1604:                case XPATH_STRING:
        !          1605:                    cache->dbgCachedString++;
        !          1606:                    break;
        !          1607:                case XPATH_POINT:
        !          1608:                    cache->dbgCachedPoint++;
        !          1609:                    break;
        !          1610:                case XPATH_RANGE:
        !          1611:                    cache->dbgCachedRange++;
        !          1612:                    break;
        !          1613:                case XPATH_LOCATIONSET:
        !          1614:                    cache->dbgCachedLocset++;
        !          1615:                    break;
        !          1616:                case XPATH_USERS:
        !          1617:                    cache->dbgCachedUsers++;
        !          1618:                    break;
        !          1619:                case XPATH_XSLT_TREE:
        !          1620:                    cache->dbgCachedXSLTTree++;
        !          1621:                    break;
        !          1622:                default:
        !          1623:                    break;
        !          1624:            }
        !          1625: 
        !          1626:        }
        !          1627:     }
        !          1628:     switch (objType) {
        !          1629:        case XPATH_UNDEFINED:
        !          1630:            xmlXPathDebugObjCounterUndefined--;
        !          1631:            break;
        !          1632:        case XPATH_NODESET:
        !          1633:            xmlXPathDebugObjCounterNodeset--;
        !          1634:            break;
        !          1635:        case XPATH_BOOLEAN:
        !          1636:            xmlXPathDebugObjCounterBool--;
        !          1637:            break;
        !          1638:        case XPATH_NUMBER:
        !          1639:            xmlXPathDebugObjCounterNumber--;
        !          1640:            break;
        !          1641:        case XPATH_STRING:
        !          1642:            xmlXPathDebugObjCounterString--;
        !          1643:            break;
        !          1644:        case XPATH_POINT:
        !          1645:            xmlXPathDebugObjCounterPoint--;
        !          1646:            break;
        !          1647:        case XPATH_RANGE:
        !          1648:            xmlXPathDebugObjCounterRange--;
        !          1649:            break;
        !          1650:        case XPATH_LOCATIONSET:
        !          1651:            xmlXPathDebugObjCounterLocset--;
        !          1652:            break;
        !          1653:        case XPATH_USERS:
        !          1654:            xmlXPathDebugObjCounterUsers--;
        !          1655:            break;
        !          1656:        case XPATH_XSLT_TREE:
        !          1657:            xmlXPathDebugObjCounterXSLTTree--;
        !          1658:            break;
        !          1659:        default:
        !          1660:            break;
        !          1661:     }
        !          1662:     xmlXPathDebugObjCounterAll--;
        !          1663: }
        !          1664: 
        !          1665: /* REVISIT TODO: Make this static when committing */
        !          1666: static void
        !          1667: xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
        !          1668: {
        !          1669:     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
        !          1670:        reqXSLTTree, reqUndefined;
        !          1671:     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
        !          1672:        caNumber = 0, caXSLTTree = 0, caUndefined = 0;
        !          1673:     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
        !          1674:        reNumber = 0, reXSLTTree = 0, reUndefined = 0;
        !          1675:     int leftObjs = xmlXPathDebugObjCounterAll;
        !          1676: 
        !          1677:     reqAll = xmlXPathDebugObjTotalAll;
        !          1678:     reqNodeset = xmlXPathDebugObjTotalNodeset;
        !          1679:     reqString = xmlXPathDebugObjTotalString;
        !          1680:     reqBool = xmlXPathDebugObjTotalBool;
        !          1681:     reqNumber = xmlXPathDebugObjTotalNumber;
        !          1682:     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
        !          1683:     reqUndefined = xmlXPathDebugObjTotalUndefined;
        !          1684: 
        !          1685:     printf("# XPath object usage:\n");
        !          1686: 
        !          1687:     if (ctxt != NULL) {
        !          1688:        if (ctxt->cache != NULL) {
        !          1689:            xmlXPathContextCachePtr cache =
        !          1690:                (xmlXPathContextCachePtr) ctxt->cache;
        !          1691: 
        !          1692:            reAll = cache->dbgReusedAll;
        !          1693:            reqAll += reAll;
        !          1694:            reNodeset = cache->dbgReusedNodeset;
        !          1695:            reqNodeset += reNodeset;
        !          1696:            reString = cache->dbgReusedString;
        !          1697:            reqString += reString;
        !          1698:            reBool = cache->dbgReusedBool;
        !          1699:            reqBool += reBool;
        !          1700:            reNumber = cache->dbgReusedNumber;
        !          1701:            reqNumber += reNumber;
        !          1702:            reXSLTTree = cache->dbgReusedXSLTTree;
        !          1703:            reqXSLTTree += reXSLTTree;
        !          1704:            reUndefined = cache->dbgReusedUndefined;
        !          1705:            reqUndefined += reUndefined;
        !          1706: 
        !          1707:            caAll = cache->dbgCachedAll;
        !          1708:            caBool = cache->dbgCachedBool;
        !          1709:            caNodeset = cache->dbgCachedNodeset;
        !          1710:            caString = cache->dbgCachedString;
        !          1711:            caNumber = cache->dbgCachedNumber;
        !          1712:            caXSLTTree = cache->dbgCachedXSLTTree;
        !          1713:            caUndefined = cache->dbgCachedUndefined;
        !          1714: 
        !          1715:            if (cache->nodesetObjs)
        !          1716:                leftObjs -= cache->nodesetObjs->number;
        !          1717:            if (cache->stringObjs)
        !          1718:                leftObjs -= cache->stringObjs->number;
        !          1719:            if (cache->booleanObjs)
        !          1720:                leftObjs -= cache->booleanObjs->number;
        !          1721:            if (cache->numberObjs)
        !          1722:                leftObjs -= cache->numberObjs->number;
        !          1723:            if (cache->miscObjs)
        !          1724:                leftObjs -= cache->miscObjs->number;
        !          1725:        }
        !          1726:     }
        !          1727: 
        !          1728:     printf("# all\n");
        !          1729:     printf("#   total  : %d\n", reqAll);
        !          1730:     printf("#   left  : %d\n", leftObjs);
        !          1731:     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
        !          1732:     printf("#   reused : %d\n", reAll);
        !          1733:     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
        !          1734: 
        !          1735:     printf("# node-sets\n");
        !          1736:     printf("#   total  : %d\n", reqNodeset);
        !          1737:     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
        !          1738:     printf("#   reused : %d\n", reNodeset);
        !          1739:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
        !          1740: 
        !          1741:     printf("# strings\n");
        !          1742:     printf("#   total  : %d\n", reqString);
        !          1743:     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
        !          1744:     printf("#   reused : %d\n", reString);
        !          1745:     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
        !          1746: 
        !          1747:     printf("# booleans\n");
        !          1748:     printf("#   total  : %d\n", reqBool);
        !          1749:     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
        !          1750:     printf("#   reused : %d\n", reBool);
        !          1751:     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
        !          1752: 
        !          1753:     printf("# numbers\n");
        !          1754:     printf("#   total  : %d\n", reqNumber);
        !          1755:     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
        !          1756:     printf("#   reused : %d\n", reNumber);
        !          1757:     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
        !          1758: 
        !          1759:     printf("# XSLT result tree fragments\n");
        !          1760:     printf("#   total  : %d\n", reqXSLTTree);
        !          1761:     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
        !          1762:     printf("#   reused : %d\n", reXSLTTree);
        !          1763:     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
        !          1764: 
        !          1765:     printf("# undefined\n");
        !          1766:     printf("#   total  : %d\n", reqUndefined);
        !          1767:     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
        !          1768:     printf("#   reused : %d\n", reUndefined);
        !          1769:     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
        !          1770: 
        !          1771: }
        !          1772: 
        !          1773: #endif /* XP_DEBUG_OBJ_USAGE */
        !          1774: 
        !          1775: #endif /* LIBXML_DEBUG_ENABLED */
        !          1776: 
        !          1777: /************************************************************************
        !          1778:  *                                                                     *
        !          1779:  *                     XPath object caching                            *
        !          1780:  *                                                                     *
        !          1781:  ************************************************************************/
        !          1782: 
        !          1783: /**
        !          1784:  * xmlXPathNewCache:
        !          1785:  *
        !          1786:  * Create a new object cache
        !          1787:  *
        !          1788:  * Returns the xmlXPathCache just allocated.
        !          1789:  */
        !          1790: static xmlXPathContextCachePtr
        !          1791: xmlXPathNewCache(void)
        !          1792: {
        !          1793:     xmlXPathContextCachePtr ret;
        !          1794: 
        !          1795:     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
        !          1796:     if (ret == NULL) {
        !          1797:         xmlXPathErrMemory(NULL, "creating object cache\n");
        !          1798:        return(NULL);
        !          1799:     }
        !          1800:     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
        !          1801:     ret->maxNodeset = 100;
        !          1802:     ret->maxString = 100;
        !          1803:     ret->maxBoolean = 100;
        !          1804:     ret->maxNumber = 100;
        !          1805:     ret->maxMisc = 100;
        !          1806:     return(ret);
        !          1807: }
        !          1808: 
        !          1809: static void
        !          1810: xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
        !          1811: {
        !          1812:     int i;
        !          1813:     xmlXPathObjectPtr obj;
        !          1814: 
        !          1815:     if (list == NULL)
        !          1816:        return;
        !          1817: 
        !          1818:     for (i = 0; i < list->number; i++) {
        !          1819:        obj = list->items[i];
        !          1820:        /*
        !          1821:        * Note that it is already assured that we don't need to
        !          1822:        * look out for namespace nodes in the node-set.
        !          1823:        */
        !          1824:        if (obj->nodesetval != NULL) {
        !          1825:            if (obj->nodesetval->nodeTab != NULL)
        !          1826:                xmlFree(obj->nodesetval->nodeTab);
        !          1827:            xmlFree(obj->nodesetval);
        !          1828:        }
        !          1829:        xmlFree(obj);
        !          1830: #ifdef XP_DEBUG_OBJ_USAGE
        !          1831:        xmlXPathDebugObjCounterAll--;
        !          1832: #endif
        !          1833:     }
        !          1834:     xmlPointerListFree(list);
        !          1835: }
        !          1836: 
        !          1837: static void
        !          1838: xmlXPathFreeCache(xmlXPathContextCachePtr cache)
        !          1839: {
        !          1840:     if (cache == NULL)
        !          1841:        return;
        !          1842:     if (cache->nodesetObjs)
        !          1843:        xmlXPathCacheFreeObjectList(cache->nodesetObjs);
        !          1844:     if (cache->stringObjs)
        !          1845:        xmlXPathCacheFreeObjectList(cache->stringObjs);
        !          1846:     if (cache->booleanObjs)
        !          1847:        xmlXPathCacheFreeObjectList(cache->booleanObjs);
        !          1848:     if (cache->numberObjs)
        !          1849:        xmlXPathCacheFreeObjectList(cache->numberObjs);
        !          1850:     if (cache->miscObjs)
        !          1851:        xmlXPathCacheFreeObjectList(cache->miscObjs);
        !          1852:     xmlFree(cache);
        !          1853: }
        !          1854: 
        !          1855: /**
        !          1856:  * xmlXPathContextSetCache:
        !          1857:  *
        !          1858:  * @ctxt:  the XPath context
        !          1859:  * @active: enables/disables (creates/frees) the cache
        !          1860:  * @value: a value with semantics dependant on @options
        !          1861:  * @options: options (currently only the value 0 is used)
        !          1862:  *
        !          1863:  * Creates/frees an object cache on the XPath context.
        !          1864:  * If activates XPath objects (xmlXPathObject) will be cached internally
        !          1865:  * to be reused.
        !          1866:  * @options:
        !          1867:  *   0: This will set the XPath object caching:
        !          1868:  *      @value:
        !          1869:  *        This will set the maximum number of XPath objects
        !          1870:  *        to be cached per slot
        !          1871:  *        There are 5 slots for: node-set, string, number, boolean, and
        !          1872:  *        misc objects. Use <0 for the default number (100).
        !          1873:  *   Other values for @options have currently no effect.
        !          1874:  *
        !          1875:  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
        !          1876:  */
        !          1877: int
        !          1878: xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
        !          1879:                        int active,
        !          1880:                        int value,
        !          1881:                        int options)
        !          1882: {
        !          1883:     if (ctxt == NULL)
        !          1884:        return(-1);
        !          1885:     if (active) {
        !          1886:        xmlXPathContextCachePtr cache;
        !          1887: 
        !          1888:        if (ctxt->cache == NULL) {
        !          1889:            ctxt->cache = xmlXPathNewCache();
        !          1890:            if (ctxt->cache == NULL)
        !          1891:                return(-1);
        !          1892:        }
        !          1893:        cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          1894:        if (options == 0) {
        !          1895:            if (value < 0)
        !          1896:                value = 100;
        !          1897:            cache->maxNodeset = value;
        !          1898:            cache->maxString = value;
        !          1899:            cache->maxNumber = value;
        !          1900:            cache->maxBoolean = value;
        !          1901:            cache->maxMisc = value;
        !          1902:        }
        !          1903:     } else if (ctxt->cache != NULL) {
        !          1904:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
        !          1905:        ctxt->cache = NULL;
        !          1906:     }
        !          1907:     return(0);
        !          1908: }
        !          1909: 
        !          1910: /**
        !          1911:  * xmlXPathCacheWrapNodeSet:
        !          1912:  * @ctxt: the XPath context
        !          1913:  * @val:  the NodePtr value
        !          1914:  *
        !          1915:  * This is the cached version of xmlXPathWrapNodeSet().
        !          1916:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
        !          1917:  *
        !          1918:  * Returns the created or reused object.
        !          1919:  */
        !          1920: static xmlXPathObjectPtr
        !          1921: xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
        !          1922: {
        !          1923:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
        !          1924:        xmlXPathContextCachePtr cache =
        !          1925:            (xmlXPathContextCachePtr) ctxt->cache;
        !          1926: 
        !          1927:        if ((cache->miscObjs != NULL) &&
        !          1928:            (cache->miscObjs->number != 0))
        !          1929:        {
        !          1930:            xmlXPathObjectPtr ret;
        !          1931: 
        !          1932:            ret = (xmlXPathObjectPtr)
        !          1933:                cache->miscObjs->items[--cache->miscObjs->number];
        !          1934:            ret->type = XPATH_NODESET;
        !          1935:            ret->nodesetval = val;
        !          1936: #ifdef XP_DEBUG_OBJ_USAGE
        !          1937:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
        !          1938: #endif
        !          1939:            return(ret);
        !          1940:        }
        !          1941:     }
        !          1942: 
        !          1943:     return(xmlXPathWrapNodeSet(val));
        !          1944: 
        !          1945: }
        !          1946: 
        !          1947: /**
        !          1948:  * xmlXPathCacheWrapString:
        !          1949:  * @ctxt: the XPath context
        !          1950:  * @val:  the xmlChar * value
        !          1951:  *
        !          1952:  * This is the cached version of xmlXPathWrapString().
        !          1953:  * Wraps the @val string into an XPath object.
        !          1954:  *
        !          1955:  * Returns the created or reused object.
        !          1956:  */
        !          1957: static xmlXPathObjectPtr
        !          1958: xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
        !          1959: {
        !          1960:     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
        !          1961:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          1962: 
        !          1963:        if ((cache->stringObjs != NULL) &&
        !          1964:            (cache->stringObjs->number != 0))
        !          1965:        {
        !          1966: 
        !          1967:            xmlXPathObjectPtr ret;
        !          1968: 
        !          1969:            ret = (xmlXPathObjectPtr)
        !          1970:                cache->stringObjs->items[--cache->stringObjs->number];
        !          1971:            ret->type = XPATH_STRING;
        !          1972:            ret->stringval = val;
        !          1973: #ifdef XP_DEBUG_OBJ_USAGE
        !          1974:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          1975: #endif
        !          1976:            return(ret);
        !          1977:        } else if ((cache->miscObjs != NULL) &&
        !          1978:            (cache->miscObjs->number != 0))
        !          1979:        {
        !          1980:            xmlXPathObjectPtr ret;
        !          1981:            /*
        !          1982:            * Fallback to misc-cache.
        !          1983:            */
        !          1984:            ret = (xmlXPathObjectPtr)
        !          1985:                cache->miscObjs->items[--cache->miscObjs->number];
        !          1986: 
        !          1987:            ret->type = XPATH_STRING;
        !          1988:            ret->stringval = val;
        !          1989: #ifdef XP_DEBUG_OBJ_USAGE
        !          1990:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          1991: #endif
        !          1992:            return(ret);
        !          1993:        }
        !          1994:     }
        !          1995:     return(xmlXPathWrapString(val));
        !          1996: }
        !          1997: 
        !          1998: /**
        !          1999:  * xmlXPathCacheNewNodeSet:
        !          2000:  * @ctxt: the XPath context
        !          2001:  * @val:  the NodePtr value
        !          2002:  *
        !          2003:  * This is the cached version of xmlXPathNewNodeSet().
        !          2004:  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
        !          2005:  * it with the single Node @val
        !          2006:  *
        !          2007:  * Returns the created or reused object.
        !          2008:  */
        !          2009: static xmlXPathObjectPtr
        !          2010: xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
        !          2011: {
        !          2012:     if ((ctxt != NULL) && (ctxt->cache)) {
        !          2013:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          2014: 
        !          2015:        if ((cache->nodesetObjs != NULL) &&
        !          2016:            (cache->nodesetObjs->number != 0))
        !          2017:        {
        !          2018:            xmlXPathObjectPtr ret;
        !          2019:            /*
        !          2020:            * Use the nodset-cache.
        !          2021:            */
        !          2022:            ret = (xmlXPathObjectPtr)
        !          2023:                cache->nodesetObjs->items[--cache->nodesetObjs->number];
        !          2024:            ret->type = XPATH_NODESET;
        !          2025:            ret->boolval = 0;
        !          2026:            if (val) {
        !          2027:                if ((ret->nodesetval->nodeMax == 0) ||
        !          2028:                    (val->type == XML_NAMESPACE_DECL))
        !          2029:                {
        !          2030:                    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
        !          2031:                } else {
        !          2032:                    ret->nodesetval->nodeTab[0] = val;
        !          2033:                    ret->nodesetval->nodeNr = 1;
        !          2034:                }
        !          2035:            }
        !          2036: #ifdef XP_DEBUG_OBJ_USAGE
        !          2037:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
        !          2038: #endif
        !          2039:            return(ret);
        !          2040:        } else if ((cache->miscObjs != NULL) &&
        !          2041:            (cache->miscObjs->number != 0))
        !          2042:        {
        !          2043:            xmlXPathObjectPtr ret;
        !          2044:            /*
        !          2045:            * Fallback to misc-cache.
        !          2046:            */
        !          2047: 
        !          2048:            ret = (xmlXPathObjectPtr)
        !          2049:                cache->miscObjs->items[--cache->miscObjs->number];
        !          2050: 
        !          2051:            ret->type = XPATH_NODESET;
        !          2052:            ret->boolval = 0;
        !          2053:            ret->nodesetval = xmlXPathNodeSetCreate(val);
        !          2054: #ifdef XP_DEBUG_OBJ_USAGE
        !          2055:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
        !          2056: #endif
        !          2057:            return(ret);
        !          2058:        }
        !          2059:     }
        !          2060:     return(xmlXPathNewNodeSet(val));
        !          2061: }
        !          2062: 
        !          2063: /**
        !          2064:  * xmlXPathCacheNewCString:
        !          2065:  * @ctxt: the XPath context
        !          2066:  * @val:  the char * value
        !          2067:  *
        !          2068:  * This is the cached version of xmlXPathNewCString().
        !          2069:  * Acquire an xmlXPathObjectPtr of type string and of value @val
        !          2070:  *
        !          2071:  * Returns the created or reused object.
        !          2072:  */
        !          2073: static xmlXPathObjectPtr
        !          2074: xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
        !          2075: {
        !          2076:     if ((ctxt != NULL) && (ctxt->cache)) {
        !          2077:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          2078: 
        !          2079:        if ((cache->stringObjs != NULL) &&
        !          2080:            (cache->stringObjs->number != 0))
        !          2081:        {
        !          2082:            xmlXPathObjectPtr ret;
        !          2083: 
        !          2084:            ret = (xmlXPathObjectPtr)
        !          2085:                cache->stringObjs->items[--cache->stringObjs->number];
        !          2086: 
        !          2087:            ret->type = XPATH_STRING;
        !          2088:            ret->stringval = xmlStrdup(BAD_CAST val);
        !          2089: #ifdef XP_DEBUG_OBJ_USAGE
        !          2090:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          2091: #endif
        !          2092:            return(ret);
        !          2093:        } else if ((cache->miscObjs != NULL) &&
        !          2094:            (cache->miscObjs->number != 0))
        !          2095:        {
        !          2096:            xmlXPathObjectPtr ret;
        !          2097: 
        !          2098:            ret = (xmlXPathObjectPtr)
        !          2099:                cache->miscObjs->items[--cache->miscObjs->number];
        !          2100: 
        !          2101:            ret->type = XPATH_STRING;
        !          2102:            ret->stringval = xmlStrdup(BAD_CAST val);
        !          2103: #ifdef XP_DEBUG_OBJ_USAGE
        !          2104:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          2105: #endif
        !          2106:            return(ret);
        !          2107:        }
        !          2108:     }
        !          2109:     return(xmlXPathNewCString(val));
        !          2110: }
        !          2111: 
        !          2112: /**
        !          2113:  * xmlXPathCacheNewString:
        !          2114:  * @ctxt: the XPath context
        !          2115:  * @val:  the xmlChar * value
        !          2116:  *
        !          2117:  * This is the cached version of xmlXPathNewString().
        !          2118:  * Acquire an xmlXPathObjectPtr of type string and of value @val
        !          2119:  *
        !          2120:  * Returns the created or reused object.
        !          2121:  */
        !          2122: static xmlXPathObjectPtr
        !          2123: xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
        !          2124: {
        !          2125:     if ((ctxt != NULL) && (ctxt->cache)) {
        !          2126:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          2127: 
        !          2128:        if ((cache->stringObjs != NULL) &&
        !          2129:            (cache->stringObjs->number != 0))
        !          2130:        {
        !          2131:            xmlXPathObjectPtr ret;
        !          2132: 
        !          2133:            ret = (xmlXPathObjectPtr)
        !          2134:                cache->stringObjs->items[--cache->stringObjs->number];
        !          2135:            ret->type = XPATH_STRING;
        !          2136:            if (val != NULL)
        !          2137:                ret->stringval = xmlStrdup(val);
        !          2138:            else
        !          2139:                ret->stringval = xmlStrdup((const xmlChar *)"");
        !          2140: #ifdef XP_DEBUG_OBJ_USAGE
        !          2141:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          2142: #endif
        !          2143:            return(ret);
        !          2144:        } else if ((cache->miscObjs != NULL) &&
        !          2145:            (cache->miscObjs->number != 0))
        !          2146:        {
        !          2147:            xmlXPathObjectPtr ret;
        !          2148: 
        !          2149:            ret = (xmlXPathObjectPtr)
        !          2150:                cache->miscObjs->items[--cache->miscObjs->number];
        !          2151: 
        !          2152:            ret->type = XPATH_STRING;
        !          2153:            if (val != NULL)
        !          2154:                ret->stringval = xmlStrdup(val);
        !          2155:            else
        !          2156:                ret->stringval = xmlStrdup((const xmlChar *)"");
        !          2157: #ifdef XP_DEBUG_OBJ_USAGE
        !          2158:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
        !          2159: #endif
        !          2160:            return(ret);
        !          2161:        }
        !          2162:     }
        !          2163:     return(xmlXPathNewString(val));
        !          2164: }
        !          2165: 
        !          2166: /**
        !          2167:  * xmlXPathCacheNewBoolean:
        !          2168:  * @ctxt: the XPath context
        !          2169:  * @val:  the boolean value
        !          2170:  *
        !          2171:  * This is the cached version of xmlXPathNewBoolean().
        !          2172:  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
        !          2173:  *
        !          2174:  * Returns the created or reused object.
        !          2175:  */
        !          2176: static xmlXPathObjectPtr
        !          2177: xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
        !          2178: {
        !          2179:     if ((ctxt != NULL) && (ctxt->cache)) {
        !          2180:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          2181: 
        !          2182:        if ((cache->booleanObjs != NULL) &&
        !          2183:            (cache->booleanObjs->number != 0))
        !          2184:        {
        !          2185:            xmlXPathObjectPtr ret;
        !          2186: 
        !          2187:            ret = (xmlXPathObjectPtr)
        !          2188:                cache->booleanObjs->items[--cache->booleanObjs->number];
        !          2189:            ret->type = XPATH_BOOLEAN;
        !          2190:            ret->boolval = (val != 0);
        !          2191: #ifdef XP_DEBUG_OBJ_USAGE
        !          2192:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
        !          2193: #endif
        !          2194:            return(ret);
        !          2195:        } else if ((cache->miscObjs != NULL) &&
        !          2196:            (cache->miscObjs->number != 0))
        !          2197:        {
        !          2198:            xmlXPathObjectPtr ret;
        !          2199: 
        !          2200:            ret = (xmlXPathObjectPtr)
        !          2201:                cache->miscObjs->items[--cache->miscObjs->number];
        !          2202: 
        !          2203:            ret->type = XPATH_BOOLEAN;
        !          2204:            ret->boolval = (val != 0);
        !          2205: #ifdef XP_DEBUG_OBJ_USAGE
        !          2206:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
        !          2207: #endif
        !          2208:            return(ret);
        !          2209:        }
        !          2210:     }
        !          2211:     return(xmlXPathNewBoolean(val));
        !          2212: }
        !          2213: 
        !          2214: /**
        !          2215:  * xmlXPathCacheNewFloat:
        !          2216:  * @ctxt: the XPath context
        !          2217:  * @val:  the double value
        !          2218:  *
        !          2219:  * This is the cached version of xmlXPathNewFloat().
        !          2220:  * Acquires an xmlXPathObjectPtr of type double and of value @val
        !          2221:  *
        !          2222:  * Returns the created or reused object.
        !          2223:  */
        !          2224: static xmlXPathObjectPtr
        !          2225: xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
        !          2226: {
        !          2227:      if ((ctxt != NULL) && (ctxt->cache)) {
        !          2228:        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
        !          2229: 
        !          2230:        if ((cache->numberObjs != NULL) &&
        !          2231:            (cache->numberObjs->number != 0))
        !          2232:        {
        !          2233:            xmlXPathObjectPtr ret;
        !          2234: 
        !          2235:            ret = (xmlXPathObjectPtr)
        !          2236:                cache->numberObjs->items[--cache->numberObjs->number];
        !          2237:            ret->type = XPATH_NUMBER;
        !          2238:            ret->floatval = val;
        !          2239: #ifdef XP_DEBUG_OBJ_USAGE
        !          2240:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
        !          2241: #endif
        !          2242:            return(ret);
        !          2243:        } else if ((cache->miscObjs != NULL) &&
        !          2244:            (cache->miscObjs->number != 0))
        !          2245:        {
        !          2246:            xmlXPathObjectPtr ret;
        !          2247: 
        !          2248:            ret = (xmlXPathObjectPtr)
        !          2249:                cache->miscObjs->items[--cache->miscObjs->number];
        !          2250: 
        !          2251:            ret->type = XPATH_NUMBER;
        !          2252:            ret->floatval = val;
        !          2253: #ifdef XP_DEBUG_OBJ_USAGE
        !          2254:            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
        !          2255: #endif
        !          2256:            return(ret);
        !          2257:        }
        !          2258:     }
        !          2259:     return(xmlXPathNewFloat(val));
        !          2260: }
        !          2261: 
        !          2262: /**
        !          2263:  * xmlXPathCacheConvertString:
        !          2264:  * @ctxt: the XPath context
        !          2265:  * @val:  an XPath object
        !          2266:  *
        !          2267:  * This is the cached version of xmlXPathConvertString().
        !          2268:  * Converts an existing object to its string() equivalent
        !          2269:  *
        !          2270:  * Returns a created or reused object, the old one is freed (cached)
        !          2271:  *         (or the operation is done directly on @val)
        !          2272:  */
        !          2273: 
        !          2274: static xmlXPathObjectPtr
        !          2275: xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
        !          2276:     xmlChar *res = NULL;
        !          2277: 
        !          2278:     if (val == NULL)
        !          2279:        return(xmlXPathCacheNewCString(ctxt, ""));
        !          2280: 
        !          2281:     switch (val->type) {
        !          2282:     case XPATH_UNDEFINED:
        !          2283: #ifdef DEBUG_EXPR
        !          2284:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
        !          2285: #endif
        !          2286:        break;
        !          2287:     case XPATH_NODESET:
        !          2288:     case XPATH_XSLT_TREE:
        !          2289:        res = xmlXPathCastNodeSetToString(val->nodesetval);
        !          2290:        break;
        !          2291:     case XPATH_STRING:
        !          2292:        return(val);
        !          2293:     case XPATH_BOOLEAN:
        !          2294:        res = xmlXPathCastBooleanToString(val->boolval);
        !          2295:        break;
        !          2296:     case XPATH_NUMBER:
        !          2297:        res = xmlXPathCastNumberToString(val->floatval);
        !          2298:        break;
        !          2299:     case XPATH_USERS:
        !          2300:     case XPATH_POINT:
        !          2301:     case XPATH_RANGE:
        !          2302:     case XPATH_LOCATIONSET:
        !          2303:        TODO;
        !          2304:        break;
        !          2305:     }
        !          2306:     xmlXPathReleaseObject(ctxt, val);
        !          2307:     if (res == NULL)
        !          2308:        return(xmlXPathCacheNewCString(ctxt, ""));
        !          2309:     return(xmlXPathCacheWrapString(ctxt, res));
        !          2310: }
        !          2311: 
        !          2312: /**
        !          2313:  * xmlXPathCacheObjectCopy:
        !          2314:  * @ctxt: the XPath context
        !          2315:  * @val:  the original object
        !          2316:  *
        !          2317:  * This is the cached version of xmlXPathObjectCopy().
        !          2318:  * Acquire a copy of a given object
        !          2319:  *
        !          2320:  * Returns a created or reused created object.
        !          2321:  */
        !          2322: static xmlXPathObjectPtr
        !          2323: xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
        !          2324: {
        !          2325:     if (val == NULL)
        !          2326:        return(NULL);
        !          2327: 
        !          2328:     if (XP_HAS_CACHE(ctxt)) {
        !          2329:        switch (val->type) {
        !          2330:            case XPATH_NODESET:
        !          2331:                return(xmlXPathCacheWrapNodeSet(ctxt,
        !          2332:                    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
        !          2333:            case XPATH_STRING:
        !          2334:                return(xmlXPathCacheNewString(ctxt, val->stringval));
        !          2335:            case XPATH_BOOLEAN:
        !          2336:                return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
        !          2337:            case XPATH_NUMBER:
        !          2338:                return(xmlXPathCacheNewFloat(ctxt, val->floatval));
        !          2339:            default:
        !          2340:                break;
        !          2341:        }
        !          2342:     }
        !          2343:     return(xmlXPathObjectCopy(val));
        !          2344: }
        !          2345: 
        !          2346: /**
        !          2347:  * xmlXPathCacheConvertBoolean:
        !          2348:  * @ctxt: the XPath context
        !          2349:  * @val:  an XPath object
        !          2350:  *
        !          2351:  * This is the cached version of xmlXPathConvertBoolean().
        !          2352:  * Converts an existing object to its boolean() equivalent
        !          2353:  *
        !          2354:  * Returns a created or reused object, the old one is freed (or the operation
        !          2355:  *         is done directly on @val)
        !          2356:  */
        !          2357: static xmlXPathObjectPtr
        !          2358: xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
        !          2359:     xmlXPathObjectPtr ret;
        !          2360: 
        !          2361:     if (val == NULL)
        !          2362:        return(xmlXPathCacheNewBoolean(ctxt, 0));
        !          2363:     if (val->type == XPATH_BOOLEAN)
        !          2364:        return(val);
        !          2365:     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
        !          2366:     xmlXPathReleaseObject(ctxt, val);
        !          2367:     return(ret);
        !          2368: }
        !          2369: 
        !          2370: /**
        !          2371:  * xmlXPathCacheConvertNumber:
        !          2372:  * @ctxt: the XPath context
        !          2373:  * @val:  an XPath object
        !          2374:  *
        !          2375:  * This is the cached version of xmlXPathConvertNumber().
        !          2376:  * Converts an existing object to its number() equivalent
        !          2377:  *
        !          2378:  * Returns a created or reused object, the old one is freed (or the operation
        !          2379:  *         is done directly on @val)
        !          2380:  */
        !          2381: static xmlXPathObjectPtr
        !          2382: xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
        !          2383:     xmlXPathObjectPtr ret;
        !          2384: 
        !          2385:     if (val == NULL)
        !          2386:        return(xmlXPathCacheNewFloat(ctxt, 0.0));
        !          2387:     if (val->type == XPATH_NUMBER)
        !          2388:        return(val);
        !          2389:     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
        !          2390:     xmlXPathReleaseObject(ctxt, val);
        !          2391:     return(ret);
        !          2392: }
        !          2393: 
        !          2394: /************************************************************************
        !          2395:  *                                                                     *
        !          2396:  *             Parser stacks related functions and macros              *
        !          2397:  *                                                                     *
        !          2398:  ************************************************************************/
        !          2399: 
        !          2400: /**
        !          2401:  * valuePop:
        !          2402:  * @ctxt: an XPath evaluation context
        !          2403:  *
        !          2404:  * Pops the top XPath object from the value stack
        !          2405:  *
        !          2406:  * Returns the XPath object just removed
        !          2407:  */
        !          2408: xmlXPathObjectPtr
        !          2409: valuePop(xmlXPathParserContextPtr ctxt)
        !          2410: {
        !          2411:     xmlXPathObjectPtr ret;
        !          2412: 
        !          2413:     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
        !          2414:         return (NULL);
        !          2415:     ctxt->valueNr--;
        !          2416:     if (ctxt->valueNr > 0)
        !          2417:         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
        !          2418:     else
        !          2419:         ctxt->value = NULL;
        !          2420:     ret = ctxt->valueTab[ctxt->valueNr];
        !          2421:     ctxt->valueTab[ctxt->valueNr] = NULL;
        !          2422:     return (ret);
        !          2423: }
        !          2424: /**
        !          2425:  * valuePush:
        !          2426:  * @ctxt:  an XPath evaluation context
        !          2427:  * @value:  the XPath object
        !          2428:  *
        !          2429:  * Pushes a new XPath object on top of the value stack
        !          2430:  *
        !          2431:  * returns the number of items on the value stack
        !          2432:  */
        !          2433: int
        !          2434: valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
        !          2435: {
        !          2436:     if ((ctxt == NULL) || (value == NULL)) return(-1);
        !          2437:     if (ctxt->valueNr >= ctxt->valueMax) {
        !          2438:         xmlXPathObjectPtr *tmp;
        !          2439: 
        !          2440:         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
        !          2441:                                              2 * ctxt->valueMax *
        !          2442:                                              sizeof(ctxt->valueTab[0]));
        !          2443:         if (tmp == NULL) {
        !          2444:             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
        !          2445:             return (0);
        !          2446:         }
        !          2447:         ctxt->valueMax *= 2;
        !          2448:        ctxt->valueTab = tmp;
        !          2449:     }
        !          2450:     ctxt->valueTab[ctxt->valueNr] = value;
        !          2451:     ctxt->value = value;
        !          2452:     return (ctxt->valueNr++);
        !          2453: }
        !          2454: 
        !          2455: /**
        !          2456:  * xmlXPathPopBoolean:
        !          2457:  * @ctxt:  an XPath parser context
        !          2458:  *
        !          2459:  * Pops a boolean from the stack, handling conversion if needed.
        !          2460:  * Check error with #xmlXPathCheckError.
        !          2461:  *
        !          2462:  * Returns the boolean
        !          2463:  */
        !          2464: int
        !          2465: xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
        !          2466:     xmlXPathObjectPtr obj;
        !          2467:     int ret;
        !          2468: 
        !          2469:     obj = valuePop(ctxt);
        !          2470:     if (obj == NULL) {
        !          2471:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
        !          2472:        return(0);
        !          2473:     }
        !          2474:     if (obj->type != XPATH_BOOLEAN)
        !          2475:        ret = xmlXPathCastToBoolean(obj);
        !          2476:     else
        !          2477:         ret = obj->boolval;
        !          2478:     xmlXPathReleaseObject(ctxt->context, obj);
        !          2479:     return(ret);
        !          2480: }
        !          2481: 
        !          2482: /**
        !          2483:  * xmlXPathPopNumber:
        !          2484:  * @ctxt:  an XPath parser context
        !          2485:  *
        !          2486:  * Pops a number from the stack, handling conversion if needed.
        !          2487:  * Check error with #xmlXPathCheckError.
        !          2488:  *
        !          2489:  * Returns the number
        !          2490:  */
        !          2491: double
        !          2492: xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
        !          2493:     xmlXPathObjectPtr obj;
        !          2494:     double ret;
        !          2495: 
        !          2496:     obj = valuePop(ctxt);
        !          2497:     if (obj == NULL) {
        !          2498:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
        !          2499:        return(0);
        !          2500:     }
        !          2501:     if (obj->type != XPATH_NUMBER)
        !          2502:        ret = xmlXPathCastToNumber(obj);
        !          2503:     else
        !          2504:         ret = obj->floatval;
        !          2505:     xmlXPathReleaseObject(ctxt->context, obj);
        !          2506:     return(ret);
        !          2507: }
        !          2508: 
        !          2509: /**
        !          2510:  * xmlXPathPopString:
        !          2511:  * @ctxt:  an XPath parser context
        !          2512:  *
        !          2513:  * Pops a string from the stack, handling conversion if needed.
        !          2514:  * Check error with #xmlXPathCheckError.
        !          2515:  *
        !          2516:  * Returns the string
        !          2517:  */
        !          2518: xmlChar *
        !          2519: xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
        !          2520:     xmlXPathObjectPtr obj;
        !          2521:     xmlChar * ret;
        !          2522: 
        !          2523:     obj = valuePop(ctxt);
        !          2524:     if (obj == NULL) {
        !          2525:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
        !          2526:        return(NULL);
        !          2527:     }
        !          2528:     ret = xmlXPathCastToString(obj);   /* this does required strdup */
        !          2529:     /* TODO: needs refactoring somewhere else */
        !          2530:     if (obj->stringval == ret)
        !          2531:        obj->stringval = NULL;
        !          2532:     xmlXPathReleaseObject(ctxt->context, obj);
        !          2533:     return(ret);
        !          2534: }
        !          2535: 
        !          2536: /**
        !          2537:  * xmlXPathPopNodeSet:
        !          2538:  * @ctxt:  an XPath parser context
        !          2539:  *
        !          2540:  * Pops a node-set from the stack, handling conversion if needed.
        !          2541:  * Check error with #xmlXPathCheckError.
        !          2542:  *
        !          2543:  * Returns the node-set
        !          2544:  */
        !          2545: xmlNodeSetPtr
        !          2546: xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
        !          2547:     xmlXPathObjectPtr obj;
        !          2548:     xmlNodeSetPtr ret;
        !          2549: 
        !          2550:     if (ctxt == NULL) return(NULL);
        !          2551:     if (ctxt->value == NULL) {
        !          2552:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
        !          2553:        return(NULL);
        !          2554:     }
        !          2555:     if (!xmlXPathStackIsNodeSet(ctxt)) {
        !          2556:        xmlXPathSetTypeError(ctxt);
        !          2557:        return(NULL);
        !          2558:     }
        !          2559:     obj = valuePop(ctxt);
        !          2560:     ret = obj->nodesetval;
        !          2561: #if 0
        !          2562:     /* to fix memory leak of not clearing obj->user */
        !          2563:     if (obj->boolval && obj->user != NULL)
        !          2564:         xmlFreeNodeList((xmlNodePtr) obj->user);
        !          2565: #endif
        !          2566:     obj->nodesetval = NULL;
        !          2567:     xmlXPathReleaseObject(ctxt->context, obj);
        !          2568:     return(ret);
        !          2569: }
        !          2570: 
        !          2571: /**
        !          2572:  * xmlXPathPopExternal:
        !          2573:  * @ctxt:  an XPath parser context
        !          2574:  *
        !          2575:  * Pops an external object from the stack, handling conversion if needed.
        !          2576:  * Check error with #xmlXPathCheckError.
        !          2577:  *
        !          2578:  * Returns the object
        !          2579:  */
        !          2580: void *
        !          2581: xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
        !          2582:     xmlXPathObjectPtr obj;
        !          2583:     void * ret;
        !          2584: 
        !          2585:     if ((ctxt == NULL) || (ctxt->value == NULL)) {
        !          2586:        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
        !          2587:        return(NULL);
        !          2588:     }
        !          2589:     if (ctxt->value->type != XPATH_USERS) {
        !          2590:        xmlXPathSetTypeError(ctxt);
        !          2591:        return(NULL);
        !          2592:     }
        !          2593:     obj = valuePop(ctxt);
        !          2594:     ret = obj->user;
        !          2595:     obj->user = NULL;
        !          2596:     xmlXPathReleaseObject(ctxt->context, obj);
        !          2597:     return(ret);
        !          2598: }
        !          2599: 
        !          2600: /*
        !          2601:  * Macros for accessing the content. Those should be used only by the parser,
        !          2602:  * and not exported.
        !          2603:  *
        !          2604:  * Dirty macros, i.e. one need to make assumption on the context to use them
        !          2605:  *
        !          2606:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
        !          2607:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
        !          2608:  *           in ISO-Latin or UTF-8.
        !          2609:  *           This should be used internally by the parser
        !          2610:  *           only to compare to ASCII values otherwise it would break when
        !          2611:  *           running with UTF-8 encoding.
        !          2612:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
        !          2613:  *           to compare on ASCII based substring.
        !          2614:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
        !          2615:  *           strings within the parser.
        !          2616:  *   CURRENT Returns the current char value, with the full decoding of
        !          2617:  *           UTF-8 if we are using this mode. It returns an int.
        !          2618:  *   NEXT    Skip to the next character, this does the proper decoding
        !          2619:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
        !          2620:  *           It returns the pointer to the current xmlChar.
        !          2621:  */
        !          2622: 
        !          2623: #define CUR (*ctxt->cur)
        !          2624: #define SKIP(val) ctxt->cur += (val)
        !          2625: #define NXT(val) ctxt->cur[(val)]
        !          2626: #define CUR_PTR ctxt->cur
        !          2627: #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
        !          2628: 
        !          2629: #define COPY_BUF(l,b,i,v)                                              \
        !          2630:     if (l == 1) b[i++] = (xmlChar) v;                                  \
        !          2631:     else i += xmlCopyChar(l,&b[i],v)
        !          2632: 
        !          2633: #define NEXTL(l)  ctxt->cur += l
        !          2634: 
        !          2635: #define SKIP_BLANKS                                                    \
        !          2636:     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
        !          2637: 
        !          2638: #define CURRENT (*ctxt->cur)
        !          2639: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
        !          2640: 
        !          2641: 
        !          2642: #ifndef DBL_DIG
        !          2643: #define DBL_DIG 16
        !          2644: #endif
        !          2645: #ifndef DBL_EPSILON
        !          2646: #define DBL_EPSILON 1E-9
        !          2647: #endif
        !          2648: 
        !          2649: #define UPPER_DOUBLE 1E9
        !          2650: #define LOWER_DOUBLE 1E-5
        !          2651: #define        LOWER_DOUBLE_EXP 5
        !          2652: 
        !          2653: #define INTEGER_DIGITS DBL_DIG
        !          2654: #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
        !          2655: #define EXPONENT_DIGITS (3 + 2)
        !          2656: 
        !          2657: /**
        !          2658:  * xmlXPathFormatNumber:
        !          2659:  * @number:     number to format
        !          2660:  * @buffer:     output buffer
        !          2661:  * @buffersize: size of output buffer
        !          2662:  *
        !          2663:  * Convert the number into a string representation.
        !          2664:  */
        !          2665: static void
        !          2666: xmlXPathFormatNumber(double number, char buffer[], int buffersize)
        !          2667: {
        !          2668:     switch (xmlXPathIsInf(number)) {
        !          2669:     case 1:
        !          2670:        if (buffersize > (int)sizeof("Infinity"))
        !          2671:            snprintf(buffer, buffersize, "Infinity");
        !          2672:        break;
        !          2673:     case -1:
        !          2674:        if (buffersize > (int)sizeof("-Infinity"))
        !          2675:            snprintf(buffer, buffersize, "-Infinity");
        !          2676:        break;
        !          2677:     default:
        !          2678:        if (xmlXPathIsNaN(number)) {
        !          2679:            if (buffersize > (int)sizeof("NaN"))
        !          2680:                snprintf(buffer, buffersize, "NaN");
        !          2681:        } else if (number == 0 && xmlXPathGetSign(number) != 0) {
        !          2682:            snprintf(buffer, buffersize, "0");
        !          2683:        } else if (number == ((int) number)) {
        !          2684:            char work[30];
        !          2685:            char *ptr, *cur;
        !          2686:            int value = (int) number;
        !          2687: 
        !          2688:             ptr = &buffer[0];
        !          2689:            if (value == 0) {
        !          2690:                *ptr++ = '0';
        !          2691:            } else {
        !          2692:                snprintf(work, 29, "%d", value);
        !          2693:                cur = &work[0];
        !          2694:                while ((*cur) && (ptr - buffer < buffersize)) {
        !          2695:                    *ptr++ = *cur++;
        !          2696:                }
        !          2697:            }
        !          2698:            if (ptr - buffer < buffersize) {
        !          2699:                *ptr = 0;
        !          2700:            } else if (buffersize > 0) {
        !          2701:                ptr--;
        !          2702:                *ptr = 0;
        !          2703:            }
        !          2704:        } else {
        !          2705:            /*
        !          2706:              For the dimension of work,
        !          2707:                  DBL_DIG is number of significant digits
        !          2708:                  EXPONENT is only needed for "scientific notation"
        !          2709:                  3 is sign, decimal point, and terminating zero
        !          2710:                  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
        !          2711:              Note that this dimension is slightly (a few characters)
        !          2712:              larger than actually necessary.
        !          2713:            */
        !          2714:            char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
        !          2715:            int integer_place, fraction_place;
        !          2716:            char *ptr;
        !          2717:            char *after_fraction;
        !          2718:            double absolute_value;
        !          2719:            int size;
        !          2720: 
        !          2721:            absolute_value = fabs(number);
        !          2722: 
        !          2723:            /*
        !          2724:             * First choose format - scientific or regular floating point.
        !          2725:             * In either case, result is in work, and after_fraction points
        !          2726:             * just past the fractional part.
        !          2727:            */
        !          2728:            if ( ((absolute_value > UPPER_DOUBLE) ||
        !          2729:                  (absolute_value < LOWER_DOUBLE)) &&
        !          2730:                 (absolute_value != 0.0) ) {
        !          2731:                /* Use scientific notation */
        !          2732:                integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
        !          2733:                fraction_place = DBL_DIG - 1;
        !          2734:                size = snprintf(work, sizeof(work),"%*.*e",
        !          2735:                         integer_place, fraction_place, number);
        !          2736:                while ((size > 0) && (work[size] != 'e')) size--;
        !          2737: 
        !          2738:            }
        !          2739:            else {
        !          2740:                /* Use regular notation */
        !          2741:                if (absolute_value > 0.0) {
        !          2742:                    integer_place = (int)log10(absolute_value);
        !          2743:                    if (integer_place > 0)
        !          2744:                        fraction_place = DBL_DIG - integer_place - 1;
        !          2745:                    else
        !          2746:                        fraction_place = DBL_DIG - integer_place;
        !          2747:                } else {
        !          2748:                    fraction_place = 1;
        !          2749:                }
        !          2750:                size = snprintf(work, sizeof(work), "%0.*f",
        !          2751:                                fraction_place, number);
        !          2752:            }
        !          2753: 
        !          2754:            /* Remove fractional trailing zeroes */
        !          2755:            after_fraction = work + size;
        !          2756:            ptr = after_fraction;
        !          2757:            while (*(--ptr) == '0')
        !          2758:                ;
        !          2759:            if (*ptr != '.')
        !          2760:                ptr++;
        !          2761:            while ((*ptr++ = *after_fraction++) != 0);
        !          2762: 
        !          2763:            /* Finally copy result back to caller */
        !          2764:            size = strlen(work) + 1;
        !          2765:            if (size > buffersize) {
        !          2766:                work[buffersize - 1] = 0;
        !          2767:                size = buffersize;
        !          2768:            }
        !          2769:            memmove(buffer, work, size);
        !          2770:        }
        !          2771:        break;
        !          2772:     }
        !          2773: }
        !          2774: 
        !          2775: 
        !          2776: /************************************************************************
        !          2777:  *                                                                     *
        !          2778:  *                     Routines to handle NodeSets                     *
        !          2779:  *                                                                     *
        !          2780:  ************************************************************************/
        !          2781: 
        !          2782: /**
        !          2783:  * xmlXPathOrderDocElems:
        !          2784:  * @doc:  an input document
        !          2785:  *
        !          2786:  * Call this routine to speed up XPath computation on static documents.
        !          2787:  * This stamps all the element nodes with the document order
        !          2788:  * Like for line information, the order is kept in the element->content
        !          2789:  * field, the value stored is actually - the node number (starting at -1)
        !          2790:  * to be able to differentiate from line numbers.
        !          2791:  *
        !          2792:  * Returns the number of elements found in the document or -1 in case
        !          2793:  *    of error.
        !          2794:  */
        !          2795: long
        !          2796: xmlXPathOrderDocElems(xmlDocPtr doc) {
        !          2797:     long count = 0;
        !          2798:     xmlNodePtr cur;
        !          2799: 
        !          2800:     if (doc == NULL)
        !          2801:        return(-1);
        !          2802:     cur = doc->children;
        !          2803:     while (cur != NULL) {
        !          2804:        if (cur->type == XML_ELEMENT_NODE) {
        !          2805:            cur->content = (void *) (-(++count));
        !          2806:            if (cur->children != NULL) {
        !          2807:                cur = cur->children;
        !          2808:                continue;
        !          2809:            }
        !          2810:        }
        !          2811:        if (cur->next != NULL) {
        !          2812:            cur = cur->next;
        !          2813:            continue;
        !          2814:        }
        !          2815:        do {
        !          2816:            cur = cur->parent;
        !          2817:            if (cur == NULL)
        !          2818:                break;
        !          2819:            if (cur == (xmlNodePtr) doc) {
        !          2820:                cur = NULL;
        !          2821:                break;
        !          2822:            }
        !          2823:            if (cur->next != NULL) {
        !          2824:                cur = cur->next;
        !          2825:                break;
        !          2826:            }
        !          2827:        } while (cur != NULL);
        !          2828:     }
        !          2829:     return(count);
        !          2830: }
        !          2831: 
        !          2832: /**
        !          2833:  * xmlXPathCmpNodes:
        !          2834:  * @node1:  the first node
        !          2835:  * @node2:  the second node
        !          2836:  *
        !          2837:  * Compare two nodes w.r.t document order
        !          2838:  *
        !          2839:  * Returns -2 in case of error 1 if first point < second point, 0 if
        !          2840:  *         it's the same node, -1 otherwise
        !          2841:  */
        !          2842: int
        !          2843: xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
        !          2844:     int depth1, depth2;
        !          2845:     int attr1 = 0, attr2 = 0;
        !          2846:     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
        !          2847:     xmlNodePtr cur, root;
        !          2848: 
        !          2849:     if ((node1 == NULL) || (node2 == NULL))
        !          2850:        return(-2);
        !          2851:     /*
        !          2852:      * a couple of optimizations which will avoid computations in most cases
        !          2853:      */
        !          2854:     if (node1 == node2)                /* trivial case */
        !          2855:        return(0);
        !          2856:     if (node1->type == XML_ATTRIBUTE_NODE) {
        !          2857:        attr1 = 1;
        !          2858:        attrNode1 = node1;
        !          2859:        node1 = node1->parent;
        !          2860:     }
        !          2861:     if (node2->type == XML_ATTRIBUTE_NODE) {
        !          2862:        attr2 = 1;
        !          2863:        attrNode2 = node2;
        !          2864:        node2 = node2->parent;
        !          2865:     }
        !          2866:     if (node1 == node2) {
        !          2867:        if (attr1 == attr2) {
        !          2868:            /* not required, but we keep attributes in order */
        !          2869:            if (attr1 != 0) {
        !          2870:                cur = attrNode2->prev;
        !          2871:                while (cur != NULL) {
        !          2872:                    if (cur == attrNode1)
        !          2873:                        return (1);
        !          2874:                    cur = cur->prev;
        !          2875:                }
        !          2876:                return (-1);
        !          2877:            }
        !          2878:            return(0);
        !          2879:        }
        !          2880:        if (attr2 == 1)
        !          2881:            return(1);
        !          2882:        return(-1);
        !          2883:     }
        !          2884:     if ((node1->type == XML_NAMESPACE_DECL) ||
        !          2885:         (node2->type == XML_NAMESPACE_DECL))
        !          2886:        return(1);
        !          2887:     if (node1 == node2->prev)
        !          2888:        return(1);
        !          2889:     if (node1 == node2->next)
        !          2890:        return(-1);
        !          2891: 
        !          2892:     /*
        !          2893:      * Speedup using document order if availble.
        !          2894:      */
        !          2895:     if ((node1->type == XML_ELEMENT_NODE) &&
        !          2896:        (node2->type == XML_ELEMENT_NODE) &&
        !          2897:        (0 > (long) node1->content) &&
        !          2898:        (0 > (long) node2->content) &&
        !          2899:        (node1->doc == node2->doc)) {
        !          2900:        long l1, l2;
        !          2901: 
        !          2902:        l1 = -((long) node1->content);
        !          2903:        l2 = -((long) node2->content);
        !          2904:        if (l1 < l2)
        !          2905:            return(1);
        !          2906:        if (l1 > l2)
        !          2907:            return(-1);
        !          2908:     }
        !          2909: 
        !          2910:     /*
        !          2911:      * compute depth to root
        !          2912:      */
        !          2913:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
        !          2914:        if (cur == node1)
        !          2915:            return(1);
        !          2916:        depth2++;
        !          2917:     }
        !          2918:     root = cur;
        !          2919:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
        !          2920:        if (cur == node2)
        !          2921:            return(-1);
        !          2922:        depth1++;
        !          2923:     }
        !          2924:     /*
        !          2925:      * Distinct document (or distinct entities :-( ) case.
        !          2926:      */
        !          2927:     if (root != cur) {
        !          2928:        return(-2);
        !          2929:     }
        !          2930:     /*
        !          2931:      * get the nearest common ancestor.
        !          2932:      */
        !          2933:     while (depth1 > depth2) {
        !          2934:        depth1--;
        !          2935:        node1 = node1->parent;
        !          2936:     }
        !          2937:     while (depth2 > depth1) {
        !          2938:        depth2--;
        !          2939:        node2 = node2->parent;
        !          2940:     }
        !          2941:     while (node1->parent != node2->parent) {
        !          2942:        node1 = node1->parent;
        !          2943:        node2 = node2->parent;
        !          2944:        /* should not happen but just in case ... */
        !          2945:        if ((node1 == NULL) || (node2 == NULL))
        !          2946:            return(-2);
        !          2947:     }
        !          2948:     /*
        !          2949:      * Find who's first.
        !          2950:      */
        !          2951:     if (node1 == node2->prev)
        !          2952:        return(1);
        !          2953:     if (node1 == node2->next)
        !          2954:        return(-1);
        !          2955:     /*
        !          2956:      * Speedup using document order if availble.
        !          2957:      */
        !          2958:     if ((node1->type == XML_ELEMENT_NODE) &&
        !          2959:        (node2->type == XML_ELEMENT_NODE) &&
        !          2960:        (0 > (long) node1->content) &&
        !          2961:        (0 > (long) node2->content) &&
        !          2962:        (node1->doc == node2->doc)) {
        !          2963:        long l1, l2;
        !          2964: 
        !          2965:        l1 = -((long) node1->content);
        !          2966:        l2 = -((long) node2->content);
        !          2967:        if (l1 < l2)
        !          2968:            return(1);
        !          2969:        if (l1 > l2)
        !          2970:            return(-1);
        !          2971:     }
        !          2972: 
        !          2973:     for (cur = node1->next;cur != NULL;cur = cur->next)
        !          2974:        if (cur == node2)
        !          2975:            return(1);
        !          2976:     return(-1); /* assume there is no sibling list corruption */
        !          2977: }
        !          2978: 
        !          2979: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
        !          2980: /**
        !          2981:  * xmlXPathCmpNodesExt:
        !          2982:  * @node1:  the first node
        !          2983:  * @node2:  the second node
        !          2984:  *
        !          2985:  * Compare two nodes w.r.t document order.
        !          2986:  * This one is optimized for handling of non-element nodes.
        !          2987:  *
        !          2988:  * Returns -2 in case of error 1 if first point < second point, 0 if
        !          2989:  *         it's the same node, -1 otherwise
        !          2990:  */
        !          2991: static int
        !          2992: xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
        !          2993:     int depth1, depth2;
        !          2994:     int misc = 0, precedence1 = 0, precedence2 = 0;
        !          2995:     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
        !          2996:     xmlNodePtr cur, root;
        !          2997:     long l1, l2;
        !          2998: 
        !          2999:     if ((node1 == NULL) || (node2 == NULL))
        !          3000:        return(-2);
        !          3001: 
        !          3002:     if (node1 == node2)
        !          3003:        return(0);
        !          3004: 
        !          3005:     /*
        !          3006:      * a couple of optimizations which will avoid computations in most cases
        !          3007:      */
        !          3008:     switch (node1->type) {
        !          3009:        case XML_ELEMENT_NODE:
        !          3010:            if (node2->type == XML_ELEMENT_NODE) {
        !          3011:                if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
        !          3012:                    (0 > (long) node2->content) &&
        !          3013:                    (node1->doc == node2->doc))
        !          3014:                {
        !          3015:                    l1 = -((long) node1->content);
        !          3016:                    l2 = -((long) node2->content);
        !          3017:                    if (l1 < l2)
        !          3018:                        return(1);
        !          3019:                    if (l1 > l2)
        !          3020:                        return(-1);
        !          3021:                } else
        !          3022:                    goto turtle_comparison;
        !          3023:            }
        !          3024:            break;
        !          3025:        case XML_ATTRIBUTE_NODE:
        !          3026:            precedence1 = 1; /* element is owner */
        !          3027:            miscNode1 = node1;
        !          3028:            node1 = node1->parent;
        !          3029:            misc = 1;
        !          3030:            break;
        !          3031:        case XML_TEXT_NODE:
        !          3032:        case XML_CDATA_SECTION_NODE:
        !          3033:        case XML_COMMENT_NODE:
        !          3034:        case XML_PI_NODE: {
        !          3035:            miscNode1 = node1;
        !          3036:            /*
        !          3037:            * Find nearest element node.
        !          3038:            */
        !          3039:            if (node1->prev != NULL) {
        !          3040:                do {
        !          3041:                    node1 = node1->prev;
        !          3042:                    if (node1->type == XML_ELEMENT_NODE) {
        !          3043:                        precedence1 = 3; /* element in prev-sibl axis */
        !          3044:                        break;
        !          3045:                    }
        !          3046:                    if (node1->prev == NULL) {
        !          3047:                        precedence1 = 2; /* element is parent */
        !          3048:                        /*
        !          3049:                        * URGENT TODO: Are there any cases, where the
        !          3050:                        * parent of such a node is not an element node?
        !          3051:                        */
        !          3052:                        node1 = node1->parent;
        !          3053:                        break;
        !          3054:                    }
        !          3055:                } while (1);
        !          3056:            } else {
        !          3057:                precedence1 = 2; /* element is parent */
        !          3058:                node1 = node1->parent;
        !          3059:            }
        !          3060:            if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
        !          3061:                (0 <= (long) node1->content)) {
        !          3062:                /*
        !          3063:                * Fallback for whatever case.
        !          3064:                */
        !          3065:                node1 = miscNode1;
        !          3066:                precedence1 = 0;
        !          3067:            } else
        !          3068:                misc = 1;
        !          3069:        }
        !          3070:            break;
        !          3071:        case XML_NAMESPACE_DECL:
        !          3072:            /*
        !          3073:            * TODO: why do we return 1 for namespace nodes?
        !          3074:            */
        !          3075:            return(1);
        !          3076:        default:
        !          3077:            break;
        !          3078:     }
        !          3079:     switch (node2->type) {
        !          3080:        case XML_ELEMENT_NODE:
        !          3081:            break;
        !          3082:        case XML_ATTRIBUTE_NODE:
        !          3083:            precedence2 = 1; /* element is owner */
        !          3084:            miscNode2 = node2;
        !          3085:            node2 = node2->parent;
        !          3086:            misc = 1;
        !          3087:            break;
        !          3088:        case XML_TEXT_NODE:
        !          3089:        case XML_CDATA_SECTION_NODE:
        !          3090:        case XML_COMMENT_NODE:
        !          3091:        case XML_PI_NODE: {
        !          3092:            miscNode2 = node2;
        !          3093:            if (node2->prev != NULL) {
        !          3094:                do {
        !          3095:                    node2 = node2->prev;
        !          3096:                    if (node2->type == XML_ELEMENT_NODE) {
        !          3097:                        precedence2 = 3; /* element in prev-sibl axis */
        !          3098:                        break;
        !          3099:                    }
        !          3100:                    if (node2->prev == NULL) {
        !          3101:                        precedence2 = 2; /* element is parent */
        !          3102:                        node2 = node2->parent;
        !          3103:                        break;
        !          3104:                    }
        !          3105:                } while (1);
        !          3106:            } else {
        !          3107:                precedence2 = 2; /* element is parent */
        !          3108:                node2 = node2->parent;
        !          3109:            }
        !          3110:            if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
        !          3111:                (0 <= (long) node1->content))
        !          3112:            {
        !          3113:                node2 = miscNode2;
        !          3114:                precedence2 = 0;
        !          3115:            } else
        !          3116:                misc = 1;
        !          3117:        }
        !          3118:            break;
        !          3119:        case XML_NAMESPACE_DECL:
        !          3120:            return(1);
        !          3121:        default:
        !          3122:            break;
        !          3123:     }
        !          3124:     if (misc) {
        !          3125:        if (node1 == node2) {
        !          3126:            if (precedence1 == precedence2) {
        !          3127:                /*
        !          3128:                * The ugly case; but normally there aren't many
        !          3129:                * adjacent non-element nodes around.
        !          3130:                */
        !          3131:                cur = miscNode2->prev;
        !          3132:                while (cur != NULL) {
        !          3133:                    if (cur == miscNode1)
        !          3134:                        return(1);
        !          3135:                    if (cur->type == XML_ELEMENT_NODE)
        !          3136:                        return(-1);
        !          3137:                    cur = cur->prev;
        !          3138:                }
        !          3139:                return (-1);
        !          3140:            } else {
        !          3141:                /*
        !          3142:                * Evaluate based on higher precedence wrt to the element.
        !          3143:                * TODO: This assumes attributes are sorted before content.
        !          3144:                *   Is this 100% correct?
        !          3145:                */
        !          3146:                if (precedence1 < precedence2)
        !          3147:                    return(1);
        !          3148:                else
        !          3149:                    return(-1);
        !          3150:            }
        !          3151:        }
        !          3152:        /*
        !          3153:        * Special case: One of the helper-elements is contained by the other.
        !          3154:        * <foo>
        !          3155:        *   <node2>
        !          3156:        *     <node1>Text-1(precedence1 == 2)</node1>
        !          3157:        *   </node2>
        !          3158:        *   Text-6(precedence2 == 3)
        !          3159:        * </foo>
        !          3160:        */
        !          3161:        if ((precedence2 == 3) && (precedence1 > 1)) {
        !          3162:            cur = node1->parent;
        !          3163:            while (cur) {
        !          3164:                if (cur == node2)
        !          3165:                    return(1);
        !          3166:                cur = cur->parent;
        !          3167:            }
        !          3168:        }
        !          3169:        if ((precedence1 == 3) && (precedence2 > 1)) {
        !          3170:            cur = node2->parent;
        !          3171:            while (cur) {
        !          3172:                if (cur == node1)
        !          3173:                    return(-1);
        !          3174:                cur = cur->parent;
        !          3175:            }
        !          3176:        }
        !          3177:     }
        !          3178: 
        !          3179:     /*
        !          3180:      * Speedup using document order if availble.
        !          3181:      */
        !          3182:     if ((node1->type == XML_ELEMENT_NODE) &&
        !          3183:        (node2->type == XML_ELEMENT_NODE) &&
        !          3184:        (0 > (long) node1->content) &&
        !          3185:        (0 > (long) node2->content) &&
        !          3186:        (node1->doc == node2->doc)) {
        !          3187: 
        !          3188:        l1 = -((long) node1->content);
        !          3189:        l2 = -((long) node2->content);
        !          3190:        if (l1 < l2)
        !          3191:            return(1);
        !          3192:        if (l1 > l2)
        !          3193:            return(-1);
        !          3194:     }
        !          3195: 
        !          3196: turtle_comparison:
        !          3197: 
        !          3198:     if (node1 == node2->prev)
        !          3199:        return(1);
        !          3200:     if (node1 == node2->next)
        !          3201:        return(-1);
        !          3202:     /*
        !          3203:      * compute depth to root
        !          3204:      */
        !          3205:     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
        !          3206:        if (cur == node1)
        !          3207:            return(1);
        !          3208:        depth2++;
        !          3209:     }
        !          3210:     root = cur;
        !          3211:     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
        !          3212:        if (cur == node2)
        !          3213:            return(-1);
        !          3214:        depth1++;
        !          3215:     }
        !          3216:     /*
        !          3217:      * Distinct document (or distinct entities :-( ) case.
        !          3218:      */
        !          3219:     if (root != cur) {
        !          3220:        return(-2);
        !          3221:     }
        !          3222:     /*
        !          3223:      * get the nearest common ancestor.
        !          3224:      */
        !          3225:     while (depth1 > depth2) {
        !          3226:        depth1--;
        !          3227:        node1 = node1->parent;
        !          3228:     }
        !          3229:     while (depth2 > depth1) {
        !          3230:        depth2--;
        !          3231:        node2 = node2->parent;
        !          3232:     }
        !          3233:     while (node1->parent != node2->parent) {
        !          3234:        node1 = node1->parent;
        !          3235:        node2 = node2->parent;
        !          3236:        /* should not happen but just in case ... */
        !          3237:        if ((node1 == NULL) || (node2 == NULL))
        !          3238:            return(-2);
        !          3239:     }
        !          3240:     /*
        !          3241:      * Find who's first.
        !          3242:      */
        !          3243:     if (node1 == node2->prev)
        !          3244:        return(1);
        !          3245:     if (node1 == node2->next)
        !          3246:        return(-1);
        !          3247:     /*
        !          3248:      * Speedup using document order if availble.
        !          3249:      */
        !          3250:     if ((node1->type == XML_ELEMENT_NODE) &&
        !          3251:        (node2->type == XML_ELEMENT_NODE) &&
        !          3252:        (0 > (long) node1->content) &&
        !          3253:        (0 > (long) node2->content) &&
        !          3254:        (node1->doc == node2->doc)) {
        !          3255: 
        !          3256:        l1 = -((long) node1->content);
        !          3257:        l2 = -((long) node2->content);
        !          3258:        if (l1 < l2)
        !          3259:            return(1);
        !          3260:        if (l1 > l2)
        !          3261:            return(-1);
        !          3262:     }
        !          3263: 
        !          3264:     for (cur = node1->next;cur != NULL;cur = cur->next)
        !          3265:        if (cur == node2)
        !          3266:            return(1);
        !          3267:     return(-1); /* assume there is no sibling list corruption */
        !          3268: }
        !          3269: #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
        !          3270: 
        !          3271: /**
        !          3272:  * xmlXPathNodeSetSort:
        !          3273:  * @set:  the node set
        !          3274:  *
        !          3275:  * Sort the node set in document order
        !          3276:  */
        !          3277: void
        !          3278: xmlXPathNodeSetSort(xmlNodeSetPtr set) {
        !          3279:     int i, j, incr, len;
        !          3280:     xmlNodePtr tmp;
        !          3281: 
        !          3282:     if (set == NULL)
        !          3283:        return;
        !          3284: 
        !          3285:     /* Use Shell's sort to sort the node-set */
        !          3286:     len = set->nodeNr;
        !          3287:     for (incr = len / 2; incr > 0; incr /= 2) {
        !          3288:        for (i = incr; i < len; i++) {
        !          3289:            j = i - incr;
        !          3290:            while (j >= 0) {
        !          3291: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
        !          3292:                if (xmlXPathCmpNodesExt(set->nodeTab[j],
        !          3293:                        set->nodeTab[j + incr]) == -1)
        !          3294: #else
        !          3295:                if (xmlXPathCmpNodes(set->nodeTab[j],
        !          3296:                        set->nodeTab[j + incr]) == -1)
        !          3297: #endif
        !          3298:                {
        !          3299:                    tmp = set->nodeTab[j];
        !          3300:                    set->nodeTab[j] = set->nodeTab[j + incr];
        !          3301:                    set->nodeTab[j + incr] = tmp;
        !          3302:                    j -= incr;
        !          3303:                } else
        !          3304:                    break;
        !          3305:            }
        !          3306:        }
        !          3307:     }
        !          3308: }
        !          3309: 
        !          3310: #define XML_NODESET_DEFAULT    10
        !          3311: /**
        !          3312:  * xmlXPathNodeSetDupNs:
        !          3313:  * @node:  the parent node of the namespace XPath node
        !          3314:  * @ns:  the libxml namespace declaration node.
        !          3315:  *
        !          3316:  * Namespace node in libxml don't match the XPath semantic. In a node set
        !          3317:  * the namespace nodes are duplicated and the next pointer is set to the
        !          3318:  * parent node in the XPath semantic.
        !          3319:  *
        !          3320:  * Returns the newly created object.
        !          3321:  */
        !          3322: static xmlNodePtr
        !          3323: xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
        !          3324:     xmlNsPtr cur;
        !          3325: 
        !          3326:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
        !          3327:        return(NULL);
        !          3328:     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
        !          3329:        return((xmlNodePtr) ns);
        !          3330: 
        !          3331:     /*
        !          3332:      * Allocate a new Namespace and fill the fields.
        !          3333:      */
        !          3334:     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
        !          3335:     if (cur == NULL) {
        !          3336:         xmlXPathErrMemory(NULL, "duplicating namespace\n");
        !          3337:        return(NULL);
        !          3338:     }
        !          3339:     memset(cur, 0, sizeof(xmlNs));
        !          3340:     cur->type = XML_NAMESPACE_DECL;
        !          3341:     if (ns->href != NULL)
        !          3342:        cur->href = xmlStrdup(ns->href);
        !          3343:     if (ns->prefix != NULL)
        !          3344:        cur->prefix = xmlStrdup(ns->prefix);
        !          3345:     cur->next = (xmlNsPtr) node;
        !          3346:     return((xmlNodePtr) cur);
        !          3347: }
        !          3348: 
        !          3349: /**
        !          3350:  * xmlXPathNodeSetFreeNs:
        !          3351:  * @ns:  the XPath namespace node found in a nodeset.
        !          3352:  *
        !          3353:  * Namespace nodes in libxml don't match the XPath semantic. In a node set
        !          3354:  * the namespace nodes are duplicated and the next pointer is set to the
        !          3355:  * parent node in the XPath semantic. Check if such a node needs to be freed
        !          3356:  */
        !          3357: void
        !          3358: xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
        !          3359:     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
        !          3360:        return;
        !          3361: 
        !          3362:     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
        !          3363:        if (ns->href != NULL)
        !          3364:            xmlFree((xmlChar *)ns->href);
        !          3365:        if (ns->prefix != NULL)
        !          3366:            xmlFree((xmlChar *)ns->prefix);
        !          3367:        xmlFree(ns);
        !          3368:     }
        !          3369: }
        !          3370: 
        !          3371: /**
        !          3372:  * xmlXPathNodeSetCreate:
        !          3373:  * @val:  an initial xmlNodePtr, or NULL
        !          3374:  *
        !          3375:  * Create a new xmlNodeSetPtr of type double and of value @val
        !          3376:  *
        !          3377:  * Returns the newly created object.
        !          3378:  */
        !          3379: xmlNodeSetPtr
        !          3380: xmlXPathNodeSetCreate(xmlNodePtr val) {
        !          3381:     xmlNodeSetPtr ret;
        !          3382: 
        !          3383:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
        !          3384:     if (ret == NULL) {
        !          3385:         xmlXPathErrMemory(NULL, "creating nodeset\n");
        !          3386:        return(NULL);
        !          3387:     }
        !          3388:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
        !          3389:     if (val != NULL) {
        !          3390:         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3391:                                             sizeof(xmlNodePtr));
        !          3392:        if (ret->nodeTab == NULL) {
        !          3393:            xmlXPathErrMemory(NULL, "creating nodeset\n");
        !          3394:            xmlFree(ret);
        !          3395:            return(NULL);
        !          3396:        }
        !          3397:        memset(ret->nodeTab, 0 ,
        !          3398:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3399:         ret->nodeMax = XML_NODESET_DEFAULT;
        !          3400:        if (val->type == XML_NAMESPACE_DECL) {
        !          3401:            xmlNsPtr ns = (xmlNsPtr) val;
        !          3402: 
        !          3403:            ret->nodeTab[ret->nodeNr++] =
        !          3404:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3405:        } else
        !          3406:            ret->nodeTab[ret->nodeNr++] = val;
        !          3407:     }
        !          3408:     return(ret);
        !          3409: }
        !          3410: 
        !          3411: /**
        !          3412:  * xmlXPathNodeSetCreateSize:
        !          3413:  * @size:  the initial size of the set
        !          3414:  *
        !          3415:  * Create a new xmlNodeSetPtr of type double and of value @val
        !          3416:  *
        !          3417:  * Returns the newly created object.
        !          3418:  */
        !          3419: static xmlNodeSetPtr
        !          3420: xmlXPathNodeSetCreateSize(int size) {
        !          3421:     xmlNodeSetPtr ret;
        !          3422: 
        !          3423:     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
        !          3424:     if (ret == NULL) {
        !          3425:         xmlXPathErrMemory(NULL, "creating nodeset\n");
        !          3426:        return(NULL);
        !          3427:     }
        !          3428:     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
        !          3429:     if (size < XML_NODESET_DEFAULT)
        !          3430:        size = XML_NODESET_DEFAULT;
        !          3431:     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
        !          3432:     if (ret->nodeTab == NULL) {
        !          3433:        xmlXPathErrMemory(NULL, "creating nodeset\n");
        !          3434:        xmlFree(ret);
        !          3435:        return(NULL);
        !          3436:     }
        !          3437:     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
        !          3438:     ret->nodeMax = size;
        !          3439:     return(ret);
        !          3440: }
        !          3441: 
        !          3442: /**
        !          3443:  * xmlXPathNodeSetContains:
        !          3444:  * @cur:  the node-set
        !          3445:  * @val:  the node
        !          3446:  *
        !          3447:  * checks whether @cur contains @val
        !          3448:  *
        !          3449:  * Returns true (1) if @cur contains @val, false (0) otherwise
        !          3450:  */
        !          3451: int
        !          3452: xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
        !          3453:     int i;
        !          3454: 
        !          3455:     if ((cur == NULL) || (val == NULL)) return(0);
        !          3456:     if (val->type == XML_NAMESPACE_DECL) {
        !          3457:        for (i = 0; i < cur->nodeNr; i++) {
        !          3458:            if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
        !          3459:                xmlNsPtr ns1, ns2;
        !          3460: 
        !          3461:                ns1 = (xmlNsPtr) val;
        !          3462:                ns2 = (xmlNsPtr) cur->nodeTab[i];
        !          3463:                if (ns1 == ns2)
        !          3464:                    return(1);
        !          3465:                if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
        !          3466:                    (xmlStrEqual(ns1->prefix, ns2->prefix)))
        !          3467:                    return(1);
        !          3468:            }
        !          3469:        }
        !          3470:     } else {
        !          3471:        for (i = 0; i < cur->nodeNr; i++) {
        !          3472:            if (cur->nodeTab[i] == val)
        !          3473:                return(1);
        !          3474:        }
        !          3475:     }
        !          3476:     return(0);
        !          3477: }
        !          3478: 
        !          3479: /**
        !          3480:  * xmlXPathNodeSetAddNs:
        !          3481:  * @cur:  the initial node set
        !          3482:  * @node:  the hosting node
        !          3483:  * @ns:  a the namespace node
        !          3484:  *
        !          3485:  * add a new namespace node to an existing NodeSet
        !          3486:  */
        !          3487: void
        !          3488: xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
        !          3489:     int i;
        !          3490: 
        !          3491: 
        !          3492:     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
        !          3493:         (ns->type != XML_NAMESPACE_DECL) ||
        !          3494:        (node->type != XML_ELEMENT_NODE))
        !          3495:        return;
        !          3496: 
        !          3497:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          3498:     /*
        !          3499:      * prevent duplicates
        !          3500:      */
        !          3501:     for (i = 0;i < cur->nodeNr;i++) {
        !          3502:         if ((cur->nodeTab[i] != NULL) &&
        !          3503:            (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
        !          3504:            (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
        !          3505:            (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
        !          3506:            return;
        !          3507:     }
        !          3508: 
        !          3509:     /*
        !          3510:      * grow the nodeTab if needed
        !          3511:      */
        !          3512:     if (cur->nodeMax == 0) {
        !          3513:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3514:                                             sizeof(xmlNodePtr));
        !          3515:        if (cur->nodeTab == NULL) {
        !          3516:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3517:            return;
        !          3518:        }
        !          3519:        memset(cur->nodeTab, 0 ,
        !          3520:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3521:         cur->nodeMax = XML_NODESET_DEFAULT;
        !          3522:     } else if (cur->nodeNr == cur->nodeMax) {
        !          3523:         xmlNodePtr *temp;
        !          3524: 
        !          3525:         cur->nodeMax *= 2;
        !          3526:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
        !          3527:                                      sizeof(xmlNodePtr));
        !          3528:        if (temp == NULL) {
        !          3529:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3530:            return;
        !          3531:        }
        !          3532:        cur->nodeTab = temp;
        !          3533:     }
        !          3534:     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
        !          3535: }
        !          3536: 
        !          3537: /**
        !          3538:  * xmlXPathNodeSetAdd:
        !          3539:  * @cur:  the initial node set
        !          3540:  * @val:  a new xmlNodePtr
        !          3541:  *
        !          3542:  * add a new xmlNodePtr to an existing NodeSet
        !          3543:  */
        !          3544: void
        !          3545: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
        !          3546:     int i;
        !          3547: 
        !          3548:     if ((cur == NULL) || (val == NULL)) return;
        !          3549: 
        !          3550: #if 0
        !          3551:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
        !          3552:        return; /* an XSLT fake node */
        !          3553: #endif
        !          3554: 
        !          3555:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          3556:     /*
        !          3557:      * prevent duplcates
        !          3558:      */
        !          3559:     for (i = 0;i < cur->nodeNr;i++)
        !          3560:         if (cur->nodeTab[i] == val) return;
        !          3561: 
        !          3562:     /*
        !          3563:      * grow the nodeTab if needed
        !          3564:      */
        !          3565:     if (cur->nodeMax == 0) {
        !          3566:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3567:                                             sizeof(xmlNodePtr));
        !          3568:        if (cur->nodeTab == NULL) {
        !          3569:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3570:            return;
        !          3571:        }
        !          3572:        memset(cur->nodeTab, 0 ,
        !          3573:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3574:         cur->nodeMax = XML_NODESET_DEFAULT;
        !          3575:     } else if (cur->nodeNr == cur->nodeMax) {
        !          3576:         xmlNodePtr *temp;
        !          3577: 
        !          3578:         cur->nodeMax *= 2;
        !          3579:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
        !          3580:                                      sizeof(xmlNodePtr));
        !          3581:        if (temp == NULL) {
        !          3582:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3583:            return;
        !          3584:        }
        !          3585:        cur->nodeTab = temp;
        !          3586:     }
        !          3587:     if (val->type == XML_NAMESPACE_DECL) {
        !          3588:        xmlNsPtr ns = (xmlNsPtr) val;
        !          3589: 
        !          3590:        cur->nodeTab[cur->nodeNr++] =
        !          3591:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3592:     } else
        !          3593:        cur->nodeTab[cur->nodeNr++] = val;
        !          3594: }
        !          3595: 
        !          3596: /**
        !          3597:  * xmlXPathNodeSetAddUnique:
        !          3598:  * @cur:  the initial node set
        !          3599:  * @val:  a new xmlNodePtr
        !          3600:  *
        !          3601:  * add a new xmlNodePtr to an existing NodeSet, optimized version
        !          3602:  * when we are sure the node is not already in the set.
        !          3603:  */
        !          3604: void
        !          3605: xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
        !          3606:     if ((cur == NULL) || (val == NULL)) return;
        !          3607: 
        !          3608: #if 0
        !          3609:     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
        !          3610:        return; /* an XSLT fake node */
        !          3611: #endif
        !          3612: 
        !          3613:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          3614:     /*
        !          3615:      * grow the nodeTab if needed
        !          3616:      */
        !          3617:     if (cur->nodeMax == 0) {
        !          3618:         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3619:                                             sizeof(xmlNodePtr));
        !          3620:        if (cur->nodeTab == NULL) {
        !          3621:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3622:            return;
        !          3623:        }
        !          3624:        memset(cur->nodeTab, 0 ,
        !          3625:               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3626:         cur->nodeMax = XML_NODESET_DEFAULT;
        !          3627:     } else if (cur->nodeNr == cur->nodeMax) {
        !          3628:         xmlNodePtr *temp;
        !          3629: 
        !          3630:         cur->nodeMax *= 2;
        !          3631:        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
        !          3632:                                      sizeof(xmlNodePtr));
        !          3633:        if (temp == NULL) {
        !          3634:            xmlXPathErrMemory(NULL, "growing nodeset\n");
        !          3635:            return;
        !          3636:        }
        !          3637:        cur->nodeTab = temp;
        !          3638:     }
        !          3639:     if (val->type == XML_NAMESPACE_DECL) {
        !          3640:        xmlNsPtr ns = (xmlNsPtr) val;
        !          3641: 
        !          3642:        cur->nodeTab[cur->nodeNr++] =
        !          3643:            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3644:     } else
        !          3645:        cur->nodeTab[cur->nodeNr++] = val;
        !          3646: }
        !          3647: 
        !          3648: /**
        !          3649:  * xmlXPathNodeSetMerge:
        !          3650:  * @val1:  the first NodeSet or NULL
        !          3651:  * @val2:  the second NodeSet
        !          3652:  *
        !          3653:  * Merges two nodesets, all nodes from @val2 are added to @val1
        !          3654:  * if @val1 is NULL, a new set is created and copied from @val2
        !          3655:  *
        !          3656:  * Returns @val1 once extended or NULL in case of error.
        !          3657:  */
        !          3658: xmlNodeSetPtr
        !          3659: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
        !          3660:     int i, j, initNr, skip;
        !          3661:     xmlNodePtr n1, n2;
        !          3662: 
        !          3663:     if (val2 == NULL) return(val1);
        !          3664:     if (val1 == NULL) {
        !          3665:        val1 = xmlXPathNodeSetCreate(NULL);
        !          3666:     if (val1 == NULL)
        !          3667:         return (NULL);
        !          3668: #if 0
        !          3669:        /*
        !          3670:        * TODO: The optimization won't work in every case, since
        !          3671:        *  those nasty namespace nodes need to be added with
        !          3672:        *  xmlXPathNodeSetDupNs() to the set; thus a pure
        !          3673:        *  memcpy is not possible.
        !          3674:        *  If there was a flag on the nodesetval, indicating that
        !          3675:        *  some temporary nodes are in, that would be helpfull.
        !          3676:        */
        !          3677:        /*
        !          3678:        * Optimization: Create an equally sized node-set
        !          3679:        * and memcpy the content.
        !          3680:        */
        !          3681:        val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
        !          3682:        if (val1 == NULL)
        !          3683:            return(NULL);
        !          3684:        if (val2->nodeNr != 0) {
        !          3685:            if (val2->nodeNr == 1)
        !          3686:                *(val1->nodeTab) = *(val2->nodeTab);
        !          3687:            else {
        !          3688:                memcpy(val1->nodeTab, val2->nodeTab,
        !          3689:                    val2->nodeNr * sizeof(xmlNodePtr));
        !          3690:            }
        !          3691:            val1->nodeNr = val2->nodeNr;
        !          3692:        }
        !          3693:        return(val1);
        !          3694: #endif
        !          3695:     }
        !          3696: 
        !          3697:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          3698:     initNr = val1->nodeNr;
        !          3699: 
        !          3700:     for (i = 0;i < val2->nodeNr;i++) {
        !          3701:        n2 = val2->nodeTab[i];
        !          3702:        /*
        !          3703:         * check against duplicates
        !          3704:         */
        !          3705:        skip = 0;
        !          3706:        for (j = 0; j < initNr; j++) {
        !          3707:            n1 = val1->nodeTab[j];
        !          3708:            if (n1 == n2) {
        !          3709:                skip = 1;
        !          3710:                break;
        !          3711:            } else if ((n1->type == XML_NAMESPACE_DECL) &&
        !          3712:                       (n2->type == XML_NAMESPACE_DECL)) {
        !          3713:                if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
        !          3714:                    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
        !          3715:                        ((xmlNsPtr) n2)->prefix)))
        !          3716:                {
        !          3717:                    skip = 1;
        !          3718:                    break;
        !          3719:                }
        !          3720:            }
        !          3721:        }
        !          3722:        if (skip)
        !          3723:            continue;
        !          3724: 
        !          3725:        /*
        !          3726:         * grow the nodeTab if needed
        !          3727:         */
        !          3728:        if (val1->nodeMax == 0) {
        !          3729:            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3730:                                                    sizeof(xmlNodePtr));
        !          3731:            if (val1->nodeTab == NULL) {
        !          3732:                xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3733:                return(NULL);
        !          3734:            }
        !          3735:            memset(val1->nodeTab, 0 ,
        !          3736:                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3737:            val1->nodeMax = XML_NODESET_DEFAULT;
        !          3738:        } else if (val1->nodeNr == val1->nodeMax) {
        !          3739:            xmlNodePtr *temp;
        !          3740: 
        !          3741:            val1->nodeMax *= 2;
        !          3742:            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
        !          3743:                                             sizeof(xmlNodePtr));
        !          3744:            if (temp == NULL) {
        !          3745:                xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3746:                return(NULL);
        !          3747:            }
        !          3748:            val1->nodeTab = temp;
        !          3749:        }
        !          3750:        if (n2->type == XML_NAMESPACE_DECL) {
        !          3751:            xmlNsPtr ns = (xmlNsPtr) n2;
        !          3752: 
        !          3753:            val1->nodeTab[val1->nodeNr++] =
        !          3754:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3755:        } else
        !          3756:            val1->nodeTab[val1->nodeNr++] = n2;
        !          3757:     }
        !          3758: 
        !          3759:     return(val1);
        !          3760: }
        !          3761: 
        !          3762: #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
        !          3763: /**
        !          3764:  * xmlXPathNodeSetMergeUnique:
        !          3765:  * @val1:  the first NodeSet or NULL
        !          3766:  * @val2:  the second NodeSet
        !          3767:  *
        !          3768:  * Merges two nodesets, all nodes from @val2 are added to @val1
        !          3769:  * if @val1 is NULL, a new set is created and copied from @val2
        !          3770:  *
        !          3771:  * Returns @val1 once extended or NULL in case of error.
        !          3772:  */
        !          3773: static xmlNodeSetPtr
        !          3774: xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
        !          3775:     int i;
        !          3776: 
        !          3777:     if (val2 == NULL) return(val1);
        !          3778:     if (val1 == NULL) {
        !          3779:        val1 = xmlXPathNodeSetCreate(NULL);
        !          3780:     }
        !          3781:     if (val1 == NULL)
        !          3782:         return (NULL);
        !          3783: 
        !          3784:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          3785: 
        !          3786:     for (i = 0;i < val2->nodeNr;i++) {
        !          3787:        /*
        !          3788:         * grow the nodeTab if needed
        !          3789:         */
        !          3790:        if (val1->nodeMax == 0) {
        !          3791:            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
        !          3792:                                                    sizeof(xmlNodePtr));
        !          3793:            if (val1->nodeTab == NULL) {
        !          3794:                xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3795:                return(NULL);
        !          3796:            }
        !          3797:            memset(val1->nodeTab, 0 ,
        !          3798:                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3799:            val1->nodeMax = XML_NODESET_DEFAULT;
        !          3800:        } else if (val1->nodeNr == val1->nodeMax) {
        !          3801:            xmlNodePtr *temp;
        !          3802: 
        !          3803:            val1->nodeMax *= 2;
        !          3804:            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
        !          3805:                                             sizeof(xmlNodePtr));
        !          3806:            if (temp == NULL) {
        !          3807:                xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3808:                return(NULL);
        !          3809:            }
        !          3810:            val1->nodeTab = temp;
        !          3811:        }
        !          3812:        if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
        !          3813:            xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
        !          3814: 
        !          3815:            val1->nodeTab[val1->nodeNr++] =
        !          3816:                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3817:        } else
        !          3818:            val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
        !          3819:     }
        !          3820: 
        !          3821:     return(val1);
        !          3822: }
        !          3823: #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
        !          3824: 
        !          3825: /**
        !          3826:  * xmlXPathNodeSetMergeAndClear:
        !          3827:  * @set1:  the first NodeSet or NULL
        !          3828:  * @set2:  the second NodeSet
        !          3829:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
        !          3830:  *
        !          3831:  * Merges two nodesets, all nodes from @set2 are added to @set1
        !          3832:  * if @set1 is NULL, a new set is created and copied from @set2.
        !          3833:  * Checks for duplicate nodes. Clears set2.
        !          3834:  *
        !          3835:  * Returns @set1 once extended or NULL in case of error.
        !          3836:  */
        !          3837: static xmlNodeSetPtr
        !          3838: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
        !          3839:                             int hasNullEntries)
        !          3840: {
        !          3841:     if ((set1 == NULL) && (hasNullEntries == 0)) {
        !          3842:        /*
        !          3843:        * Note that doing a memcpy of the list, namespace nodes are
        !          3844:        * just assigned to set1, since set2 is cleared anyway.
        !          3845:        */
        !          3846:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
        !          3847:        if (set1 == NULL)
        !          3848:            return(NULL);
        !          3849:        if (set2->nodeNr != 0) {
        !          3850:            memcpy(set1->nodeTab, set2->nodeTab,
        !          3851:                set2->nodeNr * sizeof(xmlNodePtr));
        !          3852:            set1->nodeNr = set2->nodeNr;
        !          3853:        }
        !          3854:     } else {
        !          3855:        int i, j, initNbSet1;
        !          3856:        xmlNodePtr n1, n2;
        !          3857: 
        !          3858:        if (set1 == NULL)
        !          3859:             set1 = xmlXPathNodeSetCreate(NULL);
        !          3860:         if (set1 == NULL)
        !          3861:             return (NULL);
        !          3862: 
        !          3863:        initNbSet1 = set1->nodeNr;
        !          3864:        for (i = 0;i < set2->nodeNr;i++) {
        !          3865:            n2 = set2->nodeTab[i];
        !          3866:            /*
        !          3867:            * Skip NULLed entries.
        !          3868:            */
        !          3869:            if (n2 == NULL)
        !          3870:                continue;
        !          3871:            /*
        !          3872:            * Skip duplicates.
        !          3873:            */
        !          3874:            for (j = 0; j < initNbSet1; j++) {
        !          3875:                n1 = set1->nodeTab[j];
        !          3876:                if (n1 == n2) {
        !          3877:                    goto skip_node;
        !          3878:                } else if ((n1->type == XML_NAMESPACE_DECL) &&
        !          3879:                    (n2->type == XML_NAMESPACE_DECL))
        !          3880:                {
        !          3881:                    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
        !          3882:                        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
        !          3883:                        ((xmlNsPtr) n2)->prefix)))
        !          3884:                    {
        !          3885:                        /*
        !          3886:                        * Free the namespace node.
        !          3887:                        */
        !          3888:                        set2->nodeTab[i] = NULL;
        !          3889:                        xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
        !          3890:                        goto skip_node;
        !          3891:                    }
        !          3892:                }
        !          3893:            }
        !          3894:            /*
        !          3895:            * grow the nodeTab if needed
        !          3896:            */
        !          3897:            if (set1->nodeMax == 0) {
        !          3898:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
        !          3899:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
        !          3900:                if (set1->nodeTab == NULL) {
        !          3901:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3902:                    return(NULL);
        !          3903:                }
        !          3904:                memset(set1->nodeTab, 0,
        !          3905:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3906:                set1->nodeMax = XML_NODESET_DEFAULT;
        !          3907:            } else if (set1->nodeNr >= set1->nodeMax) {
        !          3908:                xmlNodePtr *temp;
        !          3909: 
        !          3910:                set1->nodeMax *= 2;
        !          3911:                temp = (xmlNodePtr *) xmlRealloc(
        !          3912:                    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
        !          3913:                if (temp == NULL) {
        !          3914:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3915:                    return(NULL);
        !          3916:                }
        !          3917:                set1->nodeTab = temp;
        !          3918:            }
        !          3919:            if (n2->type == XML_NAMESPACE_DECL) {
        !          3920:                xmlNsPtr ns = (xmlNsPtr) n2;
        !          3921: 
        !          3922:                set1->nodeTab[set1->nodeNr++] =
        !          3923:                    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
        !          3924:            } else
        !          3925:                set1->nodeTab[set1->nodeNr++] = n2;
        !          3926: skip_node:
        !          3927:            {}
        !          3928:        }
        !          3929:     }
        !          3930:     set2->nodeNr = 0;
        !          3931:     return(set1);
        !          3932: }
        !          3933: 
        !          3934: /**
        !          3935:  * xmlXPathNodeSetMergeAndClearNoDupls:
        !          3936:  * @set1:  the first NodeSet or NULL
        !          3937:  * @set2:  the second NodeSet
        !          3938:  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
        !          3939:  *
        !          3940:  * Merges two nodesets, all nodes from @set2 are added to @set1
        !          3941:  * if @set1 is NULL, a new set is created and copied from @set2.
        !          3942:  * Doesn't chack for duplicate nodes. Clears set2.
        !          3943:  *
        !          3944:  * Returns @set1 once extended or NULL in case of error.
        !          3945:  */
        !          3946: static xmlNodeSetPtr
        !          3947: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
        !          3948:                                    int hasNullEntries)
        !          3949: {
        !          3950:     if (set2 == NULL)
        !          3951:        return(set1);
        !          3952:     if ((set1 == NULL) && (hasNullEntries == 0)) {
        !          3953:        /*
        !          3954:        * Note that doing a memcpy of the list, namespace nodes are
        !          3955:        * just assigned to set1, since set2 is cleared anyway.
        !          3956:        */
        !          3957:        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
        !          3958:        if (set1 == NULL)
        !          3959:            return(NULL);
        !          3960:        if (set2->nodeNr != 0) {
        !          3961:            memcpy(set1->nodeTab, set2->nodeTab,
        !          3962:                set2->nodeNr * sizeof(xmlNodePtr));
        !          3963:            set1->nodeNr = set2->nodeNr;
        !          3964:        }
        !          3965:     } else {
        !          3966:        int i;
        !          3967:        xmlNodePtr n2;
        !          3968: 
        !          3969:        if (set1 == NULL)
        !          3970:            set1 = xmlXPathNodeSetCreate(NULL);
        !          3971:         if (set1 == NULL)
        !          3972:             return (NULL);
        !          3973: 
        !          3974:        for (i = 0;i < set2->nodeNr;i++) {
        !          3975:            n2 = set2->nodeTab[i];
        !          3976:            /*
        !          3977:            * Skip NULLed entries.
        !          3978:            */
        !          3979:            if (n2 == NULL)
        !          3980:                continue;
        !          3981:            if (set1->nodeMax == 0) {
        !          3982:                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
        !          3983:                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
        !          3984:                if (set1->nodeTab == NULL) {
        !          3985:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3986:                    return(NULL);
        !          3987:                }
        !          3988:                memset(set1->nodeTab, 0,
        !          3989:                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
        !          3990:                set1->nodeMax = XML_NODESET_DEFAULT;
        !          3991:            } else if (set1->nodeNr >= set1->nodeMax) {
        !          3992:                xmlNodePtr *temp;
        !          3993: 
        !          3994:                set1->nodeMax *= 2;
        !          3995:                temp = (xmlNodePtr *) xmlRealloc(
        !          3996:                    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
        !          3997:                if (temp == NULL) {
        !          3998:                    xmlXPathErrMemory(NULL, "merging nodeset\n");
        !          3999:                    return(NULL);
        !          4000:                }
        !          4001:                set1->nodeTab = temp;
        !          4002:            }
        !          4003:            set1->nodeTab[set1->nodeNr++] = n2;
        !          4004:        }
        !          4005:     }
        !          4006:     set2->nodeNr = 0;
        !          4007:     return(set1);
        !          4008: }
        !          4009: 
        !          4010: /**
        !          4011:  * xmlXPathNodeSetDel:
        !          4012:  * @cur:  the initial node set
        !          4013:  * @val:  an xmlNodePtr
        !          4014:  *
        !          4015:  * Removes an xmlNodePtr from an existing NodeSet
        !          4016:  */
        !          4017: void
        !          4018: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
        !          4019:     int i;
        !          4020: 
        !          4021:     if (cur == NULL) return;
        !          4022:     if (val == NULL) return;
        !          4023: 
        !          4024:     /*
        !          4025:      * find node in nodeTab
        !          4026:      */
        !          4027:     for (i = 0;i < cur->nodeNr;i++)
        !          4028:         if (cur->nodeTab[i] == val) break;
        !          4029: 
        !          4030:     if (i >= cur->nodeNr) {    /* not found */
        !          4031: #ifdef DEBUG
        !          4032:         xmlGenericError(xmlGenericErrorContext,
        !          4033:                "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
        !          4034:                val->name);
        !          4035: #endif
        !          4036:         return;
        !          4037:     }
        !          4038:     if ((cur->nodeTab[i] != NULL) &&
        !          4039:        (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
        !          4040:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
        !          4041:     cur->nodeNr--;
        !          4042:     for (;i < cur->nodeNr;i++)
        !          4043:         cur->nodeTab[i] = cur->nodeTab[i + 1];
        !          4044:     cur->nodeTab[cur->nodeNr] = NULL;
        !          4045: }
        !          4046: 
        !          4047: /**
        !          4048:  * xmlXPathNodeSetRemove:
        !          4049:  * @cur:  the initial node set
        !          4050:  * @val:  the index to remove
        !          4051:  *
        !          4052:  * Removes an entry from an existing NodeSet list.
        !          4053:  */
        !          4054: void
        !          4055: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
        !          4056:     if (cur == NULL) return;
        !          4057:     if (val >= cur->nodeNr) return;
        !          4058:     if ((cur->nodeTab[val] != NULL) &&
        !          4059:        (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
        !          4060:        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
        !          4061:     cur->nodeNr--;
        !          4062:     for (;val < cur->nodeNr;val++)
        !          4063:         cur->nodeTab[val] = cur->nodeTab[val + 1];
        !          4064:     cur->nodeTab[cur->nodeNr] = NULL;
        !          4065: }
        !          4066: 
        !          4067: /**
        !          4068:  * xmlXPathFreeNodeSet:
        !          4069:  * @obj:  the xmlNodeSetPtr to free
        !          4070:  *
        !          4071:  * Free the NodeSet compound (not the actual nodes !).
        !          4072:  */
        !          4073: void
        !          4074: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
        !          4075:     if (obj == NULL) return;
        !          4076:     if (obj->nodeTab != NULL) {
        !          4077:        int i;
        !          4078: 
        !          4079:        /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          4080:        for (i = 0;i < obj->nodeNr;i++)
        !          4081:            if ((obj->nodeTab[i] != NULL) &&
        !          4082:                (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
        !          4083:                xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
        !          4084:        xmlFree(obj->nodeTab);
        !          4085:     }
        !          4086:     xmlFree(obj);
        !          4087: }
        !          4088: 
        !          4089: /**
        !          4090:  * xmlXPathNodeSetClear:
        !          4091:  * @set:  the node set to clear
        !          4092:  *
        !          4093:  * Clears the list from all temporary XPath objects (e.g. namespace nodes
        !          4094:  * are feed), but does *not* free the list itself. Sets the length of the
        !          4095:  * list to 0.
        !          4096:  */
        !          4097: static void
        !          4098: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
        !          4099: {
        !          4100:     if ((set == NULL) || (set->nodeNr <= 0))
        !          4101:        return;
        !          4102:     else if (hasNsNodes) {
        !          4103:        int i;
        !          4104:        xmlNodePtr node;
        !          4105: 
        !          4106:        for (i = 0; i < set->nodeNr; i++) {
        !          4107:            node = set->nodeTab[i];
        !          4108:            if ((node != NULL) &&
        !          4109:                (node->type == XML_NAMESPACE_DECL))
        !          4110:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
        !          4111:        }
        !          4112:     }
        !          4113:     set->nodeNr = 0;
        !          4114: }
        !          4115: 
        !          4116: /**
        !          4117:  * xmlXPathNodeSetClearFromPos:
        !          4118:  * @set: the node set to be cleared
        !          4119:  * @pos: the start position to clear from
        !          4120:  *
        !          4121:  * Clears the list from temporary XPath objects (e.g. namespace nodes
        !          4122:  * are feed) starting with the entry at @pos, but does *not* free the list
        !          4123:  * itself. Sets the length of the list to @pos.
        !          4124:  */
        !          4125: static void
        !          4126: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
        !          4127: {
        !          4128:     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
        !          4129:        return;
        !          4130:     else if ((hasNsNodes)) {
        !          4131:        int i;
        !          4132:        xmlNodePtr node;
        !          4133: 
        !          4134:        for (i = pos; i < set->nodeNr; i++) {
        !          4135:            node = set->nodeTab[i];
        !          4136:            if ((node != NULL) &&
        !          4137:                (node->type == XML_NAMESPACE_DECL))
        !          4138:                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
        !          4139:        }
        !          4140:     }
        !          4141:     set->nodeNr = pos;
        !          4142: }
        !          4143: 
        !          4144: /**
        !          4145:  * xmlXPathFreeValueTree:
        !          4146:  * @obj:  the xmlNodeSetPtr to free
        !          4147:  *
        !          4148:  * Free the NodeSet compound and the actual tree, this is different
        !          4149:  * from xmlXPathFreeNodeSet()
        !          4150:  */
        !          4151: static void
        !          4152: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
        !          4153:     int i;
        !          4154: 
        !          4155:     if (obj == NULL) return;
        !          4156: 
        !          4157:     if (obj->nodeTab != NULL) {
        !          4158:        for (i = 0;i < obj->nodeNr;i++) {
        !          4159:            if (obj->nodeTab[i] != NULL) {
        !          4160:                if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
        !          4161:                    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
        !          4162:                } else {
        !          4163:                    xmlFreeNodeList(obj->nodeTab[i]);
        !          4164:                }
        !          4165:            }
        !          4166:        }
        !          4167:        xmlFree(obj->nodeTab);
        !          4168:     }
        !          4169:     xmlFree(obj);
        !          4170: }
        !          4171: 
        !          4172: #if defined(DEBUG) || defined(DEBUG_STEP)
        !          4173: /**
        !          4174:  * xmlGenericErrorContextNodeSet:
        !          4175:  * @output:  a FILE * for the output
        !          4176:  * @obj:  the xmlNodeSetPtr to display
        !          4177:  *
        !          4178:  * Quick display of a NodeSet
        !          4179:  */
        !          4180: void
        !          4181: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
        !          4182:     int i;
        !          4183: 
        !          4184:     if (output == NULL) output = xmlGenericErrorContext;
        !          4185:     if (obj == NULL)  {
        !          4186:         fprintf(output, "NodeSet == NULL !\n");
        !          4187:        return;
        !          4188:     }
        !          4189:     if (obj->nodeNr == 0) {
        !          4190:         fprintf(output, "NodeSet is empty\n");
        !          4191:        return;
        !          4192:     }
        !          4193:     if (obj->nodeTab == NULL) {
        !          4194:        fprintf(output, " nodeTab == NULL !\n");
        !          4195:        return;
        !          4196:     }
        !          4197:     for (i = 0; i < obj->nodeNr; i++) {
        !          4198:         if (obj->nodeTab[i] == NULL) {
        !          4199:            fprintf(output, " NULL !\n");
        !          4200:            return;
        !          4201:         }
        !          4202:        if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
        !          4203:            (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
        !          4204:            fprintf(output, " /");
        !          4205:        else if (obj->nodeTab[i]->name == NULL)
        !          4206:            fprintf(output, " noname!");
        !          4207:        else fprintf(output, " %s", obj->nodeTab[i]->name);
        !          4208:     }
        !          4209:     fprintf(output, "\n");
        !          4210: }
        !          4211: #endif
        !          4212: 
        !          4213: /**
        !          4214:  * xmlXPathNewNodeSet:
        !          4215:  * @val:  the NodePtr value
        !          4216:  *
        !          4217:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
        !          4218:  * it with the single Node @val
        !          4219:  *
        !          4220:  * Returns the newly created object.
        !          4221:  */
        !          4222: xmlXPathObjectPtr
        !          4223: xmlXPathNewNodeSet(xmlNodePtr val) {
        !          4224:     xmlXPathObjectPtr ret;
        !          4225: 
        !          4226:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          4227:     if (ret == NULL) {
        !          4228:         xmlXPathErrMemory(NULL, "creating nodeset\n");
        !          4229:        return(NULL);
        !          4230:     }
        !          4231:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          4232:     ret->type = XPATH_NODESET;
        !          4233:     ret->boolval = 0;
        !          4234:     ret->nodesetval = xmlXPathNodeSetCreate(val);
        !          4235:     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
        !          4236: #ifdef XP_DEBUG_OBJ_USAGE
        !          4237:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
        !          4238: #endif
        !          4239:     return(ret);
        !          4240: }
        !          4241: 
        !          4242: /**
        !          4243:  * xmlXPathNewValueTree:
        !          4244:  * @val:  the NodePtr value
        !          4245:  *
        !          4246:  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
        !          4247:  * it with the tree root @val
        !          4248:  *
        !          4249:  * Returns the newly created object.
        !          4250:  */
        !          4251: xmlXPathObjectPtr
        !          4252: xmlXPathNewValueTree(xmlNodePtr val) {
        !          4253:     xmlXPathObjectPtr ret;
        !          4254: 
        !          4255:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          4256:     if (ret == NULL) {
        !          4257:         xmlXPathErrMemory(NULL, "creating result value tree\n");
        !          4258:        return(NULL);
        !          4259:     }
        !          4260:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          4261:     ret->type = XPATH_XSLT_TREE;
        !          4262:     ret->boolval = 1;
        !          4263:     ret->user = (void *) val;
        !          4264:     ret->nodesetval = xmlXPathNodeSetCreate(val);
        !          4265: #ifdef XP_DEBUG_OBJ_USAGE
        !          4266:     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
        !          4267: #endif
        !          4268:     return(ret);
        !          4269: }
        !          4270: 
        !          4271: /**
        !          4272:  * xmlXPathNewNodeSetList:
        !          4273:  * @val:  an existing NodeSet
        !          4274:  *
        !          4275:  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
        !          4276:  * it with the Nodeset @val
        !          4277:  *
        !          4278:  * Returns the newly created object.
        !          4279:  */
        !          4280: xmlXPathObjectPtr
        !          4281: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
        !          4282: {
        !          4283:     xmlXPathObjectPtr ret;
        !          4284:     int i;
        !          4285: 
        !          4286:     if (val == NULL)
        !          4287:         ret = NULL;
        !          4288:     else if (val->nodeTab == NULL)
        !          4289:         ret = xmlXPathNewNodeSet(NULL);
        !          4290:     else {
        !          4291:         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
        !          4292:         if (ret)
        !          4293:             for (i = 1; i < val->nodeNr; ++i)
        !          4294:                 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
        !          4295:     }
        !          4296: 
        !          4297:     return (ret);
        !          4298: }
        !          4299: 
        !          4300: /**
        !          4301:  * xmlXPathWrapNodeSet:
        !          4302:  * @val:  the NodePtr value
        !          4303:  *
        !          4304:  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
        !          4305:  *
        !          4306:  * Returns the newly created object.
        !          4307:  */
        !          4308: xmlXPathObjectPtr
        !          4309: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
        !          4310:     xmlXPathObjectPtr ret;
        !          4311: 
        !          4312:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          4313:     if (ret == NULL) {
        !          4314:         xmlXPathErrMemory(NULL, "creating node set object\n");
        !          4315:        return(NULL);
        !          4316:     }
        !          4317:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          4318:     ret->type = XPATH_NODESET;
        !          4319:     ret->nodesetval = val;
        !          4320: #ifdef XP_DEBUG_OBJ_USAGE
        !          4321:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
        !          4322: #endif
        !          4323:     return(ret);
        !          4324: }
        !          4325: 
        !          4326: /**
        !          4327:  * xmlXPathFreeNodeSetList:
        !          4328:  * @obj:  an existing NodeSetList object
        !          4329:  *
        !          4330:  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
        !          4331:  * the list contrary to xmlXPathFreeObject().
        !          4332:  */
        !          4333: void
        !          4334: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
        !          4335:     if (obj == NULL) return;
        !          4336: #ifdef XP_DEBUG_OBJ_USAGE
        !          4337:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
        !          4338: #endif
        !          4339:     xmlFree(obj);
        !          4340: }
        !          4341: 
        !          4342: /**
        !          4343:  * xmlXPathDifference:
        !          4344:  * @nodes1:  a node-set
        !          4345:  * @nodes2:  a node-set
        !          4346:  *
        !          4347:  * Implements the EXSLT - Sets difference() function:
        !          4348:  *    node-set set:difference (node-set, node-set)
        !          4349:  *
        !          4350:  * Returns the difference between the two node sets, or nodes1 if
        !          4351:  *         nodes2 is empty
        !          4352:  */
        !          4353: xmlNodeSetPtr
        !          4354: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4355:     xmlNodeSetPtr ret;
        !          4356:     int i, l1;
        !          4357:     xmlNodePtr cur;
        !          4358: 
        !          4359:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4360:        return(nodes1);
        !          4361: 
        !          4362:     ret = xmlXPathNodeSetCreate(NULL);
        !          4363:     if (xmlXPathNodeSetIsEmpty(nodes1))
        !          4364:        return(ret);
        !          4365: 
        !          4366:     l1 = xmlXPathNodeSetGetLength(nodes1);
        !          4367: 
        !          4368:     for (i = 0; i < l1; i++) {
        !          4369:        cur = xmlXPathNodeSetItem(nodes1, i);
        !          4370:        if (!xmlXPathNodeSetContains(nodes2, cur))
        !          4371:            xmlXPathNodeSetAddUnique(ret, cur);
        !          4372:     }
        !          4373:     return(ret);
        !          4374: }
        !          4375: 
        !          4376: /**
        !          4377:  * xmlXPathIntersection:
        !          4378:  * @nodes1:  a node-set
        !          4379:  * @nodes2:  a node-set
        !          4380:  *
        !          4381:  * Implements the EXSLT - Sets intersection() function:
        !          4382:  *    node-set set:intersection (node-set, node-set)
        !          4383:  *
        !          4384:  * Returns a node set comprising the nodes that are within both the
        !          4385:  *         node sets passed as arguments
        !          4386:  */
        !          4387: xmlNodeSetPtr
        !          4388: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4389:     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
        !          4390:     int i, l1;
        !          4391:     xmlNodePtr cur;
        !          4392: 
        !          4393:     if (ret == NULL)
        !          4394:         return(ret);
        !          4395:     if (xmlXPathNodeSetIsEmpty(nodes1))
        !          4396:        return(ret);
        !          4397:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4398:        return(ret);
        !          4399: 
        !          4400:     l1 = xmlXPathNodeSetGetLength(nodes1);
        !          4401: 
        !          4402:     for (i = 0; i < l1; i++) {
        !          4403:        cur = xmlXPathNodeSetItem(nodes1, i);
        !          4404:        if (xmlXPathNodeSetContains(nodes2, cur))
        !          4405:            xmlXPathNodeSetAddUnique(ret, cur);
        !          4406:     }
        !          4407:     return(ret);
        !          4408: }
        !          4409: 
        !          4410: /**
        !          4411:  * xmlXPathDistinctSorted:
        !          4412:  * @nodes:  a node-set, sorted by document order
        !          4413:  *
        !          4414:  * Implements the EXSLT - Sets distinct() function:
        !          4415:  *    node-set set:distinct (node-set)
        !          4416:  *
        !          4417:  * Returns a subset of the nodes contained in @nodes, or @nodes if
        !          4418:  *         it is empty
        !          4419:  */
        !          4420: xmlNodeSetPtr
        !          4421: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
        !          4422:     xmlNodeSetPtr ret;
        !          4423:     xmlHashTablePtr hash;
        !          4424:     int i, l;
        !          4425:     xmlChar * strval;
        !          4426:     xmlNodePtr cur;
        !          4427: 
        !          4428:     if (xmlXPathNodeSetIsEmpty(nodes))
        !          4429:        return(nodes);
        !          4430: 
        !          4431:     ret = xmlXPathNodeSetCreate(NULL);
        !          4432:     if (ret == NULL)
        !          4433:         return(ret);
        !          4434:     l = xmlXPathNodeSetGetLength(nodes);
        !          4435:     hash = xmlHashCreate (l);
        !          4436:     for (i = 0; i < l; i++) {
        !          4437:        cur = xmlXPathNodeSetItem(nodes, i);
        !          4438:        strval = xmlXPathCastNodeToString(cur);
        !          4439:        if (xmlHashLookup(hash, strval) == NULL) {
        !          4440:            xmlHashAddEntry(hash, strval, strval);
        !          4441:            xmlXPathNodeSetAddUnique(ret, cur);
        !          4442:        } else {
        !          4443:            xmlFree(strval);
        !          4444:        }
        !          4445:     }
        !          4446:     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
        !          4447:     return(ret);
        !          4448: }
        !          4449: 
        !          4450: /**
        !          4451:  * xmlXPathDistinct:
        !          4452:  * @nodes:  a node-set
        !          4453:  *
        !          4454:  * Implements the EXSLT - Sets distinct() function:
        !          4455:  *    node-set set:distinct (node-set)
        !          4456:  * @nodes is sorted by document order, then #exslSetsDistinctSorted
        !          4457:  * is called with the sorted node-set
        !          4458:  *
        !          4459:  * Returns a subset of the nodes contained in @nodes, or @nodes if
        !          4460:  *         it is empty
        !          4461:  */
        !          4462: xmlNodeSetPtr
        !          4463: xmlXPathDistinct (xmlNodeSetPtr nodes) {
        !          4464:     if (xmlXPathNodeSetIsEmpty(nodes))
        !          4465:        return(nodes);
        !          4466: 
        !          4467:     xmlXPathNodeSetSort(nodes);
        !          4468:     return(xmlXPathDistinctSorted(nodes));
        !          4469: }
        !          4470: 
        !          4471: /**
        !          4472:  * xmlXPathHasSameNodes:
        !          4473:  * @nodes1:  a node-set
        !          4474:  * @nodes2:  a node-set
        !          4475:  *
        !          4476:  * Implements the EXSLT - Sets has-same-nodes function:
        !          4477:  *    boolean set:has-same-node(node-set, node-set)
        !          4478:  *
        !          4479:  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
        !          4480:  *         otherwise
        !          4481:  */
        !          4482: int
        !          4483: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4484:     int i, l;
        !          4485:     xmlNodePtr cur;
        !          4486: 
        !          4487:     if (xmlXPathNodeSetIsEmpty(nodes1) ||
        !          4488:        xmlXPathNodeSetIsEmpty(nodes2))
        !          4489:        return(0);
        !          4490: 
        !          4491:     l = xmlXPathNodeSetGetLength(nodes1);
        !          4492:     for (i = 0; i < l; i++) {
        !          4493:        cur = xmlXPathNodeSetItem(nodes1, i);
        !          4494:        if (xmlXPathNodeSetContains(nodes2, cur))
        !          4495:            return(1);
        !          4496:     }
        !          4497:     return(0);
        !          4498: }
        !          4499: 
        !          4500: /**
        !          4501:  * xmlXPathNodeLeadingSorted:
        !          4502:  * @nodes: a node-set, sorted by document order
        !          4503:  * @node: a node
        !          4504:  *
        !          4505:  * Implements the EXSLT - Sets leading() function:
        !          4506:  *    node-set set:leading (node-set, node-set)
        !          4507:  *
        !          4508:  * Returns the nodes in @nodes that precede @node in document order,
        !          4509:  *         @nodes if @node is NULL or an empty node-set if @nodes
        !          4510:  *         doesn't contain @node
        !          4511:  */
        !          4512: xmlNodeSetPtr
        !          4513: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
        !          4514:     int i, l;
        !          4515:     xmlNodePtr cur;
        !          4516:     xmlNodeSetPtr ret;
        !          4517: 
        !          4518:     if (node == NULL)
        !          4519:        return(nodes);
        !          4520: 
        !          4521:     ret = xmlXPathNodeSetCreate(NULL);
        !          4522:     if (ret == NULL)
        !          4523:         return(ret);
        !          4524:     if (xmlXPathNodeSetIsEmpty(nodes) ||
        !          4525:        (!xmlXPathNodeSetContains(nodes, node)))
        !          4526:        return(ret);
        !          4527: 
        !          4528:     l = xmlXPathNodeSetGetLength(nodes);
        !          4529:     for (i = 0; i < l; i++) {
        !          4530:        cur = xmlXPathNodeSetItem(nodes, i);
        !          4531:        if (cur == node)
        !          4532:            break;
        !          4533:        xmlXPathNodeSetAddUnique(ret, cur);
        !          4534:     }
        !          4535:     return(ret);
        !          4536: }
        !          4537: 
        !          4538: /**
        !          4539:  * xmlXPathNodeLeading:
        !          4540:  * @nodes:  a node-set
        !          4541:  * @node:  a node
        !          4542:  *
        !          4543:  * Implements the EXSLT - Sets leading() function:
        !          4544:  *    node-set set:leading (node-set, node-set)
        !          4545:  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
        !          4546:  * is called.
        !          4547:  *
        !          4548:  * Returns the nodes in @nodes that precede @node in document order,
        !          4549:  *         @nodes if @node is NULL or an empty node-set if @nodes
        !          4550:  *         doesn't contain @node
        !          4551:  */
        !          4552: xmlNodeSetPtr
        !          4553: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
        !          4554:     xmlXPathNodeSetSort(nodes);
        !          4555:     return(xmlXPathNodeLeadingSorted(nodes, node));
        !          4556: }
        !          4557: 
        !          4558: /**
        !          4559:  * xmlXPathLeadingSorted:
        !          4560:  * @nodes1:  a node-set, sorted by document order
        !          4561:  * @nodes2:  a node-set, sorted by document order
        !          4562:  *
        !          4563:  * Implements the EXSLT - Sets leading() function:
        !          4564:  *    node-set set:leading (node-set, node-set)
        !          4565:  *
        !          4566:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
        !          4567:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
        !          4568:  *         an empty node-set if @nodes1 doesn't contain @nodes2
        !          4569:  */
        !          4570: xmlNodeSetPtr
        !          4571: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4572:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4573:        return(nodes1);
        !          4574:     return(xmlXPathNodeLeadingSorted(nodes1,
        !          4575:                                     xmlXPathNodeSetItem(nodes2, 1)));
        !          4576: }
        !          4577: 
        !          4578: /**
        !          4579:  * xmlXPathLeading:
        !          4580:  * @nodes1:  a node-set
        !          4581:  * @nodes2:  a node-set
        !          4582:  *
        !          4583:  * Implements the EXSLT - Sets leading() function:
        !          4584:  *    node-set set:leading (node-set, node-set)
        !          4585:  * @nodes1 and @nodes2 are sorted by document order, then
        !          4586:  * #exslSetsLeadingSorted is called.
        !          4587:  *
        !          4588:  * Returns the nodes in @nodes1 that precede the first node in @nodes2
        !          4589:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
        !          4590:  *         an empty node-set if @nodes1 doesn't contain @nodes2
        !          4591:  */
        !          4592: xmlNodeSetPtr
        !          4593: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4594:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4595:        return(nodes1);
        !          4596:     if (xmlXPathNodeSetIsEmpty(nodes1))
        !          4597:        return(xmlXPathNodeSetCreate(NULL));
        !          4598:     xmlXPathNodeSetSort(nodes1);
        !          4599:     xmlXPathNodeSetSort(nodes2);
        !          4600:     return(xmlXPathNodeLeadingSorted(nodes1,
        !          4601:                                     xmlXPathNodeSetItem(nodes2, 1)));
        !          4602: }
        !          4603: 
        !          4604: /**
        !          4605:  * xmlXPathNodeTrailingSorted:
        !          4606:  * @nodes: a node-set, sorted by document order
        !          4607:  * @node: a node
        !          4608:  *
        !          4609:  * Implements the EXSLT - Sets trailing() function:
        !          4610:  *    node-set set:trailing (node-set, node-set)
        !          4611:  *
        !          4612:  * Returns the nodes in @nodes that follow @node in document order,
        !          4613:  *         @nodes if @node is NULL or an empty node-set if @nodes
        !          4614:  *         doesn't contain @node
        !          4615:  */
        !          4616: xmlNodeSetPtr
        !          4617: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
        !          4618:     int i, l;
        !          4619:     xmlNodePtr cur;
        !          4620:     xmlNodeSetPtr ret;
        !          4621: 
        !          4622:     if (node == NULL)
        !          4623:        return(nodes);
        !          4624: 
        !          4625:     ret = xmlXPathNodeSetCreate(NULL);
        !          4626:     if (ret == NULL)
        !          4627:         return(ret);
        !          4628:     if (xmlXPathNodeSetIsEmpty(nodes) ||
        !          4629:        (!xmlXPathNodeSetContains(nodes, node)))
        !          4630:        return(ret);
        !          4631: 
        !          4632:     l = xmlXPathNodeSetGetLength(nodes);
        !          4633:     for (i = l - 1; i >= 0; i--) {
        !          4634:        cur = xmlXPathNodeSetItem(nodes, i);
        !          4635:        if (cur == node)
        !          4636:            break;
        !          4637:        xmlXPathNodeSetAddUnique(ret, cur);
        !          4638:     }
        !          4639:     xmlXPathNodeSetSort(ret);  /* bug 413451 */
        !          4640:     return(ret);
        !          4641: }
        !          4642: 
        !          4643: /**
        !          4644:  * xmlXPathNodeTrailing:
        !          4645:  * @nodes:  a node-set
        !          4646:  * @node:  a node
        !          4647:  *
        !          4648:  * Implements the EXSLT - Sets trailing() function:
        !          4649:  *    node-set set:trailing (node-set, node-set)
        !          4650:  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
        !          4651:  * is called.
        !          4652:  *
        !          4653:  * Returns the nodes in @nodes that follow @node in document order,
        !          4654:  *         @nodes if @node is NULL or an empty node-set if @nodes
        !          4655:  *         doesn't contain @node
        !          4656:  */
        !          4657: xmlNodeSetPtr
        !          4658: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
        !          4659:     xmlXPathNodeSetSort(nodes);
        !          4660:     return(xmlXPathNodeTrailingSorted(nodes, node));
        !          4661: }
        !          4662: 
        !          4663: /**
        !          4664:  * xmlXPathTrailingSorted:
        !          4665:  * @nodes1:  a node-set, sorted by document order
        !          4666:  * @nodes2:  a node-set, sorted by document order
        !          4667:  *
        !          4668:  * Implements the EXSLT - Sets trailing() function:
        !          4669:  *    node-set set:trailing (node-set, node-set)
        !          4670:  *
        !          4671:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
        !          4672:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
        !          4673:  *         an empty node-set if @nodes1 doesn't contain @nodes2
        !          4674:  */
        !          4675: xmlNodeSetPtr
        !          4676: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4677:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4678:        return(nodes1);
        !          4679:     return(xmlXPathNodeTrailingSorted(nodes1,
        !          4680:                                      xmlXPathNodeSetItem(nodes2, 0)));
        !          4681: }
        !          4682: 
        !          4683: /**
        !          4684:  * xmlXPathTrailing:
        !          4685:  * @nodes1:  a node-set
        !          4686:  * @nodes2:  a node-set
        !          4687:  *
        !          4688:  * Implements the EXSLT - Sets trailing() function:
        !          4689:  *    node-set set:trailing (node-set, node-set)
        !          4690:  * @nodes1 and @nodes2 are sorted by document order, then
        !          4691:  * #xmlXPathTrailingSorted is called.
        !          4692:  *
        !          4693:  * Returns the nodes in @nodes1 that follow the first node in @nodes2
        !          4694:  *         in document order, @nodes1 if @nodes2 is NULL or empty or
        !          4695:  *         an empty node-set if @nodes1 doesn't contain @nodes2
        !          4696:  */
        !          4697: xmlNodeSetPtr
        !          4698: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
        !          4699:     if (xmlXPathNodeSetIsEmpty(nodes2))
        !          4700:        return(nodes1);
        !          4701:     if (xmlXPathNodeSetIsEmpty(nodes1))
        !          4702:        return(xmlXPathNodeSetCreate(NULL));
        !          4703:     xmlXPathNodeSetSort(nodes1);
        !          4704:     xmlXPathNodeSetSort(nodes2);
        !          4705:     return(xmlXPathNodeTrailingSorted(nodes1,
        !          4706:                                      xmlXPathNodeSetItem(nodes2, 0)));
        !          4707: }
        !          4708: 
        !          4709: /************************************************************************
        !          4710:  *                                                                     *
        !          4711:  *             Routines to handle extra functions                      *
        !          4712:  *                                                                     *
        !          4713:  ************************************************************************/
        !          4714: 
        !          4715: /**
        !          4716:  * xmlXPathRegisterFunc:
        !          4717:  * @ctxt:  the XPath context
        !          4718:  * @name:  the function name
        !          4719:  * @f:  the function implementation or NULL
        !          4720:  *
        !          4721:  * Register a new function. If @f is NULL it unregisters the function
        !          4722:  *
        !          4723:  * Returns 0 in case of success, -1 in case of error
        !          4724:  */
        !          4725: int
        !          4726: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4727:                     xmlXPathFunction f) {
        !          4728:     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
        !          4729: }
        !          4730: 
        !          4731: /**
        !          4732:  * xmlXPathRegisterFuncNS:
        !          4733:  * @ctxt:  the XPath context
        !          4734:  * @name:  the function name
        !          4735:  * @ns_uri:  the function namespace URI
        !          4736:  * @f:  the function implementation or NULL
        !          4737:  *
        !          4738:  * Register a new function. If @f is NULL it unregisters the function
        !          4739:  *
        !          4740:  * Returns 0 in case of success, -1 in case of error
        !          4741:  */
        !          4742: int
        !          4743: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4744:                       const xmlChar *ns_uri, xmlXPathFunction f) {
        !          4745:     if (ctxt == NULL)
        !          4746:        return(-1);
        !          4747:     if (name == NULL)
        !          4748:        return(-1);
        !          4749: 
        !          4750:     if (ctxt->funcHash == NULL)
        !          4751:        ctxt->funcHash = xmlHashCreate(0);
        !          4752:     if (ctxt->funcHash == NULL)
        !          4753:        return(-1);
        !          4754:     if (f == NULL)
        !          4755:         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
        !          4756:     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
        !          4757: }
        !          4758: 
        !          4759: /**
        !          4760:  * xmlXPathRegisterFuncLookup:
        !          4761:  * @ctxt:  the XPath context
        !          4762:  * @f:  the lookup function
        !          4763:  * @funcCtxt:  the lookup data
        !          4764:  *
        !          4765:  * Registers an external mechanism to do function lookup.
        !          4766:  */
        !          4767: void
        !          4768: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
        !          4769:                            xmlXPathFuncLookupFunc f,
        !          4770:                            void *funcCtxt) {
        !          4771:     if (ctxt == NULL)
        !          4772:        return;
        !          4773:     ctxt->funcLookupFunc = f;
        !          4774:     ctxt->funcLookupData = funcCtxt;
        !          4775: }
        !          4776: 
        !          4777: /**
        !          4778:  * xmlXPathFunctionLookup:
        !          4779:  * @ctxt:  the XPath context
        !          4780:  * @name:  the function name
        !          4781:  *
        !          4782:  * Search in the Function array of the context for the given
        !          4783:  * function.
        !          4784:  *
        !          4785:  * Returns the xmlXPathFunction or NULL if not found
        !          4786:  */
        !          4787: xmlXPathFunction
        !          4788: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
        !          4789:     if (ctxt == NULL)
        !          4790:        return (NULL);
        !          4791: 
        !          4792:     if (ctxt->funcLookupFunc != NULL) {
        !          4793:        xmlXPathFunction ret;
        !          4794:        xmlXPathFuncLookupFunc f;
        !          4795: 
        !          4796:        f = ctxt->funcLookupFunc;
        !          4797:        ret = f(ctxt->funcLookupData, name, NULL);
        !          4798:        if (ret != NULL)
        !          4799:            return(ret);
        !          4800:     }
        !          4801:     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
        !          4802: }
        !          4803: 
        !          4804: /**
        !          4805:  * xmlXPathFunctionLookupNS:
        !          4806:  * @ctxt:  the XPath context
        !          4807:  * @name:  the function name
        !          4808:  * @ns_uri:  the function namespace URI
        !          4809:  *
        !          4810:  * Search in the Function array of the context for the given
        !          4811:  * function.
        !          4812:  *
        !          4813:  * Returns the xmlXPathFunction or NULL if not found
        !          4814:  */
        !          4815: xmlXPathFunction
        !          4816: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4817:                         const xmlChar *ns_uri) {
        !          4818:     xmlXPathFunction ret;
        !          4819: 
        !          4820:     if (ctxt == NULL)
        !          4821:        return(NULL);
        !          4822:     if (name == NULL)
        !          4823:        return(NULL);
        !          4824: 
        !          4825:     if (ctxt->funcLookupFunc != NULL) {
        !          4826:        xmlXPathFuncLookupFunc f;
        !          4827: 
        !          4828:        f = ctxt->funcLookupFunc;
        !          4829:        ret = f(ctxt->funcLookupData, name, ns_uri);
        !          4830:        if (ret != NULL)
        !          4831:            return(ret);
        !          4832:     }
        !          4833: 
        !          4834:     if (ctxt->funcHash == NULL)
        !          4835:        return(NULL);
        !          4836: 
        !          4837:     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
        !          4838:     return(ret);
        !          4839: }
        !          4840: 
        !          4841: /**
        !          4842:  * xmlXPathRegisteredFuncsCleanup:
        !          4843:  * @ctxt:  the XPath context
        !          4844:  *
        !          4845:  * Cleanup the XPath context data associated to registered functions
        !          4846:  */
        !          4847: void
        !          4848: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
        !          4849:     if (ctxt == NULL)
        !          4850:        return;
        !          4851: 
        !          4852:     xmlHashFree(ctxt->funcHash, NULL);
        !          4853:     ctxt->funcHash = NULL;
        !          4854: }
        !          4855: 
        !          4856: /************************************************************************
        !          4857:  *                                                                     *
        !          4858:  *                     Routines to handle Variables                    *
        !          4859:  *                                                                     *
        !          4860:  ************************************************************************/
        !          4861: 
        !          4862: /**
        !          4863:  * xmlXPathRegisterVariable:
        !          4864:  * @ctxt:  the XPath context
        !          4865:  * @name:  the variable name
        !          4866:  * @value:  the variable value or NULL
        !          4867:  *
        !          4868:  * Register a new variable value. If @value is NULL it unregisters
        !          4869:  * the variable
        !          4870:  *
        !          4871:  * Returns 0 in case of success, -1 in case of error
        !          4872:  */
        !          4873: int
        !          4874: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4875:                         xmlXPathObjectPtr value) {
        !          4876:     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
        !          4877: }
        !          4878: 
        !          4879: /**
        !          4880:  * xmlXPathRegisterVariableNS:
        !          4881:  * @ctxt:  the XPath context
        !          4882:  * @name:  the variable name
        !          4883:  * @ns_uri:  the variable namespace URI
        !          4884:  * @value:  the variable value or NULL
        !          4885:  *
        !          4886:  * Register a new variable value. If @value is NULL it unregisters
        !          4887:  * the variable
        !          4888:  *
        !          4889:  * Returns 0 in case of success, -1 in case of error
        !          4890:  */
        !          4891: int
        !          4892: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4893:                           const xmlChar *ns_uri,
        !          4894:                           xmlXPathObjectPtr value) {
        !          4895:     if (ctxt == NULL)
        !          4896:        return(-1);
        !          4897:     if (name == NULL)
        !          4898:        return(-1);
        !          4899: 
        !          4900:     if (ctxt->varHash == NULL)
        !          4901:        ctxt->varHash = xmlHashCreate(0);
        !          4902:     if (ctxt->varHash == NULL)
        !          4903:        return(-1);
        !          4904:     if (value == NULL)
        !          4905:         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
        !          4906:                                   (xmlHashDeallocator)xmlXPathFreeObject));
        !          4907:     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
        !          4908:                               (void *) value,
        !          4909:                               (xmlHashDeallocator)xmlXPathFreeObject));
        !          4910: }
        !          4911: 
        !          4912: /**
        !          4913:  * xmlXPathRegisterVariableLookup:
        !          4914:  * @ctxt:  the XPath context
        !          4915:  * @f:  the lookup function
        !          4916:  * @data:  the lookup data
        !          4917:  *
        !          4918:  * register an external mechanism to do variable lookup
        !          4919:  */
        !          4920: void
        !          4921: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
        !          4922:         xmlXPathVariableLookupFunc f, void *data) {
        !          4923:     if (ctxt == NULL)
        !          4924:        return;
        !          4925:     ctxt->varLookupFunc = f;
        !          4926:     ctxt->varLookupData = data;
        !          4927: }
        !          4928: 
        !          4929: /**
        !          4930:  * xmlXPathVariableLookup:
        !          4931:  * @ctxt:  the XPath context
        !          4932:  * @name:  the variable name
        !          4933:  *
        !          4934:  * Search in the Variable array of the context for the given
        !          4935:  * variable value.
        !          4936:  *
        !          4937:  * Returns a copy of the value or NULL if not found
        !          4938:  */
        !          4939: xmlXPathObjectPtr
        !          4940: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
        !          4941:     if (ctxt == NULL)
        !          4942:        return(NULL);
        !          4943: 
        !          4944:     if (ctxt->varLookupFunc != NULL) {
        !          4945:        xmlXPathObjectPtr ret;
        !          4946: 
        !          4947:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
        !          4948:                (ctxt->varLookupData, name, NULL);
        !          4949:        return(ret);
        !          4950:     }
        !          4951:     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
        !          4952: }
        !          4953: 
        !          4954: /**
        !          4955:  * xmlXPathVariableLookupNS:
        !          4956:  * @ctxt:  the XPath context
        !          4957:  * @name:  the variable name
        !          4958:  * @ns_uri:  the variable namespace URI
        !          4959:  *
        !          4960:  * Search in the Variable array of the context for the given
        !          4961:  * variable value.
        !          4962:  *
        !          4963:  * Returns the a copy of the value or NULL if not found
        !          4964:  */
        !          4965: xmlXPathObjectPtr
        !          4966: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
        !          4967:                         const xmlChar *ns_uri) {
        !          4968:     if (ctxt == NULL)
        !          4969:        return(NULL);
        !          4970: 
        !          4971:     if (ctxt->varLookupFunc != NULL) {
        !          4972:        xmlXPathObjectPtr ret;
        !          4973: 
        !          4974:        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
        !          4975:                (ctxt->varLookupData, name, ns_uri);
        !          4976:        if (ret != NULL) return(ret);
        !          4977:     }
        !          4978: 
        !          4979:     if (ctxt->varHash == NULL)
        !          4980:        return(NULL);
        !          4981:     if (name == NULL)
        !          4982:        return(NULL);
        !          4983: 
        !          4984:     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
        !          4985:                xmlHashLookup2(ctxt->varHash, name, ns_uri)));
        !          4986: }
        !          4987: 
        !          4988: /**
        !          4989:  * xmlXPathRegisteredVariablesCleanup:
        !          4990:  * @ctxt:  the XPath context
        !          4991:  *
        !          4992:  * Cleanup the XPath context data associated to registered variables
        !          4993:  */
        !          4994: void
        !          4995: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
        !          4996:     if (ctxt == NULL)
        !          4997:        return;
        !          4998: 
        !          4999:     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
        !          5000:     ctxt->varHash = NULL;
        !          5001: }
        !          5002: 
        !          5003: /**
        !          5004:  * xmlXPathRegisterNs:
        !          5005:  * @ctxt:  the XPath context
        !          5006:  * @prefix:  the namespace prefix cannot be NULL or empty string
        !          5007:  * @ns_uri:  the namespace name
        !          5008:  *
        !          5009:  * Register a new namespace. If @ns_uri is NULL it unregisters
        !          5010:  * the namespace
        !          5011:  *
        !          5012:  * Returns 0 in case of success, -1 in case of error
        !          5013:  */
        !          5014: int
        !          5015: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
        !          5016:                           const xmlChar *ns_uri) {
        !          5017:     if (ctxt == NULL)
        !          5018:        return(-1);
        !          5019:     if (prefix == NULL)
        !          5020:        return(-1);
        !          5021:     if (prefix[0] == 0)
        !          5022:        return(-1);
        !          5023: 
        !          5024:     if (ctxt->nsHash == NULL)
        !          5025:        ctxt->nsHash = xmlHashCreate(10);
        !          5026:     if (ctxt->nsHash == NULL)
        !          5027:        return(-1);
        !          5028:     if (ns_uri == NULL)
        !          5029:         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
        !          5030:                                  (xmlHashDeallocator)xmlFree));
        !          5031:     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
        !          5032:                              (xmlHashDeallocator)xmlFree));
        !          5033: }
        !          5034: 
        !          5035: /**
        !          5036:  * xmlXPathNsLookup:
        !          5037:  * @ctxt:  the XPath context
        !          5038:  * @prefix:  the namespace prefix value
        !          5039:  *
        !          5040:  * Search in the namespace declaration array of the context for the given
        !          5041:  * namespace name associated to the given prefix
        !          5042:  *
        !          5043:  * Returns the value or NULL if not found
        !          5044:  */
        !          5045: const xmlChar *
        !          5046: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
        !          5047:     if (ctxt == NULL)
        !          5048:        return(NULL);
        !          5049:     if (prefix == NULL)
        !          5050:        return(NULL);
        !          5051: 
        !          5052: #ifdef XML_XML_NAMESPACE
        !          5053:     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
        !          5054:        return(XML_XML_NAMESPACE);
        !          5055: #endif
        !          5056: 
        !          5057:     if (ctxt->namespaces != NULL) {
        !          5058:        int i;
        !          5059: 
        !          5060:        for (i = 0;i < ctxt->nsNr;i++) {
        !          5061:            if ((ctxt->namespaces[i] != NULL) &&
        !          5062:                (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
        !          5063:                return(ctxt->namespaces[i]->href);
        !          5064:        }
        !          5065:     }
        !          5066: 
        !          5067:     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
        !          5068: }
        !          5069: 
        !          5070: /**
        !          5071:  * xmlXPathRegisteredNsCleanup:
        !          5072:  * @ctxt:  the XPath context
        !          5073:  *
        !          5074:  * Cleanup the XPath context data associated to registered variables
        !          5075:  */
        !          5076: void
        !          5077: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
        !          5078:     if (ctxt == NULL)
        !          5079:        return;
        !          5080: 
        !          5081:     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
        !          5082:     ctxt->nsHash = NULL;
        !          5083: }
        !          5084: 
        !          5085: /************************************************************************
        !          5086:  *                                                                     *
        !          5087:  *                     Routines to handle Values                       *
        !          5088:  *                                                                     *
        !          5089:  ************************************************************************/
        !          5090: 
        !          5091: /* Allocations are terrible, one needs to optimize all this !!! */
        !          5092: 
        !          5093: /**
        !          5094:  * xmlXPathNewFloat:
        !          5095:  * @val:  the double value
        !          5096:  *
        !          5097:  * Create a new xmlXPathObjectPtr of type double and of value @val
        !          5098:  *
        !          5099:  * Returns the newly created object.
        !          5100:  */
        !          5101: xmlXPathObjectPtr
        !          5102: xmlXPathNewFloat(double val) {
        !          5103:     xmlXPathObjectPtr ret;
        !          5104: 
        !          5105:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5106:     if (ret == NULL) {
        !          5107:         xmlXPathErrMemory(NULL, "creating float object\n");
        !          5108:        return(NULL);
        !          5109:     }
        !          5110:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5111:     ret->type = XPATH_NUMBER;
        !          5112:     ret->floatval = val;
        !          5113: #ifdef XP_DEBUG_OBJ_USAGE
        !          5114:     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
        !          5115: #endif
        !          5116:     return(ret);
        !          5117: }
        !          5118: 
        !          5119: /**
        !          5120:  * xmlXPathNewBoolean:
        !          5121:  * @val:  the boolean value
        !          5122:  *
        !          5123:  * Create a new xmlXPathObjectPtr of type boolean and of value @val
        !          5124:  *
        !          5125:  * Returns the newly created object.
        !          5126:  */
        !          5127: xmlXPathObjectPtr
        !          5128: xmlXPathNewBoolean(int val) {
        !          5129:     xmlXPathObjectPtr ret;
        !          5130: 
        !          5131:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5132:     if (ret == NULL) {
        !          5133:         xmlXPathErrMemory(NULL, "creating boolean object\n");
        !          5134:        return(NULL);
        !          5135:     }
        !          5136:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5137:     ret->type = XPATH_BOOLEAN;
        !          5138:     ret->boolval = (val != 0);
        !          5139: #ifdef XP_DEBUG_OBJ_USAGE
        !          5140:     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
        !          5141: #endif
        !          5142:     return(ret);
        !          5143: }
        !          5144: 
        !          5145: /**
        !          5146:  * xmlXPathNewString:
        !          5147:  * @val:  the xmlChar * value
        !          5148:  *
        !          5149:  * Create a new xmlXPathObjectPtr of type string and of value @val
        !          5150:  *
        !          5151:  * Returns the newly created object.
        !          5152:  */
        !          5153: xmlXPathObjectPtr
        !          5154: xmlXPathNewString(const xmlChar *val) {
        !          5155:     xmlXPathObjectPtr ret;
        !          5156: 
        !          5157:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5158:     if (ret == NULL) {
        !          5159:         xmlXPathErrMemory(NULL, "creating string object\n");
        !          5160:        return(NULL);
        !          5161:     }
        !          5162:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5163:     ret->type = XPATH_STRING;
        !          5164:     if (val != NULL)
        !          5165:        ret->stringval = xmlStrdup(val);
        !          5166:     else
        !          5167:        ret->stringval = xmlStrdup((const xmlChar *)"");
        !          5168: #ifdef XP_DEBUG_OBJ_USAGE
        !          5169:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
        !          5170: #endif
        !          5171:     return(ret);
        !          5172: }
        !          5173: 
        !          5174: /**
        !          5175:  * xmlXPathWrapString:
        !          5176:  * @val:  the xmlChar * value
        !          5177:  *
        !          5178:  * Wraps the @val string into an XPath object.
        !          5179:  *
        !          5180:  * Returns the newly created object.
        !          5181:  */
        !          5182: xmlXPathObjectPtr
        !          5183: xmlXPathWrapString (xmlChar *val) {
        !          5184:     xmlXPathObjectPtr ret;
        !          5185: 
        !          5186:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5187:     if (ret == NULL) {
        !          5188:         xmlXPathErrMemory(NULL, "creating string object\n");
        !          5189:        return(NULL);
        !          5190:     }
        !          5191:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5192:     ret->type = XPATH_STRING;
        !          5193:     ret->stringval = val;
        !          5194: #ifdef XP_DEBUG_OBJ_USAGE
        !          5195:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
        !          5196: #endif
        !          5197:     return(ret);
        !          5198: }
        !          5199: 
        !          5200: /**
        !          5201:  * xmlXPathNewCString:
        !          5202:  * @val:  the char * value
        !          5203:  *
        !          5204:  * Create a new xmlXPathObjectPtr of type string and of value @val
        !          5205:  *
        !          5206:  * Returns the newly created object.
        !          5207:  */
        !          5208: xmlXPathObjectPtr
        !          5209: xmlXPathNewCString(const char *val) {
        !          5210:     xmlXPathObjectPtr ret;
        !          5211: 
        !          5212:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5213:     if (ret == NULL) {
        !          5214:         xmlXPathErrMemory(NULL, "creating string object\n");
        !          5215:        return(NULL);
        !          5216:     }
        !          5217:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5218:     ret->type = XPATH_STRING;
        !          5219:     ret->stringval = xmlStrdup(BAD_CAST val);
        !          5220: #ifdef XP_DEBUG_OBJ_USAGE
        !          5221:     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
        !          5222: #endif
        !          5223:     return(ret);
        !          5224: }
        !          5225: 
        !          5226: /**
        !          5227:  * xmlXPathWrapCString:
        !          5228:  * @val:  the char * value
        !          5229:  *
        !          5230:  * Wraps a string into an XPath object.
        !          5231:  *
        !          5232:  * Returns the newly created object.
        !          5233:  */
        !          5234: xmlXPathObjectPtr
        !          5235: xmlXPathWrapCString (char * val) {
        !          5236:     return(xmlXPathWrapString((xmlChar *)(val)));
        !          5237: }
        !          5238: 
        !          5239: /**
        !          5240:  * xmlXPathWrapExternal:
        !          5241:  * @val:  the user data
        !          5242:  *
        !          5243:  * Wraps the @val data into an XPath object.
        !          5244:  *
        !          5245:  * Returns the newly created object.
        !          5246:  */
        !          5247: xmlXPathObjectPtr
        !          5248: xmlXPathWrapExternal (void *val) {
        !          5249:     xmlXPathObjectPtr ret;
        !          5250: 
        !          5251:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5252:     if (ret == NULL) {
        !          5253:         xmlXPathErrMemory(NULL, "creating user object\n");
        !          5254:        return(NULL);
        !          5255:     }
        !          5256:     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
        !          5257:     ret->type = XPATH_USERS;
        !          5258:     ret->user = val;
        !          5259: #ifdef XP_DEBUG_OBJ_USAGE
        !          5260:     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
        !          5261: #endif
        !          5262:     return(ret);
        !          5263: }
        !          5264: 
        !          5265: /**
        !          5266:  * xmlXPathObjectCopy:
        !          5267:  * @val:  the original object
        !          5268:  *
        !          5269:  * allocate a new copy of a given object
        !          5270:  *
        !          5271:  * Returns the newly created object.
        !          5272:  */
        !          5273: xmlXPathObjectPtr
        !          5274: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
        !          5275:     xmlXPathObjectPtr ret;
        !          5276: 
        !          5277:     if (val == NULL)
        !          5278:        return(NULL);
        !          5279: 
        !          5280:     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
        !          5281:     if (ret == NULL) {
        !          5282:         xmlXPathErrMemory(NULL, "copying object\n");
        !          5283:        return(NULL);
        !          5284:     }
        !          5285:     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
        !          5286: #ifdef XP_DEBUG_OBJ_USAGE
        !          5287:     xmlXPathDebugObjUsageRequested(NULL, val->type);
        !          5288: #endif
        !          5289:     switch (val->type) {
        !          5290:        case XPATH_BOOLEAN:
        !          5291:        case XPATH_NUMBER:
        !          5292:        case XPATH_POINT:
        !          5293:        case XPATH_RANGE:
        !          5294:            break;
        !          5295:        case XPATH_STRING:
        !          5296:            ret->stringval = xmlStrdup(val->stringval);
        !          5297:            break;
        !          5298:        case XPATH_XSLT_TREE:
        !          5299: #if 0
        !          5300: /*
        !          5301:   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
        !          5302:   this previous handling is no longer correct, and can cause some serious
        !          5303:   problems (ref. bug 145547)
        !          5304: */
        !          5305:            if ((val->nodesetval != NULL) &&
        !          5306:                (val->nodesetval->nodeTab != NULL)) {
        !          5307:                xmlNodePtr cur, tmp;
        !          5308:                xmlDocPtr top;
        !          5309: 
        !          5310:                ret->boolval = 1;
        !          5311:                top =  xmlNewDoc(NULL);
        !          5312:                top->name = (char *)
        !          5313:                    xmlStrdup(val->nodesetval->nodeTab[0]->name);
        !          5314:                ret->user = top;
        !          5315:                if (top != NULL) {
        !          5316:                    top->doc = top;
        !          5317:                    cur = val->nodesetval->nodeTab[0]->children;
        !          5318:                    while (cur != NULL) {
        !          5319:                        tmp = xmlDocCopyNode(cur, top, 1);
        !          5320:                        xmlAddChild((xmlNodePtr) top, tmp);
        !          5321:                        cur = cur->next;
        !          5322:                    }
        !          5323:                }
        !          5324: 
        !          5325:                ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
        !          5326:            } else
        !          5327:                ret->nodesetval = xmlXPathNodeSetCreate(NULL);
        !          5328:            /* Deallocate the copied tree value */
        !          5329:            break;
        !          5330: #endif
        !          5331:        case XPATH_NODESET:
        !          5332:            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
        !          5333:            /* Do not deallocate the copied tree value */
        !          5334:            ret->boolval = 0;
        !          5335:            break;
        !          5336:        case XPATH_LOCATIONSET:
        !          5337: #ifdef LIBXML_XPTR_ENABLED
        !          5338:        {
        !          5339:            xmlLocationSetPtr loc = val->user;
        !          5340:            ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
        !          5341:            break;
        !          5342:        }
        !          5343: #endif
        !          5344:         case XPATH_USERS:
        !          5345:            ret->user = val->user;
        !          5346:            break;
        !          5347:         case XPATH_UNDEFINED:
        !          5348:            xmlGenericError(xmlGenericErrorContext,
        !          5349:                    "xmlXPathObjectCopy: unsupported type %d\n",
        !          5350:                    val->type);
        !          5351:            break;
        !          5352:     }
        !          5353:     return(ret);
        !          5354: }
        !          5355: 
        !          5356: /**
        !          5357:  * xmlXPathFreeObject:
        !          5358:  * @obj:  the object to free
        !          5359:  *
        !          5360:  * Free up an xmlXPathObjectPtr object.
        !          5361:  */
        !          5362: void
        !          5363: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
        !          5364:     if (obj == NULL) return;
        !          5365:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
        !          5366:        if (obj->boolval) {
        !          5367: #if 0
        !          5368:            if (obj->user != NULL) {
        !          5369:                 xmlXPathFreeNodeSet(obj->nodesetval);
        !          5370:                xmlFreeNodeList((xmlNodePtr) obj->user);
        !          5371:            } else
        !          5372: #endif
        !          5373:            obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
        !          5374:            if (obj->nodesetval != NULL)
        !          5375:                xmlXPathFreeValueTree(obj->nodesetval);
        !          5376:        } else {
        !          5377:            if (obj->nodesetval != NULL)
        !          5378:                xmlXPathFreeNodeSet(obj->nodesetval);
        !          5379:        }
        !          5380: #ifdef LIBXML_XPTR_ENABLED
        !          5381:     } else if (obj->type == XPATH_LOCATIONSET) {
        !          5382:        if (obj->user != NULL)
        !          5383:            xmlXPtrFreeLocationSet(obj->user);
        !          5384: #endif
        !          5385:     } else if (obj->type == XPATH_STRING) {
        !          5386:        if (obj->stringval != NULL)
        !          5387:            xmlFree(obj->stringval);
        !          5388:     }
        !          5389: #ifdef XP_DEBUG_OBJ_USAGE
        !          5390:     xmlXPathDebugObjUsageReleased(NULL, obj->type);
        !          5391: #endif
        !          5392:     xmlFree(obj);
        !          5393: }
        !          5394: 
        !          5395: /**
        !          5396:  * xmlXPathReleaseObject:
        !          5397:  * @obj:  the xmlXPathObjectPtr to free or to cache
        !          5398:  *
        !          5399:  * Depending on the state of the cache this frees the given
        !          5400:  * XPath object or stores it in the cache.
        !          5401:  */
        !          5402: static void
        !          5403: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
        !          5404: {
        !          5405: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
        !          5406:        sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
        !          5407:     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
        !          5408: 
        !          5409: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
        !          5410: 
        !          5411:     if (obj == NULL)
        !          5412:        return;
        !          5413:     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
        !          5414:         xmlXPathFreeObject(obj);
        !          5415:     } else {
        !          5416:        xmlXPathContextCachePtr cache =
        !          5417:            (xmlXPathContextCachePtr) ctxt->cache;
        !          5418: 
        !          5419:        switch (obj->type) {
        !          5420:            case XPATH_NODESET:
        !          5421:            case XPATH_XSLT_TREE:
        !          5422:                if (obj->nodesetval != NULL) {
        !          5423:                    if (obj->boolval) {
        !          5424:                        /*
        !          5425:                        * It looks like the @boolval is used for
        !          5426:                        * evaluation if this an XSLT Result Tree Fragment.
        !          5427:                        * TODO: Check if this assumption is correct.
        !          5428:                        */
        !          5429:                        obj->type = XPATH_XSLT_TREE; /* just for debugging */
        !          5430:                        xmlXPathFreeValueTree(obj->nodesetval);
        !          5431:                        obj->nodesetval = NULL;
        !          5432:                    } else if ((obj->nodesetval->nodeMax <= 40) &&
        !          5433:                        (XP_CACHE_WANTS(cache->nodesetObjs,
        !          5434:                                        cache->maxNodeset)))
        !          5435:                    {
        !          5436:                        XP_CACHE_ADD(cache->nodesetObjs, obj);
        !          5437:                        goto obj_cached;
        !          5438:                    } else {
        !          5439:                        xmlXPathFreeNodeSet(obj->nodesetval);
        !          5440:                        obj->nodesetval = NULL;
        !          5441:                    }
        !          5442:                }
        !          5443:                break;
        !          5444:            case XPATH_STRING:
        !          5445:                if (obj->stringval != NULL)
        !          5446:                    xmlFree(obj->stringval);
        !          5447: 
        !          5448:                if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
        !          5449:                    XP_CACHE_ADD(cache->stringObjs, obj);
        !          5450:                    goto obj_cached;
        !          5451:                }
        !          5452:                break;
        !          5453:            case XPATH_BOOLEAN:
        !          5454:                if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
        !          5455:                    XP_CACHE_ADD(cache->booleanObjs, obj);
        !          5456:                    goto obj_cached;
        !          5457:                }
        !          5458:                break;
        !          5459:            case XPATH_NUMBER:
        !          5460:                if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
        !          5461:                    XP_CACHE_ADD(cache->numberObjs, obj);
        !          5462:                    goto obj_cached;
        !          5463:                }
        !          5464:                break;
        !          5465: #ifdef LIBXML_XPTR_ENABLED
        !          5466:            case XPATH_LOCATIONSET:
        !          5467:                if (obj->user != NULL) {
        !          5468:                    xmlXPtrFreeLocationSet(obj->user);
        !          5469:                }
        !          5470:                goto free_obj;
        !          5471: #endif
        !          5472:            default:
        !          5473:                goto free_obj;
        !          5474:        }
        !          5475: 
        !          5476:        /*
        !          5477:        * Fallback to adding to the misc-objects slot.
        !          5478:        */
        !          5479:        if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
        !          5480:            XP_CACHE_ADD(cache->miscObjs, obj);
        !          5481:        } else
        !          5482:            goto free_obj;
        !          5483: 
        !          5484: obj_cached:
        !          5485: 
        !          5486: #ifdef XP_DEBUG_OBJ_USAGE
        !          5487:        xmlXPathDebugObjUsageReleased(ctxt, obj->type);
        !          5488: #endif
        !          5489: 
        !          5490:        if (obj->nodesetval != NULL) {
        !          5491:            xmlNodeSetPtr tmpset = obj->nodesetval;
        !          5492: 
        !          5493:            /*
        !          5494:            * TODO: Due to those nasty ns-nodes, we need to traverse
        !          5495:            *  the list and free the ns-nodes.
        !          5496:            * URGENT TODO: Check if it's actually slowing things down.
        !          5497:            *  Maybe we shouldn't try to preserve the list.
        !          5498:            */
        !          5499:            if (tmpset->nodeNr > 1) {
        !          5500:                int i;
        !          5501:                xmlNodePtr node;
        !          5502: 
        !          5503:                for (i = 0; i < tmpset->nodeNr; i++) {
        !          5504:                    node = tmpset->nodeTab[i];
        !          5505:                    if ((node != NULL) &&
        !          5506:                        (node->type == XML_NAMESPACE_DECL))
        !          5507:                    {
        !          5508:                        xmlXPathNodeSetFreeNs((xmlNsPtr) node);
        !          5509:                    }
        !          5510:                }
        !          5511:            } else if (tmpset->nodeNr == 1) {
        !          5512:                if ((tmpset->nodeTab[0] != NULL) &&
        !          5513:                    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
        !          5514:                    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
        !          5515:            }
        !          5516:            tmpset->nodeNr = 0;
        !          5517:            memset(obj, 0, sizeof(xmlXPathObject));
        !          5518:            obj->nodesetval = tmpset;
        !          5519:        } else
        !          5520:            memset(obj, 0, sizeof(xmlXPathObject));
        !          5521: 
        !          5522:        return;
        !          5523: 
        !          5524: free_obj:
        !          5525:        /*
        !          5526:        * Cache is full; free the object.
        !          5527:        */
        !          5528:        if (obj->nodesetval != NULL)
        !          5529:            xmlXPathFreeNodeSet(obj->nodesetval);
        !          5530: #ifdef XP_DEBUG_OBJ_USAGE
        !          5531:        xmlXPathDebugObjUsageReleased(NULL, obj->type);
        !          5532: #endif
        !          5533:        xmlFree(obj);
        !          5534:     }
        !          5535:     return;
        !          5536: }
        !          5537: 
        !          5538: 
        !          5539: /************************************************************************
        !          5540:  *                                                                     *
        !          5541:  *                     Type Casting Routines                           *
        !          5542:  *                                                                     *
        !          5543:  ************************************************************************/
        !          5544: 
        !          5545: /**
        !          5546:  * xmlXPathCastBooleanToString:
        !          5547:  * @val:  a boolean
        !          5548:  *
        !          5549:  * Converts a boolean to its string value.
        !          5550:  *
        !          5551:  * Returns a newly allocated string.
        !          5552:  */
        !          5553: xmlChar *
        !          5554: xmlXPathCastBooleanToString (int val) {
        !          5555:     xmlChar *ret;
        !          5556:     if (val)
        !          5557:        ret = xmlStrdup((const xmlChar *) "true");
        !          5558:     else
        !          5559:        ret = xmlStrdup((const xmlChar *) "false");
        !          5560:     return(ret);
        !          5561: }
        !          5562: 
        !          5563: /**
        !          5564:  * xmlXPathCastNumberToString:
        !          5565:  * @val:  a number
        !          5566:  *
        !          5567:  * Converts a number to its string value.
        !          5568:  *
        !          5569:  * Returns a newly allocated string.
        !          5570:  */
        !          5571: xmlChar *
        !          5572: xmlXPathCastNumberToString (double val) {
        !          5573:     xmlChar *ret;
        !          5574:     switch (xmlXPathIsInf(val)) {
        !          5575:     case 1:
        !          5576:        ret = xmlStrdup((const xmlChar *) "Infinity");
        !          5577:        break;
        !          5578:     case -1:
        !          5579:        ret = xmlStrdup((const xmlChar *) "-Infinity");
        !          5580:        break;
        !          5581:     default:
        !          5582:        if (xmlXPathIsNaN(val)) {
        !          5583:            ret = xmlStrdup((const xmlChar *) "NaN");
        !          5584:        } else if (val == 0 && xmlXPathGetSign(val) != 0) {
        !          5585:            ret = xmlStrdup((const xmlChar *) "0");
        !          5586:        } else {
        !          5587:            /* could be improved */
        !          5588:            char buf[100];
        !          5589:            xmlXPathFormatNumber(val, buf, 99);
        !          5590:            buf[99] = 0;
        !          5591:            ret = xmlStrdup((const xmlChar *) buf);
        !          5592:        }
        !          5593:     }
        !          5594:     return(ret);
        !          5595: }
        !          5596: 
        !          5597: /**
        !          5598:  * xmlXPathCastNodeToString:
        !          5599:  * @node:  a node
        !          5600:  *
        !          5601:  * Converts a node to its string value.
        !          5602:  *
        !          5603:  * Returns a newly allocated string.
        !          5604:  */
        !          5605: xmlChar *
        !          5606: xmlXPathCastNodeToString (xmlNodePtr node) {
        !          5607: xmlChar *ret;
        !          5608:     if ((ret = xmlNodeGetContent(node)) == NULL)
        !          5609:        ret = xmlStrdup((const xmlChar *) "");
        !          5610:     return(ret);
        !          5611: }
        !          5612: 
        !          5613: /**
        !          5614:  * xmlXPathCastNodeSetToString:
        !          5615:  * @ns:  a node-set
        !          5616:  *
        !          5617:  * Converts a node-set to its string value.
        !          5618:  *
        !          5619:  * Returns a newly allocated string.
        !          5620:  */
        !          5621: xmlChar *
        !          5622: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
        !          5623:     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
        !          5624:        return(xmlStrdup((const xmlChar *) ""));
        !          5625: 
        !          5626:     if (ns->nodeNr > 1)
        !          5627:        xmlXPathNodeSetSort(ns);
        !          5628:     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
        !          5629: }
        !          5630: 
        !          5631: /**
        !          5632:  * xmlXPathCastToString:
        !          5633:  * @val:  an XPath object
        !          5634:  *
        !          5635:  * Converts an existing object to its string() equivalent
        !          5636:  *
        !          5637:  * Returns the allocated string value of the object, NULL in case of error.
        !          5638:  *         It's up to the caller to free the string memory with xmlFree().
        !          5639:  */
        !          5640: xmlChar *
        !          5641: xmlXPathCastToString(xmlXPathObjectPtr val) {
        !          5642:     xmlChar *ret = NULL;
        !          5643: 
        !          5644:     if (val == NULL)
        !          5645:        return(xmlStrdup((const xmlChar *) ""));
        !          5646:     switch (val->type) {
        !          5647:        case XPATH_UNDEFINED:
        !          5648: #ifdef DEBUG_EXPR
        !          5649:            xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
        !          5650: #endif
        !          5651:            ret = xmlStrdup((const xmlChar *) "");
        !          5652:            break;
        !          5653:         case XPATH_NODESET:
        !          5654:         case XPATH_XSLT_TREE:
        !          5655:            ret = xmlXPathCastNodeSetToString(val->nodesetval);
        !          5656:            break;
        !          5657:        case XPATH_STRING:
        !          5658:            return(xmlStrdup(val->stringval));
        !          5659:         case XPATH_BOOLEAN:
        !          5660:            ret = xmlXPathCastBooleanToString(val->boolval);
        !          5661:            break;
        !          5662:        case XPATH_NUMBER: {
        !          5663:            ret = xmlXPathCastNumberToString(val->floatval);
        !          5664:            break;
        !          5665:        }
        !          5666:        case XPATH_USERS:
        !          5667:        case XPATH_POINT:
        !          5668:        case XPATH_RANGE:
        !          5669:        case XPATH_LOCATIONSET:
        !          5670:            TODO
        !          5671:            ret = xmlStrdup((const xmlChar *) "");
        !          5672:            break;
        !          5673:     }
        !          5674:     return(ret);
        !          5675: }
        !          5676: 
        !          5677: /**
        !          5678:  * xmlXPathConvertString:
        !          5679:  * @val:  an XPath object
        !          5680:  *
        !          5681:  * Converts an existing object to its string() equivalent
        !          5682:  *
        !          5683:  * Returns the new object, the old one is freed (or the operation
        !          5684:  *         is done directly on @val)
        !          5685:  */
        !          5686: xmlXPathObjectPtr
        !          5687: xmlXPathConvertString(xmlXPathObjectPtr val) {
        !          5688:     xmlChar *res = NULL;
        !          5689: 
        !          5690:     if (val == NULL)
        !          5691:        return(xmlXPathNewCString(""));
        !          5692: 
        !          5693:     switch (val->type) {
        !          5694:     case XPATH_UNDEFINED:
        !          5695: #ifdef DEBUG_EXPR
        !          5696:        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
        !          5697: #endif
        !          5698:        break;
        !          5699:     case XPATH_NODESET:
        !          5700:     case XPATH_XSLT_TREE:
        !          5701:        res = xmlXPathCastNodeSetToString(val->nodesetval);
        !          5702:        break;
        !          5703:     case XPATH_STRING:
        !          5704:        return(val);
        !          5705:     case XPATH_BOOLEAN:
        !          5706:        res = xmlXPathCastBooleanToString(val->boolval);
        !          5707:        break;
        !          5708:     case XPATH_NUMBER:
        !          5709:        res = xmlXPathCastNumberToString(val->floatval);
        !          5710:        break;
        !          5711:     case XPATH_USERS:
        !          5712:     case XPATH_POINT:
        !          5713:     case XPATH_RANGE:
        !          5714:     case XPATH_LOCATIONSET:
        !          5715:        TODO;
        !          5716:        break;
        !          5717:     }
        !          5718:     xmlXPathFreeObject(val);
        !          5719:     if (res == NULL)
        !          5720:        return(xmlXPathNewCString(""));
        !          5721:     return(xmlXPathWrapString(res));
        !          5722: }
        !          5723: 
        !          5724: /**
        !          5725:  * xmlXPathCastBooleanToNumber:
        !          5726:  * @val:  a boolean
        !          5727:  *
        !          5728:  * Converts a boolean to its number value
        !          5729:  *
        !          5730:  * Returns the number value
        !          5731:  */
        !          5732: double
        !          5733: xmlXPathCastBooleanToNumber(int val) {
        !          5734:     if (val)
        !          5735:        return(1.0);
        !          5736:     return(0.0);
        !          5737: }
        !          5738: 
        !          5739: /**
        !          5740:  * xmlXPathCastStringToNumber:
        !          5741:  * @val:  a string
        !          5742:  *
        !          5743:  * Converts a string to its number value
        !          5744:  *
        !          5745:  * Returns the number value
        !          5746:  */
        !          5747: double
        !          5748: xmlXPathCastStringToNumber(const xmlChar * val) {
        !          5749:     return(xmlXPathStringEvalNumber(val));
        !          5750: }
        !          5751: 
        !          5752: /**
        !          5753:  * xmlXPathCastNodeToNumber:
        !          5754:  * @node:  a node
        !          5755:  *
        !          5756:  * Converts a node to its number value
        !          5757:  *
        !          5758:  * Returns the number value
        !          5759:  */
        !          5760: double
        !          5761: xmlXPathCastNodeToNumber (xmlNodePtr node) {
        !          5762:     xmlChar *strval;
        !          5763:     double ret;
        !          5764: 
        !          5765:     if (node == NULL)
        !          5766:        return(xmlXPathNAN);
        !          5767:     strval = xmlXPathCastNodeToString(node);
        !          5768:     if (strval == NULL)
        !          5769:        return(xmlXPathNAN);
        !          5770:     ret = xmlXPathCastStringToNumber(strval);
        !          5771:     xmlFree(strval);
        !          5772: 
        !          5773:     return(ret);
        !          5774: }
        !          5775: 
        !          5776: /**
        !          5777:  * xmlXPathCastNodeSetToNumber:
        !          5778:  * @ns:  a node-set
        !          5779:  *
        !          5780:  * Converts a node-set to its number value
        !          5781:  *
        !          5782:  * Returns the number value
        !          5783:  */
        !          5784: double
        !          5785: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
        !          5786:     xmlChar *str;
        !          5787:     double ret;
        !          5788: 
        !          5789:     if (ns == NULL)
        !          5790:        return(xmlXPathNAN);
        !          5791:     str = xmlXPathCastNodeSetToString(ns);
        !          5792:     ret = xmlXPathCastStringToNumber(str);
        !          5793:     xmlFree(str);
        !          5794:     return(ret);
        !          5795: }
        !          5796: 
        !          5797: /**
        !          5798:  * xmlXPathCastToNumber:
        !          5799:  * @val:  an XPath object
        !          5800:  *
        !          5801:  * Converts an XPath object to its number value
        !          5802:  *
        !          5803:  * Returns the number value
        !          5804:  */
        !          5805: double
        !          5806: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
        !          5807:     double ret = 0.0;
        !          5808: 
        !          5809:     if (val == NULL)
        !          5810:        return(xmlXPathNAN);
        !          5811:     switch (val->type) {
        !          5812:     case XPATH_UNDEFINED:
        !          5813: #ifdef DEGUB_EXPR
        !          5814:        xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
        !          5815: #endif
        !          5816:        ret = xmlXPathNAN;
        !          5817:        break;
        !          5818:     case XPATH_NODESET:
        !          5819:     case XPATH_XSLT_TREE:
        !          5820:        ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
        !          5821:        break;
        !          5822:     case XPATH_STRING:
        !          5823:        ret = xmlXPathCastStringToNumber(val->stringval);
        !          5824:        break;
        !          5825:     case XPATH_NUMBER:
        !          5826:        ret = val->floatval;
        !          5827:        break;
        !          5828:     case XPATH_BOOLEAN:
        !          5829:        ret = xmlXPathCastBooleanToNumber(val->boolval);
        !          5830:        break;
        !          5831:     case XPATH_USERS:
        !          5832:     case XPATH_POINT:
        !          5833:     case XPATH_RANGE:
        !          5834:     case XPATH_LOCATIONSET:
        !          5835:        TODO;
        !          5836:        ret = xmlXPathNAN;
        !          5837:        break;
        !          5838:     }
        !          5839:     return(ret);
        !          5840: }
        !          5841: 
        !          5842: /**
        !          5843:  * xmlXPathConvertNumber:
        !          5844:  * @val:  an XPath object
        !          5845:  *
        !          5846:  * Converts an existing object to its number() equivalent
        !          5847:  *
        !          5848:  * Returns the new object, the old one is freed (or the operation
        !          5849:  *         is done directly on @val)
        !          5850:  */
        !          5851: xmlXPathObjectPtr
        !          5852: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
        !          5853:     xmlXPathObjectPtr ret;
        !          5854: 
        !          5855:     if (val == NULL)
        !          5856:        return(xmlXPathNewFloat(0.0));
        !          5857:     if (val->type == XPATH_NUMBER)
        !          5858:        return(val);
        !          5859:     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
        !          5860:     xmlXPathFreeObject(val);
        !          5861:     return(ret);
        !          5862: }
        !          5863: 
        !          5864: /**
        !          5865:  * xmlXPathCastNumberToBoolean:
        !          5866:  * @val:  a number
        !          5867:  *
        !          5868:  * Converts a number to its boolean value
        !          5869:  *
        !          5870:  * Returns the boolean value
        !          5871:  */
        !          5872: int
        !          5873: xmlXPathCastNumberToBoolean (double val) {
        !          5874:      if (xmlXPathIsNaN(val) || (val == 0.0))
        !          5875:         return(0);
        !          5876:      return(1);
        !          5877: }
        !          5878: 
        !          5879: /**
        !          5880:  * xmlXPathCastStringToBoolean:
        !          5881:  * @val:  a string
        !          5882:  *
        !          5883:  * Converts a string to its boolean value
        !          5884:  *
        !          5885:  * Returns the boolean value
        !          5886:  */
        !          5887: int
        !          5888: xmlXPathCastStringToBoolean (const xmlChar *val) {
        !          5889:     if ((val == NULL) || (xmlStrlen(val) == 0))
        !          5890:        return(0);
        !          5891:     return(1);
        !          5892: }
        !          5893: 
        !          5894: /**
        !          5895:  * xmlXPathCastNodeSetToBoolean:
        !          5896:  * @ns:  a node-set
        !          5897:  *
        !          5898:  * Converts a node-set to its boolean value
        !          5899:  *
        !          5900:  * Returns the boolean value
        !          5901:  */
        !          5902: int
        !          5903: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
        !          5904:     if ((ns == NULL) || (ns->nodeNr == 0))
        !          5905:        return(0);
        !          5906:     return(1);
        !          5907: }
        !          5908: 
        !          5909: /**
        !          5910:  * xmlXPathCastToBoolean:
        !          5911:  * @val:  an XPath object
        !          5912:  *
        !          5913:  * Converts an XPath object to its boolean value
        !          5914:  *
        !          5915:  * Returns the boolean value
        !          5916:  */
        !          5917: int
        !          5918: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
        !          5919:     int ret = 0;
        !          5920: 
        !          5921:     if (val == NULL)
        !          5922:        return(0);
        !          5923:     switch (val->type) {
        !          5924:     case XPATH_UNDEFINED:
        !          5925: #ifdef DEBUG_EXPR
        !          5926:        xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
        !          5927: #endif
        !          5928:        ret = 0;
        !          5929:        break;
        !          5930:     case XPATH_NODESET:
        !          5931:     case XPATH_XSLT_TREE:
        !          5932:        ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
        !          5933:        break;
        !          5934:     case XPATH_STRING:
        !          5935:        ret = xmlXPathCastStringToBoolean(val->stringval);
        !          5936:        break;
        !          5937:     case XPATH_NUMBER:
        !          5938:        ret = xmlXPathCastNumberToBoolean(val->floatval);
        !          5939:        break;
        !          5940:     case XPATH_BOOLEAN:
        !          5941:        ret = val->boolval;
        !          5942:        break;
        !          5943:     case XPATH_USERS:
        !          5944:     case XPATH_POINT:
        !          5945:     case XPATH_RANGE:
        !          5946:     case XPATH_LOCATIONSET:
        !          5947:        TODO;
        !          5948:        ret = 0;
        !          5949:        break;
        !          5950:     }
        !          5951:     return(ret);
        !          5952: }
        !          5953: 
        !          5954: 
        !          5955: /**
        !          5956:  * xmlXPathConvertBoolean:
        !          5957:  * @val:  an XPath object
        !          5958:  *
        !          5959:  * Converts an existing object to its boolean() equivalent
        !          5960:  *
        !          5961:  * Returns the new object, the old one is freed (or the operation
        !          5962:  *         is done directly on @val)
        !          5963:  */
        !          5964: xmlXPathObjectPtr
        !          5965: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
        !          5966:     xmlXPathObjectPtr ret;
        !          5967: 
        !          5968:     if (val == NULL)
        !          5969:        return(xmlXPathNewBoolean(0));
        !          5970:     if (val->type == XPATH_BOOLEAN)
        !          5971:        return(val);
        !          5972:     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
        !          5973:     xmlXPathFreeObject(val);
        !          5974:     return(ret);
        !          5975: }
        !          5976: 
        !          5977: /************************************************************************
        !          5978:  *                                                                     *
        !          5979:  *             Routines to handle XPath contexts                       *
        !          5980:  *                                                                     *
        !          5981:  ************************************************************************/
        !          5982: 
        !          5983: /**
        !          5984:  * xmlXPathNewContext:
        !          5985:  * @doc:  the XML document
        !          5986:  *
        !          5987:  * Create a new xmlXPathContext
        !          5988:  *
        !          5989:  * Returns the xmlXPathContext just allocated. The caller will need to free it.
        !          5990:  */
        !          5991: xmlXPathContextPtr
        !          5992: xmlXPathNewContext(xmlDocPtr doc) {
        !          5993:     xmlXPathContextPtr ret;
        !          5994: 
        !          5995:     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
        !          5996:     if (ret == NULL) {
        !          5997:         xmlXPathErrMemory(NULL, "creating context\n");
        !          5998:        return(NULL);
        !          5999:     }
        !          6000:     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
        !          6001:     ret->doc = doc;
        !          6002:     ret->node = NULL;
        !          6003: 
        !          6004:     ret->varHash = NULL;
        !          6005: 
        !          6006:     ret->nb_types = 0;
        !          6007:     ret->max_types = 0;
        !          6008:     ret->types = NULL;
        !          6009: 
        !          6010:     ret->funcHash = xmlHashCreate(0);
        !          6011: 
        !          6012:     ret->nb_axis = 0;
        !          6013:     ret->max_axis = 0;
        !          6014:     ret->axis = NULL;
        !          6015: 
        !          6016:     ret->nsHash = NULL;
        !          6017:     ret->user = NULL;
        !          6018: 
        !          6019:     ret->contextSize = -1;
        !          6020:     ret->proximityPosition = -1;
        !          6021: 
        !          6022: #ifdef XP_DEFAULT_CACHE_ON
        !          6023:     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
        !          6024:        xmlXPathFreeContext(ret);
        !          6025:        return(NULL);
        !          6026:     }
        !          6027: #endif
        !          6028: 
        !          6029:     xmlXPathRegisterAllFunctions(ret);
        !          6030: 
        !          6031:     return(ret);
        !          6032: }
        !          6033: 
        !          6034: /**
        !          6035:  * xmlXPathFreeContext:
        !          6036:  * @ctxt:  the context to free
        !          6037:  *
        !          6038:  * Free up an xmlXPathContext
        !          6039:  */
        !          6040: void
        !          6041: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
        !          6042:     if (ctxt == NULL) return;
        !          6043: 
        !          6044:     if (ctxt->cache != NULL)
        !          6045:        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
        !          6046:     xmlXPathRegisteredNsCleanup(ctxt);
        !          6047:     xmlXPathRegisteredFuncsCleanup(ctxt);
        !          6048:     xmlXPathRegisteredVariablesCleanup(ctxt);
        !          6049:     xmlResetError(&ctxt->lastError);
        !          6050:     xmlFree(ctxt);
        !          6051: }
        !          6052: 
        !          6053: /************************************************************************
        !          6054:  *                                                                     *
        !          6055:  *             Routines to handle XPath parser contexts                *
        !          6056:  *                                                                     *
        !          6057:  ************************************************************************/
        !          6058: 
        !          6059: #define CHECK_CTXT(ctxt)                                               \
        !          6060:     if (ctxt == NULL) {                                                \
        !          6061:        __xmlRaiseError(NULL, NULL, NULL,                               \
        !          6062:                NULL, NULL, XML_FROM_XPATH,                             \
        !          6063:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
        !          6064:                __FILE__, __LINE__,                                     \
        !          6065:                NULL, NULL, NULL, 0, 0,                                 \
        !          6066:                "NULL context pointer\n");                              \
        !          6067:        return(NULL);                                                   \
        !          6068:     }                                                                  \
        !          6069: 
        !          6070: #define CHECK_CTXT_NEG(ctxt)                                           \
        !          6071:     if (ctxt == NULL) {                                                \
        !          6072:        __xmlRaiseError(NULL, NULL, NULL,                               \
        !          6073:                NULL, NULL, XML_FROM_XPATH,                             \
        !          6074:                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
        !          6075:                __FILE__, __LINE__,                                     \
        !          6076:                NULL, NULL, NULL, 0, 0,                                 \
        !          6077:                "NULL context pointer\n");                              \
        !          6078:        return(-1);                                                     \
        !          6079:     }                                                                  \
        !          6080: 
        !          6081: 
        !          6082: #define CHECK_CONTEXT(ctxt)                                            \
        !          6083:     if ((ctxt == NULL) || (ctxt->doc == NULL) ||                       \
        !          6084:         (ctxt->doc->children == NULL)) {                               \
        !          6085:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
        !          6086:        return(NULL);                                                   \
        !          6087:     }
        !          6088: 
        !          6089: 
        !          6090: /**
        !          6091:  * xmlXPathNewParserContext:
        !          6092:  * @str:  the XPath expression
        !          6093:  * @ctxt:  the XPath context
        !          6094:  *
        !          6095:  * Create a new xmlXPathParserContext
        !          6096:  *
        !          6097:  * Returns the xmlXPathParserContext just allocated.
        !          6098:  */
        !          6099: xmlXPathParserContextPtr
        !          6100: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
        !          6101:     xmlXPathParserContextPtr ret;
        !          6102: 
        !          6103:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
        !          6104:     if (ret == NULL) {
        !          6105:         xmlXPathErrMemory(ctxt, "creating parser context\n");
        !          6106:        return(NULL);
        !          6107:     }
        !          6108:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
        !          6109:     ret->cur = ret->base = str;
        !          6110:     ret->context = ctxt;
        !          6111: 
        !          6112:     ret->comp = xmlXPathNewCompExpr();
        !          6113:     if (ret->comp == NULL) {
        !          6114:        xmlFree(ret->valueTab);
        !          6115:        xmlFree(ret);
        !          6116:        return(NULL);
        !          6117:     }
        !          6118:     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
        !          6119:         ret->comp->dict = ctxt->dict;
        !          6120:        xmlDictReference(ret->comp->dict);
        !          6121:     }
        !          6122: 
        !          6123:     return(ret);
        !          6124: }
        !          6125: 
        !          6126: /**
        !          6127:  * xmlXPathCompParserContext:
        !          6128:  * @comp:  the XPath compiled expression
        !          6129:  * @ctxt:  the XPath context
        !          6130:  *
        !          6131:  * Create a new xmlXPathParserContext when processing a compiled expression
        !          6132:  *
        !          6133:  * Returns the xmlXPathParserContext just allocated.
        !          6134:  */
        !          6135: static xmlXPathParserContextPtr
        !          6136: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
        !          6137:     xmlXPathParserContextPtr ret;
        !          6138: 
        !          6139:     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
        !          6140:     if (ret == NULL) {
        !          6141:         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
        !          6142:        return(NULL);
        !          6143:     }
        !          6144:     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
        !          6145: 
        !          6146:     /* Allocate the value stack */
        !          6147:     ret->valueTab = (xmlXPathObjectPtr *)
        !          6148:                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
        !          6149:     if (ret->valueTab == NULL) {
        !          6150:        xmlFree(ret);
        !          6151:        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
        !          6152:        return(NULL);
        !          6153:     }
        !          6154:     ret->valueNr = 0;
        !          6155:     ret->valueMax = 10;
        !          6156:     ret->value = NULL;
        !          6157: 
        !          6158:     ret->context = ctxt;
        !          6159:     ret->comp = comp;
        !          6160: 
        !          6161:     return(ret);
        !          6162: }
        !          6163: 
        !          6164: /**
        !          6165:  * xmlXPathFreeParserContext:
        !          6166:  * @ctxt:  the context to free
        !          6167:  *
        !          6168:  * Free up an xmlXPathParserContext
        !          6169:  */
        !          6170: void
        !          6171: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
        !          6172:     if (ctxt->valueTab != NULL) {
        !          6173:         xmlFree(ctxt->valueTab);
        !          6174:     }
        !          6175:     if (ctxt->comp != NULL) {
        !          6176: #ifdef XPATH_STREAMING
        !          6177:        if (ctxt->comp->stream != NULL) {
        !          6178:            xmlFreePatternList(ctxt->comp->stream);
        !          6179:            ctxt->comp->stream = NULL;
        !          6180:        }
        !          6181: #endif
        !          6182:        xmlXPathFreeCompExpr(ctxt->comp);
        !          6183:     }
        !          6184:     xmlFree(ctxt);
        !          6185: }
        !          6186: 
        !          6187: /************************************************************************
        !          6188:  *                                                                     *
        !          6189:  *             The implicit core function library                      *
        !          6190:  *                                                                     *
        !          6191:  ************************************************************************/
        !          6192: 
        !          6193: /**
        !          6194:  * xmlXPathNodeValHash:
        !          6195:  * @node:  a node pointer
        !          6196:  *
        !          6197:  * Function computing the beginning of the string value of the node,
        !          6198:  * used to speed up comparisons
        !          6199:  *
        !          6200:  * Returns an int usable as a hash
        !          6201:  */
        !          6202: static unsigned int
        !          6203: xmlXPathNodeValHash(xmlNodePtr node) {
        !          6204:     int len = 2;
        !          6205:     const xmlChar * string = NULL;
        !          6206:     xmlNodePtr tmp = NULL;
        !          6207:     unsigned int ret = 0;
        !          6208: 
        !          6209:     if (node == NULL)
        !          6210:        return(0);
        !          6211: 
        !          6212:     if (node->type == XML_DOCUMENT_NODE) {
        !          6213:        tmp = xmlDocGetRootElement((xmlDocPtr) node);
        !          6214:        if (tmp == NULL)
        !          6215:            node = node->children;
        !          6216:        else
        !          6217:            node = tmp;
        !          6218: 
        !          6219:        if (node == NULL)
        !          6220:            return(0);
        !          6221:     }
        !          6222: 
        !          6223:     switch (node->type) {
        !          6224:        case XML_COMMENT_NODE:
        !          6225:        case XML_PI_NODE:
        !          6226:        case XML_CDATA_SECTION_NODE:
        !          6227:        case XML_TEXT_NODE:
        !          6228:            string = node->content;
        !          6229:            if (string == NULL)
        !          6230:                return(0);
        !          6231:            if (string[0] == 0)
        !          6232:                return(0);
        !          6233:            return(((unsigned int) string[0]) +
        !          6234:                   (((unsigned int) string[1]) << 8));
        !          6235:        case XML_NAMESPACE_DECL:
        !          6236:            string = ((xmlNsPtr)node)->href;
        !          6237:            if (string == NULL)
        !          6238:                return(0);
        !          6239:            if (string[0] == 0)
        !          6240:                return(0);
        !          6241:            return(((unsigned int) string[0]) +
        !          6242:                   (((unsigned int) string[1]) << 8));
        !          6243:        case XML_ATTRIBUTE_NODE:
        !          6244:            tmp = ((xmlAttrPtr) node)->children;
        !          6245:            break;
        !          6246:        case XML_ELEMENT_NODE:
        !          6247:            tmp = node->children;
        !          6248:            break;
        !          6249:        default:
        !          6250:            return(0);
        !          6251:     }
        !          6252:     while (tmp != NULL) {
        !          6253:        switch (tmp->type) {
        !          6254:            case XML_COMMENT_NODE:
        !          6255:            case XML_PI_NODE:
        !          6256:            case XML_CDATA_SECTION_NODE:
        !          6257:            case XML_TEXT_NODE:
        !          6258:                string = tmp->content;
        !          6259:                break;
        !          6260:            case XML_NAMESPACE_DECL:
        !          6261:                string = ((xmlNsPtr)tmp)->href;
        !          6262:                break;
        !          6263:            default:
        !          6264:                break;
        !          6265:        }
        !          6266:        if ((string != NULL) && (string[0] != 0)) {
        !          6267:            if (len == 1) {
        !          6268:                return(ret + (((unsigned int) string[0]) << 8));
        !          6269:            }
        !          6270:            if (string[1] == 0) {
        !          6271:                len = 1;
        !          6272:                ret = (unsigned int) string[0];
        !          6273:            } else {
        !          6274:                return(((unsigned int) string[0]) +
        !          6275:                       (((unsigned int) string[1]) << 8));
        !          6276:            }
        !          6277:        }
        !          6278:        /*
        !          6279:         * Skip to next node
        !          6280:         */
        !          6281:        if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
        !          6282:            if (tmp->children->type != XML_ENTITY_DECL) {
        !          6283:                tmp = tmp->children;
        !          6284:                continue;
        !          6285:            }
        !          6286:        }
        !          6287:        if (tmp == node)
        !          6288:            break;
        !          6289: 
        !          6290:        if (tmp->next != NULL) {
        !          6291:            tmp = tmp->next;
        !          6292:            continue;
        !          6293:        }
        !          6294: 
        !          6295:        do {
        !          6296:            tmp = tmp->parent;
        !          6297:            if (tmp == NULL)
        !          6298:                break;
        !          6299:            if (tmp == node) {
        !          6300:                tmp = NULL;
        !          6301:                break;
        !          6302:            }
        !          6303:            if (tmp->next != NULL) {
        !          6304:                tmp = tmp->next;
        !          6305:                break;
        !          6306:            }
        !          6307:        } while (tmp != NULL);
        !          6308:     }
        !          6309:     return(ret);
        !          6310: }
        !          6311: 
        !          6312: /**
        !          6313:  * xmlXPathStringHash:
        !          6314:  * @string:  a string
        !          6315:  *
        !          6316:  * Function computing the beginning of the string value of the node,
        !          6317:  * used to speed up comparisons
        !          6318:  *
        !          6319:  * Returns an int usable as a hash
        !          6320:  */
        !          6321: static unsigned int
        !          6322: xmlXPathStringHash(const xmlChar * string) {
        !          6323:     if (string == NULL)
        !          6324:        return((unsigned int) 0);
        !          6325:     if (string[0] == 0)
        !          6326:        return(0);
        !          6327:     return(((unsigned int) string[0]) +
        !          6328:           (((unsigned int) string[1]) << 8));
        !          6329: }
        !          6330: 
        !          6331: /**
        !          6332:  * xmlXPathCompareNodeSetFloat:
        !          6333:  * @ctxt:  the XPath Parser context
        !          6334:  * @inf:  less than (1) or greater than (0)
        !          6335:  * @strict:  is the comparison strict
        !          6336:  * @arg:  the node set
        !          6337:  * @f:  the value
        !          6338:  *
        !          6339:  * Implement the compare operation between a nodeset and a number
        !          6340:  *     @ns < @val    (1, 1, ...
        !          6341:  *     @ns <= @val   (1, 0, ...
        !          6342:  *     @ns > @val    (0, 1, ...
        !          6343:  *     @ns >= @val   (0, 0, ...
        !          6344:  *
        !          6345:  * If one object to be compared is a node-set and the other is a number,
        !          6346:  * then the comparison will be true if and only if there is a node in the
        !          6347:  * node-set such that the result of performing the comparison on the number
        !          6348:  * to be compared and on the result of converting the string-value of that
        !          6349:  * node to a number using the number function is true.
        !          6350:  *
        !          6351:  * Returns 0 or 1 depending on the results of the test.
        !          6352:  */
        !          6353: static int
        !          6354: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
        !          6355:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
        !          6356:     int i, ret = 0;
        !          6357:     xmlNodeSetPtr ns;
        !          6358:     xmlChar *str2;
        !          6359: 
        !          6360:     if ((f == NULL) || (arg == NULL) ||
        !          6361:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
        !          6362:        xmlXPathReleaseObject(ctxt->context, arg);
        !          6363:        xmlXPathReleaseObject(ctxt->context, f);
        !          6364:         return(0);
        !          6365:     }
        !          6366:     ns = arg->nodesetval;
        !          6367:     if (ns != NULL) {
        !          6368:        for (i = 0;i < ns->nodeNr;i++) {
        !          6369:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
        !          6370:             if (str2 != NULL) {
        !          6371:                 valuePush(ctxt,
        !          6372:                           xmlXPathCacheNewString(ctxt->context, str2));
        !          6373:                 xmlFree(str2);
        !          6374:                 xmlXPathNumberFunction(ctxt, 1);
        !          6375:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
        !          6376:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
        !          6377:                 if (ret)
        !          6378:                     break;
        !          6379:             }
        !          6380:        }
        !          6381:     }
        !          6382:     xmlXPathReleaseObject(ctxt->context, arg);
        !          6383:     xmlXPathReleaseObject(ctxt->context, f);
        !          6384:     return(ret);
        !          6385: }
        !          6386: 
        !          6387: /**
        !          6388:  * xmlXPathCompareNodeSetString:
        !          6389:  * @ctxt:  the XPath Parser context
        !          6390:  * @inf:  less than (1) or greater than (0)
        !          6391:  * @strict:  is the comparison strict
        !          6392:  * @arg:  the node set
        !          6393:  * @s:  the value
        !          6394:  *
        !          6395:  * Implement the compare operation between a nodeset and a string
        !          6396:  *     @ns < @val    (1, 1, ...
        !          6397:  *     @ns <= @val   (1, 0, ...
        !          6398:  *     @ns > @val    (0, 1, ...
        !          6399:  *     @ns >= @val   (0, 0, ...
        !          6400:  *
        !          6401:  * If one object to be compared is a node-set and the other is a string,
        !          6402:  * then the comparison will be true if and only if there is a node in
        !          6403:  * the node-set such that the result of performing the comparison on the
        !          6404:  * string-value of the node and the other string is true.
        !          6405:  *
        !          6406:  * Returns 0 or 1 depending on the results of the test.
        !          6407:  */
        !          6408: static int
        !          6409: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
        !          6410:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
        !          6411:     int i, ret = 0;
        !          6412:     xmlNodeSetPtr ns;
        !          6413:     xmlChar *str2;
        !          6414: 
        !          6415:     if ((s == NULL) || (arg == NULL) ||
        !          6416:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
        !          6417:        xmlXPathReleaseObject(ctxt->context, arg);
        !          6418:        xmlXPathReleaseObject(ctxt->context, s);
        !          6419:         return(0);
        !          6420:     }
        !          6421:     ns = arg->nodesetval;
        !          6422:     if (ns != NULL) {
        !          6423:        for (i = 0;i < ns->nodeNr;i++) {
        !          6424:             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
        !          6425:             if (str2 != NULL) {
        !          6426:                 valuePush(ctxt,
        !          6427:                           xmlXPathCacheNewString(ctxt->context, str2));
        !          6428:                 xmlFree(str2);
        !          6429:                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
        !          6430:                 ret = xmlXPathCompareValues(ctxt, inf, strict);
        !          6431:                 if (ret)
        !          6432:                     break;
        !          6433:             }
        !          6434:        }
        !          6435:     }
        !          6436:     xmlXPathReleaseObject(ctxt->context, arg);
        !          6437:     xmlXPathReleaseObject(ctxt->context, s);
        !          6438:     return(ret);
        !          6439: }
        !          6440: 
        !          6441: /**
        !          6442:  * xmlXPathCompareNodeSets:
        !          6443:  * @inf:  less than (1) or greater than (0)
        !          6444:  * @strict:  is the comparison strict
        !          6445:  * @arg1:  the first node set object
        !          6446:  * @arg2:  the second node set object
        !          6447:  *
        !          6448:  * Implement the compare operation on nodesets:
        !          6449:  *
        !          6450:  * If both objects to be compared are node-sets, then the comparison
        !          6451:  * will be true if and only if there is a node in the first node-set
        !          6452:  * and a node in the second node-set such that the result of performing
        !          6453:  * the comparison on the string-values of the two nodes is true.
        !          6454:  * ....
        !          6455:  * When neither object to be compared is a node-set and the operator
        !          6456:  * is <=, <, >= or >, then the objects are compared by converting both
        !          6457:  * objects to numbers and comparing the numbers according to IEEE 754.
        !          6458:  * ....
        !          6459:  * The number function converts its argument to a number as follows:
        !          6460:  *  - a string that consists of optional whitespace followed by an
        !          6461:  *    optional minus sign followed by a Number followed by whitespace
        !          6462:  *    is converted to the IEEE 754 number that is nearest (according
        !          6463:  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
        !          6464:  *    represented by the string; any other string is converted to NaN
        !          6465:  *
        !          6466:  * Conclusion all nodes need to be converted first to their string value
        !          6467:  * and then the comparison must be done when possible
        !          6468:  */
        !          6469: static int
        !          6470: xmlXPathCompareNodeSets(int inf, int strict,
        !          6471:                        xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
        !          6472:     int i, j, init = 0;
        !          6473:     double val1;
        !          6474:     double *values2;
        !          6475:     int ret = 0;
        !          6476:     xmlNodeSetPtr ns1;
        !          6477:     xmlNodeSetPtr ns2;
        !          6478: 
        !          6479:     if ((arg1 == NULL) ||
        !          6480:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
        !          6481:        xmlXPathFreeObject(arg2);
        !          6482:         return(0);
        !          6483:     }
        !          6484:     if ((arg2 == NULL) ||
        !          6485:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
        !          6486:        xmlXPathFreeObject(arg1);
        !          6487:        xmlXPathFreeObject(arg2);
        !          6488:         return(0);
        !          6489:     }
        !          6490: 
        !          6491:     ns1 = arg1->nodesetval;
        !          6492:     ns2 = arg2->nodesetval;
        !          6493: 
        !          6494:     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
        !          6495:        xmlXPathFreeObject(arg1);
        !          6496:        xmlXPathFreeObject(arg2);
        !          6497:        return(0);
        !          6498:     }
        !          6499:     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
        !          6500:        xmlXPathFreeObject(arg1);
        !          6501:        xmlXPathFreeObject(arg2);
        !          6502:        return(0);
        !          6503:     }
        !          6504: 
        !          6505:     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
        !          6506:     if (values2 == NULL) {
        !          6507:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
        !          6508:        xmlXPathFreeObject(arg1);
        !          6509:        xmlXPathFreeObject(arg2);
        !          6510:        return(0);
        !          6511:     }
        !          6512:     for (i = 0;i < ns1->nodeNr;i++) {
        !          6513:        val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
        !          6514:        if (xmlXPathIsNaN(val1))
        !          6515:            continue;
        !          6516:        for (j = 0;j < ns2->nodeNr;j++) {
        !          6517:            if (init == 0) {
        !          6518:                values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
        !          6519:            }
        !          6520:            if (xmlXPathIsNaN(values2[j]))
        !          6521:                continue;
        !          6522:            if (inf && strict)
        !          6523:                ret = (val1 < values2[j]);
        !          6524:            else if (inf && !strict)
        !          6525:                ret = (val1 <= values2[j]);
        !          6526:            else if (!inf && strict)
        !          6527:                ret = (val1 > values2[j]);
        !          6528:            else if (!inf && !strict)
        !          6529:                ret = (val1 >= values2[j]);
        !          6530:            if (ret)
        !          6531:                break;
        !          6532:        }
        !          6533:        if (ret)
        !          6534:            break;
        !          6535:        init = 1;
        !          6536:     }
        !          6537:     xmlFree(values2);
        !          6538:     xmlXPathFreeObject(arg1);
        !          6539:     xmlXPathFreeObject(arg2);
        !          6540:     return(ret);
        !          6541: }
        !          6542: 
        !          6543: /**
        !          6544:  * xmlXPathCompareNodeSetValue:
        !          6545:  * @ctxt:  the XPath Parser context
        !          6546:  * @inf:  less than (1) or greater than (0)
        !          6547:  * @strict:  is the comparison strict
        !          6548:  * @arg:  the node set
        !          6549:  * @val:  the value
        !          6550:  *
        !          6551:  * Implement the compare operation between a nodeset and a value
        !          6552:  *     @ns < @val    (1, 1, ...
        !          6553:  *     @ns <= @val   (1, 0, ...
        !          6554:  *     @ns > @val    (0, 1, ...
        !          6555:  *     @ns >= @val   (0, 0, ...
        !          6556:  *
        !          6557:  * If one object to be compared is a node-set and the other is a boolean,
        !          6558:  * then the comparison will be true if and only if the result of performing
        !          6559:  * the comparison on the boolean and on the result of converting
        !          6560:  * the node-set to a boolean using the boolean function is true.
        !          6561:  *
        !          6562:  * Returns 0 or 1 depending on the results of the test.
        !          6563:  */
        !          6564: static int
        !          6565: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
        !          6566:                            xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
        !          6567:     if ((val == NULL) || (arg == NULL) ||
        !          6568:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
        !          6569:         return(0);
        !          6570: 
        !          6571:     switch(val->type) {
        !          6572:         case XPATH_NUMBER:
        !          6573:            return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
        !          6574:         case XPATH_NODESET:
        !          6575:         case XPATH_XSLT_TREE:
        !          6576:            return(xmlXPathCompareNodeSets(inf, strict, arg, val));
        !          6577:         case XPATH_STRING:
        !          6578:            return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
        !          6579:         case XPATH_BOOLEAN:
        !          6580:            valuePush(ctxt, arg);
        !          6581:            xmlXPathBooleanFunction(ctxt, 1);
        !          6582:            valuePush(ctxt, val);
        !          6583:            return(xmlXPathCompareValues(ctxt, inf, strict));
        !          6584:        default:
        !          6585:            TODO
        !          6586:     }
        !          6587:     return(0);
        !          6588: }
        !          6589: 
        !          6590: /**
        !          6591:  * xmlXPathEqualNodeSetString:
        !          6592:  * @arg:  the nodeset object argument
        !          6593:  * @str:  the string to compare to.
        !          6594:  * @neq:  flag to show whether for '=' (0) or '!=' (1)
        !          6595:  *
        !          6596:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
        !          6597:  * If one object to be compared is a node-set and the other is a string,
        !          6598:  * then the comparison will be true if and only if there is a node in
        !          6599:  * the node-set such that the result of performing the comparison on the
        !          6600:  * string-value of the node and the other string is true.
        !          6601:  *
        !          6602:  * Returns 0 or 1 depending on the results of the test.
        !          6603:  */
        !          6604: static int
        !          6605: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
        !          6606: {
        !          6607:     int i;
        !          6608:     xmlNodeSetPtr ns;
        !          6609:     xmlChar *str2;
        !          6610:     unsigned int hash;
        !          6611: 
        !          6612:     if ((str == NULL) || (arg == NULL) ||
        !          6613:         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
        !          6614:         return (0);
        !          6615:     ns = arg->nodesetval;
        !          6616:     /*
        !          6617:      * A NULL nodeset compared with a string is always false
        !          6618:      * (since there is no node equal, and no node not equal)
        !          6619:      */
        !          6620:     if ((ns == NULL) || (ns->nodeNr <= 0) )
        !          6621:         return (0);
        !          6622:     hash = xmlXPathStringHash(str);
        !          6623:     for (i = 0; i < ns->nodeNr; i++) {
        !          6624:         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
        !          6625:             str2 = xmlNodeGetContent(ns->nodeTab[i]);
        !          6626:             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
        !          6627:                 xmlFree(str2);
        !          6628:                if (neq)
        !          6629:                    continue;
        !          6630:                 return (1);
        !          6631:            } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
        !          6632:                if (neq)
        !          6633:                    continue;
        !          6634:                 return (1);
        !          6635:             } else if (neq) {
        !          6636:                if (str2 != NULL)
        !          6637:                    xmlFree(str2);
        !          6638:                return (1);
        !          6639:            }
        !          6640:             if (str2 != NULL)
        !          6641:                 xmlFree(str2);
        !          6642:         } else if (neq)
        !          6643:            return (1);
        !          6644:     }
        !          6645:     return (0);
        !          6646: }
        !          6647: 
        !          6648: /**
        !          6649:  * xmlXPathEqualNodeSetFloat:
        !          6650:  * @arg:  the nodeset object argument
        !          6651:  * @f:  the float to compare to
        !          6652:  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
        !          6653:  *
        !          6654:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
        !          6655:  * If one object to be compared is a node-set and the other is a number,
        !          6656:  * then the comparison will be true if and only if there is a node in
        !          6657:  * the node-set such that the result of performing the comparison on the
        !          6658:  * number to be compared and on the result of converting the string-value
        !          6659:  * of that node to a number using the number function is true.
        !          6660:  *
        !          6661:  * Returns 0 or 1 depending on the results of the test.
        !          6662:  */
        !          6663: static int
        !          6664: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
        !          6665:     xmlXPathObjectPtr arg, double f, int neq) {
        !          6666:   int i, ret=0;
        !          6667:   xmlNodeSetPtr ns;
        !          6668:   xmlChar *str2;
        !          6669:   xmlXPathObjectPtr val;
        !          6670:   double v;
        !          6671: 
        !          6672:     if ((arg == NULL) ||
        !          6673:        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
        !          6674:         return(0);
        !          6675: 
        !          6676:     ns = arg->nodesetval;
        !          6677:     if (ns != NULL) {
        !          6678:        for (i=0;i<ns->nodeNr;i++) {
        !          6679:            str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
        !          6680:            if (str2 != NULL) {
        !          6681:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
        !          6682:                xmlFree(str2);
        !          6683:                xmlXPathNumberFunction(ctxt, 1);
        !          6684:                val = valuePop(ctxt);
        !          6685:                v = val->floatval;
        !          6686:                xmlXPathReleaseObject(ctxt->context, val);
        !          6687:                if (!xmlXPathIsNaN(v)) {
        !          6688:                    if ((!neq) && (v==f)) {
        !          6689:                        ret = 1;
        !          6690:                        break;
        !          6691:                    } else if ((neq) && (v!=f)) {
        !          6692:                        ret = 1;
        !          6693:                        break;
        !          6694:                    }
        !          6695:                } else {        /* NaN is unequal to any value */
        !          6696:                    if (neq)
        !          6697:                        ret = 1;
        !          6698:                }
        !          6699:            }
        !          6700:        }
        !          6701:     }
        !          6702: 
        !          6703:     return(ret);
        !          6704: }
        !          6705: 
        !          6706: 
        !          6707: /**
        !          6708:  * xmlXPathEqualNodeSets:
        !          6709:  * @arg1:  first nodeset object argument
        !          6710:  * @arg2:  second nodeset object argument
        !          6711:  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
        !          6712:  *
        !          6713:  * Implement the equal / not equal operation on XPath nodesets:
        !          6714:  * @arg1 == @arg2  or  @arg1 != @arg2
        !          6715:  * If both objects to be compared are node-sets, then the comparison
        !          6716:  * will be true if and only if there is a node in the first node-set and
        !          6717:  * a node in the second node-set such that the result of performing the
        !          6718:  * comparison on the string-values of the two nodes is true.
        !          6719:  *
        !          6720:  * (needless to say, this is a costly operation)
        !          6721:  *
        !          6722:  * Returns 0 or 1 depending on the results of the test.
        !          6723:  */
        !          6724: static int
        !          6725: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
        !          6726:     int i, j;
        !          6727:     unsigned int *hashs1;
        !          6728:     unsigned int *hashs2;
        !          6729:     xmlChar **values1;
        !          6730:     xmlChar **values2;
        !          6731:     int ret = 0;
        !          6732:     xmlNodeSetPtr ns1;
        !          6733:     xmlNodeSetPtr ns2;
        !          6734: 
        !          6735:     if ((arg1 == NULL) ||
        !          6736:        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
        !          6737:         return(0);
        !          6738:     if ((arg2 == NULL) ||
        !          6739:        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
        !          6740:         return(0);
        !          6741: 
        !          6742:     ns1 = arg1->nodesetval;
        !          6743:     ns2 = arg2->nodesetval;
        !          6744: 
        !          6745:     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
        !          6746:        return(0);
        !          6747:     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
        !          6748:        return(0);
        !          6749: 
        !          6750:     /*
        !          6751:      * for equal, check if there is a node pertaining to both sets
        !          6752:      */
        !          6753:     if (neq == 0)
        !          6754:        for (i = 0;i < ns1->nodeNr;i++)
        !          6755:            for (j = 0;j < ns2->nodeNr;j++)
        !          6756:                if (ns1->nodeTab[i] == ns2->nodeTab[j])
        !          6757:                    return(1);
        !          6758: 
        !          6759:     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
        !          6760:     if (values1 == NULL) {
        !          6761:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
        !          6762:        return(0);
        !          6763:     }
        !          6764:     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
        !          6765:     if (hashs1 == NULL) {
        !          6766:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
        !          6767:        xmlFree(values1);
        !          6768:        return(0);
        !          6769:     }
        !          6770:     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
        !          6771:     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
        !          6772:     if (values2 == NULL) {
        !          6773:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
        !          6774:        xmlFree(hashs1);
        !          6775:        xmlFree(values1);
        !          6776:        return(0);
        !          6777:     }
        !          6778:     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
        !          6779:     if (hashs2 == NULL) {
        !          6780:         xmlXPathErrMemory(NULL, "comparing nodesets\n");
        !          6781:        xmlFree(hashs1);
        !          6782:        xmlFree(values1);
        !          6783:        xmlFree(values2);
        !          6784:        return(0);
        !          6785:     }
        !          6786:     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
        !          6787:     for (i = 0;i < ns1->nodeNr;i++) {
        !          6788:        hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
        !          6789:        for (j = 0;j < ns2->nodeNr;j++) {
        !          6790:            if (i == 0)
        !          6791:                hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
        !          6792:            if (hashs1[i] != hashs2[j]) {
        !          6793:                if (neq) {
        !          6794:                    ret = 1;
        !          6795:                    break;
        !          6796:                }
        !          6797:            }
        !          6798:            else {
        !          6799:                if (values1[i] == NULL)
        !          6800:                    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
        !          6801:                if (values2[j] == NULL)
        !          6802:                    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
        !          6803:                ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
        !          6804:                if (ret)
        !          6805:                    break;
        !          6806:            }
        !          6807:        }
        !          6808:        if (ret)
        !          6809:            break;
        !          6810:     }
        !          6811:     for (i = 0;i < ns1->nodeNr;i++)
        !          6812:        if (values1[i] != NULL)
        !          6813:            xmlFree(values1[i]);
        !          6814:     for (j = 0;j < ns2->nodeNr;j++)
        !          6815:        if (values2[j] != NULL)
        !          6816:            xmlFree(values2[j]);
        !          6817:     xmlFree(values1);
        !          6818:     xmlFree(values2);
        !          6819:     xmlFree(hashs1);
        !          6820:     xmlFree(hashs2);
        !          6821:     return(ret);
        !          6822: }
        !          6823: 
        !          6824: static int
        !          6825: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
        !          6826:   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
        !          6827:     int ret = 0;
        !          6828:     /*
        !          6829:      *At this point we are assured neither arg1 nor arg2
        !          6830:      *is a nodeset, so we can just pick the appropriate routine.
        !          6831:      */
        !          6832:     switch (arg1->type) {
        !          6833:         case XPATH_UNDEFINED:
        !          6834: #ifdef DEBUG_EXPR
        !          6835:            xmlGenericError(xmlGenericErrorContext,
        !          6836:                    "Equal: undefined\n");
        !          6837: #endif
        !          6838:            break;
        !          6839:         case XPATH_BOOLEAN:
        !          6840:            switch (arg2->type) {
        !          6841:                case XPATH_UNDEFINED:
        !          6842: #ifdef DEBUG_EXPR
        !          6843:                    xmlGenericError(xmlGenericErrorContext,
        !          6844:                            "Equal: undefined\n");
        !          6845: #endif
        !          6846:                    break;
        !          6847:                case XPATH_BOOLEAN:
        !          6848: #ifdef DEBUG_EXPR
        !          6849:                    xmlGenericError(xmlGenericErrorContext,
        !          6850:                            "Equal: %d boolean %d \n",
        !          6851:                            arg1->boolval, arg2->boolval);
        !          6852: #endif
        !          6853:                    ret = (arg1->boolval == arg2->boolval);
        !          6854:                    break;
        !          6855:                case XPATH_NUMBER:
        !          6856:                    ret = (arg1->boolval ==
        !          6857:                           xmlXPathCastNumberToBoolean(arg2->floatval));
        !          6858:                    break;
        !          6859:                case XPATH_STRING:
        !          6860:                    if ((arg2->stringval == NULL) ||
        !          6861:                        (arg2->stringval[0] == 0)) ret = 0;
        !          6862:                    else
        !          6863:                        ret = 1;
        !          6864:                    ret = (arg1->boolval == ret);
        !          6865:                    break;
        !          6866:                case XPATH_USERS:
        !          6867:                case XPATH_POINT:
        !          6868:                case XPATH_RANGE:
        !          6869:                case XPATH_LOCATIONSET:
        !          6870:                    TODO
        !          6871:                    break;
        !          6872:                case XPATH_NODESET:
        !          6873:                case XPATH_XSLT_TREE:
        !          6874:                    break;
        !          6875:            }
        !          6876:            break;
        !          6877:         case XPATH_NUMBER:
        !          6878:            switch (arg2->type) {
        !          6879:                case XPATH_UNDEFINED:
        !          6880: #ifdef DEBUG_EXPR
        !          6881:                    xmlGenericError(xmlGenericErrorContext,
        !          6882:                            "Equal: undefined\n");
        !          6883: #endif
        !          6884:                    break;
        !          6885:                case XPATH_BOOLEAN:
        !          6886:                    ret = (arg2->boolval==
        !          6887:                           xmlXPathCastNumberToBoolean(arg1->floatval));
        !          6888:                    break;
        !          6889:                case XPATH_STRING:
        !          6890:                    valuePush(ctxt, arg2);
        !          6891:                    xmlXPathNumberFunction(ctxt, 1);
        !          6892:                    arg2 = valuePop(ctxt);
        !          6893:                    /* no break on purpose */
        !          6894:                case XPATH_NUMBER:
        !          6895:                    /* Hand check NaN and Infinity equalities */
        !          6896:                    if (xmlXPathIsNaN(arg1->floatval) ||
        !          6897:                            xmlXPathIsNaN(arg2->floatval)) {
        !          6898:                        ret = 0;
        !          6899:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
        !          6900:                        if (xmlXPathIsInf(arg2->floatval) == 1)
        !          6901:                            ret = 1;
        !          6902:                        else
        !          6903:                            ret = 0;
        !          6904:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
        !          6905:                        if (xmlXPathIsInf(arg2->floatval) == -1)
        !          6906:                            ret = 1;
        !          6907:                        else
        !          6908:                            ret = 0;
        !          6909:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
        !          6910:                        if (xmlXPathIsInf(arg1->floatval) == 1)
        !          6911:                            ret = 1;
        !          6912:                        else
        !          6913:                            ret = 0;
        !          6914:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
        !          6915:                        if (xmlXPathIsInf(arg1->floatval) == -1)
        !          6916:                            ret = 1;
        !          6917:                        else
        !          6918:                            ret = 0;
        !          6919:                    } else {
        !          6920:                        ret = (arg1->floatval == arg2->floatval);
        !          6921:                    }
        !          6922:                    break;
        !          6923:                case XPATH_USERS:
        !          6924:                case XPATH_POINT:
        !          6925:                case XPATH_RANGE:
        !          6926:                case XPATH_LOCATIONSET:
        !          6927:                    TODO
        !          6928:                    break;
        !          6929:                case XPATH_NODESET:
        !          6930:                case XPATH_XSLT_TREE:
        !          6931:                    break;
        !          6932:            }
        !          6933:            break;
        !          6934:         case XPATH_STRING:
        !          6935:            switch (arg2->type) {
        !          6936:                case XPATH_UNDEFINED:
        !          6937: #ifdef DEBUG_EXPR
        !          6938:                    xmlGenericError(xmlGenericErrorContext,
        !          6939:                            "Equal: undefined\n");
        !          6940: #endif
        !          6941:                    break;
        !          6942:                case XPATH_BOOLEAN:
        !          6943:                    if ((arg1->stringval == NULL) ||
        !          6944:                        (arg1->stringval[0] == 0)) ret = 0;
        !          6945:                    else
        !          6946:                        ret = 1;
        !          6947:                    ret = (arg2->boolval == ret);
        !          6948:                    break;
        !          6949:                case XPATH_STRING:
        !          6950:                    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
        !          6951:                    break;
        !          6952:                case XPATH_NUMBER:
        !          6953:                    valuePush(ctxt, arg1);
        !          6954:                    xmlXPathNumberFunction(ctxt, 1);
        !          6955:                    arg1 = valuePop(ctxt);
        !          6956:                    /* Hand check NaN and Infinity equalities */
        !          6957:                    if (xmlXPathIsNaN(arg1->floatval) ||
        !          6958:                            xmlXPathIsNaN(arg2->floatval)) {
        !          6959:                        ret = 0;
        !          6960:                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
        !          6961:                        if (xmlXPathIsInf(arg2->floatval) == 1)
        !          6962:                            ret = 1;
        !          6963:                        else
        !          6964:                            ret = 0;
        !          6965:                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
        !          6966:                        if (xmlXPathIsInf(arg2->floatval) == -1)
        !          6967:                            ret = 1;
        !          6968:                        else
        !          6969:                            ret = 0;
        !          6970:                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
        !          6971:                        if (xmlXPathIsInf(arg1->floatval) == 1)
        !          6972:                            ret = 1;
        !          6973:                        else
        !          6974:                            ret = 0;
        !          6975:                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
        !          6976:                        if (xmlXPathIsInf(arg1->floatval) == -1)
        !          6977:                            ret = 1;
        !          6978:                        else
        !          6979:                            ret = 0;
        !          6980:                    } else {
        !          6981:                        ret = (arg1->floatval == arg2->floatval);
        !          6982:                    }
        !          6983:                    break;
        !          6984:                case XPATH_USERS:
        !          6985:                case XPATH_POINT:
        !          6986:                case XPATH_RANGE:
        !          6987:                case XPATH_LOCATIONSET:
        !          6988:                    TODO
        !          6989:                    break;
        !          6990:                case XPATH_NODESET:
        !          6991:                case XPATH_XSLT_TREE:
        !          6992:                    break;
        !          6993:            }
        !          6994:            break;
        !          6995:         case XPATH_USERS:
        !          6996:        case XPATH_POINT:
        !          6997:        case XPATH_RANGE:
        !          6998:        case XPATH_LOCATIONSET:
        !          6999:            TODO
        !          7000:            break;
        !          7001:        case XPATH_NODESET:
        !          7002:        case XPATH_XSLT_TREE:
        !          7003:            break;
        !          7004:     }
        !          7005:     xmlXPathReleaseObject(ctxt->context, arg1);
        !          7006:     xmlXPathReleaseObject(ctxt->context, arg2);
        !          7007:     return(ret);
        !          7008: }
        !          7009: 
        !          7010: /**
        !          7011:  * xmlXPathEqualValues:
        !          7012:  * @ctxt:  the XPath Parser context
        !          7013:  *
        !          7014:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
        !          7015:  *
        !          7016:  * Returns 0 or 1 depending on the results of the test.
        !          7017:  */
        !          7018: int
        !          7019: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
        !          7020:     xmlXPathObjectPtr arg1, arg2, argtmp;
        !          7021:     int ret = 0;
        !          7022: 
        !          7023:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
        !          7024:     arg2 = valuePop(ctxt);
        !          7025:     arg1 = valuePop(ctxt);
        !          7026:     if ((arg1 == NULL) || (arg2 == NULL)) {
        !          7027:        if (arg1 != NULL)
        !          7028:            xmlXPathReleaseObject(ctxt->context, arg1);
        !          7029:        else
        !          7030:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          7031:        XP_ERROR0(XPATH_INVALID_OPERAND);
        !          7032:     }
        !          7033: 
        !          7034:     if (arg1 == arg2) {
        !          7035: #ifdef DEBUG_EXPR
        !          7036:         xmlGenericError(xmlGenericErrorContext,
        !          7037:                "Equal: by pointer\n");
        !          7038: #endif
        !          7039:        xmlXPathFreeObject(arg1);
        !          7040:         return(1);
        !          7041:     }
        !          7042: 
        !          7043:     /*
        !          7044:      *If either argument is a nodeset, it's a 'special case'
        !          7045:      */
        !          7046:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
        !          7047:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
        !          7048:        /*
        !          7049:         *Hack it to assure arg1 is the nodeset
        !          7050:         */
        !          7051:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
        !          7052:                argtmp = arg2;
        !          7053:                arg2 = arg1;
        !          7054:                arg1 = argtmp;
        !          7055:        }
        !          7056:        switch (arg2->type) {
        !          7057:            case XPATH_UNDEFINED:
        !          7058: #ifdef DEBUG_EXPR
        !          7059:                xmlGenericError(xmlGenericErrorContext,
        !          7060:                        "Equal: undefined\n");
        !          7061: #endif
        !          7062:                break;
        !          7063:            case XPATH_NODESET:
        !          7064:            case XPATH_XSLT_TREE:
        !          7065:                ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
        !          7066:                break;
        !          7067:            case XPATH_BOOLEAN:
        !          7068:                if ((arg1->nodesetval == NULL) ||
        !          7069:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
        !          7070:                else
        !          7071:                    ret = 1;
        !          7072:                ret = (ret == arg2->boolval);
        !          7073:                break;
        !          7074:            case XPATH_NUMBER:
        !          7075:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
        !          7076:                break;
        !          7077:            case XPATH_STRING:
        !          7078:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
        !          7079:                break;
        !          7080:            case XPATH_USERS:
        !          7081:            case XPATH_POINT:
        !          7082:            case XPATH_RANGE:
        !          7083:            case XPATH_LOCATIONSET:
        !          7084:                TODO
        !          7085:                break;
        !          7086:        }
        !          7087:        xmlXPathReleaseObject(ctxt->context, arg1);
        !          7088:        xmlXPathReleaseObject(ctxt->context, arg2);
        !          7089:        return(ret);
        !          7090:     }
        !          7091: 
        !          7092:     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
        !          7093: }
        !          7094: 
        !          7095: /**
        !          7096:  * xmlXPathNotEqualValues:
        !          7097:  * @ctxt:  the XPath Parser context
        !          7098:  *
        !          7099:  * Implement the equal operation on XPath objects content: @arg1 == @arg2
        !          7100:  *
        !          7101:  * Returns 0 or 1 depending on the results of the test.
        !          7102:  */
        !          7103: int
        !          7104: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
        !          7105:     xmlXPathObjectPtr arg1, arg2, argtmp;
        !          7106:     int ret = 0;
        !          7107: 
        !          7108:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
        !          7109:     arg2 = valuePop(ctxt);
        !          7110:     arg1 = valuePop(ctxt);
        !          7111:     if ((arg1 == NULL) || (arg2 == NULL)) {
        !          7112:        if (arg1 != NULL)
        !          7113:            xmlXPathReleaseObject(ctxt->context, arg1);
        !          7114:        else
        !          7115:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          7116:        XP_ERROR0(XPATH_INVALID_OPERAND);
        !          7117:     }
        !          7118: 
        !          7119:     if (arg1 == arg2) {
        !          7120: #ifdef DEBUG_EXPR
        !          7121:         xmlGenericError(xmlGenericErrorContext,
        !          7122:                "NotEqual: by pointer\n");
        !          7123: #endif
        !          7124:        xmlXPathReleaseObject(ctxt->context, arg1);
        !          7125:         return(0);
        !          7126:     }
        !          7127: 
        !          7128:     /*
        !          7129:      *If either argument is a nodeset, it's a 'special case'
        !          7130:      */
        !          7131:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
        !          7132:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
        !          7133:        /*
        !          7134:         *Hack it to assure arg1 is the nodeset
        !          7135:         */
        !          7136:        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
        !          7137:                argtmp = arg2;
        !          7138:                arg2 = arg1;
        !          7139:                arg1 = argtmp;
        !          7140:        }
        !          7141:        switch (arg2->type) {
        !          7142:            case XPATH_UNDEFINED:
        !          7143: #ifdef DEBUG_EXPR
        !          7144:                xmlGenericError(xmlGenericErrorContext,
        !          7145:                        "NotEqual: undefined\n");
        !          7146: #endif
        !          7147:                break;
        !          7148:            case XPATH_NODESET:
        !          7149:            case XPATH_XSLT_TREE:
        !          7150:                ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
        !          7151:                break;
        !          7152:            case XPATH_BOOLEAN:
        !          7153:                if ((arg1->nodesetval == NULL) ||
        !          7154:                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
        !          7155:                else
        !          7156:                    ret = 1;
        !          7157:                ret = (ret != arg2->boolval);
        !          7158:                break;
        !          7159:            case XPATH_NUMBER:
        !          7160:                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
        !          7161:                break;
        !          7162:            case XPATH_STRING:
        !          7163:                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
        !          7164:                break;
        !          7165:            case XPATH_USERS:
        !          7166:            case XPATH_POINT:
        !          7167:            case XPATH_RANGE:
        !          7168:            case XPATH_LOCATIONSET:
        !          7169:                TODO
        !          7170:                break;
        !          7171:        }
        !          7172:        xmlXPathReleaseObject(ctxt->context, arg1);
        !          7173:        xmlXPathReleaseObject(ctxt->context, arg2);
        !          7174:        return(ret);
        !          7175:     }
        !          7176: 
        !          7177:     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
        !          7178: }
        !          7179: 
        !          7180: /**
        !          7181:  * xmlXPathCompareValues:
        !          7182:  * @ctxt:  the XPath Parser context
        !          7183:  * @inf:  less than (1) or greater than (0)
        !          7184:  * @strict:  is the comparison strict
        !          7185:  *
        !          7186:  * Implement the compare operation on XPath objects:
        !          7187:  *     @arg1 < @arg2    (1, 1, ...
        !          7188:  *     @arg1 <= @arg2   (1, 0, ...
        !          7189:  *     @arg1 > @arg2    (0, 1, ...
        !          7190:  *     @arg1 >= @arg2   (0, 0, ...
        !          7191:  *
        !          7192:  * When neither object to be compared is a node-set and the operator is
        !          7193:  * <=, <, >=, >, then the objects are compared by converted both objects
        !          7194:  * to numbers and comparing the numbers according to IEEE 754. The <
        !          7195:  * comparison will be true if and only if the first number is less than the
        !          7196:  * second number. The <= comparison will be true if and only if the first
        !          7197:  * number is less than or equal to the second number. The > comparison
        !          7198:  * will be true if and only if the first number is greater than the second
        !          7199:  * number. The >= comparison will be true if and only if the first number
        !          7200:  * is greater than or equal to the second number.
        !          7201:  *
        !          7202:  * Returns 1 if the comparison succeeded, 0 if it failed
        !          7203:  */
        !          7204: int
        !          7205: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
        !          7206:     int ret = 0, arg1i = 0, arg2i = 0;
        !          7207:     xmlXPathObjectPtr arg1, arg2;
        !          7208: 
        !          7209:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
        !          7210:     arg2 = valuePop(ctxt);
        !          7211:     arg1 = valuePop(ctxt);
        !          7212:     if ((arg1 == NULL) || (arg2 == NULL)) {
        !          7213:        if (arg1 != NULL)
        !          7214:            xmlXPathReleaseObject(ctxt->context, arg1);
        !          7215:        else
        !          7216:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          7217:        XP_ERROR0(XPATH_INVALID_OPERAND);
        !          7218:     }
        !          7219: 
        !          7220:     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
        !          7221:       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
        !          7222:        /*
        !          7223:         * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
        !          7224:         * are not freed from within this routine; they will be freed from the
        !          7225:         * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
        !          7226:         */
        !          7227:        if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
        !          7228:          ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
        !          7229:            ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
        !          7230:        } else {
        !          7231:            if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
        !          7232:                ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
        !          7233:                                                  arg1, arg2);
        !          7234:            } else {
        !          7235:                ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
        !          7236:                                                  arg2, arg1);
        !          7237:            }
        !          7238:        }
        !          7239:        return(ret);
        !          7240:     }
        !          7241: 
        !          7242:     if (arg1->type != XPATH_NUMBER) {
        !          7243:        valuePush(ctxt, arg1);
        !          7244:        xmlXPathNumberFunction(ctxt, 1);
        !          7245:        arg1 = valuePop(ctxt);
        !          7246:     }
        !          7247:     if (arg1->type != XPATH_NUMBER) {
        !          7248:        xmlXPathFreeObject(arg1);
        !          7249:        xmlXPathFreeObject(arg2);
        !          7250:        XP_ERROR0(XPATH_INVALID_OPERAND);
        !          7251:     }
        !          7252:     if (arg2->type != XPATH_NUMBER) {
        !          7253:        valuePush(ctxt, arg2);
        !          7254:        xmlXPathNumberFunction(ctxt, 1);
        !          7255:        arg2 = valuePop(ctxt);
        !          7256:     }
        !          7257:     if (arg2->type != XPATH_NUMBER) {
        !          7258:        xmlXPathReleaseObject(ctxt->context, arg1);
        !          7259:        xmlXPathReleaseObject(ctxt->context, arg2);
        !          7260:        XP_ERROR0(XPATH_INVALID_OPERAND);
        !          7261:     }
        !          7262:     /*
        !          7263:      * Add tests for infinity and nan
        !          7264:      * => feedback on 3.4 for Inf and NaN
        !          7265:      */
        !          7266:     /* Hand check NaN and Infinity comparisons */
        !          7267:     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
        !          7268:        ret=0;
        !          7269:     } else {
        !          7270:        arg1i=xmlXPathIsInf(arg1->floatval);
        !          7271:        arg2i=xmlXPathIsInf(arg2->floatval);
        !          7272:        if (inf && strict) {
        !          7273:            if ((arg1i == -1 && arg2i != -1) ||
        !          7274:                (arg2i == 1 && arg1i != 1)) {
        !          7275:                ret = 1;
        !          7276:            } else if (arg1i == 0 && arg2i == 0) {
        !          7277:                ret = (arg1->floatval < arg2->floatval);
        !          7278:            } else {
        !          7279:                ret = 0;
        !          7280:            }
        !          7281:        }
        !          7282:        else if (inf && !strict) {
        !          7283:            if (arg1i == -1 || arg2i == 1) {
        !          7284:                ret = 1;
        !          7285:            } else if (arg1i == 0 && arg2i == 0) {
        !          7286:                ret = (arg1->floatval <= arg2->floatval);
        !          7287:            } else {
        !          7288:                ret = 0;
        !          7289:            }
        !          7290:        }
        !          7291:        else if (!inf && strict) {
        !          7292:            if ((arg1i == 1 && arg2i != 1) ||
        !          7293:                (arg2i == -1 && arg1i != -1)) {
        !          7294:                ret = 1;
        !          7295:            } else if (arg1i == 0 && arg2i == 0) {
        !          7296:                ret = (arg1->floatval > arg2->floatval);
        !          7297:            } else {
        !          7298:                ret = 0;
        !          7299:            }
        !          7300:        }
        !          7301:        else if (!inf && !strict) {
        !          7302:            if (arg1i == 1 || arg2i == -1) {
        !          7303:                ret = 1;
        !          7304:            } else if (arg1i == 0 && arg2i == 0) {
        !          7305:                ret = (arg1->floatval >= arg2->floatval);
        !          7306:            } else {
        !          7307:                ret = 0;
        !          7308:            }
        !          7309:        }
        !          7310:     }
        !          7311:     xmlXPathReleaseObject(ctxt->context, arg1);
        !          7312:     xmlXPathReleaseObject(ctxt->context, arg2);
        !          7313:     return(ret);
        !          7314: }
        !          7315: 
        !          7316: /**
        !          7317:  * xmlXPathValueFlipSign:
        !          7318:  * @ctxt:  the XPath Parser context
        !          7319:  *
        !          7320:  * Implement the unary - operation on an XPath object
        !          7321:  * The numeric operators convert their operands to numbers as if
        !          7322:  * by calling the number function.
        !          7323:  */
        !          7324: void
        !          7325: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
        !          7326:     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
        !          7327:     CAST_TO_NUMBER;
        !          7328:     CHECK_TYPE(XPATH_NUMBER);
        !          7329:     if (xmlXPathIsNaN(ctxt->value->floatval))
        !          7330:         ctxt->value->floatval=xmlXPathNAN;
        !          7331:     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
        !          7332:         ctxt->value->floatval=xmlXPathNINF;
        !          7333:     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
        !          7334:         ctxt->value->floatval=xmlXPathPINF;
        !          7335:     else if (ctxt->value->floatval == 0) {
        !          7336:         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
        !          7337:            ctxt->value->floatval = xmlXPathNZERO;
        !          7338:        else
        !          7339:            ctxt->value->floatval = 0;
        !          7340:     }
        !          7341:     else
        !          7342:         ctxt->value->floatval = - ctxt->value->floatval;
        !          7343: }
        !          7344: 
        !          7345: /**
        !          7346:  * xmlXPathAddValues:
        !          7347:  * @ctxt:  the XPath Parser context
        !          7348:  *
        !          7349:  * Implement the add operation on XPath objects:
        !          7350:  * The numeric operators convert their operands to numbers as if
        !          7351:  * by calling the number function.
        !          7352:  */
        !          7353: void
        !          7354: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
        !          7355:     xmlXPathObjectPtr arg;
        !          7356:     double val;
        !          7357: 
        !          7358:     arg = valuePop(ctxt);
        !          7359:     if (arg == NULL)
        !          7360:        XP_ERROR(XPATH_INVALID_OPERAND);
        !          7361:     val = xmlXPathCastToNumber(arg);
        !          7362:     xmlXPathReleaseObject(ctxt->context, arg);
        !          7363:     CAST_TO_NUMBER;
        !          7364:     CHECK_TYPE(XPATH_NUMBER);
        !          7365:     ctxt->value->floatval += val;
        !          7366: }
        !          7367: 
        !          7368: /**
        !          7369:  * xmlXPathSubValues:
        !          7370:  * @ctxt:  the XPath Parser context
        !          7371:  *
        !          7372:  * Implement the subtraction operation on XPath objects:
        !          7373:  * The numeric operators convert their operands to numbers as if
        !          7374:  * by calling the number function.
        !          7375:  */
        !          7376: void
        !          7377: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
        !          7378:     xmlXPathObjectPtr arg;
        !          7379:     double val;
        !          7380: 
        !          7381:     arg = valuePop(ctxt);
        !          7382:     if (arg == NULL)
        !          7383:        XP_ERROR(XPATH_INVALID_OPERAND);
        !          7384:     val = xmlXPathCastToNumber(arg);
        !          7385:     xmlXPathReleaseObject(ctxt->context, arg);
        !          7386:     CAST_TO_NUMBER;
        !          7387:     CHECK_TYPE(XPATH_NUMBER);
        !          7388:     ctxt->value->floatval -= val;
        !          7389: }
        !          7390: 
        !          7391: /**
        !          7392:  * xmlXPathMultValues:
        !          7393:  * @ctxt:  the XPath Parser context
        !          7394:  *
        !          7395:  * Implement the multiply operation on XPath objects:
        !          7396:  * The numeric operators convert their operands to numbers as if
        !          7397:  * by calling the number function.
        !          7398:  */
        !          7399: void
        !          7400: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
        !          7401:     xmlXPathObjectPtr arg;
        !          7402:     double val;
        !          7403: 
        !          7404:     arg = valuePop(ctxt);
        !          7405:     if (arg == NULL)
        !          7406:        XP_ERROR(XPATH_INVALID_OPERAND);
        !          7407:     val = xmlXPathCastToNumber(arg);
        !          7408:     xmlXPathReleaseObject(ctxt->context, arg);
        !          7409:     CAST_TO_NUMBER;
        !          7410:     CHECK_TYPE(XPATH_NUMBER);
        !          7411:     ctxt->value->floatval *= val;
        !          7412: }
        !          7413: 
        !          7414: /**
        !          7415:  * xmlXPathDivValues:
        !          7416:  * @ctxt:  the XPath Parser context
        !          7417:  *
        !          7418:  * Implement the div operation on XPath objects @arg1 / @arg2:
        !          7419:  * The numeric operators convert their operands to numbers as if
        !          7420:  * by calling the number function.
        !          7421:  */
        !          7422: void
        !          7423: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
        !          7424:     xmlXPathObjectPtr arg;
        !          7425:     double val;
        !          7426: 
        !          7427:     arg = valuePop(ctxt);
        !          7428:     if (arg == NULL)
        !          7429:        XP_ERROR(XPATH_INVALID_OPERAND);
        !          7430:     val = xmlXPathCastToNumber(arg);
        !          7431:     xmlXPathReleaseObject(ctxt->context, arg);
        !          7432:     CAST_TO_NUMBER;
        !          7433:     CHECK_TYPE(XPATH_NUMBER);
        !          7434:     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
        !          7435:        ctxt->value->floatval = xmlXPathNAN;
        !          7436:     else if (val == 0 && xmlXPathGetSign(val) != 0) {
        !          7437:        if (ctxt->value->floatval == 0)
        !          7438:            ctxt->value->floatval = xmlXPathNAN;
        !          7439:        else if (ctxt->value->floatval > 0)
        !          7440:            ctxt->value->floatval = xmlXPathNINF;
        !          7441:        else if (ctxt->value->floatval < 0)
        !          7442:            ctxt->value->floatval = xmlXPathPINF;
        !          7443:     }
        !          7444:     else if (val == 0) {
        !          7445:        if (ctxt->value->floatval == 0)
        !          7446:            ctxt->value->floatval = xmlXPathNAN;
        !          7447:        else if (ctxt->value->floatval > 0)
        !          7448:            ctxt->value->floatval = xmlXPathPINF;
        !          7449:        else if (ctxt->value->floatval < 0)
        !          7450:            ctxt->value->floatval = xmlXPathNINF;
        !          7451:     } else
        !          7452:        ctxt->value->floatval /= val;
        !          7453: }
        !          7454: 
        !          7455: /**
        !          7456:  * xmlXPathModValues:
        !          7457:  * @ctxt:  the XPath Parser context
        !          7458:  *
        !          7459:  * Implement the mod operation on XPath objects: @arg1 / @arg2
        !          7460:  * The numeric operators convert their operands to numbers as if
        !          7461:  * by calling the number function.
        !          7462:  */
        !          7463: void
        !          7464: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
        !          7465:     xmlXPathObjectPtr arg;
        !          7466:     double arg1, arg2;
        !          7467: 
        !          7468:     arg = valuePop(ctxt);
        !          7469:     if (arg == NULL)
        !          7470:        XP_ERROR(XPATH_INVALID_OPERAND);
        !          7471:     arg2 = xmlXPathCastToNumber(arg);
        !          7472:     xmlXPathReleaseObject(ctxt->context, arg);
        !          7473:     CAST_TO_NUMBER;
        !          7474:     CHECK_TYPE(XPATH_NUMBER);
        !          7475:     arg1 = ctxt->value->floatval;
        !          7476:     if (arg2 == 0)
        !          7477:        ctxt->value->floatval = xmlXPathNAN;
        !          7478:     else {
        !          7479:        ctxt->value->floatval = fmod(arg1, arg2);
        !          7480:     }
        !          7481: }
        !          7482: 
        !          7483: /************************************************************************
        !          7484:  *                                                                     *
        !          7485:  *             The traversal functions                                 *
        !          7486:  *                                                                     *
        !          7487:  ************************************************************************/
        !          7488: 
        !          7489: /*
        !          7490:  * A traversal function enumerates nodes along an axis.
        !          7491:  * Initially it must be called with NULL, and it indicates
        !          7492:  * termination on the axis by returning NULL.
        !          7493:  */
        !          7494: typedef xmlNodePtr (*xmlXPathTraversalFunction)
        !          7495:                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
        !          7496: 
        !          7497: /*
        !          7498:  * xmlXPathTraversalFunctionExt:
        !          7499:  * A traversal function enumerates nodes along an axis.
        !          7500:  * Initially it must be called with NULL, and it indicates
        !          7501:  * termination on the axis by returning NULL.
        !          7502:  * The context node of the traversal is specified via @contextNode.
        !          7503:  */
        !          7504: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
        !          7505:                     (xmlNodePtr cur, xmlNodePtr contextNode);
        !          7506: 
        !          7507: /*
        !          7508:  * xmlXPathNodeSetMergeFunction:
        !          7509:  * Used for merging node sets in xmlXPathCollectAndTest().
        !          7510:  */
        !          7511: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
        !          7512:                    (xmlNodeSetPtr, xmlNodeSetPtr, int);
        !          7513: 
        !          7514: 
        !          7515: /**
        !          7516:  * xmlXPathNextSelf:
        !          7517:  * @ctxt:  the XPath Parser context
        !          7518:  * @cur:  the current node in the traversal
        !          7519:  *
        !          7520:  * Traversal function for the "self" direction
        !          7521:  * The self axis contains just the context node itself
        !          7522:  *
        !          7523:  * Returns the next element following that axis
        !          7524:  */
        !          7525: xmlNodePtr
        !          7526: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7527:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7528:     if (cur == NULL)
        !          7529:         return(ctxt->context->node);
        !          7530:     return(NULL);
        !          7531: }
        !          7532: 
        !          7533: /**
        !          7534:  * xmlXPathNextChild:
        !          7535:  * @ctxt:  the XPath Parser context
        !          7536:  * @cur:  the current node in the traversal
        !          7537:  *
        !          7538:  * Traversal function for the "child" direction
        !          7539:  * The child axis contains the children of the context node in document order.
        !          7540:  *
        !          7541:  * Returns the next element following that axis
        !          7542:  */
        !          7543: xmlNodePtr
        !          7544: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7545:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7546:     if (cur == NULL) {
        !          7547:        if (ctxt->context->node == NULL) return(NULL);
        !          7548:        switch (ctxt->context->node->type) {
        !          7549:             case XML_ELEMENT_NODE:
        !          7550:             case XML_TEXT_NODE:
        !          7551:             case XML_CDATA_SECTION_NODE:
        !          7552:             case XML_ENTITY_REF_NODE:
        !          7553:             case XML_ENTITY_NODE:
        !          7554:             case XML_PI_NODE:
        !          7555:             case XML_COMMENT_NODE:
        !          7556:             case XML_NOTATION_NODE:
        !          7557:             case XML_DTD_NODE:
        !          7558:                return(ctxt->context->node->children);
        !          7559:             case XML_DOCUMENT_NODE:
        !          7560:             case XML_DOCUMENT_TYPE_NODE:
        !          7561:             case XML_DOCUMENT_FRAG_NODE:
        !          7562:             case XML_HTML_DOCUMENT_NODE:
        !          7563: #ifdef LIBXML_DOCB_ENABLED
        !          7564:            case XML_DOCB_DOCUMENT_NODE:
        !          7565: #endif
        !          7566:                return(((xmlDocPtr) ctxt->context->node)->children);
        !          7567:            case XML_ELEMENT_DECL:
        !          7568:            case XML_ATTRIBUTE_DECL:
        !          7569:            case XML_ENTITY_DECL:
        !          7570:             case XML_ATTRIBUTE_NODE:
        !          7571:            case XML_NAMESPACE_DECL:
        !          7572:            case XML_XINCLUDE_START:
        !          7573:            case XML_XINCLUDE_END:
        !          7574:                return(NULL);
        !          7575:        }
        !          7576:        return(NULL);
        !          7577:     }
        !          7578:     if ((cur->type == XML_DOCUMENT_NODE) ||
        !          7579:         (cur->type == XML_HTML_DOCUMENT_NODE))
        !          7580:        return(NULL);
        !          7581:     return(cur->next);
        !          7582: }
        !          7583: 
        !          7584: /**
        !          7585:  * xmlXPathNextChildElement:
        !          7586:  * @ctxt:  the XPath Parser context
        !          7587:  * @cur:  the current node in the traversal
        !          7588:  *
        !          7589:  * Traversal function for the "child" direction and nodes of type element.
        !          7590:  * The child axis contains the children of the context node in document order.
        !          7591:  *
        !          7592:  * Returns the next element following that axis
        !          7593:  */
        !          7594: static xmlNodePtr
        !          7595: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7596:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7597:     if (cur == NULL) {
        !          7598:        cur = ctxt->context->node;
        !          7599:        if (cur == NULL) return(NULL);
        !          7600:        /*
        !          7601:        * Get the first element child.
        !          7602:        */
        !          7603:        switch (cur->type) {
        !          7604:             case XML_ELEMENT_NODE:
        !          7605:            case XML_DOCUMENT_FRAG_NODE:
        !          7606:            case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
        !          7607:             case XML_ENTITY_NODE:
        !          7608:                cur = cur->children;
        !          7609:                if (cur != NULL) {
        !          7610:                    if (cur->type == XML_ELEMENT_NODE)
        !          7611:                        return(cur);
        !          7612:                    do {
        !          7613:                        cur = cur->next;
        !          7614:                    } while ((cur != NULL) &&
        !          7615:                        (cur->type != XML_ELEMENT_NODE));
        !          7616:                    return(cur);
        !          7617:                }
        !          7618:                return(NULL);
        !          7619:             case XML_DOCUMENT_NODE:
        !          7620:             case XML_HTML_DOCUMENT_NODE:
        !          7621: #ifdef LIBXML_DOCB_ENABLED
        !          7622:            case XML_DOCB_DOCUMENT_NODE:
        !          7623: #endif
        !          7624:                return(xmlDocGetRootElement((xmlDocPtr) cur));
        !          7625:            default:
        !          7626:                return(NULL);
        !          7627:        }
        !          7628:        return(NULL);
        !          7629:     }
        !          7630:     /*
        !          7631:     * Get the next sibling element node.
        !          7632:     */
        !          7633:     switch (cur->type) {
        !          7634:        case XML_ELEMENT_NODE:
        !          7635:        case XML_TEXT_NODE:
        !          7636:        case XML_ENTITY_REF_NODE:
        !          7637:        case XML_ENTITY_NODE:
        !          7638:        case XML_CDATA_SECTION_NODE:
        !          7639:        case XML_PI_NODE:
        !          7640:        case XML_COMMENT_NODE:
        !          7641:        case XML_XINCLUDE_END:
        !          7642:            break;
        !          7643:        /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
        !          7644:        default:
        !          7645:            return(NULL);
        !          7646:     }
        !          7647:     if (cur->next != NULL) {
        !          7648:        if (cur->next->type == XML_ELEMENT_NODE)
        !          7649:            return(cur->next);
        !          7650:        cur = cur->next;
        !          7651:        do {
        !          7652:            cur = cur->next;
        !          7653:        } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
        !          7654:        return(cur);
        !          7655:     }
        !          7656:     return(NULL);
        !          7657: }
        !          7658: 
        !          7659: /**
        !          7660:  * xmlXPathNextDescendantOrSelfElemParent:
        !          7661:  * @ctxt:  the XPath Parser context
        !          7662:  * @cur:  the current node in the traversal
        !          7663:  *
        !          7664:  * Traversal function for the "descendant-or-self" axis.
        !          7665:  * Additionally it returns only nodes which can be parents of
        !          7666:  * element nodes.
        !          7667:  *
        !          7668:  *
        !          7669:  * Returns the next element following that axis
        !          7670:  */
        !          7671: static xmlNodePtr
        !          7672: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
        !          7673:                                       xmlNodePtr contextNode)
        !          7674: {
        !          7675:     if (cur == NULL) {
        !          7676:        if (contextNode == NULL)
        !          7677:            return(NULL);
        !          7678:        switch (contextNode->type) {
        !          7679:            case XML_ELEMENT_NODE:
        !          7680:            case XML_XINCLUDE_START:
        !          7681:            case XML_DOCUMENT_FRAG_NODE:
        !          7682:            case XML_DOCUMENT_NODE:
        !          7683: #ifdef LIBXML_DOCB_ENABLED
        !          7684:            case XML_DOCB_DOCUMENT_NODE:
        !          7685: #endif
        !          7686:            case XML_HTML_DOCUMENT_NODE:            
        !          7687:                return(contextNode);
        !          7688:            default:
        !          7689:                return(NULL);
        !          7690:        }
        !          7691:        return(NULL);
        !          7692:     } else {
        !          7693:        xmlNodePtr start = cur;
        !          7694: 
        !          7695:        while (cur != NULL) {
        !          7696:            switch (cur->type) {
        !          7697:                case XML_ELEMENT_NODE:
        !          7698:                /* TODO: OK to have XInclude here? */
        !          7699:                case XML_XINCLUDE_START:
        !          7700:                case XML_DOCUMENT_FRAG_NODE:
        !          7701:                    if (cur != start)
        !          7702:                        return(cur);
        !          7703:                    if (cur->children != NULL) {
        !          7704:                        cur = cur->children;
        !          7705:                        continue;
        !          7706:                    }
        !          7707:                    break;
        !          7708:                /* Not sure if we need those here. */
        !          7709:                case XML_DOCUMENT_NODE:
        !          7710: #ifdef LIBXML_DOCB_ENABLED
        !          7711:                case XML_DOCB_DOCUMENT_NODE:
        !          7712: #endif
        !          7713:                case XML_HTML_DOCUMENT_NODE:
        !          7714:                    if (cur != start)
        !          7715:                        return(cur);
        !          7716:                    return(xmlDocGetRootElement((xmlDocPtr) cur));
        !          7717:                default:
        !          7718:                    break;
        !          7719:            }
        !          7720: 
        !          7721: next_sibling:
        !          7722:            if ((cur == NULL) || (cur == contextNode))
        !          7723:                return(NULL);
        !          7724:            if (cur->next != NULL) {
        !          7725:                cur = cur->next;
        !          7726:            } else {
        !          7727:                cur = cur->parent;
        !          7728:                goto next_sibling;
        !          7729:            }
        !          7730:        }
        !          7731:     }
        !          7732:     return(NULL);
        !          7733: }
        !          7734: 
        !          7735: /**
        !          7736:  * xmlXPathNextDescendant:
        !          7737:  * @ctxt:  the XPath Parser context
        !          7738:  * @cur:  the current node in the traversal
        !          7739:  *
        !          7740:  * Traversal function for the "descendant" direction
        !          7741:  * the descendant axis contains the descendants of the context node in document
        !          7742:  * order; a descendant is a child or a child of a child and so on.
        !          7743:  *
        !          7744:  * Returns the next element following that axis
        !          7745:  */
        !          7746: xmlNodePtr
        !          7747: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7748:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7749:     if (cur == NULL) {
        !          7750:        if (ctxt->context->node == NULL)
        !          7751:            return(NULL);
        !          7752:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
        !          7753:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
        !          7754:            return(NULL);
        !          7755: 
        !          7756:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
        !          7757:            return(ctxt->context->doc->children);
        !          7758:         return(ctxt->context->node->children);
        !          7759:     }
        !          7760: 
        !          7761:     if (cur->children != NULL) {
        !          7762:        /*
        !          7763:         * Do not descend on entities declarations
        !          7764:         */
        !          7765:        if (cur->children->type != XML_ENTITY_DECL) {
        !          7766:            cur = cur->children;
        !          7767:            /*
        !          7768:             * Skip DTDs
        !          7769:             */
        !          7770:            if (cur->type != XML_DTD_NODE)
        !          7771:                return(cur);
        !          7772:        }
        !          7773:     }
        !          7774: 
        !          7775:     if (cur == ctxt->context->node) return(NULL);
        !          7776: 
        !          7777:     while (cur->next != NULL) {
        !          7778:        cur = cur->next;
        !          7779:        if ((cur->type != XML_ENTITY_DECL) &&
        !          7780:            (cur->type != XML_DTD_NODE))
        !          7781:            return(cur);
        !          7782:     }
        !          7783: 
        !          7784:     do {
        !          7785:         cur = cur->parent;
        !          7786:        if (cur == NULL) break;
        !          7787:        if (cur == ctxt->context->node) return(NULL);
        !          7788:        if (cur->next != NULL) {
        !          7789:            cur = cur->next;
        !          7790:            return(cur);
        !          7791:        }
        !          7792:     } while (cur != NULL);
        !          7793:     return(cur);
        !          7794: }
        !          7795: 
        !          7796: /**
        !          7797:  * xmlXPathNextDescendantOrSelf:
        !          7798:  * @ctxt:  the XPath Parser context
        !          7799:  * @cur:  the current node in the traversal
        !          7800:  *
        !          7801:  * Traversal function for the "descendant-or-self" direction
        !          7802:  * the descendant-or-self axis contains the context node and the descendants
        !          7803:  * of the context node in document order; thus the context node is the first
        !          7804:  * node on the axis, and the first child of the context node is the second node
        !          7805:  * on the axis
        !          7806:  *
        !          7807:  * Returns the next element following that axis
        !          7808:  */
        !          7809: xmlNodePtr
        !          7810: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7811:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7812:     if (cur == NULL) {
        !          7813:        if (ctxt->context->node == NULL)
        !          7814:            return(NULL);
        !          7815:        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
        !          7816:            (ctxt->context->node->type == XML_NAMESPACE_DECL))
        !          7817:            return(NULL);
        !          7818:         return(ctxt->context->node);
        !          7819:     }
        !          7820: 
        !          7821:     return(xmlXPathNextDescendant(ctxt, cur));
        !          7822: }
        !          7823: 
        !          7824: /**
        !          7825:  * xmlXPathNextParent:
        !          7826:  * @ctxt:  the XPath Parser context
        !          7827:  * @cur:  the current node in the traversal
        !          7828:  *
        !          7829:  * Traversal function for the "parent" direction
        !          7830:  * The parent axis contains the parent of the context node, if there is one.
        !          7831:  *
        !          7832:  * Returns the next element following that axis
        !          7833:  */
        !          7834: xmlNodePtr
        !          7835: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7836:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7837:     /*
        !          7838:      * the parent of an attribute or namespace node is the element
        !          7839:      * to which the attribute or namespace node is attached
        !          7840:      * Namespace handling !!!
        !          7841:      */
        !          7842:     if (cur == NULL) {
        !          7843:        if (ctxt->context->node == NULL) return(NULL);
        !          7844:        switch (ctxt->context->node->type) {
        !          7845:             case XML_ELEMENT_NODE:
        !          7846:             case XML_TEXT_NODE:
        !          7847:             case XML_CDATA_SECTION_NODE:
        !          7848:             case XML_ENTITY_REF_NODE:
        !          7849:             case XML_ENTITY_NODE:
        !          7850:             case XML_PI_NODE:
        !          7851:             case XML_COMMENT_NODE:
        !          7852:             case XML_NOTATION_NODE:
        !          7853:             case XML_DTD_NODE:
        !          7854:            case XML_ELEMENT_DECL:
        !          7855:            case XML_ATTRIBUTE_DECL:
        !          7856:            case XML_XINCLUDE_START:
        !          7857:            case XML_XINCLUDE_END:
        !          7858:            case XML_ENTITY_DECL:
        !          7859:                if (ctxt->context->node->parent == NULL)
        !          7860:                    return((xmlNodePtr) ctxt->context->doc);
        !          7861:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
        !          7862:                    ((ctxt->context->node->parent->name[0] == ' ') ||
        !          7863:                     (xmlStrEqual(ctxt->context->node->parent->name,
        !          7864:                                 BAD_CAST "fake node libxslt"))))
        !          7865:                    return(NULL);
        !          7866:                return(ctxt->context->node->parent);
        !          7867:             case XML_ATTRIBUTE_NODE: {
        !          7868:                xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
        !          7869: 
        !          7870:                return(att->parent);
        !          7871:            }
        !          7872:             case XML_DOCUMENT_NODE:
        !          7873:             case XML_DOCUMENT_TYPE_NODE:
        !          7874:             case XML_DOCUMENT_FRAG_NODE:
        !          7875:             case XML_HTML_DOCUMENT_NODE:
        !          7876: #ifdef LIBXML_DOCB_ENABLED
        !          7877:            case XML_DOCB_DOCUMENT_NODE:
        !          7878: #endif
        !          7879:                 return(NULL);
        !          7880:            case XML_NAMESPACE_DECL: {
        !          7881:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
        !          7882: 
        !          7883:                if ((ns->next != NULL) &&
        !          7884:                    (ns->next->type != XML_NAMESPACE_DECL))
        !          7885:                    return((xmlNodePtr) ns->next);
        !          7886:                 return(NULL);
        !          7887:            }
        !          7888:        }
        !          7889:     }
        !          7890:     return(NULL);
        !          7891: }
        !          7892: 
        !          7893: /**
        !          7894:  * xmlXPathNextAncestor:
        !          7895:  * @ctxt:  the XPath Parser context
        !          7896:  * @cur:  the current node in the traversal
        !          7897:  *
        !          7898:  * Traversal function for the "ancestor" direction
        !          7899:  * the ancestor axis contains the ancestors of the context node; the ancestors
        !          7900:  * of the context node consist of the parent of context node and the parent's
        !          7901:  * parent and so on; the nodes are ordered in reverse document order; thus the
        !          7902:  * parent is the first node on the axis, and the parent's parent is the second
        !          7903:  * node on the axis
        !          7904:  *
        !          7905:  * Returns the next element following that axis
        !          7906:  */
        !          7907: xmlNodePtr
        !          7908: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          7909:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          7910:     /*
        !          7911:      * the parent of an attribute or namespace node is the element
        !          7912:      * to which the attribute or namespace node is attached
        !          7913:      * !!!!!!!!!!!!!
        !          7914:      */
        !          7915:     if (cur == NULL) {
        !          7916:        if (ctxt->context->node == NULL) return(NULL);
        !          7917:        switch (ctxt->context->node->type) {
        !          7918:             case XML_ELEMENT_NODE:
        !          7919:             case XML_TEXT_NODE:
        !          7920:             case XML_CDATA_SECTION_NODE:
        !          7921:             case XML_ENTITY_REF_NODE:
        !          7922:             case XML_ENTITY_NODE:
        !          7923:             case XML_PI_NODE:
        !          7924:             case XML_COMMENT_NODE:
        !          7925:            case XML_DTD_NODE:
        !          7926:            case XML_ELEMENT_DECL:
        !          7927:            case XML_ATTRIBUTE_DECL:
        !          7928:            case XML_ENTITY_DECL:
        !          7929:             case XML_NOTATION_NODE:
        !          7930:            case XML_XINCLUDE_START:
        !          7931:            case XML_XINCLUDE_END:
        !          7932:                if (ctxt->context->node->parent == NULL)
        !          7933:                    return((xmlNodePtr) ctxt->context->doc);
        !          7934:                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
        !          7935:                    ((ctxt->context->node->parent->name[0] == ' ') ||
        !          7936:                     (xmlStrEqual(ctxt->context->node->parent->name,
        !          7937:                                 BAD_CAST "fake node libxslt"))))
        !          7938:                    return(NULL);
        !          7939:                return(ctxt->context->node->parent);
        !          7940:             case XML_ATTRIBUTE_NODE: {
        !          7941:                xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
        !          7942: 
        !          7943:                return(tmp->parent);
        !          7944:            }
        !          7945:             case XML_DOCUMENT_NODE:
        !          7946:             case XML_DOCUMENT_TYPE_NODE:
        !          7947:             case XML_DOCUMENT_FRAG_NODE:
        !          7948:             case XML_HTML_DOCUMENT_NODE:
        !          7949: #ifdef LIBXML_DOCB_ENABLED
        !          7950:            case XML_DOCB_DOCUMENT_NODE:
        !          7951: #endif
        !          7952:                 return(NULL);
        !          7953:            case XML_NAMESPACE_DECL: {
        !          7954:                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
        !          7955: 
        !          7956:                if ((ns->next != NULL) &&
        !          7957:                    (ns->next->type != XML_NAMESPACE_DECL))
        !          7958:                    return((xmlNodePtr) ns->next);
        !          7959:                /* Bad, how did that namespace end up here ? */
        !          7960:                 return(NULL);
        !          7961:            }
        !          7962:        }
        !          7963:        return(NULL);
        !          7964:     }
        !          7965:     if (cur == ctxt->context->doc->children)
        !          7966:        return((xmlNodePtr) ctxt->context->doc);
        !          7967:     if (cur == (xmlNodePtr) ctxt->context->doc)
        !          7968:        return(NULL);
        !          7969:     switch (cur->type) {
        !          7970:        case XML_ELEMENT_NODE:
        !          7971:        case XML_TEXT_NODE:
        !          7972:        case XML_CDATA_SECTION_NODE:
        !          7973:        case XML_ENTITY_REF_NODE:
        !          7974:        case XML_ENTITY_NODE:
        !          7975:        case XML_PI_NODE:
        !          7976:        case XML_COMMENT_NODE:
        !          7977:        case XML_NOTATION_NODE:
        !          7978:        case XML_DTD_NODE:
        !          7979:         case XML_ELEMENT_DECL:
        !          7980:         case XML_ATTRIBUTE_DECL:
        !          7981:         case XML_ENTITY_DECL:
        !          7982:        case XML_XINCLUDE_START:
        !          7983:        case XML_XINCLUDE_END:
        !          7984:            if (cur->parent == NULL)
        !          7985:                return(NULL);
        !          7986:            if ((cur->parent->type == XML_ELEMENT_NODE) &&
        !          7987:                ((cur->parent->name[0] == ' ') ||
        !          7988:                 (xmlStrEqual(cur->parent->name,
        !          7989:                              BAD_CAST "fake node libxslt"))))
        !          7990:                return(NULL);
        !          7991:            return(cur->parent);
        !          7992:        case XML_ATTRIBUTE_NODE: {
        !          7993:            xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
        !          7994: 
        !          7995:            return(att->parent);
        !          7996:        }
        !          7997:        case XML_NAMESPACE_DECL: {
        !          7998:            xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
        !          7999: 
        !          8000:            if ((ns->next != NULL) &&
        !          8001:                (ns->next->type != XML_NAMESPACE_DECL))
        !          8002:                return((xmlNodePtr) ns->next);
        !          8003:            /* Bad, how did that namespace end up here ? */
        !          8004:             return(NULL);
        !          8005:        }
        !          8006:        case XML_DOCUMENT_NODE:
        !          8007:        case XML_DOCUMENT_TYPE_NODE:
        !          8008:        case XML_DOCUMENT_FRAG_NODE:
        !          8009:        case XML_HTML_DOCUMENT_NODE:
        !          8010: #ifdef LIBXML_DOCB_ENABLED
        !          8011:        case XML_DOCB_DOCUMENT_NODE:
        !          8012: #endif
        !          8013:            return(NULL);
        !          8014:     }
        !          8015:     return(NULL);
        !          8016: }
        !          8017: 
        !          8018: /**
        !          8019:  * xmlXPathNextAncestorOrSelf:
        !          8020:  * @ctxt:  the XPath Parser context
        !          8021:  * @cur:  the current node in the traversal
        !          8022:  *
        !          8023:  * Traversal function for the "ancestor-or-self" direction
        !          8024:  * he ancestor-or-self axis contains the context node and ancestors of
        !          8025:  * the context node in reverse document order; thus the context node is
        !          8026:  * the first node on the axis, and the context node's parent the second;
        !          8027:  * parent here is defined the same as with the parent axis.
        !          8028:  *
        !          8029:  * Returns the next element following that axis
        !          8030:  */
        !          8031: xmlNodePtr
        !          8032: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8033:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8034:     if (cur == NULL)
        !          8035:         return(ctxt->context->node);
        !          8036:     return(xmlXPathNextAncestor(ctxt, cur));
        !          8037: }
        !          8038: 
        !          8039: /**
        !          8040:  * xmlXPathNextFollowingSibling:
        !          8041:  * @ctxt:  the XPath Parser context
        !          8042:  * @cur:  the current node in the traversal
        !          8043:  *
        !          8044:  * Traversal function for the "following-sibling" direction
        !          8045:  * The following-sibling axis contains the following siblings of the context
        !          8046:  * node in document order.
        !          8047:  *
        !          8048:  * Returns the next element following that axis
        !          8049:  */
        !          8050: xmlNodePtr
        !          8051: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8052:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8053:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
        !          8054:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
        !          8055:        return(NULL);
        !          8056:     if (cur == (xmlNodePtr) ctxt->context->doc)
        !          8057:         return(NULL);
        !          8058:     if (cur == NULL)
        !          8059:         return(ctxt->context->node->next);
        !          8060:     return(cur->next);
        !          8061: }
        !          8062: 
        !          8063: /**
        !          8064:  * xmlXPathNextPrecedingSibling:
        !          8065:  * @ctxt:  the XPath Parser context
        !          8066:  * @cur:  the current node in the traversal
        !          8067:  *
        !          8068:  * Traversal function for the "preceding-sibling" direction
        !          8069:  * The preceding-sibling axis contains the preceding siblings of the context
        !          8070:  * node in reverse document order; the first preceding sibling is first on the
        !          8071:  * axis; the sibling preceding that node is the second on the axis and so on.
        !          8072:  *
        !          8073:  * Returns the next element following that axis
        !          8074:  */
        !          8075: xmlNodePtr
        !          8076: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8077:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8078:     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
        !          8079:        (ctxt->context->node->type == XML_NAMESPACE_DECL))
        !          8080:        return(NULL);
        !          8081:     if (cur == (xmlNodePtr) ctxt->context->doc)
        !          8082:         return(NULL);
        !          8083:     if (cur == NULL)
        !          8084:         return(ctxt->context->node->prev);
        !          8085:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
        !          8086:        cur = cur->prev;
        !          8087:        if (cur == NULL)
        !          8088:            return(ctxt->context->node->prev);
        !          8089:     }
        !          8090:     return(cur->prev);
        !          8091: }
        !          8092: 
        !          8093: /**
        !          8094:  * xmlXPathNextFollowing:
        !          8095:  * @ctxt:  the XPath Parser context
        !          8096:  * @cur:  the current node in the traversal
        !          8097:  *
        !          8098:  * Traversal function for the "following" direction
        !          8099:  * The following axis contains all nodes in the same document as the context
        !          8100:  * node that are after the context node in document order, excluding any
        !          8101:  * descendants and excluding attribute nodes and namespace nodes; the nodes
        !          8102:  * are ordered in document order
        !          8103:  *
        !          8104:  * Returns the next element following that axis
        !          8105:  */
        !          8106: xmlNodePtr
        !          8107: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8108:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8109:     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
        !          8110:         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
        !          8111:         return(cur->children);
        !          8112: 
        !          8113:     if (cur == NULL) {
        !          8114:         cur = ctxt->context->node;
        !          8115:         if (cur->type == XML_NAMESPACE_DECL)
        !          8116:             return(NULL);
        !          8117:         if (cur->type == XML_ATTRIBUTE_NODE)
        !          8118:             cur = cur->parent;
        !          8119:     }
        !          8120:     if (cur == NULL) return(NULL) ; /* ERROR */
        !          8121:     if (cur->next != NULL) return(cur->next) ;
        !          8122:     do {
        !          8123:         cur = cur->parent;
        !          8124:         if (cur == NULL) break;
        !          8125:         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
        !          8126:         if (cur->next != NULL) return(cur->next);
        !          8127:     } while (cur != NULL);
        !          8128:     return(cur);
        !          8129: }
        !          8130: 
        !          8131: /*
        !          8132:  * xmlXPathIsAncestor:
        !          8133:  * @ancestor:  the ancestor node
        !          8134:  * @node:  the current node
        !          8135:  *
        !          8136:  * Check that @ancestor is a @node's ancestor
        !          8137:  *
        !          8138:  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
        !          8139:  */
        !          8140: static int
        !          8141: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
        !          8142:     if ((ancestor == NULL) || (node == NULL)) return(0);
        !          8143:     /* nodes need to be in the same document */
        !          8144:     if (ancestor->doc != node->doc) return(0);
        !          8145:     /* avoid searching if ancestor or node is the root node */
        !          8146:     if (ancestor == (xmlNodePtr) node->doc) return(1);
        !          8147:     if (node == (xmlNodePtr) ancestor->doc) return(0);
        !          8148:     while (node->parent != NULL) {
        !          8149:         if (node->parent == ancestor)
        !          8150:             return(1);
        !          8151:        node = node->parent;
        !          8152:     }
        !          8153:     return(0);
        !          8154: }
        !          8155: 
        !          8156: /**
        !          8157:  * xmlXPathNextPreceding:
        !          8158:  * @ctxt:  the XPath Parser context
        !          8159:  * @cur:  the current node in the traversal
        !          8160:  *
        !          8161:  * Traversal function for the "preceding" direction
        !          8162:  * the preceding axis contains all nodes in the same document as the context
        !          8163:  * node that are before the context node in document order, excluding any
        !          8164:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
        !          8165:  * ordered in reverse document order
        !          8166:  *
        !          8167:  * Returns the next element following that axis
        !          8168:  */
        !          8169: xmlNodePtr
        !          8170: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
        !          8171: {
        !          8172:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8173:     if (cur == NULL) {
        !          8174:         cur = ctxt->context->node;
        !          8175:         if (cur->type == XML_NAMESPACE_DECL)
        !          8176:             return(NULL);
        !          8177:         if (cur->type == XML_ATTRIBUTE_NODE)
        !          8178:             return(cur->parent);
        !          8179:     }
        !          8180:     if (cur == NULL)
        !          8181:        return (NULL);
        !          8182:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
        !          8183:        cur = cur->prev;
        !          8184:     do {
        !          8185:         if (cur->prev != NULL) {
        !          8186:             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
        !          8187:             return (cur);
        !          8188:         }
        !          8189: 
        !          8190:         cur = cur->parent;
        !          8191:         if (cur == NULL)
        !          8192:             return (NULL);
        !          8193:         if (cur == ctxt->context->doc->children)
        !          8194:             return (NULL);
        !          8195:     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
        !          8196:     return (cur);
        !          8197: }
        !          8198: 
        !          8199: /**
        !          8200:  * xmlXPathNextPrecedingInternal:
        !          8201:  * @ctxt:  the XPath Parser context
        !          8202:  * @cur:  the current node in the traversal
        !          8203:  *
        !          8204:  * Traversal function for the "preceding" direction
        !          8205:  * the preceding axis contains all nodes in the same document as the context
        !          8206:  * node that are before the context node in document order, excluding any
        !          8207:  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
        !          8208:  * ordered in reverse document order
        !          8209:  * This is a faster implementation but internal only since it requires a
        !          8210:  * state kept in the parser context: ctxt->ancestor.
        !          8211:  *
        !          8212:  * Returns the next element following that axis
        !          8213:  */
        !          8214: static xmlNodePtr
        !          8215: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
        !          8216:                               xmlNodePtr cur)
        !          8217: {
        !          8218:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8219:     if (cur == NULL) {
        !          8220:         cur = ctxt->context->node;
        !          8221:         if (cur == NULL)
        !          8222:             return (NULL);
        !          8223:         if (cur->type == XML_NAMESPACE_DECL)
        !          8224:             return (NULL);
        !          8225:         ctxt->ancestor = cur->parent;
        !          8226:     }
        !          8227:     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
        !          8228:        cur = cur->prev;
        !          8229:     while (cur->prev == NULL) {
        !          8230:         cur = cur->parent;
        !          8231:         if (cur == NULL)
        !          8232:             return (NULL);
        !          8233:         if (cur == ctxt->context->doc->children)
        !          8234:             return (NULL);
        !          8235:         if (cur != ctxt->ancestor)
        !          8236:             return (cur);
        !          8237:         ctxt->ancestor = cur->parent;
        !          8238:     }
        !          8239:     cur = cur->prev;
        !          8240:     while (cur->last != NULL)
        !          8241:         cur = cur->last;
        !          8242:     return (cur);
        !          8243: }
        !          8244: 
        !          8245: /**
        !          8246:  * xmlXPathNextNamespace:
        !          8247:  * @ctxt:  the XPath Parser context
        !          8248:  * @cur:  the current attribute in the traversal
        !          8249:  *
        !          8250:  * Traversal function for the "namespace" direction
        !          8251:  * the namespace axis contains the namespace nodes of the context node;
        !          8252:  * the order of nodes on this axis is implementation-defined; the axis will
        !          8253:  * be empty unless the context node is an element
        !          8254:  *
        !          8255:  * We keep the XML namespace node at the end of the list.
        !          8256:  *
        !          8257:  * Returns the next element following that axis
        !          8258:  */
        !          8259: xmlNodePtr
        !          8260: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8261:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8262:     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
        !          8263:     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
        !          8264:         if (ctxt->context->tmpNsList != NULL)
        !          8265:            xmlFree(ctxt->context->tmpNsList);
        !          8266:        ctxt->context->tmpNsList =
        !          8267:            xmlGetNsList(ctxt->context->doc, ctxt->context->node);
        !          8268:        ctxt->context->tmpNsNr = 0;
        !          8269:        if (ctxt->context->tmpNsList != NULL) {
        !          8270:            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
        !          8271:                ctxt->context->tmpNsNr++;
        !          8272:            }
        !          8273:        }
        !          8274:        return((xmlNodePtr) xmlXPathXMLNamespace);
        !          8275:     }
        !          8276:     if (ctxt->context->tmpNsNr > 0) {
        !          8277:        return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
        !          8278:     } else {
        !          8279:        if (ctxt->context->tmpNsList != NULL)
        !          8280:            xmlFree(ctxt->context->tmpNsList);
        !          8281:        ctxt->context->tmpNsList = NULL;
        !          8282:        return(NULL);
        !          8283:     }
        !          8284: }
        !          8285: 
        !          8286: /**
        !          8287:  * xmlXPathNextAttribute:
        !          8288:  * @ctxt:  the XPath Parser context
        !          8289:  * @cur:  the current attribute in the traversal
        !          8290:  *
        !          8291:  * Traversal function for the "attribute" direction
        !          8292:  * TODO: support DTD inherited default attributes
        !          8293:  *
        !          8294:  * Returns the next element following that axis
        !          8295:  */
        !          8296: xmlNodePtr
        !          8297: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
        !          8298:     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
        !          8299:     if (ctxt->context->node == NULL)
        !          8300:        return(NULL);
        !          8301:     if (ctxt->context->node->type != XML_ELEMENT_NODE)
        !          8302:        return(NULL);
        !          8303:     if (cur == NULL) {
        !          8304:         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
        !          8305:            return(NULL);
        !          8306:         return((xmlNodePtr)ctxt->context->node->properties);
        !          8307:     }
        !          8308:     return((xmlNodePtr)cur->next);
        !          8309: }
        !          8310: 
        !          8311: /************************************************************************
        !          8312:  *                                                                     *
        !          8313:  *             NodeTest Functions                                      *
        !          8314:  *                                                                     *
        !          8315:  ************************************************************************/
        !          8316: 
        !          8317: #define IS_FUNCTION                    200
        !          8318: 
        !          8319: 
        !          8320: /************************************************************************
        !          8321:  *                                                                     *
        !          8322:  *             Implicit tree core function library                     *
        !          8323:  *                                                                     *
        !          8324:  ************************************************************************/
        !          8325: 
        !          8326: /**
        !          8327:  * xmlXPathRoot:
        !          8328:  * @ctxt:  the XPath Parser context
        !          8329:  *
        !          8330:  * Initialize the context to the root of the document
        !          8331:  */
        !          8332: void
        !          8333: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
        !          8334:     if ((ctxt == NULL) || (ctxt->context == NULL))
        !          8335:        return;
        !          8336:     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
        !          8337:     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          8338:        ctxt->context->node));
        !          8339: }
        !          8340: 
        !          8341: /************************************************************************
        !          8342:  *                                                                     *
        !          8343:  *             The explicit core function library                      *
        !          8344:  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib        *
        !          8345:  *                                                                     *
        !          8346:  ************************************************************************/
        !          8347: 
        !          8348: 
        !          8349: /**
        !          8350:  * xmlXPathLastFunction:
        !          8351:  * @ctxt:  the XPath Parser context
        !          8352:  * @nargs:  the number of arguments
        !          8353:  *
        !          8354:  * Implement the last() XPath function
        !          8355:  *    number last()
        !          8356:  * The last function returns the number of nodes in the context node list.
        !          8357:  */
        !          8358: void
        !          8359: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8360:     CHECK_ARITY(0);
        !          8361:     if (ctxt->context->contextSize >= 0) {
        !          8362:        valuePush(ctxt,
        !          8363:            xmlXPathCacheNewFloat(ctxt->context,
        !          8364:                (double) ctxt->context->contextSize));
        !          8365: #ifdef DEBUG_EXPR
        !          8366:        xmlGenericError(xmlGenericErrorContext,
        !          8367:                "last() : %d\n", ctxt->context->contextSize);
        !          8368: #endif
        !          8369:     } else {
        !          8370:        XP_ERROR(XPATH_INVALID_CTXT_SIZE);
        !          8371:     }
        !          8372: }
        !          8373: 
        !          8374: /**
        !          8375:  * xmlXPathPositionFunction:
        !          8376:  * @ctxt:  the XPath Parser context
        !          8377:  * @nargs:  the number of arguments
        !          8378:  *
        !          8379:  * Implement the position() XPath function
        !          8380:  *    number position()
        !          8381:  * The position function returns the position of the context node in the
        !          8382:  * context node list. The first position is 1, and so the last position
        !          8383:  * will be equal to last().
        !          8384:  */
        !          8385: void
        !          8386: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8387:     CHECK_ARITY(0);
        !          8388:     if (ctxt->context->proximityPosition >= 0) {
        !          8389:        valuePush(ctxt,
        !          8390:              xmlXPathCacheNewFloat(ctxt->context,
        !          8391:                (double) ctxt->context->proximityPosition));
        !          8392: #ifdef DEBUG_EXPR
        !          8393:        xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
        !          8394:                ctxt->context->proximityPosition);
        !          8395: #endif
        !          8396:     } else {
        !          8397:        XP_ERROR(XPATH_INVALID_CTXT_POSITION);
        !          8398:     }
        !          8399: }
        !          8400: 
        !          8401: /**
        !          8402:  * xmlXPathCountFunction:
        !          8403:  * @ctxt:  the XPath Parser context
        !          8404:  * @nargs:  the number of arguments
        !          8405:  *
        !          8406:  * Implement the count() XPath function
        !          8407:  *    number count(node-set)
        !          8408:  */
        !          8409: void
        !          8410: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8411:     xmlXPathObjectPtr cur;
        !          8412: 
        !          8413:     CHECK_ARITY(1);
        !          8414:     if ((ctxt->value == NULL) ||
        !          8415:        ((ctxt->value->type != XPATH_NODESET) &&
        !          8416:         (ctxt->value->type != XPATH_XSLT_TREE)))
        !          8417:        XP_ERROR(XPATH_INVALID_TYPE);
        !          8418:     cur = valuePop(ctxt);
        !          8419: 
        !          8420:     if ((cur == NULL) || (cur->nodesetval == NULL))
        !          8421:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
        !          8422:     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
        !          8423:        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
        !          8424:            (double) cur->nodesetval->nodeNr));
        !          8425:     } else {
        !          8426:        if ((cur->nodesetval->nodeNr != 1) ||
        !          8427:            (cur->nodesetval->nodeTab == NULL)) {
        !          8428:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
        !          8429:        } else {
        !          8430:            xmlNodePtr tmp;
        !          8431:            int i = 0;
        !          8432: 
        !          8433:            tmp = cur->nodesetval->nodeTab[0];
        !          8434:            if (tmp != NULL) {
        !          8435:                tmp = tmp->children;
        !          8436:                while (tmp != NULL) {
        !          8437:                    tmp = tmp->next;
        !          8438:                    i++;
        !          8439:                }
        !          8440:            }
        !          8441:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
        !          8442:        }
        !          8443:     }
        !          8444:     xmlXPathReleaseObject(ctxt->context, cur);
        !          8445: }
        !          8446: 
        !          8447: /**
        !          8448:  * xmlXPathGetElementsByIds:
        !          8449:  * @doc:  the document
        !          8450:  * @ids:  a whitespace separated list of IDs
        !          8451:  *
        !          8452:  * Selects elements by their unique ID.
        !          8453:  *
        !          8454:  * Returns a node-set of selected elements.
        !          8455:  */
        !          8456: static xmlNodeSetPtr
        !          8457: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
        !          8458:     xmlNodeSetPtr ret;
        !          8459:     const xmlChar *cur = ids;
        !          8460:     xmlChar *ID;
        !          8461:     xmlAttrPtr attr;
        !          8462:     xmlNodePtr elem = NULL;
        !          8463: 
        !          8464:     if (ids == NULL) return(NULL);
        !          8465: 
        !          8466:     ret = xmlXPathNodeSetCreate(NULL);
        !          8467:     if (ret == NULL)
        !          8468:         return(ret);
        !          8469: 
        !          8470:     while (IS_BLANK_CH(*cur)) cur++;
        !          8471:     while (*cur != 0) {
        !          8472:        while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
        !          8473:            cur++;
        !          8474: 
        !          8475:         ID = xmlStrndup(ids, cur - ids);
        !          8476:        if (ID != NULL) {
        !          8477:            /*
        !          8478:             * We used to check the fact that the value passed
        !          8479:             * was an NCName, but this generated much troubles for
        !          8480:             * me and Aleksey Sanin, people blatantly violated that
        !          8481:             * constaint, like Visa3D spec.
        !          8482:             * if (xmlValidateNCName(ID, 1) == 0)
        !          8483:             */
        !          8484:            attr = xmlGetID(doc, ID);
        !          8485:            if (attr != NULL) {
        !          8486:                if (attr->type == XML_ATTRIBUTE_NODE)
        !          8487:                    elem = attr->parent;
        !          8488:                else if (attr->type == XML_ELEMENT_NODE)
        !          8489:                    elem = (xmlNodePtr) attr;
        !          8490:                else
        !          8491:                    elem = NULL;
        !          8492:                if (elem != NULL)
        !          8493:                    xmlXPathNodeSetAdd(ret, elem);
        !          8494:            }
        !          8495:            xmlFree(ID);
        !          8496:        }
        !          8497: 
        !          8498:        while (IS_BLANK_CH(*cur)) cur++;
        !          8499:        ids = cur;
        !          8500:     }
        !          8501:     return(ret);
        !          8502: }
        !          8503: 
        !          8504: /**
        !          8505:  * xmlXPathIdFunction:
        !          8506:  * @ctxt:  the XPath Parser context
        !          8507:  * @nargs:  the number of arguments
        !          8508:  *
        !          8509:  * Implement the id() XPath function
        !          8510:  *    node-set id(object)
        !          8511:  * The id function selects elements by their unique ID
        !          8512:  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
        !          8513:  * then the result is the union of the result of applying id to the
        !          8514:  * string value of each of the nodes in the argument node-set. When the
        !          8515:  * argument to id is of any other type, the argument is converted to a
        !          8516:  * string as if by a call to the string function; the string is split
        !          8517:  * into a whitespace-separated list of tokens (whitespace is any sequence
        !          8518:  * of characters matching the production S); the result is a node-set
        !          8519:  * containing the elements in the same document as the context node that
        !          8520:  * have a unique ID equal to any of the tokens in the list.
        !          8521:  */
        !          8522: void
        !          8523: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8524:     xmlChar *tokens;
        !          8525:     xmlNodeSetPtr ret;
        !          8526:     xmlXPathObjectPtr obj;
        !          8527: 
        !          8528:     CHECK_ARITY(1);
        !          8529:     obj = valuePop(ctxt);
        !          8530:     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
        !          8531:     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
        !          8532:        xmlNodeSetPtr ns;
        !          8533:        int i;
        !          8534: 
        !          8535:        ret = xmlXPathNodeSetCreate(NULL);
        !          8536:         /*
        !          8537:          * FIXME -- in an out-of-memory condition this will behave badly.
        !          8538:          * The solution is not clear -- we already popped an item from
        !          8539:          * ctxt, so the object is in a corrupt state.
        !          8540:          */
        !          8541: 
        !          8542:        if (obj->nodesetval != NULL) {
        !          8543:            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
        !          8544:                tokens =
        !          8545:                    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
        !          8546:                ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
        !          8547:                ret = xmlXPathNodeSetMerge(ret, ns);
        !          8548:                xmlXPathFreeNodeSet(ns);
        !          8549:                if (tokens != NULL)
        !          8550:                    xmlFree(tokens);
        !          8551:            }
        !          8552:        }
        !          8553:        xmlXPathReleaseObject(ctxt->context, obj);
        !          8554:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
        !          8555:        return;
        !          8556:     }
        !          8557:     obj = xmlXPathCacheConvertString(ctxt->context, obj);
        !          8558:     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
        !          8559:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
        !          8560:     xmlXPathReleaseObject(ctxt->context, obj);
        !          8561:     return;
        !          8562: }
        !          8563: 
        !          8564: /**
        !          8565:  * xmlXPathLocalNameFunction:
        !          8566:  * @ctxt:  the XPath Parser context
        !          8567:  * @nargs:  the number of arguments
        !          8568:  *
        !          8569:  * Implement the local-name() XPath function
        !          8570:  *    string local-name(node-set?)
        !          8571:  * The local-name function returns a string containing the local part
        !          8572:  * of the name of the node in the argument node-set that is first in
        !          8573:  * document order. If the node-set is empty or the first node has no
        !          8574:  * name, an empty string is returned. If the argument is omitted it
        !          8575:  * defaults to the context node.
        !          8576:  */
        !          8577: void
        !          8578: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8579:     xmlXPathObjectPtr cur;
        !          8580: 
        !          8581:     if (ctxt == NULL) return;
        !          8582: 
        !          8583:     if (nargs == 0) {
        !          8584:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          8585:            ctxt->context->node));
        !          8586:        nargs = 1;
        !          8587:     }
        !          8588: 
        !          8589:     CHECK_ARITY(1);
        !          8590:     if ((ctxt->value == NULL) ||
        !          8591:        ((ctxt->value->type != XPATH_NODESET) &&
        !          8592:         (ctxt->value->type != XPATH_XSLT_TREE)))
        !          8593:        XP_ERROR(XPATH_INVALID_TYPE);
        !          8594:     cur = valuePop(ctxt);
        !          8595: 
        !          8596:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
        !          8597:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8598:     } else {
        !          8599:        int i = 0; /* Should be first in document order !!!!! */
        !          8600:        switch (cur->nodesetval->nodeTab[i]->type) {
        !          8601:        case XML_ELEMENT_NODE:
        !          8602:        case XML_ATTRIBUTE_NODE:
        !          8603:        case XML_PI_NODE:
        !          8604:            if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
        !          8605:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8606:            else
        !          8607:                valuePush(ctxt,
        !          8608:                      xmlXPathCacheNewString(ctxt->context,
        !          8609:                        cur->nodesetval->nodeTab[i]->name));
        !          8610:            break;
        !          8611:        case XML_NAMESPACE_DECL:
        !          8612:            valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          8613:                        ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
        !          8614:            break;
        !          8615:        default:
        !          8616:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8617:        }
        !          8618:     }
        !          8619:     xmlXPathReleaseObject(ctxt->context, cur);
        !          8620: }
        !          8621: 
        !          8622: /**
        !          8623:  * xmlXPathNamespaceURIFunction:
        !          8624:  * @ctxt:  the XPath Parser context
        !          8625:  * @nargs:  the number of arguments
        !          8626:  *
        !          8627:  * Implement the namespace-uri() XPath function
        !          8628:  *    string namespace-uri(node-set?)
        !          8629:  * The namespace-uri function returns a string containing the
        !          8630:  * namespace URI of the expanded name of the node in the argument
        !          8631:  * node-set that is first in document order. If the node-set is empty,
        !          8632:  * the first node has no name, or the expanded name has no namespace
        !          8633:  * URI, an empty string is returned. If the argument is omitted it
        !          8634:  * defaults to the context node.
        !          8635:  */
        !          8636: void
        !          8637: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8638:     xmlXPathObjectPtr cur;
        !          8639: 
        !          8640:     if (ctxt == NULL) return;
        !          8641: 
        !          8642:     if (nargs == 0) {
        !          8643:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          8644:            ctxt->context->node));
        !          8645:        nargs = 1;
        !          8646:     }
        !          8647:     CHECK_ARITY(1);
        !          8648:     if ((ctxt->value == NULL) ||
        !          8649:        ((ctxt->value->type != XPATH_NODESET) &&
        !          8650:         (ctxt->value->type != XPATH_XSLT_TREE)))
        !          8651:        XP_ERROR(XPATH_INVALID_TYPE);
        !          8652:     cur = valuePop(ctxt);
        !          8653: 
        !          8654:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
        !          8655:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8656:     } else {
        !          8657:        int i = 0; /* Should be first in document order !!!!! */
        !          8658:        switch (cur->nodesetval->nodeTab[i]->type) {
        !          8659:        case XML_ELEMENT_NODE:
        !          8660:        case XML_ATTRIBUTE_NODE:
        !          8661:            if (cur->nodesetval->nodeTab[i]->ns == NULL)
        !          8662:                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8663:            else
        !          8664:                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          8665:                          cur->nodesetval->nodeTab[i]->ns->href));
        !          8666:            break;
        !          8667:        default:
        !          8668:            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8669:        }
        !          8670:     }
        !          8671:     xmlXPathReleaseObject(ctxt->context, cur);
        !          8672: }
        !          8673: 
        !          8674: /**
        !          8675:  * xmlXPathNameFunction:
        !          8676:  * @ctxt:  the XPath Parser context
        !          8677:  * @nargs:  the number of arguments
        !          8678:  *
        !          8679:  * Implement the name() XPath function
        !          8680:  *    string name(node-set?)
        !          8681:  * The name function returns a string containing a QName representing
        !          8682:  * the name of the node in the argument node-set that is first in document
        !          8683:  * order. The QName must represent the name with respect to the namespace
        !          8684:  * declarations in effect on the node whose name is being represented.
        !          8685:  * Typically, this will be the form in which the name occurred in the XML
        !          8686:  * source. This need not be the case if there are namespace declarations
        !          8687:  * in effect on the node that associate multiple prefixes with the same
        !          8688:  * namespace. However, an implementation may include information about
        !          8689:  * the original prefix in its representation of nodes; in this case, an
        !          8690:  * implementation can ensure that the returned string is always the same
        !          8691:  * as the QName used in the XML source. If the argument it omitted it
        !          8692:  * defaults to the context node.
        !          8693:  * Libxml keep the original prefix so the "real qualified name" used is
        !          8694:  * returned.
        !          8695:  */
        !          8696: static void
        !          8697: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
        !          8698: {
        !          8699:     xmlXPathObjectPtr cur;
        !          8700: 
        !          8701:     if (nargs == 0) {
        !          8702:        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          8703:            ctxt->context->node));
        !          8704:         nargs = 1;
        !          8705:     }
        !          8706: 
        !          8707:     CHECK_ARITY(1);
        !          8708:     if ((ctxt->value == NULL) ||
        !          8709:         ((ctxt->value->type != XPATH_NODESET) &&
        !          8710:          (ctxt->value->type != XPATH_XSLT_TREE)))
        !          8711:         XP_ERROR(XPATH_INVALID_TYPE);
        !          8712:     cur = valuePop(ctxt);
        !          8713: 
        !          8714:     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
        !          8715:         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          8716:     } else {
        !          8717:         int i = 0;              /* Should be first in document order !!!!! */
        !          8718: 
        !          8719:         switch (cur->nodesetval->nodeTab[i]->type) {
        !          8720:             case XML_ELEMENT_NODE:
        !          8721:             case XML_ATTRIBUTE_NODE:
        !          8722:                if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
        !          8723:                    valuePush(ctxt,
        !          8724:                        xmlXPathCacheNewCString(ctxt->context, ""));
        !          8725:                else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
        !          8726:                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
        !          8727:                    valuePush(ctxt,
        !          8728:                        xmlXPathCacheNewString(ctxt->context,
        !          8729:                            cur->nodesetval->nodeTab[i]->name));
        !          8730:                } else {
        !          8731:                    xmlChar *fullname;
        !          8732: 
        !          8733:                    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
        !          8734:                                     cur->nodesetval->nodeTab[i]->ns->prefix,
        !          8735:                                     NULL, 0);
        !          8736:                    if (fullname == cur->nodesetval->nodeTab[i]->name)
        !          8737:                        fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
        !          8738:                    if (fullname == NULL) {
        !          8739:                        XP_ERROR(XPATH_MEMORY_ERROR);
        !          8740:                    }
        !          8741:                    valuePush(ctxt, xmlXPathCacheWrapString(
        !          8742:                        ctxt->context, fullname));
        !          8743:                 }
        !          8744:                 break;
        !          8745:             default:
        !          8746:                valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          8747:                    cur->nodesetval->nodeTab[i]));
        !          8748:                 xmlXPathLocalNameFunction(ctxt, 1);
        !          8749:         }
        !          8750:     }
        !          8751:     xmlXPathReleaseObject(ctxt->context, cur);
        !          8752: }
        !          8753: 
        !          8754: 
        !          8755: /**
        !          8756:  * xmlXPathStringFunction:
        !          8757:  * @ctxt:  the XPath Parser context
        !          8758:  * @nargs:  the number of arguments
        !          8759:  *
        !          8760:  * Implement the string() XPath function
        !          8761:  *    string string(object?)
        !          8762:  * The string function converts an object to a string as follows:
        !          8763:  *    - A node-set is converted to a string by returning the value of
        !          8764:  *      the node in the node-set that is first in document order.
        !          8765:  *      If the node-set is empty, an empty string is returned.
        !          8766:  *    - A number is converted to a string as follows
        !          8767:  *      + NaN is converted to the string NaN
        !          8768:  *      + positive zero is converted to the string 0
        !          8769:  *      + negative zero is converted to the string 0
        !          8770:  *      + positive infinity is converted to the string Infinity
        !          8771:  *      + negative infinity is converted to the string -Infinity
        !          8772:  *      + if the number is an integer, the number is represented in
        !          8773:  *        decimal form as a Number with no decimal point and no leading
        !          8774:  *        zeros, preceded by a minus sign (-) if the number is negative
        !          8775:  *      + otherwise, the number is represented in decimal form as a
        !          8776:  *        Number including a decimal point with at least one digit
        !          8777:  *        before the decimal point and at least one digit after the
        !          8778:  *        decimal point, preceded by a minus sign (-) if the number
        !          8779:  *        is negative; there must be no leading zeros before the decimal
        !          8780:  *        point apart possibly from the one required digit immediately
        !          8781:  *        before the decimal point; beyond the one required digit
        !          8782:  *        after the decimal point there must be as many, but only as
        !          8783:  *        many, more digits as are needed to uniquely distinguish the
        !          8784:  *        number from all other IEEE 754 numeric values.
        !          8785:  *    - The boolean false value is converted to the string false.
        !          8786:  *      The boolean true value is converted to the string true.
        !          8787:  *
        !          8788:  * If the argument is omitted, it defaults to a node-set with the
        !          8789:  * context node as its only member.
        !          8790:  */
        !          8791: void
        !          8792: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8793:     xmlXPathObjectPtr cur;
        !          8794: 
        !          8795:     if (ctxt == NULL) return;
        !          8796:     if (nargs == 0) {
        !          8797:     valuePush(ctxt,
        !          8798:        xmlXPathCacheWrapString(ctxt->context,
        !          8799:            xmlXPathCastNodeToString(ctxt->context->node)));
        !          8800:        return;
        !          8801:     }
        !          8802: 
        !          8803:     CHECK_ARITY(1);
        !          8804:     cur = valuePop(ctxt);
        !          8805:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
        !          8806:     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
        !          8807: }
        !          8808: 
        !          8809: /**
        !          8810:  * xmlXPathStringLengthFunction:
        !          8811:  * @ctxt:  the XPath Parser context
        !          8812:  * @nargs:  the number of arguments
        !          8813:  *
        !          8814:  * Implement the string-length() XPath function
        !          8815:  *    number string-length(string?)
        !          8816:  * The string-length returns the number of characters in the string
        !          8817:  * (see [3.6 Strings]). If the argument is omitted, it defaults to
        !          8818:  * the context node converted to a string, in other words the value
        !          8819:  * of the context node.
        !          8820:  */
        !          8821: void
        !          8822: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8823:     xmlXPathObjectPtr cur;
        !          8824: 
        !          8825:     if (nargs == 0) {
        !          8826:         if ((ctxt == NULL) || (ctxt->context == NULL))
        !          8827:            return;
        !          8828:        if (ctxt->context->node == NULL) {
        !          8829:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
        !          8830:        } else {
        !          8831:            xmlChar *content;
        !          8832: 
        !          8833:            content = xmlXPathCastNodeToString(ctxt->context->node);
        !          8834:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
        !          8835:                xmlUTF8Strlen(content)));
        !          8836:            xmlFree(content);
        !          8837:        }
        !          8838:        return;
        !          8839:     }
        !          8840:     CHECK_ARITY(1);
        !          8841:     CAST_TO_STRING;
        !          8842:     CHECK_TYPE(XPATH_STRING);
        !          8843:     cur = valuePop(ctxt);
        !          8844:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
        !          8845:        xmlUTF8Strlen(cur->stringval)));
        !          8846:     xmlXPathReleaseObject(ctxt->context, cur);
        !          8847: }
        !          8848: 
        !          8849: /**
        !          8850:  * xmlXPathConcatFunction:
        !          8851:  * @ctxt:  the XPath Parser context
        !          8852:  * @nargs:  the number of arguments
        !          8853:  *
        !          8854:  * Implement the concat() XPath function
        !          8855:  *    string concat(string, string, string*)
        !          8856:  * The concat function returns the concatenation of its arguments.
        !          8857:  */
        !          8858: void
        !          8859: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8860:     xmlXPathObjectPtr cur, newobj;
        !          8861:     xmlChar *tmp;
        !          8862: 
        !          8863:     if (ctxt == NULL) return;
        !          8864:     if (nargs < 2) {
        !          8865:        CHECK_ARITY(2);
        !          8866:     }
        !          8867: 
        !          8868:     CAST_TO_STRING;
        !          8869:     cur = valuePop(ctxt);
        !          8870:     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
        !          8871:        xmlXPathReleaseObject(ctxt->context, cur);
        !          8872:        return;
        !          8873:     }
        !          8874:     nargs--;
        !          8875: 
        !          8876:     while (nargs > 0) {
        !          8877:        CAST_TO_STRING;
        !          8878:        newobj = valuePop(ctxt);
        !          8879:        if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
        !          8880:            xmlXPathReleaseObject(ctxt->context, newobj);
        !          8881:            xmlXPathReleaseObject(ctxt->context, cur);
        !          8882:            XP_ERROR(XPATH_INVALID_TYPE);
        !          8883:        }
        !          8884:        tmp = xmlStrcat(newobj->stringval, cur->stringval);
        !          8885:        newobj->stringval = cur->stringval;
        !          8886:        cur->stringval = tmp;
        !          8887:        xmlXPathReleaseObject(ctxt->context, newobj);
        !          8888:        nargs--;
        !          8889:     }
        !          8890:     valuePush(ctxt, cur);
        !          8891: }
        !          8892: 
        !          8893: /**
        !          8894:  * xmlXPathContainsFunction:
        !          8895:  * @ctxt:  the XPath Parser context
        !          8896:  * @nargs:  the number of arguments
        !          8897:  *
        !          8898:  * Implement the contains() XPath function
        !          8899:  *    boolean contains(string, string)
        !          8900:  * The contains function returns true if the first argument string
        !          8901:  * contains the second argument string, and otherwise returns false.
        !          8902:  */
        !          8903: void
        !          8904: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8905:     xmlXPathObjectPtr hay, needle;
        !          8906: 
        !          8907:     CHECK_ARITY(2);
        !          8908:     CAST_TO_STRING;
        !          8909:     CHECK_TYPE(XPATH_STRING);
        !          8910:     needle = valuePop(ctxt);
        !          8911:     CAST_TO_STRING;
        !          8912:     hay = valuePop(ctxt);
        !          8913: 
        !          8914:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
        !          8915:        xmlXPathReleaseObject(ctxt->context, hay);
        !          8916:        xmlXPathReleaseObject(ctxt->context, needle);
        !          8917:        XP_ERROR(XPATH_INVALID_TYPE);
        !          8918:     }
        !          8919:     if (xmlStrstr(hay->stringval, needle->stringval))
        !          8920:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
        !          8921:     else
        !          8922:        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
        !          8923:     xmlXPathReleaseObject(ctxt->context, hay);
        !          8924:     xmlXPathReleaseObject(ctxt->context, needle);
        !          8925: }
        !          8926: 
        !          8927: /**
        !          8928:  * xmlXPathStartsWithFunction:
        !          8929:  * @ctxt:  the XPath Parser context
        !          8930:  * @nargs:  the number of arguments
        !          8931:  *
        !          8932:  * Implement the starts-with() XPath function
        !          8933:  *    boolean starts-with(string, string)
        !          8934:  * The starts-with function returns true if the first argument string
        !          8935:  * starts with the second argument string, and otherwise returns false.
        !          8936:  */
        !          8937: void
        !          8938: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8939:     xmlXPathObjectPtr hay, needle;
        !          8940:     int n;
        !          8941: 
        !          8942:     CHECK_ARITY(2);
        !          8943:     CAST_TO_STRING;
        !          8944:     CHECK_TYPE(XPATH_STRING);
        !          8945:     needle = valuePop(ctxt);
        !          8946:     CAST_TO_STRING;
        !          8947:     hay = valuePop(ctxt);
        !          8948: 
        !          8949:     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
        !          8950:        xmlXPathReleaseObject(ctxt->context, hay);
        !          8951:        xmlXPathReleaseObject(ctxt->context, needle);
        !          8952:        XP_ERROR(XPATH_INVALID_TYPE);
        !          8953:     }
        !          8954:     n = xmlStrlen(needle->stringval);
        !          8955:     if (xmlStrncmp(hay->stringval, needle->stringval, n))
        !          8956:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
        !          8957:     else
        !          8958:         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
        !          8959:     xmlXPathReleaseObject(ctxt->context, hay);
        !          8960:     xmlXPathReleaseObject(ctxt->context, needle);
        !          8961: }
        !          8962: 
        !          8963: /**
        !          8964:  * xmlXPathSubstringFunction:
        !          8965:  * @ctxt:  the XPath Parser context
        !          8966:  * @nargs:  the number of arguments
        !          8967:  *
        !          8968:  * Implement the substring() XPath function
        !          8969:  *    string substring(string, number, number?)
        !          8970:  * The substring function returns the substring of the first argument
        !          8971:  * starting at the position specified in the second argument with
        !          8972:  * length specified in the third argument. For example,
        !          8973:  * substring("12345",2,3) returns "234". If the third argument is not
        !          8974:  * specified, it returns the substring starting at the position specified
        !          8975:  * in the second argument and continuing to the end of the string. For
        !          8976:  * example, substring("12345",2) returns "2345".  More precisely, each
        !          8977:  * character in the string (see [3.6 Strings]) is considered to have a
        !          8978:  * numeric position: the position of the first character is 1, the position
        !          8979:  * of the second character is 2 and so on. The returned substring contains
        !          8980:  * those characters for which the position of the character is greater than
        !          8981:  * or equal to the second argument and, if the third argument is specified,
        !          8982:  * less than the sum of the second and third arguments; the comparisons
        !          8983:  * and addition used for the above follow the standard IEEE 754 rules. Thus:
        !          8984:  *  - substring("12345", 1.5, 2.6) returns "234"
        !          8985:  *  - substring("12345", 0, 3) returns "12"
        !          8986:  *  - substring("12345", 0 div 0, 3) returns ""
        !          8987:  *  - substring("12345", 1, 0 div 0) returns ""
        !          8988:  *  - substring("12345", -42, 1 div 0) returns "12345"
        !          8989:  *  - substring("12345", -1 div 0, 1 div 0) returns ""
        !          8990:  */
        !          8991: void
        !          8992: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          8993:     xmlXPathObjectPtr str, start, len;
        !          8994:     double le=0, in;
        !          8995:     int i, l, m;
        !          8996:     xmlChar *ret;
        !          8997: 
        !          8998:     if (nargs < 2) {
        !          8999:        CHECK_ARITY(2);
        !          9000:     }
        !          9001:     if (nargs > 3) {
        !          9002:        CHECK_ARITY(3);
        !          9003:     }
        !          9004:     /*
        !          9005:      * take care of possible last (position) argument
        !          9006:     */
        !          9007:     if (nargs == 3) {
        !          9008:        CAST_TO_NUMBER;
        !          9009:        CHECK_TYPE(XPATH_NUMBER);
        !          9010:        len = valuePop(ctxt);
        !          9011:        le = len->floatval;
        !          9012:        xmlXPathReleaseObject(ctxt->context, len);
        !          9013:     }
        !          9014: 
        !          9015:     CAST_TO_NUMBER;
        !          9016:     CHECK_TYPE(XPATH_NUMBER);
        !          9017:     start = valuePop(ctxt);
        !          9018:     in = start->floatval;
        !          9019:     xmlXPathReleaseObject(ctxt->context, start);
        !          9020:     CAST_TO_STRING;
        !          9021:     CHECK_TYPE(XPATH_STRING);
        !          9022:     str = valuePop(ctxt);
        !          9023:     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
        !          9024: 
        !          9025:     /*
        !          9026:      * If last pos not present, calculate last position
        !          9027:     */
        !          9028:     if (nargs != 3) {
        !          9029:        le = (double)m;
        !          9030:        if (in < 1.0)
        !          9031:            in = 1.0;
        !          9032:     }
        !          9033: 
        !          9034:     /* Need to check for the special cases where either
        !          9035:      * the index is NaN, the length is NaN, or both
        !          9036:      * arguments are infinity (relying on Inf + -Inf = NaN)
        !          9037:      */
        !          9038:     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
        !          9039:         /*
        !          9040:          * To meet the requirements of the spec, the arguments
        !          9041:         * must be converted to integer format before
        !          9042:         * initial index calculations are done
        !          9043:          *
        !          9044:          * First we go to integer form, rounding up
        !          9045:         * and checking for special cases
        !          9046:          */
        !          9047:         i = (int) in;
        !          9048:         if (((double)i)+0.5 <= in) i++;
        !          9049: 
        !          9050:        if (xmlXPathIsInf(le) == 1) {
        !          9051:            l = m;
        !          9052:            if (i < 1)
        !          9053:                i = 1;
        !          9054:        }
        !          9055:        else if (xmlXPathIsInf(le) == -1 || le < 0.0)
        !          9056:            l = 0;
        !          9057:        else {
        !          9058:            l = (int) le;
        !          9059:            if (((double)l)+0.5 <= le) l++;
        !          9060:        }
        !          9061: 
        !          9062:        /* Now we normalize inidices */
        !          9063:         i -= 1;
        !          9064:         l += i;
        !          9065:         if (i < 0)
        !          9066:             i = 0;
        !          9067:         if (l > m)
        !          9068:             l = m;
        !          9069: 
        !          9070:         /* number of chars to copy */
        !          9071:         l -= i;
        !          9072: 
        !          9073:         ret = xmlUTF8Strsub(str->stringval, i, l);
        !          9074:     }
        !          9075:     else {
        !          9076:         ret = NULL;
        !          9077:     }
        !          9078:     if (ret == NULL)
        !          9079:        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
        !          9080:     else {
        !          9081:        valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
        !          9082:        xmlFree(ret);
        !          9083:     }
        !          9084:     xmlXPathReleaseObject(ctxt->context, str);
        !          9085: }
        !          9086: 
        !          9087: /**
        !          9088:  * xmlXPathSubstringBeforeFunction:
        !          9089:  * @ctxt:  the XPath Parser context
        !          9090:  * @nargs:  the number of arguments
        !          9091:  *
        !          9092:  * Implement the substring-before() XPath function
        !          9093:  *    string substring-before(string, string)
        !          9094:  * The substring-before function returns the substring of the first
        !          9095:  * argument string that precedes the first occurrence of the second
        !          9096:  * argument string in the first argument string, or the empty string
        !          9097:  * if the first argument string does not contain the second argument
        !          9098:  * string. For example, substring-before("1999/04/01","/") returns 1999.
        !          9099:  */
        !          9100: void
        !          9101: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9102:   xmlXPathObjectPtr str;
        !          9103:   xmlXPathObjectPtr find;
        !          9104:   xmlBufferPtr target;
        !          9105:   const xmlChar *point;
        !          9106:   int offset;
        !          9107: 
        !          9108:   CHECK_ARITY(2);
        !          9109:   CAST_TO_STRING;
        !          9110:   find = valuePop(ctxt);
        !          9111:   CAST_TO_STRING;
        !          9112:   str = valuePop(ctxt);
        !          9113: 
        !          9114:   target = xmlBufferCreate();
        !          9115:   if (target) {
        !          9116:     point = xmlStrstr(str->stringval, find->stringval);
        !          9117:     if (point) {
        !          9118:       offset = (int)(point - str->stringval);
        !          9119:       xmlBufferAdd(target, str->stringval, offset);
        !          9120:     }
        !          9121:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          9122:        xmlBufferContent(target)));
        !          9123:     xmlBufferFree(target);
        !          9124:   }
        !          9125:   xmlXPathReleaseObject(ctxt->context, str);
        !          9126:   xmlXPathReleaseObject(ctxt->context, find);
        !          9127: }
        !          9128: 
        !          9129: /**
        !          9130:  * xmlXPathSubstringAfterFunction:
        !          9131:  * @ctxt:  the XPath Parser context
        !          9132:  * @nargs:  the number of arguments
        !          9133:  *
        !          9134:  * Implement the substring-after() XPath function
        !          9135:  *    string substring-after(string, string)
        !          9136:  * The substring-after function returns the substring of the first
        !          9137:  * argument string that follows the first occurrence of the second
        !          9138:  * argument string in the first argument string, or the empty stringi
        !          9139:  * if the first argument string does not contain the second argument
        !          9140:  * string. For example, substring-after("1999/04/01","/") returns 04/01,
        !          9141:  * and substring-after("1999/04/01","19") returns 99/04/01.
        !          9142:  */
        !          9143: void
        !          9144: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9145:   xmlXPathObjectPtr str;
        !          9146:   xmlXPathObjectPtr find;
        !          9147:   xmlBufferPtr target;
        !          9148:   const xmlChar *point;
        !          9149:   int offset;
        !          9150: 
        !          9151:   CHECK_ARITY(2);
        !          9152:   CAST_TO_STRING;
        !          9153:   find = valuePop(ctxt);
        !          9154:   CAST_TO_STRING;
        !          9155:   str = valuePop(ctxt);
        !          9156: 
        !          9157:   target = xmlBufferCreate();
        !          9158:   if (target) {
        !          9159:     point = xmlStrstr(str->stringval, find->stringval);
        !          9160:     if (point) {
        !          9161:       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
        !          9162:       xmlBufferAdd(target, &str->stringval[offset],
        !          9163:                   xmlStrlen(str->stringval) - offset);
        !          9164:     }
        !          9165:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          9166:        xmlBufferContent(target)));
        !          9167:     xmlBufferFree(target);
        !          9168:   }
        !          9169:   xmlXPathReleaseObject(ctxt->context, str);
        !          9170:   xmlXPathReleaseObject(ctxt->context, find);
        !          9171: }
        !          9172: 
        !          9173: /**
        !          9174:  * xmlXPathNormalizeFunction:
        !          9175:  * @ctxt:  the XPath Parser context
        !          9176:  * @nargs:  the number of arguments
        !          9177:  *
        !          9178:  * Implement the normalize-space() XPath function
        !          9179:  *    string normalize-space(string?)
        !          9180:  * The normalize-space function returns the argument string with white
        !          9181:  * space normalized by stripping leading and trailing whitespace
        !          9182:  * and replacing sequences of whitespace characters by a single
        !          9183:  * space. Whitespace characters are the same allowed by the S production
        !          9184:  * in XML. If the argument is omitted, it defaults to the context
        !          9185:  * node converted to a string, in other words the value of the context node.
        !          9186:  */
        !          9187: void
        !          9188: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9189:   xmlXPathObjectPtr obj = NULL;
        !          9190:   xmlChar *source = NULL;
        !          9191:   xmlBufferPtr target;
        !          9192:   xmlChar blank;
        !          9193: 
        !          9194:   if (ctxt == NULL) return;
        !          9195:   if (nargs == 0) {
        !          9196:     /* Use current context node */
        !          9197:       valuePush(ctxt,
        !          9198:          xmlXPathCacheWrapString(ctxt->context,
        !          9199:            xmlXPathCastNodeToString(ctxt->context->node)));
        !          9200:     nargs = 1;
        !          9201:   }
        !          9202: 
        !          9203:   CHECK_ARITY(1);
        !          9204:   CAST_TO_STRING;
        !          9205:   CHECK_TYPE(XPATH_STRING);
        !          9206:   obj = valuePop(ctxt);
        !          9207:   source = obj->stringval;
        !          9208: 
        !          9209:   target = xmlBufferCreate();
        !          9210:   if (target && source) {
        !          9211: 
        !          9212:     /* Skip leading whitespaces */
        !          9213:     while (IS_BLANK_CH(*source))
        !          9214:       source++;
        !          9215: 
        !          9216:     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
        !          9217:     blank = 0;
        !          9218:     while (*source) {
        !          9219:       if (IS_BLANK_CH(*source)) {
        !          9220:        blank = 0x20;
        !          9221:       } else {
        !          9222:        if (blank) {
        !          9223:          xmlBufferAdd(target, &blank, 1);
        !          9224:          blank = 0;
        !          9225:        }
        !          9226:        xmlBufferAdd(target, source, 1);
        !          9227:       }
        !          9228:       source++;
        !          9229:     }
        !          9230:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          9231:        xmlBufferContent(target)));
        !          9232:     xmlBufferFree(target);
        !          9233:   }
        !          9234:   xmlXPathReleaseObject(ctxt->context, obj);
        !          9235: }
        !          9236: 
        !          9237: /**
        !          9238:  * xmlXPathTranslateFunction:
        !          9239:  * @ctxt:  the XPath Parser context
        !          9240:  * @nargs:  the number of arguments
        !          9241:  *
        !          9242:  * Implement the translate() XPath function
        !          9243:  *    string translate(string, string, string)
        !          9244:  * The translate function returns the first argument string with
        !          9245:  * occurrences of characters in the second argument string replaced
        !          9246:  * by the character at the corresponding position in the third argument
        !          9247:  * string. For example, translate("bar","abc","ABC") returns the string
        !          9248:  * BAr. If there is a character in the second argument string with no
        !          9249:  * character at a corresponding position in the third argument string
        !          9250:  * (because the second argument string is longer than the third argument
        !          9251:  * string), then occurrences of that character in the first argument
        !          9252:  * string are removed. For example, translate("--aaa--","abc-","ABC")
        !          9253:  * returns "AAA". If a character occurs more than once in second
        !          9254:  * argument string, then the first occurrence determines the replacement
        !          9255:  * character. If the third argument string is longer than the second
        !          9256:  * argument string, then excess characters are ignored.
        !          9257:  */
        !          9258: void
        !          9259: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9260:     xmlXPathObjectPtr str;
        !          9261:     xmlXPathObjectPtr from;
        !          9262:     xmlXPathObjectPtr to;
        !          9263:     xmlBufferPtr target;
        !          9264:     int offset, max;
        !          9265:     xmlChar ch;
        !          9266:     const xmlChar *point;
        !          9267:     xmlChar *cptr;
        !          9268: 
        !          9269:     CHECK_ARITY(3);
        !          9270: 
        !          9271:     CAST_TO_STRING;
        !          9272:     to = valuePop(ctxt);
        !          9273:     CAST_TO_STRING;
        !          9274:     from = valuePop(ctxt);
        !          9275:     CAST_TO_STRING;
        !          9276:     str = valuePop(ctxt);
        !          9277: 
        !          9278:     target = xmlBufferCreate();
        !          9279:     if (target) {
        !          9280:        max = xmlUTF8Strlen(to->stringval);
        !          9281:        for (cptr = str->stringval; (ch=*cptr); ) {
        !          9282:            offset = xmlUTF8Strloc(from->stringval, cptr);
        !          9283:            if (offset >= 0) {
        !          9284:                if (offset < max) {
        !          9285:                    point = xmlUTF8Strpos(to->stringval, offset);
        !          9286:                    if (point)
        !          9287:                        xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
        !          9288:                }
        !          9289:            } else
        !          9290:                xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
        !          9291: 
        !          9292:            /* Step to next character in input */
        !          9293:            cptr++;
        !          9294:            if ( ch & 0x80 ) {
        !          9295:                /* if not simple ascii, verify proper format */
        !          9296:                if ( (ch & 0xc0) != 0xc0 ) {
        !          9297:                    xmlGenericError(xmlGenericErrorContext,
        !          9298:                        "xmlXPathTranslateFunction: Invalid UTF8 string\n");
        !          9299:                    break;
        !          9300:                }
        !          9301:                /* then skip over remaining bytes for this char */
        !          9302:                while ( (ch <<= 1) & 0x80 )
        !          9303:                    if ( (*cptr++ & 0xc0) != 0x80 ) {
        !          9304:                        xmlGenericError(xmlGenericErrorContext,
        !          9305:                            "xmlXPathTranslateFunction: Invalid UTF8 string\n");
        !          9306:                        break;
        !          9307:                    }
        !          9308:                if (ch & 0x80) /* must have had error encountered */
        !          9309:                    break;
        !          9310:            }
        !          9311:        }
        !          9312:     }
        !          9313:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          9314:        xmlBufferContent(target)));
        !          9315:     xmlBufferFree(target);
        !          9316:     xmlXPathReleaseObject(ctxt->context, str);
        !          9317:     xmlXPathReleaseObject(ctxt->context, from);
        !          9318:     xmlXPathReleaseObject(ctxt->context, to);
        !          9319: }
        !          9320: 
        !          9321: /**
        !          9322:  * xmlXPathBooleanFunction:
        !          9323:  * @ctxt:  the XPath Parser context
        !          9324:  * @nargs:  the number of arguments
        !          9325:  *
        !          9326:  * Implement the boolean() XPath function
        !          9327:  *    boolean boolean(object)
        !          9328:  * The boolean function converts its argument to a boolean as follows:
        !          9329:  *    - a number is true if and only if it is neither positive or
        !          9330:  *      negative zero nor NaN
        !          9331:  *    - a node-set is true if and only if it is non-empty
        !          9332:  *    - a string is true if and only if its length is non-zero
        !          9333:  */
        !          9334: void
        !          9335: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9336:     xmlXPathObjectPtr cur;
        !          9337: 
        !          9338:     CHECK_ARITY(1);
        !          9339:     cur = valuePop(ctxt);
        !          9340:     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
        !          9341:     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
        !          9342:     valuePush(ctxt, cur);
        !          9343: }
        !          9344: 
        !          9345: /**
        !          9346:  * xmlXPathNotFunction:
        !          9347:  * @ctxt:  the XPath Parser context
        !          9348:  * @nargs:  the number of arguments
        !          9349:  *
        !          9350:  * Implement the not() XPath function
        !          9351:  *    boolean not(boolean)
        !          9352:  * The not function returns true if its argument is false,
        !          9353:  * and false otherwise.
        !          9354:  */
        !          9355: void
        !          9356: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9357:     CHECK_ARITY(1);
        !          9358:     CAST_TO_BOOLEAN;
        !          9359:     CHECK_TYPE(XPATH_BOOLEAN);
        !          9360:     ctxt->value->boolval = ! ctxt->value->boolval;
        !          9361: }
        !          9362: 
        !          9363: /**
        !          9364:  * xmlXPathTrueFunction:
        !          9365:  * @ctxt:  the XPath Parser context
        !          9366:  * @nargs:  the number of arguments
        !          9367:  *
        !          9368:  * Implement the true() XPath function
        !          9369:  *    boolean true()
        !          9370:  */
        !          9371: void
        !          9372: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9373:     CHECK_ARITY(0);
        !          9374:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
        !          9375: }
        !          9376: 
        !          9377: /**
        !          9378:  * xmlXPathFalseFunction:
        !          9379:  * @ctxt:  the XPath Parser context
        !          9380:  * @nargs:  the number of arguments
        !          9381:  *
        !          9382:  * Implement the false() XPath function
        !          9383:  *    boolean false()
        !          9384:  */
        !          9385: void
        !          9386: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9387:     CHECK_ARITY(0);
        !          9388:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
        !          9389: }
        !          9390: 
        !          9391: /**
        !          9392:  * xmlXPathLangFunction:
        !          9393:  * @ctxt:  the XPath Parser context
        !          9394:  * @nargs:  the number of arguments
        !          9395:  *
        !          9396:  * Implement the lang() XPath function
        !          9397:  *    boolean lang(string)
        !          9398:  * The lang function returns true or false depending on whether the
        !          9399:  * language of the context node as specified by xml:lang attributes
        !          9400:  * is the same as or is a sublanguage of the language specified by
        !          9401:  * the argument string. The language of the context node is determined
        !          9402:  * by the value of the xml:lang attribute on the context node, or, if
        !          9403:  * the context node has no xml:lang attribute, by the value of the
        !          9404:  * xml:lang attribute on the nearest ancestor of the context node that
        !          9405:  * has an xml:lang attribute. If there is no such attribute, then lang
        !          9406:  * returns false. If there is such an attribute, then lang returns
        !          9407:  * true if the attribute value is equal to the argument ignoring case,
        !          9408:  * or if there is some suffix starting with - such that the attribute
        !          9409:  * value is equal to the argument ignoring that suffix of the attribute
        !          9410:  * value and ignoring case.
        !          9411:  */
        !          9412: void
        !          9413: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9414:     xmlXPathObjectPtr val = NULL;
        !          9415:     const xmlChar *theLang = NULL;
        !          9416:     const xmlChar *lang;
        !          9417:     int ret = 0;
        !          9418:     int i;
        !          9419: 
        !          9420:     CHECK_ARITY(1);
        !          9421:     CAST_TO_STRING;
        !          9422:     CHECK_TYPE(XPATH_STRING);
        !          9423:     val = valuePop(ctxt);
        !          9424:     lang = val->stringval;
        !          9425:     theLang = xmlNodeGetLang(ctxt->context->node);
        !          9426:     if ((theLang != NULL) && (lang != NULL)) {
        !          9427:         for (i = 0;lang[i] != 0;i++)
        !          9428:            if (toupper(lang[i]) != toupper(theLang[i]))
        !          9429:                goto not_equal;
        !          9430:        if ((theLang[i] == 0) || (theLang[i] == '-'))
        !          9431:            ret = 1;
        !          9432:     }
        !          9433: not_equal:
        !          9434:     if (theLang != NULL)
        !          9435:        xmlFree((void *)theLang);
        !          9436: 
        !          9437:     xmlXPathReleaseObject(ctxt->context, val);
        !          9438:     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
        !          9439: }
        !          9440: 
        !          9441: /**
        !          9442:  * xmlXPathNumberFunction:
        !          9443:  * @ctxt:  the XPath Parser context
        !          9444:  * @nargs:  the number of arguments
        !          9445:  *
        !          9446:  * Implement the number() XPath function
        !          9447:  *    number number(object?)
        !          9448:  */
        !          9449: void
        !          9450: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9451:     xmlXPathObjectPtr cur;
        !          9452:     double res;
        !          9453: 
        !          9454:     if (ctxt == NULL) return;
        !          9455:     if (nargs == 0) {
        !          9456:        if (ctxt->context->node == NULL) {
        !          9457:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
        !          9458:        } else {
        !          9459:            xmlChar* content = xmlNodeGetContent(ctxt->context->node);
        !          9460: 
        !          9461:            res = xmlXPathStringEvalNumber(content);
        !          9462:            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
        !          9463:            xmlFree(content);
        !          9464:        }
        !          9465:        return;
        !          9466:     }
        !          9467: 
        !          9468:     CHECK_ARITY(1);
        !          9469:     cur = valuePop(ctxt);
        !          9470:     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
        !          9471: }
        !          9472: 
        !          9473: /**
        !          9474:  * xmlXPathSumFunction:
        !          9475:  * @ctxt:  the XPath Parser context
        !          9476:  * @nargs:  the number of arguments
        !          9477:  *
        !          9478:  * Implement the sum() XPath function
        !          9479:  *    number sum(node-set)
        !          9480:  * The sum function returns the sum of the values of the nodes in
        !          9481:  * the argument node-set.
        !          9482:  */
        !          9483: void
        !          9484: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9485:     xmlXPathObjectPtr cur;
        !          9486:     int i;
        !          9487:     double res = 0.0;
        !          9488: 
        !          9489:     CHECK_ARITY(1);
        !          9490:     if ((ctxt->value == NULL) ||
        !          9491:        ((ctxt->value->type != XPATH_NODESET) &&
        !          9492:         (ctxt->value->type != XPATH_XSLT_TREE)))
        !          9493:        XP_ERROR(XPATH_INVALID_TYPE);
        !          9494:     cur = valuePop(ctxt);
        !          9495: 
        !          9496:     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
        !          9497:        for (i = 0; i < cur->nodesetval->nodeNr; i++) {
        !          9498:            res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
        !          9499:        }
        !          9500:     }
        !          9501:     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
        !          9502:     xmlXPathReleaseObject(ctxt->context, cur);
        !          9503: }
        !          9504: 
        !          9505: /*
        !          9506:  * To assure working code on multiple platforms, we want to only depend
        !          9507:  * upon the characteristic truncation of converting a floating point value
        !          9508:  * to an integer.  Unfortunately, because of the different storage sizes
        !          9509:  * of our internal floating point value (double) and integer (int), we
        !          9510:  * can't directly convert (see bug 301162).  This macro is a messy
        !          9511:  * 'workaround'
        !          9512:  */
        !          9513: #define XTRUNC(f, v)            \
        !          9514:     f = fmod((v), INT_MAX);     \
        !          9515:     f = (v) - (f) + (double)((int)(f));
        !          9516: 
        !          9517: /**
        !          9518:  * xmlXPathFloorFunction:
        !          9519:  * @ctxt:  the XPath Parser context
        !          9520:  * @nargs:  the number of arguments
        !          9521:  *
        !          9522:  * Implement the floor() XPath function
        !          9523:  *    number floor(number)
        !          9524:  * The floor function returns the largest (closest to positive infinity)
        !          9525:  * number that is not greater than the argument and that is an integer.
        !          9526:  */
        !          9527: void
        !          9528: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9529:     double f;
        !          9530: 
        !          9531:     CHECK_ARITY(1);
        !          9532:     CAST_TO_NUMBER;
        !          9533:     CHECK_TYPE(XPATH_NUMBER);
        !          9534: 
        !          9535:     XTRUNC(f, ctxt->value->floatval);
        !          9536:     if (f != ctxt->value->floatval) {
        !          9537:        if (ctxt->value->floatval > 0)
        !          9538:            ctxt->value->floatval = f;
        !          9539:        else
        !          9540:            ctxt->value->floatval = f - 1;
        !          9541:     }
        !          9542: }
        !          9543: 
        !          9544: /**
        !          9545:  * xmlXPathCeilingFunction:
        !          9546:  * @ctxt:  the XPath Parser context
        !          9547:  * @nargs:  the number of arguments
        !          9548:  *
        !          9549:  * Implement the ceiling() XPath function
        !          9550:  *    number ceiling(number)
        !          9551:  * The ceiling function returns the smallest (closest to negative infinity)
        !          9552:  * number that is not less than the argument and that is an integer.
        !          9553:  */
        !          9554: void
        !          9555: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9556:     double f;
        !          9557: 
        !          9558:     CHECK_ARITY(1);
        !          9559:     CAST_TO_NUMBER;
        !          9560:     CHECK_TYPE(XPATH_NUMBER);
        !          9561: 
        !          9562: #if 0
        !          9563:     ctxt->value->floatval = ceil(ctxt->value->floatval);
        !          9564: #else
        !          9565:     XTRUNC(f, ctxt->value->floatval);
        !          9566:     if (f != ctxt->value->floatval) {
        !          9567:        if (ctxt->value->floatval > 0)
        !          9568:            ctxt->value->floatval = f + 1;
        !          9569:        else {
        !          9570:            if (ctxt->value->floatval < 0 && f == 0)
        !          9571:                ctxt->value->floatval = xmlXPathNZERO;
        !          9572:            else
        !          9573:                ctxt->value->floatval = f;
        !          9574:        }
        !          9575: 
        !          9576:     }
        !          9577: #endif
        !          9578: }
        !          9579: 
        !          9580: /**
        !          9581:  * xmlXPathRoundFunction:
        !          9582:  * @ctxt:  the XPath Parser context
        !          9583:  * @nargs:  the number of arguments
        !          9584:  *
        !          9585:  * Implement the round() XPath function
        !          9586:  *    number round(number)
        !          9587:  * The round function returns the number that is closest to the
        !          9588:  * argument and that is an integer. If there are two such numbers,
        !          9589:  * then the one that is even is returned.
        !          9590:  */
        !          9591: void
        !          9592: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          9593:     double f;
        !          9594: 
        !          9595:     CHECK_ARITY(1);
        !          9596:     CAST_TO_NUMBER;
        !          9597:     CHECK_TYPE(XPATH_NUMBER);
        !          9598: 
        !          9599:     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
        !          9600:        (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
        !          9601:        (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
        !          9602:        (ctxt->value->floatval == 0.0))
        !          9603:        return;
        !          9604: 
        !          9605:     XTRUNC(f, ctxt->value->floatval);
        !          9606:     if (ctxt->value->floatval < 0) {
        !          9607:        if (ctxt->value->floatval < f - 0.5)
        !          9608:            ctxt->value->floatval = f - 1;
        !          9609:        else
        !          9610:            ctxt->value->floatval = f;
        !          9611:        if (ctxt->value->floatval == 0)
        !          9612:            ctxt->value->floatval = xmlXPathNZERO;
        !          9613:     } else {
        !          9614:        if (ctxt->value->floatval < f + 0.5)
        !          9615:            ctxt->value->floatval = f;
        !          9616:        else
        !          9617:            ctxt->value->floatval = f + 1;
        !          9618:     }
        !          9619: }
        !          9620: 
        !          9621: /************************************************************************
        !          9622:  *                                                                     *
        !          9623:  *                     The Parser                                      *
        !          9624:  *                                                                     *
        !          9625:  ************************************************************************/
        !          9626: 
        !          9627: /*
        !          9628:  * a few forward declarations since we use a recursive call based
        !          9629:  * implementation.
        !          9630:  */
        !          9631: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
        !          9632: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
        !          9633: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
        !          9634: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
        !          9635: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
        !          9636:                                          int qualified);
        !          9637: 
        !          9638: /**
        !          9639:  * xmlXPathCurrentChar:
        !          9640:  * @ctxt:  the XPath parser context
        !          9641:  * @cur:  pointer to the beginning of the char
        !          9642:  * @len:  pointer to the length of the char read
        !          9643:  *
        !          9644:  * The current char value, if using UTF-8 this may actually span multiple
        !          9645:  * bytes in the input buffer.
        !          9646:  *
        !          9647:  * Returns the current char value and its length
        !          9648:  */
        !          9649: 
        !          9650: static int
        !          9651: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
        !          9652:     unsigned char c;
        !          9653:     unsigned int val;
        !          9654:     const xmlChar *cur;
        !          9655: 
        !          9656:     if (ctxt == NULL)
        !          9657:        return(0);
        !          9658:     cur = ctxt->cur;
        !          9659: 
        !          9660:     /*
        !          9661:      * We are supposed to handle UTF8, check it's valid
        !          9662:      * From rfc2044: encoding of the Unicode values on UTF-8:
        !          9663:      *
        !          9664:      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
        !          9665:      * 0000 0000-0000 007F   0xxxxxxx
        !          9666:      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
        !          9667:      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
        !          9668:      *
        !          9669:      * Check for the 0x110000 limit too
        !          9670:      */
        !          9671:     c = *cur;
        !          9672:     if (c & 0x80) {
        !          9673:        if ((cur[1] & 0xc0) != 0x80)
        !          9674:            goto encoding_error;
        !          9675:        if ((c & 0xe0) == 0xe0) {
        !          9676: 
        !          9677:            if ((cur[2] & 0xc0) != 0x80)
        !          9678:                goto encoding_error;
        !          9679:            if ((c & 0xf0) == 0xf0) {
        !          9680:                if (((c & 0xf8) != 0xf0) ||
        !          9681:                    ((cur[3] & 0xc0) != 0x80))
        !          9682:                    goto encoding_error;
        !          9683:                /* 4-byte code */
        !          9684:                *len = 4;
        !          9685:                val = (cur[0] & 0x7) << 18;
        !          9686:                val |= (cur[1] & 0x3f) << 12;
        !          9687:                val |= (cur[2] & 0x3f) << 6;
        !          9688:                val |= cur[3] & 0x3f;
        !          9689:            } else {
        !          9690:              /* 3-byte code */
        !          9691:                *len = 3;
        !          9692:                val = (cur[0] & 0xf) << 12;
        !          9693:                val |= (cur[1] & 0x3f) << 6;
        !          9694:                val |= cur[2] & 0x3f;
        !          9695:            }
        !          9696:        } else {
        !          9697:          /* 2-byte code */
        !          9698:            *len = 2;
        !          9699:            val = (cur[0] & 0x1f) << 6;
        !          9700:            val |= cur[1] & 0x3f;
        !          9701:        }
        !          9702:        if (!IS_CHAR(val)) {
        !          9703:            XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
        !          9704:        }
        !          9705:        return(val);
        !          9706:     } else {
        !          9707:        /* 1-byte code */
        !          9708:        *len = 1;
        !          9709:        return((int) *cur);
        !          9710:     }
        !          9711: encoding_error:
        !          9712:     /*
        !          9713:      * If we detect an UTF8 error that probably means that the
        !          9714:      * input encoding didn't get properly advertised in the
        !          9715:      * declaration header. Report the error and switch the encoding
        !          9716:      * to ISO-Latin-1 (if you don't like this policy, just declare the
        !          9717:      * encoding !)
        !          9718:      */
        !          9719:     *len = 0;
        !          9720:     XP_ERROR0(XPATH_ENCODING_ERROR);
        !          9721: }
        !          9722: 
        !          9723: /**
        !          9724:  * xmlXPathParseNCName:
        !          9725:  * @ctxt:  the XPath Parser context
        !          9726:  *
        !          9727:  * parse an XML namespace non qualified name.
        !          9728:  *
        !          9729:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
        !          9730:  *
        !          9731:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
        !          9732:  *                       CombiningChar | Extender
        !          9733:  *
        !          9734:  * Returns the namespace name or NULL
        !          9735:  */
        !          9736: 
        !          9737: xmlChar *
        !          9738: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
        !          9739:     const xmlChar *in;
        !          9740:     xmlChar *ret;
        !          9741:     int count = 0;
        !          9742: 
        !          9743:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
        !          9744:     /*
        !          9745:      * Accelerator for simple ASCII names
        !          9746:      */
        !          9747:     in = ctxt->cur;
        !          9748:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
        !          9749:        ((*in >= 0x41) && (*in <= 0x5A)) ||
        !          9750:        (*in == '_')) {
        !          9751:        in++;
        !          9752:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
        !          9753:               ((*in >= 0x41) && (*in <= 0x5A)) ||
        !          9754:               ((*in >= 0x30) && (*in <= 0x39)) ||
        !          9755:               (*in == '_') || (*in == '.') ||
        !          9756:               (*in == '-'))
        !          9757:            in++;
        !          9758:        if ((*in == ' ') || (*in == '>') || (*in == '/') ||
        !          9759:             (*in == '[') || (*in == ']') || (*in == ':') ||
        !          9760:             (*in == '@') || (*in == '*')) {
        !          9761:            count = in - ctxt->cur;
        !          9762:            if (count == 0)
        !          9763:                return(NULL);
        !          9764:            ret = xmlStrndup(ctxt->cur, count);
        !          9765:            ctxt->cur = in;
        !          9766:            return(ret);
        !          9767:        }
        !          9768:     }
        !          9769:     return(xmlXPathParseNameComplex(ctxt, 0));
        !          9770: }
        !          9771: 
        !          9772: 
        !          9773: /**
        !          9774:  * xmlXPathParseQName:
        !          9775:  * @ctxt:  the XPath Parser context
        !          9776:  * @prefix:  a xmlChar **
        !          9777:  *
        !          9778:  * parse an XML qualified name
        !          9779:  *
        !          9780:  * [NS 5] QName ::= (Prefix ':')? LocalPart
        !          9781:  *
        !          9782:  * [NS 6] Prefix ::= NCName
        !          9783:  *
        !          9784:  * [NS 7] LocalPart ::= NCName
        !          9785:  *
        !          9786:  * Returns the function returns the local part, and prefix is updated
        !          9787:  *   to get the Prefix if any.
        !          9788:  */
        !          9789: 
        !          9790: static xmlChar *
        !          9791: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
        !          9792:     xmlChar *ret = NULL;
        !          9793: 
        !          9794:     *prefix = NULL;
        !          9795:     ret = xmlXPathParseNCName(ctxt);
        !          9796:     if (ret && CUR == ':') {
        !          9797:         *prefix = ret;
        !          9798:        NEXT;
        !          9799:        ret = xmlXPathParseNCName(ctxt);
        !          9800:     }
        !          9801:     return(ret);
        !          9802: }
        !          9803: 
        !          9804: /**
        !          9805:  * xmlXPathParseName:
        !          9806:  * @ctxt:  the XPath Parser context
        !          9807:  *
        !          9808:  * parse an XML name
        !          9809:  *
        !          9810:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
        !          9811:  *                  CombiningChar | Extender
        !          9812:  *
        !          9813:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
        !          9814:  *
        !          9815:  * Returns the namespace name or NULL
        !          9816:  */
        !          9817: 
        !          9818: xmlChar *
        !          9819: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
        !          9820:     const xmlChar *in;
        !          9821:     xmlChar *ret;
        !          9822:     int count = 0;
        !          9823: 
        !          9824:     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
        !          9825:     /*
        !          9826:      * Accelerator for simple ASCII names
        !          9827:      */
        !          9828:     in = ctxt->cur;
        !          9829:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
        !          9830:        ((*in >= 0x41) && (*in <= 0x5A)) ||
        !          9831:        (*in == '_') || (*in == ':')) {
        !          9832:        in++;
        !          9833:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
        !          9834:               ((*in >= 0x41) && (*in <= 0x5A)) ||
        !          9835:               ((*in >= 0x30) && (*in <= 0x39)) ||
        !          9836:               (*in == '_') || (*in == '-') ||
        !          9837:               (*in == ':') || (*in == '.'))
        !          9838:            in++;
        !          9839:        if ((*in > 0) && (*in < 0x80)) {
        !          9840:            count = in - ctxt->cur;
        !          9841:            ret = xmlStrndup(ctxt->cur, count);
        !          9842:            ctxt->cur = in;
        !          9843:            return(ret);
        !          9844:        }
        !          9845:     }
        !          9846:     return(xmlXPathParseNameComplex(ctxt, 1));
        !          9847: }
        !          9848: 
        !          9849: static xmlChar *
        !          9850: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
        !          9851:     xmlChar buf[XML_MAX_NAMELEN + 5];
        !          9852:     int len = 0, l;
        !          9853:     int c;
        !          9854: 
        !          9855:     /*
        !          9856:      * Handler for more complex cases
        !          9857:      */
        !          9858:     c = CUR_CHAR(l);
        !          9859:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
        !          9860:         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
        !          9861:         (c == '*') || /* accelerators */
        !          9862:        (!IS_LETTER(c) && (c != '_') &&
        !          9863:          ((qualified) && (c != ':')))) {
        !          9864:        return(NULL);
        !          9865:     }
        !          9866: 
        !          9867:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
        !          9868:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
        !          9869:             (c == '.') || (c == '-') ||
        !          9870:            (c == '_') || ((qualified) && (c == ':')) ||
        !          9871:            (IS_COMBINING(c)) ||
        !          9872:            (IS_EXTENDER(c)))) {
        !          9873:        COPY_BUF(l,buf,len,c);
        !          9874:        NEXTL(l);
        !          9875:        c = CUR_CHAR(l);
        !          9876:        if (len >= XML_MAX_NAMELEN) {
        !          9877:            /*
        !          9878:             * Okay someone managed to make a huge name, so he's ready to pay
        !          9879:             * for the processing speed.
        !          9880:             */
        !          9881:            xmlChar *buffer;
        !          9882:            int max = len * 2;
        !          9883: 
        !          9884:            buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
        !          9885:            if (buffer == NULL) {
        !          9886:                XP_ERRORNULL(XPATH_MEMORY_ERROR);
        !          9887:            }
        !          9888:            memcpy(buffer, buf, len);
        !          9889:            while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
        !          9890:                   (c == '.') || (c == '-') ||
        !          9891:                   (c == '_') || ((qualified) && (c == ':')) ||
        !          9892:                   (IS_COMBINING(c)) ||
        !          9893:                   (IS_EXTENDER(c))) {
        !          9894:                if (len + 10 > max) {
        !          9895:                    max *= 2;
        !          9896:                    buffer = (xmlChar *) xmlRealloc(buffer,
        !          9897:                                                    max * sizeof(xmlChar));
        !          9898:                    if (buffer == NULL) {
        !          9899:                        XP_ERRORNULL(XPATH_MEMORY_ERROR);
        !          9900:                    }
        !          9901:                }
        !          9902:                COPY_BUF(l,buffer,len,c);
        !          9903:                NEXTL(l);
        !          9904:                c = CUR_CHAR(l);
        !          9905:            }
        !          9906:            buffer[len] = 0;
        !          9907:            return(buffer);
        !          9908:        }
        !          9909:     }
        !          9910:     if (len == 0)
        !          9911:        return(NULL);
        !          9912:     return(xmlStrndup(buf, len));
        !          9913: }
        !          9914: 
        !          9915: #define MAX_FRAC 20
        !          9916: 
        !          9917: /*
        !          9918:  * These are used as divisors for the fractional part of a number.
        !          9919:  * Since the table includes 1.0 (representing '0' fractional digits),
        !          9920:  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
        !          9921:  */
        !          9922: static double my_pow10[MAX_FRAC+1] = {
        !          9923:     1.0, 10.0, 100.0, 1000.0, 10000.0,
        !          9924:     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
        !          9925:     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
        !          9926:     100000000000000.0,
        !          9927:     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
        !          9928:     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
        !          9929: };
        !          9930: 
        !          9931: /**
        !          9932:  * xmlXPathStringEvalNumber:
        !          9933:  * @str:  A string to scan
        !          9934:  *
        !          9935:  *  [30a]  Float  ::= Number ('e' Digits?)?
        !          9936:  *
        !          9937:  *  [30]   Number ::=   Digits ('.' Digits?)?
        !          9938:  *                    | '.' Digits
        !          9939:  *  [31]   Digits ::=   [0-9]+
        !          9940:  *
        !          9941:  * Compile a Number in the string
        !          9942:  * In complement of the Number expression, this function also handles
        !          9943:  * negative values : '-' Number.
        !          9944:  *
        !          9945:  * Returns the double value.
        !          9946:  */
        !          9947: double
        !          9948: xmlXPathStringEvalNumber(const xmlChar *str) {
        !          9949:     const xmlChar *cur = str;
        !          9950:     double ret;
        !          9951:     int ok = 0;
        !          9952:     int isneg = 0;
        !          9953:     int exponent = 0;
        !          9954:     int is_exponent_negative = 0;
        !          9955: #ifdef __GNUC__
        !          9956:     unsigned long tmp = 0;
        !          9957:     double temp;
        !          9958: #endif
        !          9959:     if (cur == NULL) return(0);
        !          9960:     while (IS_BLANK_CH(*cur)) cur++;
        !          9961:     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
        !          9962:         return(xmlXPathNAN);
        !          9963:     }
        !          9964:     if (*cur == '-') {
        !          9965:        isneg = 1;
        !          9966:        cur++;
        !          9967:     }
        !          9968: 
        !          9969: #ifdef __GNUC__
        !          9970:     /*
        !          9971:      * tmp/temp is a workaround against a gcc compiler bug
        !          9972:      * http://veillard.com/gcc.bug
        !          9973:      */
        !          9974:     ret = 0;
        !          9975:     while ((*cur >= '0') && (*cur <= '9')) {
        !          9976:        ret = ret * 10;
        !          9977:        tmp = (*cur - '0');
        !          9978:        ok = 1;
        !          9979:        cur++;
        !          9980:        temp = (double) tmp;
        !          9981:        ret = ret + temp;
        !          9982:     }
        !          9983: #else
        !          9984:     ret = 0;
        !          9985:     while ((*cur >= '0') && (*cur <= '9')) {
        !          9986:        ret = ret * 10 + (*cur - '0');
        !          9987:        ok = 1;
        !          9988:        cur++;
        !          9989:     }
        !          9990: #endif
        !          9991: 
        !          9992:     if (*cur == '.') {
        !          9993:        int v, frac = 0;
        !          9994:        double fraction = 0;
        !          9995: 
        !          9996:         cur++;
        !          9997:        if (((*cur < '0') || (*cur > '9')) && (!ok)) {
        !          9998:            return(xmlXPathNAN);
        !          9999:        }
        !          10000:        while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
        !          10001:            v = (*cur - '0');
        !          10002:            fraction = fraction * 10 + v;
        !          10003:            frac = frac + 1;
        !          10004:            cur++;
        !          10005:        }
        !          10006:        fraction /= my_pow10[frac];
        !          10007:        ret = ret + fraction;
        !          10008:        while ((*cur >= '0') && (*cur <= '9'))
        !          10009:            cur++;
        !          10010:     }
        !          10011:     if ((*cur == 'e') || (*cur == 'E')) {
        !          10012:       cur++;
        !          10013:       if (*cur == '-') {
        !          10014:        is_exponent_negative = 1;
        !          10015:        cur++;
        !          10016:       } else if (*cur == '+') {
        !          10017:         cur++;
        !          10018:       }
        !          10019:       while ((*cur >= '0') && (*cur <= '9')) {
        !          10020:        exponent = exponent * 10 + (*cur - '0');
        !          10021:        cur++;
        !          10022:       }
        !          10023:     }
        !          10024:     while (IS_BLANK_CH(*cur)) cur++;
        !          10025:     if (*cur != 0) return(xmlXPathNAN);
        !          10026:     if (isneg) ret = -ret;
        !          10027:     if (is_exponent_negative) exponent = -exponent;
        !          10028:     ret *= pow(10.0, (double)exponent);
        !          10029:     return(ret);
        !          10030: }
        !          10031: 
        !          10032: /**
        !          10033:  * xmlXPathCompNumber:
        !          10034:  * @ctxt:  the XPath Parser context
        !          10035:  *
        !          10036:  *  [30]   Number ::=   Digits ('.' Digits?)?
        !          10037:  *                    | '.' Digits
        !          10038:  *  [31]   Digits ::=   [0-9]+
        !          10039:  *
        !          10040:  * Compile a Number, then push it on the stack
        !          10041:  *
        !          10042:  */
        !          10043: static void
        !          10044: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
        !          10045: {
        !          10046:     double ret = 0.0;
        !          10047:     double mult = 1;
        !          10048:     int ok = 0;
        !          10049:     int exponent = 0;
        !          10050:     int is_exponent_negative = 0;
        !          10051: #ifdef __GNUC__
        !          10052:     unsigned long tmp = 0;
        !          10053:     double temp;
        !          10054: #endif
        !          10055: 
        !          10056:     CHECK_ERROR;
        !          10057:     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
        !          10058:         XP_ERROR(XPATH_NUMBER_ERROR);
        !          10059:     }
        !          10060: #ifdef __GNUC__
        !          10061:     /*
        !          10062:      * tmp/temp is a workaround against a gcc compiler bug
        !          10063:      * http://veillard.com/gcc.bug
        !          10064:      */
        !          10065:     ret = 0;
        !          10066:     while ((CUR >= '0') && (CUR <= '9')) {
        !          10067:        ret = ret * 10;
        !          10068:        tmp = (CUR - '0');
        !          10069:         ok = 1;
        !          10070:         NEXT;
        !          10071:        temp = (double) tmp;
        !          10072:        ret = ret + temp;
        !          10073:     }
        !          10074: #else
        !          10075:     ret = 0;
        !          10076:     while ((CUR >= '0') && (CUR <= '9')) {
        !          10077:        ret = ret * 10 + (CUR - '0');
        !          10078:        ok = 1;
        !          10079:        NEXT;
        !          10080:     }
        !          10081: #endif
        !          10082:     if (CUR == '.') {
        !          10083:        int v, frac = 0;
        !          10084:        double fraction = 0;
        !          10085: 
        !          10086:         NEXT;
        !          10087:         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
        !          10088:             XP_ERROR(XPATH_NUMBER_ERROR);
        !          10089:         }
        !          10090:         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
        !          10091:            v = (CUR - '0');
        !          10092:            fraction = fraction * 10 + v;
        !          10093:            frac = frac + 1;
        !          10094:             NEXT;
        !          10095:         }
        !          10096:         fraction /= my_pow10[frac];
        !          10097:         ret = ret + fraction;
        !          10098:         while ((CUR >= '0') && (CUR <= '9'))
        !          10099:             NEXT;
        !          10100:     }
        !          10101:     if ((CUR == 'e') || (CUR == 'E')) {
        !          10102:         NEXT;
        !          10103:         if (CUR == '-') {
        !          10104:             is_exponent_negative = 1;
        !          10105:             NEXT;
        !          10106:         } else if (CUR == '+') {
        !          10107:            NEXT;
        !          10108:        }
        !          10109:         while ((CUR >= '0') && (CUR <= '9')) {
        !          10110:             exponent = exponent * 10 + (CUR - '0');
        !          10111:             NEXT;
        !          10112:         }
        !          10113:         if (is_exponent_negative)
        !          10114:             exponent = -exponent;
        !          10115:         ret *= pow(10.0, (double) exponent);
        !          10116:     }
        !          10117:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
        !          10118:                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
        !          10119: }
        !          10120: 
        !          10121: /**
        !          10122:  * xmlXPathParseLiteral:
        !          10123:  * @ctxt:  the XPath Parser context
        !          10124:  *
        !          10125:  * Parse a Literal
        !          10126:  *
        !          10127:  *  [29]   Literal ::=   '"' [^"]* '"'
        !          10128:  *                    | "'" [^']* "'"
        !          10129:  *
        !          10130:  * Returns the value found or NULL in case of error
        !          10131:  */
        !          10132: static xmlChar *
        !          10133: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
        !          10134:     const xmlChar *q;
        !          10135:     xmlChar *ret = NULL;
        !          10136: 
        !          10137:     if (CUR == '"') {
        !          10138:         NEXT;
        !          10139:        q = CUR_PTR;
        !          10140:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
        !          10141:            NEXT;
        !          10142:        if (!IS_CHAR_CH(CUR)) {
        !          10143:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
        !          10144:        } else {
        !          10145:            ret = xmlStrndup(q, CUR_PTR - q);
        !          10146:            NEXT;
        !          10147:         }
        !          10148:     } else if (CUR == '\'') {
        !          10149:         NEXT;
        !          10150:        q = CUR_PTR;
        !          10151:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
        !          10152:            NEXT;
        !          10153:        if (!IS_CHAR_CH(CUR)) {
        !          10154:            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
        !          10155:        } else {
        !          10156:            ret = xmlStrndup(q, CUR_PTR - q);
        !          10157:            NEXT;
        !          10158:         }
        !          10159:     } else {
        !          10160:        XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
        !          10161:     }
        !          10162:     return(ret);
        !          10163: }
        !          10164: 
        !          10165: /**
        !          10166:  * xmlXPathCompLiteral:
        !          10167:  * @ctxt:  the XPath Parser context
        !          10168:  *
        !          10169:  * Parse a Literal and push it on the stack.
        !          10170:  *
        !          10171:  *  [29]   Literal ::=   '"' [^"]* '"'
        !          10172:  *                    | "'" [^']* "'"
        !          10173:  *
        !          10174:  * TODO: xmlXPathCompLiteral memory allocation could be improved.
        !          10175:  */
        !          10176: static void
        !          10177: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
        !          10178:     const xmlChar *q;
        !          10179:     xmlChar *ret = NULL;
        !          10180: 
        !          10181:     if (CUR == '"') {
        !          10182:         NEXT;
        !          10183:        q = CUR_PTR;
        !          10184:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
        !          10185:            NEXT;
        !          10186:        if (!IS_CHAR_CH(CUR)) {
        !          10187:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
        !          10188:        } else {
        !          10189:            ret = xmlStrndup(q, CUR_PTR - q);
        !          10190:            NEXT;
        !          10191:         }
        !          10192:     } else if (CUR == '\'') {
        !          10193:         NEXT;
        !          10194:        q = CUR_PTR;
        !          10195:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
        !          10196:            NEXT;
        !          10197:        if (!IS_CHAR_CH(CUR)) {
        !          10198:            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
        !          10199:        } else {
        !          10200:            ret = xmlStrndup(q, CUR_PTR - q);
        !          10201:            NEXT;
        !          10202:         }
        !          10203:     } else {
        !          10204:        XP_ERROR(XPATH_START_LITERAL_ERROR);
        !          10205:     }
        !          10206:     if (ret == NULL) return;
        !          10207:     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
        !          10208:                   xmlXPathCacheNewString(ctxt->context, ret), NULL);
        !          10209:     xmlFree(ret);
        !          10210: }
        !          10211: 
        !          10212: /**
        !          10213:  * xmlXPathCompVariableReference:
        !          10214:  * @ctxt:  the XPath Parser context
        !          10215:  *
        !          10216:  * Parse a VariableReference, evaluate it and push it on the stack.
        !          10217:  *
        !          10218:  * The variable bindings consist of a mapping from variable names
        !          10219:  * to variable values. The value of a variable is an object, which can be
        !          10220:  * of any of the types that are possible for the value of an expression,
        !          10221:  * and may also be of additional types not specified here.
        !          10222:  *
        !          10223:  * Early evaluation is possible since:
        !          10224:  * The variable bindings [...] used to evaluate a subexpression are
        !          10225:  * always the same as those used to evaluate the containing expression.
        !          10226:  *
        !          10227:  *  [36]   VariableReference ::=   '$' QName
        !          10228:  */
        !          10229: static void
        !          10230: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
        !          10231:     xmlChar *name;
        !          10232:     xmlChar *prefix;
        !          10233: 
        !          10234:     SKIP_BLANKS;
        !          10235:     if (CUR != '$') {
        !          10236:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
        !          10237:     }
        !          10238:     NEXT;
        !          10239:     name = xmlXPathParseQName(ctxt, &prefix);
        !          10240:     if (name == NULL) {
        !          10241:        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
        !          10242:     }
        !          10243:     ctxt->comp->last = -1;
        !          10244:     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
        !          10245:                   name, prefix);
        !          10246:     SKIP_BLANKS;
        !          10247:     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
        !          10248:        XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
        !          10249:     }
        !          10250: }
        !          10251: 
        !          10252: /**
        !          10253:  * xmlXPathIsNodeType:
        !          10254:  * @name:  a name string
        !          10255:  *
        !          10256:  * Is the name given a NodeType one.
        !          10257:  *
        !          10258:  *  [38]   NodeType ::=   'comment'
        !          10259:  *                    | 'text'
        !          10260:  *                    | 'processing-instruction'
        !          10261:  *                    | 'node'
        !          10262:  *
        !          10263:  * Returns 1 if true 0 otherwise
        !          10264:  */
        !          10265: int
        !          10266: xmlXPathIsNodeType(const xmlChar *name) {
        !          10267:     if (name == NULL)
        !          10268:        return(0);
        !          10269: 
        !          10270:     if (xmlStrEqual(name, BAD_CAST "node"))
        !          10271:        return(1);
        !          10272:     if (xmlStrEqual(name, BAD_CAST "text"))
        !          10273:        return(1);
        !          10274:     if (xmlStrEqual(name, BAD_CAST "comment"))
        !          10275:        return(1);
        !          10276:     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
        !          10277:        return(1);
        !          10278:     return(0);
        !          10279: }
        !          10280: 
        !          10281: /**
        !          10282:  * xmlXPathCompFunctionCall:
        !          10283:  * @ctxt:  the XPath Parser context
        !          10284:  *
        !          10285:  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
        !          10286:  *  [17]   Argument ::=   Expr
        !          10287:  *
        !          10288:  * Compile a function call, the evaluation of all arguments are
        !          10289:  * pushed on the stack
        !          10290:  */
        !          10291: static void
        !          10292: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
        !          10293:     xmlChar *name;
        !          10294:     xmlChar *prefix;
        !          10295:     int nbargs = 0;
        !          10296:     int sort = 1;
        !          10297: 
        !          10298:     name = xmlXPathParseQName(ctxt, &prefix);
        !          10299:     if (name == NULL) {
        !          10300:        xmlFree(prefix);
        !          10301:        XP_ERROR(XPATH_EXPR_ERROR);
        !          10302:     }
        !          10303:     SKIP_BLANKS;
        !          10304: #ifdef DEBUG_EXPR
        !          10305:     if (prefix == NULL)
        !          10306:        xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
        !          10307:                        name);
        !          10308:     else
        !          10309:        xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
        !          10310:                        prefix, name);
        !          10311: #endif
        !          10312: 
        !          10313:     if (CUR != '(') {
        !          10314:        XP_ERROR(XPATH_EXPR_ERROR);
        !          10315:     }
        !          10316:     NEXT;
        !          10317:     SKIP_BLANKS;
        !          10318: 
        !          10319:     /*
        !          10320:     * Optimization for count(): we don't need the node-set to be sorted.
        !          10321:     */
        !          10322:     if ((prefix == NULL) && (name[0] == 'c') &&
        !          10323:        xmlStrEqual(name, BAD_CAST "count"))
        !          10324:     {
        !          10325:        sort = 0;
        !          10326:     }
        !          10327:     ctxt->comp->last = -1;
        !          10328:     if (CUR != ')') {
        !          10329:        while (CUR != 0) {
        !          10330:            int op1 = ctxt->comp->last;
        !          10331:            ctxt->comp->last = -1;
        !          10332:            xmlXPathCompileExpr(ctxt, sort);
        !          10333:            if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          10334:                xmlFree(name);
        !          10335:                xmlFree(prefix);
        !          10336:                return;
        !          10337:            }
        !          10338:            PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
        !          10339:            nbargs++;
        !          10340:            if (CUR == ')') break;
        !          10341:            if (CUR != ',') {
        !          10342:                XP_ERROR(XPATH_EXPR_ERROR);
        !          10343:            }
        !          10344:            NEXT;
        !          10345:            SKIP_BLANKS;
        !          10346:        }
        !          10347:     }
        !          10348:     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
        !          10349:                   name, prefix);
        !          10350:     NEXT;
        !          10351:     SKIP_BLANKS;
        !          10352: }
        !          10353: 
        !          10354: /**
        !          10355:  * xmlXPathCompPrimaryExpr:
        !          10356:  * @ctxt:  the XPath Parser context
        !          10357:  *
        !          10358:  *  [15]   PrimaryExpr ::=   VariableReference
        !          10359:  *                | '(' Expr ')'
        !          10360:  *                | Literal
        !          10361:  *                | Number
        !          10362:  *                | FunctionCall
        !          10363:  *
        !          10364:  * Compile a primary expression.
        !          10365:  */
        !          10366: static void
        !          10367: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
        !          10368:     SKIP_BLANKS;
        !          10369:     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
        !          10370:     else if (CUR == '(') {
        !          10371:        NEXT;
        !          10372:        SKIP_BLANKS;
        !          10373:        xmlXPathCompileExpr(ctxt, 1);
        !          10374:        CHECK_ERROR;
        !          10375:        if (CUR != ')') {
        !          10376:            XP_ERROR(XPATH_EXPR_ERROR);
        !          10377:        }
        !          10378:        NEXT;
        !          10379:        SKIP_BLANKS;
        !          10380:     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
        !          10381:        xmlXPathCompNumber(ctxt);
        !          10382:     } else if ((CUR == '\'') || (CUR == '"')) {
        !          10383:        xmlXPathCompLiteral(ctxt);
        !          10384:     } else {
        !          10385:        xmlXPathCompFunctionCall(ctxt);
        !          10386:     }
        !          10387:     SKIP_BLANKS;
        !          10388: }
        !          10389: 
        !          10390: /**
        !          10391:  * xmlXPathCompFilterExpr:
        !          10392:  * @ctxt:  the XPath Parser context
        !          10393:  *
        !          10394:  *  [20]   FilterExpr ::=   PrimaryExpr
        !          10395:  *               | FilterExpr Predicate
        !          10396:  *
        !          10397:  * Compile a filter expression.
        !          10398:  * Square brackets are used to filter expressions in the same way that
        !          10399:  * they are used in location paths. It is an error if the expression to
        !          10400:  * be filtered does not evaluate to a node-set. The context node list
        !          10401:  * used for evaluating the expression in square brackets is the node-set
        !          10402:  * to be filtered listed in document order.
        !          10403:  */
        !          10404: 
        !          10405: static void
        !          10406: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
        !          10407:     xmlXPathCompPrimaryExpr(ctxt);
        !          10408:     CHECK_ERROR;
        !          10409:     SKIP_BLANKS;
        !          10410: 
        !          10411:     while (CUR == '[') {
        !          10412:        xmlXPathCompPredicate(ctxt, 1);
        !          10413:        SKIP_BLANKS;
        !          10414:     }
        !          10415: 
        !          10416: 
        !          10417: }
        !          10418: 
        !          10419: /**
        !          10420:  * xmlXPathScanName:
        !          10421:  * @ctxt:  the XPath Parser context
        !          10422:  *
        !          10423:  * Trickery: parse an XML name but without consuming the input flow
        !          10424:  * Needed to avoid insanity in the parser state.
        !          10425:  *
        !          10426:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
        !          10427:  *                  CombiningChar | Extender
        !          10428:  *
        !          10429:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
        !          10430:  *
        !          10431:  * [6] Names ::= Name (S Name)*
        !          10432:  *
        !          10433:  * Returns the Name parsed or NULL
        !          10434:  */
        !          10435: 
        !          10436: static xmlChar *
        !          10437: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
        !          10438:     int len = 0, l;
        !          10439:     int c;
        !          10440:     const xmlChar *cur;
        !          10441:     xmlChar *ret;
        !          10442: 
        !          10443:     cur = ctxt->cur;
        !          10444: 
        !          10445:     c = CUR_CHAR(l);
        !          10446:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
        !          10447:        (!IS_LETTER(c) && (c != '_') &&
        !          10448:          (c != ':'))) {
        !          10449:        return(NULL);
        !          10450:     }
        !          10451: 
        !          10452:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
        !          10453:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
        !          10454:             (c == '.') || (c == '-') ||
        !          10455:            (c == '_') || (c == ':') ||
        !          10456:            (IS_COMBINING(c)) ||
        !          10457:            (IS_EXTENDER(c)))) {
        !          10458:        len += l;
        !          10459:        NEXTL(l);
        !          10460:        c = CUR_CHAR(l);
        !          10461:     }
        !          10462:     ret = xmlStrndup(cur, ctxt->cur - cur);
        !          10463:     ctxt->cur = cur;
        !          10464:     return(ret);
        !          10465: }
        !          10466: 
        !          10467: /**
        !          10468:  * xmlXPathCompPathExpr:
        !          10469:  * @ctxt:  the XPath Parser context
        !          10470:  *
        !          10471:  *  [19]   PathExpr ::=   LocationPath
        !          10472:  *               | FilterExpr
        !          10473:  *               | FilterExpr '/' RelativeLocationPath
        !          10474:  *               | FilterExpr '//' RelativeLocationPath
        !          10475:  *
        !          10476:  * Compile a path expression.
        !          10477:  * The / operator and // operators combine an arbitrary expression
        !          10478:  * and a relative location path. It is an error if the expression
        !          10479:  * does not evaluate to a node-set.
        !          10480:  * The / operator does composition in the same way as when / is
        !          10481:  * used in a location path. As in location paths, // is short for
        !          10482:  * /descendant-or-self::node()/.
        !          10483:  */
        !          10484: 
        !          10485: static void
        !          10486: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
        !          10487:     int lc = 1;           /* Should we branch to LocationPath ?         */
        !          10488:     xmlChar *name = NULL; /* we may have to preparse a name to find out */
        !          10489: 
        !          10490:     SKIP_BLANKS;
        !          10491:     if ((CUR == '$') || (CUR == '(') ||
        !          10492:        (IS_ASCII_DIGIT(CUR)) ||
        !          10493:         (CUR == '\'') || (CUR == '"') ||
        !          10494:        (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
        !          10495:        lc = 0;
        !          10496:     } else if (CUR == '*') {
        !          10497:        /* relative or absolute location path */
        !          10498:        lc = 1;
        !          10499:     } else if (CUR == '/') {
        !          10500:        /* relative or absolute location path */
        !          10501:        lc = 1;
        !          10502:     } else if (CUR == '@') {
        !          10503:        /* relative abbreviated attribute location path */
        !          10504:        lc = 1;
        !          10505:     } else if (CUR == '.') {
        !          10506:        /* relative abbreviated attribute location path */
        !          10507:        lc = 1;
        !          10508:     } else {
        !          10509:        /*
        !          10510:         * Problem is finding if we have a name here whether it's:
        !          10511:         *   - a nodetype
        !          10512:         *   - a function call in which case it's followed by '('
        !          10513:         *   - an axis in which case it's followed by ':'
        !          10514:         *   - a element name
        !          10515:         * We do an a priori analysis here rather than having to
        !          10516:         * maintain parsed token content through the recursive function
        !          10517:         * calls. This looks uglier but makes the code easier to
        !          10518:         * read/write/debug.
        !          10519:         */
        !          10520:        SKIP_BLANKS;
        !          10521:        name = xmlXPathScanName(ctxt);
        !          10522:        if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
        !          10523: #ifdef DEBUG_STEP
        !          10524:            xmlGenericError(xmlGenericErrorContext,
        !          10525:                    "PathExpr: Axis\n");
        !          10526: #endif
        !          10527:            lc = 1;
        !          10528:            xmlFree(name);
        !          10529:        } else if (name != NULL) {
        !          10530:            int len =xmlStrlen(name);
        !          10531: 
        !          10532: 
        !          10533:            while (NXT(len) != 0) {
        !          10534:                if (NXT(len) == '/') {
        !          10535:                    /* element name */
        !          10536: #ifdef DEBUG_STEP
        !          10537:                    xmlGenericError(xmlGenericErrorContext,
        !          10538:                            "PathExpr: AbbrRelLocation\n");
        !          10539: #endif
        !          10540:                    lc = 1;
        !          10541:                    break;
        !          10542:                } else if (IS_BLANK_CH(NXT(len))) {
        !          10543:                    /* ignore blanks */
        !          10544:                    ;
        !          10545:                } else if (NXT(len) == ':') {
        !          10546: #ifdef DEBUG_STEP
        !          10547:                    xmlGenericError(xmlGenericErrorContext,
        !          10548:                            "PathExpr: AbbrRelLocation\n");
        !          10549: #endif
        !          10550:                    lc = 1;
        !          10551:                    break;
        !          10552:                } else if ((NXT(len) == '(')) {
        !          10553:                    /* Note Type or Function */
        !          10554:                    if (xmlXPathIsNodeType(name)) {
        !          10555: #ifdef DEBUG_STEP
        !          10556:                        xmlGenericError(xmlGenericErrorContext,
        !          10557:                                "PathExpr: Type search\n");
        !          10558: #endif
        !          10559:                        lc = 1;
        !          10560:                    } else {
        !          10561: #ifdef DEBUG_STEP
        !          10562:                        xmlGenericError(xmlGenericErrorContext,
        !          10563:                                "PathExpr: function call\n");
        !          10564: #endif
        !          10565:                        lc = 0;
        !          10566:                    }
        !          10567:                     break;
        !          10568:                } else if ((NXT(len) == '[')) {
        !          10569:                    /* element name */
        !          10570: #ifdef DEBUG_STEP
        !          10571:                    xmlGenericError(xmlGenericErrorContext,
        !          10572:                            "PathExpr: AbbrRelLocation\n");
        !          10573: #endif
        !          10574:                    lc = 1;
        !          10575:                    break;
        !          10576:                } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
        !          10577:                           (NXT(len) == '=')) {
        !          10578:                    lc = 1;
        !          10579:                    break;
        !          10580:                } else {
        !          10581:                    lc = 1;
        !          10582:                    break;
        !          10583:                }
        !          10584:                len++;
        !          10585:            }
        !          10586:            if (NXT(len) == 0) {
        !          10587: #ifdef DEBUG_STEP
        !          10588:                xmlGenericError(xmlGenericErrorContext,
        !          10589:                        "PathExpr: AbbrRelLocation\n");
        !          10590: #endif
        !          10591:                /* element name */
        !          10592:                lc = 1;
        !          10593:            }
        !          10594:            xmlFree(name);
        !          10595:        } else {
        !          10596:            /* make sure all cases are covered explicitly */
        !          10597:            XP_ERROR(XPATH_EXPR_ERROR);
        !          10598:        }
        !          10599:     }
        !          10600: 
        !          10601:     if (lc) {
        !          10602:        if (CUR == '/') {
        !          10603:            PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
        !          10604:        } else {
        !          10605:            PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
        !          10606:        }
        !          10607:        xmlXPathCompLocationPath(ctxt);
        !          10608:     } else {
        !          10609:        xmlXPathCompFilterExpr(ctxt);
        !          10610:        CHECK_ERROR;
        !          10611:        if ((CUR == '/') && (NXT(1) == '/')) {
        !          10612:            SKIP(2);
        !          10613:            SKIP_BLANKS;
        !          10614: 
        !          10615:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
        !          10616:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
        !          10617:            PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
        !          10618: 
        !          10619:            xmlXPathCompRelativeLocationPath(ctxt);
        !          10620:        } else if (CUR == '/') {
        !          10621:            xmlXPathCompRelativeLocationPath(ctxt);
        !          10622:        }
        !          10623:     }
        !          10624:     SKIP_BLANKS;
        !          10625: }
        !          10626: 
        !          10627: /**
        !          10628:  * xmlXPathCompUnionExpr:
        !          10629:  * @ctxt:  the XPath Parser context
        !          10630:  *
        !          10631:  *  [18]   UnionExpr ::=   PathExpr
        !          10632:  *               | UnionExpr '|' PathExpr
        !          10633:  *
        !          10634:  * Compile an union expression.
        !          10635:  */
        !          10636: 
        !          10637: static void
        !          10638: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
        !          10639:     xmlXPathCompPathExpr(ctxt);
        !          10640:     CHECK_ERROR;
        !          10641:     SKIP_BLANKS;
        !          10642:     while (CUR == '|') {
        !          10643:        int op1 = ctxt->comp->last;
        !          10644:        PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
        !          10645: 
        !          10646:        NEXT;
        !          10647:        SKIP_BLANKS;
        !          10648:        xmlXPathCompPathExpr(ctxt);
        !          10649: 
        !          10650:        PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
        !          10651: 
        !          10652:        SKIP_BLANKS;
        !          10653:     }
        !          10654: }
        !          10655: 
        !          10656: /**
        !          10657:  * xmlXPathCompUnaryExpr:
        !          10658:  * @ctxt:  the XPath Parser context
        !          10659:  *
        !          10660:  *  [27]   UnaryExpr ::=   UnionExpr
        !          10661:  *                   | '-' UnaryExpr
        !          10662:  *
        !          10663:  * Compile an unary expression.
        !          10664:  */
        !          10665: 
        !          10666: static void
        !          10667: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
        !          10668:     int minus = 0;
        !          10669:     int found = 0;
        !          10670: 
        !          10671:     SKIP_BLANKS;
        !          10672:     while (CUR == '-') {
        !          10673:         minus = 1 - minus;
        !          10674:        found = 1;
        !          10675:        NEXT;
        !          10676:        SKIP_BLANKS;
        !          10677:     }
        !          10678: 
        !          10679:     xmlXPathCompUnionExpr(ctxt);
        !          10680:     CHECK_ERROR;
        !          10681:     if (found) {
        !          10682:        if (minus)
        !          10683:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
        !          10684:        else
        !          10685:            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
        !          10686:     }
        !          10687: }
        !          10688: 
        !          10689: /**
        !          10690:  * xmlXPathCompMultiplicativeExpr:
        !          10691:  * @ctxt:  the XPath Parser context
        !          10692:  *
        !          10693:  *  [26]   MultiplicativeExpr ::=   UnaryExpr
        !          10694:  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
        !          10695:  *                   | MultiplicativeExpr 'div' UnaryExpr
        !          10696:  *                   | MultiplicativeExpr 'mod' UnaryExpr
        !          10697:  *  [34]   MultiplyOperator ::=   '*'
        !          10698:  *
        !          10699:  * Compile an Additive expression.
        !          10700:  */
        !          10701: 
        !          10702: static void
        !          10703: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
        !          10704:     xmlXPathCompUnaryExpr(ctxt);
        !          10705:     CHECK_ERROR;
        !          10706:     SKIP_BLANKS;
        !          10707:     while ((CUR == '*') ||
        !          10708:            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
        !          10709:            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
        !          10710:        int op = -1;
        !          10711:        int op1 = ctxt->comp->last;
        !          10712: 
        !          10713:         if (CUR == '*') {
        !          10714:            op = 0;
        !          10715:            NEXT;
        !          10716:        } else if (CUR == 'd') {
        !          10717:            op = 1;
        !          10718:            SKIP(3);
        !          10719:        } else if (CUR == 'm') {
        !          10720:            op = 2;
        !          10721:            SKIP(3);
        !          10722:        }
        !          10723:        SKIP_BLANKS;
        !          10724:         xmlXPathCompUnaryExpr(ctxt);
        !          10725:        CHECK_ERROR;
        !          10726:        PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
        !          10727:        SKIP_BLANKS;
        !          10728:     }
        !          10729: }
        !          10730: 
        !          10731: /**
        !          10732:  * xmlXPathCompAdditiveExpr:
        !          10733:  * @ctxt:  the XPath Parser context
        !          10734:  *
        !          10735:  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
        !          10736:  *                   | AdditiveExpr '+' MultiplicativeExpr
        !          10737:  *                   | AdditiveExpr '-' MultiplicativeExpr
        !          10738:  *
        !          10739:  * Compile an Additive expression.
        !          10740:  */
        !          10741: 
        !          10742: static void
        !          10743: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
        !          10744: 
        !          10745:     xmlXPathCompMultiplicativeExpr(ctxt);
        !          10746:     CHECK_ERROR;
        !          10747:     SKIP_BLANKS;
        !          10748:     while ((CUR == '+') || (CUR == '-')) {
        !          10749:        int plus;
        !          10750:        int op1 = ctxt->comp->last;
        !          10751: 
        !          10752:         if (CUR == '+') plus = 1;
        !          10753:        else plus = 0;
        !          10754:        NEXT;
        !          10755:        SKIP_BLANKS;
        !          10756:         xmlXPathCompMultiplicativeExpr(ctxt);
        !          10757:        CHECK_ERROR;
        !          10758:        PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
        !          10759:        SKIP_BLANKS;
        !          10760:     }
        !          10761: }
        !          10762: 
        !          10763: /**
        !          10764:  * xmlXPathCompRelationalExpr:
        !          10765:  * @ctxt:  the XPath Parser context
        !          10766:  *
        !          10767:  *  [24]   RelationalExpr ::=   AdditiveExpr
        !          10768:  *                 | RelationalExpr '<' AdditiveExpr
        !          10769:  *                 | RelationalExpr '>' AdditiveExpr
        !          10770:  *                 | RelationalExpr '<=' AdditiveExpr
        !          10771:  *                 | RelationalExpr '>=' AdditiveExpr
        !          10772:  *
        !          10773:  *  A <= B > C is allowed ? Answer from James, yes with
        !          10774:  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
        !          10775:  *  which is basically what got implemented.
        !          10776:  *
        !          10777:  * Compile a Relational expression, then push the result
        !          10778:  * on the stack
        !          10779:  */
        !          10780: 
        !          10781: static void
        !          10782: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
        !          10783:     xmlXPathCompAdditiveExpr(ctxt);
        !          10784:     CHECK_ERROR;
        !          10785:     SKIP_BLANKS;
        !          10786:     while ((CUR == '<') ||
        !          10787:            (CUR == '>') ||
        !          10788:            ((CUR == '<') && (NXT(1) == '=')) ||
        !          10789:            ((CUR == '>') && (NXT(1) == '='))) {
        !          10790:        int inf, strict;
        !          10791:        int op1 = ctxt->comp->last;
        !          10792: 
        !          10793:         if (CUR == '<') inf = 1;
        !          10794:        else inf = 0;
        !          10795:        if (NXT(1) == '=') strict = 0;
        !          10796:        else strict = 1;
        !          10797:        NEXT;
        !          10798:        if (!strict) NEXT;
        !          10799:        SKIP_BLANKS;
        !          10800:         xmlXPathCompAdditiveExpr(ctxt);
        !          10801:        CHECK_ERROR;
        !          10802:        PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
        !          10803:        SKIP_BLANKS;
        !          10804:     }
        !          10805: }
        !          10806: 
        !          10807: /**
        !          10808:  * xmlXPathCompEqualityExpr:
        !          10809:  * @ctxt:  the XPath Parser context
        !          10810:  *
        !          10811:  *  [23]   EqualityExpr ::=   RelationalExpr
        !          10812:  *                 | EqualityExpr '=' RelationalExpr
        !          10813:  *                 | EqualityExpr '!=' RelationalExpr
        !          10814:  *
        !          10815:  *  A != B != C is allowed ? Answer from James, yes with
        !          10816:  *  (RelationalExpr = RelationalExpr) = RelationalExpr
        !          10817:  *  (RelationalExpr != RelationalExpr) != RelationalExpr
        !          10818:  *  which is basically what got implemented.
        !          10819:  *
        !          10820:  * Compile an Equality expression.
        !          10821:  *
        !          10822:  */
        !          10823: static void
        !          10824: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
        !          10825:     xmlXPathCompRelationalExpr(ctxt);
        !          10826:     CHECK_ERROR;
        !          10827:     SKIP_BLANKS;
        !          10828:     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
        !          10829:        int eq;
        !          10830:        int op1 = ctxt->comp->last;
        !          10831: 
        !          10832:         if (CUR == '=') eq = 1;
        !          10833:        else eq = 0;
        !          10834:        NEXT;
        !          10835:        if (!eq) NEXT;
        !          10836:        SKIP_BLANKS;
        !          10837:         xmlXPathCompRelationalExpr(ctxt);
        !          10838:        CHECK_ERROR;
        !          10839:        PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
        !          10840:        SKIP_BLANKS;
        !          10841:     }
        !          10842: }
        !          10843: 
        !          10844: /**
        !          10845:  * xmlXPathCompAndExpr:
        !          10846:  * @ctxt:  the XPath Parser context
        !          10847:  *
        !          10848:  *  [22]   AndExpr ::=   EqualityExpr
        !          10849:  *                 | AndExpr 'and' EqualityExpr
        !          10850:  *
        !          10851:  * Compile an AND expression.
        !          10852:  *
        !          10853:  */
        !          10854: static void
        !          10855: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
        !          10856:     xmlXPathCompEqualityExpr(ctxt);
        !          10857:     CHECK_ERROR;
        !          10858:     SKIP_BLANKS;
        !          10859:     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
        !          10860:        int op1 = ctxt->comp->last;
        !          10861:         SKIP(3);
        !          10862:        SKIP_BLANKS;
        !          10863:         xmlXPathCompEqualityExpr(ctxt);
        !          10864:        CHECK_ERROR;
        !          10865:        PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
        !          10866:        SKIP_BLANKS;
        !          10867:     }
        !          10868: }
        !          10869: 
        !          10870: /**
        !          10871:  * xmlXPathCompileExpr:
        !          10872:  * @ctxt:  the XPath Parser context
        !          10873:  *
        !          10874:  *  [14]   Expr ::=   OrExpr
        !          10875:  *  [21]   OrExpr ::=   AndExpr
        !          10876:  *                 | OrExpr 'or' AndExpr
        !          10877:  *
        !          10878:  * Parse and compile an expression
        !          10879:  */
        !          10880: static void
        !          10881: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
        !          10882:     xmlXPathCompAndExpr(ctxt);
        !          10883:     CHECK_ERROR;
        !          10884:     SKIP_BLANKS;
        !          10885:     while ((CUR == 'o') && (NXT(1) == 'r')) {
        !          10886:        int op1 = ctxt->comp->last;
        !          10887:         SKIP(2);
        !          10888:        SKIP_BLANKS;
        !          10889:         xmlXPathCompAndExpr(ctxt);
        !          10890:        CHECK_ERROR;
        !          10891:        PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
        !          10892:        SKIP_BLANKS;
        !          10893:     }
        !          10894:     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
        !          10895:        /* more ops could be optimized too */
        !          10896:        /*
        !          10897:        * This is the main place to eliminate sorting for
        !          10898:        * operations which don't require a sorted node-set.
        !          10899:        * E.g. count().
        !          10900:        */
        !          10901:        PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
        !          10902:     }
        !          10903: }
        !          10904: 
        !          10905: /**
        !          10906:  * xmlXPathCompPredicate:
        !          10907:  * @ctxt:  the XPath Parser context
        !          10908:  * @filter:  act as a filter
        !          10909:  *
        !          10910:  *  [8]   Predicate ::=   '[' PredicateExpr ']'
        !          10911:  *  [9]   PredicateExpr ::=   Expr
        !          10912:  *
        !          10913:  * Compile a predicate expression
        !          10914:  */
        !          10915: static void
        !          10916: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
        !          10917:     int op1 = ctxt->comp->last;
        !          10918: 
        !          10919:     SKIP_BLANKS;
        !          10920:     if (CUR != '[') {
        !          10921:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
        !          10922:     }
        !          10923:     NEXT;
        !          10924:     SKIP_BLANKS;
        !          10925: 
        !          10926:     ctxt->comp->last = -1;
        !          10927:     /*
        !          10928:     * This call to xmlXPathCompileExpr() will deactivate sorting
        !          10929:     * of the predicate result.
        !          10930:     * TODO: Sorting is still activated for filters, since I'm not
        !          10931:     *  sure if needed. Normally sorting should not be needed, since
        !          10932:     *  a filter can only diminish the number of items in a sequence,
        !          10933:     *  but won't change its order; so if the initial sequence is sorted,
        !          10934:     *  subsequent sorting is not needed.
        !          10935:     */
        !          10936:     if (! filter)
        !          10937:        xmlXPathCompileExpr(ctxt, 0);
        !          10938:     else
        !          10939:        xmlXPathCompileExpr(ctxt, 1);
        !          10940:     CHECK_ERROR;
        !          10941: 
        !          10942:     if (CUR != ']') {
        !          10943:        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
        !          10944:     }
        !          10945: 
        !          10946:     if (filter)
        !          10947:        PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
        !          10948:     else
        !          10949:        PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
        !          10950: 
        !          10951:     NEXT;
        !          10952:     SKIP_BLANKS;
        !          10953: }
        !          10954: 
        !          10955: /**
        !          10956:  * xmlXPathCompNodeTest:
        !          10957:  * @ctxt:  the XPath Parser context
        !          10958:  * @test:  pointer to a xmlXPathTestVal
        !          10959:  * @type:  pointer to a xmlXPathTypeVal
        !          10960:  * @prefix:  placeholder for a possible name prefix
        !          10961:  *
        !          10962:  * [7] NodeTest ::=   NameTest
        !          10963:  *                 | NodeType '(' ')'
        !          10964:  *                 | 'processing-instruction' '(' Literal ')'
        !          10965:  *
        !          10966:  * [37] NameTest ::=  '*'
        !          10967:  *                 | NCName ':' '*'
        !          10968:  *                 | QName
        !          10969:  * [38] NodeType ::= 'comment'
        !          10970:  *                | 'text'
        !          10971:  *                | 'processing-instruction'
        !          10972:  *                | 'node'
        !          10973:  *
        !          10974:  * Returns the name found and updates @test, @type and @prefix appropriately
        !          10975:  */
        !          10976: static xmlChar *
        !          10977: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
        !          10978:                     xmlXPathTypeVal *type, const xmlChar **prefix,
        !          10979:                     xmlChar *name) {
        !          10980:     int blanks;
        !          10981: 
        !          10982:     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
        !          10983:        STRANGE;
        !          10984:        return(NULL);
        !          10985:     }
        !          10986:     *type = (xmlXPathTypeVal) 0;
        !          10987:     *test = (xmlXPathTestVal) 0;
        !          10988:     *prefix = NULL;
        !          10989:     SKIP_BLANKS;
        !          10990: 
        !          10991:     if ((name == NULL) && (CUR == '*')) {
        !          10992:        /*
        !          10993:         * All elements
        !          10994:         */
        !          10995:        NEXT;
        !          10996:        *test = NODE_TEST_ALL;
        !          10997:        return(NULL);
        !          10998:     }
        !          10999: 
        !          11000:     if (name == NULL)
        !          11001:        name = xmlXPathParseNCName(ctxt);
        !          11002:     if (name == NULL) {
        !          11003:        XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          11004:     }
        !          11005: 
        !          11006:     blanks = IS_BLANK_CH(CUR);
        !          11007:     SKIP_BLANKS;
        !          11008:     if (CUR == '(') {
        !          11009:        NEXT;
        !          11010:        /*
        !          11011:         * NodeType or PI search
        !          11012:         */
        !          11013:        if (xmlStrEqual(name, BAD_CAST "comment"))
        !          11014:            *type = NODE_TYPE_COMMENT;
        !          11015:        else if (xmlStrEqual(name, BAD_CAST "node"))
        !          11016:            *type = NODE_TYPE_NODE;
        !          11017:        else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
        !          11018:            *type = NODE_TYPE_PI;
        !          11019:        else if (xmlStrEqual(name, BAD_CAST "text"))
        !          11020:            *type = NODE_TYPE_TEXT;
        !          11021:        else {
        !          11022:            if (name != NULL)
        !          11023:                xmlFree(name);
        !          11024:            XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          11025:        }
        !          11026: 
        !          11027:        *test = NODE_TEST_TYPE;
        !          11028: 
        !          11029:        SKIP_BLANKS;
        !          11030:        if (*type == NODE_TYPE_PI) {
        !          11031:            /*
        !          11032:             * Specific case: search a PI by name.
        !          11033:             */
        !          11034:            if (name != NULL)
        !          11035:                xmlFree(name);
        !          11036:            name = NULL;
        !          11037:            if (CUR != ')') {
        !          11038:                name = xmlXPathParseLiteral(ctxt);
        !          11039:                CHECK_ERROR NULL;
        !          11040:                *test = NODE_TEST_PI;
        !          11041:                SKIP_BLANKS;
        !          11042:            }
        !          11043:        }
        !          11044:        if (CUR != ')') {
        !          11045:            if (name != NULL)
        !          11046:                xmlFree(name);
        !          11047:            XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
        !          11048:        }
        !          11049:        NEXT;
        !          11050:        return(name);
        !          11051:     }
        !          11052:     *test = NODE_TEST_NAME;
        !          11053:     if ((!blanks) && (CUR == ':')) {
        !          11054:        NEXT;
        !          11055: 
        !          11056:        /*
        !          11057:         * Since currently the parser context don't have a
        !          11058:         * namespace list associated:
        !          11059:         * The namespace name for this prefix can be computed
        !          11060:         * only at evaluation time. The compilation is done
        !          11061:         * outside of any context.
        !          11062:         */
        !          11063: #if 0
        !          11064:        *prefix = xmlXPathNsLookup(ctxt->context, name);
        !          11065:        if (name != NULL)
        !          11066:            xmlFree(name);
        !          11067:        if (*prefix == NULL) {
        !          11068:            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
        !          11069:        }
        !          11070: #else
        !          11071:        *prefix = name;
        !          11072: #endif
        !          11073: 
        !          11074:        if (CUR == '*') {
        !          11075:            /*
        !          11076:             * All elements
        !          11077:             */
        !          11078:            NEXT;
        !          11079:            *test = NODE_TEST_ALL;
        !          11080:            return(NULL);
        !          11081:        }
        !          11082: 
        !          11083:        name = xmlXPathParseNCName(ctxt);
        !          11084:        if (name == NULL) {
        !          11085:            XP_ERRORNULL(XPATH_EXPR_ERROR);
        !          11086:        }
        !          11087:     }
        !          11088:     return(name);
        !          11089: }
        !          11090: 
        !          11091: /**
        !          11092:  * xmlXPathIsAxisName:
        !          11093:  * @name:  a preparsed name token
        !          11094:  *
        !          11095:  * [6] AxisName ::=   'ancestor'
        !          11096:  *                  | 'ancestor-or-self'
        !          11097:  *                  | 'attribute'
        !          11098:  *                  | 'child'
        !          11099:  *                  | 'descendant'
        !          11100:  *                  | 'descendant-or-self'
        !          11101:  *                  | 'following'
        !          11102:  *                  | 'following-sibling'
        !          11103:  *                  | 'namespace'
        !          11104:  *                  | 'parent'
        !          11105:  *                  | 'preceding'
        !          11106:  *                  | 'preceding-sibling'
        !          11107:  *                  | 'self'
        !          11108:  *
        !          11109:  * Returns the axis or 0
        !          11110:  */
        !          11111: static xmlXPathAxisVal
        !          11112: xmlXPathIsAxisName(const xmlChar *name) {
        !          11113:     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
        !          11114:     switch (name[0]) {
        !          11115:        case 'a':
        !          11116:            if (xmlStrEqual(name, BAD_CAST "ancestor"))
        !          11117:                ret = AXIS_ANCESTOR;
        !          11118:            if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
        !          11119:                ret = AXIS_ANCESTOR_OR_SELF;
        !          11120:            if (xmlStrEqual(name, BAD_CAST "attribute"))
        !          11121:                ret = AXIS_ATTRIBUTE;
        !          11122:            break;
        !          11123:        case 'c':
        !          11124:            if (xmlStrEqual(name, BAD_CAST "child"))
        !          11125:                ret = AXIS_CHILD;
        !          11126:            break;
        !          11127:        case 'd':
        !          11128:            if (xmlStrEqual(name, BAD_CAST "descendant"))
        !          11129:                ret = AXIS_DESCENDANT;
        !          11130:            if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
        !          11131:                ret = AXIS_DESCENDANT_OR_SELF;
        !          11132:            break;
        !          11133:        case 'f':
        !          11134:            if (xmlStrEqual(name, BAD_CAST "following"))
        !          11135:                ret = AXIS_FOLLOWING;
        !          11136:            if (xmlStrEqual(name, BAD_CAST "following-sibling"))
        !          11137:                ret = AXIS_FOLLOWING_SIBLING;
        !          11138:            break;
        !          11139:        case 'n':
        !          11140:            if (xmlStrEqual(name, BAD_CAST "namespace"))
        !          11141:                ret = AXIS_NAMESPACE;
        !          11142:            break;
        !          11143:        case 'p':
        !          11144:            if (xmlStrEqual(name, BAD_CAST "parent"))
        !          11145:                ret = AXIS_PARENT;
        !          11146:            if (xmlStrEqual(name, BAD_CAST "preceding"))
        !          11147:                ret = AXIS_PRECEDING;
        !          11148:            if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
        !          11149:                ret = AXIS_PRECEDING_SIBLING;
        !          11150:            break;
        !          11151:        case 's':
        !          11152:            if (xmlStrEqual(name, BAD_CAST "self"))
        !          11153:                ret = AXIS_SELF;
        !          11154:            break;
        !          11155:     }
        !          11156:     return(ret);
        !          11157: }
        !          11158: 
        !          11159: /**
        !          11160:  * xmlXPathCompStep:
        !          11161:  * @ctxt:  the XPath Parser context
        !          11162:  *
        !          11163:  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
        !          11164:  *                  | AbbreviatedStep
        !          11165:  *
        !          11166:  * [12] AbbreviatedStep ::=   '.' | '..'
        !          11167:  *
        !          11168:  * [5] AxisSpecifier ::= AxisName '::'
        !          11169:  *                  | AbbreviatedAxisSpecifier
        !          11170:  *
        !          11171:  * [13] AbbreviatedAxisSpecifier ::= '@'?
        !          11172:  *
        !          11173:  * Modified for XPtr range support as:
        !          11174:  *
        !          11175:  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
        !          11176:  *                     | AbbreviatedStep
        !          11177:  *                     | 'range-to' '(' Expr ')' Predicate*
        !          11178:  *
        !          11179:  * Compile one step in a Location Path
        !          11180:  * A location step of . is short for self::node(). This is
        !          11181:  * particularly useful in conjunction with //. For example, the
        !          11182:  * location path .//para is short for
        !          11183:  * self::node()/descendant-or-self::node()/child::para
        !          11184:  * and so will select all para descendant elements of the context
        !          11185:  * node.
        !          11186:  * Similarly, a location step of .. is short for parent::node().
        !          11187:  * For example, ../title is short for parent::node()/child::title
        !          11188:  * and so will select the title children of the parent of the context
        !          11189:  * node.
        !          11190:  */
        !          11191: static void
        !          11192: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
        !          11193: #ifdef LIBXML_XPTR_ENABLED
        !          11194:     int rangeto = 0;
        !          11195:     int op2 = -1;
        !          11196: #endif
        !          11197: 
        !          11198:     SKIP_BLANKS;
        !          11199:     if ((CUR == '.') && (NXT(1) == '.')) {
        !          11200:        SKIP(2);
        !          11201:        SKIP_BLANKS;
        !          11202:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
        !          11203:                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
        !          11204:     } else if (CUR == '.') {
        !          11205:        NEXT;
        !          11206:        SKIP_BLANKS;
        !          11207:     } else {
        !          11208:        xmlChar *name = NULL;
        !          11209:        const xmlChar *prefix = NULL;
        !          11210:        xmlXPathTestVal test = (xmlXPathTestVal) 0;
        !          11211:        xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
        !          11212:        xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
        !          11213:        int op1;
        !          11214: 
        !          11215:        /*
        !          11216:         * The modification needed for XPointer change to the production
        !          11217:         */
        !          11218: #ifdef LIBXML_XPTR_ENABLED
        !          11219:        if (ctxt->xptr) {
        !          11220:            name = xmlXPathParseNCName(ctxt);
        !          11221:            if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
        !          11222:                 op2 = ctxt->comp->last;
        !          11223:                xmlFree(name);
        !          11224:                SKIP_BLANKS;
        !          11225:                if (CUR != '(') {
        !          11226:                    XP_ERROR(XPATH_EXPR_ERROR);
        !          11227:                }
        !          11228:                NEXT;
        !          11229:                SKIP_BLANKS;
        !          11230: 
        !          11231:                xmlXPathCompileExpr(ctxt, 1);
        !          11232:                /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
        !          11233:                CHECK_ERROR;
        !          11234: 
        !          11235:                SKIP_BLANKS;
        !          11236:                if (CUR != ')') {
        !          11237:                    XP_ERROR(XPATH_EXPR_ERROR);
        !          11238:                }
        !          11239:                NEXT;
        !          11240:                rangeto = 1;
        !          11241:                goto eval_predicates;
        !          11242:            }
        !          11243:        }
        !          11244: #endif
        !          11245:        if (CUR == '*') {
        !          11246:            axis = AXIS_CHILD;
        !          11247:        } else {
        !          11248:            if (name == NULL)
        !          11249:                name = xmlXPathParseNCName(ctxt);
        !          11250:            if (name != NULL) {
        !          11251:                axis = xmlXPathIsAxisName(name);
        !          11252:                if (axis != 0) {
        !          11253:                    SKIP_BLANKS;
        !          11254:                    if ((CUR == ':') && (NXT(1) == ':')) {
        !          11255:                        SKIP(2);
        !          11256:                        xmlFree(name);
        !          11257:                        name = NULL;
        !          11258:                    } else {
        !          11259:                        /* an element name can conflict with an axis one :-\ */
        !          11260:                        axis = AXIS_CHILD;
        !          11261:                    }
        !          11262:                } else {
        !          11263:                    axis = AXIS_CHILD;
        !          11264:                }
        !          11265:            } else if (CUR == '@') {
        !          11266:                NEXT;
        !          11267:                axis = AXIS_ATTRIBUTE;
        !          11268:            } else {
        !          11269:                axis = AXIS_CHILD;
        !          11270:            }
        !          11271:        }
        !          11272: 
        !          11273:         if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          11274:             xmlFree(name);
        !          11275:             return;
        !          11276:         }
        !          11277: 
        !          11278:        name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
        !          11279:        if (test == 0)
        !          11280:            return;
        !          11281: 
        !          11282:         if ((prefix != NULL) && (ctxt->context != NULL) &&
        !          11283:            (ctxt->context->flags & XML_XPATH_CHECKNS)) {
        !          11284:            if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
        !          11285:                xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
        !          11286:            }
        !          11287:        }
        !          11288: #ifdef DEBUG_STEP
        !          11289:        xmlGenericError(xmlGenericErrorContext,
        !          11290:                "Basis : computing new set\n");
        !          11291: #endif
        !          11292: 
        !          11293: #ifdef DEBUG_STEP
        !          11294:        xmlGenericError(xmlGenericErrorContext, "Basis : ");
        !          11295:        if (ctxt->value == NULL)
        !          11296:            xmlGenericError(xmlGenericErrorContext, "no value\n");
        !          11297:        else if (ctxt->value->nodesetval == NULL)
        !          11298:            xmlGenericError(xmlGenericErrorContext, "Empty\n");
        !          11299:        else
        !          11300:            xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
        !          11301: #endif
        !          11302: 
        !          11303: #ifdef LIBXML_XPTR_ENABLED
        !          11304: eval_predicates:
        !          11305: #endif
        !          11306:        op1 = ctxt->comp->last;
        !          11307:        ctxt->comp->last = -1;
        !          11308: 
        !          11309:        SKIP_BLANKS;
        !          11310:        while (CUR == '[') {
        !          11311:            xmlXPathCompPredicate(ctxt, 0);
        !          11312:        }
        !          11313: 
        !          11314: #ifdef LIBXML_XPTR_ENABLED
        !          11315:        if (rangeto) {
        !          11316:            PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
        !          11317:        } else
        !          11318: #endif
        !          11319:            PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
        !          11320:                           test, type, (void *)prefix, (void *)name);
        !          11321: 
        !          11322:     }
        !          11323: #ifdef DEBUG_STEP
        !          11324:     xmlGenericError(xmlGenericErrorContext, "Step : ");
        !          11325:     if (ctxt->value == NULL)
        !          11326:        xmlGenericError(xmlGenericErrorContext, "no value\n");
        !          11327:     else if (ctxt->value->nodesetval == NULL)
        !          11328:        xmlGenericError(xmlGenericErrorContext, "Empty\n");
        !          11329:     else
        !          11330:        xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
        !          11331:                ctxt->value->nodesetval);
        !          11332: #endif
        !          11333: }
        !          11334: 
        !          11335: /**
        !          11336:  * xmlXPathCompRelativeLocationPath:
        !          11337:  * @ctxt:  the XPath Parser context
        !          11338:  *
        !          11339:  *  [3]   RelativeLocationPath ::=   Step
        !          11340:  *                     | RelativeLocationPath '/' Step
        !          11341:  *                     | AbbreviatedRelativeLocationPath
        !          11342:  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
        !          11343:  *
        !          11344:  * Compile a relative location path.
        !          11345:  */
        !          11346: static void
        !          11347: xmlXPathCompRelativeLocationPath
        !          11348: (xmlXPathParserContextPtr ctxt) {
        !          11349:     SKIP_BLANKS;
        !          11350:     if ((CUR == '/') && (NXT(1) == '/')) {
        !          11351:        SKIP(2);
        !          11352:        SKIP_BLANKS;
        !          11353:        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
        !          11354:                         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
        !          11355:     } else if (CUR == '/') {
        !          11356:            NEXT;
        !          11357:        SKIP_BLANKS;
        !          11358:     }
        !          11359:     xmlXPathCompStep(ctxt);
        !          11360:     CHECK_ERROR;
        !          11361:     SKIP_BLANKS;
        !          11362:     while (CUR == '/') {
        !          11363:        if ((CUR == '/') && (NXT(1) == '/')) {
        !          11364:            SKIP(2);
        !          11365:            SKIP_BLANKS;
        !          11366:            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
        !          11367:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
        !          11368:            xmlXPathCompStep(ctxt);
        !          11369:        } else if (CUR == '/') {
        !          11370:            NEXT;
        !          11371:            SKIP_BLANKS;
        !          11372:            xmlXPathCompStep(ctxt);
        !          11373:        }
        !          11374:        SKIP_BLANKS;
        !          11375:     }
        !          11376: }
        !          11377: 
        !          11378: /**
        !          11379:  * xmlXPathCompLocationPath:
        !          11380:  * @ctxt:  the XPath Parser context
        !          11381:  *
        !          11382:  *  [1]   LocationPath ::=   RelativeLocationPath
        !          11383:  *                     | AbsoluteLocationPath
        !          11384:  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
        !          11385:  *                     | AbbreviatedAbsoluteLocationPath
        !          11386:  *  [10]   AbbreviatedAbsoluteLocationPath ::=
        !          11387:  *                           '//' RelativeLocationPath
        !          11388:  *
        !          11389:  * Compile a location path
        !          11390:  *
        !          11391:  * // is short for /descendant-or-self::node()/. For example,
        !          11392:  * //para is short for /descendant-or-self::node()/child::para and
        !          11393:  * so will select any para element in the document (even a para element
        !          11394:  * that is a document element will be selected by //para since the
        !          11395:  * document element node is a child of the root node); div//para is
        !          11396:  * short for div/descendant-or-self::node()/child::para and so will
        !          11397:  * select all para descendants of div children.
        !          11398:  */
        !          11399: static void
        !          11400: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
        !          11401:     SKIP_BLANKS;
        !          11402:     if (CUR != '/') {
        !          11403:         xmlXPathCompRelativeLocationPath(ctxt);
        !          11404:     } else {
        !          11405:        while (CUR == '/') {
        !          11406:            if ((CUR == '/') && (NXT(1) == '/')) {
        !          11407:                SKIP(2);
        !          11408:                SKIP_BLANKS;
        !          11409:                PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
        !          11410:                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
        !          11411:                xmlXPathCompRelativeLocationPath(ctxt);
        !          11412:            } else if (CUR == '/') {
        !          11413:                NEXT;
        !          11414:                SKIP_BLANKS;
        !          11415:                if ((CUR != 0 ) &&
        !          11416:                    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
        !          11417:                     (CUR == '@') || (CUR == '*')))
        !          11418:                    xmlXPathCompRelativeLocationPath(ctxt);
        !          11419:            }
        !          11420:            CHECK_ERROR;
        !          11421:        }
        !          11422:     }
        !          11423: }
        !          11424: 
        !          11425: /************************************************************************
        !          11426:  *                                                                     *
        !          11427:  *             XPath precompiled expression evaluation                 *
        !          11428:  *                                                                     *
        !          11429:  ************************************************************************/
        !          11430: 
        !          11431: static int
        !          11432: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
        !          11433: 
        !          11434: #ifdef DEBUG_STEP
        !          11435: static void
        !          11436: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
        !          11437:                          int nbNodes)
        !          11438: {
        !          11439:     xmlGenericError(xmlGenericErrorContext, "new step : ");
        !          11440:     switch (op->value) {
        !          11441:         case AXIS_ANCESTOR:
        !          11442:             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
        !          11443:             break;
        !          11444:         case AXIS_ANCESTOR_OR_SELF:
        !          11445:             xmlGenericError(xmlGenericErrorContext,
        !          11446:                             "axis 'ancestors-or-self' ");
        !          11447:             break;
        !          11448:         case AXIS_ATTRIBUTE:
        !          11449:             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
        !          11450:             break;
        !          11451:         case AXIS_CHILD:
        !          11452:             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
        !          11453:             break;
        !          11454:         case AXIS_DESCENDANT:
        !          11455:             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
        !          11456:             break;
        !          11457:         case AXIS_DESCENDANT_OR_SELF:
        !          11458:             xmlGenericError(xmlGenericErrorContext,
        !          11459:                             "axis 'descendant-or-self' ");
        !          11460:             break;
        !          11461:         case AXIS_FOLLOWING:
        !          11462:             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
        !          11463:             break;
        !          11464:         case AXIS_FOLLOWING_SIBLING:
        !          11465:             xmlGenericError(xmlGenericErrorContext,
        !          11466:                             "axis 'following-siblings' ");
        !          11467:             break;
        !          11468:         case AXIS_NAMESPACE:
        !          11469:             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
        !          11470:             break;
        !          11471:         case AXIS_PARENT:
        !          11472:             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
        !          11473:             break;
        !          11474:         case AXIS_PRECEDING:
        !          11475:             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
        !          11476:             break;
        !          11477:         case AXIS_PRECEDING_SIBLING:
        !          11478:             xmlGenericError(xmlGenericErrorContext,
        !          11479:                             "axis 'preceding-sibling' ");
        !          11480:             break;
        !          11481:         case AXIS_SELF:
        !          11482:             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
        !          11483:             break;
        !          11484:     }
        !          11485:     xmlGenericError(xmlGenericErrorContext,
        !          11486:        " context contains %d nodes\n", nbNodes);
        !          11487:     switch (op->value2) {
        !          11488:         case NODE_TEST_NONE:
        !          11489:             xmlGenericError(xmlGenericErrorContext,
        !          11490:                             "           searching for none !!!\n");
        !          11491:             break;
        !          11492:         case NODE_TEST_TYPE:
        !          11493:             xmlGenericError(xmlGenericErrorContext,
        !          11494:                             "           searching for type %d\n", op->value3);
        !          11495:             break;
        !          11496:         case NODE_TEST_PI:
        !          11497:             xmlGenericError(xmlGenericErrorContext,
        !          11498:                             "           searching for PI !!!\n");
        !          11499:             break;
        !          11500:         case NODE_TEST_ALL:
        !          11501:             xmlGenericError(xmlGenericErrorContext,
        !          11502:                             "           searching for *\n");
        !          11503:             break;
        !          11504:         case NODE_TEST_NS:
        !          11505:             xmlGenericError(xmlGenericErrorContext,
        !          11506:                             "           searching for namespace %s\n",
        !          11507:                             op->value5);
        !          11508:             break;
        !          11509:         case NODE_TEST_NAME:
        !          11510:             xmlGenericError(xmlGenericErrorContext,
        !          11511:                             "           searching for name %s\n", op->value5);
        !          11512:             if (op->value4)
        !          11513:                 xmlGenericError(xmlGenericErrorContext,
        !          11514:                                 "           with namespace %s\n", op->value4);
        !          11515:             break;
        !          11516:     }
        !          11517:     xmlGenericError(xmlGenericErrorContext, "Testing : ");
        !          11518: }
        !          11519: #endif /* DEBUG_STEP */
        !          11520: 
        !          11521: static int
        !          11522: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
        !          11523:                            xmlXPathStepOpPtr op,
        !          11524:                            xmlNodeSetPtr set,
        !          11525:                            int contextSize,
        !          11526:                            int hasNsNodes)
        !          11527: {
        !          11528:     if (op->ch1 != -1) {
        !          11529:        xmlXPathCompExprPtr comp = ctxt->comp;
        !          11530:        /*
        !          11531:        * Process inner predicates first.
        !          11532:        */
        !          11533:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
        !          11534:            /*
        !          11535:            * TODO: raise an internal error.
        !          11536:            */
        !          11537:        }
        !          11538:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
        !          11539:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
        !          11540:        CHECK_ERROR0;
        !          11541:        if (contextSize <= 0)
        !          11542:            return(0);
        !          11543:     }
        !          11544:     if (op->ch2 != -1) {
        !          11545:        xmlXPathContextPtr xpctxt = ctxt->context;
        !          11546:        xmlNodePtr contextNode, oldContextNode;
        !          11547:        xmlDocPtr oldContextDoc;
        !          11548:        int i, res, contextPos = 0, newContextSize;
        !          11549:        xmlXPathStepOpPtr exprOp;
        !          11550:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
        !          11551: 
        !          11552: #ifdef LIBXML_XPTR_ENABLED
        !          11553:        /*
        !          11554:        * URGENT TODO: Check the following:
        !          11555:        *  We don't expect location sets if evaluating prediates, right?
        !          11556:        *  Only filters should expect location sets, right?
        !          11557:        */
        !          11558: #endif
        !          11559:        /*
        !          11560:        * SPEC XPath 1.0:
        !          11561:        *  "For each node in the node-set to be filtered, the
        !          11562:        *  PredicateExpr is evaluated with that node as the
        !          11563:        *  context node, with the number of nodes in the
        !          11564:        *  node-set as the context size, and with the proximity
        !          11565:        *  position of the node in the node-set with respect to
        !          11566:        *  the axis as the context position;"
        !          11567:        * @oldset is the node-set" to be filtered.
        !          11568:        *
        !          11569:        * SPEC XPath 1.0:
        !          11570:        *  "only predicates change the context position and
        !          11571:        *  context size (see [2.4 Predicates])."
        !          11572:        * Example:
        !          11573:        *   node-set  context pos
        !          11574:        *    nA         1
        !          11575:        *    nB         2
        !          11576:        *    nC         3
        !          11577:        *   After applying predicate [position() > 1] :
        !          11578:        *   node-set  context pos
        !          11579:        *    nB         1
        !          11580:        *    nC         2
        !          11581:        */
        !          11582:        oldContextNode = xpctxt->node;
        !          11583:        oldContextDoc = xpctxt->doc;
        !          11584:        /*
        !          11585:        * Get the expression of this predicate.
        !          11586:        */
        !          11587:        exprOp = &ctxt->comp->steps[op->ch2];
        !          11588:        newContextSize = 0;
        !          11589:        for (i = 0; i < set->nodeNr; i++) {
        !          11590:            if (set->nodeTab[i] == NULL)
        !          11591:                continue;
        !          11592: 
        !          11593:            contextNode = set->nodeTab[i];
        !          11594:            xpctxt->node = contextNode;
        !          11595:            xpctxt->contextSize = contextSize;
        !          11596:            xpctxt->proximityPosition = ++contextPos;
        !          11597: 
        !          11598:            /*
        !          11599:            * Also set the xpath document in case things like
        !          11600:            * key() are evaluated in the predicate.
        !          11601:            */
        !          11602:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
        !          11603:                (contextNode->doc != NULL))
        !          11604:                xpctxt->doc = contextNode->doc;
        !          11605:            /*
        !          11606:            * Evaluate the predicate expression with 1 context node
        !          11607:            * at a time; this node is packaged into a node set; this
        !          11608:            * node set is handed over to the evaluation mechanism.
        !          11609:            */
        !          11610:            if (contextObj == NULL)
        !          11611:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
        !          11612:            else
        !          11613:                xmlXPathNodeSetAddUnique(contextObj->nodesetval,
        !          11614:                    contextNode);
        !          11615: 
        !          11616:            valuePush(ctxt, contextObj);
        !          11617: 
        !          11618:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
        !          11619: 
        !          11620:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
        !          11621:                xmlXPathNodeSetClear(set, hasNsNodes);
        !          11622:                newContextSize = 0;
        !          11623:                goto evaluation_exit;
        !          11624:            }
        !          11625: 
        !          11626:            if (res != 0) {
        !          11627:                newContextSize++;
        !          11628:            } else {
        !          11629:                /*
        !          11630:                * Remove the entry from the initial node set.
        !          11631:                */
        !          11632:                set->nodeTab[i] = NULL;
        !          11633:                if (contextNode->type == XML_NAMESPACE_DECL)
        !          11634:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
        !          11635:            }
        !          11636:            if (ctxt->value == contextObj) {
        !          11637:                /*
        !          11638:                * Don't free the temporary XPath object holding the
        !          11639:                * context node, in order to avoid massive recreation
        !          11640:                * inside this loop.
        !          11641:                */
        !          11642:                valuePop(ctxt);
        !          11643:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
        !          11644:            } else {
        !          11645:                /*
        !          11646:                * TODO: The object was lost in the evaluation machinery.
        !          11647:                *  Can this happen? Maybe in internal-error cases.
        !          11648:                */
        !          11649:                contextObj = NULL;
        !          11650:            }
        !          11651:        }
        !          11652: 
        !          11653:        if (contextObj != NULL) {
        !          11654:            if (ctxt->value == contextObj)
        !          11655:                valuePop(ctxt);
        !          11656:            xmlXPathReleaseObject(xpctxt, contextObj);
        !          11657:        }
        !          11658: evaluation_exit:
        !          11659:        if (exprRes != NULL)
        !          11660:            xmlXPathReleaseObject(ctxt->context, exprRes);
        !          11661:        /*
        !          11662:        * Reset/invalidate the context.
        !          11663:        */
        !          11664:        xpctxt->node = oldContextNode;
        !          11665:        xpctxt->doc = oldContextDoc;
        !          11666:        xpctxt->contextSize = -1;
        !          11667:        xpctxt->proximityPosition = -1;
        !          11668:        return(newContextSize);
        !          11669:     }
        !          11670:     return(contextSize);
        !          11671: }
        !          11672: 
        !          11673: static int
        !          11674: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
        !          11675:                                      xmlXPathStepOpPtr op,
        !          11676:                                      xmlNodeSetPtr set,
        !          11677:                                      int contextSize,
        !          11678:                                      int minPos,
        !          11679:                                      int maxPos,
        !          11680:                                      int hasNsNodes)
        !          11681: {
        !          11682:     if (op->ch1 != -1) {
        !          11683:        xmlXPathCompExprPtr comp = ctxt->comp;
        !          11684:        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
        !          11685:            /*
        !          11686:            * TODO: raise an internal error.
        !          11687:            */
        !          11688:        }
        !          11689:        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
        !          11690:            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
        !          11691:        CHECK_ERROR0;
        !          11692:        if (contextSize <= 0)
        !          11693:            return(0);
        !          11694:     }
        !          11695:     /*
        !          11696:     * Check if the node set contains a sufficient number of nodes for
        !          11697:     * the requested range.
        !          11698:     */
        !          11699:     if (contextSize < minPos) {
        !          11700:        xmlXPathNodeSetClear(set, hasNsNodes);
        !          11701:        return(0);
        !          11702:     }
        !          11703:     if (op->ch2 == -1) {
        !          11704:        /*
        !          11705:        * TODO: Can this ever happen?
        !          11706:        */
        !          11707:        return (contextSize);
        !          11708:     } else {
        !          11709:        xmlDocPtr oldContextDoc;
        !          11710:        int i, pos = 0, newContextSize = 0, contextPos = 0, res;
        !          11711:        xmlXPathStepOpPtr exprOp;
        !          11712:        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
        !          11713:        xmlNodePtr oldContextNode, contextNode = NULL;
        !          11714:        xmlXPathContextPtr xpctxt = ctxt->context;
        !          11715: 
        !          11716: #ifdef LIBXML_XPTR_ENABLED
        !          11717:            /*
        !          11718:            * URGENT TODO: Check the following:
        !          11719:            *  We don't expect location sets if evaluating prediates, right?
        !          11720:            *  Only filters should expect location sets, right?
        !          11721:        */
        !          11722: #endif /* LIBXML_XPTR_ENABLED */
        !          11723: 
        !          11724:        /*
        !          11725:        * Save old context.
        !          11726:        */
        !          11727:        oldContextNode = xpctxt->node;
        !          11728:        oldContextDoc = xpctxt->doc;
        !          11729:        /*
        !          11730:        * Get the expression of this predicate.
        !          11731:        */
        !          11732:        exprOp = &ctxt->comp->steps[op->ch2];
        !          11733:        for (i = 0; i < set->nodeNr; i++) {
        !          11734:            if (set->nodeTab[i] == NULL)
        !          11735:                continue;
        !          11736: 
        !          11737:            contextNode = set->nodeTab[i];
        !          11738:            xpctxt->node = contextNode;
        !          11739:            xpctxt->contextSize = contextSize;
        !          11740:            xpctxt->proximityPosition = ++contextPos;
        !          11741: 
        !          11742:            /*
        !          11743:            * Initialize the new set.
        !          11744:            * Also set the xpath document in case things like
        !          11745:            * key() evaluation are attempted on the predicate
        !          11746:            */
        !          11747:            if ((contextNode->type != XML_NAMESPACE_DECL) &&
        !          11748:                (contextNode->doc != NULL))
        !          11749:                xpctxt->doc = contextNode->doc;
        !          11750:            /*
        !          11751:            * Evaluate the predicate expression with 1 context node
        !          11752:            * at a time; this node is packaged into a node set; this
        !          11753:            * node set is handed over to the evaluation mechanism.
        !          11754:            */
        !          11755:            if (contextObj == NULL)
        !          11756:                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
        !          11757:            else
        !          11758:                xmlXPathNodeSetAddUnique(contextObj->nodesetval,
        !          11759:                    contextNode);
        !          11760: 
        !          11761:            valuePush(ctxt, contextObj);
        !          11762:            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
        !          11763: 
        !          11764:            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
        !          11765:                xmlXPathObjectPtr tmp;
        !          11766:                /* pop the result */
        !          11767:                tmp = valuePop(ctxt);
        !          11768:                xmlXPathReleaseObject(xpctxt, tmp);
        !          11769:                /* then pop off contextObj, which will be freed later */
        !          11770:                valuePop(ctxt);
        !          11771:                goto evaluation_error;
        !          11772:            }
        !          11773: 
        !          11774:            if (res)
        !          11775:                pos++;
        !          11776: 
        !          11777:            if (res && (pos >= minPos) && (pos <= maxPos)) {
        !          11778:                /*
        !          11779:                * Fits in the requested range.
        !          11780:                */
        !          11781:                newContextSize++;
        !          11782:                if (minPos == maxPos) {
        !          11783:                    /*
        !          11784:                    * Only 1 node was requested.
        !          11785:                    */
        !          11786:                    if (contextNode->type == XML_NAMESPACE_DECL) {
        !          11787:                        /*
        !          11788:                        * As always: take care of those nasty
        !          11789:                        * namespace nodes.
        !          11790:                        */
        !          11791:                        set->nodeTab[i] = NULL;
        !          11792:                    }
        !          11793:                    xmlXPathNodeSetClear(set, hasNsNodes);
        !          11794:                    set->nodeNr = 1;
        !          11795:                    set->nodeTab[0] = contextNode;
        !          11796:                    goto evaluation_exit;
        !          11797:                }
        !          11798:                if (pos == maxPos) {
        !          11799:                    /*
        !          11800:                    * We are done.
        !          11801:                    */
        !          11802:                    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
        !          11803:                    goto evaluation_exit;
        !          11804:                }
        !          11805:            } else {
        !          11806:                /*
        !          11807:                * Remove the entry from the initial node set.
        !          11808:                */
        !          11809:                set->nodeTab[i] = NULL;
        !          11810:                if (contextNode->type == XML_NAMESPACE_DECL)
        !          11811:                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
        !          11812:            }
        !          11813:            if (exprRes != NULL) {
        !          11814:                xmlXPathReleaseObject(ctxt->context, exprRes);
        !          11815:                exprRes = NULL;
        !          11816:            }
        !          11817:            if (ctxt->value == contextObj) {
        !          11818:                /*
        !          11819:                * Don't free the temporary XPath object holding the
        !          11820:                * context node, in order to avoid massive recreation
        !          11821:                * inside this loop.
        !          11822:                */
        !          11823:                valuePop(ctxt);
        !          11824:                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
        !          11825:            } else {
        !          11826:                /*
        !          11827:                * The object was lost in the evaluation machinery.
        !          11828:                * Can this happen? Maybe in case of internal-errors.
        !          11829:                */
        !          11830:                contextObj = NULL;
        !          11831:            }
        !          11832:        }
        !          11833:        goto evaluation_exit;
        !          11834: 
        !          11835: evaluation_error:
        !          11836:        xmlXPathNodeSetClear(set, hasNsNodes);
        !          11837:        newContextSize = 0;
        !          11838: 
        !          11839: evaluation_exit:
        !          11840:        if (contextObj != NULL) {
        !          11841:            if (ctxt->value == contextObj)
        !          11842:                valuePop(ctxt);
        !          11843:            xmlXPathReleaseObject(xpctxt, contextObj);
        !          11844:        }
        !          11845:        if (exprRes != NULL)
        !          11846:            xmlXPathReleaseObject(ctxt->context, exprRes);
        !          11847:        /*
        !          11848:        * Reset/invalidate the context.
        !          11849:        */
        !          11850:        xpctxt->node = oldContextNode;
        !          11851:        xpctxt->doc = oldContextDoc;
        !          11852:        xpctxt->contextSize = -1;
        !          11853:        xpctxt->proximityPosition = -1;
        !          11854:        return(newContextSize);
        !          11855:     }
        !          11856:     return(contextSize);
        !          11857: }
        !          11858: 
        !          11859: static int
        !          11860: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
        !          11861:                            xmlXPathStepOpPtr op,
        !          11862:                            int *maxPos)
        !          11863: {
        !          11864: 
        !          11865:     xmlXPathStepOpPtr exprOp;
        !          11866: 
        !          11867:     /*
        !          11868:     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
        !          11869:     */
        !          11870: 
        !          11871:     /*
        !          11872:     * If not -1, then ch1 will point to:
        !          11873:     * 1) For predicates (XPATH_OP_PREDICATE):
        !          11874:     *    - an inner predicate operator
        !          11875:     * 2) For filters (XPATH_OP_FILTER):
        !          11876:     *    - an inner filter operater OR
        !          11877:     *    - an expression selecting the node set.
        !          11878:     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
        !          11879:     */
        !          11880:     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
        !          11881:        return(0);
        !          11882: 
        !          11883:     if (op->ch2 != -1) {
        !          11884:        exprOp = &ctxt->comp->steps[op->ch2];
        !          11885:     } else
        !          11886:        return(0);
        !          11887: 
        !          11888:     if ((exprOp != NULL) &&
        !          11889:        (exprOp->op == XPATH_OP_VALUE) &&
        !          11890:        (exprOp->value4 != NULL) &&
        !          11891:        (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
        !          11892:     {
        !          11893:        /*
        !          11894:        * We have a "[n]" predicate here.
        !          11895:        * TODO: Unfortunately this simplistic test here is not
        !          11896:        * able to detect a position() predicate in compound
        !          11897:        * expressions like "[@attr = 'a" and position() = 1],
        !          11898:        * and even not the usage of position() in
        !          11899:        * "[position() = 1]"; thus - obviously - a position-range,
        !          11900:        * like it "[position() < 5]", is also not detected.
        !          11901:        * Maybe we could rewrite the AST to ease the optimization.
        !          11902:        */
        !          11903:        *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
        !          11904: 
        !          11905:        if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
        !          11906:            (float) *maxPos)
        !          11907:        {
        !          11908:            return(1);
        !          11909:        }
        !          11910:     }
        !          11911:     return(0);
        !          11912: }
        !          11913: 
        !          11914: static int
        !          11915: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
        !          11916:                            xmlXPathStepOpPtr op,
        !          11917:                           xmlNodePtr * first, xmlNodePtr * last,
        !          11918:                           int toBool)
        !          11919: {
        !          11920: 
        !          11921: #define XP_TEST_HIT \
        !          11922:     if (hasAxisRange != 0) { \
        !          11923:        if (++pos == maxPos) { \
        !          11924:            addNode(seq, cur); \
        !          11925:        goto axis_range_end; } \
        !          11926:     } else { \
        !          11927:        addNode(seq, cur); \
        !          11928:        if (breakOnFirstHit) goto first_hit; }
        !          11929: 
        !          11930: #define XP_TEST_HIT_NS \
        !          11931:     if (hasAxisRange != 0) { \
        !          11932:        if (++pos == maxPos) { \
        !          11933:            hasNsNodes = 1; \
        !          11934:            xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
        !          11935:        goto axis_range_end; } \
        !          11936:     } else { \
        !          11937:        hasNsNodes = 1; \
        !          11938:        xmlXPathNodeSetAddNs(seq, \
        !          11939:        xpctxt->node, (xmlNsPtr) cur); \
        !          11940:        if (breakOnFirstHit) goto first_hit; }
        !          11941: 
        !          11942:     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
        !          11943:     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
        !          11944:     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
        !          11945:     const xmlChar *prefix = op->value4;
        !          11946:     const xmlChar *name = op->value5;
        !          11947:     const xmlChar *URI = NULL;
        !          11948: 
        !          11949: #ifdef DEBUG_STEP
        !          11950:     int nbMatches = 0, prevMatches = 0;
        !          11951: #endif
        !          11952:     int total = 0, hasNsNodes = 0;
        !          11953:     /* The popped object holding the context nodes */
        !          11954:     xmlXPathObjectPtr obj;
        !          11955:     /* The set of context nodes for the node tests */
        !          11956:     xmlNodeSetPtr contextSeq;
        !          11957:     int contextIdx;
        !          11958:     xmlNodePtr contextNode;
        !          11959:     /* The context node for a compound traversal */
        !          11960:     xmlNodePtr outerContextNode;
        !          11961:     /* The final resulting node set wrt to all context nodes */
        !          11962:     xmlNodeSetPtr outSeq;
        !          11963:     /*
        !          11964:     * The temporary resulting node set wrt 1 context node.
        !          11965:     * Used to feed predicate evaluation.
        !          11966:     */
        !          11967:     xmlNodeSetPtr seq;
        !          11968:     xmlNodePtr cur;
        !          11969:     /* First predicate operator */
        !          11970:     xmlXPathStepOpPtr predOp;
        !          11971:     int maxPos; /* The requested position() (when a "[n]" predicate) */
        !          11972:     int hasPredicateRange, hasAxisRange, pos, size, newSize;
        !          11973:     int breakOnFirstHit;
        !          11974: 
        !          11975:     xmlXPathTraversalFunction next = NULL;
        !          11976:     /* compound axis traversal */
        !          11977:     xmlXPathTraversalFunctionExt outerNext = NULL;
        !          11978:     void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
        !          11979:     xmlXPathNodeSetMergeFunction mergeAndClear;
        !          11980:     xmlNodePtr oldContextNode;
        !          11981:     xmlXPathContextPtr xpctxt = ctxt->context;
        !          11982: 
        !          11983: 
        !          11984:     CHECK_TYPE0(XPATH_NODESET);
        !          11985:     obj = valuePop(ctxt);
        !          11986:     /*
        !          11987:     * Setup namespaces.
        !          11988:     */
        !          11989:     if (prefix != NULL) {
        !          11990:         URI = xmlXPathNsLookup(xpctxt, prefix);
        !          11991:         if (URI == NULL) {
        !          11992:            xmlXPathReleaseObject(xpctxt, obj);
        !          11993:             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
        !          11994:        }
        !          11995:     }
        !          11996:     /*
        !          11997:     * Setup axis.
        !          11998:     *
        !          11999:     * MAYBE FUTURE TODO: merging optimizations:
        !          12000:     * - If the nodes to be traversed wrt to the initial nodes and
        !          12001:     *   the current axis cannot overlap, then we could avoid searching
        !          12002:     *   for duplicates during the merge.
        !          12003:     *   But the question is how/when to evaluate if they cannot overlap.
        !          12004:     *   Example: if we know that for two initial nodes, the one is
        !          12005:     *   not in the ancestor-or-self axis of the other, then we could safely
        !          12006:     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
        !          12007:     *   the descendant-or-self axis.
        !          12008:     */
        !          12009:     mergeAndClear = xmlXPathNodeSetMergeAndClear;
        !          12010:     switch (axis) {
        !          12011:         case AXIS_ANCESTOR:
        !          12012:             first = NULL;
        !          12013:             next = xmlXPathNextAncestor;
        !          12014:             break;
        !          12015:         case AXIS_ANCESTOR_OR_SELF:
        !          12016:             first = NULL;
        !          12017:             next = xmlXPathNextAncestorOrSelf;
        !          12018:             break;
        !          12019:         case AXIS_ATTRIBUTE:
        !          12020:             first = NULL;
        !          12021:            last = NULL;
        !          12022:             next = xmlXPathNextAttribute;
        !          12023:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
        !          12024:             break;
        !          12025:         case AXIS_CHILD:
        !          12026:            last = NULL;
        !          12027:            if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
        !          12028:                /*
        !          12029:                * This iterator will give us only nodes which can
        !          12030:                * hold element nodes.
        !          12031:                */
        !          12032:                outerNext = xmlXPathNextDescendantOrSelfElemParent;
        !          12033:            }
        !          12034:            if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
        !          12035:                (type == NODE_TYPE_NODE))
        !          12036:            {
        !          12037:                /*
        !          12038:                * Optimization if an element node type is 'element'.
        !          12039:                */
        !          12040:                next = xmlXPathNextChildElement;
        !          12041:            } else
        !          12042:                next = xmlXPathNextChild;
        !          12043:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
        !          12044:             break;
        !          12045:         case AXIS_DESCENDANT:
        !          12046:            last = NULL;
        !          12047:             next = xmlXPathNextDescendant;
        !          12048:             break;
        !          12049:         case AXIS_DESCENDANT_OR_SELF:
        !          12050:            last = NULL;
        !          12051:             next = xmlXPathNextDescendantOrSelf;
        !          12052:             break;
        !          12053:         case AXIS_FOLLOWING:
        !          12054:            last = NULL;
        !          12055:             next = xmlXPathNextFollowing;
        !          12056:             break;
        !          12057:         case AXIS_FOLLOWING_SIBLING:
        !          12058:            last = NULL;
        !          12059:             next = xmlXPathNextFollowingSibling;
        !          12060:             break;
        !          12061:         case AXIS_NAMESPACE:
        !          12062:             first = NULL;
        !          12063:            last = NULL;
        !          12064:             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
        !          12065:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
        !          12066:             break;
        !          12067:         case AXIS_PARENT:
        !          12068:             first = NULL;
        !          12069:             next = xmlXPathNextParent;
        !          12070:             break;
        !          12071:         case AXIS_PRECEDING:
        !          12072:             first = NULL;
        !          12073:             next = xmlXPathNextPrecedingInternal;
        !          12074:             break;
        !          12075:         case AXIS_PRECEDING_SIBLING:
        !          12076:             first = NULL;
        !          12077:             next = xmlXPathNextPrecedingSibling;
        !          12078:             break;
        !          12079:         case AXIS_SELF:
        !          12080:             first = NULL;
        !          12081:            last = NULL;
        !          12082:             next = xmlXPathNextSelf;
        !          12083:            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
        !          12084:             break;
        !          12085:     }
        !          12086: 
        !          12087: #ifdef DEBUG_STEP
        !          12088:     xmlXPathDebugDumpStepAxis(op,
        !          12089:        (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
        !          12090: #endif
        !          12091: 
        !          12092:     if (next == NULL) {
        !          12093:        xmlXPathReleaseObject(xpctxt, obj);
        !          12094:         return(0);
        !          12095:     }
        !          12096:     contextSeq = obj->nodesetval;
        !          12097:     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
        !          12098:        xmlXPathReleaseObject(xpctxt, obj);
        !          12099:         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
        !          12100:         return(0);
        !          12101:     }
        !          12102:     /*
        !          12103:     * Predicate optimization ---------------------------------------------
        !          12104:     * If this step has a last predicate, which contains a position(),
        !          12105:     * then we'll optimize (although not exactly "position()", but only
        !          12106:     * the  short-hand form, i.e., "[n]".
        !          12107:     *
        !          12108:     * Example - expression "/foo[parent::bar][1]":
        !          12109:     *
        !          12110:     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
        !          12111:     *   ROOT                               -- op->ch1
        !          12112:     *   PREDICATE                          -- op->ch2 (predOp)
        !          12113:     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
        !          12114:     *       SORT
        !          12115:     *         COLLECT  'parent' 'name' 'node' bar
        !          12116:     *           NODE
        !          12117:     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
        !          12118:     *
        !          12119:     */
        !          12120:     maxPos = 0;
        !          12121:     predOp = NULL;
        !          12122:     hasPredicateRange = 0;
        !          12123:     hasAxisRange = 0;
        !          12124:     if (op->ch2 != -1) {
        !          12125:        /*
        !          12126:        * There's at least one predicate. 16 == XPATH_OP_PREDICATE
        !          12127:        */
        !          12128:        predOp = &ctxt->comp->steps[op->ch2];
        !          12129:        if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
        !          12130:            if (predOp->ch1 != -1) {
        !          12131:                /*
        !          12132:                * Use the next inner predicate operator.
        !          12133:                */
        !          12134:                predOp = &ctxt->comp->steps[predOp->ch1];
        !          12135:                hasPredicateRange = 1;
        !          12136:            } else {
        !          12137:                /*
        !          12138:                * There's no other predicate than the [n] predicate.
        !          12139:                */
        !          12140:                predOp = NULL;
        !          12141:                hasAxisRange = 1;
        !          12142:            }
        !          12143:        }
        !          12144:     }
        !          12145:     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
        !          12146:     /*
        !          12147:     * Axis traversal -----------------------------------------------------
        !          12148:     */
        !          12149:     /*
        !          12150:      * 2.3 Node Tests
        !          12151:      *  - For the attribute axis, the principal node type is attribute.
        !          12152:      *  - For the namespace axis, the principal node type is namespace.
        !          12153:      *  - For other axes, the principal node type is element.
        !          12154:      *
        !          12155:      * A node test * is true for any node of the
        !          12156:      * principal node type. For example, child::* will
        !          12157:      * select all element children of the context node
        !          12158:      */
        !          12159:     oldContextNode = xpctxt->node;
        !          12160:     addNode = xmlXPathNodeSetAddUnique;
        !          12161:     outSeq = NULL;
        !          12162:     seq = NULL;
        !          12163:     outerContextNode = NULL;
        !          12164:     contextNode = NULL;
        !          12165:     contextIdx = 0;
        !          12166: 
        !          12167: 
        !          12168:     while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
        !          12169:        if (outerNext != NULL) {
        !          12170:            /*
        !          12171:            * This is a compound traversal.
        !          12172:            */
        !          12173:            if (contextNode == NULL) {
        !          12174:                /*
        !          12175:                * Set the context for the outer traversal.
        !          12176:                */
        !          12177:                outerContextNode = contextSeq->nodeTab[contextIdx++];
        !          12178:                contextNode = outerNext(NULL, outerContextNode);
        !          12179:            } else
        !          12180:                contextNode = outerNext(contextNode, outerContextNode);
        !          12181:            if (contextNode == NULL)
        !          12182:                continue;
        !          12183:            /*
        !          12184:            * Set the context for the main traversal.
        !          12185:            */
        !          12186:            xpctxt->node = contextNode;
        !          12187:        } else
        !          12188:            xpctxt->node = contextSeq->nodeTab[contextIdx++];
        !          12189: 
        !          12190:        if (seq == NULL) {
        !          12191:            seq = xmlXPathNodeSetCreate(NULL);
        !          12192:            if (seq == NULL) {
        !          12193:                total = 0;
        !          12194:                goto error;
        !          12195:            }
        !          12196:        }
        !          12197:        /*
        !          12198:        * Traverse the axis and test the nodes.
        !          12199:        */
        !          12200:        pos = 0;
        !          12201:        cur = NULL;
        !          12202:        hasNsNodes = 0;
        !          12203:         do {
        !          12204:             cur = next(ctxt, cur);
        !          12205:             if (cur == NULL)
        !          12206:                 break;
        !          12207: 
        !          12208:            /*
        !          12209:            * QUESTION TODO: What does the "first" and "last" stuff do?
        !          12210:            */
        !          12211:             if ((first != NULL) && (*first != NULL)) {
        !          12212:                if (*first == cur)
        !          12213:                    break;
        !          12214:                if (((total % 256) == 0) &&
        !          12215: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
        !          12216:                    (xmlXPathCmpNodesExt(*first, cur) >= 0))
        !          12217: #else
        !          12218:                    (xmlXPathCmpNodes(*first, cur) >= 0))
        !          12219: #endif
        !          12220:                {
        !          12221:                    break;
        !          12222:                }
        !          12223:            }
        !          12224:            if ((last != NULL) && (*last != NULL)) {
        !          12225:                if (*last == cur)
        !          12226:                    break;
        !          12227:                if (((total % 256) == 0) &&
        !          12228: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
        !          12229:                    (xmlXPathCmpNodesExt(cur, *last) >= 0))
        !          12230: #else
        !          12231:                    (xmlXPathCmpNodes(cur, *last) >= 0))
        !          12232: #endif
        !          12233:                {
        !          12234:                    break;
        !          12235:                }
        !          12236:            }
        !          12237: 
        !          12238:             total++;
        !          12239: 
        !          12240: #ifdef DEBUG_STEP
        !          12241:             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
        !          12242: #endif
        !          12243: 
        !          12244:            switch (test) {
        !          12245:                 case NODE_TEST_NONE:
        !          12246:                    total = 0;
        !          12247:                     STRANGE
        !          12248:                    goto error;
        !          12249:                 case NODE_TEST_TYPE:
        !          12250:                    /*
        !          12251:                    * TODO: Don't we need to use
        !          12252:                    *  xmlXPathNodeSetAddNs() for namespace nodes here?
        !          12253:                    *  Surprisingly, some c14n tests fail, if we do this.
        !          12254:                    */
        !          12255:                    if (type == NODE_TYPE_NODE) {
        !          12256:                        switch (cur->type) {
        !          12257:                            case XML_DOCUMENT_NODE:
        !          12258:                            case XML_HTML_DOCUMENT_NODE:
        !          12259: #ifdef LIBXML_DOCB_ENABLED
        !          12260:                            case XML_DOCB_DOCUMENT_NODE:
        !          12261: #endif
        !          12262:                            case XML_ELEMENT_NODE:
        !          12263:                            case XML_ATTRIBUTE_NODE:
        !          12264:                            case XML_PI_NODE:
        !          12265:                            case XML_COMMENT_NODE:
        !          12266:                            case XML_CDATA_SECTION_NODE:
        !          12267:                            case XML_TEXT_NODE:
        !          12268:                            case XML_NAMESPACE_DECL:
        !          12269:                                XP_TEST_HIT
        !          12270:                                break;
        !          12271:                            default:
        !          12272:                                break;
        !          12273:                        }
        !          12274:                    } else if (cur->type == type) {
        !          12275:                        if (type == XML_NAMESPACE_DECL)
        !          12276:                            XP_TEST_HIT_NS
        !          12277:                        else
        !          12278:                            XP_TEST_HIT
        !          12279:                    } else if ((type == NODE_TYPE_TEXT) &&
        !          12280:                         (cur->type == XML_CDATA_SECTION_NODE))
        !          12281:                    {
        !          12282:                        XP_TEST_HIT
        !          12283:                    }
        !          12284:                    break;
        !          12285:                 case NODE_TEST_PI:
        !          12286:                     if ((cur->type == XML_PI_NODE) &&
        !          12287:                         ((name == NULL) || xmlStrEqual(name, cur->name)))
        !          12288:                    {
        !          12289:                        XP_TEST_HIT
        !          12290:                     }
        !          12291:                     break;
        !          12292:                 case NODE_TEST_ALL:
        !          12293:                     if (axis == AXIS_ATTRIBUTE) {
        !          12294:                         if (cur->type == XML_ATTRIBUTE_NODE)
        !          12295:                        {
        !          12296:                            XP_TEST_HIT
        !          12297:                         }
        !          12298:                     } else if (axis == AXIS_NAMESPACE) {
        !          12299:                         if (cur->type == XML_NAMESPACE_DECL)
        !          12300:                        {
        !          12301:                            XP_TEST_HIT_NS
        !          12302:                         }
        !          12303:                     } else {
        !          12304:                         if (cur->type == XML_ELEMENT_NODE) {
        !          12305:                             if (prefix == NULL)
        !          12306:                            {
        !          12307:                                XP_TEST_HIT
        !          12308: 
        !          12309:                             } else if ((cur->ns != NULL) &&
        !          12310:                                (xmlStrEqual(URI, cur->ns->href)))
        !          12311:                            {
        !          12312:                                XP_TEST_HIT
        !          12313:                             }
        !          12314:                         }
        !          12315:                     }
        !          12316:                     break;
        !          12317:                 case NODE_TEST_NS:{
        !          12318:                         TODO;
        !          12319:                         break;
        !          12320:                     }
        !          12321:                 case NODE_TEST_NAME:
        !          12322:                     if (axis == AXIS_ATTRIBUTE) {
        !          12323:                         if (cur->type != XML_ATTRIBUTE_NODE)
        !          12324:                            break;
        !          12325:                    } else if (axis == AXIS_NAMESPACE) {
        !          12326:                         if (cur->type != XML_NAMESPACE_DECL)
        !          12327:                            break;
        !          12328:                    } else {
        !          12329:                        if (cur->type != XML_ELEMENT_NODE)
        !          12330:                            break;
        !          12331:                    }
        !          12332:                     switch (cur->type) {
        !          12333:                         case XML_ELEMENT_NODE:
        !          12334:                             if (xmlStrEqual(name, cur->name)) {
        !          12335:                                 if (prefix == NULL) {
        !          12336:                                     if (cur->ns == NULL)
        !          12337:                                    {
        !          12338:                                        XP_TEST_HIT
        !          12339:                                     }
        !          12340:                                 } else {
        !          12341:                                     if ((cur->ns != NULL) &&
        !          12342:                                         (xmlStrEqual(URI, cur->ns->href)))
        !          12343:                                    {
        !          12344:                                        XP_TEST_HIT
        !          12345:                                     }
        !          12346:                                 }
        !          12347:                             }
        !          12348:                             break;
        !          12349:                         case XML_ATTRIBUTE_NODE:{
        !          12350:                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
        !          12351: 
        !          12352:                                 if (xmlStrEqual(name, attr->name)) {
        !          12353:                                     if (prefix == NULL) {
        !          12354:                                         if ((attr->ns == NULL) ||
        !          12355:                                             (attr->ns->prefix == NULL))
        !          12356:                                        {
        !          12357:                                            XP_TEST_HIT
        !          12358:                                         }
        !          12359:                                     } else {
        !          12360:                                         if ((attr->ns != NULL) &&
        !          12361:                                             (xmlStrEqual(URI,
        !          12362:                                              attr->ns->href)))
        !          12363:                                        {
        !          12364:                                            XP_TEST_HIT
        !          12365:                                         }
        !          12366:                                     }
        !          12367:                                 }
        !          12368:                                 break;
        !          12369:                             }
        !          12370:                         case XML_NAMESPACE_DECL:
        !          12371:                             if (cur->type == XML_NAMESPACE_DECL) {
        !          12372:                                 xmlNsPtr ns = (xmlNsPtr) cur;
        !          12373: 
        !          12374:                                 if ((ns->prefix != NULL) && (name != NULL)
        !          12375:                                     && (xmlStrEqual(ns->prefix, name)))
        !          12376:                                {
        !          12377:                                    XP_TEST_HIT_NS
        !          12378:                                 }
        !          12379:                             }
        !          12380:                             break;
        !          12381:                         default:
        !          12382:                             break;
        !          12383:                     }
        !          12384:                     break;
        !          12385:            } /* switch(test) */
        !          12386:         } while (cur != NULL);
        !          12387: 
        !          12388:        goto apply_predicates;
        !          12389: 
        !          12390: axis_range_end: /* ----------------------------------------------------- */
        !          12391:        /*
        !          12392:        * We have a "/foo[n]", and position() = n was reached.
        !          12393:        * Note that we can have as well "/foo/::parent::foo[1]", so
        !          12394:        * a duplicate-aware merge is still needed.
        !          12395:        * Merge with the result.
        !          12396:        */
        !          12397:        if (outSeq == NULL) {
        !          12398:            outSeq = seq;
        !          12399:            seq = NULL;
        !          12400:        } else
        !          12401:            outSeq = mergeAndClear(outSeq, seq, 0);
        !          12402:        /*
        !          12403:        * Break if only a true/false result was requested.
        !          12404:        */
        !          12405:        if (toBool)
        !          12406:            break;
        !          12407:        continue;
        !          12408: 
        !          12409: first_hit: /* ---------------------------------------------------------- */
        !          12410:        /*
        !          12411:        * Break if only a true/false result was requested and
        !          12412:        * no predicates existed and a node test succeeded.
        !          12413:        */
        !          12414:        if (outSeq == NULL) {
        !          12415:            outSeq = seq;
        !          12416:            seq = NULL;
        !          12417:        } else
        !          12418:            outSeq = mergeAndClear(outSeq, seq, 0);
        !          12419:        break;
        !          12420: 
        !          12421: #ifdef DEBUG_STEP
        !          12422:        if (seq != NULL)
        !          12423:            nbMatches += seq->nodeNr;
        !          12424: #endif
        !          12425: 
        !          12426: apply_predicates: /* --------------------------------------------------- */
        !          12427:         /*
        !          12428:        * Apply predicates.
        !          12429:        */
        !          12430:         if ((predOp != NULL) && (seq->nodeNr > 0)) {
        !          12431:            /*
        !          12432:            * E.g. when we have a "/foo[some expression][n]".
        !          12433:            */      
        !          12434:            /*
        !          12435:            * QUESTION TODO: The old predicate evaluation took into
        !          12436:            *  account location-sets.
        !          12437:            *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
        !          12438:            *  Do we expect such a set here?
        !          12439:            *  All what I learned now from the evaluation semantics
        !          12440:            *  does not indicate that a location-set will be processed
        !          12441:            *  here, so this looks OK.
        !          12442:            */      
        !          12443:            /*
        !          12444:            * Iterate over all predicates, starting with the outermost
        !          12445:            * predicate.
        !          12446:            * TODO: Problem: we cannot execute the inner predicates first
        !          12447:            *  since we cannot go back *up* the operator tree!
        !          12448:            *  Options we have:
        !          12449:            *  1) Use of recursive functions (like is it currently done
        !          12450:            *     via xmlXPathCompOpEval())
        !          12451:            *  2) Add a predicate evaluation information stack to the
        !          12452:            *     context struct
        !          12453:            *  3) Change the way the operators are linked; we need a
        !          12454:            *     "parent" field on xmlXPathStepOp
        !          12455:            *
        !          12456:            * For the moment, I'll try to solve this with a recursive
        !          12457:            * function: xmlXPathCompOpEvalPredicate().
        !          12458:            */
        !          12459:            size = seq->nodeNr;
        !          12460:            if (hasPredicateRange != 0)
        !          12461:                newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
        !          12462:                    predOp, seq, size, maxPos, maxPos, hasNsNodes);
        !          12463:            else
        !          12464:                newSize = xmlXPathCompOpEvalPredicate(ctxt,
        !          12465:                    predOp, seq, size, hasNsNodes);
        !          12466: 
        !          12467:            if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          12468:                total = 0;
        !          12469:                goto error;
        !          12470:            }
        !          12471:            /*
        !          12472:            * Add the filtered set of nodes to the result node set.
        !          12473:            */
        !          12474:            if (newSize == 0) {
        !          12475:                /*
        !          12476:                * The predicates filtered all nodes out.
        !          12477:                */
        !          12478:                xmlXPathNodeSetClear(seq, hasNsNodes);
        !          12479:            } else if (seq->nodeNr > 0) {
        !          12480:                /*
        !          12481:                * Add to result set.
        !          12482:                */
        !          12483:                if (outSeq == NULL) {
        !          12484:                    if (size != newSize) {
        !          12485:                        /*
        !          12486:                        * We need to merge and clear here, since
        !          12487:                        * the sequence will contained NULLed entries.
        !          12488:                        */
        !          12489:                        outSeq = mergeAndClear(NULL, seq, 1);
        !          12490:                    } else {
        !          12491:                        outSeq = seq;
        !          12492:                        seq = NULL;
        !          12493:                    }
        !          12494:                } else
        !          12495:                    outSeq = mergeAndClear(outSeq, seq,
        !          12496:                        (size != newSize) ? 1: 0);
        !          12497:                /*
        !          12498:                * Break if only a true/false result was requested.
        !          12499:                */
        !          12500:                if (toBool)
        !          12501:                    break;
        !          12502:            }
        !          12503:         } else if (seq->nodeNr > 0) {
        !          12504:            /*
        !          12505:            * Add to result set.
        !          12506:            */
        !          12507:            if (outSeq == NULL) {
        !          12508:                outSeq = seq;
        !          12509:                seq = NULL;
        !          12510:            } else {
        !          12511:                outSeq = mergeAndClear(outSeq, seq, 0);
        !          12512:            }
        !          12513:        }
        !          12514:     }
        !          12515: 
        !          12516: error:
        !          12517:     if ((obj->boolval) && (obj->user != NULL)) {
        !          12518:        /*
        !          12519:        * QUESTION TODO: What does this do and why?
        !          12520:        * TODO: Do we have to do this also for the "error"
        !          12521:        * cleanup further down?
        !          12522:        */
        !          12523:        ctxt->value->boolval = 1;
        !          12524:        ctxt->value->user = obj->user;
        !          12525:        obj->user = NULL;
        !          12526:        obj->boolval = 0;
        !          12527:     }
        !          12528:     xmlXPathReleaseObject(xpctxt, obj);
        !          12529: 
        !          12530:     /*
        !          12531:     * Ensure we return at least an emtpy set.
        !          12532:     */
        !          12533:     if (outSeq == NULL) {
        !          12534:        if ((seq != NULL) && (seq->nodeNr == 0))
        !          12535:            outSeq = seq;
        !          12536:        else
        !          12537:            outSeq = xmlXPathNodeSetCreate(NULL);
        !          12538:         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
        !          12539:     }
        !          12540:     if ((seq != NULL) && (seq != outSeq)) {
        !          12541:         xmlXPathFreeNodeSet(seq);
        !          12542:     }
        !          12543:     /*
        !          12544:     * Hand over the result. Better to push the set also in
        !          12545:     * case of errors.
        !          12546:     */
        !          12547:     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
        !          12548:     /*
        !          12549:     * Reset the context node.
        !          12550:     */
        !          12551:     xpctxt->node = oldContextNode;
        !          12552: 
        !          12553: #ifdef DEBUG_STEP
        !          12554:     xmlGenericError(xmlGenericErrorContext,
        !          12555:        "\nExamined %d nodes, found %d nodes at that step\n",
        !          12556:        total, nbMatches);
        !          12557: #endif
        !          12558: 
        !          12559:     return(total);
        !          12560: }
        !          12561: 
        !          12562: static int
        !          12563: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
        !          12564:                              xmlXPathStepOpPtr op, xmlNodePtr * first);
        !          12565: 
        !          12566: /**
        !          12567:  * xmlXPathCompOpEvalFirst:
        !          12568:  * @ctxt:  the XPath parser context with the compiled expression
        !          12569:  * @op:  an XPath compiled operation
        !          12570:  * @first:  the first elem found so far
        !          12571:  *
        !          12572:  * Evaluate the Precompiled XPath operation searching only the first
        !          12573:  * element in document order
        !          12574:  *
        !          12575:  * Returns the number of examined objects.
        !          12576:  */
        !          12577: static int
        !          12578: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
        !          12579:                         xmlXPathStepOpPtr op, xmlNodePtr * first)
        !          12580: {
        !          12581:     int total = 0, cur;
        !          12582:     xmlXPathCompExprPtr comp;
        !          12583:     xmlXPathObjectPtr arg1, arg2;
        !          12584: 
        !          12585:     CHECK_ERROR0;
        !          12586:     comp = ctxt->comp;
        !          12587:     switch (op->op) {
        !          12588:         case XPATH_OP_END:
        !          12589:             return (0);
        !          12590:         case XPATH_OP_UNION:
        !          12591:             total =
        !          12592:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
        !          12593:                                         first);
        !          12594:            CHECK_ERROR0;
        !          12595:             if ((ctxt->value != NULL)
        !          12596:                 && (ctxt->value->type == XPATH_NODESET)
        !          12597:                 && (ctxt->value->nodesetval != NULL)
        !          12598:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
        !          12599:                 /*
        !          12600:                  * limit tree traversing to first node in the result
        !          12601:                  */
        !          12602:                /*
        !          12603:                * OPTIMIZE TODO: This implicitely sorts
        !          12604:                *  the result, even if not needed. E.g. if the argument
        !          12605:                *  of the count() function, no sorting is needed.
        !          12606:                * OPTIMIZE TODO: How do we know if the node-list wasn't
        !          12607:                *  aready sorted?
        !          12608:                */
        !          12609:                if (ctxt->value->nodesetval->nodeNr > 1)
        !          12610:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
        !          12611:                 *first = ctxt->value->nodesetval->nodeTab[0];
        !          12612:             }
        !          12613:             cur =
        !          12614:                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
        !          12615:                                         first);
        !          12616:            CHECK_ERROR0;
        !          12617:             CHECK_TYPE0(XPATH_NODESET);
        !          12618:             arg2 = valuePop(ctxt);
        !          12619: 
        !          12620:             CHECK_TYPE0(XPATH_NODESET);
        !          12621:             arg1 = valuePop(ctxt);
        !          12622: 
        !          12623:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
        !          12624:                                                     arg2->nodesetval);
        !          12625:             valuePush(ctxt, arg1);
        !          12626:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          12627:             /* optimizer */
        !          12628:            if (total > cur)
        !          12629:                xmlXPathCompSwap(op);
        !          12630:             return (total + cur);
        !          12631:         case XPATH_OP_ROOT:
        !          12632:             xmlXPathRoot(ctxt);
        !          12633:             return (0);
        !          12634:         case XPATH_OP_NODE:
        !          12635:             if (op->ch1 != -1)
        !          12636:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12637:            CHECK_ERROR0;
        !          12638:             if (op->ch2 != -1)
        !          12639:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12640:            CHECK_ERROR0;
        !          12641:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          12642:                ctxt->context->node));
        !          12643:             return (total);
        !          12644:         case XPATH_OP_RESET:
        !          12645:             if (op->ch1 != -1)
        !          12646:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12647:            CHECK_ERROR0;
        !          12648:             if (op->ch2 != -1)
        !          12649:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12650:            CHECK_ERROR0;
        !          12651:             ctxt->context->node = NULL;
        !          12652:             return (total);
        !          12653:         case XPATH_OP_COLLECT:{
        !          12654:                 if (op->ch1 == -1)
        !          12655:                     return (total);
        !          12656: 
        !          12657:                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12658:                CHECK_ERROR0;
        !          12659: 
        !          12660:                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
        !          12661:                 return (total);
        !          12662:             }
        !          12663:         case XPATH_OP_VALUE:
        !          12664:             valuePush(ctxt,
        !          12665:                       xmlXPathCacheObjectCopy(ctxt->context,
        !          12666:                        (xmlXPathObjectPtr) op->value4));
        !          12667:             return (0);
        !          12668:         case XPATH_OP_SORT:
        !          12669:             if (op->ch1 != -1)
        !          12670:                 total +=
        !          12671:                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
        !          12672:                                             first);
        !          12673:            CHECK_ERROR0;
        !          12674:             if ((ctxt->value != NULL)
        !          12675:                 && (ctxt->value->type == XPATH_NODESET)
        !          12676:                 && (ctxt->value->nodesetval != NULL)
        !          12677:                && (ctxt->value->nodesetval->nodeNr > 1))
        !          12678:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
        !          12679:             return (total);
        !          12680: #ifdef XP_OPTIMIZED_FILTER_FIRST
        !          12681:        case XPATH_OP_FILTER:
        !          12682:                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
        !          12683:             return (total);
        !          12684: #endif
        !          12685:         default:
        !          12686:             return (xmlXPathCompOpEval(ctxt, op));
        !          12687:     }
        !          12688: }
        !          12689: 
        !          12690: /**
        !          12691:  * xmlXPathCompOpEvalLast:
        !          12692:  * @ctxt:  the XPath parser context with the compiled expression
        !          12693:  * @op:  an XPath compiled operation
        !          12694:  * @last:  the last elem found so far
        !          12695:  *
        !          12696:  * Evaluate the Precompiled XPath operation searching only the last
        !          12697:  * element in document order
        !          12698:  *
        !          12699:  * Returns the number of nodes traversed
        !          12700:  */
        !          12701: static int
        !          12702: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
        !          12703:                        xmlNodePtr * last)
        !          12704: {
        !          12705:     int total = 0, cur;
        !          12706:     xmlXPathCompExprPtr comp;
        !          12707:     xmlXPathObjectPtr arg1, arg2;
        !          12708:     xmlNodePtr bak;
        !          12709:     xmlDocPtr bakd;
        !          12710:     int pp;
        !          12711:     int cs;
        !          12712: 
        !          12713:     CHECK_ERROR0;
        !          12714:     comp = ctxt->comp;
        !          12715:     switch (op->op) {
        !          12716:         case XPATH_OP_END:
        !          12717:             return (0);
        !          12718:         case XPATH_OP_UNION:
        !          12719:            bakd = ctxt->context->doc;
        !          12720:            bak = ctxt->context->node;
        !          12721:            pp = ctxt->context->proximityPosition;
        !          12722:            cs = ctxt->context->contextSize;
        !          12723:             total =
        !          12724:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
        !          12725:            CHECK_ERROR0;
        !          12726:             if ((ctxt->value != NULL)
        !          12727:                 && (ctxt->value->type == XPATH_NODESET)
        !          12728:                 && (ctxt->value->nodesetval != NULL)
        !          12729:                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
        !          12730:                 /*
        !          12731:                  * limit tree traversing to first node in the result
        !          12732:                  */
        !          12733:                if (ctxt->value->nodesetval->nodeNr > 1)
        !          12734:                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
        !          12735:                 *last =
        !          12736:                     ctxt->value->nodesetval->nodeTab[ctxt->value->
        !          12737:                                                      nodesetval->nodeNr -
        !          12738:                                                      1];
        !          12739:             }
        !          12740:            ctxt->context->doc = bakd;
        !          12741:            ctxt->context->node = bak;
        !          12742:            ctxt->context->proximityPosition = pp;
        !          12743:            ctxt->context->contextSize = cs;
        !          12744:             cur =
        !          12745:                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
        !          12746:            CHECK_ERROR0;
        !          12747:             if ((ctxt->value != NULL)
        !          12748:                 && (ctxt->value->type == XPATH_NODESET)
        !          12749:                 && (ctxt->value->nodesetval != NULL)
        !          12750:                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
        !          12751:             }
        !          12752:             CHECK_TYPE0(XPATH_NODESET);
        !          12753:             arg2 = valuePop(ctxt);
        !          12754: 
        !          12755:             CHECK_TYPE0(XPATH_NODESET);
        !          12756:             arg1 = valuePop(ctxt);
        !          12757: 
        !          12758:             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
        !          12759:                                                     arg2->nodesetval);
        !          12760:             valuePush(ctxt, arg1);
        !          12761:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          12762:             /* optimizer */
        !          12763:            if (total > cur)
        !          12764:                xmlXPathCompSwap(op);
        !          12765:             return (total + cur);
        !          12766:         case XPATH_OP_ROOT:
        !          12767:             xmlXPathRoot(ctxt);
        !          12768:             return (0);
        !          12769:         case XPATH_OP_NODE:
        !          12770:             if (op->ch1 != -1)
        !          12771:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12772:            CHECK_ERROR0;
        !          12773:             if (op->ch2 != -1)
        !          12774:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12775:            CHECK_ERROR0;
        !          12776:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          12777:                ctxt->context->node));
        !          12778:             return (total);
        !          12779:         case XPATH_OP_RESET:
        !          12780:             if (op->ch1 != -1)
        !          12781:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12782:            CHECK_ERROR0;
        !          12783:             if (op->ch2 != -1)
        !          12784:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12785:            CHECK_ERROR0;
        !          12786:             ctxt->context->node = NULL;
        !          12787:             return (total);
        !          12788:         case XPATH_OP_COLLECT:{
        !          12789:                 if (op->ch1 == -1)
        !          12790:                     return (0);
        !          12791: 
        !          12792:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12793:                CHECK_ERROR0;
        !          12794: 
        !          12795:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
        !          12796:                 return (total);
        !          12797:             }
        !          12798:         case XPATH_OP_VALUE:
        !          12799:             valuePush(ctxt,
        !          12800:                       xmlXPathCacheObjectCopy(ctxt->context,
        !          12801:                        (xmlXPathObjectPtr) op->value4));
        !          12802:             return (0);
        !          12803:         case XPATH_OP_SORT:
        !          12804:             if (op->ch1 != -1)
        !          12805:                 total +=
        !          12806:                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
        !          12807:                                            last);
        !          12808:            CHECK_ERROR0;
        !          12809:             if ((ctxt->value != NULL)
        !          12810:                 && (ctxt->value->type == XPATH_NODESET)
        !          12811:                 && (ctxt->value->nodesetval != NULL)
        !          12812:                && (ctxt->value->nodesetval->nodeNr > 1))
        !          12813:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
        !          12814:             return (total);
        !          12815:         default:
        !          12816:             return (xmlXPathCompOpEval(ctxt, op));
        !          12817:     }
        !          12818: }
        !          12819: 
        !          12820: #ifdef XP_OPTIMIZED_FILTER_FIRST
        !          12821: static int
        !          12822: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
        !          12823:                              xmlXPathStepOpPtr op, xmlNodePtr * first)
        !          12824: {
        !          12825:     int total = 0;
        !          12826:     xmlXPathCompExprPtr comp;
        !          12827:     xmlXPathObjectPtr res;
        !          12828:     xmlXPathObjectPtr obj;
        !          12829:     xmlNodeSetPtr oldset;
        !          12830:     xmlNodePtr oldnode;
        !          12831:     xmlDocPtr oldDoc;
        !          12832:     int i;
        !          12833: 
        !          12834:     CHECK_ERROR0;
        !          12835:     comp = ctxt->comp;
        !          12836:     /*
        !          12837:     * Optimization for ()[last()] selection i.e. the last elem
        !          12838:     */
        !          12839:     if ((op->ch1 != -1) && (op->ch2 != -1) &&
        !          12840:        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
        !          12841:        (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
        !          12842:        int f = comp->steps[op->ch2].ch1;
        !          12843: 
        !          12844:        if ((f != -1) &&
        !          12845:            (comp->steps[f].op == XPATH_OP_FUNCTION) &&
        !          12846:            (comp->steps[f].value5 == NULL) &&
        !          12847:            (comp->steps[f].value == 0) &&
        !          12848:            (comp->steps[f].value4 != NULL) &&
        !          12849:            (xmlStrEqual
        !          12850:            (comp->steps[f].value4, BAD_CAST "last"))) {
        !          12851:            xmlNodePtr last = NULL;
        !          12852: 
        !          12853:            total +=
        !          12854:                xmlXPathCompOpEvalLast(ctxt,
        !          12855:                    &comp->steps[op->ch1],
        !          12856:                    &last);
        !          12857:            CHECK_ERROR0;
        !          12858:            /*
        !          12859:            * The nodeset should be in document order,
        !          12860:            * Keep only the last value
        !          12861:            */
        !          12862:            if ((ctxt->value != NULL) &&
        !          12863:                (ctxt->value->type == XPATH_NODESET) &&
        !          12864:                (ctxt->value->nodesetval != NULL) &&
        !          12865:                (ctxt->value->nodesetval->nodeTab != NULL) &&
        !          12866:                (ctxt->value->nodesetval->nodeNr > 1)) {
        !          12867:                ctxt->value->nodesetval->nodeTab[0] =
        !          12868:                    ctxt->value->nodesetval->nodeTab[ctxt->
        !          12869:                    value->
        !          12870:                    nodesetval->
        !          12871:                    nodeNr -
        !          12872:                    1];
        !          12873:                ctxt->value->nodesetval->nodeNr = 1;
        !          12874:                *first = *(ctxt->value->nodesetval->nodeTab);
        !          12875:            }
        !          12876:            return (total);
        !          12877:        }
        !          12878:     }
        !          12879: 
        !          12880:     if (op->ch1 != -1)
        !          12881:        total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          12882:     CHECK_ERROR0;
        !          12883:     if (op->ch2 == -1)
        !          12884:        return (total);
        !          12885:     if (ctxt->value == NULL)
        !          12886:        return (total);
        !          12887: 
        !          12888: #ifdef LIBXML_XPTR_ENABLED
        !          12889:     oldnode = ctxt->context->node;
        !          12890:     /*
        !          12891:     * Hum are we filtering the result of an XPointer expression
        !          12892:     */
        !          12893:     if (ctxt->value->type == XPATH_LOCATIONSET) {
        !          12894:        xmlXPathObjectPtr tmp = NULL;
        !          12895:        xmlLocationSetPtr newlocset = NULL;
        !          12896:        xmlLocationSetPtr oldlocset;
        !          12897: 
        !          12898:        /*
        !          12899:        * Extract the old locset, and then evaluate the result of the
        !          12900:        * expression for all the element in the locset. use it to grow
        !          12901:        * up a new locset.
        !          12902:        */
        !          12903:        CHECK_TYPE0(XPATH_LOCATIONSET);
        !          12904:        obj = valuePop(ctxt);
        !          12905:        oldlocset = obj->user;
        !          12906:        ctxt->context->node = NULL;
        !          12907: 
        !          12908:        if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
        !          12909:            ctxt->context->contextSize = 0;
        !          12910:            ctxt->context->proximityPosition = 0;
        !          12911:            if (op->ch2 != -1)
        !          12912:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12913:            res = valuePop(ctxt);
        !          12914:            if (res != NULL) {
        !          12915:                xmlXPathReleaseObject(ctxt->context, res);
        !          12916:            }
        !          12917:            valuePush(ctxt, obj);
        !          12918:            CHECK_ERROR0;
        !          12919:            return (total);
        !          12920:        }
        !          12921:        newlocset = xmlXPtrLocationSetCreate(NULL);
        !          12922: 
        !          12923:        for (i = 0; i < oldlocset->locNr; i++) {
        !          12924:            /*
        !          12925:            * Run the evaluation with a node list made of a
        !          12926:            * single item in the nodelocset.
        !          12927:            */
        !          12928:            ctxt->context->node = oldlocset->locTab[i]->user;
        !          12929:            ctxt->context->contextSize = oldlocset->locNr;
        !          12930:            ctxt->context->proximityPosition = i + 1;
        !          12931:            if (tmp == NULL) {
        !          12932:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          12933:                    ctxt->context->node);
        !          12934:            } else {
        !          12935:                xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          12936:                    ctxt->context->node);
        !          12937:            }
        !          12938:            valuePush(ctxt, tmp);
        !          12939:            if (op->ch2 != -1)
        !          12940:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          12941:            if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          12942:                xmlXPathFreeObject(obj);
        !          12943:                return(0);
        !          12944:            }
        !          12945:            /*
        !          12946:            * The result of the evaluation need to be tested to
        !          12947:            * decided whether the filter succeeded or not
        !          12948:            */
        !          12949:            res = valuePop(ctxt);
        !          12950:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
        !          12951:                xmlXPtrLocationSetAdd(newlocset,
        !          12952:                    xmlXPathCacheObjectCopy(ctxt->context,
        !          12953:                        oldlocset->locTab[i]));
        !          12954:            }
        !          12955:            /*
        !          12956:            * Cleanup
        !          12957:            */
        !          12958:            if (res != NULL) {
        !          12959:                xmlXPathReleaseObject(ctxt->context, res);
        !          12960:            }
        !          12961:            if (ctxt->value == tmp) {
        !          12962:                valuePop(ctxt);
        !          12963:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
        !          12964:                /*
        !          12965:                * REVISIT TODO: Don't create a temporary nodeset
        !          12966:                * for everly iteration.
        !          12967:                */
        !          12968:                /* OLD: xmlXPathFreeObject(res); */
        !          12969:            } else
        !          12970:                tmp = NULL;
        !          12971:            ctxt->context->node = NULL;
        !          12972:            /*
        !          12973:            * Only put the first node in the result, then leave.
        !          12974:            */
        !          12975:            if (newlocset->locNr > 0) {
        !          12976:                *first = (xmlNodePtr) oldlocset->locTab[i]->user;
        !          12977:                break;
        !          12978:            }
        !          12979:        }
        !          12980:        if (tmp != NULL) {
        !          12981:            xmlXPathReleaseObject(ctxt->context, tmp);
        !          12982:        }
        !          12983:        /*
        !          12984:        * The result is used as the new evaluation locset.
        !          12985:        */
        !          12986:        xmlXPathReleaseObject(ctxt->context, obj);
        !          12987:        ctxt->context->node = NULL;
        !          12988:        ctxt->context->contextSize = -1;
        !          12989:        ctxt->context->proximityPosition = -1;
        !          12990:        valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
        !          12991:        ctxt->context->node = oldnode;
        !          12992:        return (total);
        !          12993:     }
        !          12994: #endif /* LIBXML_XPTR_ENABLED */
        !          12995: 
        !          12996:     /*
        !          12997:     * Extract the old set, and then evaluate the result of the
        !          12998:     * expression for all the element in the set. use it to grow
        !          12999:     * up a new set.
        !          13000:     */
        !          13001:     CHECK_TYPE0(XPATH_NODESET);
        !          13002:     obj = valuePop(ctxt);
        !          13003:     oldset = obj->nodesetval;
        !          13004: 
        !          13005:     oldnode = ctxt->context->node;
        !          13006:     oldDoc = ctxt->context->doc;
        !          13007:     ctxt->context->node = NULL;
        !          13008: 
        !          13009:     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
        !          13010:        ctxt->context->contextSize = 0;
        !          13011:        ctxt->context->proximityPosition = 0;
        !          13012:        /* QUESTION TODO: Why was this code commented out?
        !          13013:            if (op->ch2 != -1)
        !          13014:                total +=
        !          13015:                    xmlXPathCompOpEval(ctxt,
        !          13016:                        &comp->steps[op->ch2]);
        !          13017:            CHECK_ERROR0;
        !          13018:            res = valuePop(ctxt);
        !          13019:            if (res != NULL)
        !          13020:                xmlXPathFreeObject(res);
        !          13021:        */
        !          13022:        valuePush(ctxt, obj);
        !          13023:        ctxt->context->node = oldnode;
        !          13024:        CHECK_ERROR0;
        !          13025:     } else {
        !          13026:        xmlNodeSetPtr newset;
        !          13027:        xmlXPathObjectPtr tmp = NULL;
        !          13028:        /*
        !          13029:        * Initialize the new set.
        !          13030:        * Also set the xpath document in case things like
        !          13031:        * key() evaluation are attempted on the predicate
        !          13032:        */
        !          13033:        newset = xmlXPathNodeSetCreate(NULL);
        !          13034:         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
        !          13035: 
        !          13036:        for (i = 0; i < oldset->nodeNr; i++) {
        !          13037:            /*
        !          13038:            * Run the evaluation with a node list made of
        !          13039:            * a single item in the nodeset.
        !          13040:            */
        !          13041:            ctxt->context->node = oldset->nodeTab[i];
        !          13042:            if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
        !          13043:                (oldset->nodeTab[i]->doc != NULL))
        !          13044:                ctxt->context->doc = oldset->nodeTab[i]->doc;
        !          13045:            if (tmp == NULL) {
        !          13046:                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          13047:                    ctxt->context->node);
        !          13048:            } else {
        !          13049:                xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          13050:                    ctxt->context->node);
        !          13051:            }
        !          13052:            valuePush(ctxt, tmp);
        !          13053:            ctxt->context->contextSize = oldset->nodeNr;
        !          13054:            ctxt->context->proximityPosition = i + 1;
        !          13055:            if (op->ch2 != -1)
        !          13056:                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13057:            if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          13058:                xmlXPathFreeNodeSet(newset);
        !          13059:                xmlXPathFreeObject(obj);
        !          13060:                return(0);
        !          13061:            }
        !          13062:            /*
        !          13063:            * The result of the evaluation needs to be tested to
        !          13064:            * decide whether the filter succeeded or not
        !          13065:            */
        !          13066:            res = valuePop(ctxt);
        !          13067:            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
        !          13068:                xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
        !          13069:            }
        !          13070:            /*
        !          13071:            * Cleanup
        !          13072:            */
        !          13073:            if (res != NULL) {
        !          13074:                xmlXPathReleaseObject(ctxt->context, res);
        !          13075:            }
        !          13076:            if (ctxt->value == tmp) {
        !          13077:                valuePop(ctxt);
        !          13078:                /*
        !          13079:                * Don't free the temporary nodeset
        !          13080:                * in order to avoid massive recreation inside this
        !          13081:                * loop.
        !          13082:                */
        !          13083:                xmlXPathNodeSetClear(tmp->nodesetval, 1);
        !          13084:            } else
        !          13085:                tmp = NULL;
        !          13086:            ctxt->context->node = NULL;
        !          13087:            /*
        !          13088:            * Only put the first node in the result, then leave.
        !          13089:            */
        !          13090:            if (newset->nodeNr > 0) {
        !          13091:                *first = *(newset->nodeTab);
        !          13092:                break;
        !          13093:            }
        !          13094:        }
        !          13095:        if (tmp != NULL) {
        !          13096:            xmlXPathReleaseObject(ctxt->context, tmp);
        !          13097:        }
        !          13098:        /*
        !          13099:        * The result is used as the new evaluation set.
        !          13100:        */
        !          13101:        xmlXPathReleaseObject(ctxt->context, obj);
        !          13102:        ctxt->context->node = NULL;
        !          13103:        ctxt->context->contextSize = -1;
        !          13104:        ctxt->context->proximityPosition = -1;
        !          13105:        /* may want to move this past the '}' later */
        !          13106:        ctxt->context->doc = oldDoc;
        !          13107:        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
        !          13108:     }
        !          13109:     ctxt->context->node = oldnode;
        !          13110:     return(total);
        !          13111: }
        !          13112: #endif /* XP_OPTIMIZED_FILTER_FIRST */
        !          13113: 
        !          13114: /**
        !          13115:  * xmlXPathCompOpEval:
        !          13116:  * @ctxt:  the XPath parser context with the compiled expression
        !          13117:  * @op:  an XPath compiled operation
        !          13118:  *
        !          13119:  * Evaluate the Precompiled XPath operation
        !          13120:  * Returns the number of nodes traversed
        !          13121:  */
        !          13122: static int
        !          13123: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
        !          13124: {
        !          13125:     int total = 0;
        !          13126:     int equal, ret;
        !          13127:     xmlXPathCompExprPtr comp;
        !          13128:     xmlXPathObjectPtr arg1, arg2;
        !          13129:     xmlNodePtr bak;
        !          13130:     xmlDocPtr bakd;
        !          13131:     int pp;
        !          13132:     int cs;
        !          13133: 
        !          13134:     CHECK_ERROR0;
        !          13135:     comp = ctxt->comp;
        !          13136:     switch (op->op) {
        !          13137:         case XPATH_OP_END:
        !          13138:             return (0);
        !          13139:         case XPATH_OP_AND:
        !          13140:            bakd = ctxt->context->doc;
        !          13141:            bak = ctxt->context->node;
        !          13142:            pp = ctxt->context->proximityPosition;
        !          13143:            cs = ctxt->context->contextSize;
        !          13144:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13145:            CHECK_ERROR0;
        !          13146:             xmlXPathBooleanFunction(ctxt, 1);
        !          13147:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
        !          13148:                 return (total);
        !          13149:             arg2 = valuePop(ctxt);
        !          13150:            ctxt->context->doc = bakd;
        !          13151:            ctxt->context->node = bak;
        !          13152:            ctxt->context->proximityPosition = pp;
        !          13153:            ctxt->context->contextSize = cs;
        !          13154:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13155:            if (ctxt->error) {
        !          13156:                xmlXPathFreeObject(arg2);
        !          13157:                return(0);
        !          13158:            }
        !          13159:             xmlXPathBooleanFunction(ctxt, 1);
        !          13160:             arg1 = valuePop(ctxt);
        !          13161:             arg1->boolval &= arg2->boolval;
        !          13162:             valuePush(ctxt, arg1);
        !          13163:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          13164:             return (total);
        !          13165:         case XPATH_OP_OR:
        !          13166:            bakd = ctxt->context->doc;
        !          13167:            bak = ctxt->context->node;
        !          13168:            pp = ctxt->context->proximityPosition;
        !          13169:            cs = ctxt->context->contextSize;
        !          13170:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13171:            CHECK_ERROR0;
        !          13172:             xmlXPathBooleanFunction(ctxt, 1);
        !          13173:             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
        !          13174:                 return (total);
        !          13175:             arg2 = valuePop(ctxt);
        !          13176:            ctxt->context->doc = bakd;
        !          13177:            ctxt->context->node = bak;
        !          13178:            ctxt->context->proximityPosition = pp;
        !          13179:            ctxt->context->contextSize = cs;
        !          13180:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13181:            if (ctxt->error) {
        !          13182:                xmlXPathFreeObject(arg2);
        !          13183:                return(0);
        !          13184:            }
        !          13185:             xmlXPathBooleanFunction(ctxt, 1);
        !          13186:             arg1 = valuePop(ctxt);
        !          13187:             arg1->boolval |= arg2->boolval;
        !          13188:             valuePush(ctxt, arg1);
        !          13189:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          13190:             return (total);
        !          13191:         case XPATH_OP_EQUAL:
        !          13192:            bakd = ctxt->context->doc;
        !          13193:            bak = ctxt->context->node;
        !          13194:            pp = ctxt->context->proximityPosition;
        !          13195:            cs = ctxt->context->contextSize;
        !          13196:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13197:            CHECK_ERROR0;
        !          13198:            ctxt->context->doc = bakd;
        !          13199:            ctxt->context->node = bak;
        !          13200:            ctxt->context->proximityPosition = pp;
        !          13201:            ctxt->context->contextSize = cs;
        !          13202:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13203:            CHECK_ERROR0;
        !          13204:            if (op->value)
        !          13205:                equal = xmlXPathEqualValues(ctxt);
        !          13206:            else
        !          13207:                equal = xmlXPathNotEqualValues(ctxt);
        !          13208:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
        !          13209:             return (total);
        !          13210:         case XPATH_OP_CMP:
        !          13211:            bakd = ctxt->context->doc;
        !          13212:            bak = ctxt->context->node;
        !          13213:            pp = ctxt->context->proximityPosition;
        !          13214:            cs = ctxt->context->contextSize;
        !          13215:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13216:            CHECK_ERROR0;
        !          13217:            ctxt->context->doc = bakd;
        !          13218:            ctxt->context->node = bak;
        !          13219:            ctxt->context->proximityPosition = pp;
        !          13220:            ctxt->context->contextSize = cs;
        !          13221:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13222:            CHECK_ERROR0;
        !          13223:             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
        !          13224:            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
        !          13225:             return (total);
        !          13226:         case XPATH_OP_PLUS:
        !          13227:            bakd = ctxt->context->doc;
        !          13228:            bak = ctxt->context->node;
        !          13229:            pp = ctxt->context->proximityPosition;
        !          13230:            cs = ctxt->context->contextSize;
        !          13231:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13232:            CHECK_ERROR0;
        !          13233:             if (op->ch2 != -1) {
        !          13234:                ctxt->context->doc = bakd;
        !          13235:                ctxt->context->node = bak;
        !          13236:                ctxt->context->proximityPosition = pp;
        !          13237:                ctxt->context->contextSize = cs;
        !          13238:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13239:            }
        !          13240:            CHECK_ERROR0;
        !          13241:             if (op->value == 0)
        !          13242:                 xmlXPathSubValues(ctxt);
        !          13243:             else if (op->value == 1)
        !          13244:                 xmlXPathAddValues(ctxt);
        !          13245:             else if (op->value == 2)
        !          13246:                 xmlXPathValueFlipSign(ctxt);
        !          13247:             else if (op->value == 3) {
        !          13248:                 CAST_TO_NUMBER;
        !          13249:                 CHECK_TYPE0(XPATH_NUMBER);
        !          13250:             }
        !          13251:             return (total);
        !          13252:         case XPATH_OP_MULT:
        !          13253:            bakd = ctxt->context->doc;
        !          13254:            bak = ctxt->context->node;
        !          13255:            pp = ctxt->context->proximityPosition;
        !          13256:            cs = ctxt->context->contextSize;
        !          13257:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13258:            CHECK_ERROR0;
        !          13259:            ctxt->context->doc = bakd;
        !          13260:            ctxt->context->node = bak;
        !          13261:            ctxt->context->proximityPosition = pp;
        !          13262:            ctxt->context->contextSize = cs;
        !          13263:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13264:            CHECK_ERROR0;
        !          13265:             if (op->value == 0)
        !          13266:                 xmlXPathMultValues(ctxt);
        !          13267:             else if (op->value == 1)
        !          13268:                 xmlXPathDivValues(ctxt);
        !          13269:             else if (op->value == 2)
        !          13270:                 xmlXPathModValues(ctxt);
        !          13271:             return (total);
        !          13272:         case XPATH_OP_UNION:
        !          13273:            bakd = ctxt->context->doc;
        !          13274:            bak = ctxt->context->node;
        !          13275:            pp = ctxt->context->proximityPosition;
        !          13276:            cs = ctxt->context->contextSize;
        !          13277:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13278:            CHECK_ERROR0;
        !          13279:            ctxt->context->doc = bakd;
        !          13280:            ctxt->context->node = bak;
        !          13281:            ctxt->context->proximityPosition = pp;
        !          13282:            ctxt->context->contextSize = cs;
        !          13283:             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13284:            CHECK_ERROR0;
        !          13285:             CHECK_TYPE0(XPATH_NODESET);
        !          13286:             arg2 = valuePop(ctxt);
        !          13287: 
        !          13288:             CHECK_TYPE0(XPATH_NODESET);
        !          13289:             arg1 = valuePop(ctxt);
        !          13290: 
        !          13291:            if ((arg1->nodesetval == NULL) ||
        !          13292:                ((arg2->nodesetval != NULL) &&
        !          13293:                 (arg2->nodesetval->nodeNr != 0)))
        !          13294:            {
        !          13295:                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
        !          13296:                                                        arg2->nodesetval);
        !          13297:            }
        !          13298: 
        !          13299:             valuePush(ctxt, arg1);
        !          13300:            xmlXPathReleaseObject(ctxt->context, arg2);
        !          13301:             return (total);
        !          13302:         case XPATH_OP_ROOT:
        !          13303:             xmlXPathRoot(ctxt);
        !          13304:             return (total);
        !          13305:         case XPATH_OP_NODE:
        !          13306:             if (op->ch1 != -1)
        !          13307:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13308:            CHECK_ERROR0;
        !          13309:             if (op->ch2 != -1)
        !          13310:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13311:            CHECK_ERROR0;
        !          13312:            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
        !          13313:                ctxt->context->node));
        !          13314:             return (total);
        !          13315:         case XPATH_OP_RESET:
        !          13316:             if (op->ch1 != -1)
        !          13317:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13318:            CHECK_ERROR0;
        !          13319:             if (op->ch2 != -1)
        !          13320:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13321:            CHECK_ERROR0;
        !          13322:             ctxt->context->node = NULL;
        !          13323:             return (total);
        !          13324:         case XPATH_OP_COLLECT:{
        !          13325:                 if (op->ch1 == -1)
        !          13326:                     return (total);
        !          13327: 
        !          13328:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13329:                CHECK_ERROR0;
        !          13330: 
        !          13331:                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
        !          13332:                 return (total);
        !          13333:             }
        !          13334:         case XPATH_OP_VALUE:
        !          13335:             valuePush(ctxt,
        !          13336:                       xmlXPathCacheObjectCopy(ctxt->context,
        !          13337:                        (xmlXPathObjectPtr) op->value4));
        !          13338:             return (total);
        !          13339:         case XPATH_OP_VARIABLE:{
        !          13340:                xmlXPathObjectPtr val;
        !          13341: 
        !          13342:                 if (op->ch1 != -1)
        !          13343:                     total +=
        !          13344:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13345:                 if (op->value5 == NULL) {
        !          13346:                    val = xmlXPathVariableLookup(ctxt->context, op->value4);
        !          13347:                    if (val == NULL) {
        !          13348:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
        !          13349:                        return(0);
        !          13350:                    }
        !          13351:                     valuePush(ctxt, val);
        !          13352:                } else {
        !          13353:                     const xmlChar *URI;
        !          13354: 
        !          13355:                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
        !          13356:                     if (URI == NULL) {
        !          13357:                         xmlGenericError(xmlGenericErrorContext,
        !          13358:             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
        !          13359:                                     (char *) op->value4, (char *)op->value5);
        !          13360:                         return (total);
        !          13361:                     }
        !          13362:                    val = xmlXPathVariableLookupNS(ctxt->context,
        !          13363:                                                        op->value4, URI);
        !          13364:                    if (val == NULL) {
        !          13365:                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
        !          13366:                        return(0);
        !          13367:                    }
        !          13368:                     valuePush(ctxt, val);
        !          13369:                 }
        !          13370:                 return (total);
        !          13371:             }
        !          13372:         case XPATH_OP_FUNCTION:{
        !          13373:                 xmlXPathFunction func;
        !          13374:                 const xmlChar *oldFunc, *oldFuncURI;
        !          13375:                int i;
        !          13376: 
        !          13377:                 if (op->ch1 != -1)
        !          13378:                     total +=
        !          13379:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13380:                if (ctxt->valueNr < op->value) {
        !          13381:                    xmlGenericError(xmlGenericErrorContext,
        !          13382:                            "xmlXPathCompOpEval: parameter error\n");
        !          13383:                    ctxt->error = XPATH_INVALID_OPERAND;
        !          13384:                    return (total);
        !          13385:                }
        !          13386:                for (i = 0; i < op->value; i++)
        !          13387:                    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
        !          13388:                        xmlGenericError(xmlGenericErrorContext,
        !          13389:                                "xmlXPathCompOpEval: parameter error\n");
        !          13390:                        ctxt->error = XPATH_INVALID_OPERAND;
        !          13391:                        return (total);
        !          13392:                    }
        !          13393:                 if (op->cache != NULL)
        !          13394:                     XML_CAST_FPTR(func) = op->cache;
        !          13395:                 else {
        !          13396:                     const xmlChar *URI = NULL;
        !          13397: 
        !          13398:                     if (op->value5 == NULL)
        !          13399:                         func =
        !          13400:                             xmlXPathFunctionLookup(ctxt->context,
        !          13401:                                                    op->value4);
        !          13402:                     else {
        !          13403:                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
        !          13404:                         if (URI == NULL) {
        !          13405:                             xmlGenericError(xmlGenericErrorContext,
        !          13406:             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
        !          13407:                                     (char *)op->value4, (char *)op->value5);
        !          13408:                             return (total);
        !          13409:                         }
        !          13410:                         func = xmlXPathFunctionLookupNS(ctxt->context,
        !          13411:                                                         op->value4, URI);
        !          13412:                     }
        !          13413:                     if (func == NULL) {
        !          13414:                         xmlGenericError(xmlGenericErrorContext,
        !          13415:                                 "xmlXPathCompOpEval: function %s not found\n",
        !          13416:                                         (char *)op->value4);
        !          13417:                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
        !          13418:                     }
        !          13419:                     op->cache = XML_CAST_FPTR(func);
        !          13420:                     op->cacheURI = (void *) URI;
        !          13421:                 }
        !          13422:                 oldFunc = ctxt->context->function;
        !          13423:                 oldFuncURI = ctxt->context->functionURI;
        !          13424:                 ctxt->context->function = op->value4;
        !          13425:                 ctxt->context->functionURI = op->cacheURI;
        !          13426:                 func(ctxt, op->value);
        !          13427:                 ctxt->context->function = oldFunc;
        !          13428:                 ctxt->context->functionURI = oldFuncURI;
        !          13429:                 return (total);
        !          13430:             }
        !          13431:         case XPATH_OP_ARG:
        !          13432:            bakd = ctxt->context->doc;
        !          13433:            bak = ctxt->context->node;
        !          13434:            pp = ctxt->context->proximityPosition;
        !          13435:            cs = ctxt->context->contextSize;
        !          13436:             if (op->ch1 != -1)
        !          13437:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13438:            ctxt->context->contextSize = cs;
        !          13439:            ctxt->context->proximityPosition = pp;
        !          13440:            ctxt->context->node = bak;
        !          13441:            ctxt->context->doc = bakd;
        !          13442:            CHECK_ERROR0;
        !          13443:             if (op->ch2 != -1) {
        !          13444:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
        !          13445:                ctxt->context->doc = bakd;
        !          13446:                ctxt->context->node = bak;
        !          13447:                CHECK_ERROR0;
        !          13448:            }
        !          13449:             return (total);
        !          13450:         case XPATH_OP_PREDICATE:
        !          13451:         case XPATH_OP_FILTER:{
        !          13452:                 xmlXPathObjectPtr res;
        !          13453:                 xmlXPathObjectPtr obj, tmp;
        !          13454:                 xmlNodeSetPtr newset = NULL;
        !          13455:                 xmlNodeSetPtr oldset;
        !          13456:                 xmlNodePtr oldnode;
        !          13457:                xmlDocPtr oldDoc;
        !          13458:                 int i;
        !          13459: 
        !          13460:                 /*
        !          13461:                  * Optimization for ()[1] selection i.e. the first elem
        !          13462:                  */
        !          13463:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
        !          13464: #ifdef XP_OPTIMIZED_FILTER_FIRST
        !          13465:                    /*
        !          13466:                    * FILTER TODO: Can we assume that the inner processing
        !          13467:                    *  will result in an ordered list if we have an
        !          13468:                    *  XPATH_OP_FILTER?
        !          13469:                    *  What about an additional field or flag on
        !          13470:                    *  xmlXPathObject like @sorted ? This way we wouln'd need
        !          13471:                    *  to assume anything, so it would be more robust and
        !          13472:                    *  easier to optimize.
        !          13473:                    */
        !          13474:                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
        !          13475:                     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
        !          13476: #else
        !          13477:                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
        !          13478: #endif
        !          13479:                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
        !          13480:                     xmlXPathObjectPtr val;
        !          13481: 
        !          13482:                     val = comp->steps[op->ch2].value4;
        !          13483:                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
        !          13484:                         (val->floatval == 1.0)) {
        !          13485:                         xmlNodePtr first = NULL;
        !          13486: 
        !          13487:                         total +=
        !          13488:                             xmlXPathCompOpEvalFirst(ctxt,
        !          13489:                                                     &comp->steps[op->ch1],
        !          13490:                                                     &first);
        !          13491:                        CHECK_ERROR0;
        !          13492:                         /*
        !          13493:                          * The nodeset should be in document order,
        !          13494:                          * Keep only the first value
        !          13495:                          */
        !          13496:                         if ((ctxt->value != NULL) &&
        !          13497:                             (ctxt->value->type == XPATH_NODESET) &&
        !          13498:                             (ctxt->value->nodesetval != NULL) &&
        !          13499:                             (ctxt->value->nodesetval->nodeNr > 1))
        !          13500:                             ctxt->value->nodesetval->nodeNr = 1;
        !          13501:                         return (total);
        !          13502:                     }
        !          13503:                 }
        !          13504:                 /*
        !          13505:                  * Optimization for ()[last()] selection i.e. the last elem
        !          13506:                  */
        !          13507:                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
        !          13508:                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
        !          13509:                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
        !          13510:                     int f = comp->steps[op->ch2].ch1;
        !          13511: 
        !          13512:                     if ((f != -1) &&
        !          13513:                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
        !          13514:                         (comp->steps[f].value5 == NULL) &&
        !          13515:                         (comp->steps[f].value == 0) &&
        !          13516:                         (comp->steps[f].value4 != NULL) &&
        !          13517:                         (xmlStrEqual
        !          13518:                          (comp->steps[f].value4, BAD_CAST "last"))) {
        !          13519:                         xmlNodePtr last = NULL;
        !          13520: 
        !          13521:                         total +=
        !          13522:                             xmlXPathCompOpEvalLast(ctxt,
        !          13523:                                                    &comp->steps[op->ch1],
        !          13524:                                                    &last);
        !          13525:                        CHECK_ERROR0;
        !          13526:                         /*
        !          13527:                          * The nodeset should be in document order,
        !          13528:                          * Keep only the last value
        !          13529:                          */
        !          13530:                         if ((ctxt->value != NULL) &&
        !          13531:                             (ctxt->value->type == XPATH_NODESET) &&
        !          13532:                             (ctxt->value->nodesetval != NULL) &&
        !          13533:                             (ctxt->value->nodesetval->nodeTab != NULL) &&
        !          13534:                             (ctxt->value->nodesetval->nodeNr > 1)) {
        !          13535:                             ctxt->value->nodesetval->nodeTab[0] =
        !          13536:                                 ctxt->value->nodesetval->nodeTab[ctxt->
        !          13537:                                                                  value->
        !          13538:                                                                  nodesetval->
        !          13539:                                                                  nodeNr -
        !          13540:                                                                  1];
        !          13541:                             ctxt->value->nodesetval->nodeNr = 1;
        !          13542:                         }
        !          13543:                         return (total);
        !          13544:                     }
        !          13545:                 }
        !          13546:                /*
        !          13547:                * Process inner predicates first.
        !          13548:                * Example "index[parent::book][1]":
        !          13549:                * ...
        !          13550:                *   PREDICATE   <-- we are here "[1]"
        !          13551:                *     PREDICATE <-- process "[parent::book]" first
        !          13552:                *       SORT
        !          13553:                *         COLLECT  'parent' 'name' 'node' book
        !          13554:                *           NODE
        !          13555:                *     ELEM Object is a number : 1
        !          13556:                */
        !          13557:                 if (op->ch1 != -1)
        !          13558:                     total +=
        !          13559:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13560:                CHECK_ERROR0;
        !          13561:                 if (op->ch2 == -1)
        !          13562:                     return (total);
        !          13563:                 if (ctxt->value == NULL)
        !          13564:                     return (total);
        !          13565: 
        !          13566:                 oldnode = ctxt->context->node;
        !          13567: 
        !          13568: #ifdef LIBXML_XPTR_ENABLED
        !          13569:                 /*
        !          13570:                  * Hum are we filtering the result of an XPointer expression
        !          13571:                  */
        !          13572:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
        !          13573:                     xmlLocationSetPtr newlocset = NULL;
        !          13574:                     xmlLocationSetPtr oldlocset;
        !          13575: 
        !          13576:                     /*
        !          13577:                      * Extract the old locset, and then evaluate the result of the
        !          13578:                      * expression for all the element in the locset. use it to grow
        !          13579:                      * up a new locset.
        !          13580:                      */
        !          13581:                     CHECK_TYPE0(XPATH_LOCATIONSET);
        !          13582:                     obj = valuePop(ctxt);
        !          13583:                     oldlocset = obj->user;
        !          13584:                     ctxt->context->node = NULL;
        !          13585: 
        !          13586:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
        !          13587:                         ctxt->context->contextSize = 0;
        !          13588:                         ctxt->context->proximityPosition = 0;
        !          13589:                         if (op->ch2 != -1)
        !          13590:                             total +=
        !          13591:                                 xmlXPathCompOpEval(ctxt,
        !          13592:                                                    &comp->steps[op->ch2]);
        !          13593:                         res = valuePop(ctxt);
        !          13594:                         if (res != NULL) {
        !          13595:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13596:                        }
        !          13597:                         valuePush(ctxt, obj);
        !          13598:                         CHECK_ERROR0;
        !          13599:                         return (total);
        !          13600:                     }
        !          13601:                     newlocset = xmlXPtrLocationSetCreate(NULL);
        !          13602: 
        !          13603:                     for (i = 0; i < oldlocset->locNr; i++) {
        !          13604:                         /*
        !          13605:                          * Run the evaluation with a node list made of a
        !          13606:                          * single item in the nodelocset.
        !          13607:                          */
        !          13608:                         ctxt->context->node = oldlocset->locTab[i]->user;
        !          13609:                         ctxt->context->contextSize = oldlocset->locNr;
        !          13610:                         ctxt->context->proximityPosition = i + 1;
        !          13611:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          13612:                            ctxt->context->node);
        !          13613:                         valuePush(ctxt, tmp);
        !          13614: 
        !          13615:                         if (op->ch2 != -1)
        !          13616:                             total +=
        !          13617:                                 xmlXPathCompOpEval(ctxt,
        !          13618:                                                    &comp->steps[op->ch2]);
        !          13619:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          13620:                            xmlXPathFreeObject(obj);
        !          13621:                            return(0);
        !          13622:                        }
        !          13623: 
        !          13624:                         /*
        !          13625:                          * The result of the evaluation need to be tested to
        !          13626:                          * decided whether the filter succeeded or not
        !          13627:                          */
        !          13628:                         res = valuePop(ctxt);
        !          13629:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
        !          13630:                             xmlXPtrLocationSetAdd(newlocset,
        !          13631:                                                   xmlXPathObjectCopy
        !          13632:                                                   (oldlocset->locTab[i]));
        !          13633:                         }
        !          13634: 
        !          13635:                         /*
        !          13636:                          * Cleanup
        !          13637:                          */
        !          13638:                         if (res != NULL) {
        !          13639:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13640:                        }
        !          13641:                         if (ctxt->value == tmp) {
        !          13642:                             res = valuePop(ctxt);
        !          13643:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13644:                         }
        !          13645: 
        !          13646:                         ctxt->context->node = NULL;
        !          13647:                     }
        !          13648: 
        !          13649:                     /*
        !          13650:                      * The result is used as the new evaluation locset.
        !          13651:                      */
        !          13652:                    xmlXPathReleaseObject(ctxt->context, obj);
        !          13653:                     ctxt->context->node = NULL;
        !          13654:                     ctxt->context->contextSize = -1;
        !          13655:                     ctxt->context->proximityPosition = -1;
        !          13656:                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
        !          13657:                     ctxt->context->node = oldnode;
        !          13658:                     return (total);
        !          13659:                 }
        !          13660: #endif /* LIBXML_XPTR_ENABLED */
        !          13661: 
        !          13662:                 /*
        !          13663:                  * Extract the old set, and then evaluate the result of the
        !          13664:                  * expression for all the element in the set. use it to grow
        !          13665:                  * up a new set.
        !          13666:                  */
        !          13667:                 CHECK_TYPE0(XPATH_NODESET);
        !          13668:                 obj = valuePop(ctxt);
        !          13669:                 oldset = obj->nodesetval;
        !          13670: 
        !          13671:                 oldnode = ctxt->context->node;
        !          13672:                oldDoc = ctxt->context->doc;
        !          13673:                 ctxt->context->node = NULL;
        !          13674: 
        !          13675:                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
        !          13676:                     ctxt->context->contextSize = 0;
        !          13677:                     ctxt->context->proximityPosition = 0;
        !          13678: /*
        !          13679:                     if (op->ch2 != -1)
        !          13680:                         total +=
        !          13681:                             xmlXPathCompOpEval(ctxt,
        !          13682:                                                &comp->steps[op->ch2]);
        !          13683:                    CHECK_ERROR0;
        !          13684:                     res = valuePop(ctxt);
        !          13685:                     if (res != NULL)
        !          13686:                         xmlXPathFreeObject(res);
        !          13687: */
        !          13688:                     valuePush(ctxt, obj);
        !          13689:                     ctxt->context->node = oldnode;
        !          13690:                     CHECK_ERROR0;
        !          13691:                 } else {
        !          13692:                    tmp = NULL;
        !          13693:                     /*
        !          13694:                      * Initialize the new set.
        !          13695:                     * Also set the xpath document in case things like
        !          13696:                     * key() evaluation are attempted on the predicate
        !          13697:                      */
        !          13698:                     newset = xmlXPathNodeSetCreate(NULL);
        !          13699:                    /*
        !          13700:                    * SPEC XPath 1.0:
        !          13701:                    *  "For each node in the node-set to be filtered, the
        !          13702:                    *  PredicateExpr is evaluated with that node as the
        !          13703:                    *  context node, with the number of nodes in the
        !          13704:                    *  node-set as the context size, and with the proximity
        !          13705:                    *  position of the node in the node-set with respect to
        !          13706:                    *  the axis as the context position;"
        !          13707:                    * @oldset is the node-set" to be filtered.
        !          13708:                    *
        !          13709:                    * SPEC XPath 1.0:
        !          13710:                    *  "only predicates change the context position and
        !          13711:                    *  context size (see [2.4 Predicates])."
        !          13712:                    * Example:
        !          13713:                    *   node-set  context pos
        !          13714:                    *    nA         1
        !          13715:                    *    nB         2
        !          13716:                    *    nC         3
        !          13717:                    *   After applying predicate [position() > 1] :
        !          13718:                    *   node-set  context pos
        !          13719:                    *    nB         1
        !          13720:                    *    nC         2
        !          13721:                    *
        !          13722:                    * removed the first node in the node-set, then
        !          13723:                    * the context position of the
        !          13724:                    */
        !          13725:                     for (i = 0; i < oldset->nodeNr; i++) {
        !          13726:                         /*
        !          13727:                          * Run the evaluation with a node list made of
        !          13728:                          * a single item in the nodeset.
        !          13729:                          */
        !          13730:                         ctxt->context->node = oldset->nodeTab[i];
        !          13731:                        if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
        !          13732:                            (oldset->nodeTab[i]->doc != NULL))
        !          13733:                            ctxt->context->doc = oldset->nodeTab[i]->doc;
        !          13734:                        if (tmp == NULL) {
        !          13735:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          13736:                                ctxt->context->node);
        !          13737:                        } else {
        !          13738:                            xmlXPathNodeSetAddUnique(tmp->nodesetval,
        !          13739:                                ctxt->context->node);
        !          13740:                        }
        !          13741:                         valuePush(ctxt, tmp);
        !          13742:                         ctxt->context->contextSize = oldset->nodeNr;
        !          13743:                         ctxt->context->proximityPosition = i + 1;
        !          13744:                        /*
        !          13745:                        * Evaluate the predicate against the context node.
        !          13746:                        * Can/should we optimize position() predicates
        !          13747:                        * here (e.g. "[1]")?
        !          13748:                        */
        !          13749:                         if (op->ch2 != -1)
        !          13750:                             total +=
        !          13751:                                 xmlXPathCompOpEval(ctxt,
        !          13752:                                                    &comp->steps[op->ch2]);
        !          13753:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          13754:                            xmlXPathFreeNodeSet(newset);
        !          13755:                            xmlXPathFreeObject(obj);
        !          13756:                            return(0);
        !          13757:                        }
        !          13758: 
        !          13759:                         /*
        !          13760:                          * The result of the evaluation needs to be tested to
        !          13761:                          * decide whether the filter succeeded or not
        !          13762:                          */
        !          13763:                        /*
        !          13764:                        * OPTIMIZE TODO: Can we use
        !          13765:                        * xmlXPathNodeSetAdd*Unique()* instead?
        !          13766:                        */
        !          13767:                         res = valuePop(ctxt);
        !          13768:                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
        !          13769:                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
        !          13770:                         }
        !          13771: 
        !          13772:                         /*
        !          13773:                          * Cleanup
        !          13774:                          */
        !          13775:                         if (res != NULL) {
        !          13776:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13777:                        }
        !          13778:                         if (ctxt->value == tmp) {
        !          13779:                             valuePop(ctxt);
        !          13780:                            xmlXPathNodeSetClear(tmp->nodesetval, 1);
        !          13781:                            /*
        !          13782:                            * Don't free the temporary nodeset
        !          13783:                            * in order to avoid massive recreation inside this
        !          13784:                            * loop.
        !          13785:                            */
        !          13786:                         } else
        !          13787:                            tmp = NULL;
        !          13788:                         ctxt->context->node = NULL;
        !          13789:                     }
        !          13790:                    if (tmp != NULL)
        !          13791:                        xmlXPathReleaseObject(ctxt->context, tmp);
        !          13792:                     /*
        !          13793:                      * The result is used as the new evaluation set.
        !          13794:                      */
        !          13795:                    xmlXPathReleaseObject(ctxt->context, obj);
        !          13796:                     ctxt->context->node = NULL;
        !          13797:                     ctxt->context->contextSize = -1;
        !          13798:                     ctxt->context->proximityPosition = -1;
        !          13799:                    /* may want to move this past the '}' later */
        !          13800:                    ctxt->context->doc = oldDoc;
        !          13801:                    valuePush(ctxt,
        !          13802:                        xmlXPathCacheWrapNodeSet(ctxt->context, newset));
        !          13803:                 }
        !          13804:                 ctxt->context->node = oldnode;
        !          13805:                 return (total);
        !          13806:             }
        !          13807:         case XPATH_OP_SORT:
        !          13808:             if (op->ch1 != -1)
        !          13809:                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13810:            CHECK_ERROR0;
        !          13811:             if ((ctxt->value != NULL) &&
        !          13812:                 (ctxt->value->type == XPATH_NODESET) &&
        !          13813:                 (ctxt->value->nodesetval != NULL) &&
        !          13814:                (ctxt->value->nodesetval->nodeNr > 1))
        !          13815:            {
        !          13816:                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
        !          13817:            }
        !          13818:             return (total);
        !          13819: #ifdef LIBXML_XPTR_ENABLED
        !          13820:         case XPATH_OP_RANGETO:{
        !          13821:                 xmlXPathObjectPtr range;
        !          13822:                 xmlXPathObjectPtr res, obj;
        !          13823:                 xmlXPathObjectPtr tmp;
        !          13824:                 xmlLocationSetPtr newlocset = NULL;
        !          13825:                    xmlLocationSetPtr oldlocset;
        !          13826:                 xmlNodeSetPtr oldset;
        !          13827:                 int i, j;
        !          13828: 
        !          13829:                 if (op->ch1 != -1)
        !          13830:                     total +=
        !          13831:                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
        !          13832:                 if (op->ch2 == -1)
        !          13833:                     return (total);
        !          13834: 
        !          13835:                 if (ctxt->value->type == XPATH_LOCATIONSET) {
        !          13836:                     /*
        !          13837:                      * Extract the old locset, and then evaluate the result of the
        !          13838:                      * expression for all the element in the locset. use it to grow
        !          13839:                      * up a new locset.
        !          13840:                      */
        !          13841:                     CHECK_TYPE0(XPATH_LOCATIONSET);
        !          13842:                     obj = valuePop(ctxt);
        !          13843:                     oldlocset = obj->user;
        !          13844: 
        !          13845:                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
        !          13846:                        ctxt->context->node = NULL;
        !          13847:                         ctxt->context->contextSize = 0;
        !          13848:                         ctxt->context->proximityPosition = 0;
        !          13849:                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
        !          13850:                         res = valuePop(ctxt);
        !          13851:                         if (res != NULL) {
        !          13852:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13853:                        }
        !          13854:                         valuePush(ctxt, obj);
        !          13855:                         CHECK_ERROR0;
        !          13856:                         return (total);
        !          13857:                     }
        !          13858:                     newlocset = xmlXPtrLocationSetCreate(NULL);
        !          13859: 
        !          13860:                     for (i = 0; i < oldlocset->locNr; i++) {
        !          13861:                         /*
        !          13862:                          * Run the evaluation with a node list made of a
        !          13863:                          * single item in the nodelocset.
        !          13864:                          */
        !          13865:                         ctxt->context->node = oldlocset->locTab[i]->user;
        !          13866:                         ctxt->context->contextSize = oldlocset->locNr;
        !          13867:                         ctxt->context->proximityPosition = i + 1;
        !          13868:                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          13869:                            ctxt->context->node);
        !          13870:                         valuePush(ctxt, tmp);
        !          13871: 
        !          13872:                         if (op->ch2 != -1)
        !          13873:                             total +=
        !          13874:                                 xmlXPathCompOpEval(ctxt,
        !          13875:                                                    &comp->steps[op->ch2]);
        !          13876:                        if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          13877:                            xmlXPathFreeObject(obj);
        !          13878:                            return(0);
        !          13879:                        }
        !          13880: 
        !          13881:                         res = valuePop(ctxt);
        !          13882:                        if (res->type == XPATH_LOCATIONSET) {
        !          13883:                            xmlLocationSetPtr rloc =
        !          13884:                                (xmlLocationSetPtr)res->user;
        !          13885:                            for (j=0; j<rloc->locNr; j++) {
        !          13886:                                range = xmlXPtrNewRange(
        !          13887:                                  oldlocset->locTab[i]->user,
        !          13888:                                  oldlocset->locTab[i]->index,
        !          13889:                                  rloc->locTab[j]->user2,
        !          13890:                                  rloc->locTab[j]->index2);
        !          13891:                                if (range != NULL) {
        !          13892:                                    xmlXPtrLocationSetAdd(newlocset, range);
        !          13893:                                }
        !          13894:                            }
        !          13895:                        } else {
        !          13896:                            range = xmlXPtrNewRangeNodeObject(
        !          13897:                                (xmlNodePtr)oldlocset->locTab[i]->user, res);
        !          13898:                             if (range != NULL) {
        !          13899:                                 xmlXPtrLocationSetAdd(newlocset,range);
        !          13900:                            }
        !          13901:                         }
        !          13902: 
        !          13903:                         /*
        !          13904:                          * Cleanup
        !          13905:                          */
        !          13906:                         if (res != NULL) {
        !          13907:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13908:                        }
        !          13909:                         if (ctxt->value == tmp) {
        !          13910:                             res = valuePop(ctxt);
        !          13911:                            xmlXPathReleaseObject(ctxt->context, res);
        !          13912:                         }
        !          13913: 
        !          13914:                         ctxt->context->node = NULL;
        !          13915:                     }
        !          13916:                } else {        /* Not a location set */
        !          13917:                     CHECK_TYPE0(XPATH_NODESET);
        !          13918:                     obj = valuePop(ctxt);
        !          13919:                     oldset = obj->nodesetval;
        !          13920:                     ctxt->context->node = NULL;
        !          13921: 
        !          13922:                     newlocset = xmlXPtrLocationSetCreate(NULL);
        !          13923: 
        !          13924:                     if (oldset != NULL) {
        !          13925:                         for (i = 0; i < oldset->nodeNr; i++) {
        !          13926:                             /*
        !          13927:                              * Run the evaluation with a node list made of a single item
        !          13928:                              * in the nodeset.
        !          13929:                              */
        !          13930:                             ctxt->context->node = oldset->nodeTab[i];
        !          13931:                            /*
        !          13932:                            * OPTIMIZE TODO: Avoid recreation for every iteration.
        !          13933:                            */
        !          13934:                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
        !          13935:                                ctxt->context->node);
        !          13936:                             valuePush(ctxt, tmp);
        !          13937: 
        !          13938:                             if (op->ch2 != -1)
        !          13939:                                 total +=
        !          13940:                                     xmlXPathCompOpEval(ctxt,
        !          13941:                                                    &comp->steps[op->ch2]);
        !          13942:                            if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          13943:                                xmlXPathFreeObject(obj);
        !          13944:                                return(0);
        !          13945:                            }
        !          13946: 
        !          13947:                             res = valuePop(ctxt);
        !          13948:                             range =
        !          13949:                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
        !          13950:                                                       res);
        !          13951:                             if (range != NULL) {
        !          13952:                                 xmlXPtrLocationSetAdd(newlocset, range);
        !          13953:                             }
        !          13954: 
        !          13955:                             /*
        !          13956:                              * Cleanup
        !          13957:                              */
        !          13958:                             if (res != NULL) {
        !          13959:                                xmlXPathReleaseObject(ctxt->context, res);
        !          13960:                            }
        !          13961:                             if (ctxt->value == tmp) {
        !          13962:                                 res = valuePop(ctxt);
        !          13963:                                xmlXPathReleaseObject(ctxt->context, res);
        !          13964:                             }
        !          13965: 
        !          13966:                             ctxt->context->node = NULL;
        !          13967:                         }
        !          13968:                     }
        !          13969:                 }
        !          13970: 
        !          13971:                 /*
        !          13972:                  * The result is used as the new evaluation set.
        !          13973:                  */
        !          13974:                xmlXPathReleaseObject(ctxt->context, obj);
        !          13975:                 ctxt->context->node = NULL;
        !          13976:                 ctxt->context->contextSize = -1;
        !          13977:                 ctxt->context->proximityPosition = -1;
        !          13978:                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
        !          13979:                 return (total);
        !          13980:             }
        !          13981: #endif /* LIBXML_XPTR_ENABLED */
        !          13982:     }
        !          13983:     xmlGenericError(xmlGenericErrorContext,
        !          13984:                     "XPath: unknown precompiled operation %d\n", op->op);
        !          13985:     return (total);
        !          13986: }
        !          13987: 
        !          13988: /**
        !          13989:  * xmlXPathCompOpEvalToBoolean:
        !          13990:  * @ctxt:  the XPath parser context
        !          13991:  *
        !          13992:  * Evaluates if the expression evaluates to true.
        !          13993:  *
        !          13994:  * Returns 1 if true, 0 if false and -1 on API or internal errors.
        !          13995:  */
        !          13996: static int
        !          13997: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
        !          13998:                            xmlXPathStepOpPtr op,
        !          13999:                            int isPredicate)
        !          14000: {
        !          14001:     xmlXPathObjectPtr resObj = NULL;
        !          14002: 
        !          14003: start:
        !          14004:     /* comp = ctxt->comp; */
        !          14005:     switch (op->op) {
        !          14006:         case XPATH_OP_END:
        !          14007:             return (0);
        !          14008:        case XPATH_OP_VALUE:
        !          14009:            resObj = (xmlXPathObjectPtr) op->value4;
        !          14010:            if (isPredicate)
        !          14011:                return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
        !          14012:            return(xmlXPathCastToBoolean(resObj));
        !          14013:        case XPATH_OP_SORT:
        !          14014:            /*
        !          14015:            * We don't need sorting for boolean results. Skip this one.
        !          14016:            */
        !          14017:             if (op->ch1 != -1) {
        !          14018:                op = &ctxt->comp->steps[op->ch1];
        !          14019:                goto start;
        !          14020:            }
        !          14021:            return(0);
        !          14022:        case XPATH_OP_COLLECT:
        !          14023:            if (op->ch1 == -1)
        !          14024:                return(0);
        !          14025: 
        !          14026:             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
        !          14027:            if (ctxt->error != XPATH_EXPRESSION_OK)
        !          14028:                return(-1);
        !          14029: 
        !          14030:             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
        !          14031:            if (ctxt->error != XPATH_EXPRESSION_OK)
        !          14032:                return(-1);
        !          14033: 
        !          14034:            resObj = valuePop(ctxt);
        !          14035:            if (resObj == NULL)
        !          14036:                return(-1);
        !          14037:            break;
        !          14038:        default:
        !          14039:            /*
        !          14040:            * Fallback to call xmlXPathCompOpEval().
        !          14041:            */
        !          14042:            xmlXPathCompOpEval(ctxt, op);
        !          14043:            if (ctxt->error != XPATH_EXPRESSION_OK)
        !          14044:                return(-1);
        !          14045: 
        !          14046:            resObj = valuePop(ctxt);
        !          14047:            if (resObj == NULL)
        !          14048:                return(-1);
        !          14049:            break;
        !          14050:     }
        !          14051: 
        !          14052:     if (resObj) {
        !          14053:        int res;
        !          14054: 
        !          14055:        if (resObj->type == XPATH_BOOLEAN) {
        !          14056:            res = resObj->boolval;
        !          14057:        } else if (isPredicate) {
        !          14058:            /*
        !          14059:            * For predicates a result of type "number" is handled
        !          14060:            * differently:
        !          14061:            * SPEC XPath 1.0:
        !          14062:            * "If the result is a number, the result will be converted
        !          14063:            *  to true if the number is equal to the context position
        !          14064:            *  and will be converted to false otherwise;"
        !          14065:            */
        !          14066:            res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
        !          14067:        } else {
        !          14068:            res = xmlXPathCastToBoolean(resObj);
        !          14069:        }
        !          14070:        xmlXPathReleaseObject(ctxt->context, resObj);
        !          14071:        return(res);
        !          14072:     }
        !          14073: 
        !          14074:     return(0);
        !          14075: }
        !          14076: 
        !          14077: #ifdef XPATH_STREAMING
        !          14078: /**
        !          14079:  * xmlXPathRunStreamEval:
        !          14080:  * @ctxt:  the XPath parser context with the compiled expression
        !          14081:  *
        !          14082:  * Evaluate the Precompiled Streamable XPath expression in the given context.
        !          14083:  */
        !          14084: static int
        !          14085: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
        !          14086:                      xmlXPathObjectPtr *resultSeq, int toBool)
        !          14087: {
        !          14088:     int max_depth, min_depth;
        !          14089:     int from_root;
        !          14090:     int ret, depth;
        !          14091:     int eval_all_nodes;
        !          14092:     xmlNodePtr cur = NULL, limit = NULL;
        !          14093:     xmlStreamCtxtPtr patstream = NULL;
        !          14094: 
        !          14095:     int nb_nodes = 0;
        !          14096: 
        !          14097:     if ((ctxt == NULL) || (comp == NULL))
        !          14098:         return(-1);
        !          14099:     max_depth = xmlPatternMaxDepth(comp);
        !          14100:     if (max_depth == -1)
        !          14101:         return(-1);
        !          14102:     if (max_depth == -2)
        !          14103:         max_depth = 10000;
        !          14104:     min_depth = xmlPatternMinDepth(comp);
        !          14105:     if (min_depth == -1)
        !          14106:         return(-1);
        !          14107:     from_root = xmlPatternFromRoot(comp);
        !          14108:     if (from_root < 0)
        !          14109:         return(-1);
        !          14110: #if 0
        !          14111:     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
        !          14112: #endif
        !          14113: 
        !          14114:     if (! toBool) {
        !          14115:        if (resultSeq == NULL)
        !          14116:            return(-1);
        !          14117:        *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
        !          14118:        if (*resultSeq == NULL)
        !          14119:            return(-1);
        !          14120:     }
        !          14121: 
        !          14122:     /*
        !          14123:      * handle the special cases of "/" amd "." being matched
        !          14124:      */
        !          14125:     if (min_depth == 0) {
        !          14126:        if (from_root) {
        !          14127:            /* Select "/" */
        !          14128:            if (toBool)
        !          14129:                return(1);
        !          14130:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
        !          14131:                (xmlNodePtr) ctxt->doc);
        !          14132:        } else {
        !          14133:            /* Select "self::node()" */
        !          14134:            if (toBool)
        !          14135:                return(1);
        !          14136:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
        !          14137:        }
        !          14138:     }
        !          14139:     if (max_depth == 0) {
        !          14140:        return(0);
        !          14141:     }
        !          14142: 
        !          14143:     if (from_root) {
        !          14144:         cur = (xmlNodePtr)ctxt->doc;
        !          14145:     } else if (ctxt->node != NULL) {
        !          14146:         switch (ctxt->node->type) {
        !          14147:             case XML_ELEMENT_NODE:
        !          14148:             case XML_DOCUMENT_NODE:
        !          14149:             case XML_DOCUMENT_FRAG_NODE:
        !          14150:             case XML_HTML_DOCUMENT_NODE:
        !          14151: #ifdef LIBXML_DOCB_ENABLED
        !          14152:             case XML_DOCB_DOCUMENT_NODE:
        !          14153: #endif
        !          14154:                cur = ctxt->node;
        !          14155:                break;
        !          14156:             case XML_ATTRIBUTE_NODE:
        !          14157:             case XML_TEXT_NODE:
        !          14158:             case XML_CDATA_SECTION_NODE:
        !          14159:             case XML_ENTITY_REF_NODE:
        !          14160:             case XML_ENTITY_NODE:
        !          14161:             case XML_PI_NODE:
        !          14162:             case XML_COMMENT_NODE:
        !          14163:             case XML_NOTATION_NODE:
        !          14164:             case XML_DTD_NODE:
        !          14165:             case XML_DOCUMENT_TYPE_NODE:
        !          14166:             case XML_ELEMENT_DECL:
        !          14167:             case XML_ATTRIBUTE_DECL:
        !          14168:             case XML_ENTITY_DECL:
        !          14169:             case XML_NAMESPACE_DECL:
        !          14170:             case XML_XINCLUDE_START:
        !          14171:             case XML_XINCLUDE_END:
        !          14172:                break;
        !          14173:        }
        !          14174:        limit = cur;
        !          14175:     }
        !          14176:     if (cur == NULL) {
        !          14177:         return(0);
        !          14178:     }
        !          14179: 
        !          14180:     patstream = xmlPatternGetStreamCtxt(comp);
        !          14181:     if (patstream == NULL) {
        !          14182:        /*
        !          14183:        * QUESTION TODO: Is this an error?
        !          14184:        */
        !          14185:        return(0);
        !          14186:     }
        !          14187: 
        !          14188:     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
        !          14189: 
        !          14190:     if (from_root) {
        !          14191:        ret = xmlStreamPush(patstream, NULL, NULL);
        !          14192:        if (ret < 0) {
        !          14193:        } else if (ret == 1) {
        !          14194:            if (toBool)
        !          14195:                goto return_1;
        !          14196:            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
        !          14197:        }
        !          14198:     }
        !          14199:     depth = 0;
        !          14200:     goto scan_children;
        !          14201: next_node:
        !          14202:     do {
        !          14203:         nb_nodes++;
        !          14204: 
        !          14205:        switch (cur->type) {
        !          14206:            case XML_ELEMENT_NODE:
        !          14207:            case XML_TEXT_NODE:
        !          14208:            case XML_CDATA_SECTION_NODE:
        !          14209:            case XML_COMMENT_NODE:
        !          14210:            case XML_PI_NODE:
        !          14211:                if (cur->type == XML_ELEMENT_NODE) {
        !          14212:                    ret = xmlStreamPush(patstream, cur->name,
        !          14213:                                (cur->ns ? cur->ns->href : NULL));
        !          14214:                } else if (eval_all_nodes)
        !          14215:                    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
        !          14216:                else
        !          14217:                    break;
        !          14218: 
        !          14219:                if (ret < 0) {
        !          14220:                    /* NOP. */
        !          14221:                } else if (ret == 1) {
        !          14222:                    if (toBool)
        !          14223:                        goto return_1;
        !          14224:                    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
        !          14225:                }
        !          14226:                if ((cur->children == NULL) || (depth >= max_depth)) {
        !          14227:                    ret = xmlStreamPop(patstream);
        !          14228:                    while (cur->next != NULL) {
        !          14229:                        cur = cur->next;
        !          14230:                        if ((cur->type != XML_ENTITY_DECL) &&
        !          14231:                            (cur->type != XML_DTD_NODE))
        !          14232:                            goto next_node;
        !          14233:                    }
        !          14234:                }
        !          14235:            default:
        !          14236:                break;
        !          14237:        }
        !          14238: 
        !          14239: scan_children:
        !          14240:        if ((cur->children != NULL) && (depth < max_depth)) {
        !          14241:            /*
        !          14242:             * Do not descend on entities declarations
        !          14243:             */
        !          14244:            if (cur->children->type != XML_ENTITY_DECL) {
        !          14245:                cur = cur->children;
        !          14246:                depth++;
        !          14247:                /*
        !          14248:                 * Skip DTDs
        !          14249:                 */
        !          14250:                if (cur->type != XML_DTD_NODE)
        !          14251:                    continue;
        !          14252:            }
        !          14253:        }
        !          14254: 
        !          14255:        if (cur == limit)
        !          14256:            break;
        !          14257: 
        !          14258:        while (cur->next != NULL) {
        !          14259:            cur = cur->next;
        !          14260:            if ((cur->type != XML_ENTITY_DECL) &&
        !          14261:                (cur->type != XML_DTD_NODE))
        !          14262:                goto next_node;
        !          14263:        }
        !          14264: 
        !          14265:        do {
        !          14266:            cur = cur->parent;
        !          14267:            depth--;
        !          14268:            if ((cur == NULL) || (cur == limit))
        !          14269:                goto done;
        !          14270:            if (cur->type == XML_ELEMENT_NODE) {
        !          14271:                ret = xmlStreamPop(patstream);
        !          14272:            } else if ((eval_all_nodes) &&
        !          14273:                ((cur->type == XML_TEXT_NODE) ||
        !          14274:                 (cur->type == XML_CDATA_SECTION_NODE) ||
        !          14275:                 (cur->type == XML_COMMENT_NODE) ||
        !          14276:                 (cur->type == XML_PI_NODE)))
        !          14277:            {
        !          14278:                ret = xmlStreamPop(patstream);
        !          14279:            }
        !          14280:            if (cur->next != NULL) {
        !          14281:                cur = cur->next;
        !          14282:                break;
        !          14283:            }
        !          14284:        } while (cur != NULL);
        !          14285: 
        !          14286:     } while ((cur != NULL) && (depth >= 0));
        !          14287: 
        !          14288: done:
        !          14289: 
        !          14290: #if 0
        !          14291:     printf("stream eval: checked %d nodes selected %d\n",
        !          14292:            nb_nodes, retObj->nodesetval->nodeNr);
        !          14293: #endif
        !          14294: 
        !          14295:     if (patstream)
        !          14296:        xmlFreeStreamCtxt(patstream);
        !          14297:     return(0);
        !          14298: 
        !          14299: return_1:
        !          14300:     if (patstream)
        !          14301:        xmlFreeStreamCtxt(patstream);
        !          14302:     return(1);
        !          14303: }
        !          14304: #endif /* XPATH_STREAMING */
        !          14305: 
        !          14306: /**
        !          14307:  * xmlXPathRunEval:
        !          14308:  * @ctxt:  the XPath parser context with the compiled expression
        !          14309:  * @toBool:  evaluate to a boolean result
        !          14310:  *
        !          14311:  * Evaluate the Precompiled XPath expression in the given context.
        !          14312:  */
        !          14313: static int
        !          14314: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
        !          14315: {
        !          14316:     xmlXPathCompExprPtr comp;
        !          14317: 
        !          14318:     if ((ctxt == NULL) || (ctxt->comp == NULL))
        !          14319:        return(-1);
        !          14320: 
        !          14321:     if (ctxt->valueTab == NULL) {
        !          14322:        /* Allocate the value stack */
        !          14323:        ctxt->valueTab = (xmlXPathObjectPtr *)
        !          14324:                         xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
        !          14325:        if (ctxt->valueTab == NULL) {
        !          14326:            xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
        !          14327:            xmlFree(ctxt);
        !          14328:        }
        !          14329:        ctxt->valueNr = 0;
        !          14330:        ctxt->valueMax = 10;
        !          14331:        ctxt->value = NULL;
        !          14332:     }
        !          14333: #ifdef XPATH_STREAMING
        !          14334:     if (ctxt->comp->stream) {
        !          14335:        int res;
        !          14336: 
        !          14337:        if (toBool) {
        !          14338:            /*
        !          14339:            * Evaluation to boolean result.
        !          14340:            */
        !          14341:            res = xmlXPathRunStreamEval(ctxt->context,
        !          14342:                ctxt->comp->stream, NULL, 1);
        !          14343:            if (res != -1)
        !          14344:                return(res);
        !          14345:        } else {
        !          14346:            xmlXPathObjectPtr resObj = NULL;
        !          14347: 
        !          14348:            /*
        !          14349:            * Evaluation to a sequence.
        !          14350:            */
        !          14351:            res = xmlXPathRunStreamEval(ctxt->context,
        !          14352:                ctxt->comp->stream, &resObj, 0);
        !          14353: 
        !          14354:            if ((res != -1) && (resObj != NULL)) {
        !          14355:                valuePush(ctxt, resObj);
        !          14356:                return(0);
        !          14357:            }
        !          14358:            if (resObj != NULL)
        !          14359:                xmlXPathReleaseObject(ctxt->context, resObj);
        !          14360:        }
        !          14361:        /*
        !          14362:        * QUESTION TODO: This falls back to normal XPath evaluation
        !          14363:        * if res == -1. Is this intended?
        !          14364:        */
        !          14365:     }
        !          14366: #endif
        !          14367:     comp = ctxt->comp;
        !          14368:     if (comp->last < 0) {
        !          14369:        xmlGenericError(xmlGenericErrorContext,
        !          14370:            "xmlXPathRunEval: last is less than zero\n");
        !          14371:        return(-1);
        !          14372:     }
        !          14373:     if (toBool)
        !          14374:        return(xmlXPathCompOpEvalToBoolean(ctxt,
        !          14375:            &comp->steps[comp->last], 0));
        !          14376:     else
        !          14377:        xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
        !          14378: 
        !          14379:     return(0);
        !          14380: }
        !          14381: 
        !          14382: /************************************************************************
        !          14383:  *                                                                     *
        !          14384:  *                     Public interfaces                               *
        !          14385:  *                                                                     *
        !          14386:  ************************************************************************/
        !          14387: 
        !          14388: /**
        !          14389:  * xmlXPathEvalPredicate:
        !          14390:  * @ctxt:  the XPath context
        !          14391:  * @res:  the Predicate Expression evaluation result
        !          14392:  *
        !          14393:  * Evaluate a predicate result for the current node.
        !          14394:  * A PredicateExpr is evaluated by evaluating the Expr and converting
        !          14395:  * the result to a boolean. If the result is a number, the result will
        !          14396:  * be converted to true if the number is equal to the position of the
        !          14397:  * context node in the context node list (as returned by the position
        !          14398:  * function) and will be converted to false otherwise; if the result
        !          14399:  * is not a number, then the result will be converted as if by a call
        !          14400:  * to the boolean function.
        !          14401:  *
        !          14402:  * Returns 1 if predicate is true, 0 otherwise
        !          14403:  */
        !          14404: int
        !          14405: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
        !          14406:     if ((ctxt == NULL) || (res == NULL)) return(0);
        !          14407:     switch (res->type) {
        !          14408:         case XPATH_BOOLEAN:
        !          14409:            return(res->boolval);
        !          14410:         case XPATH_NUMBER:
        !          14411:            return(res->floatval == ctxt->proximityPosition);
        !          14412:         case XPATH_NODESET:
        !          14413:         case XPATH_XSLT_TREE:
        !          14414:            if (res->nodesetval == NULL)
        !          14415:                return(0);
        !          14416:            return(res->nodesetval->nodeNr != 0);
        !          14417:         case XPATH_STRING:
        !          14418:            return((res->stringval != NULL) &&
        !          14419:                   (xmlStrlen(res->stringval) != 0));
        !          14420:         default:
        !          14421:            STRANGE
        !          14422:     }
        !          14423:     return(0);
        !          14424: }
        !          14425: 
        !          14426: /**
        !          14427:  * xmlXPathEvaluatePredicateResult:
        !          14428:  * @ctxt:  the XPath Parser context
        !          14429:  * @res:  the Predicate Expression evaluation result
        !          14430:  *
        !          14431:  * Evaluate a predicate result for the current node.
        !          14432:  * A PredicateExpr is evaluated by evaluating the Expr and converting
        !          14433:  * the result to a boolean. If the result is a number, the result will
        !          14434:  * be converted to true if the number is equal to the position of the
        !          14435:  * context node in the context node list (as returned by the position
        !          14436:  * function) and will be converted to false otherwise; if the result
        !          14437:  * is not a number, then the result will be converted as if by a call
        !          14438:  * to the boolean function.
        !          14439:  *
        !          14440:  * Returns 1 if predicate is true, 0 otherwise
        !          14441:  */
        !          14442: int
        !          14443: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
        !          14444:                                 xmlXPathObjectPtr res) {
        !          14445:     if ((ctxt == NULL) || (res == NULL)) return(0);
        !          14446:     switch (res->type) {
        !          14447:         case XPATH_BOOLEAN:
        !          14448:            return(res->boolval);
        !          14449:         case XPATH_NUMBER:
        !          14450: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
        !          14451:            return((res->floatval == ctxt->context->proximityPosition) &&
        !          14452:                   (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
        !          14453: #else
        !          14454:            return(res->floatval == ctxt->context->proximityPosition);
        !          14455: #endif
        !          14456:         case XPATH_NODESET:
        !          14457:         case XPATH_XSLT_TREE:
        !          14458:            if (res->nodesetval == NULL)
        !          14459:                return(0);
        !          14460:            return(res->nodesetval->nodeNr != 0);
        !          14461:         case XPATH_STRING:
        !          14462:            return((res->stringval != NULL) && (res->stringval[0] != 0));
        !          14463: #ifdef LIBXML_XPTR_ENABLED
        !          14464:        case XPATH_LOCATIONSET:{
        !          14465:            xmlLocationSetPtr ptr = res->user;
        !          14466:            if (ptr == NULL)
        !          14467:                return(0);
        !          14468:            return (ptr->locNr != 0);
        !          14469:            }
        !          14470: #endif
        !          14471:         default:
        !          14472:            STRANGE
        !          14473:     }
        !          14474:     return(0);
        !          14475: }
        !          14476: 
        !          14477: #ifdef XPATH_STREAMING
        !          14478: /**
        !          14479:  * xmlXPathTryStreamCompile:
        !          14480:  * @ctxt: an XPath context
        !          14481:  * @str:  the XPath expression
        !          14482:  *
        !          14483:  * Try to compile the XPath expression as a streamable subset.
        !          14484:  *
        !          14485:  * Returns the compiled expression or NULL if failed to compile.
        !          14486:  */
        !          14487: static xmlXPathCompExprPtr
        !          14488: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
        !          14489:     /*
        !          14490:      * Optimization: use streaming patterns when the XPath expression can
        !          14491:      * be compiled to a stream lookup
        !          14492:      */
        !          14493:     xmlPatternPtr stream;
        !          14494:     xmlXPathCompExprPtr comp;
        !          14495:     xmlDictPtr dict = NULL;
        !          14496:     const xmlChar **namespaces = NULL;
        !          14497:     xmlNsPtr ns;
        !          14498:     int i, j;
        !          14499: 
        !          14500:     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
        !          14501:         (!xmlStrchr(str, '@'))) {
        !          14502:        const xmlChar *tmp;
        !          14503: 
        !          14504:        /*
        !          14505:         * We don't try to handle expressions using the verbose axis
        !          14506:         * specifiers ("::"), just the simplied form at this point.
        !          14507:         * Additionally, if there is no list of namespaces available and
        !          14508:         *  there's a ":" in the expression, indicating a prefixed QName,
        !          14509:         *  then we won't try to compile either. xmlPatterncompile() needs
        !          14510:         *  to have a list of namespaces at compilation time in order to
        !          14511:         *  compile prefixed name tests.
        !          14512:         */
        !          14513:        tmp = xmlStrchr(str, ':');
        !          14514:        if ((tmp != NULL) &&
        !          14515:            ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
        !          14516:            return(NULL);
        !          14517: 
        !          14518:        if (ctxt != NULL) {
        !          14519:            dict = ctxt->dict;
        !          14520:            if (ctxt->nsNr > 0) {
        !          14521:                namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
        !          14522:                if (namespaces == NULL) {
        !          14523:                    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
        !          14524:                    return(NULL);
        !          14525:                }
        !          14526:                for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
        !          14527:                    ns = ctxt->namespaces[j];
        !          14528:                    namespaces[i++] = ns->href;
        !          14529:                    namespaces[i++] = ns->prefix;
        !          14530:                }
        !          14531:                namespaces[i++] = NULL;
        !          14532:                namespaces[i] = NULL;
        !          14533:            }
        !          14534:        }
        !          14535: 
        !          14536:        stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
        !          14537:                        &namespaces[0]);
        !          14538:        if (namespaces != NULL) {
        !          14539:            xmlFree((xmlChar **)namespaces);
        !          14540:        }
        !          14541:        if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
        !          14542:            comp = xmlXPathNewCompExpr();
        !          14543:            if (comp == NULL) {
        !          14544:                xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
        !          14545:                return(NULL);
        !          14546:            }
        !          14547:            comp->stream = stream;
        !          14548:            comp->dict = dict;
        !          14549:            if (comp->dict)
        !          14550:                xmlDictReference(comp->dict);
        !          14551:            return(comp);
        !          14552:        }
        !          14553:        xmlFreePattern(stream);
        !          14554:     }
        !          14555:     return(NULL);
        !          14556: }
        !          14557: #endif /* XPATH_STREAMING */
        !          14558: 
        !          14559: static int
        !          14560: xmlXPathCanRewriteDosExpression(xmlChar *expr)
        !          14561: {
        !          14562:     if (expr == NULL)
        !          14563:        return(0);
        !          14564:     do {
        !          14565:         if ((*expr == '/') && (*(++expr) == '/'))
        !          14566:            return(1);
        !          14567:     } while (*expr++);
        !          14568:     return(0);
        !          14569: }
        !          14570: static void
        !          14571: xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
        !          14572: {
        !          14573:     /*
        !          14574:     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
        !          14575:     * internal representation.
        !          14576:     */
        !          14577:     if (op->ch1 != -1) {
        !          14578:        if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
        !          14579:            ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
        !          14580:            ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
        !          14581:            ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
        !          14582:        {
        !          14583:            /*
        !          14584:            * This is a "child::foo"
        !          14585:            */
        !          14586:            xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
        !          14587: 
        !          14588:            if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
        !          14589:                (prevop->ch1 != -1) &&
        !          14590:                ((xmlXPathAxisVal) prevop->value ==
        !          14591:                    AXIS_DESCENDANT_OR_SELF) &&
        !          14592:                (prevop->ch2 == -1) &&
        !          14593:                ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
        !          14594:                ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
        !          14595:                (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
        !          14596:            {
        !          14597:                /*
        !          14598:                * This is a "/descendant-or-self::node()" without predicates.
        !          14599:                * Eliminate it.
        !          14600:                */
        !          14601:                op->ch1 = prevop->ch1;
        !          14602:                op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
        !          14603:            }
        !          14604:        }
        !          14605:        if (op->ch1 != -1)
        !          14606:            xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
        !          14607:     }
        !          14608:     if (op->ch2 != -1)
        !          14609:        xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
        !          14610: }
        !          14611: 
        !          14612: /**
        !          14613:  * xmlXPathCtxtCompile:
        !          14614:  * @ctxt: an XPath context
        !          14615:  * @str:  the XPath expression
        !          14616:  *
        !          14617:  * Compile an XPath expression
        !          14618:  *
        !          14619:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
        !          14620:  *         the caller has to free the object.
        !          14621:  */
        !          14622: xmlXPathCompExprPtr
        !          14623: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
        !          14624:     xmlXPathParserContextPtr pctxt;
        !          14625:     xmlXPathCompExprPtr comp;
        !          14626: 
        !          14627: #ifdef XPATH_STREAMING
        !          14628:     comp = xmlXPathTryStreamCompile(ctxt, str);
        !          14629:     if (comp != NULL)
        !          14630:         return(comp);
        !          14631: #endif
        !          14632: 
        !          14633:     xmlXPathInit();
        !          14634: 
        !          14635:     pctxt = xmlXPathNewParserContext(str, ctxt);
        !          14636:     if (pctxt == NULL)
        !          14637:         return NULL;
        !          14638:     xmlXPathCompileExpr(pctxt, 1);
        !          14639: 
        !          14640:     if( pctxt->error != XPATH_EXPRESSION_OK )
        !          14641:     {
        !          14642:         xmlXPathFreeParserContext(pctxt);
        !          14643:         return(NULL);
        !          14644:     }
        !          14645: 
        !          14646:     if (*pctxt->cur != 0) {
        !          14647:        /*
        !          14648:         * aleksey: in some cases this line prints *second* error message
        !          14649:         * (see bug #78858) and probably this should be fixed.
        !          14650:         * However, we are not sure that all error messages are printed
        !          14651:         * out in other places. It's not critical so we leave it as-is for now
        !          14652:         */
        !          14653:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
        !          14654:        comp = NULL;
        !          14655:     } else {
        !          14656:        comp = pctxt->comp;
        !          14657:        pctxt->comp = NULL;
        !          14658:     }
        !          14659:     xmlXPathFreeParserContext(pctxt);
        !          14660: 
        !          14661:     if (comp != NULL) {
        !          14662:        comp->expr = xmlStrdup(str);
        !          14663: #ifdef DEBUG_EVAL_COUNTS
        !          14664:        comp->string = xmlStrdup(str);
        !          14665:        comp->nb = 0;
        !          14666: #endif
        !          14667:        if ((comp->expr != NULL) &&
        !          14668:            (comp->nbStep > 2) &&
        !          14669:            (comp->last >= 0) &&
        !          14670:            (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
        !          14671:        {
        !          14672:            xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
        !          14673:        }
        !          14674:     }
        !          14675:     return(comp);
        !          14676: }
        !          14677: 
        !          14678: /**
        !          14679:  * xmlXPathCompile:
        !          14680:  * @str:  the XPath expression
        !          14681:  *
        !          14682:  * Compile an XPath expression
        !          14683:  *
        !          14684:  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
        !          14685:  *         the caller has to free the object.
        !          14686:  */
        !          14687: xmlXPathCompExprPtr
        !          14688: xmlXPathCompile(const xmlChar *str) {
        !          14689:     return(xmlXPathCtxtCompile(NULL, str));
        !          14690: }
        !          14691: 
        !          14692: /**
        !          14693:  * xmlXPathCompiledEvalInternal:
        !          14694:  * @comp:  the compiled XPath expression
        !          14695:  * @ctxt:  the XPath context
        !          14696:  * @resObj: the resulting XPath object or NULL
        !          14697:  * @toBool: 1 if only a boolean result is requested
        !          14698:  *
        !          14699:  * Evaluate the Precompiled XPath expression in the given context.
        !          14700:  * The caller has to free @resObj.
        !          14701:  *
        !          14702:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
        !          14703:  *         the caller has to free the object.
        !          14704:  */
        !          14705: static int
        !          14706: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
        !          14707:                             xmlXPathContextPtr ctxt,
        !          14708:                             xmlXPathObjectPtr *resObj,
        !          14709:                             int toBool)
        !          14710: {
        !          14711:     xmlXPathParserContextPtr pctxt;
        !          14712: #ifndef LIBXML_THREAD_ENABLED
        !          14713:     static int reentance = 0;
        !          14714: #endif
        !          14715:     int res;
        !          14716: 
        !          14717:     CHECK_CTXT_NEG(ctxt)
        !          14718: 
        !          14719:     if (comp == NULL)
        !          14720:        return(-1);
        !          14721:     xmlXPathInit();
        !          14722: 
        !          14723: #ifndef LIBXML_THREAD_ENABLED
        !          14724:     reentance++;
        !          14725:     if (reentance > 1)
        !          14726:        xmlXPathDisableOptimizer = 1;
        !          14727: #endif
        !          14728: 
        !          14729: #ifdef DEBUG_EVAL_COUNTS
        !          14730:     comp->nb++;
        !          14731:     if ((comp->string != NULL) && (comp->nb > 100)) {
        !          14732:        fprintf(stderr, "100 x %s\n", comp->string);
        !          14733:        comp->nb = 0;
        !          14734:     }
        !          14735: #endif
        !          14736:     pctxt = xmlXPathCompParserContext(comp, ctxt);
        !          14737:     res = xmlXPathRunEval(pctxt, toBool);
        !          14738: 
        !          14739:     if (resObj) {
        !          14740:        if (pctxt->value == NULL) {
        !          14741:            xmlGenericError(xmlGenericErrorContext,
        !          14742:                "xmlXPathCompiledEval: evaluation failed\n");
        !          14743:            *resObj = NULL;
        !          14744:        } else {
        !          14745:            *resObj = valuePop(pctxt);
        !          14746:        }
        !          14747:     }
        !          14748: 
        !          14749:     /*
        !          14750:     * Pop all remaining objects from the stack.
        !          14751:     */
        !          14752:     if (pctxt->valueNr > 0) {
        !          14753:        xmlXPathObjectPtr tmp;
        !          14754:        int stack = 0;
        !          14755: 
        !          14756:        do {
        !          14757:            tmp = valuePop(pctxt);
        !          14758:            if (tmp != NULL) {
        !          14759:                stack++;
        !          14760:                xmlXPathReleaseObject(ctxt, tmp);
        !          14761:            }
        !          14762:        } while (tmp != NULL);
        !          14763:        if ((stack != 0) &&
        !          14764:            ((toBool) || ((resObj) && (*resObj))))
        !          14765:        {
        !          14766:            xmlGenericError(xmlGenericErrorContext,
        !          14767:                "xmlXPathCompiledEval: %d objects left on the stack.\n",
        !          14768:                stack);
        !          14769:        }
        !          14770:     }
        !          14771: 
        !          14772:     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
        !          14773:        xmlXPathFreeObject(*resObj);
        !          14774:        *resObj = NULL;
        !          14775:     }
        !          14776:     pctxt->comp = NULL;
        !          14777:     xmlXPathFreeParserContext(pctxt);
        !          14778: #ifndef LIBXML_THREAD_ENABLED
        !          14779:     reentance--;
        !          14780: #endif
        !          14781: 
        !          14782:     return(res);
        !          14783: }
        !          14784: 
        !          14785: /**
        !          14786:  * xmlXPathCompiledEval:
        !          14787:  * @comp:  the compiled XPath expression
        !          14788:  * @ctx:  the XPath context
        !          14789:  *
        !          14790:  * Evaluate the Precompiled XPath expression in the given context.
        !          14791:  *
        !          14792:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
        !          14793:  *         the caller has to free the object.
        !          14794:  */
        !          14795: xmlXPathObjectPtr
        !          14796: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
        !          14797: {
        !          14798:     xmlXPathObjectPtr res = NULL;
        !          14799: 
        !          14800:     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
        !          14801:     return(res);
        !          14802: }
        !          14803: 
        !          14804: /**
        !          14805:  * xmlXPathCompiledEvalToBoolean:
        !          14806:  * @comp:  the compiled XPath expression
        !          14807:  * @ctxt:  the XPath context
        !          14808:  *
        !          14809:  * Applies the XPath boolean() function on the result of the given
        !          14810:  * compiled expression.
        !          14811:  *
        !          14812:  * Returns 1 if the expression evaluated to true, 0 if to false and
        !          14813:  *         -1 in API and internal errors.
        !          14814:  */
        !          14815: int
        !          14816: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
        !          14817:                              xmlXPathContextPtr ctxt)
        !          14818: {
        !          14819:     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
        !          14820: }
        !          14821: 
        !          14822: /**
        !          14823:  * xmlXPathEvalExpr:
        !          14824:  * @ctxt:  the XPath Parser context
        !          14825:  *
        !          14826:  * Parse and evaluate an XPath expression in the given context,
        !          14827:  * then push the result on the context stack
        !          14828:  */
        !          14829: void
        !          14830: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
        !          14831: #ifdef XPATH_STREAMING
        !          14832:     xmlXPathCompExprPtr comp;
        !          14833: #endif
        !          14834: 
        !          14835:     if (ctxt == NULL) return;
        !          14836: 
        !          14837: #ifdef XPATH_STREAMING
        !          14838:     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
        !          14839:     if (comp != NULL) {
        !          14840:         if (ctxt->comp != NULL)
        !          14841:            xmlXPathFreeCompExpr(ctxt->comp);
        !          14842:         ctxt->comp = comp;
        !          14843:        if (ctxt->cur != NULL)
        !          14844:            while (*ctxt->cur != 0) ctxt->cur++;
        !          14845:     } else
        !          14846: #endif
        !          14847:     {
        !          14848:        xmlXPathCompileExpr(ctxt, 1);
        !          14849:        /*
        !          14850:        * In this scenario the expression string will sit in ctxt->base.
        !          14851:        */
        !          14852:        if ((ctxt->error == XPATH_EXPRESSION_OK) &&
        !          14853:            (ctxt->comp != NULL) &&
        !          14854:            (ctxt->base != NULL) &&
        !          14855:            (ctxt->comp->nbStep > 2) &&
        !          14856:            (ctxt->comp->last >= 0) &&
        !          14857:            (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
        !          14858:        {
        !          14859:            xmlXPathRewriteDOSExpression(ctxt->comp,
        !          14860:                &ctxt->comp->steps[ctxt->comp->last]);
        !          14861:        }
        !          14862:     }
        !          14863:     CHECK_ERROR;
        !          14864:     xmlXPathRunEval(ctxt, 0);
        !          14865: }
        !          14866: 
        !          14867: /**
        !          14868:  * xmlXPathEval:
        !          14869:  * @str:  the XPath expression
        !          14870:  * @ctx:  the XPath context
        !          14871:  *
        !          14872:  * Evaluate the XPath Location Path in the given context.
        !          14873:  *
        !          14874:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
        !          14875:  *         the caller has to free the object.
        !          14876:  */
        !          14877: xmlXPathObjectPtr
        !          14878: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
        !          14879:     xmlXPathParserContextPtr ctxt;
        !          14880:     xmlXPathObjectPtr res, tmp, init = NULL;
        !          14881:     int stack = 0;
        !          14882: 
        !          14883:     CHECK_CTXT(ctx)
        !          14884: 
        !          14885:     xmlXPathInit();
        !          14886: 
        !          14887:     ctxt = xmlXPathNewParserContext(str, ctx);
        !          14888:     if (ctxt == NULL)
        !          14889:         return NULL;
        !          14890:     xmlXPathEvalExpr(ctxt);
        !          14891: 
        !          14892:     if (ctxt->value == NULL) {
        !          14893:        xmlGenericError(xmlGenericErrorContext,
        !          14894:                "xmlXPathEval: evaluation failed\n");
        !          14895:        res = NULL;
        !          14896:     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
        !          14897: #ifdef XPATH_STREAMING
        !          14898:             && (ctxt->comp->stream == NULL)
        !          14899: #endif
        !          14900:              ) {
        !          14901:        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
        !          14902:        res = NULL;
        !          14903:     } else {
        !          14904:        res = valuePop(ctxt);
        !          14905:     }
        !          14906: 
        !          14907:     do {
        !          14908:         tmp = valuePop(ctxt);
        !          14909:        if (tmp != NULL) {
        !          14910:            if (tmp != init)
        !          14911:                stack++;
        !          14912:            xmlXPathReleaseObject(ctx, tmp);
        !          14913:         }
        !          14914:     } while (tmp != NULL);
        !          14915:     if ((stack != 0) && (res != NULL)) {
        !          14916:        xmlGenericError(xmlGenericErrorContext,
        !          14917:                "xmlXPathEval: %d object left on the stack\n",
        !          14918:                stack);
        !          14919:     }
        !          14920:     if (ctxt->error != XPATH_EXPRESSION_OK) {
        !          14921:        xmlXPathFreeObject(res);
        !          14922:        res = NULL;
        !          14923:     }
        !          14924: 
        !          14925:     xmlXPathFreeParserContext(ctxt);
        !          14926:     return(res);
        !          14927: }
        !          14928: 
        !          14929: /**
        !          14930:  * xmlXPathEvalExpression:
        !          14931:  * @str:  the XPath expression
        !          14932:  * @ctxt:  the XPath context
        !          14933:  *
        !          14934:  * Evaluate the XPath expression in the given context.
        !          14935:  *
        !          14936:  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
        !          14937:  *         the caller has to free the object.
        !          14938:  */
        !          14939: xmlXPathObjectPtr
        !          14940: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
        !          14941:     xmlXPathParserContextPtr pctxt;
        !          14942:     xmlXPathObjectPtr res, tmp;
        !          14943:     int stack = 0;
        !          14944: 
        !          14945:     CHECK_CTXT(ctxt)
        !          14946: 
        !          14947:     xmlXPathInit();
        !          14948: 
        !          14949:     pctxt = xmlXPathNewParserContext(str, ctxt);
        !          14950:     if (pctxt == NULL)
        !          14951:         return NULL;
        !          14952:     xmlXPathEvalExpr(pctxt);
        !          14953: 
        !          14954:     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
        !          14955:        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
        !          14956:        res = NULL;
        !          14957:     } else {
        !          14958:        res = valuePop(pctxt);
        !          14959:     }
        !          14960:     do {
        !          14961:         tmp = valuePop(pctxt);
        !          14962:        if (tmp != NULL) {
        !          14963:            xmlXPathReleaseObject(ctxt, tmp);
        !          14964:            stack++;
        !          14965:        }
        !          14966:     } while (tmp != NULL);
        !          14967:     if ((stack != 0) && (res != NULL)) {
        !          14968:        xmlGenericError(xmlGenericErrorContext,
        !          14969:                "xmlXPathEvalExpression: %d object left on the stack\n",
        !          14970:                stack);
        !          14971:     }
        !          14972:     xmlXPathFreeParserContext(pctxt);
        !          14973:     return(res);
        !          14974: }
        !          14975: 
        !          14976: /************************************************************************
        !          14977:  *                                                                     *
        !          14978:  *     Extra functions not pertaining to the XPath spec                *
        !          14979:  *                                                                     *
        !          14980:  ************************************************************************/
        !          14981: /**
        !          14982:  * xmlXPathEscapeUriFunction:
        !          14983:  * @ctxt:  the XPath Parser context
        !          14984:  * @nargs:  the number of arguments
        !          14985:  *
        !          14986:  * Implement the escape-uri() XPath function
        !          14987:  *    string escape-uri(string $str, bool $escape-reserved)
        !          14988:  *
        !          14989:  * This function applies the URI escaping rules defined in section 2 of [RFC
        !          14990:  * 2396] to the string supplied as $uri-part, which typically represents all
        !          14991:  * or part of a URI. The effect of the function is to replace any special
        !          14992:  * character in the string by an escape sequence of the form %xx%yy...,
        !          14993:  * where xxyy... is the hexadecimal representation of the octets used to
        !          14994:  * represent the character in UTF-8.
        !          14995:  *
        !          14996:  * The set of characters that are escaped depends on the setting of the
        !          14997:  * boolean argument $escape-reserved.
        !          14998:  *
        !          14999:  * If $escape-reserved is true, all characters are escaped other than lower
        !          15000:  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
        !          15001:  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
        !          15002:  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
        !          15003:  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
        !          15004:  * A-F).
        !          15005:  *
        !          15006:  * If $escape-reserved is false, the behavior differs in that characters
        !          15007:  * referred to in [RFC 2396] as reserved characters are not escaped. These
        !          15008:  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
        !          15009:  *
        !          15010:  * [RFC 2396] does not define whether escaped URIs should use lower case or
        !          15011:  * upper case for hexadecimal digits. To ensure that escaped URIs can be
        !          15012:  * compared using string comparison functions, this function must always use
        !          15013:  * the upper-case letters A-F.
        !          15014:  *
        !          15015:  * Generally, $escape-reserved should be set to true when escaping a string
        !          15016:  * that is to form a single part of a URI, and to false when escaping an
        !          15017:  * entire URI or URI reference.
        !          15018:  *
        !          15019:  * In the case of non-ascii characters, the string is encoded according to
        !          15020:  * utf-8 and then converted according to RFC 2396.
        !          15021:  *
        !          15022:  * Examples
        !          15023:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
        !          15024:  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
        !          15025:  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
        !          15026:  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
        !          15027:  *
        !          15028:  */
        !          15029: static void
        !          15030: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
        !          15031:     xmlXPathObjectPtr str;
        !          15032:     int escape_reserved;
        !          15033:     xmlBufferPtr target;
        !          15034:     xmlChar *cptr;
        !          15035:     xmlChar escape[4];
        !          15036: 
        !          15037:     CHECK_ARITY(2);
        !          15038: 
        !          15039:     escape_reserved = xmlXPathPopBoolean(ctxt);
        !          15040: 
        !          15041:     CAST_TO_STRING;
        !          15042:     str = valuePop(ctxt);
        !          15043: 
        !          15044:     target = xmlBufferCreate();
        !          15045: 
        !          15046:     escape[0] = '%';
        !          15047:     escape[3] = 0;
        !          15048: 
        !          15049:     if (target) {
        !          15050:        for (cptr = str->stringval; *cptr; cptr++) {
        !          15051:            if ((*cptr >= 'A' && *cptr <= 'Z') ||
        !          15052:                (*cptr >= 'a' && *cptr <= 'z') ||
        !          15053:                (*cptr >= '0' && *cptr <= '9') ||
        !          15054:                *cptr == '-' || *cptr == '_' || *cptr == '.' ||
        !          15055:                *cptr == '!' || *cptr == '~' || *cptr == '*' ||
        !          15056:                *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
        !          15057:                (*cptr == '%' &&
        !          15058:                 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
        !          15059:                  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
        !          15060:                  (cptr[1] >= '0' && cptr[1] <= '9')) &&
        !          15061:                 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
        !          15062:                  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
        !          15063:                  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
        !          15064:                (!escape_reserved &&
        !          15065:                 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
        !          15066:                  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
        !          15067:                  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
        !          15068:                  *cptr == ','))) {
        !          15069:                xmlBufferAdd(target, cptr, 1);
        !          15070:            } else {
        !          15071:                if ((*cptr >> 4) < 10)
        !          15072:                    escape[1] = '0' + (*cptr >> 4);
        !          15073:                else
        !          15074:                    escape[1] = 'A' - 10 + (*cptr >> 4);
        !          15075:                if ((*cptr & 0xF) < 10)
        !          15076:                    escape[2] = '0' + (*cptr & 0xF);
        !          15077:                else
        !          15078:                    escape[2] = 'A' - 10 + (*cptr & 0xF);
        !          15079: 
        !          15080:                xmlBufferAdd(target, &escape[0], 3);
        !          15081:            }
        !          15082:        }
        !          15083:     }
        !          15084:     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
        !          15085:        xmlBufferContent(target)));
        !          15086:     xmlBufferFree(target);
        !          15087:     xmlXPathReleaseObject(ctxt->context, str);
        !          15088: }
        !          15089: 
        !          15090: /**
        !          15091:  * xmlXPathRegisterAllFunctions:
        !          15092:  * @ctxt:  the XPath context
        !          15093:  *
        !          15094:  * Registers all default XPath functions in this context
        !          15095:  */
        !          15096: void
        !          15097: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
        !          15098: {
        !          15099:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
        !          15100:                          xmlXPathBooleanFunction);
        !          15101:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
        !          15102:                          xmlXPathCeilingFunction);
        !          15103:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
        !          15104:                          xmlXPathCountFunction);
        !          15105:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
        !          15106:                          xmlXPathConcatFunction);
        !          15107:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
        !          15108:                          xmlXPathContainsFunction);
        !          15109:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
        !          15110:                          xmlXPathIdFunction);
        !          15111:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
        !          15112:                          xmlXPathFalseFunction);
        !          15113:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
        !          15114:                          xmlXPathFloorFunction);
        !          15115:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
        !          15116:                          xmlXPathLastFunction);
        !          15117:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
        !          15118:                          xmlXPathLangFunction);
        !          15119:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
        !          15120:                          xmlXPathLocalNameFunction);
        !          15121:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
        !          15122:                          xmlXPathNotFunction);
        !          15123:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
        !          15124:                          xmlXPathNameFunction);
        !          15125:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
        !          15126:                          xmlXPathNamespaceURIFunction);
        !          15127:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
        !          15128:                          xmlXPathNormalizeFunction);
        !          15129:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
        !          15130:                          xmlXPathNumberFunction);
        !          15131:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
        !          15132:                          xmlXPathPositionFunction);
        !          15133:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
        !          15134:                          xmlXPathRoundFunction);
        !          15135:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
        !          15136:                          xmlXPathStringFunction);
        !          15137:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
        !          15138:                          xmlXPathStringLengthFunction);
        !          15139:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
        !          15140:                          xmlXPathStartsWithFunction);
        !          15141:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
        !          15142:                          xmlXPathSubstringFunction);
        !          15143:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
        !          15144:                          xmlXPathSubstringBeforeFunction);
        !          15145:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
        !          15146:                          xmlXPathSubstringAfterFunction);
        !          15147:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
        !          15148:                          xmlXPathSumFunction);
        !          15149:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
        !          15150:                          xmlXPathTrueFunction);
        !          15151:     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
        !          15152:                          xmlXPathTranslateFunction);
        !          15153: 
        !          15154:     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
        !          15155:         (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
        !          15156:                          xmlXPathEscapeUriFunction);
        !          15157: }
        !          15158: 
        !          15159: #endif /* LIBXML_XPATH_ENABLED */
        !          15160: #define bottom_xpath
        !          15161: #include "elfgcchack.h"

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