Annotation of embedaddon/libxml2/xpath.c, revision 1.1.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>